#include "pch.hpp"
//===========================================================================//
// File:	 Renderstates.cpp												 //
// Project:  GameOS					                                         //
// Contents: Direct3D Renderstate routines									 //
//---------------------------------------------------------------------------//
// Date      Who    Modification                                             //
// 11/27/98  AG		Created								 					 //
//																			 //
//---------------------------------------------------------------------------//
// Copyright (C) 1999 Microsoft Corp.						                 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//
#include "3DRasterizer.hpp"
#include "Debugger.hpp"
#include "DirectX.hpp"
#include "DXRasterizer.hpp"
#include "Texture Manager.hpp"
#include "Time.hpp"

extern DWORD gLanguageDLL;

void DoRenderState( gos_RenderState RenderState, int Value );

// Converts a FLOAT to a DWORD for use in SetRenderState() calls
inline DWORD F2DW( FLOAT f ) { return *((DWORD*)&f); }

extern bool gNoBlade;
extern int HasBumpEnvMap;

//
// Array containing current render states
//
DWORD RenderStates[gos_MaxState];			// Current User settings
DWORD PreviousStates[gos_MaxState];			// Old renderstate
//
// Copies of the states loaded into hardware (to prevent duplicate values ever being sent to D3D)
//  [0]=true when HW is unknown
//  [1]=value sent to hardware
//
DWORD hwTextureMapBlend[2];
DWORD hwShadeMode[2];
DWORD hwPerspective[2];
DWORD hwAlphaTest[2];
DWORD hwZEnable[2];
DWORD hwTexture[2];
DWORD hwTexture1[2];
DWORD hwTexture2[2];
DWORD hwZCompare[2];
DWORD hwMonoEnable[2];
DWORD hwClipping[2];
//
// Flags to indicate state of each renderstate
//
// 0 = Has not been altered, or hardware is up to date
// 1 = Dirty - needs to be sent to hardware
//
BYTE UpdatedState[gos_MaxState];
//
// States updated
//
bool DirtyStates=0;
DWORD AlphaOp=-1;
DWORD ColorOp=-1;
DWORD CurrentFog;
DWORD CurrentFogCol;

//
// Statistics
//
DWORD	TotalRenderStateChanges=0;		// Number of renderstates sent to D3D
DWORD	RenderStateCalls=0;				// Number of calls to gos_SetRenderState
DWORD	UniqueRenderStateCalls=0;		// Number of calls to gos_SetRenderState that changed a state
DWORD	AlphaInvAlpha=0;				// Set when alpha blend mode is AlphaInvAlpha
DWORD	AlphaBlendEnabled=0;			// Set when alpha blend is enabled
DWORD	CurrentMipFilter=D3DTFP_NONE;	// Which mip filter is currently enabled

// for memory tracking
extern HGOSHEAP DefaultHeap;
extern DWORD BGMask;

//
// When application sets a renderstate, only update D3D when a primitive drawn
//
void __stdcall gos_SetRenderState( gos_RenderState RenderState, int Value )
{
	// LOG_BLOCK("Gos3D::SetRenderState");
	gosASSERT( !RenderDevice && InsideBeginScene && RenderState<gos_MaxState );

	#ifdef LAB_ONLY
	if( !InDebugger && gEnableRS )							// Disable ALL renderstates?
		return;
	RenderStateCalls++;
	#endif

	if( RenderState==gos_State_Fog )
	{
		if( 0!=Value )
		{
			if( 0xff000000!=(Value&0xff000000) )			// If high byte not 0xff, assume it's a pointer to the color
				Value=(*(DWORD*)Value)|0xff000000;
		}
	}

	if( RenderStates[RenderState]==Value )
		return;

	UpdatedState[RenderState]=1;
	RenderStates[RenderState]=Value;
	DirtyStates=1;
}





//
//
//
SAVESTATE	StackArray[8];				// array for 8 push depths without calling malloc
SAVESTATE*	pStateStack;				// Pointer to current saved renderstates
DWORD		StackDepth=0;


//
// Save renderstate settings
//
void __stdcall gos_PushRenderStates()
{
	gosASSERT( InsideBeginScene );

	SAVESTATE* ptemp;
	
	if( StackDepth<8 )
		ptemp=&StackArray[StackDepth];
	else
		ptemp=(SAVESTATE*)gos_Malloc(sizeof(SAVESTATE), DefaultHeap);
	
	StackDepth++;

	memcpy( &ptemp->SaveState, RenderStates, sizeof(RenderStates) );

	ptemp->pNext=pStateStack;

	pStateStack=ptemp;
}


//
// Restore renderstates
//
void __stdcall gos_PopRenderStates()
{
	gosASSERT( InsideBeginScene );

	if( 0==pStateStack )
		STOP(( "No states to restore" ));

	for( int t0=gos_MaxState-1; t0; t0-- )
	{
		gos_SetRenderState( (gos_RenderState)t0, pStateStack->SaveState[t0] );
		#ifdef LAB_ONLY
		RenderStateCalls--;
		#endif;
	}

	SAVESTATE* ptemp=pStateStack;

	pStateStack=pStateStack->pNext;

	StackDepth--;

	if( StackDepth>7 )
		gos_Free(ptemp);
}










//
// About to draw primitives, send any changed renderstates to D3D
//
// Parse in reverse order so gos_State_MipMapBias gets handled before gos_State_Texture
//
void FlushRenderStates()
{
	LOG_BLOCK("Gos3D::FlushRenderStates")
	if( DirtyStates )
	{
		for( int t0=gos_MaxState-1; t0; t0--)
		{
			if( UpdatedState[t0] )
			{
				UpdatedState[t0]=0;
				#ifdef LAB_ONLY
				UniqueRenderStateCalls++;
				#endif
				DoRenderState( (gos_RenderState)t0, RenderStates[t0] );
			}
		}
		DirtyStates=0;
	}
}








