This topic is now archived and is closed to further replies.


Problem with TGA files

Recommended Posts

Anyone have code that works to load a TGA properly. I''ve been strugling with this ever since I''ve been writing my Q3 level loader. First I loaded my TGA''s, they''re upside down. Then I flip them, the program crashes. I check to see why, seems most of the TGA files are loaded o.k, but sometimes when I print the width and the height it''s wrong. I took ne he''s TGA loading code, same thing does not flip textures, and reports invalid height sometimes (which of course causes my flipping code to crash) Anyone have a TGA loader that actually works, I''d appreciate a copy, or at least an explanation of how to fix the problem.

Share this post

Link to post
Share on other sites
Forget where I got it now, but this function which I modified slightly from its original works nicely. However I am in now way trying to claim credit for it. This is not my code but it does work nicely. There''s is also a section which creates an opengl texture from the tga after it is loaded into memory. Take a few minuites to go through it, its pretty easy to understand.

It uses this header file:

#include <glut.h>

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;

bool loadTGA(TextureImage *texture, char *filename);

== End texture.h ===

--> texture.cpp <--
** This must be an uncompressed TGA file, make sure when
** you save it that it does this.
bool loadTGA(TextureImage *texture, char *filename) {
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 ||
fread(TGAcompare,1,sizeof(TGAcompare),file)!=sizeof(TGAcompare) ||
fread(header,1,sizeof(header),file)!=sizeof(header)) {

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?

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

if(texture->imageData != NULL) // Was Image Data Loaded
free(texture->imageData); // If So, Release The Image Data

fclose(file); // Close The File

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;// 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->texID);// Generate OpenGL texture IDs

glBindTexture(GL_TEXTURE_2D, texture->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->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->width, texture->height, 0, type, GL_UNSIGNED_BYTE, texture->imageData);

return true; // Texture Building Went Ok, Return True

=== End texture.cpp ===

Share this post

Link to post
Share on other sites
That''s NeHe''s source. It works fine, but not always. I think the problem is that I''m opening compressed TGA''s and this won''t handle compressed ones.

It loads the TGA''s fine, but does not properly compute the dimensions since I have a 128*256 file that the loader sees as a 256*640 file.

Photoshop opens it as 128*256 so there must be a way to get the proper dimensions. How do the people who have written Q3 loaders load their TGA''s, without getting them upside down?

Argh, I''m so frustrated.

Share this post

Link to post
Share on other sites
Check the last byte (17 bytes from the beginning) of the header. If bit 4 is set, then you need to read the pixels in right-to-left order (ie. the pixels in the file are ordered beginning on the right of each row). If bit 5 is set, you need to read them in top-to-bottom order (ie. the rows of pixels in the file are ordered beginning at the top row).

Also, you can find the height and width by just reading the 16-bit values at offsets 12 and 14.

Share this post

Link to post
Share on other sites