/****************************************************************************************/
/*  SWTHandle.C                                                                         */
/*                                                                                      */
/*  Author: Mike Sandige, John Pollard                                                  */
/*  Description:  Manager for texture construction and available texture formats for    */
/*                the software driver                                                   */
/*                                                                                      */
/*  The contents of this file are subject to the Jet3D Public License                   */
/*  Version 1.02 (the "License"); you may not use this file except in                   */
/*  compliance with the License. You may obtain a copy of the License at                */
/*  http://www.jet3d.com                                                                */
/*                                                                                      */
/*  Software distributed under the License is distributed on an "AS IS"                 */
/*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */
/*  the License for the specific language governing rights and limitations              */
/*  under the License.                                                                  */
/*                                                                                      */
/*  The Original Code is Jet3D, released December 12, 1999.                             */
/*  Copyright (C) 1996-1999 Eclipse Entertainment, L.L.C. All Rights Reserved           */
/*                                                                                      */
/****************************************************************************************/

#include <stdlib.h>					// malloc, free
#include <memory.h>					// memset
#include <Assert.h>

#include "SoftDrv.h"				// SD_Display, ClientWindow.  Could be cleaned up.
#include "SWTHandle.h"
#include "errorlog.h"

#define MAX_NUM_MIP_LEVELS  8 //or 16

typedef struct jeRDriver_THandle
{
	int32					Active, Width, Height, MipLevels;
	jeRDriver_PixelFormat	PixelFormat;
	uint16					*BitPtr[MAX_NUM_MIP_LEVELS];
	jeRDriver_THandle		*PalHandle;
	jeRDriver_THandle		*AlphaHandle;

	uint32					Flags;
} jeRDriver_THandle;

#define THANDLE_EXPORT(XX)  (XX) //jeRDriver_THandle *)( (((uint32)(XX))<<16) | (((uint32)(XX))>>16) )
#define THANDLE_IMPORT(YY)  THANDLE_EXPORT(YY)

#define	MAX_TEXTURE_HANDLES		15000

jeRDriver_THandle	SWTHandle_TextureHandles[MAX_TEXTURE_HANDLES];
int	SWTHandle_NumberOfAllocatedTextureHandles=0;

static int32 SWTHandle_SnapToPower2(int32 Width)
{
	// CB touched swthandle to make it support big textures
		 if (Width <= 1) return 1;
	else if (Width <= 2) return 2;
	else if (Width <= 4) return 4;
	else if (Width <= 8) return 8;
	else if (Width <= 16) return 16;
	else if (Width <= 32) return 32;
	else if (Width <= 64) return 64;
	else if (Width <= 128) return 128;
	else if (Width <= 256) return 256;
	else if (Width <= 512) return 512;
	else if (Width <= 1024) return 1024;
	else if (Width <= 2048) return 2048;
	else if (Width <= 4096) return 4096;
	else 
		return -1;
}


//========================================================================================
//	SWTHandle_FindTextureHandle
//========================================================================================
static jeRDriver_THandle *SWTHandle_FindTextureHandle()
{
	int32				i;
	jeRDriver_THandle	*THandle;

	THandle = SWTHandle_TextureHandles;

	for (i=0; i< MAX_TEXTURE_HANDLES; i++, THandle++)
	{
		if (!THandle->Active)
		{
			memset(THandle, 0, sizeof(jeRDriver_THandle));

			THandle->Active = JE_TRUE;

			return THandle;
		}
	}

	return NULL;
}

//========================================================================================
//	SWTHandle_FreeTextureHandle
//========================================================================================
static jeBoolean SWTHandle_FreeTextureHandle(jeRDriver_THandle *THandle)
{
	int	k;

	assert(THandle);
	//<>	assert(THandle->Active == JE_TRUE);

	if( ! THandle->Active )
	{
		return	JE_FALSE;
	}

	if(THandle->PalHandle)
	{
		SWTHandle_FreeTextureHandle(THANDLE_IMPORT(THandle->PalHandle));
	}

	if(THandle->AlphaHandle)
	{
		SWTHandle_FreeTextureHandle(THANDLE_IMPORT(THandle->AlphaHandle));
	}

	for(k=0;k < THandle->MipLevels;k++)
	{
		if(THandle->BitPtr[k])
			{
				free(THandle->BitPtr[k]);
			}
		THandle->BitPtr[k]	=NULL;
	}

	memset(THandle, 0, sizeof(jeRDriver_THandle));	

	assert(	SWTHandle_NumberOfAllocatedTextureHandles > 0);
	SWTHandle_NumberOfAllocatedTextureHandles--;
	return	JE_TRUE;
}