void UpdateTexturePipeLine( DWORD result )
{
	if( D3DTBLEND_DECAL==result && HasDecal )
	{
		if( RenderStates[gos_State_Texture] )
		{
			if( ColorOp!=1 )
			{
				wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
				ColorOp=1;
			}
			if( AlphaOp!=1 )
			{
				wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
				AlphaOp=1;
			}
		}
		else
		{
			if( ColorOp!=2 )
			{
				wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
				ColorOp=2;
			}
			if( AlphaOp!=2 )
			{
				wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
				AlphaOp=2;
			}
		}
	}
	else if( D3DTBLEND_MODULATE==result || !HasModulateAlpha )
	{
		if( RenderStates[gos_State_Texture] )
		{
			if( ColorOp!=0 )
			{
				wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
				ColorOp=0;
			}
			if( TEXHANDLE_TO_PTR(RenderStates[gos_State_Texture])->HasAlpha() )
			{
				if( AlphaOp!=1 )
				{
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
					AlphaOp=1;
				}
			}
			else
			{
				if( AlphaOp!=2 )
				{
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
					AlphaOp=2;
				}
			}
		}
		else
		{
			if( ColorOp!=2 )
			{
				wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
				ColorOp=2;
			}
			if( AlphaOp!=2 )
			{
				wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
				AlphaOp=2;
			}
		}
	}
	else		// Do modulate alpha
	{
		if( RenderStates[gos_State_Texture] )
		{
			if( ColorOp!=0 )
			{
				wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
				ColorOp=0;
			}
			if( AlphaOp!=0 )
			{
				wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
				AlphaOp=0;
			}
		}
		else
		{
			if( ColorOp!=2 )
			{
				wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
				ColorOp=2;
			}
			if( AlphaOp!=2 )
			{
				wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
				AlphaOp=2;
			}
		}
	}
}





DWORD	CurrentMipMapBias=0;	// Current render state for number of larger MipMap levels to ignore


static DWORD FlashTimer;
//
//
// Application visible function
//
// Set a renderstate
//
void DoRenderState( gos_RenderState RenderState, int Value )
{
	// LOG_BLOCK("Gos3D::DoRenderState");
	gosASSERT( InsideBeginScene );

	DWORD result=0;

	switch( RenderState )
	{
//
// 0=No texture, otherwise convert to a D3D Texture handle
//
		case gos_State_Texture:
		{
			LOG_BLOCK("Gos3D::DoRenderState(gos_State_Texture)")
			#ifdef LAB_ONLY
			if( !InDebugger && gForceNoTextures )
			{
				Value=0;
			}

			LastTexturePrim=PrimitivesRendered-LastTexturePrim;
			if( PreviousStates[gos_State_Texture] )
				NumTextured+=LastTexturePrim;
			LastTexturePrim=PrimitivesRendered;
			#endif
			if( 0==Value )
			{
				if( hwTexture[0] || hwTexture[1]!=0 )
					wSetTexture( d3dDevice7, 0, 0 );
				hwTexture[0]=0;
				hwTexture[1]=0;
				
				RenderStates[gos_State_Texture]=Value;

				UpdateTexturePipeLine( hwTextureMapBlend[1] );
			}
			else
			{
				#ifdef LAB_ONLY
				if( !InDebugger && gForceChessTexture )
				{
					Value=ChessTexture;
				}
				if( !InDebugger && SelectedHandle==Value && ( ( DebugDisplay==DbgS_UsedTextures ) || DebugDisplay==DbgS_LoadedTextures ) )
				{
					DWORD Time=((DWORD)(gos_GetHiResTime()*16))&1;
					if( Time )
					{
						TEXHANDLE_TO_PTR(Value)->SetUsed();
						Value=ChessTexture;
					}
				}
				#endif

				result=TEXHANDLE_TO_PTR(Value)->GetD3DTextureHandle();

				if( hwTexture[0] || hwTexture[1]!=result )
					wSetTexture( d3dDevice7, 0, (IDirectDrawSurface7*)result );

				hwTexture[0]=0;
				hwTexture[1]=result;

				RenderStates[gos_State_Texture]=Value;

				UpdateTexturePipeLine( hwTextureMapBlend[1] );
//
// Check if filtering has to be reenabled or disabled
//
				if( !HasMipMap || (RenderStates[gos_State_Texture] && TEXHANDLE_TO_PTR(RenderStates[gos_State_Texture])->MipmapDisabled() ) )
				{
					if( CurrentMipFilter!=D3DTFP_NONE )
					{
						CurrentMipFilter=D3DTFP_NONE;
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_NONE );
					}
				}
				else
				{
					if( gos_FilterNone==RenderStates[gos_State_Filter] )
					{
						if( RenderStates[gos_State_MipMapBias] )
						{
							if( CurrentMipFilter!=D3DTFP_POINT )
							{
								CurrentMipFilter=D3DTFP_POINT;
								wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_POINT );
							}
						}
						else
						{
							if( CurrentMipFilter!=D3DTFP_NONE )
							{
								CurrentMipFilter=D3DTFP_NONE;
								wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_NONE );
							}
						}
					}
					else if( gos_FilterBiLinear==RenderStates[gos_State_Filter] )
					{
						if( CurrentMipFilter!=D3DTFP_POINT )
						{
							CurrentMipFilter=D3DTFP_POINT;
							wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_POINT );
						}
					}
					else
					{
						if( CurrentMipFilter!=D3DTFP_LINEAR )
						{
							CurrentMipFilter=D3DTFP_LINEAR;
							wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_LINEAR );
						}
					}
				}
			}
			#ifdef _ARMOR
			HasMaxUV=0;
			if( 0!=Value && CapsDirect3D.dwMaxTextureRepeat )
			{
				if( CapsDirect3D.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE )
				{
					MaxUCoord=(float)CapsDirect3D.dwMaxTextureRepeat;
					MaxVCoord=(float)CapsDirect3D.dwMaxTextureRepeat;
				}
				else
				{
					MaxUCoord=(float)(CapsDirect3D.dwMaxTextureRepeat / TEXHANDLE_TO_PTR(Value)->Width() );
					MaxVCoord=(float)(CapsDirect3D.dwMaxTextureRepeat / TEXHANDLE_TO_PTR(Value)->Height() );
				}
				MinUCoord=-MaxUCoord;
				MinVCoord=-MaxVCoord;
				if( MinUCoord )
					HasMaxUV=1;
			}
			#endif
			break;
		}
