
#include "../include/tga.h"

TextureImage* LoadTGA(const char * filename)
{
	TGAHeader tgaheader;
	TextureImage* image;
	std::string errmsg;
	FILE* file = fopen(filename, "rb");

	if(file == NULL)
	{
		errmsg = "Could not open texture file ";
		errmsg = errmsg + filename;
		MessageBox(NULL, errmsg.c_str(), "ERROR", MB_OK);
		return NULL;
	}

	if(fread(&tgaheader, sizeof(TGAHeader), 1, file) == 0)
	{
		MessageBox(NULL, "Could not read file header", "ERROR", MB_OK);
		if(file != NULL)
			fclose(file);
		return NULL;
	}

	if(memcmp(uTGAcompare, &tgaheader, sizeof(tgaheader)) == 0)
		image = LoadUncompressedTGA(file);
	else if(memcmp(cTGAcompare, &tgaheader, sizeof(tgaheader)) == 0)
		image = LoadCompressedTGA(file);
	else
	{
		MessageBox(NULL, "TGA file must be type 2 or type 10 ", "Invalid Image", MB_OK);
		fclose(file);
		return NULL;
	}
	return image;
}

TextureImage* LoadUncompressedTGA(FILE * fTGA)
{
	TGA tga;
	TextureImage* image = new TextureImage;
	
	if(fread(tga.header, sizeof(tga.header), 1, fTGA) == 0)
	{										
		MessageBox(NULL, "Could not read info header", "ERROR", MB_OK);
		if(fTGA != NULL)
		{
			fclose(fTGA);
		}
		return NULL;
	}	

	image->sizeY  = tga.header[1] * 256 + tga.header[0];
	image->sizeX = tga.header[3] * 256 + tga.header[2];
	image->bpp	= tga.header[4];
	tga.Width		= image->sizeX;
	tga.Height		= image->sizeY;
	tga.Bpp			= image->bpp;

	if((image->sizeX <= 0) || (image->sizeY <= 0) || ((image->bpp != 24) && (image->bpp !=32)))
	{
		MessageBox(NULL, "Invalid texture information", "ERROR", MB_OK);
		if(fTGA != NULL)
		{
			fclose(fTGA);
		}
		return NULL;
	}

	if(image->bpp == 24)
	{
		image->type	= GL_RGB;
	}
	else
	{
		image->type	= GL_RGBA;
	}

	tga.bytesPerPixel	= (tga.Bpp / 8);
	tga.imageSize		= (tga.bytesPerPixel * tga.Width * tga.Height);
	image->data	= (GLubyte *)malloc(tga.imageSize);

	if(image->data == NULL)
	{
		MessageBox(NULL, "Could not allocate memory for image", "ERROR", MB_OK);
		fclose(fTGA);
		return NULL;
	}

	if(fread(image->data, 1, tga.imageSize, fTGA) != tga.imageSize)
	{
		MessageBox(NULL, "Could not read image data", "ERROR", MB_OK);
		if(image->data != NULL)
		{
			free(image->data);
		}
		fclose(fTGA);
		return NULL;
	}

	
	for(GLuint cswap = 0; cswap < (int)tga.imageSize; cswap += tga.bytesPerPixel)
	{
		image->data[cswap] ^= image->data[cswap+2] ^=
		image->data[cswap] ^= image->data[cswap+2];
	}

	fclose(fTGA);
	return image;
}

