#include "stdafx.h"
#include "globals.h"
#include "fontevw.h"
#include "english.h"
#include "alphaonly.h"
#include "mac.h"
#include "clubs.h"
#include "foreign.h"
#include "all.h"
#include "font.h"
#include "assert.h"
#include "targa.h"



static BOOL bBackOpaque=FALSE;
static BYTE frRed=0xFF,frGreen=0xFF,frBlue=0xFF;
static BYTE bkRed=0x00,bkGreen=0x00,bkBlue=0x00;
static BYTE *pfWorkspace=0;
static int wsWidth=0;
static int wsHeight=0;

BOOL DrawGrayscaleBmp(HDC hDC,int x,int y,int w,int h,BYTE *pPixels)
{
	LPBITMAPINFO lplocalbmi=NULL;
	BYTE *lplocalpixels=NULL;

	lplocalbmi = (BITMAPINFO *)new BYTE[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)];
	lplocalpixels = new BYTE[w*h];

	int nBmpWidth = w + ((w&0x3)?(4-(w&3)):0); // figure out 4 byte aligned width (make windows happy)

	lplocalbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	lplocalbmi->bmiHeader.biWidth = nBmpWidth;
	lplocalbmi->bmiHeader.biHeight = -h;
	lplocalbmi->bmiHeader.biPlanes = 1;
	lplocalbmi->bmiHeader.biBitCount = 8;
	lplocalbmi->bmiHeader.biCompression = BI_RGB;
	lplocalbmi->bmiHeader.biSizeImage = 0;
	lplocalbmi->bmiHeader.biClrUsed = 0;
	lplocalbmi->bmiHeader.biClrImportant = 0;

	BYTE *pOut = lplocalpixels;
	BYTE *pIn = pPixels;
	int n;
	for (n=0; n<h; n++)
	{
		memcpy(pOut,pIn,w);
		pOut += nBmpWidth;
		pIn += w;
	}	
	for (n=0; n<256; n++)
	{
		lplocalbmi->bmiColors[n].rgbRed = n;
		lplocalbmi->bmiColors[n].rgbGreen = n;
		lplocalbmi->bmiColors[n].rgbBlue = n;
	}

	int nResult = SetDIBitsToDevice(hDC,
						x,y,
						w,h,
						0,0,
						0,h,
						lplocalpixels,
						lplocalbmi,
						DIB_RGB_COLORS);

	delete lplocalbmi;
	delete lplocalpixels;
	return (nResult > 0);
}

BOOL Draw32BitBmp(HDC hDC,int x,int y,int w,int h,BYTE *pPixels)
{
	LPBITMAPINFO lplocalbmi=NULL;
	DWORD *lplocalpixels=NULL;

	lplocalbmi = (BITMAPINFO *)new BYTE[sizeof(BITMAPINFO)];
	lplocalpixels = new DWORD[(w+4)*h];

	int nBmpWidth = w + ((w&0x3)?(4-(w&3)):0); // figure out 4 byte aligned width (make windows happy)

	lplocalbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	lplocalbmi->bmiHeader.biWidth = nBmpWidth;
	lplocalbmi->bmiHeader.biHeight = h;
	lplocalbmi->bmiHeader.biPlanes = 1;
	lplocalbmi->bmiHeader.biBitCount = 32;
	lplocalbmi->bmiHeader.biCompression = BI_RGB;
	lplocalbmi->bmiHeader.biSizeImage = 0;
	lplocalbmi->bmiHeader.biClrUsed = 0;
	lplocalbmi->bmiHeader.biClrImportant = 0;

	DWORD *pOut = lplocalpixels + w*(h-1);
	DWORD *pIn = (DWORD *)pPixels;
	int n;
	for (n=0; n<h; n++)
	{
		memcpy(pOut,pIn,w*sizeof(DWORD));
		pOut -= nBmpWidth;
		pIn += w;
	}	

	int nResult = SetDIBitsToDevice(hDC,
						x,y,
						w,h,
						0,0,
						0,h,
						(BYTE *)lplocalpixels,
						lplocalbmi,
						DIB_RGB_COLORS);

	delete lplocalbmi;
	delete lplocalpixels;
	return (nResult > 0);
}