//
// Set the filter state (None, Bilinear, Trilinear )
//
		case gos_State_Filter:
			gosASSERT( Value>=gos_FilterNone && Value<=gos_FilterTriLinear );
			if( RenderStates[gos_State_Multitexture]==gos_Multitexture_None )
			{
				#ifdef LAB_ONLY
				if( !InDebugger )
				{
					if( gForceNoFiltering )
					{
						Value=gos_FilterNone;
					} else if( gForceBiLinear )
					{
						Value=gos_FilterBiLinear;
					} else if( gForceTriLinear )
					{
						Value=gos_FilterTriLinear;
					}
				}
				#endif
				if( Value==gos_FilterTriLinear && !HasTriLinear )			// If no trilinear, make it bilinear
					Value=gos_FilterBiLinear;
				if( Value==gos_FilterBiLinear && !HasBiLinear )				// If no bilinear, make it not filtered
					Value=gos_FilterNone;
				#ifdef LAB_ONLY
				LastFilterPrim=PrimitivesRendered-LastFilterPrim;
				switch( PreviousStates[gos_State_Filter] )
				{
					case gos_FilterBiLinear:
						NumBilinear+=LastFilterPrim;						// Record how many primitves of each filter type rendered
						break;
					case gos_FilterTriLinear:
						NumTrilinear+=LastFilterPrim;
						break;
					default:
						NumPointSampled+=LastFilterPrim;
				}
				LastFilterPrim=PrimitivesRendered;
				#endif
				switch( Value )
				{
					case gos_FilterNone:
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MINFILTER, D3DTFN_POINT );
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MAGFILTER, D3DTFG_POINT );
						if( RenderStates[gos_State_MipMapBias] )
						{
							if( CurrentMipFilter!=D3DTFP_POINT )
							{
								CurrentMipFilter=D3DTFP_POINT;
								wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_POINT );
							}
						}
						else
						{
							if( CurrentMipFilter!=D3DTFP_NONE )
							{
								CurrentMipFilter=D3DTFP_NONE;
								wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_NONE );
							}
						}
						break;
					case gos_FilterBiLinear:
						if( gos_FilterNone==PreviousStates[gos_State_Filter] )
						{
							wSetTextureStageState( d3dDevice7, 0, D3DTSS_MINFILTER, D3DTFN_LINEAR );
							wSetTextureStageState( d3dDevice7, 0, D3DTSS_MAGFILTER, D3DTFG_LINEAR );
						}
						if( HasMipMap && RenderStates[gos_State_Texture] && !TEXHANDLE_TO_PTR(RenderStates[gos_State_Texture])->MipmapDisabled() )
						{
							if( CurrentMipFilter!=D3DTFP_POINT )
							{
								CurrentMipFilter=D3DTFP_POINT;
								wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_POINT );
							}
						}
						else
						{
							if( CurrentMipFilter!=D3DTFP_NONE )
							{
								CurrentMipFilter=D3DTFP_NONE;
								wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_NONE );
							}
						}
						break;
					case gos_FilterTriLinear:
						if( gos_FilterNone==PreviousStates[gos_State_Filter] )
						{
							wSetTextureStageState( d3dDevice7, 0, D3DTSS_MINFILTER, D3DTFN_LINEAR );
							wSetTextureStageState( d3dDevice7, 0, D3DTSS_MAGFILTER, D3DTFG_LINEAR );
						}
						if( HasMipMap && RenderStates[gos_State_Texture] && !TEXHANDLE_TO_PTR(RenderStates[gos_State_Texture])->MipmapDisabled() )
						{
							if( CurrentMipFilter!=D3DTFP_LINEAR )
							{
								CurrentMipFilter=D3DTFP_LINEAR;
								wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_LINEAR );
							}
						}
						else
						{
							if( CurrentMipFilter!=D3DTFP_NONE )
							{
								CurrentMipFilter=D3DTFP_NONE;
								wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_NONE );
							}
						}
						break;
				}
			}
			break;
//
//
//
		case gos_State_ZCompare:
			result=(Value==1 ? D3DCMP_LESSEQUAL : Value==2 ? D3DCMP_LESS : D3DCMP_ALWAYS);

			gosASSERT( !(Environment.Renderer==3 && Value==2) );

			if( Environment.disableZBuffer )
				result=D3DCMP_ALWAYS;
			
			#ifdef LAB_ONLY
			LastZComparePrim=PrimitivesRendered-LastZComparePrim;
			if( PreviousStates[gos_State_ZCompare] )
				NumZCompare+=LastZComparePrim;
			LastZComparePrim=PrimitivesRendered;
			#endif

			if( (hwZCompare[0] || hwZCompare[1]!=result) )
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_ZFUNC, result );

			hwZCompare[0]=0;
			hwZCompare[1]=result;
			break;
//
//
//
		case gos_State_ZWrite:
			result=(Value ? 1 : 0);

			if( Environment.disableZBuffer )
				result=0;

			#ifdef LAB_ONLY
			LastZWritePrim=PrimitivesRendered-LastZWritePrim;
			if( PreviousStates[gos_State_ZWrite] )
				NumZWrite+=LastZWritePrim;
			LastZWritePrim=PrimitivesRendered;
			#endif

			if( (hwZEnable[0] || hwZEnable[1]!=result) )
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_ZWRITEENABLE, result );

			hwZEnable[0]=0;
			hwZEnable[1]=result;
			break;
//
//
//
		case gos_State_AlphaTest:
			if( !InDebugger )
			{
				if( gForceNoAlphaTest )
					Value=0;
				else if( gForceAlphaTest )
					Value=1;
			}

			#ifdef LAB_ONLY
			LastAlphaTestPrim=PrimitivesRendered-LastAlphaTestPrim;
			if( PreviousStates[gos_State_AlphaTest] )
				NumAlphaTest+=LastAlphaTestPrim;
			LastAlphaTestPrim=PrimitivesRendered;
			#endif

			if( HasAlphaTest )
			{
				result=(Value ? 1 : 0);
				if( hwAlphaTest[0] || hwAlphaTest[1]!=result )
					wSetRenderState( d3dDevice7, D3DRENDERSTATE_ALPHATESTENABLE, result );
				hwAlphaTest[0]=0;
				hwAlphaTest[1]=result;
			}
			else
			{
				if( Value )
				{
					if( gos_Alpha_OneZero==RenderStates[gos_State_AlphaMode] )
					{
						if( !AlphaInvAlpha )
						{
							AlphaInvAlpha=1;
							wSetRenderState( d3dDevice7, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA );
							wSetRenderState( d3dDevice7, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA );
							if( !AlphaBlendEnabled )
							{
								AlphaBlendEnabled=1;
								wSetRenderState( d3dDevice7, D3DRENDERSTATE_ALPHABLENDENABLE, 1 );
							}
						}
					}
				}
				else
				{
					if( AlphaInvAlpha && gos_Alpha_OneZero==RenderStates[gos_State_AlphaMode] )
					{
						AlphaInvAlpha=0;
						if( AlphaBlendEnabled )
						{
							AlphaBlendEnabled=0;
							wSetRenderState( d3dDevice7, D3DRENDERSTATE_ALPHABLENDENABLE, 0 );
						}
					}
				}
			}
			break;