TextureImage* LoadCompressedTGA(FILE * fTGA)
{
	TextureImage* image = new TextureImage;
	TGA tga;

	if(fread(tga.header, sizeof(tga.header), 1, fTGA) == 0)
	{
		MessageBox(NULL, "Could not read info header", "ERROR", MB_OK);
		if(fTGA != NULL)
		{
			fclose(fTGA);
		}
		return NULL;
	}

	image->sizeX  = tga.header[1] * 256 + tga.header[0];
	image->sizeY = tga.header[3] * 256 + tga.header[2];
	image->bpp	= tga.header[4];
	tga.Width		= image->sizeX;
	tga.Height		= image->sizeY;
	tga.Bpp			= image->bpp;

	if((image->sizeX <= 0) || (image->sizeY <= 0) || ((image->bpp != 24) && (image->bpp !=32)))
	{
		MessageBox(NULL, "Invalid texture information", "ERROR", MB_OK);
		if(fTGA != NULL)
		{
			fclose(fTGA);
		}
		return NULL;
	}

	tga.bytesPerPixel	= (tga.Bpp / 8);
	tga.imageSize		= (tga.bytesPerPixel * tga.Width * tga.Height);
	image->data	= (GLubyte *)malloc(tga.imageSize);

	if(image->data == NULL)
	{
		MessageBox(NULL, "Could not allocate memory for image", "ERROR", MB_OK);
		fclose(fTGA);
		return NULL;
	}

	GLuint pixelcount	= tga.Height * tga.Width;
	GLuint currentpixel	= 0;
	GLuint currentbyte	= 0;
	GLubyte * colorbuffer = (GLubyte *)malloc(tga.bytesPerPixel);

	do
	{
		GLubyte chunkheader = 0;

		if(fread(&chunkheader, sizeof(GLubyte), 1, fTGA) == 0)
		{
			MessageBox(NULL, "Could not read RLE header", "ERROR", MB_OK);
			if(fTGA != NULL)
			{
				fclose(fTGA);
			}
			if(image->data != NULL)
			{
				free(image->data);
			}
			return NULL;
		}

		if(chunkheader < 128)
		{
			chunkheader++;
			for(short counter = 0; counter < chunkheader; counter++)
			{
				if(fread(colorbuffer, 1, tga.bytesPerPixel, fTGA) != tga.bytesPerPixel)
				{
					MessageBox(NULL, "Could not read image data", "ERROR", MB_OK);

					if(fTGA != NULL)
					{
						fclose(fTGA);
					}

					if(colorbuffer != NULL)
					{
						free(colorbuffer);
					}

					if(image->data != NULL)
					{
						free(image->data);
					}

					return NULL;
				}
																						
				image->data[currentbyte		] = colorbuffer[2];
				image->data[currentbyte + 1	] = colorbuffer[1];
				image->data[currentbyte + 2	] = colorbuffer[0];

				if(tga.bytesPerPixel == 4)
				{
					image->data[currentbyte + 3] = colorbuffer[3];
				}

				currentbyte += tga.bytesPerPixel;
				currentpixel++;

				if(currentpixel > pixelcount)
				{
					MessageBox(NULL, "Too many pixels read", "ERROR", NULL);

					if(fTGA != NULL)
					{
						fclose(fTGA);
					}	

					if(colorbuffer != NULL)
					{
						free(colorbuffer);
					}

					if(image->data != NULL)
					{
						free(image->data);
					}

					return NULL;
				}
			}
		}
		else
		{
			chunkheader -= 127;
			if(fread(colorbuffer, 1, tga.bytesPerPixel, fTGA) != tga.bytesPerPixel)
			{	
				MessageBox(NULL, "Could not read from file", "ERROR", MB_OK);

				if(fTGA != NULL)
				{
					fclose(fTGA);
				}

				if(colorbuffer != NULL)
				{
					free(colorbuffer);
				}

				if(image->data != NULL)
				{
					free(image->data);
				}

				return NULL;
			}

			for(short counter = 0; counter < chunkheader; counter++)
			{
				image->data[currentbyte		] = colorbuffer[2];
				image->data[currentbyte + 1	] = colorbuffer[1];
				image->data[currentbyte + 2	] = colorbuffer[0];

				if(tga.bytesPerPixel == 4)
				{
					image->data[currentbyte + 3] = colorbuffer[3];
				}

				currentbyte += tga.bytesPerPixel;
				currentpixel++;

				if(currentpixel > pixelcount)
				{
					MessageBox(NULL, "Too many pixels read", "ERROR", NULL);

					if(fTGA != NULL)
					{
						fclose(fTGA);
					}	

					if(colorbuffer != NULL)
					{
						free(colorbuffer);
					}

					if(image->data != NULL)
					{
						free(image->data);
					}

					return NULL;
				}
			}
		}
	}

	while(currentpixel < pixelcount);
	fclose(fTGA);
	return image;
}