//==================================================================================
//	SWTHandle_FreeAllTextureHandles
//==================================================================================
jeBoolean SWTHandle_FreeAllTextureHandles(void)
{
	int32				i;
	jeRDriver_THandle	*pTHandle;

	pTHandle = SWTHandle_TextureHandles;

	for (i=0; i< MAX_TEXTURE_HANDLES; i++, pTHandle++)
	{
		if (!pTHandle->Active)
		{
			continue;
		}
		
		SWTHandle_FreeTextureHandle(pTHandle);
	}

	return JE_TRUE;
}

jeRDriver_THandle *DRIVERCC SWTHandle_CreateTexture(int32							Width, 
													int32							Height, 
													int32							NumMipLevels, 
													const jeRDriver_PixelFormat		*PixelFormat)
{
	int32				i, SWidth, SHeight;			// Snapped to power of 2 width/height
	jeRDriver_THandle	*THandle;

	assert(PixelFormat);
	if ((NumMipLevels > MAX_NUM_MIP_LEVELS) || (NumMipLevels<0))
		{
			jeErrorLog_AddString(JE_ERR_BAD_PARAMETER, "SWTHandle_CreateTexture: bad number of mip levels.",NULL);
			goto ExitWithError;
		}
	
	THandle = SWTHandle_FindTextureHandle();

	if (!THandle)
	{
		jeErrorLog_AddString(JE_ERR_INTERNAL_RESOURCE, "SWTHandle_CreateTexture:  No more handles left.",NULL);
		goto ExitWithError;
	}

	if(PixelFormat->Flags & RDRIVER_PF_3D)
	{
	/**
		CB : pointless ?
		if (Width > 256)
		{
			jeErrorLog_AddString(JE_ERR_BAD_PARAMETER, "SWTHandle_CreateTexture: Width > 256.",NULL);
			goto ExitWithError;
		}

		if (Height > 256)
		{
			jeErrorLog_AddString(JE_ERR_BAD_PARAMETER, "SWTHandle_CreateTexture: Height > 256.",NULL);
			goto ExitWithError;
		}
	***/

		SWidth = SWTHandle_SnapToPower2(Width);
		SHeight = SWTHandle_SnapToPower2(Height);

		if (Width != SWidth)
		{
			jeErrorLog_AddString(JE_ERR_BAD_PARAMETER, "SWTHandle_CreateTexture: Not a power of 2.",NULL);
			goto ExitWithError;
		}

		if (Height != SHeight)
		{
			jeErrorLog_AddString(JE_ERR_BAD_PARAMETER, "SWTHandle_CreateTexture: Not a power of 2.",NULL);
			goto ExitWithError;
		}
	}
	
	THandle->MipLevels		=NumMipLevels;
	THandle->Width			=Width;
	THandle->Height			=Height;
	THandle->PixelFormat	=*PixelFormat;

	for(i=0;i < NumMipLevels;i++)
	{
		if(PixelFormat->Flags & RDRIVER_PF_PALETTE)
		{
		
			if( PixelFormat->PixelFormat == JE_PIXELFORMAT_32BIT_XRGB ||
				PixelFormat->PixelFormat == JE_PIXELFORMAT_32BIT_XBGR)	
			{
				THandle->BitPtr[i]	=(uint16 *)malloc(sizeof(U32) * Width * Height);
			}
			else					
			{
				jeErrorLog_AddString(JE_ERR_BAD_PARAMETER, "SWTHandle_CreateTexture: Bad Pal format.",NULL);
				goto ExitWithError;
			}
		}
		else
		{
			switch (PixelFormat->PixelFormat)
			{
				case JE_PIXELFORMAT_16BIT_4444_ARGB:
				{
					THandle->BitPtr[i]	=(uint16 *)malloc(sizeof(uint16) * Width * Height);
					break;
				}
					
				case JE_PIXELFORMAT_16BIT_565_RGB:
				{
					THandle->BitPtr[i]	=(uint16 *)malloc(sizeof(uint16) * Width * Height);
					break;
				}
				
				case JE_PIXELFORMAT_16BIT_555_RGB:
				{
					THandle->BitPtr[i]	=(uint16 *)malloc(sizeof(uint16) * Width * Height);
					break;
				}

				case JE_PIXELFORMAT_8BIT:
				{
					THandle->BitPtr[i]	=(uint16 *)malloc(sizeof(uint8) * Width * Height);
					break;
				}

				case JE_PIXELFORMAT_24BIT_RGB:
				{
					THandle->BitPtr[i]	=(uint16 *)malloc((sizeof(uint8)*3) * Width * Height);
					break;
				}

				default:
				{
					jeErrorLog_AddString(JE_ERR_BAD_PARAMETER, "SOFT_Create3DTexture: Invalid pixel format.",NULL);
					goto ExitWithError;
				}
			}
			
			if ( PixelFormat->Flags & RDRIVER_PF_CAN_DO_COLORKEY )
				{
					THandle->Flags |= THANDLE_TRANS;
				}

		}
	}

	SWTHandle_NumberOfAllocatedTextureHandles++;
	assert(	SWTHandle_NumberOfAllocatedTextureHandles <= MAX_TEXTURE_HANDLES);

	return THANDLE_EXPORT(THandle);
		
	ExitWithError:
	{
		return NULL;
	}
}

