I need to put 2 textures on the same Square, but it keeps crashing when i run the app. What should i do? Do i have to use 2 different “context” variables? Do I have to make 2 instances of the Square class (one for each texture)?
My Renderer:
public class HelloOpenGLES10Renderer implements Renderer {
private Square square; // the square
private Context context;
private Context context2;
/** Constructor to set the handed over context */
public HelloOpenGLES10Renderer(Context context) {
this.square = new Square();
this.context=context;
this.context2=context2;
}
public void onDrawFrame(GL10 gl) {
// clear Screen and Depth Buffer
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Reset the Modelview Matrix
gl.glLoadIdentity();
// Drawing
gl.glTranslatef(0.0f, 0.0f, -5.0f); // move 5 units INTO the screen
square.loadGLTexture(gl, this.context,Square.getSex());
square.loadGLTexture(gl, this.context2,Square.getHair()); // is the same as moving the camera 5 units away
square.draw(gl); // Draw the triangle
}
I didn’t post my onsurfacechanged and onsurfacecreated.
My Square class:
public class Square {
private FloatBuffer vertexBuffer; // buffer holding the vertices
private static int sex=2130837504;
private static int hair=2130837511;
private FloatBuffer textureBuffer;
private FloatBuffer textureBuffer2;// buffer holding the texture coordinates
private float texture[] = {
// Mapping coordinates for the vertices
0.0f, 1.0f, // top left (V2)
0.0f, 0.0f, // bottom left (V1)
1.0f, 1.0f, // top right (V4)
1.0f, 0.0f // bottom right (V3)
};
private float texture2[] = {
// Mapping coordinates for the vertices
0.0f, 0.5f, // top left (V2)
0.0f, 0.0f, // bottom left (V1)
0.5f, 0.5f, // top right (V4)
0.5f, 0.0f // bottom right (V3)
};
private float vertices[] = {
-1.0f, -2.0f, 0.0f, // V1 - bottom left
-1.0f, 2.0f, 0.0f, // V2 - top left
0.8f, -2.0f, 0.0f, // V3 - bottom right
0.8f, 2.0f, 0.0f // V4 - top right
};
public Square() {
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
vertexBuffer = byteBuffer.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
byteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
textureBuffer = byteBuffer.asFloatBuffer();
textureBuffer.put(texture);
textureBuffer.position(0);
byteBuffer = ByteBuffer.allocateDirect(texture2.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
textureBuffer2 = byteBuffer.asFloatBuffer();
textureBuffer2.put(texture2);
textureBuffer2.position(0);
}
/** The draw method for the square with the GL context */
public void draw(GL10 gl) {
// bind the previously generated texture
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
// Point to our buffers
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// Set the face rotation
gl.glFrontFace(GL10.GL_CW);
// Point to our vertex buffer
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
// Draw the vertices as triangle strip
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
/** The texture pointer */
private int[] textures = new int[1];
public void loadGLTexture(GL10 gl, Context context,int sex ) {
// loading texture
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
sex);
// generate one texture pointer
gl.glGenTextures(1, textures, 0);
// ...and bind it to our array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
// create nearest filtered texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
// Use Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
// Clean up
bitmap.recycle();
}
public void loadGLTextureHair(GL10 gl, Context context,int hair ) {
// loading texture
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
sex);
// generate one texture pointer
gl.glGenTextures(1, textures, 0);
// ...and bind it to our array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
// create nearest filtered texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
// Use Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
// Clean up
bitmap.recycle();
}
public static int getSex() {
return sex;
}
public static void setSex(int sex) {
Square.sex = sex;
}
public static int getHair() {
return hair;
}
public static void setHair(int hair) {
Square.hair = hair;
}
}
LogCat:
06-26 10:15:10.320: D/dalvikvm(280): GC_EXTERNAL_ALLOC freed 923 objects / 64552 bytes in 83ms
06-26 10:15:10.921: D/libEGL(280): egl.cfg not found, using default config
06-26 10:15:10.921: D/libEGL(280): loaded /system/lib/egl/libGLES_android.so
06-26 10:15:11.260: I/ARMAssembler(280): generated scanline__000001B7:030101C1_00009501_00000000 [142 ipp] (234 ins) at [0x23a918:0x23acc0] in 5769170 ns
06-26 10:15:13.170: W/KeyCharacterMap(280): No keyboard for id 0
06-26 10:15:13.170: W/KeyCharacterMap(280): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
06-26 10:15:29.020: D/dalvikvm(312): GC_EXTERNAL_ALLOC freed 945 objects / 65408 bytes in 72ms
06-26 10:15:29.560: D/libEGL(312): egl.cfg not found, using default config
06-26 10:15:29.570: D/libEGL(312): loaded /system/lib/egl/libGLES_android.so
06-26 10:15:29.860: I/ARMAssembler(312): generated scanline__000001B7:030101C1_00009501_00000000 [142 ipp] (234 ins) at [0x23a830:0x23abd8] in 2951633 ns
06-26 10:15:54.629: W/KeyCharacterMap(312): No keyboard for id 0
06-26 10:15:54.639: W/KeyCharacterMap(312): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
06-26 11:21:50.350: D/dalvikvm(344): GC_EXTERNAL_ALLOC freed 967 objects / 66264 bytes in 75ms
06-26 11:21:50.950: D/libEGL(344): egl.cfg not found, using default config
06-26 11:21:50.950: D/libEGL(344): loaded /system/lib/egl/libGLES_android.so
06-26 11:21:51.290: I/ARMAssembler(344): generated scanline__000001B7:030101C1_00009501_00000000 [142 ipp] (234 ins) at [0x23a830:0x23abd8] in 12307152 ns
06-26 11:22:01.749: W/KeyCharacterMap(344): No keyboard for id 0
06-26 11:22:01.749: W/KeyCharacterMap(344): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
06-26 11:48:39.200: D/dalvikvm(371): GC_EXTERNAL_ALLOC freed 989 objects / 67120 bytes in 69ms
06-26 11:48:39.750: D/libEGL(371): egl.cfg not found, using default config
06-26 11:48:39.759: D/libEGL(371): loaded /system/lib/egl/libGLES_android.so
06-26 11:48:40.079: W/dalvikvm(371): threadid=7: thread exiting with uncaught exception (group=0x4001d800)
06-26 11:48:40.109: E/AndroidRuntime(371): FATAL EXCEPTION: GLThread 8
06-26 11:48:40.109: E/AndroidRuntime(371): java.lang.NullPointerException
06-26 11:48:40.109: E/AndroidRuntime(371): at hello.project.Square.loadGLTexture(Square.java:96)
06-26 11:48:40.109: E/AndroidRuntime(371): at hello.project.HelloOpenGLES10Renderer.onDrawFrame(HelloOpenGLES10Renderer.java:34)
06-26 11:48:40.109: E/AndroidRuntime(371): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1332)
06-26 11:48:40.109: E/AndroidRuntime(371): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1116)
06-26 11:48:42.879: I/Process(371): Sending signal. PID: 371 SIG: 9
I am almost certain that you get the
NullPointerExceptionbecause theBitmapFactorycannot find the resource id you specify, so theBitmapbecomesnull, and thus throws an exception when you try torecycle()it.Instead of using the ids as static vars as you do (
private static int sex=2130837504;), you should get the values from the generatedRclass:BitmapFactory.decodeResource(context.getResources(), R.drawable.sex);.Apart from that you have some beginner problems with your code:
You only need one
Contextobject.You don’t need two different methods for loading the textures (
loadGLTextureHair(which has another error, it should use the parameter hair, not sex) andloadGLTexture):You should call this method from your
onSurfaceCreated()method, if you call it fromonDrawFrame()it will load a new texture every frame, and you will run out of memory.To switch between textures, use the
glBindTexture()method.3. Since you don’t save the value in textures[] somewhere else, it is overwritten next time you load a texture.
These are the most obvious errors that I can see, if you fix them, your program should at least run. Keep reading lots of tutorials and examples until you got it 🙂