Font::Font(char *szFaceName,int iHeight,bool bItalic,int iWeight,bool bAntiAlias,bool bMinimizeTextureCount) 
{ // convert a TT font to our anti-aliased format
	this->bMinimizeTextureCount = bMinimizeTextureCount;
	b32Bit = false;
	strcpy(header.szFaceName,szFaceName);
	header.iWeight = iWeight;
	header.bItalic = bItalic;
	header.iSize = iHeight;
	memset(data,0,sizeof(data));
	Char *cmap_char;
	int n;
	CFont  font;
	CDC dc;
	CSize sz;
	BYTE *pPixels;
	char szChar[2] = " ";
	CBitmap bmp;
	TEXTMETRIC tm;
	ABC abc;

	if (nLanguage == 100)
		cmap_char = cmap_alphaonly;
	else
		cmap_char = cmap_foreign;


	CDC *pDC = view->GetDC();

	dc.CreateCompatibleDC(pDC);
	view->ReleaseDC(pDC);
	dc.SetTextColor(0xFFFFFF);
	dc.SetBkColor(0);

	int iSize = iHeight;
	if (bAntiAlias)
		iSize *= 8;
		
	font.CreateFont(iSize,
										0,
										0,
										0,
										iWeight,
										bItalic,
										0,
										0,
										DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,PROOF_QUALITY,DEFAULT_PITCH|FF_DONTCARE,
										szFaceName);

	CFont *oldfont = dc.SelectObject(&font);	
	CBitmap *oldbmp;
	dc.GetTextMetrics(&tm);

	for (n=0; n<256; n++)
	{
		if (cmap_char[n].nOffset) // add char if it's listed in this array as one to include
		{
			int a,c;
			szChar[0] = (char)n;
			
			// figure out how wide the character is
			sz = dc.GetTextExtent(szChar,1);
			GetCharABCWidths(dc.m_hDC,(BYTE)*szChar,(BYTE)*szChar,&abc);
			sz.cx = abc.abcB;
			if (bAntiAlias)
			{
				sz.cx += 8;

				// create a monochrom bitmap with 8x8 pixels per resultant alpha value
				pPixels = (BYTE *)malloc(((sz.cx+16) * (sz.cy+8)));
				memset(pPixels,0,((sz.cx+16) * (sz.cy+8)));
				bmp.CreateBitmap(sz.cx,sz.cy ,1,1,pPixels);
				oldbmp = dc.SelectObject(&bmp);
				dc.PatBlt(0,0,sz.cx,sz.cy,BLACKNESS);
				dc.TextOut(-abc.abcA,0,szChar,1);
				a = abc.abcA;
				c = abc.abcC;
				c-=8; // BECAUSE WE ADDED 8 TO sz.cx above
				if (a<0)
					a-=4;
				else
					a+=4;
				if (c<0)
					c-=4;
				else
					c+=4;
				a/=8;
				c/=8;
				bmp.GetBitmapBits(((sz.cx+16) * sz.cy)/8,pPixels);
				// do the work of converting the monochrome bitmap to an alpha bimap and add it to the font
				CalcAlphaAndAddChar(pPixels,sz.cx,sz.cy,n,a,c);
				free(pPixels);
				dc.SelectObject(oldbmp);
				bmp.DeleteObject();
			}
			else
			{ // non-antialiased

				// create a monochrom bitmap with 8x8 pixels per resultant alpha value
				pPixels = (BYTE *)malloc(((sz.cx+16) * (sz.cy+8)));
				memset(pPixels,0,((sz.cx+16) * (sz.cy+8)));
				bmp.CreateBitmap(sz.cx,sz.cy ,1,1,pPixels);
				oldbmp = dc.SelectObject(&bmp);
				dc.PatBlt(0,0,sz.cx,sz.cy,BLACKNESS);
				dc.TextOut(-abc.abcA,0,szChar,1);
				a = abc.abcA;
				c = abc.abcC;
				bmp.GetBitmapBits(((sz.cx+16) * sz.cy)/8,pPixels);
				// do the work of converting the monochrome bitmap to an alpha bimap and add it to the font
				CalcAndAddChar(pPixels,sz.cx,sz.cy,n,a,c);
				free(pPixels);
				dc.SelectObject(oldbmp);
				bmp.DeleteObject();
			}
		}
		else
			data[n].bUsed = false;
	}
	dc.DeleteDC();

	BuildTextures();
	CleanTempData();
}	

