Animation in OpenGL for Game Programming using SDL

Animation is the backbone of immersive experience in any game. This applies to both 2-D and 3-D games without exception. Hence, in order to create a seamless and immersive game environment, one must first understand the whys and wherefores of animation. One of the advantages that OpenGL has over other graphics and gaming toolkits is that in OpenGL, animation APIs are not low-level.

In other words, the APIs of OpenGL follow the nomenclature of trigonometry and motion used by physics and mathematics. It also means having a good base in math (especially co-ordinate geometry and trigonometry) and physics is also a requirement.

Therefore, in this discussion the first two sections will focus on the basic coordinate geometry essential for understanding animation APIs. In the third section, I will focus on the core APIs and techniques for animation and the four section will be used to demonstrate the basic animation in action. These are the issues to be discussed in this article.

2D/3D Prerequisites: the Basics

The basis of animation is performing either rotation or translation without stopping. In other words if either rotation or translation is done continuously, the resulting effect is animation. But before going into details of these operations, let me give you a quick overview of common terminology and concepts used in co-ordinate geometry. The most common terminology and concepts in 2-D as well as 3-D are:

• Origin
• Axes
• Coordinate Spaces
• Transformations

Of these, the first three are the founding concepts of 2-D/3-D whereas the fourth is the basis of all the operations in 2 as well as 3-D effects. Let’s have a look at them.

Origin is the center of the coordinate system in every Cartesian coordinate space. This is true for both 2-D as well as 3-D. It is a special location. If the coordinate space is thought to be a city with square boundaries, then the origin would be the center of the city.

As for axes, every 2-D Cartesian space has two straight lines that pass through the origin. Each line is known as axis and extends indefinitely in opposite directions. Both of them are opposite to each other. These two axes are named the x-axis (the horizontal axis) and the y-axis (the vertical axis).

When the coordinate system is extended to 3-D space, then a third axis comes into the picture, named the z-axis. One thing to keep in mind is that in 3-D space, a plane can be defined by a pair of axes. For example the plane defined by x-axis and y-axis is the xy-plane;  it is perpendicular to the z-axis. Pictorially it looks like this:

The positive and negative position of an axis is based on the coordinate system, which I will be describing next.

{mospagebreak title=The Basics Continued: Coordinate Spaces}

As already mentioned in the previous section, each axis extends to the opposite direction infinitely. The part of the x-axis starting from the origin and extending toward the right is the positive x-axis, and the portion that extends toward the left is the negative x-axis. Similarly in the case of the y-axis, the part extending toward the top is designated positive whereas the other part is designated negative. This is true for all the possible spatial directions in 2-D. But in the case of 3-D, matters are different. In 3-D the vertical and the horizontal can be interchanged. Hence the two types of coordinate space rules have come into play. One concerns the left-hand coordinate space, while the other covers the right-hand coordinate space.

To find the left-hand coordinate space, with your left hand, make an L with your thumb and index finger such that the thumb is pointing toward the right and your index finger is pointing straight up, and your third finger is pointing inwards. What we get is a Left-Hand Coordinate Space. The thumb, the index finger and the third finger point to the +x, +y and +z directions, respectively.

If you repeat this procedure with your right hand, with your index finger pointing straight up, your thumb pointing toward the left and your third finger pointing inwards, then we get a Right-Hand Coordinate Space. Again the thumb, the index and the third finger point to +x, +y and +z directions.

Now for the fourth important concept: transformations. A transformation is a process that changes graphics objects from one state to another. The state can be any property of the object from coordinates to the color and texture. There are three basic transformations: rotation, translation and shearing. Of these rotation and translation are most commonly used. And these two form the basis of animation as well.

One important point to keep in mind about any kind of transformation is that all transformations are defined by a matrix. The best example is an Identity Matrix, which represents the Identity Transform. The Identity Transform, in essence, does nothing. I will cover more about transformation and matrix in the next part of the series.

Now that terminology and concepts have been discussed we can move on to the topics of immediate interest in animation — rotation and translation.

Rotation, by definition, is "a transformation in which the coordinate axes are rotated by a fixed angle about the origin." In other words it is a transformation that shifts a graphic object around an axis. When the shifting is done continuously such that once the object reaches its initial position, the whole process is started all over again, the object is said to be animated. Since the shifting is done around the axis, the change of position is measured in Θ or degrees. Rotation can be clockwise or anti-clockwise. As the value of Θ decreases, the speed of rotation increases. Rotation around either the  x-,y- or z- axis is called principal rotation.

Translation, by definition, is the "Motion of a body in which every point of the body moves parallel to and the same distance as every other point of the body." In other words translation means linear movement along one or both axes. To compare, in rotation the object is shifted around one or more axes whereas in translation the object is shifted along one or more axes. Since the shift corresponds to the displacement along the axes, it is measured in Δ. In this case there is no requirement that the shift should, in the end, result in reaching the original position to have animation.

