Game Development 20 min read

Practical Guide to Texture Mapping in OpenGL ES on Android: Passing Bitmap to Native Layer and Rendering

This tutorial explains how to transfer a Bitmap from Java to the native layer using the NDK, retrieve its pixel data with jnigraphics, create and configure an OpenGL texture, set up vertex and fragment shaders with proper texture coordinates, handle Y‑axis flipping on Android, and finally blend multiple textures for advanced rendering effects.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Practical Guide to Texture Mapping in OpenGL ES on Android: Passing Bitmap to Native Layer and Rendering

The article begins by reminding readers of the theoretical background of texture mapping covered in a previous post and then moves to practical implementation, showing how to pass a Bitmap from the Android Java layer to native C++ code using the NDK.

In the Java side, a Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.liyingai)).getBitmap(); is obtained, and a native method public native void drawTexture(Bitmap bitmap, Object surface); is declared. The corresponding native function signature is Java_com_example_openglstudydemo_YuvPlayer_drawTexture(JNIEnv *env, jobject thiz, jobject bitmap, jobject surface) .

Inside the native code, the jnigraphics library is used. First, AndroidBitmap_getInfo(env, bitmap, &bmpInfo) retrieves basic bitmap information such as width, height, stride, format, and flags. Then void *bmpPixels; AndroidBitmap_lockPixels(env, bitmap, &bmpPixels); locks the pixel memory and provides a pointer to the pixel array.

After obtaining the pixel data, an OpenGL texture object is created and configured:

unsigned int texture1;
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
// Texture wrapping
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Texture filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Upload pixel data
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bmpInfo.width, bmpInfo.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bmpPixels);

The vertex data now includes texture coordinates, e.g.:

float vertices[] = {
    // positions        // tex coords
    0.5f, 0.5f, 0.0f,   1.0f, 1.0f,
    0.5f, -0.5f, 0.0f,  1.0f, 0.0f,
    -0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
    -0.5f, 0.5f, 0.0f,  0.0f, 1.0f
};

Vertex and fragment shaders are updated to receive and use the texture coordinates. The vertex shader passes the coordinates to the fragment shader, applying a Y‑axis flip for Android’s texture origin:

#version 300 es
layout (location = 0) in vec4 aPosition;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
void main() {
    gl_Position = aPosition;
    TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
}
#version 300 es
precision mediump float;
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D ourTexture;
void main() {
    FragColor = texture(ourTexture, TexCoord);
}

Because Android’s texture coordinate origin is at the top‑left, the Y component is inverted before passing it to the fragment shader, fixing the upside‑down rendering issue.

To demonstrate multi‑texture blending, a second texture is created similarly, and both textures are bound to different texture units (GL_TEXTURE0 and GL_TEXTURE1). Uniforms are set with glUniform1i(glGetUniformLocation(program, "ourTexture"), 0); and glUniform1i(glGetUniformLocation(program, "ourTexture1"), 1); . The fragment shader then mixes the two textures:

#version 300 es
precision mediump float;
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D ourTexture;
uniform sampler2D ourTexture1;
void main() {
    FragColor = mix(texture(ourTexture, TexCoord), texture(ourTexture1, TexCoord), 0.5);
}

Finally, the article summarizes that the tutorial covered passing a bitmap to native code, extracting pixel data, creating and configuring OpenGL textures, handling texture coordinates on Android, and blending multiple textures, providing a solid foundation for more advanced graphics effects.

ShaderAndroid NDKGraphics ProgrammingTexture MappingOpenGL ESMulti-Texture
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.