//
//
//
		case gos_State_Perspective:
			if( !InDebugger )
			{
				if( gForcePerspective )
					Value=1;
				else if( gForceNoPerspective )
					Value=0;
			}
			result=(Value ? 1 : 0);

			#ifdef LAB_ONLY
			LastPerspectivePrim=PrimitivesRendered-LastPerspectivePrim;
			if( PreviousStates[gos_State_Perspective] )
				NumPerspective+=LastPerspectivePrim;
			LastPerspectivePrim=PrimitivesRendered;
			#endif

			if( 0==(Compatibility3D&NoDisablePerspective) && (hwPerspective[0] || hwPerspective[1]!=result) )
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_TEXTUREPERSPECTIVE, result );

			hwPerspective[0]=0;
			hwPerspective[1]=result;
			break;
//
//
//
		case gos_State_Specular:
			if( !InDebugger )
			{
				if( gForceSpecular )
					Value=1;
				else if( gForceNoSpecular )
					Value=0;
			}
			result=(Value ? 1 : 0);

			#ifdef LAB_ONLY
			LastSpecularPrim=PrimitivesRendered-LastSpecularPrim;
			if( PreviousStates[gos_State_Specular] )
				NumSpecular+=LastSpecularPrim;
			LastSpecularPrim=PrimitivesRendered;
			#endif

			if( HasSpecular )
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_SPECULARENABLE, result );
			break;
//
//
//
		case gos_State_Dither:
			#ifdef LAB_ONLY
			if( !InDebugger )
			{
				if( gForceNoDithering )
					Value=0;
				if( gForceDithering )
					Value=1;
			}
			#endif

			#ifdef LAB_ONLY
			LastDitheredPrim=PrimitivesRendered-LastDitheredPrim;
			if( PreviousStates[gos_State_Dither] )
				NumDithered+=LastDitheredPrim;
			LastDitheredPrim=PrimitivesRendered;
			#endif

			if( HasDither )
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_DITHERENABLE, Value ? 1 : 0 );
			break;
//
//
//
		case gos_State_WireframeMode:
			wSetRenderState( d3dDevice7, D3DRENDERSTATE_FILLMODE, Value ? D3DFILL_WIREFRAME : D3DFILL_SOLID );
			break;
//
//
//
		case gos_State_AlphaMode:
			gosASSERT( Value>=gos_Alpha_OneZero && Value<=gos_Alpha_AlphaOne );
			if( !HasAlphaModes )
			{
				if( Value!=gos_Alpha_OneZero )
					Value=gos_Alpha_AlphaInvAlpha;
			}
	
			#ifdef LAB_ONLY
			if( !InDebugger && gForceAlphaBlending )
				Value=gos_Alpha_OneZero;
			LastAlphaPrim=PrimitivesRendered-LastAlphaPrim;
			if (PreviousStates[gos_State_AlphaMode]!=gos_Alpha_OneZero )
				NumAlpha+=LastAlphaPrim;
			LastAlphaPrim=PrimitivesRendered;
			#endif

			switch( Value )
			{
				case gos_Alpha_OneZero:
					if( !HasAlphaTest && RenderStates[gos_State_AlphaTest] )
					{
						if( !AlphaInvAlpha )
						{
							AlphaInvAlpha=1;
							wSetRenderState( d3dDevice7, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA );
							wSetRenderState( d3dDevice7, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA );
							if( !AlphaBlendEnabled )
							{
								AlphaBlendEnabled=1;
								wSetRenderState( d3dDevice7, D3DRENDERSTATE_ALPHABLENDENABLE, 1 );
							}
						}
					}
					else
					{
						AlphaInvAlpha=0;
						if( Compatibility3D&BrokenAlphaTest )
						{
							wSetRenderState( d3dDevice7, D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE );
							wSetRenderState( d3dDevice7, D3DRENDERSTATE_DESTBLEND, D3DBLEND_ZERO );
							if( !AlphaBlendEnabled )
							{
								AlphaBlendEnabled=1;
								wSetRenderState( d3dDevice7, D3DRENDERSTATE_ALPHABLENDENABLE, 1 );
							}
						}
						else
						{
							if( AlphaBlendEnabled )
							{
								AlphaBlendEnabled=0;
								wSetRenderState( d3dDevice7, D3DRENDERSTATE_ALPHABLENDENABLE, 0 );
							}
						}
					}
					break;
				case gos_Alpha_OneOne:
					AlphaInvAlpha=0;
					wSetRenderState( d3dDevice7, D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE );
					wSetRenderState( d3dDevice7, D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE );
					if( !AlphaBlendEnabled )
					{
						AlphaBlendEnabled=1;
						wSetRenderState( d3dDevice7, D3DRENDERSTATE_ALPHABLENDENABLE, 1 );
					}
					break;
				case gos_Alpha_AlphaOne:
					AlphaInvAlpha=0;
					wSetRenderState( d3dDevice7, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA );
					wSetRenderState( d3dDevice7, D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE );
					if( !AlphaBlendEnabled )
					{
						AlphaBlendEnabled=1;
						wSetRenderState( d3dDevice7, D3DRENDERSTATE_ALPHABLENDENABLE, 1 );
					}
					break;
				case gos_Alpha_OneInvAlpha:
					AlphaInvAlpha=0;
					wSetRenderState( d3dDevice7, D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE );
					wSetRenderState( d3dDevice7, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA );
					if( !AlphaBlendEnabled )
					{
						AlphaBlendEnabled=1;
						wSetRenderState( d3dDevice7, D3DRENDERSTATE_ALPHABLENDENABLE, 1 );
					}
					break;
				case gos_Alpha_AlphaInvAlpha:
					if( !AlphaInvAlpha )
					{
						AlphaInvAlpha=1;
						wSetRenderState( d3dDevice7, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA );
						wSetRenderState( d3dDevice7, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA );
						if( !AlphaBlendEnabled )
						{
							AlphaBlendEnabled=1;
							wSetRenderState( d3dDevice7, D3DRENDERSTATE_ALPHABLENDENABLE, 1 );
						}
					}
					break;
				default:
					STOP(( "Unsupported blending mode" ));
			}
			break;
//
//
//
		case gos_State_Clipping:
			{
				gosASSERT( Value>=0 && Value<=2 );

				#ifdef LAB_ONLY
				LastClipped=PrimitivesRendered-LastClipped;
				if( PreviousStates[gos_State_Clipping] )
				{
					if( PreviousStates[gos_State_Clipping]==1 || !HasGuardBandClipping )
						NumClipped+=LastClipped;
					else
						NumGuardBandClipped+=LastClipped;
				}
				LastClipped=PrimitivesRendered;
				if( ZoomMode && !InDebugger )
					Value=1;
				#endif

				DWORD result=Value;
				if( 2==Value )
				{
					if( HasGuardBandClipping )
						result=0;
					else
						result=1;
				}

				if( hwClipping[0] || hwClipping[1]!=result )
					wSetRenderState( d3dDevice7, D3DRENDERSTATE_CLIPPING, result );

				hwClipping[0]=0;
				hwClipping[1]=result;
			}
			break;
