/*********************/
/*** Texture Cache ***/
/*********************/

#include	"stdafx.h"
#include	<gl\gl.h>
#include	<gl\glu.h>
#include	<frame.hpp>
#include	<gfname.hpp>
#include	<Vector>

#include	"TexCache.h"
#include	"utils.h"

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
int		CTexCache::GetTexIdx(const char *Filename,int Flags)
{
sTex	Tex;
		Tex.Filename=Filename;
		Tex.Flags=Flags;
		return(TexList.Find(Tex));
}
*/
/*****************************************************************************/
// Checks loaded files for dups, assumes all passed RGB is unique
int		CTexCache::ProcessTexture(const char *Filename,int Flags,sRGBData *RGBData)
{
int			ListSize=TexList.size();
sTex		NewTex;
sRGBData	ThisRGB;
GFName		FName=Filename;

		NewTex.Name=FName.File();
		NewTex.Filename=Filename;
		NewTex.Flags=Flags;

		if (!RGBData)	// Need to load file
		{
			int	Idx=GetTexIdx(NewTex);	// Is already loaded?
			if (Idx!=-1) return(Idx);

			TRACE1("Loading Texture %s\n",NewTex.Filename);
			
			if (!LoadBMP(NewTex.Filename,ThisRGB))
			{
				exit(-1);
				return(ListSize);
			}
			RGBData=&ThisRGB;
			LoadTex(NewTex,RGBData);
			FreeBMP(ThisRGB);
			NewTex.Loaded=TRUE;
		}
		else
		{
			LoadTex(NewTex,RGBData);
			NewTex.Loaded=FALSE;
		}

		TexList.push_back(NewTex);
				
		return(ListSize);
}

/**************************************************************************************/
/**************************************************************************************/
/**************************************************************************************/
const int	TexAlignTable[]={1,2,4,8,16,32,64,128,256};
const int	TexAlignTableSize=sizeof(TexAlignTable)/sizeof(int);
int		CTexCache::AlignSize(int Size)
{
		for (int i=0;i<TexAlignTableSize-1; i++)
		{
			if (Size>TexAlignTable[i] && Size<TexAlignTable[i+1]) return(TexAlignTable[i+1]);
		}

		return(Size);
}


/**************************************************************************************/
bool	CTexCache::LoadBMP(const char *Filename,sRGBData &RGBData)
{
Frame	ThisFrame;
FILE	*File;
// Check File exists
		File=fopen(Filename,"r");
		
		if (!File)
		{
			CString mexstr;
			mexstr.Format("%s Not Found\n", Filename);
			AfxMessageBox(mexstr,MB_OK | MB_ICONEXCLAMATION);
			exit(EXIT_FAILURE );
			return(false);
		}

		fclose(File);		
		ThisFrame.LoadBMP(Filename);
				
		RGBData.Width=ThisFrame.GetWidth();
		RGBData.Height=ThisFrame.GetHeight();
		RGBData.RGB=(u8*)malloc(RGBData.Width*RGBData.Height*3);
		ThisFrame.FlipY();
		ThisFrame.MakeRGB(RGBData.RGB);
		return(true);
}

/**************************************************************************************/
void	CTexCache::FreeBMP(sRGBData &RGBData)
{
		if (RGBData.RGB)
		{
			free(RGBData.RGB);
		}
}

/**************************************************************************************/
void	CTexCache::LoadTex(sTex &ThisTex,sRGBData *TexData)
{
u8		*Buffer;
int		TexWidth=TexData->Width;
int		TexHeight=TexData->Height;
int		GLWidth=AlignSize(TexWidth);
int		GLHeight=AlignSize(TexHeight);
u8		*Src,*Dst;

// create RGB & alpha texture & ensuse texture is correct size for GL

		Buffer=(u8*)malloc(GLWidth*GLHeight*4);
		Src=TexData->RGB;
		Dst=&Buffer[0];

		for (int Y=0; Y<TexHeight; Y++)
		{
			for (int X=0; X<TexWidth; X++)
			{
				u8	R,G,B,A;

				R=*Src++;
				G=*Src++;
				B=*Src++;
				A=255;
				if ((R==BlankRGB.rgbRed && G==BlankRGB.rgbGreen && B==BlankRGB.rgbBlue))	// Create alpha for transparent pixels (flagged with PINK!!)
					{
						A=0;
					}
				*Dst++=R;
				*Dst++=G;
				*Dst++=B;
				*Dst++=A;
			}
			Dst+=(GLWidth-TexWidth)*4;
		}

		ThisTex.TexWidth=TexWidth;
		ThisTex.TexHeight=TexHeight;

		ThisTex.dW=(1.0f)/(float)(GLWidth/16.0f);
		ThisTex.dH=(1.0f)/(float)(GLHeight/16.0f);

		glGenTextures(1, &ThisTex.TexID);
		glBindTexture(GL_TEXTURE_2D, ThisTex.TexID);
		glTexImage2D(GL_TEXTURE_2D, 0, 4, GLWidth, GLHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, &Buffer[0]);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
		glBindTexture(GL_TEXTURE_2D, 0);
		free(Buffer);
}

/**************************************************************************************/
/**************************************************************************************/
/**************************************************************************************/
void	CTexCache::Purge()
{
int	ListSize=TexList.size();

	TRACE1("Purging %i textures\n",ListSize);

	for (int i=0; i<ListSize; i++)
	{
		glDeleteTextures(1,&TexList[i].TexID);
	}

	TexList.clear();
}

/**************************************************************************************/