jeBoolean	DRIVERCC	SWTHandle_GetInfo(jeRDriver_THandle *THandle, int32 MipLevel, jeRDriver_THandleInfo *Info)
{
	assert(THandle);
	assert(Info);
	THandle = THANDLE_IMPORT(THandle);
	if ( ! THandle->Active )
		{
			jeErrorLog_AddString(JE_ERR_BAD_PARAMETER, "SWTHandle_GetInfo:  Bad Texture Handle.",NULL);
			return JE_FALSE;
		}


	Info->Width			= THandle->Width  >> MipLevel;
	Info->Height		= THandle->Height >> MipLevel;
	Info->Stride		= THandle->Width  >> MipLevel;
	Info->ColorKey		= 1;
	Info->Flags			= 0;
	#pragma message ("is this right?")
	Info->PixelFormat	= THandle->PixelFormat;
	if ( THandle->Flags & THANDLE_TRANS )
		{
	#pragma message ("remember this")
			Info->Flags	= RDRIVER_THANDLE_HAS_COLORKEY;
		}
	return	JE_TRUE;
}

int SWTHandle_GetMipCount(jeRDriver_THandle *THandle)
{
	assert(THandle);
	THandle = THANDLE_IMPORT(THandle);
	return THandle->MipLevels;
}

//can be used to null out the pal (cant assert on palhandle)
jeBoolean DRIVERCC SWTHandle_SetPalette(jeRDriver_THandle *THandle, jeRDriver_THandle *PalHandle)
{
	assert(THandle);
	THandle = THANDLE_IMPORT(THandle);

	THandle->PalHandle	=PalHandle;

	return	JE_TRUE;
}

//can be used to null out the pal (cant assert on palhandle)
jeRDriver_THandle *DRIVERCC SWTHandle_GetPalette(jeRDriver_THandle *THandle)
{
	assert(THandle);
	THandle = THANDLE_IMPORT(THandle);
	if ( ! THandle->Active )
		{
			jeErrorLog_AddString(JE_ERR_BAD_PARAMETER, "SWTHandle_GetPalette: Bad Texture Handle.",NULL);
			return JE_FALSE;
		}

	return	THandle->PalHandle;
}

jeBoolean DRIVERCC	SWTHandle_SetAlpha(jeRDriver_THandle *THandle, jeRDriver_THandle *AHandle)
{
	assert(THandle);
	THandle = THANDLE_IMPORT(THandle);
	if ( ! THandle->Active )
		{
			jeErrorLog_AddString(JE_ERR_BAD_PARAMETER, "SWTHandle_SetAlpha: Bad Texture Handle.",NULL);
			return JE_FALSE;
		}

	if(THandle->PixelFormat.Flags & RDRIVER_PF_HAS_ALPHA_SURFACE)
	{
		if(AHandle->PixelFormat.Flags & RDRIVER_PF_ALPHA_SURFACE)
		{
			THandle->AlphaHandle	=AHandle;
			return	JE_TRUE;
		}
	}
	return	JE_FALSE;
}

jeRDriver_THandle *DRIVERCC	SWTHandle_GetAlpha(jeRDriver_THandle *THandle)
{
	assert(THandle);
	THandle = THANDLE_IMPORT(THandle);
	if ( ! THandle->Active )
		{
			jeErrorLog_AddString(JE_ERR_BAD_PARAMETER, "SWTHandle_GetAlpha: Bad Texture Handle.",NULL);
			return JE_FALSE;
		}

	return	THANDLE_EXPORT(THandle->AlphaHandle);
}

jeBoolean DRIVERCC SWTHandle_DestroyTexture(jeRDriver_THandle *THandle)
{
	return SWTHandle_FreeTextureHandle(THANDLE_IMPORT(THandle));
}

jeBoolean DRIVERCC SWTHandle_LockTextureHandle(jeRDriver_THandle *THandle, int32 MipLevel, void **Data)
{
	assert(THandle);
	THandle = THANDLE_IMPORT(THandle);

	assert(MipLevel <= THandle->MipLevels && MipLevel >= 0);
	if ( ! THandle->Active )
		{
			jeErrorLog_AddString(JE_ERR_BAD_PARAMETER, "SWTHandle_LockTextureHandle: Bad Texture Handle.",NULL);
			return JE_FALSE;
		}
	if ( ! THandle->BitPtr[MipLevel] )
		{
			jeErrorLog_AddString(JE_ERR_BAD_PARAMETER, "SWTHandle_LockTextureHandle: Bad Texture Handle in Mip.",NULL);
			return JE_FALSE;
		}

	THandle->Flags	|=(THANDLE_LOCKED << MipLevel);
	*Data			=(uint16*)THandle->BitPtr[MipLevel];

	return	JE_TRUE;
}