//
//
//
		case gos_State_TextureAddress:
			gosASSERT( Value>=gos_TextureWrap && Value<=gos_TextureClamp );

			#ifdef LAB_ONLY
			LastTextureAddressPrim=PrimitivesRendered-LastTextureAddressPrim;
			if( PreviousStates[gos_State_TextureAddress]==gos_TextureWrap )
				NumWrapped+=LastTextureAddressPrim;
			else
				NumClamped+=LastTextureAddressPrim;
			LastTextureAddressPrim=PrimitivesRendered;
			#endif

			wSetTextureStageState( d3dDevice7, 0, D3DTSS_ADDRESS , Value==gos_TextureWrap ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP );
			break;
//
//
//
		case gos_State_Culling:
			gosASSERT( Value>=gos_Cull_None && Value<=gos_Cull_CCW );

			#ifdef LAB_ONLY
			LastCulledPrim=PrimitivesRendered-LastCulledPrim;
			if( PreviousStates[gos_State_Culling]!=gos_Cull_None )
				NumCulled+=LastCulledPrim;
			LastCulledPrim=PrimitivesRendered;
			#endif

			wSetRenderState( d3dDevice7, D3DRENDERSTATE_CULLMODE, Value );
			break;
//
//
//
		case gos_State_ShadeMode:
			gosASSERT( Value>=gos_ShadeFlat && Value<=gos_ShadeGouraud );
			if( !InDebugger )
			{
				if( gForceFlat )
					Value=gos_ShadeFlat;
				else if( gForceGouraud )
					Value=gos_ShadeGouraud;
			}

			result=(Value==gos_ShadeGouraud ? D3DSHADE_GOURAUD : D3DSHADE_FLAT);

			#ifdef LAB_ONLY
			LastShadePrim=PrimitivesRendered-LastShadePrim;
			if( PreviousStates[gos_State_ShadeMode]==gos_ShadeFlat )
				NumFlat+=LastShadePrim;
			else
				NumGouraud+=LastShadePrim;
			LastShadePrim=PrimitivesRendered;
			#endif

			if( hwShadeMode[0] || hwShadeMode[1]!=result )
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_SHADEMODE, result );

			hwShadeMode[0]=0;
			hwShadeMode[1]=result;
			break;
//
//    
//
		case gos_State_TextureMapBlend:
			gosASSERT( Value>=gos_BlendDecal && Value<=gos_BlendModulateAlpha );
			if( RenderStates[gos_State_Multitexture]==gos_Multitexture_None )
			{
				if( !InDebugger )
				{
					if( gForceBlend )
						Value=gForceBlend;
				}
				result=(Value==gos_BlendModulateAlpha ? D3DTBLEND_MODULATEALPHA : (Value==gos_BlendModulate ? D3DTBLEND_MODULATE : D3DTBLEND_DECAL));

				#ifdef LAB_ONLY
				LastBlendPrim=PrimitivesRendered-LastBlendPrim;
				if( PreviousStates[gos_State_TextureMapBlend]==gos_BlendDecal )
					NumDecal+=LastBlendPrim;
				else if( PreviousStates[gos_State_TextureMapBlend]==gos_BlendModulate )
					NumModulate+=LastBlendPrim;
				else
					NumModulateAlpha+=LastBlendPrim;
				LastBlendPrim=PrimitivesRendered;
				#endif

				if( hwTextureMapBlend[0] || hwTextureMapBlend[1]!=result )
				{
					UpdateTexturePipeLine( result );
				}

				hwTextureMapBlend[0]=0;
				hwTextureMapBlend[1]=result;
			}
			break;
//
//
//
		case gos_State_MonoEnable:
			result=Value ? ((Environment.Renderer==3) ? Value : 1) : 0;		// Blade allows any value - D3D only ever sees 0 or 1

			if( !InDebugger && gForceMono )
			{
					Value=Value|1;
			}

			#ifdef LAB_ONLY
			LastMonoPrim=PrimitivesRendered-LastMonoPrim;
			if( PreviousStates[gos_State_MonoEnable] )
				NumMono+=LastMonoPrim;
			LastMonoPrim=PrimitivesRendered;
			#endif

			if( 3==Environment.Renderer && !gNoBlade && (hwMonoEnable[0] || hwMonoEnable[1]!=result) )
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_MONOENABLE, result );

			hwMonoEnable[0]=0;
			hwMonoEnable[1]=result;
			break;
//
//    
//
		case gos_State_MipMapBias:
			gosASSERT( Value<=4 );
			if( !InDebugger && gForceMipBias>=0 )
				Value=gForceMipBias;
			if( !HasMipMap )
				Value=0;
			if( CurrentMipMapBias!=Value )
			{
				CurrentMipMapBias=Value;
 				float fred=(float)Value;
				wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPMAPLODBIAS, *(DWORD*)&fred );
				UpdatedState[gos_State_Texture]=1;				// Make sure new texture pointer is obtained
			}
			break;
//
//
//
		case gos_State_Fog:
			#ifdef LAB_ONLY
			if( !InDebugger && (gForceNoFog || RenderMode==ExamineMipmaps || RenderMode==WireframeGlobalTexture || RenderMode==WireframeGlobalColor || RenderMode==ExamineMipmaps2)  )
				Value=0;
			#endif

			#ifdef LAB_ONLY
			LastFogPrim=PrimitivesRendered-LastFogPrim;
			if( PreviousStates[gos_State_Fog] )
				NumFog+=LastFogPrim;
			LastFogPrim=PrimitivesRendered;
			#endif

			if( 0==Value || 0==HasFog )
			{
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_FOGENABLE, 0 );
			}
			else
			{
//
// Mask off color bits so that BG color matches textures better
//
				DWORD FogColor=Value&BGMask;
				if( UseGammaCorrection )
				{
					FogColor=(GammaTable[(FogColor>>0)&0xff]<<0)+(GammaTable[(FogColor>>8)&0xff]<<8)+(GammaTable[(FogColor>>16)&0xff]<<16)+(FogColor&0xff000000);
				}
				#ifdef LAB_ONLY
					CurrentFog=1;
					CurrentFogCol=FogColor;
				#endif
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_FOGCOLOR, FogColor );
				if( 0==PreviousStates[gos_State_Fog] )
				{
					wSetRenderState( d3dDevice7, D3DRENDERSTATE_FOGENABLE, 1 );
				}
			}
			break;
