Create a 3-D app
In the previous section, we used an OpenGL ES 1.1 sample project to get up and running with the QNX Momentics IDE. Now, we're going to use the code from that app and create a 3-D version. We want to use this sample for two reasons. The first is that the main.c file comes with a bunch of boilerplate OpenGL ES code that we can borrow from. The second is that this template includes a file called bbutil.c. The bbutil.c file contains a whole bunch of convenient functions that you can call from your application - functions for performing common tasks like initializing and terminating EGL, loading and rendering text and textures, and changing the screen orientation.
You will learn to:
- Create a 3-D, rotating, multicolored cube
- Configure your project
- Give the cube a home and show it off
Create the cube
Now that we're all set up, it's time to get started writing some code. Creating and coloring in cubes consists of two tasks: creating the cube and then coloring in its faces.
We'll start with the code that describes the geometry of the cube. If you were to sketch out a 3-D cube, you would notice that it has six sides and eight vertices:

Open main.c and replace the vertices[] array with the code below that declares a new array to store the cube's vertices. Remember to remove any array initialization code as well:
static const GLfloat vertices[] =
{
// front
-0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
// right
0.5f, 0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, -0.5f, -0.5f,
// back
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
// left
-0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,
// top
-0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
// bottom
-0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f
};Notice that there are more than eight vertices there. OpenGL ES 1.1 is designed to work with triangles. So, we are specifying each side of our cube as a pair of triangles, like this:

Each triangle is defined by three vertices. So we need 3 vertices per triangle x 2 triangles per side x 6 sides = 36 vertices.
Next, we specify a color for each side of the cube. These colors are defined per vertex and are in RGBA format. The A in RGBA refers to the alpha channel, which represents the transparency of the color. All of our colors are opaque, so each value ends with a 1.0. Here, we're using different shades of blue (for example, R=16, G=147, B=237 becomes 0.0625, 0.57421875, and 0.92578125, since these values are normalized to 256). So, in main.c, replace the colors[] array with the new code below. Again, remember to remove any array initialization code.
static const GLfloat colors[] =
{
/* front */
0.0625f,0.57421875f,0.92578125f,1.0f,
0.0625f,0.57421875f,0.92578125f,1.0f,
0.0625f,0.57421875f,0.92578125f,1.0f,
0.0625f,0.57421875f,0.92578125f,1.0f,
0.0625f,0.57421875f,0.92578125f,1.0f,
0.0625f,0.57421875f,0.92578125f,1.0f,
/* right */
0.29296875f,0.66796875f,0.92578125f,1.0f,
0.29296875f,0.66796875f,0.92578125f,1.0f,
0.29296875f,0.66796875f,0.92578125f,1.0f,
0.29296875f,0.66796875f,0.92578125f,1.0f,
0.29296875f,0.66796875f,0.92578125f,1.0f,
0.29296875f,0.66796875f,0.92578125f,1.0f,
/* back */
0.52734375f,0.76171875f,0.92578125f,1.0f,
0.52734375f,0.76171875f,0.92578125f,1.0f,
0.52734375f,0.76171875f,0.92578125f,1.0f,
0.52734375f,0.76171875f,0.92578125f,1.0f,
0.52734375f,0.76171875f,0.92578125f,1.0f,
0.52734375f,0.76171875f,0.92578125f,1.0f,
/* left */
0.0625f,0.57421875f,0.92578125f,1.0f,
0.0625f,0.57421875f,0.92578125f,1.0f,
0.0625f,0.57421875f,0.92578125f,1.0f,
0.0625f,0.57421875f,0.92578125f,1.0f,
0.0625f,0.57421875f,0.92578125f,1.0f,
0.0625f,0.57421875f,0.92578125f,1.0f,
/* top */
0.29296875f,0.66796875f,0.92578125f,1.0f,
0.29296875f,0.66796875f,0.92578125f,1.0f,
0.29296875f,0.66796875f,0.92578125f,1.0f,
0.29296875f,0.66796875f,0.92578125f,1.0f,
0.29296875f,0.66796875f,0.92578125f,1.0f,
0.29296875f,0.66796875f,0.92578125f,1.0f,
/* bottom */
0.52734375f,0.76171875f,0.92578125f,1.0f,
0.52734375f,0.76171875f,0.92578125f,1.0f,
0.52734375f,0.76171875f,0.92578125f,1.0f,
0.52734375f,0.76171875f,0.92578125f,1.0f,
0.52734375f,0.76171875f,0.92578125f,1.0f,
0.52734375f,0.76171875f,0.92578125f,1.0f
};Next, in initialize(), we do a bit of setup work. We set the depth value and color that the screen will be cleared to using glClearDepthf() and glClearColor(). Then we specify the size of the window or viewport through which we view the scene. We use glViewport() to set the viewport to the same size as the screen. Go ahead and replace the code in the sample with the new code below.
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();
Now that you have a cube to show off, you have to give it a home so that the world can see it!
Continuing with initialize(), we specify the projection matrix by doing a bit of trigonometry and using glFrustumf(). We specify the near and far clipping planes, the vertical field of view, and the aspect ratio. Then we calculate minimum and maximum horizontal and vertical values.
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();For the M_PI constant, you'll need to include math.h:
#include <math.h>
Next, we need to update our render() function in main.c. You'll see the complete updated function below, but we'll walk you through it a bit now. In this function, use glClear() to clear the color and depth buffers.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Next, we let OpenGL know that we want to specify a vertex array to describe the geometry of our cube and a color array to specify the colors used on the sides of the cube.
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY);
After setting up how we want things to look, we should probably have something to look at. We tell OpenGL to use those matrices of vertices and color values that we defined at the beginning of the tutorial.
glVertexPointer(3, GL_FLOAT, 0, vertices); glColorPointer(4, GL_FLOAT, 0, colors);
The 3 in the glVertexPointer() call indicates that each group of three values in the vertices array specifies a single vertex. Similarly, the 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, don't worry about it yet. Just think of it as the default value.
Next, we call glRotatef() to rotate the cube, then call glDrawArrays() to tell OpenGL to draw the triangles. Remember that our representation required 36 vertices and that was because we specified the geometry as a set of triangles. This leaves us with a complete render() function below. Go ahead and update the sample with this new function.
void render()
{
//Typical render pass
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, 0, colors);
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. This will cause the angle of our cube to change during every frame update.
while (!exit_application) {
//Request and process BPS next available 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();
}
After all of that, you are now the proud owner of your very own multicolored rotating cube! Of course, we aren't exactly making the GPU sweat with this masterpiece, but it's a start. Go ahead and build and run your app on a simulator or device.