Font::Font(const char *szFileName,bool &bSuccess)
{ // load a font from a file
	bSuccess = false;
	OFSTRUCT of;
	HFILE hFile = OpenFile(szFileName,&of,OF_READ);
	if (hFile == HFILE_ERROR)
		return;

	_lread(hFile,&header,sizeof(header));
	if (header.dwSig == D3DFONTSIG)
	{
		b32Bit = false;
	}
	else if (header.dwSig == D3D32BITFONTSIG)
	{
		b32Bit = true;
	}
	else
	{
		_lclose(hFile);
		return;
	}
	for (int i=0; i<header.iTextureCount; i++)
	{
		pTextures[i] = new FontTexture(hFile,(int)header.dwFontHeight,b32Bit);
	}
	
	iNumTextures = header.iTextureCount;
	bSuccess = true;
}

Font::~Font()
{
	CleanTextures();
}



void Font::CalcAlphaAndAddChar(BYTE *pPixels,int width,int height,int num,int a, int c)
{
	int bmpw,bmph,rbmpw;
	BYTE *pAAPix;
	BYTE *pCur;
	int x,y,n;
	int val;
	

	bmpw = (width)/8 ;
	if (width%8)
		bmpw++;
	rbmpw = bmpw;

	bmph = (height/8)+1;

	if (bmpw & 1)
		rbmpw++;

	pAAPix = (BYTE *)malloc(bmpw * bmph * 2);
	for (y=0; y<bmph; y++)
	{
		for (x=0; x<bmpw; x++)
		{
			pCur = pPixels + (y*rbmpw*8) + x;
			val = 0;
			for (n=0; n<8; n++)
			{
				val += (*pCur & 0x01)?1:0;
				val += (*pCur & 0x02)?1:0;
				val += (*pCur & 0x04)?1:0;
				val += (*pCur & 0x08)?1:0;
				val += (*pCur & 0x10)?1:0;
				val += (*pCur & 0x20)?1:0;
				val += (*pCur & 0x40)?1:0;
				val += (*pCur & 0x80)?1:0;
				pCur += rbmpw;
			}
			val<<=2;
			if (val)
				val-=1;
			//if (val > 8)
			//	val += 40;
			if (val > 255)
				val = 255;

			// adjust for gama
			pAAPix[y*bmpw + x] = ((BYTE)(val & ALIAS_MASK))>>ALIAS_SHIFT;
		}
	}
	// check to see if this char is the same as the default char
	// there is no good way to determine if a given character actually exists in a font
	// so we're just going to compare the resulatant bitmap with the character zero
	// if it's exactly the same we're not going to add it to the font
	if (num)
	{
		BYTE *pData = data[0].pData;
		if (bmpw == data[0].bWidth)
		{
			int iSize = bmpw * bmph;
			if (!memcmp(pData,pAAPix,iSize))
			{
				data[num].bUsed = false;
				return; // don't add the char because it's the same as the default char
			}
		}
	}
	AddChar(pAAPix,bmpw,bmph,num,a,c);
}

void Font::CalcAndAddChar(BYTE *pPixels,int width,int height,int num,int a, int c)
{
	int bmpw,bmph,rbmpw;
	BYTE *pAAPix;
	BYTE *pCur;
	int x,y;
	int val;
	

	bmpw = width;
	rbmpw = bmpw/8;
	if (bmpw & 0x7)
		rbmpw ++;

	bmph = height;

	if (rbmpw & 1)
		rbmpw++;

	bmpw += 1; // add one pixel between each letter
	pAAPix = (BYTE *)malloc(bmpw * bmph * 2);
	for (y=0; y<bmph; y++)
	{
		for (x=0; x<bmpw; x++)
		{
			pCur = pPixels + (y*rbmpw) + x/8;
			int mask = 1 << (7-(x%8));
			val = 0;
			if (*pCur & mask)
				val = 255;
			pAAPix[y*bmpw + x] = ((BYTE)(val & ALIAS_MASK))>>ALIAS_SHIFT;
		}
	}
	// check to see if this char is the same as the default char
	// there is no good way to determine if a given character actually exists in a font
	// so we're just going to compare the resulatant bitmap with the character zero
	// if it's exactly the same we're not going to add it to the font
	if (num)
	{
		BYTE *pData = data[0].pData;
		if (bmpw == data[0].bWidth)
		{
			int iSize = bmpw * bmph;
			if (!memcmp(pData,pAAPix,iSize))
			{
				data[num].bUsed = false;
				return; // don't add the char because it's the same as the default char
			}
		}
	}
	AddChar(pAAPix,bmpw,bmph,num,a,c);
}

