Выбрать главу

int LoadGLTextures() // Load Bitmaps And Convert To Textures

{

 int Status=FALSE; // Status Indicator

 AUX_RGBImageRec *TextureImage[2]; // Create Storage Space For The Textures

The next line is the most important line to watch. If you were to replace the 2 with any other number, major problems will happen. Double check! This number should match the number you used when you set up TextureImages[ ].

The two textures we're going to load are font.bmp (our font), and bumps.bmp. The second texture can be replaced with any texture you want. I wasn't feeling very creative, so the texture I decided to use may be a little drab.

 memset(TextureImage, 0, sizeof(void *)*2); // Set The Pointer To NULL

 if ((TextureImage[0] = LoadBMP("Data/Font.bmp")) && // Load The Font Bitmap

  (TextureImage[1]=LoadBMP("Data/Bumps.bmp"))) // Load The Texture Bitmap

 {

  Status=TRUE; // Set The Status To TRUE

Another important line to double check. I can't begin to tell you how many emails I've received from people asking "why am I only seeing one texture, or why are my textures all white!?!" . Usually this line is the problem. If you were to replace the 2 with a 1, only one texture would be created and the second texture would appear all white. If you replaced the 2 with a 3 you're program may crash!

You should only have to call glGenTextures() once. After glGenTextures() you should generate all your textures. I've seen people put a glGenTextures() line before each texture they create. Usually they causes the new texture to overwrite any textures you've already created. It's a good idea to decide how many textures you need to build, call glGenTextures() once, and then build all the textures. It's not wise to put glGenTextures() inside a loop unless you have a reason to.

  glGenTextures(2, &texture[0]); // Create Two Texture

  for (loop=0; loop<2; loop++) // Loop Through All The Textures

  {

   // Build All The Textures

   glBindTexture(GL_TEXTURE_2D, texture[loop]);

   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

   glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);

  }

 }

The following lines of code check to see if the bitmap data we loaded to build our textures is using up ram. If it is, the ram is freed. Notice we check and free both rgb image records. If we used 3 different images to build our textures, we'd check and free 3 rgb image records.

 for (loop=0; loop<2; loop++) {

  if (TextureImage[loop]) // If Texture Exists

  {

   if (TextureImage[loop]->data) // If Texture Image Exists

   {

    free(TextureImage[loop]->data); // Free The Texture Image Memory

   }

   free(TextureImage[loop]); // Free The Image Structure

  }

 }

 return Status; // Return The Status

}

Now we're going to build our actual font. I'll go through this section of code in some detail. It's not really that complex, but there's a bit of math to understand, and I know math isn't something everyone enjoys.

GLvoid BuildFont(GLvoid) // Build Our Font Display List

{

The following two variable will be used to hold the position of each letter inside the font texture. cx will hold the position from left to right inside the texture, and cy will hold the position up and down.

 float cx; // Holds Our X Character Coord

 float cy; // Holds Our Y Character Coord

Next we tell OpenGL we want to build 256 display lists. The variable base will point to the location of the first display list. The second display list will be base+1, the third will be base+2, etc.

The second line of code below selects our font texture (texture[0]).

 base=glGenLists(256); // Creating 256 Display Lists

 glBindTexture(GL_TEXTURE_2D, texture[0]); // Select Our Font Texture

Now we start our loop. The loop will build all 256 characters, storing each character in it's own display lists.

 for (loop=0; loop<256; loop++) // Loop Through All 256 Lists

 {

The first line below may look a little puzzling. The % symbol means the remainder after loop is divided by 16. cx will move us through the font texture from left to right. You'll notice later in the code we subtract cy from 1 to move us from top to bottom instead of bottom to top. The % symbol is fairly hard to explain but I will make an attempt.

All we are really concerned about is (loop%16) the /16.0f just converts the results into texture coordinates. So if loop was equal to 16… cx would equal the remained of 16/16 which would be 0. but cy would equal 16/16 which is 1. So we'd move down the height of one character, and we wouldn't move to the right at all. Now if loop was equal to 17, cx would be equal to 17/16 which would be 1.0625. The remainder .0625 is also equal to 1/16th. Meaning we'd move 1 character to the right. cy would still be equal to 1 because we are only concerned with the number to the left of the decimal. 18/16 would gives us 2 over 16 moving us 2 characters to the right, and still one character down. If loop was 32, cx would once again equal 0, because there is no remained when you divide 32 by 16, but cy would equal 2. Because the number to the left of the decimal would now be 2, moving us down 2 characters from the top of our font texture. Does that make sense?

  cx=float(loop%16)/16.0f; // X Position Of Current Character

  cy=float(loop/16)/16.0f; // Y Position Of Current Character

Whew :) Ok. So now we build our 2D font by selecting an individual character from our font texture depending on the value of cx and cy. In the line below we add loop to the value of base if we didn't, every letter would be built in the first display list. We definitely don't want that to happen so by adding loop to base, each character we create is stored in the next available display list.

  glNewList(base+loop, GL_COMPILE); // Start Building A List

Now that we've selected the display list we want to build, we create our character. This is done by drawing a quad, and then texturing it with just a single character from the font texture.

  glBegin(GL_QUADS); // Use A Quad For Each Character

cx and cy should be holding a very tiny floating point value from 0.0f to 1.0f. If both cx and cy were equal to 0 the first line of code below would actually be: glTexCoord2f(0.0f, 1-0.0f-0.0625f). Remember that 0.0625 is exactly 1/16th of our texture, or the width / height of one character. The texture coordinate below would be the bottom left point of our texture.

Notice we are using glVertex2i(x,y) instead of glVertex3f(x,y,z). Our font is a 2D font, so we don't need the z value. Because we are using an Ortho screen, we don't have to translate into the screen. All you have to do to draw to an Ortho screen is specify an x and y coordinate. Because our screen is in pixels from 0 to 639 and 0 to 479, we don't have to use floating point or negative values either :)

The way we set up our Ortho screen, (0, 0) will be at the bottom left of our screen. (640, 480) will be the top right of the screen. 0 is the left side of the screen on the x axis, 639 is the right side of the screen on the x axis. 0 is the bottom of the screen on the y axis and 479 is the top of the screen on the y axis. Basically we've gotten rid of negative coordinates. This is also handy for people that don't care about perspective and prefer to work with pixels rather than units :)