//
// Stencil operations, ignored if no stencil buffer.
//
		case gos_State_StencilEnable:
		{
			if( Environment.Stencil && !StencilActive )
			{
				result=(Value ? 1 : 0);
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILENABLE, result );
			}
			break;
		}
		case gos_State_StencilFunc:
		{
			if( Environment.Stencil && !StencilActive )
			{
				gosASSERT( Value>=gos_Cmp_Never && Value<=gos_Cmp_Always );
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILFUNC, Value );
			}
			break;
		}
		case gos_State_StencilRef:
		{
			if( Environment.Stencil && !StencilActive )
			{
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILREF, Value );
			}
			break;
		}
		case gos_State_StencilMask:
		{
			if( Environment.Stencil && !StencilActive )
			{
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILMASK, Value );
			}
			break;
		}
		case gos_State_StencilFail:
		{
			if( Environment.Stencil && !StencilActive )
			{
				gosASSERT( Value>=gos_Stencil_Keep && Value<=gos_Stencil_Decr );
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILFAIL, Value );
			}
			break;
		}
		case gos_State_StencilZFail:
		{
			if( Environment.Stencil && !StencilActive )
			{
				gosASSERT( Value>=gos_Stencil_Keep && Value<=gos_Stencil_Decr );
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILZFAIL, Value );
			}
			break;
		}
		case gos_State_StencilPass:
		{
			if( Environment.Stencil && !StencilActive )
			{
				gosASSERT( Value>=gos_Stencil_Keep && Value<=gos_Stencil_Decr );
				wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILPASS, Value );
			}
			break;
		}
//
// Multitexture operations, assert if not possible
//
		case gos_State_Multitexture:
		{
			FlushRenderStates();	// since we mix renderstates & stage states, drivers get confused
			switch( Value )
			{
				case gos_Multitexture_None:
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_TEXCOORDINDEX, 0 );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_TEXCOORDINDEX, 1 );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_ADDRESS, D3DTADDRESS_WRAP );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
					if( gos_FilterNone==RenderStates[gos_State_Filter] )								// Restore any previous filter mode
					{
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MINFILTER, D3DTFN_POINT );
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MAGFILTER, D3DTFG_POINT );
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, CurrentMipFilter );
					} else if( gos_FilterBiLinear==RenderStates[gos_State_Filter] )
					{
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MINFILTER, D3DTFN_LINEAR );
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MAGFILTER, D3DTFG_LINEAR );
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, CurrentMipFilter );
					}
					else
					{
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MINFILTER, D3DTFN_LINEAR );
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MAGFILTER, D3DTFG_LINEAR );
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, CurrentMipFilter );
					}
//
// Clear the other texture stages
//
					wSetTexture( d3dDevice7, 1, 0 );
					hwTexture1[0]=0;
					hwTexture1[1]=0;
					wSetTexture( d3dDevice7, 2, 0 );
					hwTexture2[0]=0;
					hwTexture2[1]=0;
					RenderStates[gos_State_Texture2]=NULL;
					RenderStates[gos_State_Texture3]=NULL;
//
// Setup correct blending modes
//
					ColorOp=0;
					AlphaOp=0;
					UpdateTexturePipeLine( hwTextureMapBlend[1] );
					break;

				case gos_Multitexture_LightMap:
					gosASSERT( gEnableMulti && HasMultitextureLightmap );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_TEXCOORDINDEX, 0 );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_TEXCOORDINDEX, 1 );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_ADDRESS, D3DTADDRESS_WRAP );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_MINFILTER, D3DTFN_LINEAR );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_MAGFILTER, D3DTFG_LINEAR );			// Trilinear base texture
					if( HasMultitextureLightmapFilter )
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_NONE );
					else
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_LINEAR );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_MINFILTER, D3DTFN_LINEAR );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_MAGFILTER, D3DTFG_LINEAR );			// Bilinear lightmap texture
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_MIPFILTER, D3DTFP_NONE );

					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLOROP, D3DTOP_MODULATE2X );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLORARG2, D3DTA_CURRENT );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_COLOROP, D3DTOP_DISABLE );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
					break;

				case gos_Multitexture_SpecularMap:
					gosASSERT( gEnableMulti && HasMultitextureSpecularmap );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_TEXCOORDINDEX, 0 );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_TEXCOORDINDEX, 1 );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_ADDRESS, D3DTADDRESS_WRAP );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_MINFILTER, D3DTFN_LINEAR );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_MAGFILTER, D3DTFG_LINEAR );			// Trilinear base texture
					if( HasMultitextureSpecularmapFilter )
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_NONE );
					else
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_LINEAR );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_MINFILTER, D3DTFN_LINEAR );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_MAGFILTER, D3DTFG_LINEAR );			// Bilinear lightmap texture
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_MIPFILTER, D3DTFP_NONE );

					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLOROP, D3DTOP_ADD );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLORARG2, D3DTA_CURRENT );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_COLOROP, D3DTOP_DISABLE );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
					break;

				case gos_Multitexture_DetailTexture:
					gosASSERT( gEnableMulti && HasMultitextureDetailTexture );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_TEXCOORDINDEX, 0 );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_TEXCOORDINDEX, 1 );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_ADDRESS, D3DTADDRESS_WRAP );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_MINFILTER, D3DTFN_LINEAR );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_MAGFILTER, D3DTFG_LINEAR );			// Trilinear base texture
					if( HasMultitextureDetailTextureFilter )
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_NONE );
					else
						wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_LINEAR );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_MINFILTER, D3DTFN_LINEAR );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_MAGFILTER, D3DTFG_LINEAR );			// Bilinear lightmap texture
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_MIPFILTER, D3DTFP_NONE );

					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLOROP, D3DTOP_ADD );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLORARG2, D3DTA_CURRENT );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_COLOROP, D3DTOP_DISABLE );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
					break;

				case gos_Multitexture_BumpEnvMap:
					gosASSERT( gEnableMulti && HasBumpEnvMap );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ADDRESS, D3DTADDRESS_WRAP );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_ADDRESS, D3DTADDRESS_WRAP );

					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_TEXCOORDINDEX, 0 );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_TEXCOORDINDEX, 1 );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLORARG2, D3DTA_CURRENT );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_BUMPENVMAT00, F2DW(0.5f) );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_BUMPENVMAT01, F2DW(0.0f) );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_BUMPENVMAT10, F2DW(0.0f) );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_BUMPENVMAT11, F2DW(0.5f) );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_BUMPENVLSCALE, F2DW(1.0f) );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_BUMPENVLOFFSET, F2DW(0.0f) );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLOROP, D3DTOP_BUMPENVMAPLUMINANCE );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_TEXCOORDINDEX, 2 );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_COLOROP, D3DTOP_ADD );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_COLORARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_COLORARG2, D3DTA_CURRENT );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_ALPHAARG2, D3DTA_CURRENT );

					wSetTextureStageState( d3dDevice7, 3, D3DTSS_COLOROP, D3DTOP_DISABLE );
					wSetTextureStageState( d3dDevice7, 3, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
					break;

				case gos_Multitexture_BumpDotMap:
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_MAGFILTER, D3DTFP_LINEAR );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_MINFILTER, D3DTFP_LINEAR );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_LINEAR );

					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_TEXCOORDINDEX, 1 );

					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3 );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
					wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );

					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ADDRESS, D3DTADDRESS_WRAP );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_TEXCOORDINDEX, 0 );

					wSetTextureStageState( d3dDevice7, 1, D3DTSS_MAGFILTER, D3DTFP_LINEAR );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_MINFILTER, D3DTFP_LINEAR );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_MIPFILTER, D3DTFP_LINEAR );

					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLOROP, D3DTOP_ADD );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLORARG2, D3DTA_TEXTURE );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLORARG1, D3DTA_CURRENT );

					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
					wSetTextureStageState( d3dDevice7, 1, D3DTSS_ALPHAARG2, D3DTA_TEXTURE );
					
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_COLOROP, D3DTOP_DISABLE );
					wSetTextureStageState( d3dDevice7, 2, D3DTSS_ALPHAOP, D3DTOP_DISABLE );

					wSetRenderState( d3dDevice7, D3DRENDERSTATE_TEXTUREFACTOR, 0xFF80FF80 );

					break;
			}
			break;
		}
