Im very confuse with Loading TGA machanism.

Started by
1 comment, last by Fahrenheit451 17 years, 10 months ago
There is no Loading TGA in Redbook. But I do have a killer book (Beginning OpenGL Game programming by Dave Astle). And I have reached TGA Image Loading. And I dont understand the mechanism to load TGA. Any simple steps to load uncompress and compress TGA Images?
Advertisement
I don't remember what resources I used to code this (I think it might be similar to tutorials on nehe) but this is the code I use to load TGA and TGA_RLE textures.

It's pretty sloppy in general but it works.

I included the function "generateInternalTexture" but it's pretty poor design (I should not have hard coded all of those parameters for texture generation).


UINT	TextureManager::LoadTGA(char	*FileName){	int	i; //counter	WORD	width, height;	byte	*data	=	NULL;	byte	type, bits, length;	int		rowlength, channels, filesize;	byte	*pBuffer = NULL;	byte	*ptr = NULL;	FILE	*pFile = fopen(FileName, "rb");	if(!pFile)	{		TextureData	<<	"TextureManager::LoadTGA: could not load tga file: " << FileName << "\n";		return	NULL;	//FIXME: some sort of error log or notification needed		}	fseek(pFile, 0, SEEK_END);	filesize = ftell(pFile);	fseek(pFile, 0, SEEK_SET);	pBuffer = new byte[filesize];	fread(pBuffer, 1, filesize, pFile);	fclose(pFile);		ptr = pBuffer;	length	=	*(byte*)ptr;	ptr+=2;	type	=	*(byte*)ptr;	ptr += 10;	width	=	*(WORD*)ptr;	ptr += sizeof(WORD);	height	=	*(WORD*)ptr;	ptr	+= sizeof(WORD);	bits	=	*(byte*)ptr;	ptr++;	ptr += length+1;		if(bits == 16)	{		MessageBox(NULL, "LoadTGA: Doesn't support 16bit","ERROR", MB_OK);		return NULL;	}	channels = bits / 8;	rowlength = channels * width;//length of a row in bytes	data = new byte[rowlength * height];	unsigned	int y;if(type != TGA_RLE){	if(channels == 3)	{		for(i = 0; i < height; i++)		{			for(y = 0; y < rowlength; y++)			{				data[(i*rowlength)+y] = *(byte*)ptr;				ptr++;			}			}		GLenum	GLtype = GL_BGR_EXT;		return	GenerateInternalTexture(data, channels, width, height, GLtype);	}	else	{		if(channels == 4)		{			for(i = 0; i < height; i++)			{				for(y = 0; y < rowlength; y++)				{					data[(i*rowlength)+y] = *(byte*)ptr;					ptr++;				}			}			}		GLenum	GLtype	=	GL_BGRA_EXT;				ptr = NULL;		delete	[]	pBuffer;		delete	ptr;		return	GenerateInternalTexture(data, channels, width, height, GLtype);	}	//FIXME: make sure all of the data is cleaned up! }else	if(type == TGA_RLE) //NOTE: LoadTGA_RLE must delete data when done!	return	LoadTGA_RLE(pBuffer, ptr, bits, channels, width, height, data);}UINT	TextureManager::LoadTGA_RLE(byte*pBuffer, byte*ptr, byte	bits, byte	channels, WORD width, WORD height, byte	*data){		byte *pColor = new byte[channels];		int	pixelsleft = 0;		int	colorsread = 0;		int	pixelsread = 0;		int	totalpixels = width * height;		unsigned	int	y; //counter 				//FIXME: must have an error logging system! 		if(!ptr)			return	NULL;		if(!pBuffer)			return	NULL;		while(pixelsread < totalpixels)		{			pixelsleft = *(byte*)ptr;			ptr++;			if(pixelsleft < 128)			{				pixelsleft++;			if(channels == 4)			{					while(pixelsleft)					{						for(y = 0; y < channels; y++)						{							pColor[y] = *(byte*)ptr;							ptr++;						}						data[colorsread + 0] = pColor[0];							data[colorsread + 1] = pColor[1];						data[colorsread + 2] = pColor[2];							data[colorsread + 3] = pColor[3];						pixelsread++;						pixelsleft--;						colorsread += channels;					}				}				else	if(channels == 3)				{						while(pixelsleft)						{							for(y = 0; y < channels; y++)							{								pColor[y] = *(byte*)ptr;								ptr++;							}							data[colorsread + 0] = pColor[0];								data[colorsread + 1] = pColor[1];							data[colorsread + 2] = pColor[2];								pixelsread++;							pixelsleft--;							colorsread += channels;						}				}			}			else			{				pixelsleft -= 127;				for(y = 0; y < channels; y++)				{					pColor[y] = *(byte*)ptr;					ptr++;				}				if(channels == 4)				{					while(pixelsleft)					{						data[colorsread + 0] = pColor[0];						data[colorsread + 1] = pColor[1];						data[colorsread + 2] = pColor[2];						data[colorsread + 3] = pColor[3];						pixelsread++;						pixelsleft--;						colorsread += channels;					}				}				else	if(channels == 3)				{					while(pixelsleft)					{						data[colorsread + 0] = pColor[0];						data[colorsread + 1] = pColor[1];						data[colorsread + 2] = pColor[2];						pixelsread++;						pixelsleft--;						colorsread += channels;					}				}							}		}				ptr=NULL;		delete	[]	pBuffer;		delete	ptr;				GLenum	GLtype;		if(channels == 4)			GLtype = GL_BGRA_EXT;		if(channels == 3)			GLtype = GL_BGR_EXT;		return	GenerateInternalTexture(data, channels, width, height, GLtype);	}UINT	TextureManager::GenerateInternalTexture(byte * data, int channels, int width, int height, GLenum type){	UINT	texture;	gpNTGLAPI->ntglGenTextures(1, &texture);	gpNTGLAPI->ntglPixelStorei (GL_UNPACK_ALIGNMENT, 1);	gpNTGLAPI->ntglBindTexture(GL_TEXTURE_2D, texture);	gluBuild2DMipmaps(GL_TEXTURE_2D, channels,width,height, type, GL_UNSIGNED_BYTE, data);	gpNTGLAPI->ntglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); //GL_LINEAR_MIPMAP_NEAREST is faster than GL_LINEAR_MIPMAP_LINEAR	gpNTGLAPI->ntglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);	gpNTGLAPI->ntglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);	return texture;}
...and do not wildly extrapolate. Just because Saddam Hussein gassed Kurds in 1990 doesn't mean he eats babies' brains.
I used this link to work from, plus a bunch of others from a Google of "TGA file format".

Here is my uncompressed/compressed loader code. Hopefully the comments are descriptive enough and make sense after reading the info at the link above. If not, let me know what part is unclear and I will explain it more.

// Load uncompressed image databool FImageTGA::LoadUncompressed(){	// so far so good, so allocate memory for image data	// calculate byte multiplier for data array	bytesPP = spec.bpp / 8;	imageSize = spec.width * spec.height * bytesPP;	imageData = new unsigned char[imageSize];	if (imageData == NULL)	{		PrintDebug("[FImageTGA] Error: Failed to allocate %d bytes for image pixel data\n", imageSize);		return false;	}	PrintDebug("[FImageTGA] Allocated %d bytes for image pixel data\n", imageSize);	// attempt to load our image data	if (!file.read((char *)imageData, imageSize))	{		// failed, release resources		PrintDebug("[FImageTGA] ERROR: failed to read image pixel data from %s\n", filename.c_str());		delete imageData;		imageData = NULL;		return false;	}	// all ok	return true;}// Load compressed image databool FImageTGA::LoadCompressed(){	// so far so good, so allocate memory for final image data	// calculate byte multiplier for data array	bytesPP = spec.bpp / 8;	imageSize = spec.width * spec.height * bytesPP;	imageData = new unsigned char[imageSize];	if (imageData == NULL)	{		PrintDebug("[FImageTGA] Error: Failed to allocate %d bytes for image pixel data\n", imageSize);		return false;	}	PrintDebug("[FImageTGA] Allocated %d bytes for image pixel data\n", imageSize);	// temporary variables for decoding RLE data	unsigned int numPixels = spec.width * spec.height;		// number of pixels we expect to read	unsigned int pixelCount = 0;							// current pixel we are dealing with	unsigned int currentByte = 0;							// current byte we are dealing with	unsigned char * colorBuffer = new unsigned char[bytesPP];	// temp store for current pixel and chunk data	unsigned char * chunkByte = new unsigned char[sizeof(unsigned char)];	// keep reading a chunk and pixel data until we have accumulated	// enough pixels with the pixel count	do	{		// reset chunk byte each chunk read		chunkByte[0] = 0;		// read chunk byte		if (!file.read((char *)chunkByte, sizeof(unsigned char)))		{			PrintDebug("[FImageTGA] ERROR: Failed to read RLE chunk byte\n");			// release resources			delete colorBuffer;			delete chunkByte;			return false;		}		// check if we need to read raw or pixel data next		if(chunkByte[0] < 128)		{			// Raw data! increase chunk value by one to know how many pixels to reproduce			chunkByte[0]++;			// read in necessary number of pixels and populate the final image data array			for (int counter = 0; counter < chunkByte[0]; counter++)			{				// read pixel data				if (!file.read((char *)colorBuffer,bytesPP))				{					PrintDebug("[FImageTGA] ERROR: Failed to read necessary raw pixel data\n");					// release resources					delete colorBuffer;					delete chunkByte;					return false;				}				//transfer pixel colour to final image array				imageData[currentByte+0]=colorBuffer[0];				imageData[currentByte+1]=colorBuffer[1];				imageData[currentByte+2]=colorBuffer[2];				if (spec.bpp == 32)					imageData[currentByte+3]=colorBuffer[3];				// increase current byte to point to next spot in building our image				currentByte += bytesPP;				// increase our pixel count				pixelCount++;			}		} else {			// Pixel data! calculate how many of the following pixel we need to duplicate			chunkByte[0] -= 127;			// read pixel data			if (!file.read((char *)colorBuffer,bytesPP))			{				PrintDebug("[FImageTGA] ERROR: Failed to read necessary pixel data\n");				// release resources				delete colorBuffer;				delete chunkByte;				return false;			}			// duplicate pixel data as many times as necessary			for (int counter = 0; counter < chunkByte[0]; ++counter)			{				imageData[currentByte+0]=colorBuffer[0];				imageData[currentByte+1]=colorBuffer[1];				imageData[currentByte+2]=colorBuffer[2];				if (spec.bpp == 32)					imageData[currentByte+3]=colorBuffer[3];				// increase current byte to point to next spot				currentByte += bytesPP;				// increase our pixel count				pixelCount++;			}		}	} while (pixelCount < numPixels);	PrintDebug("[FImageTGA] Read %d pixels in agaist expected %d pixels\n",pixelCount,numPixels);	// release resources	delete colorBuffer;	delete chunkByte;	// all ok	return true;}


hth
F451

This topic is closed to new replies.

Advertisement