void Font::AddChar(BYTE *pAAPix,int w, int h,int nChar,int a, int c)
{
	data[nChar].pData = pAAPix;
	data[nChar].bWidth = w;
	data[nChar].aWidth = a;
	data[nChar].cWidth = c;
	data[nChar].bUsed = true;
	header.dwFontHeight = (DWORD)h; // all chars are same height;
}	

void Font::CleanTempData()
{
	for (int iChar = 0; iChar < 256; iChar++)
	{
		if (data[iChar].bUsed)
		{
			delete data[iChar].pData;
			data[iChar].bUsed = false;
		}
	}
}

void Font::CleanTextures()
{
	for (int iTexture = 0; iTexture < iNumTextures; iTexture++)
	{
		delete pTextures[iTexture];
	}
	iNumTextures = 0;
}


bool Font::BuildTextures()
{ // this function starts by trying to build 128x128 textures, if it ends up with more than 3 of them then it
  // tries for 1 256x256 texture and suppliments with 128x128 textures, if it still ends up with more than 3 128x128 textures
	// it tries for 2 256x256 textures, and so on and so on
	
	int iMaxLargeTextures = 0;
	int iNumSmallTextures = 0;
	iNumTextures = 0;
retry:
	CleanTextures();
	iNumSmallTextures = 0;
	if (iNumTextures >= iMaxLargeTextures)
	{
		pTextures[0] = new FontTexture((DWORD)128,header.dwFontHeight);
		iNumSmallTextures = 1;
	}
	else
	{
		pTextures[0] = new FontTexture((DWORD)256,header.dwFontHeight);
	}

	iNumTextures = 1;
	header.dwSig = D3DFONTSIG;

	for (int nChar=0; nChar<256; nChar++)
	{
		if (!nChar || data[nChar].bUsed)
		{
			bool bSuccess = false;
			for (int iTexture=0; iTexture<iNumTextures; iTexture++)
			{
				DWORD dwXPos,dwYPos;
				if (pTextures[iTexture]->AddChar(data[nChar].pData,data[nChar].bWidth,dwXPos,dwYPos))
				{ // the character fit in this texture, so note it and continue on to the next character
					header.bTexture[nChar] = (BYTE)iTexture;
					header.bX[nChar] = (BYTE)dwXPos;
					header.bY[nChar] = (BYTE)dwYPos;
					header.bW[nChar] = (BYTE)data[nChar].bWidth;
					header.cA[nChar] = (BYTE)data[nChar].aWidth;
					header.cC[nChar] = (BYTE)data[nChar].cWidth;
					bSuccess = true;
					break;
				}
			}
			if (!bSuccess)
			{ // we are out of space in the old texture(s) so
				// we need to create a new texture
				if (iNumTextures >= MAX_FONT_TEXTURES)
				{ // we've exceeded our maximum number of textures
					MessageBox(NULL,"Font too big","Error",MB_OK);
					CleanTextures();
					break;
				}
				// we need to create a new texture
				if (iNumTextures >= iMaxLargeTextures)
				{ // we've already created as many 256x256 textures as we determined, so now start creating 128x128 textures
					pTextures[iNumTextures] = new FontTexture((DWORD)128,header.dwFontHeight);
					iNumSmallTextures++;
					if(iNumSmallTextures > 3)
					{ // we've exceeded 3 128x128 textures, so increment the number of large textures and try another iteration
						iMaxLargeTextures++;
						goto retry;
					}
					if (bMinimizeTextureCount && iNumSmallTextures)
					{
						iMaxLargeTextures++;
						goto retry;
					}
				}
				else
				{ // we haven't used the number of 256x256 textures we determined to use, so create another
					pTextures[iNumTextures] = new FontTexture((DWORD)256,header.dwFontHeight);
				}
				iTexture = iNumTextures;
				iNumTextures++;
				DWORD dwXPos,dwYPos;
				// try to add the current character to the new texture
				if (pTextures[iTexture]->AddChar(data[nChar].pData,data[nChar].bWidth,dwXPos,dwYPos))
				{ // it worked, so note it and continue to the next char
					header.bTexture[nChar] = (BYTE)iTexture;
					header.bX[nChar] = (BYTE)dwXPos;
					header.bY[nChar] = (BYTE)dwYPos;
					header.bW[nChar] = (BYTE)data[nChar].bWidth;
					header.cA[nChar] = (BYTE)data[nChar].aWidth;
					header.cC[nChar] = (BYTE)data[nChar].cWidth;
					bSuccess = true;
				}
				else
				{ // we couldn't even fit the character on a new texture so bail
					CleanTextures();
					MessageBox(NULL,"Font too big","Error",MB_OK);
					break;
				}
			}
		}
		else
		{ // this character was either not in the font or was not in the list of characters to include
		  // so just make it point to the same spot as character zero
			header.bTexture[nChar] = header.bTexture[0];
			header.bX[nChar] = header.bX[0];
			header.bY[nChar] = header.bY[0];
			header.bW[nChar] = header.bW[0];
			header.cA[nChar] = header.cA[0];
			header.cC[nChar] = header.cC[0];
		}
	}	
	header.iTextureCount = iNumTextures;
	return true;
}