//
// Setting the 2nd texture for multitexture operations
//
		case gos_State_Texture2:
		{
			#ifdef LAB_ONLY
			if( !InDebugger && gForceNoTextures )
			{
				Value=0;
			}
			#endif
			if( 0==Value )
			{
				if( hwTexture1[0] || hwTexture1[1]!=0 )
					wSetTexture( d3dDevice7, 1, 0 );
				hwTexture1[0]=0;
				hwTexture1[1]=0;
			}
			else
			{
				#ifdef LAB_ONLY
				if( !InDebugger && gForceChessTexture )
				{
					Value=ChessTexture;
				}
				if( !InDebugger && SelectedHandle==Value && ( ( DebugDisplay==DbgS_UsedTextures ) || DebugDisplay==DbgS_LoadedTextures ) )
				{
					DWORD Time=((DWORD)(gos_GetHiResTime()*16))&1;
					if( Time )
					{
						TEXHANDLE_TO_PTR(Value)->SetUsed();
						Value=ChessTexture;
					}
				}
				#endif

				result=TEXHANDLE_TO_PTR(Value)->GetD3DTextureHandle();

				if( hwTexture1[0] || hwTexture1[1]!=result )
					wSetTexture( d3dDevice7, 1, (IDirectDrawSurface7*)result );

				hwTexture1[0]=0;
				hwTexture1[1]=result;
			}
			break;
		}
//
// Setting the 3rd texture for bump environment map operations
//
		case gos_State_Texture3:
		{
			#ifdef LAB_ONLY
			if( !InDebugger && gForceNoTextures )
			{
				Value=0;
			}
			#endif
			if( 0==Value )
			{
				if( hwTexture2[0] || hwTexture2[1]!=0 )
					wSetTexture( d3dDevice7, 2, 0 );
				hwTexture2[0]=0;
				hwTexture2[1]=0;
			}
			else
			{
				#ifdef LAB_ONLY
				if( !InDebugger && gForceChessTexture )
				{
					Value=ChessTexture;
				}
				if( !InDebugger && SelectedHandle==Value && ( ( DebugDisplay==DbgS_UsedTextures ) || DebugDisplay==DbgS_LoadedTextures ) )
				{
					DWORD Time=((DWORD)(gos_GetHiResTime()*16))&1;
					if( Time )
					{
						TEXHANDLE_TO_PTR(Value)->SetUsed();
						Value=ChessTexture;
					}
				}
				#endif

				result=TEXHANDLE_TO_PTR(Value)->GetD3DTextureHandle();

				if( hwTexture2[0] || hwTexture2[1]!=result )
					wSetTexture( d3dDevice7, 2, (IDirectDrawSurface7*)result );

				hwTexture2[0]=0;
				hwTexture2[1]=result;
			}
			break;
		}
//
// Set the default ambient lighting for the scene
//
		case gos_State_Ambient:
		{
			wSetRenderState( d3dDevice7, D3DRENDERSTATE_AMBIENT, Value );
			break;
		}
//
// Enable or disable D3D lighting
//
		case gos_State_Lighting:
		{
			result=Value ? 1 : 0;
			#ifdef LAB_ONLY
			if( !InDebugger && gDisableLighting )
				result=0;
			#endif
			wSetRenderState( d3dDevice7, D3DRENDERSTATE_LIGHTING, result );
			break;
		}
//
// Enable or disable D3D normalizing normals
//
		case gos_State_NormalizeNormals:
		{
			result=Value ? 1 : 0;
			#ifdef LAB_ONLY
			if( !InDebugger && gDisableNormalizing )
				result=0;
			#endif
			wSetRenderState( d3dDevice7, D3DRENDERSTATE_NORMALIZENORMALS, result );
			break;
		}
//
// Enable or disable D3D vertex blending
//
		case gos_State_VertexBlend:
		{
			result=Value ? 1 : 0;
			if( !HasVertexBlending )
				result=0;
			#ifdef LAB_ONLY
			if( !InDebugger && gDisableVertexBlending )
				result=0;
			#endif
			wSetRenderState( d3dDevice7, D3DRENDERSTATE_VERTEXBLEND, result );
			break;
		}
//
//
//
		default:
			STOP(( "Bad renderstate (0x%x)", RenderState ));
	}
//
// Store renderstate value back (it may have been changed back a fallback)
//
	RenderStates[RenderState]=Value;
	PreviousStates[RenderState]=Value;
}




















