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

header[ ] will hold the first 6 IMPORTANT bytes from the header file (width, height, and bits per pixel).

The variable bytesPerPixel will store the result after we divide bits per pixel by 8, leaving us with the number of bytes used per pixel.

imageSize will store the number of bytes required to make up the image (width * height * bytes per pixel).

temp is a temporary variable that we will use to swap bytes later in the program.

The last variable type is a variable that I use to select the proper texture building params depending on whether or not the TGA is 24 or 32 bit. If the texture is 24 bit we need to use GL_RGB mode when we build the texture. If the TGA is 32 bit we need to add the Alpha component, meaning we have to use GL_RGBA (By default I assume the image is 32 bit by default that is why type is GL_RGBA).

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) 

The first line below opens the TGA file for reading. file is the handle we will use to point to the data within the file. the command fopen(filename, "rb") will open the file filename, and "rb" tells our program to open it for [r]eading in [b]inary mode!

The if statement has a few jobs. First off it checks to see if the file contains any data. If there is no data, NULL will be returned, the file will be closed with fclose(file), and we return false.

If the file contains information, we attempt to read the first 12 bytes of the file into TGAcompare. We break the line down like this: fread will read sizeof(TGAcompare) (12 bytes) from file into TGAcompare. Then we check to see if the number of bytes read is equal to sizeof(TGAcompare) which should be 12 bytes. If we were unable to read the 12 bytes into TGAcompare the file will close and false will be returned.

If everything has gone good so far, we then compare the 12 bytes we read into TGAcompare with the 12 bytes we have stored in TGAheader. If the bytes do not match, the file will close, and false will be returned.

Lastly, if everything has gone great, we attempt to read 6 more bytes into header (the important bytes). If 6 bytes are not available, again, the file will close and the program will return false.

 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) // Did The File Even Exist? *Added Jim Strong*

   return false; // Return False

  else {

   fclose(file); // If Anything Failed, Close The File

   return false; // Return False

  }

 }

If everything went ok, we now have enough information to define some important variables. The first variable we want to define is width. We want width to equal the width of the TGA file. We can find out the TGA width by multiplying the value stored in header[1] by 256. We then add the lowbyte which is stored in header[0].

The height is calculated the same way but instead of using the values stored in header[0] and header[1] we use the values stored in header[2] and header[3].

After we have calculated the width and height we check to see if either the width or height is less than or equal to 0. If either of the two variables is less than or equal to zero, the file will be closed, and false will be returned.

We also check to see if the TGA is a 24 or 32 bit image. We do this by checking the value stored at header[4]. If the value is not 24 or 32 (bit), the file will be closed, and false will be returned.

In case you have not realized. A return of false will cause the program to fail with the message "Initialization Failed". Make sure your TGA is an uncompressed 24 or 32 bit image!

 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

 }

Now that we have calculated the image width and height we need to calculate the bits per pixel, bytes per pixel and image size.

The value in header[4] is the bits per pixel. So we set bpp to equal header[4].

If you know anything about bits and bytes, you know that 8 bits makes a byte. To figure out how many bytes per pixel the TGA uses, all we have to do is divide bits per pixel by 8. If the image is 32 bit, bytesPerPixel will equal 4. If the image is 24 bit, bytesPerPixel will equal 3.

To calculate the image size, we multiply width * height * bytesPerPixel. The result is stored in imageSize. If the image was 100×100×32 bit our image size would be 100 * 100 * 32/8 which equals 10000 * 4 or 40000 bytes!

 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

Now that we know how many bytes our image is going to take, we need to allocate some memory. The first line below does the trick. imageData will point to a section of ram big enough to hold our image. malloc(imagesize) allocates the memory (sets memory aside for us to use) based on the amount of ram we request (imageSize).

The "if" statement has a few tasks. First it checks to see if the memory was allocated properly. If not, imageData will equal NULL, the file will be closed, and false will be returned.

If the memory was allocated, we attempt to read the image data from the file into the allocated memory. The line fread(texture->imageData, 1, imageSize, file) does the trick. fread means file read. imageData points to the memory we want to store the data in. 1 is the size of data we want to read in bytes (we want to read 1 byte at a time). imageSize is the total number of bytes we want to read. Because imageSize is equal to the total amount of ram required to hold the image, we end up reading in the entire image. file is the handle for our open file.

After reading in the data, we check to see if the amount of data we read in is the same as the value stored in imageSize. If the amount of data read and the value of imageSize is not the same, something went wrong. If any data was loaded, we will free it. (release the memory we allocated). The file will be closed, and false will be returned.

 texture->imageData=(GLubyte *)malloc(imageSize); // Reserve Memory To Hold The TGA Data