BYTE *Font::GetCharMap(int iChar)
{ // return a copy the bitmap for the specified character
	if (iChar < 0 || iChar > 255)
		return 0;
	return pTextures[header.bTexture[iChar]]->GetCharMap(header.bX[iChar],header.bY[iChar],header.bW[iChar]);
}

void Font::SetCharMap(int iChar,BYTE *pData)
{	// copy the data specified into the data for the specified char
	if (iChar < 0 || iChar > 255)
		return;
	pTextures[header.bTexture[iChar]]->SetCharMap(pData,header.bX[iChar],header.bY[iChar],header.bW[iChar]);
}

bool Font::Save(HFILE hFile)
{
	if (b32Bit)
		header.dwSig = D3D32BITFONTSIG;
	else
		header.dwSig = D3DFONTSIG;

	_lwrite(hFile,(LPCSTR)&header,sizeof(header));
	for (int iTexture = 0; iTexture < iNumTextures; iTexture++)
	{
		pTextures[iTexture]->Save(hFile);
	}
	return true;
}

void Font::Shorten()
{ 
	header.dwFontHeight--;
	for (int i=0; i<256; i++)
	{
		header.bY[i]++;
	}
	for (i=0; i<iNumTextures; i++)
	{
		pTextures[i]->ChangeFontHeight((int)header.dwFontHeight);
	}
}

void Font::ShortenFromBottom()
{ 
	header.dwFontHeight--;
	for (int i=0; i<iNumTextures; i++)
	{
		pTextures[i]->ChangeFontHeight((int)header.dwFontHeight);
	}
}

void Font::DrawTexture(HDC hDC,int iTexture, int x, int y)
{
	DrawGrayscaleBmp(hDC,x,y,pTextures[iTexture]->Size(),pTextures[iTexture]->Size(),pTextures[iTexture]->GetTexture());
	if (b32Bit)
		Draw32BitBmp(hDC,x,y+266,pTextures[iTexture]->Size(),pTextures[iTexture]->Size(),pTextures[iTexture]->Get32BitTexture());
}

void Font::ExportTGAS(const char *szTag,const char *szOutputDir)
{
	char szOutput[260];
	strcpy(szOutput,szOutputDir);
	int iLen = strlen(szOutput);
	if (szOutput[iLen-1] != '\\')
		strcat(szOutput,"\\"); // make sure the path ends in a backspace

	for (int i=0; i<iNumTextures; i++)
	{
		char szFileName[260];
		wsprintf(szFileName,"%s%s%02d.TGA",szOutput,szTag,i);
		pTextures[i]->ExportTGA(szFileName);
	}

	char szMessage[260];
	wsprintf(szMessage,"Wrote %d .TGA files to %s.",iNumTextures,szOutputDir);
	MessageBox(NULL,szMessage,"Success",MB_OK);

}

