我在 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);
}
有人遇到过同样的问题吗?