#include "main.h"

bool LoadUncompressedTGA(void);
bool LoadCompressedTGA(void);

struct STGAINFO
{
    unsigned char ucHeader[6];
    unsigned int uiBytesPerPixel;
    unsigned int uiImageSize;
    unsigned int uiTemp;
    unsigned int uiType;
    unsigned int uiHeight;
    unsigned int uiWidth;
    unsigned int uiBpp;
};

typedef struct SIMAGE_INFO_TYP
{
    unsigned char* ucpData;
    unsigned int uiBpp;
    unsigned int uiWidth;
    unsigned int uiHeight;
    unsigned int uiType;
    unsigned int uiID;
} SIMAGE_INFO;

SIMAGE_INFO l_ImageInfo;

unsigned char l_ucUTGAcompare[12] = {0, 0, 2,  0, 0, 0, 0, 0, 0, 0, 0, 0};
unsigned char l_ucCTGAcompare[12] = {0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0};

static unsigned char* l_upcBuffer = NULL;

uint LoadTGAFile(char *a_szFilename)
{
    printf("-=uImage=-\tCreated image...\n");

    unsigned int uiTempID;

    printf("\t\tTrying to load file \"%s\".\n", a_szFilename);

    int iFile = _sopen(a_szFilename, _O_RDONLY | _O_BINARY, 0x40, _S_IREAD | _S_IWRITE);

    if(iFile < 0)
    {
        printf("\t\t\\- Could not load \"%s\". It doesn't appear to exist.\n", a_szFilename);
        return 0;
    }

    int iSize = 0, iStart = 0, iEnd = 0;
	iStart = _lseek(iFile, 0, SEEK_SET);
	iEnd = _lseek(iFile, 0, SEEK_END);
    iSize = iEnd - iStart;

    printf("\t\t\\- Filesize: %dkb\n", iSize / 1024);

    _lseek(iFile, 0, SEEK_SET);

    l_upcBuffer = new unsigned char[iSize];
    if(l_upcBuffer == NULL)
    {
        printf("\t\t\\- Memory error. Failed to resize array.\n");
        return 0;
    }

    int iBytesRead = 0;
	iBytesRead = _read(iFile, l_upcBuffer, iSize);

    if(iSize != iBytesRead)
    {
        printf("\t\t\\- Could not load \"%s\". Error while reading.\n", a_szFilename);
        _close(iFile);
        return 0;
    }

    _close(iFile);

    if(memcmp(l_upcBuffer, l_ucUTGAcompare, 12) == 0)
    {
        if(!LoadUncompressedTGA())
        {
            if(l_upcBuffer)
            {
                delete [] l_upcBuffer;
                l_upcBuffer = NULL;
            }
            return 0;
        }
    }
    else if(memcmp(l_upcBuffer, l_ucCTGAcompare, 12) == 0)
    {
        if(!LoadCompressedTGA())
        {
            if(l_upcBuffer)
            {
                delete [] l_upcBuffer;
                l_upcBuffer = NULL;
            }
            return 0;
        }
    }
    else
    {
        printf("\t\t\\- Could not load \"%s\". Unrecognized format.\n", a_szFilename);
        if(l_upcBuffer)
        {
            delete [] l_upcBuffer;
            l_upcBuffer = NULL;
        }
        return 0;
    }

    glGenTextures(1, &uiTempID);
    glBindTexture(GL_TEXTURE_2D, uiTempID);

    if(l_ImageInfo.uiBpp==24)
        l_ImageInfo.uiType= GL_RGB;
    else l_ImageInfo.uiType= GL_RGBA;

    glTexImage2D(GL_TEXTURE_2D, 0, l_ImageInfo.uiType, l_ImageInfo.uiWidth, l_ImageInfo.uiHeight, 0, l_ImageInfo.uiType, GL_UNSIGNED_BYTE, l_ImageInfo.ucpData);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    if(l_ImageInfo.ucpData) delete[] l_ImageInfo.ucpData;

    if(l_upcBuffer)
    {
        delete [] l_upcBuffer;
        l_upcBuffer = NULL;
    }

    printf("\t\t\\- Successfully loaded \"%s\".\n", a_szFilename);

    return uiTempID;
}

bool LoadUncompressedTGA(void)
{
    unsigned int uiCSwap;
    STGAINFO pTGAinfo;
    unsigned char *ucpFile = l_upcBuffer;

    ucpFile += 12;

    memcpy(pTGAinfo.ucHeader, ucpFile, sizeof(unsigned char[6]));

    l_ImageInfo.uiWidth = pTGAinfo.ucHeader[1] * 256 + pTGAinfo.ucHeader[0];
    l_ImageInfo.uiHeight = pTGAinfo.ucHeader[3] * 256 + pTGAinfo.ucHeader[2];
    l_ImageInfo.uiBpp = pTGAinfo.ucHeader[4];

    pTGAinfo.uiBpp = l_ImageInfo.uiBpp;
    pTGAinfo.uiHeight = l_ImageInfo.uiHeight;
    pTGAinfo.uiWidth = l_ImageInfo.uiWidth;

    ucpFile += 6;

    if((l_ImageInfo.uiWidth <= 0) || (l_ImageInfo.uiHeight <= 0) || ((l_ImageInfo.uiBpp != 24) && (l_ImageInfo.uiBpp != 32)))
    return false;

    pTGAinfo.uiBytesPerPixel = pTGAinfo.uiBpp / 8;
    pTGAinfo.uiImageSize = (pTGAinfo.uiBytesPerPixel * pTGAinfo.uiWidth * pTGAinfo.uiHeight);
    l_ImageInfo.ucpData = new unsigned char [pTGAinfo.uiImageSize];

    if(l_ImageInfo.ucpData == NULL) return false;

    memcpy(l_ImageInfo.ucpData, ucpFile, pTGAinfo.uiImageSize);

    for(uiCSwap = 0; uiCSwap < pTGAinfo.uiImageSize; uiCSwap += pTGAinfo.uiBytesPerPixel)
    {
        l_ImageInfo.ucpData[uiCSwap] ^= l_ImageInfo.ucpData[uiCSwap+2] ^=
        l_ImageInfo.ucpData[uiCSwap] ^= l_ImageInfo.ucpData[uiCSwap+2];
    }

    return true;
}

