bool game; // Game Over?
typedef int (*compfn)(const void*, const void*); // Typedef For Our Compare Function
Now for our objects structure. This structure holds all the information about an object. The direction it's rotating, if it's been hit, it's location on the screen, etc.
A quick rundown of the variables… rot specifies the direction we want to rotate the object. hit will be FALSE if the object has not yet been hit. If the object was hit or manually flagged as being hit, the value of hit will be TRUE.
The variable frame is used to cycle through the frames of animation for our explosion. As frame is increased the explosion texture changes. More on this later in the tutorial.
To keep track of which direction our object is moving, we have a variable called dir. dir can be one of 4 values: 0 — object is moving Left, 1 — object is moving right, 2 — object is moving up and finally 3 — object is moving down.
texid can be any number from 0 to 4. Zero represents the BlueFace texture, 1 is the Bucket texture, 2 is the Target texture, 3 is the Coke can texture and 4 is the Vase texture. Later in the load texture code, you will see that the first 5 textures are the target images.
Both x and y are used to position the object on the screen. x represents where the object is on the x-axis, and y the location of the object on the y-axis.
The objects rotate on the z-axis based on the value of spin. Later in the code, we will increase or decrease spin based on the direction the object is travelling.
Finally, distance keeps track of how far into the screen our object is. distance is an extremely important variable, we will use it to calculate the left and right sides of the screen, and to sort the objects so the objects in the distance are drawn before the objects up close.
struct objects {
GLuint rot; // Rotation (0-None, 1-Clockwise, 2-Counter Clockwise)
bool hit; // Object Hit?
GLuint frame; // Current Explosion Frame
GLuint dir; // Object Direction (0-Left, 1-Right, 2-Up, 3-Down)
GLuint texid; // Object Texture ID
GLfloat x; // Object X Position
GLfloat y; // Object Y Position
GLfloat spin; // Object Spin
GLfloat distance; // Object Distance
};
No real reason to explain the code below. We are loading TGA images in this tutorial instead of bitmaps. The structure below is used to store image data, as well as information about the TGA image. Read the tutorial on loading TGA files if you need a detailed explanation of the code below.
typedef struct // Create A Structure
{
GLubyte *imageData; // Image Data (Up To 32 Bits)
GLuint bpp; // Image Color Depth In Bits Per Pixel.
GLuint width; // Image Width
GLuint height; // Image Height
GLuint texID; // Texture ID Used To Select A Texture
} TextureImage; // Structure Name
The following code sets aside room for our 10 textures and 30 objects. If you plan to add more objects to the game make sure you increase the value from 30 to however many objects you want.
TextureImage textures[10]; // Storage For 10 Textures
objects object[30]; // Storage For 30 Objects
I didn't want to limit the size of each object. I wanted the vase to be taller than the can, I wanted the bucket to be wider than the vase. To make life easy, I create a structure that holds the objects width (w) and height (h).
I then set the width and height of each object in the last line of code. To get the coke cans width, I would check size[3].w. The Blueface is 0, the Bucket is 1, and the Target is 2, etc. The width is represented by w. Make sense?
struct dimensions { // Object Dimensions
GLfloat w; // Object Width
GLfloat h; // Object Height
};
// Size Of Each Object: Blueface, Bucket, Target, Coke, Vase
dimensions size[5] = { {1.0f,1.0f}, {1.0f,1.0f}, {1.0f,1.0f}, {0.5f,1.0f}, {0.75f,1.5f} };
The following large section of code loads our TGA images and converts them to textures. It's the same code I used in lesson 25 so if you need a detailed description go back and read lesson 25.
I use TGA images because they are capable of having an alpha channel. The alpha channel tells OpenGL which parts of the image are transparent and which parts are opaque. The alpha channel is created in an art program, and is saved inside the .TGA image. OpenGL loads the image, and uses the alpha channel to set the amount of transparency for each pixel in the image.
bool LoadTGA(TextureImage *texture, char *filename) // Loads A TGA File Into Memory
{
GLubyte TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0}; // Uncompressed TGA Header
GLubyte TGAcompare[12]; // Used To Compare TGA Header
GLubyte header[6]; // First 6 Useful Bytes From The Header
GLuint bytesPerPixel; // Holds Number Of Bytes Per Pixel Used In The TGA File
GLuint imageSize; // Used To Store The Image Size When Setting Aside Ram
GLuint temp; // Temporary Variable
GLuint type=GL_RGBA; // Set The Default GL Mode To RBGA (32 BPP)
FILE *file = fopen(filename, "rb"); // Open The TGA File
if (file==NULL || // Does File Even Exist?
fread(TGAcompare, 1, sizeof(TGAcompare), file) != sizeof(TGAcompare) || // Are There 12 Bytes To Read?
memcmp(TGAheader, TGAcompare, sizeof(TGAheader)) != 0 || // Does The Header Match What We Want?
fread(header, 1, sizeof(header), file) != sizeof(header)) // If So Read Next 6 Header Bytes
{
if (file == NULL) // Does The File Even Exist? *Added Jim Strong*
return FALSE; // Return False
else // Otherwise
{
fclose(file); // If Anything Failed, Close The File
return FALSE; // Return False
}
}
texture->width = header[1] * 256 + header[0]; // Determine The TGA Width (highbyte*256+lowbyte)
texture->height = header[3] * 256 + header[2]; // Determine The TGA Height (highbyte*256+lowbyte)
if (texture->width <=0 || // Is The Width Less Than Or Equal To Zero
texture->height <=0 || // Is The Height Less Than Or Equal To Zero
(header[4]!=24 && header[4]!=32)) // Is The TGA 24 or 32 Bit?
{
fclose(file); // If Anything Failed, Close The File
return FALSE; // Return False
}
texture->bpp = header[4]; // Grab The TGA's Bits Per Pixel (24 or 32)
bytesPerPixel = texture->bpp/8; // Divide By 8 To Get The Bytes Per Pixel
imageSize = texture->width*texture->height*bytesPerPixel; // Calculate The Memory Required For The TGA Data
texture->imageData=(GLubyte *)malloc(imageSize); // Reserve Memory To Hold The TGA Data
if (texture->imageData==NULL || // Does The Storage Memory Exist?
fread(texture->imageData, 1, imageSize, file) != imageSize) // Does The Image Size Match The Memory Reserved?
{