iPhone Game Development - Chris Craft [132]
-0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
// Right Face
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
};
As you see, there are a good many more items in the array, but this is necessary to define all the vertices in the cube. There are different ways to define the faces, but for this example we wanted to stick with the same method for clarity.
Now from the previous example you will need to change the following line:
glVertexPointer(2, GL_FLOAT, 0, squareVertices);
Change the first parameter from a 2 to a 3 to indicate that the array of vertices contains X, Y, and Z coordinates instead of just X and Y, as seen in the following line of code:
glVertexPointer(3, GL_FLOAT, 0, squareVertices);
The next change is more significant. First, the array of vertex colors from the previous example is removed in favor of face colors. In the following code snippet, you see a call to glColor4f before the call to glDrawArrays. The glColor4f method defines the color of the next face that will be drawn. And of course, instead of having one call to glDrawArrays, you now have six calls, one for each face. Notice how the second parameter increases by a factor of 4 on each call. Since the vertexes are in one big array, this tells the method what index to start with:
glColor4f(1.0f, 0.0f, 0.0f, 1.0f); // red
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glColor4f(0.0f, 1.0f, 0.0f, 1.0f); // green
glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
glColor4f(0.0f, 0.0f, 1.0f, 1.0f); // blue
glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
glColor4f(1.0f, 1.0f, 0.0f, 1.0f); // yellow
glDrawArrays(GL_TRIANGLE_STRIP, 12, 4);
glColor4f(0.0f, 1.0f, 1.0f, 1.0f); // cyan
glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
glColor4f(1.0f, 0.0f, 1.0f, 1.0f); // magenta
glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);
If you have been making the changes manually, you can click Build and Run to see the output. You will notice that the cube has a strange effect as it rotates. This is caused by the back face of each of the squares showing in front of some of the front faces. To eliminate this problem, you need to enable back-face culling. Simply stated, back-face culling removes the back face of each of the squares, which results in the desired output. To enable this feature, you need to add the following lines of code after the method call glMatrixMode(GL_PROJECTION):
glMatrixMode(GL_PROJECTION);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
Finally, just for fun, we can start tracking finger swipes to rotate the cube. This is more interesting than just simply spinning the cube around a single axis. This is more of a challenge than you may realize because the orientation of the axis of the render buffer changes when it is rotated. Simply rotating around a static X or Y axis will not work. If you do this, the cube will spin in wild, unpredictable patterns. To achieve the desired result, you can use the following pattern.
First, make a copy of the current transform matrix of the render buffer. Next, reset the render buffer by loading the identity matrix. Now the axis is correct and you can perform your rotation. Finally, apply the transform matrix you saved in the first step to merge the results. Now you can see the cube react to your finger motions as expected. The following code illustrates this process:
glMatrixMode(GL_MODELVIEW);
// save model transform matrix
GLfloat currentModelMatrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, currentModelMatrix);
// clear the model transform matrix
glLoadIdentity();
// rotate the x and y axes of the model transform matrix
glRotatef(rotateX, 1.0f, 0.0f, 0.0f);
glRotatef(rotateY, 0.0f, 1.0f, 0.0f);
// slow down the spinning if it is spinning
[self decayRotation];
// reapply the previous transforms
glMultMatrixf(currentModelMatrix);
Now you can move the cube around and see all the faces with the flick of a finger (Figure 9.18).
FIGURE 9.18
Swipe the cube with your finger to change its orientation.