Pictorially rotation and translation can be viewed as:

That’s all you need to know about concepts for this part. In the next section I will discuss how to use these concepts along with the OpenGL APIs to create basic animation.

{mospagebreak title=Animation APIs in OpenGL}

In OpenGL there are two functions that correspond to rotation and translation. They are:

• glRotate*()
• glTranslate*()

The * indicates that there is more than one form of the function. In the case of the above functions there are two — one with decimal parameters having d instead of * and the float version having f instead of *. Let’s get down to details:

glRotate*() is a function that rotates an object at the angle specified around specified axes. It terms of a matrix it "computes a matrix that performs a counterclockwise rotation of angle degrees about the vector from the origin through the point (x, y, z)." For the time being it is sufficient to understand that the rotation takes place according to the degrees specified for the axis given. The parameters are the angle through which the object has to be rotated and all the axes. The axes around which the rotation is to take place are given a value of 1 and others are given a 0. For example, if an object has to be rotated 10 degrees around the y-axis, then the statement would be

glRotatef(10.0f,0,1,0);

One important point about glRotate*() is that it follows the right-hand coordinate space rule; hence if the axis points towards the user, then the rotation would be counter-clockwise.

glTranslate*() moves the object to the point specified by (x, y, z) passed as parameters, from the current coordinates. In terms of a matrix, "The current matrix is multiplied by this translation matrix, with the product replacing the current matrix." The distance to be moved is either positive or negative according to the parameters passed. For example, to move an object 2 units along the x-axis, the statement would be

glTranslatef(1.0f,0.0f,0.0f);

By setting the value of the x, y or z parameter to the required number of units, the object can be moved that many units parallel to the axis having a value greater or smaller than 0.

Though the above APIs form the basis of animation, they cannot animate an object by themselves. It is here that logic comes into picture. Let’s see how to achieve it in the next section.

{mospagebreak title=Animation: a Basic Example}

The framework developed in the last part will become the testing ground for all the concepts in SDL and OpenGL. So let’s use it for animating the triangle created to test the framework. This time only two functions of the framework will have to be used: Initialize() and Draw3D().

First Initialize():

bool Initialize(void) // Any Application & User Initialization Code Goes Here
{
AppStatus.Visible= true;     // At The Beginning, Our App Is Visible
AppStatus.MouseFocus= true;  // And Have Both Mouse
AppStatus.KeyboardFocus = true;// And Input Focus

// Start Of User Initialization. These are just examples
angle = 0.0f; // Set The Starting Angle To Zero

{
return false;
}

return true;
// Return TRUE (Initialization Successful)
}

Angle is a global variable of type float. The only functionality of the Initialize function is to set the initial value of the angle to 0.0f. The logic of animation is completely in the Draw3D() function. The following is the code tested in the last part:

void Draw3D(SDL_Surface *S)      // OpenGL drawing code here
{

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// clear screen and
// depth buffer. Screen color has been cleared
// at init

// reset the modelview matrix

glBegin(GL_TRIANGLES);
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();

glFlush();
// flush the gl rendering pipelines

return;

}

To animate the triangle, the first step is to add the glRotate() before the glBegin() function with the parameters being angle as the first parameter, and 1.0f as the second parameter because the triangle has to be rotated around the y-axis:

void Draw3D(SDL_Surface *S)        // OpenGL drawing code here
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// clear screen and
// depth buffer. Screen color has been cleared
// at init

glRotatef(angle,0.0f,1.0f,0.0f);
// Rotate The Triangle On The Y axis
// reset the modelview matrix

glBegin(GL_TRIANGLES);
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);

glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();
glFlush();
// flush the gl rendering pipelines

return;
}

To animate the triangle, the rotation should continue. That means the value of the angle has to be increased continuously. That is done after the glEnd() function.

void Draw3D(SDL_Surface *S)        // OpenGL drawing code here
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// clear screen and

// depth buffer. Screen color has been cleared
// at init

glRotatef(angle,0.0f,1.0f,0.0f);// Rotate The Triangle On The Y axis

//  reset the modelview matrix

glBegin(GL_TRIANGLES);
glVertex3f( 0.0f, 1.0f, 0.0f);

glVertex3f(-1.0f,-1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);

glEnd();

angle+=1.0f;
glFlush();
// flush the gl rendering pipelines

return;
}

What happens in essence is that Draw3D is called continuously until a quit message is posted. So the value of the angle is increased at the end of calling  the Draw3D() function. So next time when the glRotatef() is called the new angle value is received. And the new θ value then rotates the triangle created. That’s all. The following image is what one gets.

The triangle is colored. The method to add color to the object as well as advanced coordinate mathematics including matrix and vector operations will be covered in the next part. So till next timeā¦