#ifdef JA2_PRECOMPILED_HEADERS
	#include "JA2 SGP ALL.H"
#elif defined( WIZ8_PRECOMPILED_HEADERS )
	#include "WIZ8 SGP ALL.H"
#else
	#include "DirectDraw Calls.h"
	#include <stdio.h>
	#include "debug.h"
	#if defined( JA2 ) || defined( UTIL )
		#include "video.h"
	#else
		#include "video2.h"
	#endif
	#include "himage.h"
	#include "vobject.h"
	#include "vobject_blitters.h"
	#include "shading.h"
#endif

BOOLEAN ShadesCalculateTables(SGPPaletteEntry *p8BPPPalette);
BOOLEAN ShadesCalculatePalette(SGPPaletteEntry *pSrcPalette, SGPPaletteEntry *pDestPalette, UINT16 usRed, UINT16 usGreen, UINT16 usBlue, BOOLEAN fMono);
void FindIndecies(SGPPaletteEntry *pSrcPalette, SGPPaletteEntry *pMapPalette, UINT8 *pTable);
void FindMaskIndecies(UINT8 *, UINT8 *, UINT8 *);

SGPPaletteEntry Shaded8BPPPalettes[HVOBJECT_SHADE_TABLES+3][256];
UINT8 ubColorTables[HVOBJECT_SHADE_TABLES+3][256];

UINT16	IntensityTable[65536];
UINT16	ShadeTable[65536];
UINT16	White16BPPPalette[ 256 ];
FLOAT	guiShadePercent = (FLOAT)0.48;
FLOAT	guiBrightPercent = (FLOAT)1.1;

BOOLEAN ShadesCalculateTables(SGPPaletteEntry *p8BPPPalette)
{
UINT32	uiCount;

		// Green palette
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[0], 0, 255, 0, TRUE);
		// Blue palette
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[HVOBJECT_SHADE_TABLES],	0, 0, 255, TRUE);
		// Yellow palette
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[HVOBJECT_SHADE_TABLES+1], 255, 255, 0, TRUE);
		// Red palette
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[HVOBJECT_SHADE_TABLES+2], 255, 0, 0, TRUE);

		// these are the brightening tables, 115%-150% brighter than original
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[1], 293, 293, 293, FALSE);
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[2], 281, 281, 281, FALSE);
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[3], 268, 268, 268, FALSE);

		// palette 4 is the non-modified palette.
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[4], 255, 255, 255, FALSE);

		// the rest are darkening tables, right down to all-black.
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[5], 195, 195, 195, FALSE);
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[6], 165, 165, 165, FALSE);
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[7], 135, 135, 135, FALSE);
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[8], 105, 105, 105, FALSE);
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[9], 75, 75, 75, FALSE);
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[10], 45, 45, 45, FALSE);
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[11], 36, 36, 36, FALSE);
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[12], 27, 27, 27, FALSE);
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[13], 18, 18, 18, FALSE);
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[14], 9, 9, 9, FALSE);
		ShadesCalculatePalette(p8BPPPalette, Shaded8BPPPalettes[15], 0, 0, 0, FALSE);


	// Remap the shade colors to the original palette
	for(uiCount=0; uiCount < (HVOBJECT_SHADE_TABLES+3); uiCount++)
	{
		FindIndecies(Shaded8BPPPalettes[uiCount], p8BPPPalette, ubColorTables[uiCount]);
		ubColorTables[uiCount][0]=0;
	}

	return(TRUE);
}

BOOLEAN ShadesCalculatePalette(SGPPaletteEntry *pSrcPalette, SGPPaletteEntry *pDestPalette, UINT16 usRed, UINT16 usGreen, UINT16 usBlue, BOOLEAN fMono)
{
UINT32 cnt, lumin;
UINT32 rmod, gmod, bmod;

	Assert( pSrcPalette != NULL );
	Assert( pDestPalette != NULL );

	for ( cnt = 0; cnt < 256; cnt++ )
	{
		if(fMono)
		{
			lumin=(pSrcPalette[ cnt ].peRed*299/1000)+ (pSrcPalette[ cnt ].peGreen*587/1000)+(pSrcPalette[ cnt ].peBlue*114/1000);
			rmod=usRed*lumin/255;
			gmod=usGreen*lumin/255;
			bmod=usBlue*lumin/255;
		}
		else
		{
			rmod = (usRed*pSrcPalette[ cnt ].peRed/255);
			gmod = (usGreen*pSrcPalette[ cnt ].peGreen/255);
			bmod = (usBlue*pSrcPalette[ cnt ].peBlue/255);
		}

		pDestPalette[ cnt ].peRed = (UINT8)__min(rmod, 255);
		pDestPalette[ cnt ].peGreen = (UINT8)__min(gmod, 255);
		pDestPalette[ cnt ].peBlue = (UINT8)__min(bmod, 255);
	}

	return(TRUE);
}




