#include "MLRHeaders.hpp"
#include <GameOS\ToolOS.hpp>

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
GOSImagePool::GOSImagePool() :
	imageHash(
		4099,
		NULL,
		true
	)
{
	Verify(gos_GetCurrentHeap() == TexturePoolHeap);
	texturePath = *MString::s_Empty;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
GOSImagePool::~GOSImagePool()
{
	imageHash.DeletePlugs();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
GOSImage*
	GOSImagePool::GetImage(const char* image_name)
{
	Check_Object(this);

//	MString imageName = image_name;
	Verify(strlen(image_name) > 0);

	//
	//---------------------------
	// Get the image for the name
	//---------------------------
	//
	GOSImage *image;

	gos_PushCurrentHeap(TexturePoolHeap);
	if ((image = imageHash.Find(image_name)) == NULL)
	{
		image = new GOSImage(image_name);
		Register_Object(image);
		imageHash.AddValue(image, image->imageName);
	}
	Check_Object(image);
	gos_PopCurrentHeap();

	return image;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
GOSImage*
	GOSImagePool::GetImage(const char *image_name, gos_TextureFormat format, int size, gos_TextureHints hints)
{
	Check_Object(this);

//	MString imageName = image_name;
//	Verify(imageName.GetLength() > 0);
	Verify(strlen(image_name) > 0);

	//
	//---------------------------
	// Get the image for the name
	//---------------------------
	//
	GOSImage *image;

	gos_PushCurrentHeap(TexturePoolHeap);
	if ((image = imageHash.Find(image_name)) == NULL)
	{
		image = new GOSImage(format, image_name, size, hints);
		Register_Object(image);
		imageHash.AddValue(image, image->imageName);
	}
#ifdef _ARMOR
	else
	{
	}
#endif

	Check_Object(image);
	gos_PopCurrentHeap();

	return image;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	GOSImagePool::RemoveImage(GOSImage *image)
{
	Check_Object(this);
	Unregister_Object(image);
	delete image;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	GOSImagePool::ReadHint(Stuff::Page *page)
{
	int hints = 0;
	bool flag = false;
	const char *string;
	if (page->GetEntry("Mipmap", &string))
	{
		if (!_stricmp(string, "Explicit"))
			hints |= gosHint_UserMipMaps;
		else if (!_stricmp(string, "None"))
			hints |= gosHint_DisableMipmap|gosHint_DontShrink;
	}
	if (page->GetEntry("Memory", &string))
	{
		if (!_stricmp(string, "AGP"))
			hints |= gosHint_AGPMemory;
		else if (!_stricmp(string, "Video"))
			hints |= gosHint_VideoMemory;
	}
	if (page->GetEntry("DontShrink", &flag) && flag)
		hints |= gosHint_DontShrink;
	if (page->GetEntry("PageOut", &string))
	{
		if (!_stricmp(string, "Last"))
			hints |= gosHint_PageLast;
		else if (!_stricmp(string, "First"))
			hints |= gosHint_PageFirst;
	}
	if (page->GetEntry("MipFilter", &string))
	{
		if (!_stricmp(string, "Box"))
			hints |= gosHint_MipmapFilter0;
		else if (!_stricmp(string, "Point"))
			hints |= gosHint_MipmapFilter1;
	}
	if (page->GetEntry("PinkIsTransparent", &flag) && flag)
		hints |= gosHint_PinkColorKey;
	if (page->GetEntry("BlueIsAlpha", &flag) && flag)
		hints |= gosHint_ForceAlpha;
	if (page->GetEntry("Compression", &string))
	{
		if (!_stricmp(string, "Some"))
			hints |= gosHint_Compress0;
		else if (!_stricmp(string, "Very"))
			hints |= gosHint_Compress1;
	}
	return hints;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DWORD
	GOSImagePool::SkinThis(
		const char* name,
		gos_TextureFormat format,
		DWORD skin,
		DWORD detail
	)
{
	TEXTUREPTR skin_ptr, detail_ptr, dest_ptr;	

	gos_LockTexture(skin, 0, true, &skin_ptr);
	gos_LockTexture(detail, 0, true, &detail_ptr);
	DWORD dest = gos_NewEmptyTexture(format, name, detail_ptr.Height, gosHint_AGPMemory);
	gos_LockTexture(dest, 0, false, &dest_ptr);

	SkinThis(dest_ptr, skin_ptr, detail_ptr);

	gos_UnLockTexture(skin);
	gos_UnLockTexture(detail);
	gos_UnLockTexture(dest);
	
	return dest;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	GOSImagePool::SkinThis(
		TEXTUREPTR dest_ptr,
		TEXTUREPTR skin_ptr,
		TEXTUREPTR detail_ptr
	)
{
	Verify(skin_ptr.Height==detail_ptr.Height && skin_ptr.Height==dest_ptr.Height);
	Verify(skin_ptr.Width==detail_ptr.Width && skin_ptr.Width==dest_ptr.Width);

	int count = detail_ptr.Height*detail_ptr.Width;
	BYTE *s = (BYTE*)skin_ptr.pTexture;
	BYTE *d = (BYTE*)detail_ptr.pTexture;
	BYTE *n = (BYTE*)dest_ptr.pTexture;
	for(int i=0;i<count;i++)
	{
		int alpha = d[3];
		if(alpha>0)
		{
			int col = (*s++)*(0xff-alpha) + (*d++)*alpha;
			*n++ = static_cast<unsigned char>(col>>8);

			col = (*s++)*(0xff-alpha) + (*d++)*alpha;
			*n++ = static_cast<unsigned char>(col>>8);

			col = (*s++)*(0xff-alpha) + (*d++)*alpha;
			*n++ = static_cast<unsigned char>(col>>8);

			d++;
		}
		else
		{
			*n++ = *s++;
			*n++ = *s++;
			*n++ = *s++;
			d += 4;
		}
		n++;
		s++;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TGAFilePool::TGAFilePool(
	const char* path,
	const char* hint_file
)
{
	Verify(gos_GetCurrentHeap() == TexturePoolHeap);
	texturePath = path;
	if (hint_file)
	{
		MString temp(texturePath);
		temp += hint_file;
		hintFile = new NotationFile(temp);
	}
	else
		hintFile = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TGAFilePool::~TGAFilePool()
{
	if (hintFile)
	{
		Check_Object(hintFile);
		delete hintFile;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	TGAFilePool::LoadImageGOS(GOSImage *image, int hint)
{
	if( (image->flags & GOSImage::Loaded) != 0)
		return true;

	Verify(gos_GetCurrentHeap() == TexturePoolHeap);
	MString full_name,file_name = texturePath;
	file_name += image->imageName;
	full_name =file_name;
	full_name +=".png";
	if(!gos_DoesFileExist(full_name)) 
	{
		full_name=file_name;
		full_name += ".tga";
	}

	if (hintFile)
	{
		Page *page = hintFile->FindPage(image->imageName);
		if (page)
		{
			Check_Object(page);
			hint = ReadHint(page);
		}
	}

	image->imageHandle = gos_NewTextureFromFile(gos_Texture_Detect, full_name, hint);
	image->flags |= (image->imageHandle ? GOSImage::Loaded : 0);
	return ((image->flags & GOSImage::Loaded) != 0);
}

