if (texture->imageData!=NULL) // Was Image Data Loaded
free(texture->imageData); // If So, Release The Image Data
fclose(file); // Close The File
return FALSE; // Return False
}
for(GLuint i=0; i<int(imageSize); i+=bytesPerPixel) // Loop Through The Image Data
{ // Swaps The 1st And 3rd Bytes ('R'ed and 'B'lue)
temp=texture->imageData[i]; // Temporarily Store The Value At Image Data 'i'
texture->imageData[i] = texture->imageData[i + 2]; // Set The 1st Byte To The Value Of The 3rd Byte
texture->imageData[i + 2] = temp; // Set The 3rd Byte To The Value In 'temp' (1st Byte Value)
}
fclose (file); // Close The File
// Build A Texture From The Data
glGenTextures(1, &texture[0].texID); // Generate OpenGL texture IDs
glBindTexture(GL_TEXTURE_2D, texture[0].texID); // Bind Our Texture
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Linear Filtered
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtered
if (texture[0].bpp==24) // Was The TGA 24 Bits
{
type=GL_RGB; // If So Set The 'type' To GL_RGB
}
glTexImage2D(GL_TEXTURE_2D, 0, type, texture[0].width, texture[0].height, 0, type, GL_UNSIGNED_BYTE, texture[0].imageData);
return true; // Texture Building Went Ok, Return True
}
The 2D texture font code is the same code I have used in previous tutorials. However, there are a few small changes. The thing you will notice is that we are only generating 95 display lists. If you look at the font texture, you will see there are only 95 characters counting the space at the top left of the image. The second thing you will notice is we divide by 16.0f for cx and we only divide by 8.0f for cy. The reason we do this is because the font texture is 256 pixels wide, but only half as tall (128 pixels). So to calculate cx we divide by 16.0f and to calculate cy we divide by half that (8.0f).
If you do not understand the code below, go back and read through Lesson 17. The font building code is explained in detail in lesson 17!
GLvoid BuildFont(GLvoid) // Build Our Font Display List
{
base=glGenLists(95); // Creating 95 Display Lists
glBindTexture(GL_TEXTURE_2D, textures[9].texID); // Bind Our Font Texture
for (int loop=0; loop<95; loop++) // Loop Through All 95 Lists
{
float cx=float(loop%16)/16.0f; // X Position Of Current Character
float cy=float(loop/16)/8.0f; // Y Position Of Current Character
glNewList(base+loop,GL_COMPILE); // Start Building A List
glBegin(GL_QUADS); // Use A Quad For Each Character
glTexCoord2f(cx, 1.0f-cy-0.120f); glVertex2i(0,0); // Texture / Vertex Coord (Bottom Left)
glTexCoord2f(cx+0.0625f, 1.0f-cy-0.120f); glVertex2i(16,0); // Texutre / Vertex Coord (Bottom Right)
glTexCoord2f(cx+0.0625f, 1.0f-cy); glVertex2i(16,16); // Texture / Vertex Coord (Top Right)
glTexCoord2f(cx, 1.0f-cy); glVertex2i(0,16); // Texture / Vertex Coord (Top Left)
glEnd(); // Done Building Our Quad (Character)
glTranslated(10,0,0); // Move To The Right Of The Character
glEndList(); // Done Building The Display List
} // Loop Until All 256 Are Built
}
The printing code is the code is also from lesson 17, but has been modified to allow us to print the score, level and morale to the screen (variables that continually change).
GLvoid glPrint(GLint x, GLint y, const char *string, …) // Where The Printing Happens
{
char text[256]; // Holds Our String
va_list ap; // Pointer To List Of Arguments
if (string == NULL) // If There's No Text
return; // Do Nothing
va_start(ap, string); // Parses The String For Variables
vsprintf(text, string, ap); // And Converts Symbols To Actual Numbers
va_end(ap); // Results Are Stored In Text
glBindTexture(GL_TEXTURE_2D, textures[9].texID); // Select Our Font Texture
glPushMatrix(); // Store The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
glTranslated(x,y,0); // Position The Text (0,0 – Bottom Left)
glListBase(base-32); // Choose The Font Set
glCallLists(strlen(text), GL_UNSIGNED_BYTE, text); // Draws The Display List Text
glPopMatrix(); // Restore The Old Projection Matrix
}
This code will be called later in the program by qsort. It compares the distance in two structures and return –1 if the first structures distance was less than the seconds structures distance, 1 if the first structures distance is greater than the second structures distance and 0 if the distance is the same in both structures.
int Compare(struct objects *elem1, struct objects *elem2) // Compare Function *** MSDN CODE MODIFIED FOR THIS TUT ***
{
if (elem1->distance < elem2->distance) // If First Structure distance Is Less Than The Second
return –1; // Return –1
else if (elem1->distance > elem2->distance) // If First Structure distance Is Greater Than The Second
return 1; // Return 1
else // Otherwise (If The distance Is Equal)
return 0; // Return 0
}
The InitObject() code is where we set up each object. We start off by setting rot to 1. This gives the object clockwise rotation. Then we set the explosion animation to frame 0 (we don't want the explosion to start halfway through the animation). Next we set hit to FALSE, meaning the object has not yet been hit or set to self destruct. To select an object texture, texid is assigned a random value from 0 to 4. Zero is the blueface texture and 4 is the vase texture. This gives us one of 5 random objects.
The variable distance will be a random number from –0.0f to –40.0f (4000/100 is 40). When we actually draw the object, we translate another 10 units into the screen. So when the object are drawn, they will be drawn from –10.0f to –50.0f units into the screen (not to close, and not too far). I divide the random number by 100.0f to get a more accurate floating point value.
After assigning a random distance, we then give the object a random y value. We don't want the object any lower than –1.5f, otherwise it will be under the ground, and we dont want the object any higher than 3.0f. So to stay in that range our random number can not be any higher than 4.5f (-1.5f+4.5f=3.0f).
To calculate the x position, we use some tricky math. We take our distance and we subtract 15.0f from it. Then we divide the result by 2 and subtract 5*level. Finally, we subtract a random amount from 0.0f to 5 multiplied by the current level. We subtract the 5*level and the random amount from 0.0f to 5*level so that our object appears further off the screen on higher levels. If we didn't, the objects would appear one after another, making it even more difficult to hit all the targets than it already is.
Finally we choose a random direction (dir) from 0 (left) to 1 (right).