Draw the cube with OpenGL ES 1.1

At this point, we've defined the data that represents our cube. In this part of the tutorial, we'll write the code that draws the cube on the screen using OpenGL ES 1.1.

If you're interested in learning how to draw the cube using OpenGL ES 2.0 instead, see Draw the cube with OpenGL ES 2.0.

Initialize the model

In initialize(), we obtain the EGL surface width and height by calling eglQuerySurface(), and we set the image depth value by calling glClearDepthf(). We also enable smooth shading of the model and allow polygons to be culled based on their window coordinates. We call glClearColor() to set the clear color (which is the color that's used when the color buffers are cleared) to black. By setting the clear color, when we call glClear(GL_COLOR_BUFFER_BIT), the screen is cleared to black. Then, we specify the size of the viewport through which we view the scene. We use glViewport() to set the viewport to the same size as the EGL surface. Some of these settings may differ from the template, so verify that your code appears as it does below.

int initialize() {
    EGLint surface_width, surface_height;

    eglQuerySurface(egl_disp, egl_surf, EGL_WIDTH, &surface_width);
    eglQuerySurface(egl_disp, egl_surf, EGL_HEIGHT, &surface_height);

    EGLint err = eglGetError();
    if (err != 0x3000) {
        fprintf(stderr, "Unable to query EGL surface dimensions\n");
        return EXIT_FAILURE;
    }

    glClearDepthf(1.0f);
    glEnable(GL_CULL_FACE);
    glShadeModel(GL_SMOOTH);

    //set clear color to black
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    glViewport(0, 0, surface_width, surface_height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

Next, we specify the projection matrix. We specify the near and far clipping planes, the vertical field of view, and the aspect ratio. Then we calculate the minimum and maximum horizontal and vertical values. We call glFrustumf() to perform a perspective projection. We scale the model and adjust the x- and y-axes for scaling depending on the surface width and height. Last, we set the current matrix to modelview and load the identity matrix.

    float nearClip = -2.0f;
    float farClip  = 2.0f;
    float yFOV  = 75.0f;
    float yMax = nearClip * tan(yFOV*M_PI/360.0f);
    float aspect = surface_width/surface_height;
    float xMin = -yMax * aspect;
    float xMax = yMax *aspect;

    glFrustumf(xMin, xMax, -yMax, yMax, nearClip, farClip);

    if (surface_width > surface_height)
    {
        glScalef((float)surface_height/(float)surface_width, 1.0, 1.0f);
    }
    else
    {
        glScalef(1.0, (float)surface_width/(float)surface_height, 1.0f);
    } 

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    return EXIT_SUCCESS;
} 

To use the M_PI constant, you need to verify that math.h is included:

#include <math.h>

Rotate the model

In our render() function in main.c, use glClear() to clear the color and depth buffers.

void render() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

Next, use glEnableClientState() to allow us to pass a vertex array (describing the geometry of our cube) and a color array (specifying the colors used on the sides of the cube).

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

Now, we specify the arrays of vertices and color values that we defined at the beginning of the tutorial for rendering the model.

    glVertexPointer(3, GL_FLOAT, 0, vertices);
    glColorPointer(4, GL_FLOAT, 0, colors);

The number 3 in the glVertexPointer() call indicates that each group of three values in the vertices array specifies a single vertex. Similarly, the number 4 in the glColorPointer() call indicates that each group of four values in the colors array indicates a single color value. If you don't know what the 0 means in the calls, just think of it as the default value for now.

Next, we call glRotatef() to rotate the cube, and then call glDrawArrays() to draw the triangles. Remember that our cube needs 36 vertices because we specified its geometry as a set of triangles.

We disable vertex and color array states, and then call bbutil_swap() to swap the window buffers. At this point, we've completed our render() function. Some of these settings may differ from the template, so verify that your code appears as it does below:

    glRotatef(1.0f, 1.0f, 1.0f, 0.0f);

    glDrawArrays(GL_TRIANGLES, 0, 36);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);

    //Use utility code to update the screen
    bbutil_swap();
}

Finally, in main(), we create the application loop so that the angle of our cube changes every time a frame is updated.

while (!exit_application) {
    // Request and process the next available
    // BlackBerry Platform Services (BPS) event
    bps_event_t *event = NULL;
    if (BPS_SUCCESS != bps_get_event(&event, 0)) {
        fprintf(stderr, "bps_get_event() failed\n");
    }

    if (event) {
        int domain = bps_event_get_domain(event);

        if (domain == screen_get_domain()) {
            handleScreenEvent(event);
        } else if ((domain == navigator_get_domain())
                    && (NAVIGATOR_EXIT == bps_event_get_code(event))) {
            exit_application = 1;
        }
    }

    render();
} 

We're finished! Build and run the app to see the result: your own multicolored rotating cube, created using OpenGL ES 1.1.

Device image showing the finished 3-D app.

Last modified: 2014-05-14



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus