#include "pch.hpp"
//===========================================================================//
// File:	 Texture Format.cpp												 //
// Project:  GameOS					                                         //
// Contents: Texture Format enumeration & checking							 //
//---------------------------------------------------------------------------//
// Date      Who    Modification                                             //
// 04/03/00  NK     Created													 //
//---------------------------------------------------------------------------//
// Copyright (C) 2000 Microsoft Corp.						                 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//
#include "Texture Manager.hpp"
#include "DirectXDebugging.hpp"
#include "DXRasterizer.hpp"
#include "DirectX.hpp"


DDSURFACEDESC2 TextureDesc[5][2][4];		// arranged by:  [Format][want32bpp][compression]
int TextureDescScore[5][2][4];			// validity of current entry in TextrueDesc

const int nibble_to_count[16] = 
{
	0,	// 0
	1,	// 1
	1,	// 2
	2,	// 3
	1,	// 4
	2,	// 5
	2,	// 6
	3,	// 7
	1,	// 8
	2,	// 9
	2,	// A
	3,	// B
	2,	// C
	3,	// D
	3,	// E
	4	// F
};

DWORD ValidTextures;	// cleared & used externally to check that some formats were OK

extern int HasBumpEnvMap;
extern DWORD Want32T;

int CountBits( DWORD value )
{
	int c = 0;
	for( int i=0; i<32; i+=4 )
		c += nibble_to_count[ ( value>>i ) & 0x0f ];
	return c;
}

bool TextureFormatUsable( DDPIXELFORMAT *pf, int &Compression )
{
	// Check for palettized, 24-bit, YUV, or FOURCC - none of which GameOS uses
	if( ( pf->dwFlags & ( DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXEDTO8 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED1 ) ) ||
		( ( pf->dwRGBBitCount != 16 ) && ( pf->dwRGBBitCount != 32 ) ) ||
		( pf->dwFlags & DDPF_YUV ) )
		return false;

	Compression = 0;

	if( Compatibility3D&Bad4444 )					// Does the card have problems with 4444? - Mpact
	{
		if( pf->dwRGBBitCount==16 && (pf->dwFlags&DDPF_ALPHAPIXELS) && (pf->dwRGBAlphaBitMask==0xf000) )
			return false;
	}

	if( Compatibility3D&Bad8888 )					// Does the card have problems with 8888 / Compression / Bumpmapping? - Intel 810
	{
		if( pf->dwRGBBitCount==32 || 0!=(pf->dwFlags&(DDPF_FOURCC|DDPF_BUMPLUMINANCE|DDPF_BUMPDUDV)) )
			return false;
	}

	if( pf->dwFlags & DDPF_FOURCC )
	{
		if( pf->dwFourCC == FOURCC_DXT1 )
			Compression = 1;
		else if( pf->dwFourCC == FOURCC_DXT3 )
			Compression = 2;
		else if( pf->dwFourCC == FOURCC_DXT5 )
			Compression = 3;
		else 
			return false;	// no other FOURCC codes are supported
	}

	ValidTextures++;
	return true;	// texture format looks usable so far...
}

HRESULT CALLBACK CheckEnumProc( DDPIXELFORMAT *pf, LPVOID lpContext )
{
	int Compression;
	TextureFormatUsable( pf, Compression );
	return D3DENUMRET_OK;
}

HRESULT CALLBACK EnumProc( DDPIXELFORMAT *pf, LPVOID lpContext )
{
	SPEW(( GROUP_TEXTURE, "EnumProc - Enumerated %s", GetGosPixelFormat( pf ) ));

	int Is32 = (pf->dwRGBBitCount != 32)?0:1;
	int Compression;

	if( !TextureFormatUsable( pf, Compression ) )
		return D3DENUMRET_OK;

	if( pf->dwFlags & DDPF_BUMPLUMINANCE )
	{
		// bump luminance map
		// Not handled for now...
		// PAUSE(("DDPF_BUMPLUMINANCE"));
		return D3DENUMRET_OK;
	}
	else if ( pf->dwFlags & DDPF_BUMPDUDV )
	{
		// bump dUdV map
		// PAUSE(("DDPF_BUMPDUDV"));

		// We only handle 8-bit dU, 8-bit dV
		if( pf->dwBumpBitCount != 16 )
			return D3DENUMRET_OK;

		memcpy( &TextureDesc[gos_Texture_Bump][0][0].ddpfPixelFormat, pf, sizeof(*pf) );
		TextureDescScore[gos_Texture_Bump][0][0] = 20;

		HasBumpEnvMap = 1;

	}
	else
	{
		int alphaBits = ( pf->dwFlags & DDPF_ALPHAPIXELS ) ? CountBits( pf->dwRGBAlphaBitMask ) : 0;
		// int redBits = CountBits( pf->dwRBitMask );	// don't need red or blue counted, - look at green & alpha
		int greenBits = CountBits( pf->dwGBitMask );
		// int blueBits = CountBits( pf->dwBBitMask );

		// Check that 0888 and 8888 formats are in ARGB order
		if( ( greenBits == 8 ) && ((( pf->dwRBitMask >> 16 ) & ( pf->dwBBitMask )) != 0x0000ff) )
			return D3DENUMRET_OK;

		// Store in the one entry that perfectly matches this...
		int baseFormat = (alphaBits > 1 ) ? 2 : alphaBits;

		// Make sure that 0555 is worth less than 0565
		int score = ( greenBits == 5 ) ? 10 : 20;

		if( score > TextureDescScore[baseFormat][Is32][Compression] )
		{
			memcpy( &TextureDesc[baseFormat][Is32][Compression].ddpfPixelFormat, pf, sizeof(*pf) );
			TextureDescScore[baseFormat][Is32][Compression] = score;
		}
	}

	return D3DENUMRET_OK;
}

