Ben D
Ben D

Reputation: 77

OpenGL ES 2.0 in Android NDK: Nothing being drawn

I have a 2D game project that I'm porting to Android that utilizes OpenGL ES 2.0. I am having trouble getting anything drawn on the screen (except for a solid color from clearing the screen). Everything renders just fine when running in my Windows environment, but of course the environment is set up differently for the different version of OpenGL.

I followed the native-activity sample and took advice from several other OpenGL ES 2.0 resources to compose what I currently have.

I have checked everything I know how to with no anomalous results. As mentioned, glClear works, and displays the color set by glClearColor. I also know that every frame is being rendered, as changing glClearColor frame-by-frame displays the different colors. Of course, the application properly compiles. My textures are loaded from the proper location in the app's cache. glGetError is returning GL_NO_ERROR at every step in the process, so what I am doing appears to be accepted by OpenGL. My shaders are loaded without error. I have also tested this on both a few emulators and my physical android device, so it isn't localized to a specific device configuration.

I speculate that it must be some mistake in how I initialize and set up OpenGL. I am hoping someone more versed in OpenGL ES than I am will be able to help root out my problem. I am pasting the different relevant sections of my code below. engine is a global struct I am presently using out of laziness.

Initializing the display

static int AND_InitDisplay() {

    // Desired display attributes
    const EGLint attribs[] = {
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_BLUE_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_RED_SIZE, 8,
            EGL_ALPHA_SIZE, 8,
            EGL_DEPTH_SIZE, 16,
            EGL_NONE
    };
    EGLint w, h, dummy, format;
    EGLint numConfigs;
    EGLConfig config;
    EGLSurface surface;
    EGLContext context;

    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(display, 0, 0);
    eglChooseConfig(display, attribs, &config, 1, &numConfigs);
    eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);

    ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);

    surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);

    EGLint const attrib_list[3] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
    context = eglCreateContext(display, config, NULL, attrib_list);

    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
        LOGW("Unable to eglMakeCurrent");
        return -1;
    }

    eglQuerySurface(display, surface, EGL_WIDTH, &w);
    eglQuerySurface(display, surface, EGL_HEIGHT, &h);

    engine->display = display;
    engine->context = context;
    engine->surface = surface;
    engine->width = w;
    engine->height = h;

    // Initialize GL state.
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    return 0;
}

Drawing a frame

static void AND_drawFrame() {
    if (engine->display == NULL) {
        LOGW("DB E: DISPLAY IS NULL");
        // No display.
        return;
    }

    // Clearing with red color. This displays properly.
    glClearColor(1.f, 0.f, 0.f, 1.f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // eglSwapBuffers results in no visible change
    eglSwapBuffers(engine->display, engine->surface);
}

Example of preparing VBO data

I understand many wouldn't like the idea of using multiple VBOs for the same geometry. I would love to hear if this code isn't orthodox or is incorrect, but I am not focused on this unless it the root of my problem.

GLfloat charPosVerts[] = {

    p0.x, p0.y, 0.f,
    p1.x, p0.y, 0.f,
    p1.x, p1.y, 0.f,

    p0.x, p0.y, 0.f,
    p1.x, p1.y, 0.f,
    p0.x, p1.y, 0.f
};

GLfloat charTexVerts[] = {
    0.0, 0.0,
    textures[texid].w, 0.0,
    textures[texid].w, textures[texid].h,

    0.0, 0.0,
    textures[texid].w, textures[texid].h,
    0.0, textures[texid].h
};

GLfloat charColorVerts[] = {
    e->color.r, e->color.g, e->color.b, e->color.a,
    e->color.r, e->color.g, e->color.b, e->color.a,
    e->color.r, e->color.g, e->color.b, e->color.a,

    e->color.r, e->color.g, e->color.b, e->color.a,
    e->color.r, e->color.g, e->color.b, e->color.a,
    e->color.r, e->color.g, e->color.b, e->color.a
};

glGenBuffers(1, &(e->vboPos));
glGenBuffers(1, &(e->vboTex));
glGenBuffers(1, &(e->vboColor));

glBindBuffer(GL_ARRAY_BUFFER, e->vboPos);
glBufferData(GL_ARRAY_BUFFER, sizeof(charPosVerts), charPosVerts, GL_DYNAMIC_DRAW);
glVertexAttribPointer(shaderIDs.attribPosition, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(shaderIDs.attribPosition);

glBindBuffer(GL_ARRAY_BUFFER, e->vboTex);
glBufferData(GL_ARRAY_BUFFER, sizeof(charTexVerts), charTexVerts, GL_DYNAMIC_DRAW);
glVertexAttribPointer(shaderIDs.attribTexCoord, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(shaderIDs.attribTexCoord);

glBindBuffer(GL_ARRAY_BUFFER, e->vboColor);
glBufferData(GL_ARRAY_BUFFER, sizeof(charColorVerts), charColorVerts, GL_DYNAMIC_DRAW);
glVertexAttribPointer(shaderIDs.attribColors, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(shaderIDs.attribColors);

Example of drawing VBO

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, CORE_GetBmpOpenGLTex(texix));
glUniform1i(shaderIDs.uniTexture, 0);

// Draw the sprite
glBindBuffer(GL_ARRAY_BUFFER, e->vboPos);
glVertexAttribPointer(shaderIDs.attribPosition, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(shaderIDs.attribPosition);

glBindBuffer(GL_ARRAY_BUFFER, e->vboTex);
glVertexAttribPointer(shaderIDs.attribTexCoord, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(shaderIDs.attribTexCoord);

glBindBuffer(GL_ARRAY_BUFFER, e->vboColor);
glVertexAttribPointer(shaderIDs.attribColors, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(shaderIDs.attribColors);

glDrawArrays(GL_TRIANGLES, 0, 18);

Vertex Shader

The shaders are very simple.

attribute vec3 position;
attribute vec2 texCoord;
attribute vec4 colors;

varying vec2 texCoordVar;
varying vec4 colorsVar;

void main() {
    gl_Position = vec4(position, 1.0);
    texCoordVar = texCoord;
    colorsVar = colors;
}

Fragment Shader

uniform sampler2D texture;

varying vec2 texCoordVar;
varying vec4 colorsVar;

void main()
{
    gl_FragColor = texture2D(texture, texCoordVar) * colorsVar;
}

Thanks for looking at this long post. Help is very much appreciated.

Upvotes: 1

Views: 1368

Answers (1)

Reto Koradi
Reto Koradi

Reputation: 54592

The posted code is not drawing anything. From the AND_drawFrame() function:

// Clearing with red color. This displays properly.
glClearColor(1.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// eglSwapBuffers results in no visible change
eglSwapBuffers(engine->display, engine->surface);

Based on this, the draw code is either never invoked, or the window is cleared after drawing, which would wipe out everything that was drawn before.

Upvotes: 3

Related Questions