如何通过C++中的OpenGLES在Android中显示位图?

3

我在Java层有一个实现了Renderer接口的类。在这个类中,我有一个位图需要传递到JNI层。JNI层将负责使用OpenGL显示位图。有人能告诉我如何做吗?

更新: 我知道有一个OpenGL方法glTexImage2D可以用来显示简单的2D图像。有人能告诉我如何使用它吗?在调用此方法之前和之后,我需要进行什么设置?我应该如何将我的位图从Java传递到JNI中?

更新2: 这是我的当前代码:

Java类

public class HelloRenderer implements Renderer
{
    Context _context;
    Bitmap wood;
    public void SetContext(Context context)
    {
        _context = context;
        wood = BitmapFactory.decodeResource( _context.getResources(), R.drawable.hello);
    }

    @Override
    public void onDrawFrame(GL10 gl) 
    {
        RenderGLStuff(wood.getWidth(), wood.getHeight(), wood);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) 
    {
        InitGLStuff(wood.getWidth(), wood.getHeight(), wood);

    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) 
    {

    }

    private static native void InitGLStuff(int width, int height, Bitmap  ptr);
    private static native void RenderGLStuff(int width, int height, Bitmap  ptr);

    static
    {
        System.loadLibrary("myglstuff");
    }
}

JNI 方法
JNIEXPORT void JNICALL Java_mine_NativeGL_HelloRenderer_InitGLStuff(JNIEnv * env, jobject obj, int width, int height, void * ptr )
{
   glViewport(0, 0, width, height);
   glClearColorx((GLfixed)(0.1f * 65536), (GLfixed)(0.2f * 65536), (GLfixed)(0.3f * 65536), 0x10000);
   glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();

}

 JNIEXPORT void JNICALL Java_mine_NativeGL_HelloRenderer_RenderGLStuff(JNIEnv * env, jobject obj, int width, int height, void * ptr)
{
    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &ptr);  
}

更新3 我已经更新了我的本地代码,现在我可以看到一块白色的区域代替图片,但是没有图片内容。有什么想法吗?

JNIEXPORT void JNICALL Java_mine_NativeGL_HelloRenderer_RenderGLStuff(JNIEnv * env, jobject obj, int width, int height, void * ptr)
{
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    GLfloat vertices[] = {  -1.0, 1.0,  1.0, 1.0,  -1.0, -1.0,   1.0, -1.0, }; 
    GLfloat normals[] =  {   0.0, 0.0, 1.0,   0.0, 0.0, 1.0,   0.0, 0.0, 1.0,   0.0, 0.0, 1.0 }; 
    GLfloat textureCoords[] = {   0.0, 0.0,   1.0, 0.0,   0.0, 1.0,   1.0, 1.0 }; 

    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &ptr);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  

    glBindTexture(GL_TEXTURE_2D, texture);
    glVertexPointer(2, GL_FLOAT, 0, vertices);
    glNormalPointer(GL_FLOAT, 0, normals);
    glTexCoordPointer(2, GL_FLOAT, 0, textureCoords);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrthof(-5.0, 5.0, -7.5, 7.5, -1, 1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity(); 

    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

你为什么不坚持使用常规的Android GL接口,而要做这些呢? - genpfault
我知道这很奇怪,但这是要求。事实上,这是整个过程的第一步,我无法实现。 - Haris Hasan
1个回答

3
你不能直接传递Java的Bitmap类指针并期望它能与glTexImage2D一起使用。glTexImage2D希望在指针中传递原始像素数据(实际上,你的JNI本地C函数声明看起来不正确,最后一个参数应该是jobject类型,而不是void *,请使用“javah”生成正确的JNI函数签名)。你需要使用bitmap.getPixels(..)或bitmap.copyPixelsToBuffer(..)调用从位图中获取数据,具体取决于您是否想要转换像素格式。要查看Java中的代码示例,请参考此处的代码:applying texture to Cube, different texture on each face of cube。ByteBuffer fcbuffer是保存原始像素数据的变量。您应该能够调用ByteBuffer.array()获取实际数据指针并将其向下传递给JNI。
编辑:要明确起见,RenderGLStuff应该有最后一个参数为byte[]类型,并且从JNI/C侧,您应该在传递的jbyteArray类型变量上调用GetByteArrayElements/ReleaseByteArrayElements。
编辑2:为了完全明确,我不确定您的限制是什么,但您还有其他解决纹理创建问题的方法:
- 您可以在Android端执行纹理生成调用(GLUtils.texImage2D可直接接受位图)。 - 您可以在本地端使用任何本地图像库从文件加载纹理。 - 如果您必须从Java传递Bitmap对象,则必须按照上述方法获取原始数据指针。
有关不同方法的详细讨论,请参见此线程:http://groups.google.com/group/android-ndk/browse_thread/thread/eaf038cc50d5041e/c5874712be5382cf
编辑3:我刚刚了解到还有另一种方法 - 按照你所做的方式传递位图对象,并使用jnigraphics库根据What is JNI Graphics or how to use it?中描述的方法获取对像素的原始访问权限。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接