0

我在 C 中有纹理加载例程,它调用我的游戏的 Java 部分来完成这项工作。它可以加载 .png 和 .jpg 文件并从中创建纹理。它将生成的 textureID(使用 glGenTextures 生成)返回给 C。在我开始使用frontbuffer之前它工作得很好。

由于前缓冲区的纹理是空的,我直接在 C 中创建它。当我第一次运行游戏时它工作正常 - 为前缓冲区生成的纹理 ID 与所有其他纹理 ID 不同。但是当我按下 HOME 键,然后再次跳回到游戏中,我重新加载所有纹理并再次重新创建前端缓冲区(从上下文丢失中恢复)为前端缓冲区生成的纹理 ID 与为纹理生成的纹理 ID 之一冲突 - 就像如果有两条标识线。使用帧缓冲区的屏幕已损坏 - 显示 ID 等于新分配的帧缓冲区 ID 的纹理。

这一切都只发生在真实设备上(在我的例子中是三星 Galaxy 平板电脑),而不是在模拟器中。

C 加载例程:

void Texture::construct(AssetLoader* aLoader, s32 aIdx)
{
    const c8* fileName = aLoader->getFileName();
    
    // load texture
    SBC::System::Application* app = &Game::getGame().getApplication();
   
    JNIEnv *env;
    
    bool shouldDetach = false;
    JavaVM* vm = gJavaVM;
    jint rc = vm->GetEnv((void **)&env, JNI_VERSION_1_6);
    if (rc != JNI_OK)
    {
        shouldDetach = true;
        vm->AttachCurrentThread(&env, NULL);
    }
    jclass& activityClass = gJavaActivityClass;
    
    jmethodID mid = env->GetStaticMethodID(activityClass, "loadTexture", "(Ljava/lang/String;I)I");
    jstring mystr = env->NewStringUTF(fileName);
    jint ret = env->CallStaticIntMethod(activityClass, mid, mystr, aIdx);
    env->DeleteLocalRef(mystr);
    
    // store information on ID, width and height of texture
    mTextureID = ret;
    
    LOGE("textureID = %i", mTextureID);
    
    mid = env->GetStaticMethodID(activityClass, "getTextureWidth", "()I");
    mWidth = env->CallStaticIntMethod(activityClass, mid);
    mid = env->GetStaticMethodID(activityClass, "getTextureHeight", "()I");
    mHeight = env->CallStaticIntMethod(activityClass, mid);
    
    if (shouldDetach)
        vm->DetachCurrentThread();
    
    LOGI("texture ID %i, width %i, height %i", mTextureID, mWidth, mHeight);
}

Java 方法

//-----------------------------------------------------
/* fname = asset file name
 * id >= 0 ... position in compound file
 * id < 0 ... single file (no compound)
 */
public static int loadTexture(String fname, int id)
{
    // clear last texture parameters
    txtID = width = height = -1;
        
    Log.d("Helper", "Loading texture from asset file " + fname + " with id " + id);
    
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inScaled = false;       // No pre-scaling
    AssetManager am = SBCEngine.getSBCEngine().getAssets();
    Bitmap bitmap = null;
    
    try
    {
        InputStream stream = am.open(fname);
            
        // loading from compound file?
        if (id >= 0)
        {
            DataInputStream input = new DataInputStream(stream);
                
            // skip header
            input.skip(3);
            // skip to entry offset
            input.skip(id * 4);
            // read entry beginning
            int dataStart = input.readInt();
            // read data length
            int dataLen = input.readInt() - dataStart;
            // skip to start of subfile
            // offsets are without header (3) bytes
            // we already skipped id * 4 bytes
            // we already have read 2 offset by 4 bytes = 8 in total
            input.skip(dataStart - (id * 4) - 8);
    
            // get data from correct position
            byte[] data = new byte[dataLen];
            input.read(data);
    
            bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
        }
        else    // no compound
        {
            Log.d("Helper", "Loading from stream");
            bitmap = BitmapFactory.decodeStream(stream, null, options);
        }
            
            
        // test returned bitmap for success
        if (bitmap == null)
        {
            Log.e("Helper", "Failed to load texture " + fname + " with id " + id);
        }
    
        // check whether the loaded bitmap has width and height equal to power of 2
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        if (getNearestPOT(w) != w || getNearestPOT(h) != h)
        {
            Log.w("Helper", "Texture " + fname + " with id " + id +
                        " has not either width or height power of 2");
                
            // new dimensions
            w = getNearestPOT(w);
            h = getNearestPOT(h);
    
            // get actual bitmap config
            Bitmap.Config bitmapConfig = bitmap.getConfig();
            // check for null
            if (bitmapConfig == null)
            {
                bitmapConfig = Bitmap.Config.ARGB_8888;
                Log.w("Helper", "Unknown bitmap config. Setting to ARGB_8888");
            }
            // redraw bitmap into POT bitmap
            Bitmap newBitmap = Bitmap.createBitmap(w, h, bitmapConfig);
            Canvas canvas = new Canvas(newBitmap);
            canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
            bitmap.recycle();
            canvas = null;
            bitmap = newBitmap;
                
            Log.w("Helper", "Texture " + fname + " rebuilded into texture with POT");
        }
            
        // generate textureID
        int[] textures = new int[1];
        GLES20.glGenTextures(1, textures, 0);
        int textureID = textures[0];
            
        // create texture
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
            
        // destroy bitmap
        bitmap.recycle();
            
        txtID = textureID;
        width = w;
        height = h;
            
        Log.d("Helper", "Loaded texture ID:" + textureID + ", width:" + w + ", height:" + h);
        return textureID;
    }
    catch (IOException e)
    {
        Log.e("Helper", "Failed to load texture " + fname + " with id " + id);
        return 0;
    }
}
    
    //------------------------------------------------------------------------
public static int getTextureWidth()
{
    return width;
}
    
    //------------------------------------------------------------------------
public static int getTextureHeight()
{
    return height;
}
    
    //------------------------------------------------------------------------
private static int getNearestPOT(int val)
{
    int newDim = 1;
    while(val > newDim) newDim *= 2;
    return newDim;
}

最后是为前端缓冲区创建纹理的 C 例程

// create empty texture
void Texture::construct(u32 aTextureWidth, u32 aTextureHeight)
{
    // get power of 2 dimensions
    mWidth = getNearestPOT(aTextureWidth);
    mHeight = getNearestPOT(aTextureHeight);
    
    glGenTextures(1, &mTextureID);
    glBindTexture(GL_TEXTURE_2D, mTextureID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, mWidth, mHeight, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, null);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    
    LOGE("textureID = %i", mTextureID);
}

有人遇到过同样的问题吗?

4

1 回答 1

2

我终于找到了解决方案。当上下文丢失发生时,所有纹理都会被删除。但是我在用以前的 ID 重新创建之前自己删除了它们。这导致了过程中的混乱,因为一些新生成的 ID 在更新下一个对象时立即被删除。

于 2013-03-17T18:17:11.440 回答