//**************************************************************************
//**
//**	##   ##    ##    ##   ##   ####     ####   ###     ###
//**	##   ##  ##  ##  ##   ##  ##  ##   ##  ##  ####   ####
//**	 ## ##  ##    ##  ## ##  ##    ## ##    ## ## ## ## ##
//**	 ## ##  ########  ## ##  ##    ## ##    ## ##  ###  ##
//**	  ###   ##    ##   ###    ##  ##   ##  ##  ##       ##
//**	   #    ##    ##    #      ####     ####   ##       ##
//**
//**	$Id: r_tex_base.cpp 4297 2010-06-03 22:49:00Z firebrand_kh $
//**
//**	Copyright (C) 1999-2006 Jānis Legzdiņš
//**
//**	This program is free software; you can redistribute it and/or
//**  modify it under the terms of the GNU General Public License
//**  as published by the Free Software Foundation; either version 2
//**  of the License, or (at your option) any later version.
//**
//**	This program is distributed in the hope that it will be useful,
//**  but WITHOUT ANY WARRANTY; without even the implied warranty of
//**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//**  GNU General Public License for more details.
//**
//**************************************************************************

// HEADER FILES ------------------------------------------------------------

#include "gamedefs.h"
#include "r_tex.h"

// MACROS ------------------------------------------------------------------

// TYPES -------------------------------------------------------------------

typedef VTexture* (*VTexCreateFunc)(VStream&, int);

// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------

// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------

// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------

// EXTERNAL DATA DECLARATIONS ----------------------------------------------

// PUBLIC DATA DEFINITIONS -------------------------------------------------

// PRIVATE DATA DEFINITIONS ------------------------------------------------

// CODE --------------------------------------------------------------------

//==========================================================================
//
//	VTexture::CreateTexture
//
//==========================================================================

VTexture* VTexture::CreateTexture(int Type, int LumpNum)
{
	guard(VTexture::CreateTexture);
	static const struct
	{
		VTexCreateFunc	Create;
		int				Type;
	} TexTable[] =
	{
		{ VImgzTexture::Create,		TEXTYPE_Any },
		{ VPngTexture::Create,		TEXTYPE_Any },
		{ VJpegTexture::Create,		TEXTYPE_Any },
		{ VPcxTexture::Create,		TEXTYPE_Any },
		{ VTgaTexture::Create,		TEXTYPE_Any },
		{ VFlatTexture::Create,		TEXTYPE_Flat },
		{ VRawPicTexture::Create,	TEXTYPE_Pic },
		{ VPatchTexture::Create,	TEXTYPE_Any },
		{ VAutopageTexture::Create,	TEXTYPE_Autopage },
	};

	if (LumpNum < 0)
	{
		return NULL;
	}
	VStream* Strm = W_CreateLumpReaderNum(LumpNum);

	for (size_t i = 0; i < ARRAY_COUNT(TexTable); i++)
	{
		if (TexTable[i].Type == Type || TexTable[i].Type == TEXTYPE_Any)
		{
			VTexture* Tex = TexTable[i].Create(*Strm, LumpNum);
			if (Tex)
			{
				Tex->Type = Type;
				delete Strm;
				Strm = NULL;
				return Tex;
			}
		}
	}

	delete Strm;
	Strm = NULL;
	return NULL;
	unguard;
}

//==========================================================================
//
//	VTexture::VTexture
//
//==========================================================================

VTexture::VTexture()
: Type(TEXTYPE_Any)
, Format(TEXFMT_8)
, Name(NAME_None)
, Width(0)
, Height(0)
, SOffset(0)
, TOffset(0)
, bNoRemap0(false)
, bWorldPanning(false)
, bIsCameraTexture(false)
, WarpType(0)
, SScale(1)
, TScale(1)
, TextureTranslation(0)
, DriverData(0)
, Pixels8Bit(0)
, HiResTexture(0)
, Pixels8BitValid(false)
, SourceLump(-1)
{
}

//==========================================================================
//
//	VTexture::~VTexture
//
//==========================================================================

VTexture::~VTexture()
{
	if (Pixels8Bit)
	{
		delete[] Pixels8Bit;
		Pixels8Bit = NULL;
	}
	if (HiResTexture)
	{
		delete HiResTexture;
		HiResTexture = NULL;
	}
}

//==========================================================================
//
//	VTexture::SetFrontSkyLayer
//
//==========================================================================

void VTexture::SetFrontSkyLayer()
{
	guardSlow(VTexture::SetFrontSkyLayer);
	bNoRemap0 = true;
	unguardSlow;
}

//==========================================================================
//
//	VTexture::CheckModified
//
//==========================================================================

bool VTexture::CheckModified()
{
	return false;
}

//==========================================================================
//
//	VTexture::GetPixels8
//
//==========================================================================

