I am currently learning OpenGL (using Java / Android) and up until now every problem could be solved using a site called stackoverflow or google (you probably know both).
Up until now I only drew triangles (vertices with indices) using something like.
// some math here to calculate vertices and indices
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(COORDS_PER_VERTEX, GL10.GL_FLOAT, vertex_stride, vertex_buffer);
gl.glColor4f(color.r, color.g, color.b, color.a);
gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, index_buffer_size, GL10.GL_UNSIGNED_SHORT, index_buffer);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
vertex_buffer holding the verices and index_buffer holding the indices. This works, I can draw rectangles, circles, arrows, and other simple shapes
Now I wanted to add a Texture. I did follow this: https://examples.javacodegeeks.com/android/games/opengl-es/opengl-es-texture-mapping/
On its own it also works:
// once: bitmap to texture conversion
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
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);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
// do some math for the verices and the mapping
// always: drawing
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glVertexPointer(COORDS_PER_VERTEX, GL10.GL_FLOAT, vertex_stride, vertex_buffer);
gl.glTexCoordPointer(COORDS_PER_TEXTURE_COORD, GL10.GL_FLOAT, 0, texture_buffer);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, NUM_VERTICES);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
textures[0] holding the pointer to the texture, vertex_buffer again the vertices and texture_buffer the mapping of the texture to the vertices, bitmap holds a bitmap.
Now if I use both I find that openGL only drawes the textures. All simple shapes are not displayed. If I than put the App in the background and than into the foreground again, suddenly all simple shapes get displayed but the textures become rectangles filled with a random color (probably the color I draw a the last simple shape with). The result does not change if I draw the simple shapes first and than the textures or vice versa.
I am guessing that calling only
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
for the simple shapes and than both gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
and gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
for the textures somehow clashes.
Is there a way to to use both for the same "frame"?
Perhaps I need to configure something in openGL within the Render class?
class OpenGLRenderer implements GLSurfaceView.Renderer {
public OpenGLRenderer(Context c, int screen_width_px, int screen_height_px){
context = c;
this.screen_width_px = screen_width_px;
this.screen_height_px = screen_height_px;
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig egl_config){
gl10.glEnable(GL10.GL_TEXTURE_2D);
gl10.glShadeModel(GL10.GL_SMOOTH);
gl10.glClearColor(0.5f, 0.5f, 0.0f, 0.5f);
gl10.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
gl10.glEnable(GL10.GL_DEPTH_TEST);
}
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height){
screen_height_px = height;
screen_width_px = width;
GLES20.glViewport(0,0,width,height);
float ratio = (float) width / (float) height;
gl10.glMatrixMode(GL10.GL_PROJECTION);
gl10.glLoadIdentity();
float near = 1.0f;
float far = -zoom+1;
float bottom = -1.0f;
float top = 1.0f;
float left = -ratio;
float right = ratio;
gl10.glFrustumf(left , right , bottom, top, near, far);
}
@Override
public void onDrawFrame(GL10 gl10){
prepareFrame(gl10);
// HERE I would call all simple_shapes and Textures in two for loops
}
void prepareFrame(GL10 gl10){
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
gl10.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl10.glMatrixMode(GL10.GL_MODELVIEW);
gl10.glLoadIdentity();
gl10.glTranslatef(0.0f, 0.0f, zoom);
gl10.glEnable(GL10.GL_BLEND);
gl10.glEnable(GL10.GL_TEXTURE_2D);
gl10.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
}
}
I think that is all the relevant code. I dont know if it is apropriated to post a link to the (Github)project here but if requested I can make a branch and link it too.
Problem solved: In a nutshell I needed to enable 2DTexture gl10.glEnable(GL10.GL_TEXTURE_2D)
before drawing the texture, and disable it gl10.glDisable(GL10.GL_TEXTURE_2D)
afterwards. (I just enabled it.) For a detailed answer see the accepted Answer.
The problem that after moving the app into background and back to foreground, the textures vanish is unrelated. It was solved by calling the part below // once: bitmap to texture conversion (see second code sample) again. I guess the texture behnd textures[0] pointer gets deleted by moving th app into background.
OpenGL is a state engine. once a state is set, it is kept until it is changed again. At Legacy OpenGL 2 dimensional textureing has to be enabled by gl10.glEnable(GL10.GL_TEXTURE_2D);
. Once this state is set, it is kept. If 2 dimensional texturing is enabled and not texture coordinates are provided, then all the texture coordinates attributes of the mesh have to default value of (0, 0) and the texel of the currently bound texture at this coordinate is wrapped on the entire mesh.
You have to enable 2 dimensional texturing before before drawing a geometry with a texture:
gl10.glEnable(GL10.GL_TEXTURE_2D);
// draw mesh with texture
and you have to disable 2 dimensional texturing before before drawing a geometry without a texture:
gl10.glDisable(GL10.GL_TEXTURE_2D);
// draw mesh with color