void FindIndecies(SGPPaletteEntry *pSrcPalette, SGPPaletteEntry *pMapPalette, UINT8 *pTable)
{
UINT16 usCurIndex, usCurDelta, usCurCount;
UINT32 *pSavedPtr;

__asm {

// Assumes:
//	ESI = Pointer to source palette (shaded values)
//	EDI = Pointer to original palette (palette we'll end up using!)
//	EBX = Pointer to array of indecies

		mov		esi, pSrcPalette
		mov		edi, pMapPalette
		mov		ebx, pTable

		mov		BYTE PTR [ebx],0						; Index 0 is always 0, for trans col
		inc		ebx

		add		esi,4												; Goto next color entry
		add		edi,4
		mov		pSavedPtr, edi							; Save pointer to original pal

		mov		usCurCount, 255							; We'll check cols 1-255

DoNextIndex:

		mov		edi, pSavedPtr							; Restore saved ptr
		mov		usCurIndex, 256							; Set found index & delta to some
		mov		usCurDelta, 0ffffh					; val so we get at least 1 col.

		mov		ecx,255											; Check cols 1-255 of orig pal
		push	ebx
		xor		bx,bx

NextColor:
		xor		ah,ah						; Calc delta between shaded color
		mov		al,[edi]										; and a color in the orig palette.
		mov		bl,[esi]										; Formula:
		sub		ax,bx						;	Delta = abs(red-origred) +
		or		ax,ax												;			abs(green-origgreen) +
		jns		NC1
		neg		ax
NC1:mov		dx,ax						;			abs(blue-origblue)
		xor		ah,ah
		mov		al,[edi+1]
		mov		bl,[esi+1]
		sub		ax,bx
		or		ax,ax												;			abs(green-origgreen) +
		jns		NC2
		neg		ax
NC2:add		dx,ax
		xor		ah,ah
		mov		al,[edi+2]
		mov		bl,[esi+2]
		sub		ax,bx
		or		ax,ax												;			abs(green-origgreen) +
		jns		NC3
		neg		ax
NC3:add		dx,ax

		cmp		dx,usCurDelta								; If delta < old delta
		jae		NotThisCol									;	Save this delta and it's
		mov		ax,256						;	palette index
		mov		[usCurDelta],dx
		sub	ax,cx
		mov		[usCurIndex],ax
NotThisCol:
		add		edi,4												; Try next color in orginal pal
		dec		cx
		jnz	NextColor

		pop		ebx
		mov		ax,usCurIndex								; By now, usCurIndex holds pal index
		mov		[ebx],al										; of closest color in orig pal
		inc		ebx													; so save it, then repeat above
		add		esi,4												; for the other cols in shade pal
		dec		usCurCount
		jnz		DoNextIndex
	}
}

/**********************************************************************************************
 BuildShadeTable

	Builds a 16-bit color shading table. This function should be called only after the current
	video adapter's pixel format is known (IE: GetRgbDistribution() has been called, and the
	globals for masks and shifts have been initialized by that function), and before any
	blitting is done.

	Using the table is a straight lookup. The pixel to be shaded down is used as the index into
	the table and the entry at that point will be a pixel that is 25% darker.

**********************************************************************************************/
void BuildShadeTable(void)
{
	UINT16 red, green, blue;
	UINT16 index = 0;


	for(red=0; red < 256; red+=4)
		for(green=0; green < 256; green+=4)
			for(blue=0; blue < 256; blue+=4)
			{
				index=Get16BPPColor(FROMRGB(red, green, blue));
				ShadeTable[index]=Get16BPPColor(FROMRGB(red*guiShadePercent, green*guiShadePercent, blue*guiShadePercent));
			}

	memset( White16BPPPalette, 65535, sizeof( White16BPPPalette ) );
}


/**********************************************************************************************
 BuildIntensityTable

	Builds a 16-bit color shading table. This function should be called only after the current
	video adapter's pixel format is known (IE: GetRgbDistribution() has been called, and the
	globals for masks and shifts have been initialized by that function), and before any
	blitting is done.



**********************************************************************************************/
void BuildIntensityTable(void)
{
	UINT16 red, green, blue = 0;
	UINT16 index = 0;
	FLOAT	dShadedPercent = (FLOAT)0.80;



#if 0

	UINT32 lumin;
	UINT32 rmod, gmod, bmod;

	for(red=0; red < 256; red+=4)
		for(green=0; green < 256; green+=4)
			for(blue=0; blue < 256; blue+=4)
			{
				index=Get16BPPColor(FROMRGB(red, green, blue));

				lumin=( red*299/1000)+ ( green*587/1000 ) + ( blue*114/1000 );

				//lumin = __min(lumin, 255);
				rmod=(255*lumin)/256;
				gmod=(100*lumin)/256;
				bmod=(100*lumin)/256;

				//rmod = __m( 255, rmod );

				IntensityTable[index]=Get16BPPColor( FROMRGB( rmod, gmod , bmod ) );
			}
#endif



	for(red=0; red < 256; red+=4)
		for(green=0; green < 256; green+=4)
			for(blue=0; blue < 256; blue+=4)
			{
				index=Get16BPPColor(FROMRGB(red, green, blue));
				IntensityTable[index]=Get16BPPColor(FROMRGB(red*dShadedPercent, green*dShadedPercent, blue*dShadedPercent));
			}

}



void SetShadeTablePercent( FLOAT uiShadePercent )
{
	guiShadePercent = uiShadePercent;
	BuildShadeTable( );
}


#ifdef JA2	// Jul. 23 '97 - ALEX - because Wizardry isn't using it & no longer has a version of Set8BPPPalette() available
void Init8BitTables(void)
{
SGPPaletteEntry Pal[256];
UINT32 uiCount;

	// calculate a grey-scale table for the default palette
	for(uiCount=0; uiCount < 256; uiCount++)
	{
		Pal[uiCount].peRed=(UINT8)(uiCount%128)+128;
		Pal[uiCount].peGreen=(UINT8)(uiCount%128)+128;
		Pal[uiCount].peBlue=(UINT8)(uiCount%128)+128;
	}

	Pal[0].peRed=0;
	Pal[0].peGreen=0;
	Pal[0].peBlue=0;

	Set8BPPPalette(Shaded8BPPPalettes[4]);
}

BOOLEAN Set8BitModePalette(SGPPaletteEntry *pPal)
{
	ShadesCalculateTables(pPal);
	Set8BPPPalette(pPal);
	return(TRUE);
}
#endif
