I try reuse Android Media Effects samples and want to be able to change texture data with new bitmap from camera or gallery pick. No solution so far
This is the initial load texture from the sample : https://github.com/googlesamples/android-MediaEffects/blob/master/Application/src/main/java/com/example/android/mediaeffects/MediaEffectsFragment.java
private void loadTextures() {
// Generate textures
GLES20.glGenTextures(2, mTextures, 0);
// Load input bitmap
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.puppy);
mImageWidth = bitmap.getWidth();
mImageHeight = bitmap.getHeight();
mTexRenderer.updateTextureSize(mImageWidth, mImageHeight);
// Upload to texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Set texture parameters
GLToolbox.initTexParams();
}
and this is my trouble function :
public void changeBackground(Uri bitmapUri) {
Log.d(TAG, "changeBackground : " + bitmapUri.getPath());
Bitmap bitmap = BitmapFactory.decodeFile(bitmapUri.getPath());
mImageWidth = bitmap.getWidth();
mImageHeight = bitmap.getHeight();
mTexRenderer.updateTextureSize(mImageWidth, mImageHeight);
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, bitmap);
theBackground.requestRender(); //my GLSurfaceView
bitmap.recycle();
}
I tried several ways :
using texSubImage2D only -> texture not updated
delete and recreate textures with new bitmap -> black texture
note: the bitmap dimension is fixed, at 1080 x 1080
How to change/modify/replace texture data with new bitmap ?
UPDATE:
I think the problem more relate to this question : Setting texture on 3D object using image from photo gallery. i call changeBackground() after grabbing the image from gallery intent and then crop it (another intent).
Now, how to effectively change texture data with bitmap from gallery intent? anyone have a clue?
SOLVED
I solved the problem by defering texture load process to onSurfaceChange() function. Simply use a flag to indicate the file to load and onSurfaceChange check the flag again.
private Uri mFileToLoad = null;
public void changeBackground(Uri bitmapUri) {
Log.d(TAG, "changeBackground : " + bitmapUri.getPath());
mFileToLoad = bitmapUri;
theBackground.requestRender();
}
and my onSurfaceChange()
public void onSurfaceChanged(GL10 gl, int width, int height) {
Log.d(TAG, "onSurfaceChanged w:" + width + " h:" + height);
if (mFileToLoad!=null) {
GLES20.glDeleteTextures(mTextures.length, mTextures, 0);
GLES20.glGenTextures(mTextures.length, mTextures, 0);
Bitmap bitmap = BitmapFactory.decodeFile(mFileToLoad.getPath());
mImageWidth = bitmap.getWidth();
mImageHeight = bitmap.getHeight();
mTexRenderer.updateTextureSize(mImageWidth, mImageHeight);
// Upload to texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Set texture parameters
GLToolbox.initTexParams();
mFileToLoad = null;
bitmap.recycle();
}
if (mTexRenderer != null) {
mTexRenderer.updateViewSize(width, height);
}
}
So far it works.
答案 0 :(得分:1)
看起来您的changeBackground()
方法可能是从UI线程调用的,或者至少是渲染线程以外的其他线程。
GLSurfaceView
创建一个单独的渲染线程,在调用渲染方法时,它具有当前的OpenGL上下文。因此,它可以用于您的OpenGL调用。所有其他线程都不是这种情况。当前的OpenGL上下文每个线程。因此,除非你对它做一些事情(这是可能的,但会增加显着的复杂性),你不能从其他线程进行OpenGL调用。
有几个选项可以解决这个问题。最简单的方法可能是使用queueEvent()
上的GLSurfaceView
方法,它允许您传入将在渲染线程中执行的Runnable
。
我不确定代码中的mTexRenderer.updateTextureSize()
方法是做什么的。但通常情况下,如果纹理大小发生变化,则必须使用GLUtils.texImage2D()
代替GLUtils.texSubImage2D()
来更新纹理。
代码可能看起来像这样(未经测试,因此它可能与输入完全不同):
final Bitmap bitmap = BitmapFactory.decodeFile(bitmapUri.getPath());
theBackground.queueEvent(new Runnable() {
@Override
void run() {
mImageWidth = bitmap.getWidth();
mImageHeight = bitmap.getHeight();
mTexRenderer.updateTextureSize(mImageWidth, mImageHeight);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
}
});
theBackground.requestRender();