vuint8* VTexture::GetPixels8()
{
	guard(VTexture::GetPixels8);
	//	If already have converted version, then just return it.
	if (Pixels8Bit && Pixels8BitValid)
	{
		return Pixels8Bit;
	}

	vuint8* Pixels = GetPixels();
	if (Format == TEXFMT_8Pal)
	{
		//	Remap to game palette
		int NumPixels = Width * Height;
		rgba_t* Pal = GetPalette();
		vuint8 Remap[256];
		Remap[0] = 0;
		int i;
		for (i = 1; i < 256; i++)
		{
			Remap[i] = r_rgbtable[((Pal[i].r << 7) & 0x7c00) +
				((Pal[i].g << 2) & 0x3e0) + ((Pal[i].b >> 3) & 0x1f)];
		}

		if (!Pixels8Bit)
		{
			Pixels8Bit = new vuint8[NumPixels];
		}
		vuint8* pSrc = Pixels;
		vuint8* pDst = Pixels8Bit;
		for (i = 0; i < NumPixels; i++, pSrc++, pDst++)
		{
			*pDst = Remap[*pSrc];
		}
		Pixels8BitValid = true;
		return Pixels8Bit;
	}
	else if (Format == TEXFMT_RGBA)
	{
		int NumPixels = Width * Height;
		if (!Pixels8Bit)
		{
			Pixels8Bit = new vuint8[NumPixels];
		}
		rgba_t* pSrc = (rgba_t*)Pixels;
		vuint8* pDst = Pixels8Bit;
		for (int i = 0; i < NumPixels; i++, pSrc++, pDst++)
		{
			if (pSrc->a < 128)
				*pDst = 0;
			else
				*pDst = r_rgbtable[((pSrc->r << 7) & 0x7c00) +
					((pSrc->g << 2) & 0x3e0) + ((pSrc->b >> 3) & 0x1f)];
		}
		Pixels8BitValid = true;
		return Pixels8Bit;
	}
	return Pixels;
	unguard;
}

//==========================================================================
//
//	VTexture::GetPalette
//
//==========================================================================

rgba_t* VTexture::GetPalette()
{
	guardSlow(VTexture::GetPalette);
	return r_palette;
	unguardSlow;
}

//==========================================================================
//
//	VTexture::GetHighResolutionTexture
//
//	Return high-resolution version of this texture, or self if it doesn't
// exist.
//
//==========================================================================

VTexture* VTexture::GetHighResolutionTexture()
{
	guard(VTexture::GetHighResolutionTexture);
#ifdef CLIENT
	if (!r_hirestex)
	{
		return NULL;
	}
	//	If high resolution texture is already created, then just return it.
	if (HiResTexture)
	{
		return HiResTexture;
	}

	//	Determine directory name depending on type.
	const char* DirName;
	switch (Type)
	{
	case TEXTYPE_Wall:
		DirName = "walls";
		break;
	case TEXTYPE_Flat:
		DirName = "flats";
		break;
	case TEXTYPE_Overload:
		DirName = "textures";
		break;
	case TEXTYPE_Sprite:
		DirName = "sprites";
		break;
	case TEXTYPE_Pic:
	case TEXTYPE_Autopage:
		DirName = "graphics";
		break;
	default:
		return NULL;
	}

	//	Try to find it.
	static const char* Exts[] = { "png", "jpg", "tga", NULL };
	int LumpNum = W_FindLumpByFileNameWithExts(VStr("hirestex/") + DirName +
		"/" + *Name, Exts);
	if (LumpNum >= 0)
	{
		//	Create new high-resolution texture.
		HiResTexture = CreateTexture(Type, LumpNum);
		HiResTexture->Name = Name;
		return HiResTexture;
	}
#endif
	//	No hi-res texture found.
	return NULL;
	unguard;
}

//==========================================================================
//
//	VTexture::FixupPalette
//
//==========================================================================

void VTexture::FixupPalette(vuint8* Pixels, rgba_t* Palette)
{
	guard(VTexture::FixupPalette);
	//	Find black colour for remaping.
	int i;
	int black = 0;
	int best_dist = 0x10000;
	for (i = 1; i < 256; i++)
	{
		int dist = Palette[i].r * Palette[i].r + Palette[i].g *
				Palette[i].g + Palette[i].b * Palette[i].b;
		if (dist < best_dist && Palette[i].a == 255)
		{
			black = i;
			best_dist = dist;
		}
	}
	for (i = 0; i < Width * Height; i++)
	{
		if (Palette[Pixels[i]].a == 0)
			Pixels[i] = 0;
		else if (!Pixels[i])
			Pixels[i] = black;
	}
	Palette[0].r = 0;
	Palette[0].g = 0;
	Palette[0].b = 0;
	Palette[0].a = 0;
	unguard;
}

//==========================================================================
//
//	VTexture::FindDriverTrans
//
//==========================================================================

VTexture::VTransData* VTexture::FindDriverTrans(
	VTextureTranslation* TransTab, int CMap)
{
	guard(VTexture::FindDriverTrans);
	for (int i = 0; i < DriverTranslated.Num(); i++)
	{
		if (DriverTranslated[i].Trans == TransTab &&
			DriverTranslated[i].ColourMap == CMap)
		{
			return &DriverTranslated[i];
		}
	}
	return NULL;
	unguard;
}

//==========================================================================
//
//	VDummyTexture::VDummyTexture
//
//==========================================================================

VDummyTexture::VDummyTexture()
{
	Type = TEXTYPE_Null;
	Format = TEXFMT_8;
}

//==========================================================================
//
//	VDummyTexture::GetPixels
//
//==========================================================================

vuint8* VDummyTexture::GetPixels()
{
	return NULL;
}

//==========================================================================
//
//	VDummyTexture::Unload
//
//==========================================================================

void VDummyTexture::Unload()
{
}