void Font::ImportTGAS(const char *szFirstFile)
{
	if (!strchr(szFirstFile,'.'))
	{
		MessageBox(NULL,"Invalid file path. Not a '.tga'.","Error",MB_OK);
		return;
	}
	// find out where the number index is in the file name
	const char *szWriteNumber = szFirstFile + strlen(szFirstFile) - 1;
	while (*szWriteNumber != '.')
		szWriteNumber--;
	szWriteNumber-=2; // it should now point to the last 
	if (!isdigit(*szWriteNumber) || !isdigit(*(szWriteNumber+1)))
	{
		MessageBox(NULL,"Invalid file path.  Could not file index numbers","Error",MB_OK);
		return;
	}
	int iNumberIndex = szWriteNumber - szFirstFile;
	for (int i=0; i<iNumTextures; i++)
	{
		char szFileName[260];
		char szNumber[10];
		strcpy(szFileName,szFirstFile);
		wsprintf(szNumber,"%02d",i);
		szFileName[iNumberIndex] = szNumber[0];
		szFileName[iNumberIndex+1] = szNumber[1];
		if (!pTextures[i]->ImportTGA(szFileName))
		{
			char szMessage[260];
			wsprintf(szMessage,"Could not load texture %s.",szFileName);
			MessageBox(NULL,szMessage,"Error",MB_OK);
			b32Bit = false;
			return;
		}
	}
	b32Bit = true;
}

FontTexture::FontTexture(DWORD dwSize,int iFontHeight)
{
	this->dwSize = dwSize;
	this->iFontHeight = iFontHeight;
	p32BitTexture = NULL;
	iNumRows = dwSize/iFontHeight;
	dwSpaceAvailableOnEachRow = new DWORD[iNumRows];
	for (int iRow = 0; iRow < iNumRows; iRow++)
		dwSpaceAvailableOnEachRow[iRow] = dwSize;
	pTexture = new BYTE[dwSize * dwSize];
	memset(pTexture,0,dwSize * dwSize);
	b32Bit = false;
	p32BitTexture = false;
}

FontTexture::FontTexture(HFILE hFile,int iFontHeight,bool b32Bit)
{
	this->b32Bit = b32Bit;
	p32BitTexture = NULL;
	_lread(hFile,&dwSize,sizeof(dwSize));
	this->iFontHeight = iFontHeight;
	iNumRows = dwSize/iFontHeight;
	dwSpaceAvailableOnEachRow = new DWORD[iNumRows];
	for (int iRow = 0; iRow < iNumRows; iRow++)
		dwSpaceAvailableOnEachRow[iRow] = 0; // we can't add anything else any more
	if (b32Bit)
	{
		// read in 32 bit texture
		p32BitTexture = new DWORD[dwSize * dwSize];
		_lread(hFile,p32BitTexture,dwSize * dwSize * 4);
		// now convert to 8 bit so we have something to work with
		DWORD dwPixels = dwSize * dwSize;
		pTexture = new BYTE[dwSize * dwSize];
		DWORD *pSource = p32BitTexture;
		BYTE *pDest = pTexture;
		while (dwPixels)
		{
			*pDest = (BYTE)((*pSource)>>24);
			pDest++;
			pSource++;
			dwPixels--;
		}
	}
	else
	{
		pTexture = new BYTE[dwSize * dwSize];
		_lread(hFile,pTexture,dwSize * dwSize);
	}
}

FontTexture::~FontTexture()
{
	delete pTexture;
	delete p32BitTexture;
	delete dwSpaceAvailableOnEachRow;
	pTexture = NULL;
	dwSpaceAvailableOnEachRow = NULL;
}

bool FontTexture::AddChar(BYTE *pData,DWORD dwWidth,DWORD &dwXPos,DWORD &dwYPos)
{
	for (int iRow = 0; iRow < iNumRows; iRow++)
	{
		if (dwSpaceAvailableOnEachRow[iRow] >= dwWidth)
		{
			dwXPos = dwSize - dwSpaceAvailableOnEachRow[iRow];
			dwYPos = iFontHeight * iRow;
			AddCharToTexture(pData,dwWidth,dwXPos,dwYPos);
			dwSpaceAvailableOnEachRow[iRow] -= dwWidth;
			return true;
		}
	}
	return false;
}

void FontTexture::AddCharToTexture(BYTE *pData,DWORD dwWidth,DWORD dwX,DWORD dwY)
{
	for (int y=0; y<iFontHeight; y++)
	{
		BYTE *pSource = pData + dwWidth * y;
		BYTE *pDest = pTexture + ((dwY+y) * dwSize) + dwX;
		memcpy(pDest,pSource,dwWidth);
	}
}

