Problems Loading and Displaying TARGA Textures

Alright, I’m working in C++ Visual Studio 2010. I’ve been trying for a while now to load up targa images, load them as textures, and then display them. I’m pretty familiar with the concepts of how to do all those things, but I’m not quite getting it right, it seems. The resulting image is just a distorted mess. Either I’m reading it in wrong, or I’m drawing it to the screen wrong.

Without further adieu, here’s some code. The loading code is pretty well commented, and the drawing code is pretty simple, so I don’t think I have to explain to awfully much. I got most of my targa reading code from here but I added some extra stuff to handle the case where I need to vertical-flip the image. If I’m not explaining enough, just let me know. I’m not sure how smart I’m supposed to assume people are, haha.

My image/texture loading code:

int loadTexture(char * filename)
{
	TextureImage texture;
	GLubyte		TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0};			// Uncompressed non color mapped 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		rowSize;							// Used to store the row size for image flipping
	GLuint		temp;								// Temporary Variable
	GLubyte		*reverseImage;						// for reversing the image
	GLuint		k;									// for a for loop

	FILE *file = fopen(filename, "rb");

	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 -1;							// Return False
		else
		{
			fclose(file);							// If Anything Failed, Close The File
			return -1;							// 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)								// make sure its 24-bit
	{
		fclose(file);								// If Anything Failed, Close The File
		return false;								// Return False
	}

	texture.bpp	= header[4];							// Grab The TGA's Bits Per Pixel
	bytesPerPixel	= texture.bpp/8;						// Divide By 8 To Get The Bytes Per Pixel
	imageSize	= texture.width*texture.height*bytesPerPixel;

	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;								// Return False
	} 
	
	fclose (file);
	
	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)
	}

	//if pixels start from the bottom left, vertical flip the data
	if((header[5] & 0x20) != 0x20)
	{
		rowSize = bytesPerPixel * texture.width;
		reverseImage = (GLubyte *)malloc(imageSize); //need temporary storage

		for(GLuint i=0; i<texture.height; i++)
		{
			memcpy(&reverseImage[imageSize-rowSize*(i+1)], &texture.imageData[i*rowSize], rowSize);
		}
		memcpy(texture.imageData, reverseImage, imageSize);
	}

	GLuint textureID = 0;
	glGenTextures(1, &textureID);

	glBindTexture(GL_TEXTURE_2D, textureID);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, texture.width, texture.height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture.imageData);

	return 0;
}

My drawing code:

void GameObject::displayHandler()
{
	float vert1[2];
	float vert2[2];
	float vert3[2];
	float vert4[2];
	int width;
	int height;
	float halfWidth;
	float halfHeight;

	glBindTexture(GL_TEXTURE_2D, textureID);

	glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
	glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);

	halfWidth = width/2;
	halfHeight = height/2;

	vert1[0] = -halfWidth;
	vert1[1] = -halfHeight;
	vert2[0] = halfWidth;
	vert2[1] = -halfHeight;
	vert3[0] = halfWidth;
	vert3[1] = halfHeight;
	vert4[0] = -halfWidth;
	vert4[1] = halfHeight;

	glPushMatrix();

	glTranslatef(x, y, 0);

	glBegin(GL_QUADS);

	glTexCoord2f(0, 0);
	glVertex2fv(vert1);
	glTexCoord2f(1, 0);
	glVertex2fv(vert2);
	glTexCoord2f(1, 1);
	glVertex2fv(vert3);
	glTexCoord2f(0, 1);
	glVertex2fv(vert4);

	glEnd();

	glPopMatrix();
}

What happens when you set some breakpoints and run it in the debugger? What does the debugger tell you the values of width and height are, and what should they be?

I’m just pulling in two different textures, one is 30x30 an the other 5x5. The height and width appear to be correct both when I’m reading it in during loadTexture(), and when I’m retrieving the dimensions again in displayHandler().

That’s the thing that gets me: everything seems to LOOK right. I’ve gone through in the debugger and made sure that all the Targa specifications are correct.

Like, I know the images don’t have color maps and some other things because I’ve got TGAHeader set up to represent the header data I want, and then I just compare it to the images actual header data. Looking through in debug, the header data all seems correct based on Targa specifications. I do similar things as I move along, such as checking a certain byte in the header to make sure the images have 24 bit color. Again, I know those work because I’ve checked in the debugger.

I’m actually pretty positive that I’m reading the image correctly. What I’m not positive on is my glTexImage2D() parameters, as well as my entire displayHandler(). I know I’ve read here and there that texture images are only stored at particular powers-of-two sizes, but I’m not really certain what that means exactly in terms of displaying things correctly. It’s the only thing I haven’t fully considered, so maybe it’s my problem?

Oh, also I should explain my intent in displayHandler() probably: this is a simple 2D game I’m making, and every object in the game has a single origin point that describes where the objects are “located” from the code’s vantage point, and the openGL objects are simply centered on that point, and the size of the objects are based off of the sizes of the textures. Hence the “halfWidth/halfHeight” stuff being calculated based off of the texture height and width.

I’m actually pretty positive that I’m reading the image correctly. What I’m not positive on is my glTexImage2D() parameters, as well as my entire displayHandler(). I know I’ve read here and there that texture images are only stored at particular powers-of-two sizes, but I’m not really certain what that means exactly in terms of displaying things correctly. It’s the only thing I haven’t fully considered, so maybe it’s my problem?

I think you’ve identified your problem for yourself here. :wink:

Try using 8x8 and 32x32 sizes instead and see what happens.

Okay, but the question at this point is how does one go about applying the textures correctly if you always get back an image of a certain size, but not all of that image is the original image?

I imagine there’s some common method(s) of doing so, but I haven’t really found them. I guess I’d just scale the texture coordinates accordingly?

Also considering how messed up the resulting drawn image is, this might still not be the only problem. I’ll have to try it out tonight.

Okay, turns out the texture sizes WAS the problem. I did a 32x32 and an 8x8 and it worked perfectly.

Now I just need to figure out how to scale non-standard sized textures.