jeBoolean DRIVERCC SWTHandle_UnLockTextureHandle(jeRDriver_THandle *THandle, int32 MipLevel)
{
	assert(THandle);
	THandle = THANDLE_IMPORT(THandle);
	if (!(THandle->Flags & (THANDLE_LOCKED << MipLevel)))
		{
			jeErrorLog_AddString(JE_ERR_BAD_PARAMETER, "SWTHandle_UnLockTextureHandle: Texture Handle is not Locked.",NULL);
			return JE_FALSE;
		}


	THandle->Flags	&=~(THANDLE_LOCKED << MipLevel);	// This mip is now unlocked
	THandle->Flags	|=THANDLE_UPDATE;					// Mark it for updating...

	return JE_TRUE;
}




jeBoolean DRIVERCC SWTHandle_EnumPixelFormats(DRV_ENUM_PFORMAT_CB *Cb, void *Context)
{
	jeRDriver_PixelFormat	PixelFormat;

	if(!SD_Display)
	{
		jeErrorLog_AddString(JE_ERR_INTERNAL_RESOURCE, "SWTHandle_EnumPixelFormats:  No Mode Set.",NULL);
		return JE_FALSE;
	}


	PixelFormat.PixelFormat	= JE_PIXELFORMAT_8BIT;
	PixelFormat.Flags		= RDRIVER_PF_3D;
	if(!Cb(&PixelFormat, Context))
		{
			return	JE_TRUE;
		}
	PixelFormat.PixelFormat	= JE_PIXELFORMAT_8BIT;
	PixelFormat.Flags		= RDRIVER_PF_3D| RDRIVER_PF_COMBINE_LIGHTMAP;
	if(!Cb(&PixelFormat, Context))
		{
			return	JE_TRUE;
		}

	PixelFormat.PixelFormat	= JE_PIXELFORMAT_16BIT_4444_ARGB;
	PixelFormat.Flags		= RDRIVER_PF_3D | RDRIVER_PF_ALPHA;
	if(!Cb(&PixelFormat, Context))
		{
			return	JE_TRUE;
		}
	PixelFormat.PixelFormat	= JE_PIXELFORMAT_16BIT_4444_ARGB;
	PixelFormat.Flags		= RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP | RDRIVER_PF_ALPHA;
	if(!Cb(&PixelFormat, Context))
		{
			return	JE_TRUE;
		}

	PixelFormat.PixelFormat	= JE_PIXELFORMAT_32BIT_XBGR;
	PixelFormat.Flags		= RDRIVER_PF_PALETTE;
	if(!Cb(&PixelFormat, Context))
		{
			return	JE_TRUE;
		}

	if(ClientWindow.G_mask == 0x3e0)	//555
		{
			PixelFormat.PixelFormat	= JE_PIXELFORMAT_16BIT_555_RGB;
			PixelFormat.Flags		= RDRIVER_PF_2D;
			if(!Cb(&PixelFormat, Context))
				{
					return	JE_TRUE;
				}
			PixelFormat.PixelFormat	= JE_PIXELFORMAT_16BIT_555_RGB;
			PixelFormat.Flags		= RDRIVER_PF_2D| RDRIVER_PF_CAN_DO_COLORKEY;
			if(!Cb(&PixelFormat, Context))
				{
					return	JE_TRUE;
				}
		}
	else
		{
			PixelFormat.PixelFormat	= JE_PIXELFORMAT_16BIT_565_RGB;
			PixelFormat.Flags		= RDRIVER_PF_2D;
			if(!Cb(&PixelFormat, Context))
				{
					return	JE_TRUE;
				}
			PixelFormat.PixelFormat	= JE_PIXELFORMAT_16BIT_565_RGB;
			PixelFormat.Flags		= RDRIVER_PF_2D| RDRIVER_PF_CAN_DO_COLORKEY;
			if(!Cb(&PixelFormat, Context))
				{
					return	JE_TRUE;
				}
		}

	PixelFormat.PixelFormat	= JE_PIXELFORMAT_24BIT_RGB;
	PixelFormat.Flags		= RDRIVER_PF_LIGHTMAP;

	if(!Cb(&PixelFormat, Context))
	{
		return	JE_TRUE;
	}

	return	JE_TRUE;
}