void Improve( int o1, int o2, int o3, int n1, int n2, int n3 )
{
	if( (!TextureDescScore[o1][o2][o3]) && TextureDescScore[n1][n2][n3] )
	{
		TextureDescScore[o1][o2][o3] = 1;
		memcpy( &TextureDesc[o1][o2][o3].ddpfPixelFormat,&TextureDesc[n1][n2][n3].ddpfPixelFormat,sizeof(DDPIXELFORMAT) );
	}
}

void OptimizeFormats()
{
	// First ensure we have the best possible 16-bit non-compressed versions

	// If we don't have 0565 or 0555, - try 1555,4444,0888, or 8888
	Improve(0,0,0,1,0,0);	// will get 1555 (if available)
	Improve(0,0,0,2,0,0);	// will get 4444
	Improve(0,0,0,0,1,0);	// will get 0888
	Improve(0,0,0,2,1,0);	// will get 8888

	// If we don't have 1555 - try 4444,8888,0565,0555, or 0888
	Improve(1,0,0,2,0,0);	// will get 4444
	Improve(1,0,0,2,1,0);	// will get 8888
	Improve(1,0,0,0,0,0);	// will get 0565 or failing that 0555

	// If we don't have 4444 - try 1555,8888,0565,0555, or 0888
	Improve(2,0,0,1,0,0);	// will get 1555,8888,0565,0555, or 0888

	// Now ensure we have the best possible 32-bit non-compressed versions

	// If we don't have 0888, try 8888, or failing that get the best solid 16-bit
	Improve(0,1,0,2,1,0);	// will get 8888
	Improve(0,1,0,0,0,0);	// will get best solid 16-bit

	// We won't have a 32-bit keyed (that would be like 1888) - try 8888 or failing that get the best keyed 16-bit
	Improve(1,1,0,2,1,0);	// try for 8888
	Improve(1,1,0,1,0,0);	// get best 16-bit keyed format

	// If we don't have 8888 use the best 16-bit alpha surface
	Improve(2,1,0,2,0,0);	// get best 16-bit alpha surface

	// Uncompressed solid, alpha, and keyed have now been taken care of

	// Look for dUdV
	Improve(3,0,0,3,1,0);	// use 32-bit dUdV if 16-bit unavailable
	Improve(3,1,0,3,0,0);	// use 16-bit dUdV if 32-bit unavailable

	// Normal formats are the same as solid

	Improve(4,0,0,0,0,0);	// 565 -> 16 bit normal
	Improve(4,1,0,0,1,0);	// 888 -> 32 bit normal

	// Finally, - if compressed formats are not available, use less compressed or non-compressed equivalents
	for( int base=0; base<3; base++ )
	{
		for( int compression=1; compression<4; compression++ )
		{
			Improve(base,0,compression,base,0,compression-1);
			Improve(base,1,compression,base,1,compression-1);
		}
	}


	
	if( Want32T )
	{
		// the debug option to force 32-bit textures has been selected...
		for( int format=0; format<5; format++ )
		{
			for( int compression=1; compression<4; compression++ )
			{
				memcpy( &TextureDesc[format][0][compression].ddpfPixelFormat,&TextureDesc[format][1][compression].ddpfPixelFormat,sizeof(DDPIXELFORMAT) );
			}
		}
		// Now force the uncompressed versions...
		// Instead of 0565 use 0888
		memcpy( &TextureDesc[0][0][0].ddpfPixelFormat, &TextureDesc[0][1][0].ddpfPixelFormat,sizeof(DDPIXELFORMAT) );
		// Leave 1555 alone as it is used for render targets
		// memcpy( &TextureDesc[1][0][0].ddpfPixelFormat, &TextureDesc[2][1][0].ddpfPixelFormat,sizeof(DDPIXELFORMAT) );
		// Instead of 4444 use 8888
		memcpy( &TextureDesc[2][0][0].ddpfPixelFormat, &TextureDesc[2][1][0].ddpfPixelFormat,sizeof(DDPIXELFORMAT) );
	}
}

void CTexInfo::AnalyzeTextureFormats()
{
	ValidTextures = 0;
	HasBumpEnvMap = 0;	// until we find a valid bumpmap format
	// Clear the formats and scores, set the size on each appropriately
	for( int format=0; format<5; format++ )
	{
		for( int is32=0; is32<2; is32++ )
		{
			for( int compression=0; compression<4; compression++ )
			{
				memset( (void *)(&TextureDesc[format][is32][compression]), 0, sizeof(DDSURFACEDESC2) );
				TextureDesc[format][is32][compression].dwSize = sizeof(DDSURFACEDESC2);
				TextureDescScore[format][is32][compression] = 0;
			}
		}
	}
	// Enumerate valid formats
	wEnumTextureFormats( d3dDevice7, EnumProc, 0 );
	// Fill in the blanks, - choose best-fit formats for any that weren't present
	OptimizeFormats();
}