/*
TextureImage* LoadTGA(const char * filename)
{
	TGAHeader tgaheader;
	TextureImage* image;
	std::string errmsg;
	FILE* file = fopen(filename, "rb");

	if(file == NULL)
	{
		errmsg = "Could not open texture file ";
		errmsg = errmsg + filename;
		MessageBox(NULL, errmsg.c_str(), "ERROR", MB_OK);
		return NULL;
	}

	if(fread(&tgaheader, sizeof(TGAHeader), 1, file) == 0)
	{
		MessageBox(NULL, "Could not read file header", "ERROR", MB_OK);
		if(file != NULL)
			fclose(file);
		return NULL;
	}

	if(memcmp(uTGAcompare, &tgaheader, sizeof(tgaheader)) == 0)
		image = LoadUncompressedTGA(file);
	else if(memcmp(cTGAcompare, &tgaheader, sizeof(tgaheader)) == 0)
		image = LoadCompressedTGA(file);
	else
	{
		MessageBox(NULL, "TGA file must be type 2 or type 10 ", "Invalid Image", MB_OK);
		fclose(file);
		return NULL;
	}
	return image;
}

TextureImage* LoadUncompressedTGA(FILE * fTGA)
{
	TGA tga;
	TextureImage* image = new TextureImage;
	
	if(fread(tga.header, sizeof(tga.header), 1, fTGA) == 0)
	{										
		MessageBox(NULL, "Could not read info header", "ERROR", MB_OK);
		if(fTGA != NULL)
		{
			fclose(fTGA);
		}
		return NULL;
	}	

	image->sizeY  = tga.header[1] * 256 + tga.header[0];
	image->sizeX = tga.header[3] * 256 + tga.header[2];
	image->bpp	= tga.header[4];
	tga.Width		= image->sizeX;
	tga.Height		= image->sizeY;
	tga.Bpp			= image->bpp;

	if((image->sizeX <= 0) || (image->sizeY <= 0) || ((image->bpp != 24) && (image->bpp !=32)))
	{
		MessageBox(NULL, "Invalid texture information", "ERROR", MB_OK);
		if(fTGA != NULL)
		{
			fclose(fTGA);
		}
		return NULL;
	}

	if(image->bpp == 24)
	{
		image->type	= GL_RGB;
	}
	else
	{
		image->type	= GL_RGBA;
	}

	tga.bytesPerPixel	= (tga.Bpp / 8);
	tga.imageSize		= (tga.bytesPerPixel * tga.Width * tga.Height);
	image->data	= (GLubyte *)malloc(tga.imageSize);

	if(image->data == NULL)
	{
		MessageBox(NULL, "Could not allocate memory for image", "ERROR", MB_OK);
		fclose(fTGA);
		return NULL;
	}

	if(fread(image->data, 1, tga.imageSize, fTGA) != tga.imageSize)
	{
		MessageBox(NULL, "Could not read image data", "ERROR", MB_OK);
		if(image->data != NULL)
		{
			free(image->data);
		}
		fclose(fTGA);
		return NULL;
	}

	
	for(GLuint cswap = 0; cswap < (int)tga.imageSize; cswap += tga.bytesPerPixel)
	{
		image->data[cswap] ^= image->data[cswap+2] ^=
		image->data[cswap] ^= image->data[cswap+2];
	}

	fclose(fTGA);
	return image;
}

TextureImage* LoadCompressedTGA(FILE * fTGA)
{
	TextureImage* image = new TextureImage;
	TGA tga;

	if(fread(tga.header, sizeof(tga.header), 1, fTGA) == 0)
	{
		MessageBox(NULL, "Could not read info header", "ERROR", MB_OK);
		if(fTGA != NULL)
		{
			fclose(fTGA);
		}
		return NULL;
	}

	image->sizeX  = tga.header[1] * 256 + tga.header[0];
	image->sizeY = tga.header[3] * 256 + tga.header[2];
	image->bpp	= tga.header[4];
	tga.Width		= image->sizeX;
	tga.Height		= image->sizeY;
	tga.Bpp			= image->bpp;

	if((image->sizeX <= 0) || (image->sizeY <= 0) || ((image->bpp != 24) && (image->bpp !=32)))
	{
		MessageBox(NULL, "Invalid texture information", "ERROR", MB_OK);
		if(fTGA != NULL)
		{
			fclose(fTGA);
		}
		return NULL;
	}

	tga.bytesPerPixel	= (tga.Bpp / 8);
	tga.imageSize		= (tga.bytesPerPixel * tga.Width * tga.Height);
	image->data	= (GLubyte *)malloc(tga.imageSize);

	if(image->data == NULL)
	{
		MessageBox(NULL, "Could not allocate memory for image", "ERROR", MB_OK);
		fclose(fTGA);
		return NULL;
	}

	GLuint pixelcount	= tga.Height * tga.Width;
	GLuint currentpixel	= 0;
	GLuint currentbyte	= 0;
	GLubyte * colorbuffer = (GLubyte *)malloc(tga.bytesPerPixel);

	do
	{
		GLubyte chunkheader = 0;

		if(fread(&chunkheader, sizeof(GLubyte), 1, fTGA) == 0)
		{
			MessageBox(NULL, "Could not read RLE header", "ERROR", MB_OK);
			if(fTGA != NULL)
			{
				fclose(fTGA);
			}
			if(image->data != NULL)
			{
				free(image->data);
			}
			return NULL;
		}

		if(chunkheader < 128)
		{
			chunkheader++;
			for(short counter = 0; counter < chunkheader; counter++)
			{
				if(fread(colorbuffer, 1, tga.bytesPerPixel, fTGA) != tga.bytesPerPixel)
				{
					MessageBox(NULL, "Could not read image data", "ERROR", MB_OK);

					if(fTGA != NULL)
					{
						fclose(fTGA);
					}

					if(colorbuffer != NULL)
					{
						free(colorbuffer);
					}

					if(image->data != NULL)
					{
						free(image->data);
					}

					return NULL;
				}
																						
				image->data[currentbyte		] = colorbuffer[2];
				image->data[currentbyte + 1	] = colorbuffer[1];
				image->data[currentbyte + 2	] = colorbuffer[0];

				if(tga.bytesPerPixel == 4)
				{
					image->data[currentbyte + 3] = colorbuffer[3];
				}

				currentbyte += tga.bytesPerPixel;
				currentpixel++;

				if(currentpixel > pixelcount)
				{
					MessageBox(NULL, "Too many pixels read", "ERROR", NULL);

					if(fTGA != NULL)
					{
						fclose(fTGA);
					}	

					if(colorbuffer != NULL)
					{
						free(colorbuffer);
					}

					if(image->data != NULL)
					{
						free(image->data);
					}

					return NULL;
				}
			}
		}
		else
		{
			chunkheader -= 127;
			if(fread(colorbuffer, 1, tga.bytesPerPixel, fTGA) != tga.bytesPerPixel)
			{	
				MessageBox(NULL, "Could not read from file", "ERROR", MB_OK);

				if(fTGA != NULL)
				{
					fclose(fTGA);
				}

				if(colorbuffer != NULL)
				{
					free(colorbuffer);
				}

				if(image->data != NULL)
				{
					free(image->data);
				}

				return NULL;
			}

			for(short counter = 0; counter < chunkheader; counter++)
			{
				image->data[currentbyte		] = colorbuffer[2];
				image->data[currentbyte + 1	] = colorbuffer[1];
				image->data[currentbyte + 2	] = colorbuffer[0];

				if(tga.bytesPerPixel == 4)
				{
					image->data[currentbyte + 3] = colorbuffer[3];
				}

				currentbyte += tga.bytesPerPixel;
				currentpixel++;

				if(currentpixel > pixelcount)
				{
					MessageBox(NULL, "Too many pixels read", "ERROR", NULL);

					if(fTGA != NULL)
					{
						fclose(fTGA);
					}	

					if(colorbuffer != NULL)
					{
						free(colorbuffer);
					}

					if(image->data != NULL)
					{
						free(image->data);
					}

					return NULL;
				}
			}
		}
	}

	while(currentpixel < pixelcount);
	fclose(fTGA);
	return image;
}
*/