BYTE *FontTexture::GetCharMap(int iX, int iY, int iW)
{
	BYTE *pResult = new BYTE[iW * iFontHeight];
	for (int y=0; y<iFontHeight; y++)
	{
		BYTE *pDest = pResult + iW * y;
		BYTE *pSource = pTexture + ((iY+y) * dwSize) + iX;
		memcpy(pDest,pSource,iW);
	}
	return pResult;
}




bool FontTexture::Save(HFILE hFile)
{
	_lwrite(hFile,(LPCSTR)&dwSize,sizeof(DWORD));
	if (b32Bit)
		_lwrite(hFile,(LPCSTR)p32BitTexture,dwSize * dwSize * 4);	
	else
		_lwrite(hFile,(LPCSTR)pTexture,dwSize * dwSize);	
	return true;
}

bool FontTexture::ExportTGA(const char *szFullPath)
{
	TGAHeader header;
	memset(&header,0,sizeof(header));
	header.TypeCode = 2;
	header.Width = (WORD)dwSize;
	header.Height = (WORD)dwSize;
	header.BitsPerPixel = 32;

	DWORD *dwExportTexture = new DWORD[dwSize * dwSize];
	DWORD dwPixelsLeft = dwSize * dwSize;
	DWORD *pDest = dwExportTexture;
	// need to flip image
	for (int iRow = dwSize-1; iRow>=0; iRow--)
	{
		for (int iColumn = 0; iColumn < (int)dwSize; iColumn++)
		{
			DWORD dwAlpha = pTexture[iRow * dwSize + iColumn];
			if (dwAlpha)
				*pDest = dwAlpha<<24 | 0xFFFFFF;
			else
				*pDest = 0;
			pDest++;
		}
	}

	bool bSuccess = false;
	DWORD dwSizeWritten = 0;
	HANDLE hFile = CreateFile(szFullPath,GENERIC_WRITE,0/*share mode*/,NULL/*security*/,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL/*template*/);
	if (hFile == INVALID_HANDLE_VALUE)
		goto errorexit;

	WriteFile(hFile,&header,sizeof(header),&dwSizeWritten,NULL);
	if (dwSizeWritten != sizeof(header))
		goto errorexit;
	dwSizeWritten = 0;
	WriteFile(hFile,dwExportTexture,dwSize * dwSize * sizeof(DWORD),&dwSizeWritten,NULL);
	if (dwSizeWritten != dwSize * dwSize * sizeof(DWORD))
		goto errorexit;
		
	bSuccess = true;

errorexit:	
	if (hFile != INVALID_HANDLE_VALUE)
		CloseHandle(hFile);
	delete dwExportTexture;
	return bSuccess;
}

bool FontTexture::ImportTGA(const char *szFullPath)
{
	b32Bit = true;
	bool bSuccess = false;
	HANDLE hFile = CreateFile(szFullPath,GENERIC_READ,0/*share mode*/,NULL/*security*/,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL/*template*/);
	if (hFile == INVALID_HANDLE_VALUE)
		return false;
	
	TGAHeader header;
	DWORD dwBytesRead = 0;
	ReadFile(hFile,&header,sizeof(header),&dwBytesRead,NULL);
	if (header.Width != header.Height)
		return false;
	if (header.Width != dwSize)
		return false;
	if (header.TypeCode != 2 || header.BitsPerPixel != 32)
		return false;
	DWORD *dwTexture = new DWORD[dwSize * dwSize];
	// flip the image as we read it in
	DWORD dwTotalBytesRead = 0;
	for (int iRow = dwSize-1; iRow >=0; iRow--)
	{
		dwBytesRead = 0;
		ReadFile(hFile,&dwTexture[iRow * dwSize],dwSize * 4,&dwBytesRead,NULL);
		dwTotalBytesRead += dwBytesRead;
	}
	CloseHandle(hFile);
	if (dwTotalBytesRead != dwSize * dwSize * 4)
	{
		delete dwTexture;
		return false;
	}
	delete p32BitTexture;
	p32BitTexture = dwTexture;
	DWORD dwPixels = dwSize * dwSize;
	delete pTexture;
	pTexture = new BYTE[dwSize * dwSize];
	DWORD *pSource = p32BitTexture;
	BYTE *pDest = pTexture;
	while (dwPixels)
	{
		*pDest = (BYTE)((*pSource)>>24);
		pDest++;
		pSource++;
		dwPixels--;
	}

	return true;
}