//
// 3D Device just inited - setup deault renderstates
//
void InitRenderStates()
{
	SPEW(( GROUP_GAMEOS, "InitRenderStates()" ));
//
// Antialias?
//
	if( Environment.AntiAlias && HasAntiAlias && HardwareRenderer )
		wSetRenderState( d3dDevice7, D3DRENDERSTATE_ANTIALIAS, D3DANTIALIAS_SORTINDEPENDENT );
	else
		wSetRenderState( d3dDevice7, D3DRENDERSTATE_ANTIALIAS, D3DANTIALIAS_NONE );
//
// Check to see if alpha stipple is required
//
	DWORD Stipple=0;
	if( 0==(CapsDirect3D.dpcTriCaps.dwShadeCaps & D3DPSHADECAPS_ALPHAGOURAUDBLEND) )
	{
		if( CapsDirect3D.dpcTriCaps.dwShadeCaps & D3DPSHADECAPS_ALPHAGOURAUDSTIPPLED )
		{
			Stipple=1;
		}
	}
	wSetRenderState( d3dDevice7, D3DRENDERSTATE_STIPPLEDALPHA, Stipple );
//
// If doing depth complexity setup stencil test
//
	if( StencilActive )
	{
		wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILENABLE, 1 );

		wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILREF, 1 );
		wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILMASK, 0xffffffff );
		wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILWRITEMASK, 0xffffffff );
		wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILFAIL, D3DSTENCILOP_INCR );
		wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILPASS, D3DSTENCILOP_INCR );
		wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILZFAIL, D3DSTENCILOP_INCR );
		wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILFUNC, D3DCMP_ALWAYS );
	}
	else
	{
		wSetRenderState( d3dDevice7, D3DRENDERSTATE_STENCILENABLE, 0 );
	}
//
// Disable color keying (from a G200 tech note)
//
	wSetRenderState( d3dDevice7, D3DRENDERSTATE_COLORKEYENABLE, 0 );
//
// Make sure rendering is as accurate as possible
//
	wSetRenderState( d3dDevice7, D3DRENDERSTATE_LASTPIXEL, 1 );
//
// Turn off fog by default
//
	wSetRenderState( d3dDevice7, D3DRENDERSTATE_FOGENABLE, 0 );
	wSetRenderState( d3dDevice7, D3DRENDERSTATE_FOGTABLEMODE, D3DFOG_NONE );
//
// Default alpha compare values
//
	wSetRenderState( d3dDevice7, D3DRENDERSTATE_ALPHAFUNC, D3DCMP_NOTEQUAL );
	wSetRenderState( d3dDevice7, D3DRENDERSTATE_ALPHAREF, 0 );
//
// Enable Z Buffering (not W buffering)
//
	if( Environment.disableZBuffer )
		wSetRenderState( d3dDevice7, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE );
	else
		wSetRenderState( d3dDevice7, D3DRENDERSTATE_ZENABLE, D3DZB_TRUE );
//
// Default alpha blend disabled
//
	AlphaBlendEnabled=0;
	wSetRenderState( d3dDevice7, D3DRENDERSTATE_ALPHABLENDENABLE, 0 );
//
// Always enable perspectiove correct by default
//
	wSetRenderState( d3dDevice7, D3DRENDERSTATE_TEXTUREPERSPECTIVE, 1 );
//
// Current MipFilter
//
	CurrentMipFilter=D3DTFP_NONE;
	wSetTextureStageState( d3dDevice7, 0, D3DTSS_MIPFILTER, D3DTFP_NONE );
//
// Force texture wrapping to be linear interpolate (normal)
//
	wSetRenderState( d3dDevice7, D3DRENDERSTATE_WRAP0, 0 );
	wSetRenderState( d3dDevice7, D3DRENDERSTATE_WRAP1, 0 );
//
// New DX7 renderstates
//
	wSetRenderState( d3dDevice7, D3DRENDERSTATE_EXTENTS, 0 );
	wSetRenderState( d3dDevice7, D3DRENDERSTATE_CLIPPING, 0 );
	wSetRenderState( d3dDevice7, D3DRENDERSTATE_LOCALVIEWER, 0 );
//
// Setup multitexture pipeline (MODULATEALPHA settings by default)
//
	wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
	wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
	wSetTextureStageState( d3dDevice7, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
	wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
	wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
	wSetTextureStageState( d3dDevice7, 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
	wSetTextureStageState( d3dDevice7, 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
	wSetTextureStageState( d3dDevice7, 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );

	wSetTextureStageState( d3dDevice7, 0, D3DTSS_TEXCOORDINDEX, 0 );
	wSetTextureStageState( d3dDevice7, 1, D3DTSS_TEXCOORDINDEX, 1 );
	wSetTextureStageState( d3dDevice7, 2, D3DTSS_TEXCOORDINDEX, 2 );

	wSetTextureStageState( d3dDevice7, 0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP );
	wSetTextureStageState( d3dDevice7, 1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP );
	wSetTextureStageState( d3dDevice7, 2, D3DTSS_ADDRESS, D3DTADDRESS_WRAP );
//
// Disable ALL unused stages
//
	wSetTextureStageState( d3dDevice7, 2, D3DTSS_COLOROP, D3DTOP_DISABLE );
	wSetTextureStageState( d3dDevice7, 2, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
	wSetTextureStageState( d3dDevice7, 3, D3DTSS_COLOROP, D3DTOP_DISABLE );
	wSetTextureStageState( d3dDevice7, 3, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
	wSetTextureStageState( d3dDevice7, 4, D3DTSS_COLOROP, D3DTOP_DISABLE );
	wSetTextureStageState( d3dDevice7, 4, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
	wSetTextureStageState( d3dDevice7, 5, D3DTSS_COLOROP, D3DTOP_DISABLE );
	wSetTextureStageState( d3dDevice7, 5, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
	wSetTextureStageState( d3dDevice7, 6, D3DTSS_COLOROP, D3DTOP_DISABLE );
	wSetTextureStageState( d3dDevice7, 6, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
	wSetTextureStageState( d3dDevice7, 7, D3DTSS_COLOROP, D3DTOP_DISABLE );
	wSetTextureStageState( d3dDevice7, 7, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
//
// Make sure all gos renderstates become set
//
	memset( UpdatedState, 1, sizeof(UpdatedState) );
	memset( PreviousStates,-1, sizeof(PreviousStates) );
	DirtyStates=1;
//
// Set all hardware states to unknown
//
	hwTextureMapBlend[0]=1;
	hwShadeMode[0]=1;
	hwPerspective[0]=1;
	hwAlphaTest[0]=1;
	hwZEnable[0]=1;
	hwTexture[0]=1;
	hwTexture1[0]=1;
	hwTexture2[0]=1;
	hwZCompare[0]=1;
	hwMonoEnable[0]=1;
	hwClipping[0]=1;
	AlphaOp=-1;
	ColorOp=-1;
	AlphaInvAlpha=0;
	CurrentMipFilter=D3DTFP_NONE;
//
// Debugging
//
	SPEW(( GROUP_GAMEOS, "InitRenderStates() - Finished" ));
}