bool LoadCompressedTGA(void)
{
	unsigned char* ucpColorBuffer;
	unsigned char  ucChunkHeader;	
	unsigned int   uiPixelCount;
	unsigned int   uiCurrentPixel;
	unsigned int   uiCurrentByte;
	short		   i;
	STGAINFO pTGAinfo;
	unsigned char *ucpFile = l_upcBuffer;

	ucpFile += 12;

	memcpy(pTGAinfo.ucHeader, ucpFile, sizeof(unsigned char[6]));

	l_ImageInfo.uiWidth = pTGAinfo.ucHeader[1] * 256 + pTGAinfo.ucHeader[0];
	l_ImageInfo.uiHeight= pTGAinfo.ucHeader[3] * 256 + pTGAinfo.ucHeader[2];
	l_ImageInfo.uiBpp   = pTGAinfo.ucHeader[4];
	
	pTGAinfo.uiBpp = l_ImageInfo.uiBpp;
	pTGAinfo.uiHeight = l_ImageInfo.uiHeight;
	pTGAinfo.uiWidth = l_ImageInfo.uiWidth;

	ucpFile += 6;

	if((l_ImageInfo.uiWidth<=0) || (l_ImageInfo.uiHeight<=0) || ((l_ImageInfo.uiBpp!=24) && (l_ImageInfo.uiBpp!=32)))
		return false;

	pTGAinfo.uiBytesPerPixel= pTGAinfo.uiBpp / 8;
	pTGAinfo.uiImageSize = (pTGAinfo.uiBytesPerPixel * pTGAinfo.uiWidth * pTGAinfo.uiHeight);
	l_ImageInfo.ucpData = new unsigned char [pTGAinfo.uiImageSize];

	if(l_ImageInfo.ucpData==NULL)
		return false;

	uiPixelCount = pTGAinfo.uiHeight * pTGAinfo.uiWidth;
	uiCurrentPixel = 0;
	uiCurrentByte = 0;
	ucpColorBuffer= new unsigned char [pTGAinfo.uiBytesPerPixel];

	do
	{
		ucChunkHeader= 0;

		ucChunkHeader = *(unsigned char*)ucpFile;
		ucpFile++;

		if(ucChunkHeader<128)
		{
			ucChunkHeader++;

			//Read RAW color values
			for(i=0; i<ucChunkHeader; i++)
			{
				memcpy(ucpColorBuffer, ucpFile, pTGAinfo.uiBytesPerPixel);
				ucpFile += pTGAinfo.uiBytesPerPixel;
				
				//Flip R and B color values around
				l_ImageInfo.ucpData[uiCurrentByte]  = ucpColorBuffer[2];
				l_ImageInfo.ucpData[uiCurrentByte+1]= ucpColorBuffer[1];
				l_ImageInfo.ucpData[uiCurrentByte+2]= ucpColorBuffer[0];

				if(pTGAinfo.uiBytesPerPixel==4)
					l_ImageInfo.ucpData[uiCurrentByte+3]= ucpColorBuffer[3];

				uiCurrentByte += pTGAinfo.uiBytesPerPixel;
				uiCurrentPixel++;

				//Make sure too many pixels have not been read in
				if(uiCurrentPixel>uiPixelCount)
				{
					if(ucpColorBuffer!=NULL)
						delete[] ucpColorBuffer;
					if(l_ImageInfo.ucpData!=NULL)
						delete[] l_ImageInfo.ucpData;
					return false;
				}
			}
		}

		//The chunk header is greater than 128 RLE data
		else
		{
			ucChunkHeader-= 127;

			memcpy(ucpColorBuffer, ucpFile, pTGAinfo.uiBytesPerPixel);
			ucpFile += pTGAinfo.uiBytesPerPixel;

			// Copy the color into the image data as many times as needed
			for(i=0; i<ucChunkHeader; i++)					
			{
				//Switch R and B bytes around while copying
				l_ImageInfo.ucpData[uiCurrentByte]  = ucpColorBuffer[2];					
				l_ImageInfo.ucpData[uiCurrentByte+1]= ucpColorBuffer[1];
				l_ImageInfo.ucpData[uiCurrentByte+2]= ucpColorBuffer[0];

				if(pTGAinfo.uiBytesPerPixel==4)
					l_ImageInfo.ucpData[uiCurrentByte+3]= ucpColorBuffer[3];

				uiCurrentByte += pTGAinfo.uiBytesPerPixel;
				uiCurrentPixel++;

				//Make sure that we have not written too many pixels
				if(uiCurrentPixel>uiPixelCount)
				{
					if(ucpColorBuffer!=NULL)
						delete[] ucpColorBuffer;
					if(l_ImageInfo.ucpData!=NULL)
						delete[] l_ImageInfo.ucpData;
					return false;
				}
			}
		}
	}

	//Loop while there are still pixels left
	while(uiCurrentPixel<uiPixelCount);

	return true;					
}
