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

 if (texture->imageData==NULL || // Does The Storage Memory Exist?

  fread(texture->imageData, 1, imageSize, file) != imageSize) // Does The Image Size Match The Memory Reserved?

 {

  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

 }

If the data was loaded properly, things are going good :) All we have to do now is swap the Red and Blue bytes. In OpenGL we use RGB (red, green, blue). The data in a TGA file is stored BGR (blue, green, red). If we didn't swap the red and blue bytes, anything in the picture that should be red would be blue and anything that should be blue would be red.

The first thing we do is create a loop (i) that goes from 0 to imageSize. By doing this, we can loop through all of the image data. Our loop will increase by steps of 3 (0, 3, 6, 9, etc) if the TGA file is 24 bit, and 4 (0, 4, 8, 12, etc) if the image is 32 bit. The reason we increase by steps is so that the value at i is always going to be the first byte ([b]lue byte) in our group of 3 or 4 bytes.

Inside the loop, we store the [b]lue byte in our temp variable. We then grab the red byte which is stored at texture->imageData[i+2] (Remember that TGAs store the colors as BGR[A]. B is i+0, G is i+1 and R is i+2) and store it where the [b]lue byte used to be.

Lastly we move the [b]lue byte that we stored in the temp variable to the location where the [r]ed byte used to be (i+2), and we close the file with fclose(file).

If everything went ok, the TGA should now be stored in memory as usable OpenGL texture data!

 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

Now that we have usable data, it's time to make a texture from it. We start off by telling OpenGL we want to create a texture in the memory pointed to by &texture[0].texID.

It's important that you understand a few things before we go on. In the InitGL() code, when we call LoadTGA() we pass it two parameters. The first parameter is &textures[0]. In LoadTGA() we don't make reference to &textures[0]. We make reference to &texture[0] (no 's' at the end). When we modify &texture[0] we are actually modifying textures[0]. texture[0] assumes the identity of textures[0]. I hope that makes sense.

So if we wanted to create a second texture, we would pass the parameter &textures[1]. In LoadTGA() any time we modified texture[0] we would be modifying textures[1]. If we passed &textures[2], texture[0] would assume the identity of &textures[2], etc.

Hard to explain, easy to understand. Of course I wont be happy until I make it really clear :) Last example in english using an example. Say I had a box. I called it box #10. I gave it to my friend and asked him to fill it up. My friend could care less what number it is. To him it's just a box. So he fills what he calls "just a box". He gives it back to me. To me he just filled Box #10 for me. To him he just filled a box. If I give him another box called box #11 and say hey, can you fill this. He'll again think of it as just "box". He'll fill it and give it back to me full. To me he's just filled box #11 for me.

When I give LoadTGA &textures[1] it thinks of it as &texture[0]. It fills it with texture information, and once it's done I am left with a working textures[1]. If I give LoadTGA &textures[2] it again thinks of it as &texture[0]. It fills it with data, and I'm left with a working textures[2]. Make sense :)

Anyways… On to the code! We tell LoadTGA() to build our texture. We bind the texture, and tell OpenGL we want it to be linear filtered.

 // 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

Now we check to see if the TGA file was 24 or 32 bit. If the TGA was 24 bit, we set the type to GL_RGB. (no alpha channel). If we didn't do this, OpenGL would try to build a texture with an alpha channel. The alpha information wouldn't be there, and the program would probably crash or give an error message.

 if (texture[0].bpp==24) // Was The TGA 24 Bits

 {

  type=GL_RGB; // If So Set The 'type' To GL_RGB

 }

Now we build our texture, the same way we've always done it. But instead of putting the type in ourselves (GL_RGB or GL_RGBA), we substitute the variable type. That way if the program detected that the TGA was 24 bit, the type will be GL_RGB. If our program detected that the TGA was 32 bit, the type would be GL_RGBA.

After the texture has been built, we return true. This lets the InitGL() code know that everything went ok.

 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 code below is our standard build a font from a texture code. You've all seen this code before if you've gone through all the tutorials up until now. Nothing really new here, but I figured I'd include the code to make following through the program a little easier.

Only real difference is that I bind to textures[0].texID. Which points to the font texture. Only real difference is that .texID has been added.

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

{

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

 glBindTexture(GL_TEXTURE_2D, textures[0].texID); // Select Our Font Texture

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

 {

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

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

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

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

   glTexCoord2f(cx,1.0f-cy-0.0625f); // Texture Coord (Bottom Left)

   glVertex2d(0,16); // Vertex Coord (Bottom Left)

   glTexCoord2f(cx+0.0625f,1.0f-cy-0.0625f); // Texture Coord (Bottom Right)

   glVertex2i(16,16); // Vertex Coord (Bottom Right)

   glTexCoord2f(cx+0.0625f,1.0f-cy-0.001f); // Texture Coord (Top Right)

   glVertex2i(16,0); // Vertex Coord (Top Right)

   glTexCoord2f(cx,1.0f-cy-0.001f); // Texture Coord (Top Left)

   glVertex2i(0,0); // Vertex Coord (Top Left)

  glEnd(); // Done Building Our Quad (Character)

  glTranslated(14,0,0); // Move To The Right Of The Character

  glEndList(); // Done Building The Display List