diff options
Diffstat (limited to 'materialsystem/shaderapidx9/shadershadowdx8.cpp')
| -rw-r--r-- | materialsystem/shaderapidx9/shadershadowdx8.cpp | 1826 |
1 files changed, 1826 insertions, 0 deletions
diff --git a/materialsystem/shaderapidx9/shadershadowdx8.cpp b/materialsystem/shaderapidx9/shadershadowdx8.cpp new file mode 100644 index 0000000..8c231c9 --- /dev/null +++ b/materialsystem/shaderapidx9/shadershadowdx8.cpp @@ -0,0 +1,1826 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#define DISABLE_PROTECTED_THINGS +#include "togl/rendermechanism.h" +#include "shadershadowdx8.h" +#include "locald3dtypes.h" +#include "utlvector.h" +#include "shaderapi/ishaderutil.h" +#include "shaderapidx8_global.h" +#include "shaderapidx8.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "materialsystem/imaterialsystem.h" +#include "imeshdx8.h" +#include "materialsystem/materialsystem_config.h" +#include "vertexshaderdx8.h" + +// NOTE: This must be the last file included! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// The DX8 implementation of the shader setup interface +//----------------------------------------------------------------------------- +class CShaderShadowDX8 : public IShaderShadowDX8 +{ +public: + // constructor, destructor + CShaderShadowDX8( ); + virtual ~CShaderShadowDX8(); + + // Initialize render state + void Init( ); + + // Sets the default state + void SetDefaultState(); + + // Methods related to depth buffering + void DepthFunc( ShaderDepthFunc_t depthFunc ); + void EnableDepthWrites( bool bEnable ); + void EnableDepthTest( bool bEnable ); + void EnablePolyOffset( PolygonOffsetMode_t nOffsetMode ); + + // Methods related to stencil. obsolete + virtual void EnableStencil( bool bEnable ) + { + } + virtual void StencilFunc( ShaderStencilFunc_t stencilFunc ) + { + } + virtual void StencilPassOp( ShaderStencilOp_t stencilOp ) + { + } + virtual void StencilFailOp( ShaderStencilOp_t stencilOp ) + { + } + virtual void StencilDepthFailOp( ShaderStencilOp_t stencilOp ) + { + } + virtual void StencilReference( int nReference ) + { + } + virtual void StencilMask( int nMask ) + { + } + virtual void StencilWriteMask( int nMask ) + { + } + + // Suppresses/activates color writing + void EnableColorWrites( bool bEnable ); + void EnableAlphaWrites( bool bEnable ); + + // Methods related to alpha blending + void EnableBlending( bool bEnable ); + + void BlendFunc( ShaderBlendFactor_t srcFactor, ShaderBlendFactor_t dstFactor ); + void BlendOp( ShaderBlendOp_t blendOp ); + void BlendOpSeparateAlpha( ShaderBlendOp_t blendOp ); + + // Alpha testing + void EnableAlphaTest( bool bEnable ); + void AlphaFunc( ShaderAlphaFunc_t alphaFunc, float alphaRef /* [0-1] */ ); + + // Wireframe/filled polygons + void PolyMode( ShaderPolyModeFace_t face, ShaderPolyMode_t polyMode ); + + // Back face culling + void EnableCulling( bool bEnable ); + + // constant color + void EnableConstantColor( bool bEnable ); + + // Indicates we're going to light the model + void EnableLighting( bool bEnable ); + + // Indicates specular lighting is going to be used + void EnableSpecular( bool bEnable ); + + // Convert from linear to gamma color space on writes to frame buffer. + void EnableSRGBWrite( bool bEnable ); + + // Convert from gamma to linear on texture fetch. + void EnableSRGBRead( Sampler_t stage, bool bEnable ); + + // Set up appropriate shadow filtering state (such as Fetch4 on ATI) + void SetShadowDepthFiltering( Sampler_t stage ); + + // Computes the vertex format + virtual void VertexShaderVertexFormat( unsigned int nFlags, + int nTexCoordCount, int* pTexCoordDimensions, int nUserDataSize ); + + // Pixel and vertex shader methods + virtual void SetVertexShader( const char* pFileName, int nStaticVshIndex ); + virtual void SetPixelShader( const char* pFileName, int nStaticPshIndex ); + + // Indicates we're going to be using the ambient cube + void EnableAmbientLightCubeOnStage0( bool bEnable ); + + // Activate/deactivate skinning + void EnableVertexBlend( bool bEnable ); + + // per texture unit stuff + void OverbrightValue( TextureStage_t stage, float value ); + void EnableTexture( Sampler_t stage, bool bEnable ); + void EnableTexGen( TextureStage_t stage, bool bEnable ); + void TexGen( TextureStage_t stage, ShaderTexGenParam_t param ); + void TextureCoordinate( TextureStage_t stage, int useCoord ); + + // alternate method of specifying per-texture unit stuff, more flexible and more complicated + // Can be used to specify different operation per channel (alpha/color)... + void EnableCustomPixelPipe( bool bEnable ); + void CustomTextureStages( int stageCount ); + void CustomTextureOperation( TextureStage_t stage, ShaderTexChannel_t channel, + ShaderTexOp_t op, ShaderTexArg_t arg1, ShaderTexArg_t arg2 ); + + // A simpler method of dealing with alpha modulation + void EnableAlphaPipe( bool bEnable ); + void EnableConstantAlpha( bool bEnable ); + void EnableVertexAlpha( bool bEnable ); + void EnableTextureAlpha( TextureStage_t stage, bool bEnable ); + + // helper functions + void EnableSphereMapping( TextureStage_t stage, bool bEnable ); + + // Last call to be make before snapshotting + void ComputeAggregateShadowState( ); + + // Gets at the shadow state + const ShadowState_t & GetShadowState(); + const ShadowShaderState_t & GetShadowShaderState(); + + // GR - Separate alpha blending + void EnableBlendingSeparateAlpha( bool bEnable ); + void BlendFuncSeparateAlpha( ShaderBlendFactor_t srcFactor, ShaderBlendFactor_t dstFactor ); + + void FogMode( ShaderFogMode_t fogMode ); + void DisableFogGammaCorrection( bool bDisable ); + + void SetDiffuseMaterialSource( ShaderMaterialSource_t materialSource ); + virtual void SetMorphFormat( MorphFormat_t flags ); + + // Alpha to coverage + void EnableAlphaToCoverage( bool bEnable ); + +private: + struct TextureStageState_t + { + int m_TexCoordIndex; + int m_TexCoordinate; + float m_OverbrightVal; + ShaderTexArg_t m_Arg[2][2]; + ShaderTexOp_t m_Op[2]; + unsigned char m_TexGenEnable:1; + unsigned char m_TextureAlphaEnable:1; + }; + + struct SamplerState_t + { + bool m_TextureEnable : 1; + }; + + // Computes the blend factor + D3DBLEND BlendFuncValue( ShaderBlendFactor_t factor ) const; + + // Computes the blend op + D3DBLENDOP BlendOpValue( ShaderBlendOp_t blendOp ) const; + + // Configures the FVF vertex shader + void ConfigureFVFVertexShader( unsigned int flags ); + void ConfigureCustomFVFVertexShader( unsigned int flags ); + + // Configures our texture indices + void ConfigureTextureCoordinates( unsigned int flags ); + + // Returns a blend value based on overbrighting + D3DTEXTUREOP OverbrightBlendValue( TextureStage_t stage ); + + // Sets the desired color and alpha op state + void DrawFlags( unsigned int flags ); + + // Computes a vertex format for the draw flags + VertexFormat_t FlagsToVertexFormat( int flags ) const; + + // Indicates we've got a constant color specified + bool HasConstantColor() const; + + // Configures the alpha pipe + void ConfigureAlphaPipe( unsigned int flags ); + + // returns true if we're using texture coordinates at a given stage + bool IsUsingTextureCoordinates( Sampler_t stage ) const; + + // Recomputes the tex coord index + void RecomputeTexCoordIndex( TextureStage_t stage ); + + + // State needed to create the snapshots + IMaterialSystemHardwareConfig* m_pHardwareConfig; + + // Separate alpha control? + bool m_AlphaPipe; + + // Constant color state + bool m_HasConstantColor; + bool m_HasConstantAlpha; + + // Vertex color state + bool m_HasVertexAlpha; + + // funky custom method of specifying shader state + bool m_CustomTextureStageState; + + // Number of stages used by the custom pipeline + int m_CustomTextureStages; + + // Number of bones... + int m_NumBlendVertices; + + // Draw flags + int m_DrawFlags; + + // Alpha blending... + D3DBLEND m_SrcBlend; + D3DBLEND m_DestBlend; + D3DBLENDOP m_BlendOp; + + // GR - Separate alpha blending... + D3DBLEND m_SrcBlendAlpha; + D3DBLEND m_DestBlendAlpha; + D3DBLENDOP m_BlendOpAlpha; + + // Alpha testing + D3DCMPFUNC m_AlphaFunc; + int m_AlphaRef; + + // Stencil + D3DCMPFUNC m_StencilFunc; + int m_StencilRef; + int m_StencilMask; + DWORD m_StencilFail; + DWORD m_StencilZFail; + DWORD m_StencilPass; + int m_StencilWriteMask; + + // The current shadow state + ShadowState_t m_ShadowState; + ShadowShaderState_t m_ShadowShaderState; + + // State info stores with each texture stage + TextureStageState_t m_TextureStage[MAX_TEXTURE_STAGES]; + SamplerState_t m_SamplerState[MAX_SAMPLERS]; +}; + + +//----------------------------------------------------------------------------- +// Class factory +//----------------------------------------------------------------------------- +static CShaderShadowDX8 g_ShaderShadow; +IShaderShadowDX8 *g_pShaderShadowDx8 = &g_ShaderShadow; + +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderShadowDX8, IShaderShadow, + SHADERSHADOW_INTERFACE_VERSION, g_ShaderShadow ) + +//----------------------------------------------------------------------------- +// Global instance +//----------------------------------------------------------------------------- +IShaderShadowDX8* ShaderShadow() +{ + return &g_ShaderShadow; +} + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +CShaderShadowDX8::CShaderShadowDX8( ) : + m_DrawFlags(0), m_pHardwareConfig(0), m_HasConstantColor(false) +{ + memset( &m_ShadowState, 0, sizeof(m_ShadowState) ); + memset( &m_TextureStage, 0, sizeof(m_TextureStage) ); +} + +CShaderShadowDX8::~CShaderShadowDX8() +{ +} + + +//----------------------------------------------------------------------------- +// Initialize render state +//----------------------------------------------------------------------------- +void CShaderShadowDX8::Init( ) +{ + m_pHardwareConfig = HardwareConfig(); + + // Clear out the shadow state + memset( &m_ShadowState, 0, sizeof(m_ShadowState) ); + + // No funky custom methods.. + m_CustomTextureStageState = false; + + // No constant color modulation + m_HasConstantColor = false; + m_HasConstantAlpha = false; + m_HasVertexAlpha = false; + + m_ShadowShaderState.m_ModulateConstantColor = false; + + m_ShadowState.m_bDisableFogGammaCorrection = false; + + // By default we're using fixed function + m_ShadowState.m_UsingFixedFunction = true; + + // Lighting off by default + m_ShadowState.m_Lighting = false; + + // Pixel + vertex shaders + m_ShadowShaderState.m_VertexShader = INVALID_SHADER; + m_ShadowShaderState.m_PixelShader = INVALID_SHADER; + m_ShadowShaderState.m_nStaticPshIndex = 0; + m_ShadowShaderState.m_nStaticVshIndex = 0; + m_ShadowShaderState.m_VertexUsage = 0; + + // Drawing nothing.. + m_DrawFlags = 0; + + // No alpha control + m_AlphaPipe = false; + + // Vertex blending + m_NumBlendVertices = 0; + m_ShadowState.m_VertexBlendEnable = false; + + // NOTE: If you change these defaults, change the code in ComputeAggregateShadowState + CreateTransitionTableEntry + int i; + for (i = 0; i < MAX_TEXTURE_STAGES; ++i) + { + m_ShadowState.m_TextureStage[i].m_ColorOp = D3DTOP_DISABLE; + m_ShadowState.m_TextureStage[i].m_ColorArg1 = D3DTA_TEXTURE; + m_ShadowState.m_TextureStage[i].m_ColorArg2 = (i == 0) ? D3DTA_DIFFUSE : D3DTA_CURRENT; + m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_DISABLE; + m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TEXTURE; + m_ShadowState.m_TextureStage[i].m_AlphaArg2 = (i == 0) ? D3DTA_DIFFUSE : D3DTA_CURRENT; + m_ShadowState.m_TextureStage[i].m_TexCoordIndex = i; + } + + for (i = 0; i < MAX_SAMPLERS; ++i) + { + m_ShadowState.m_SamplerState[i].m_TextureEnable = false; + m_ShadowState.m_SamplerState[i].m_SRGBReadEnable = false; + m_ShadowState.m_SamplerState[i].m_Fetch4Enable = false; +#ifdef DX_TO_GL_ABSTRACTION + m_ShadowState.m_SamplerState[i].m_ShadowFilterEnable = false; +#endif + // A *real* measure if the texture stage is being used. + // we sometimes have to set the shadow state to not mirror this. + m_SamplerState[i].m_TextureEnable = false; + } +} + + +//----------------------------------------------------------------------------- +// Sets the default state +//----------------------------------------------------------------------------- +void CShaderShadowDX8::SetDefaultState() +{ + DepthFunc( SHADER_DEPTHFUNC_NEAREROREQUAL ); + EnableDepthWrites( true ); + EnableDepthTest( true ); + EnableColorWrites( true ); + EnableAlphaWrites( false ); + EnableAlphaTest( false ); + EnableLighting( false ); + EnableConstantColor( false ); + EnableBlending( false ); + BlendFunc( SHADER_BLEND_ONE, SHADER_BLEND_ZERO ); + BlendOp( SHADER_BLEND_OP_ADD ); + // GR - separate alpha + EnableBlendingSeparateAlpha( false ); + BlendFuncSeparateAlpha( SHADER_BLEND_ONE, SHADER_BLEND_ZERO ); + BlendOpSeparateAlpha( SHADER_BLEND_OP_ADD ); + AlphaFunc( SHADER_ALPHAFUNC_GEQUAL, 0.7f ); + PolyMode( SHADER_POLYMODEFACE_FRONT_AND_BACK, SHADER_POLYMODE_FILL ); + EnableCulling( true ); + EnableAlphaToCoverage( false ); + EnablePolyOffset( SHADER_POLYOFFSET_DISABLE ); + EnableVertexBlend( false ); + EnableSpecular( false ); + EnableSRGBWrite( false ); + DrawFlags( SHADER_DRAW_POSITION ); + EnableCustomPixelPipe( false ); + CustomTextureStages( 0 ); + EnableAlphaPipe( false ); + EnableConstantAlpha( false ); + EnableVertexAlpha( false ); + SetVertexShader( NULL, 0 ); + SetPixelShader( NULL, 0 ); + FogMode( SHADER_FOGMODE_DISABLED ); + DisableFogGammaCorrection( false ); + SetDiffuseMaterialSource( SHADER_MATERIALSOURCE_MATERIAL ); + EnableStencil( false ); + StencilFunc( SHADER_STENCILFUNC_ALWAYS ); + StencilPassOp( SHADER_STENCILOP_KEEP ); + StencilFailOp( SHADER_STENCILOP_KEEP ); + StencilDepthFailOp( SHADER_STENCILOP_KEEP ); + StencilReference( 0 ); + StencilMask( 0xFFFFFFFF ); + StencilWriteMask( 0xFFFFFFFF ); + m_ShadowShaderState.m_VertexUsage = 0; + + int i; + int nSamplerCount = HardwareConfig()->GetSamplerCount(); + for( i = 0; i < nSamplerCount; i++ ) + { + EnableTexture( (Sampler_t)i, false ); + EnableSRGBRead( (Sampler_t)i, false ); + } + + int nTextureStageCount = HardwareConfig()->GetTextureStageCount(); + for( i = 0; i < nTextureStageCount; i++ ) + { + EnableTexGen( (TextureStage_t)i, false ); + OverbrightValue( (TextureStage_t)i, 1.0f ); + EnableTextureAlpha( (TextureStage_t)i, false ); + CustomTextureOperation( (TextureStage_t)i, SHADER_TEXCHANNEL_COLOR, + SHADER_TEXOP_DISABLE, SHADER_TEXARG_TEXTURE, SHADER_TEXARG_PREVIOUSSTAGE ); + CustomTextureOperation( (TextureStage_t)i, SHADER_TEXCHANNEL_ALPHA, + SHADER_TEXOP_DISABLE, SHADER_TEXARG_TEXTURE, SHADER_TEXARG_PREVIOUSSTAGE ); + } +} + + +//----------------------------------------------------------------------------- +// Gets at the shadow state +//----------------------------------------------------------------------------- +const ShadowState_t &CShaderShadowDX8::GetShadowState() +{ + return m_ShadowState; +} + +const ShadowShaderState_t &CShaderShadowDX8::GetShadowShaderState() +{ + return m_ShadowShaderState; +} + + +//----------------------------------------------------------------------------- +// Depth functions... +//----------------------------------------------------------------------------- +void CShaderShadowDX8::DepthFunc( ShaderDepthFunc_t depthFunc ) +{ + D3DCMPFUNC zFunc; + + switch( depthFunc ) + { + case SHADER_DEPTHFUNC_NEVER: + zFunc = D3DCMP_NEVER; + break; + case SHADER_DEPTHFUNC_NEARER: + zFunc = (ShaderUtil()->GetConfig().bReverseDepth ^ ReverseDepthOnX360()) ? D3DCMP_GREATER : D3DCMP_LESS; + break; + case SHADER_DEPTHFUNC_EQUAL: + zFunc = D3DCMP_EQUAL; + break; + case SHADER_DEPTHFUNC_NEAREROREQUAL: + zFunc = (ShaderUtil()->GetConfig().bReverseDepth ^ ReverseDepthOnX360()) ? D3DCMP_GREATEREQUAL : D3DCMP_LESSEQUAL; + break; + case SHADER_DEPTHFUNC_FARTHER: + zFunc = (ShaderUtil()->GetConfig().bReverseDepth ^ ReverseDepthOnX360()) ? D3DCMP_LESS : D3DCMP_GREATER; + break; + case SHADER_DEPTHFUNC_NOTEQUAL: + zFunc = D3DCMP_NOTEQUAL; + break; + case SHADER_DEPTHFUNC_FARTHEROREQUAL: + zFunc = (ShaderUtil()->GetConfig().bReverseDepth ^ ReverseDepthOnX360()) ? D3DCMP_LESSEQUAL : D3DCMP_GREATEREQUAL; + break; + case SHADER_DEPTHFUNC_ALWAYS: + zFunc = D3DCMP_ALWAYS; + break; + default: + zFunc = D3DCMP_ALWAYS; + Warning( "DepthFunc: invalid param\n" ); + break; + } + + m_ShadowState.m_ZFunc = zFunc; +} + +void CShaderShadowDX8::EnableDepthWrites( bool bEnable ) +{ + m_ShadowState.m_ZWriteEnable = bEnable; +} + +void CShaderShadowDX8::EnableDepthTest( bool bEnable ) +{ + m_ShadowState.m_ZEnable = bEnable ? D3DZB_TRUE : D3DZB_FALSE; +} + +void CShaderShadowDX8::EnablePolyOffset( PolygonOffsetMode_t nOffsetMode ) +{ + m_ShadowState.m_ZBias = nOffsetMode; +} + +//----------------------------------------------------------------------------- +// Color write state +//----------------------------------------------------------------------------- +void CShaderShadowDX8::EnableColorWrites( bool bEnable ) +{ + if (bEnable) + { + m_ShadowState.m_ColorWriteEnable |= D3DCOLORWRITEENABLE_BLUE | + D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED; + } + else + { + m_ShadowState.m_ColorWriteEnable &= ~( D3DCOLORWRITEENABLE_BLUE | + D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED ); + } +} + +void CShaderShadowDX8::EnableAlphaWrites( bool bEnable ) +{ + if (bEnable) + { + m_ShadowState.m_ColorWriteEnable |= D3DCOLORWRITEENABLE_ALPHA; + } + else + { + m_ShadowState.m_ColorWriteEnable &= ~D3DCOLORWRITEENABLE_ALPHA; + } +} + + +//----------------------------------------------------------------------------- +// Alpha blending states +//----------------------------------------------------------------------------- +void CShaderShadowDX8::EnableBlending( bool bEnable ) +{ + m_ShadowState.m_AlphaBlendEnable = bEnable; +} + +// GR - separate alpha +void CShaderShadowDX8::EnableBlendingSeparateAlpha( bool bEnable ) +{ + m_ShadowState.m_SeparateAlphaBlendEnable = bEnable; +} + +void CShaderShadowDX8::EnableAlphaTest( bool bEnable ) +{ + m_ShadowState.m_AlphaTestEnable = bEnable; +} + +void CShaderShadowDX8::AlphaFunc( ShaderAlphaFunc_t alphaFunc, float alphaRef /* [0-1] */ ) +{ + D3DCMPFUNC d3dCmpFunc; + + switch( alphaFunc ) + { + case SHADER_ALPHAFUNC_NEVER: + d3dCmpFunc = D3DCMP_NEVER; + break; + case SHADER_ALPHAFUNC_LESS: + d3dCmpFunc = D3DCMP_LESS; + break; + case SHADER_ALPHAFUNC_EQUAL: + d3dCmpFunc = D3DCMP_EQUAL; + break; + case SHADER_ALPHAFUNC_LEQUAL: + d3dCmpFunc = D3DCMP_LESSEQUAL; + break; + case SHADER_ALPHAFUNC_GREATER: + d3dCmpFunc = D3DCMP_GREATER; + break; + case SHADER_ALPHAFUNC_NOTEQUAL: + d3dCmpFunc = D3DCMP_NOTEQUAL; + break; + case SHADER_ALPHAFUNC_GEQUAL: + d3dCmpFunc = D3DCMP_GREATEREQUAL; + break; + case SHADER_ALPHAFUNC_ALWAYS: + d3dCmpFunc = D3DCMP_ALWAYS; + break; + default: + Warning( "AlphaFunc: invalid param\n" ); + return; + } + + m_AlphaFunc = d3dCmpFunc; + m_AlphaRef = (int)(alphaRef * 255); +} + +D3DBLEND CShaderShadowDX8::BlendFuncValue( ShaderBlendFactor_t factor ) const +{ + switch( factor ) + { + case SHADER_BLEND_ZERO: + return D3DBLEND_ZERO; + + case SHADER_BLEND_ONE: + return D3DBLEND_ONE; + + case SHADER_BLEND_DST_COLOR: + return D3DBLEND_DESTCOLOR; + + case SHADER_BLEND_ONE_MINUS_DST_COLOR: + return D3DBLEND_INVDESTCOLOR; + + case SHADER_BLEND_SRC_ALPHA: + return D3DBLEND_SRCALPHA; + + case SHADER_BLEND_ONE_MINUS_SRC_ALPHA: + return D3DBLEND_INVSRCALPHA; + + case SHADER_BLEND_DST_ALPHA: + return D3DBLEND_DESTALPHA; + + case SHADER_BLEND_ONE_MINUS_DST_ALPHA: + return D3DBLEND_INVDESTALPHA; + + case SHADER_BLEND_SRC_ALPHA_SATURATE: + return D3DBLEND_SRCALPHASAT; + + case SHADER_BLEND_SRC_COLOR: + return D3DBLEND_SRCCOLOR; + + case SHADER_BLEND_ONE_MINUS_SRC_COLOR: + return D3DBLEND_INVSRCCOLOR; + } + + Warning( "BlendFunc: invalid factor\n" ); + return D3DBLEND_ONE; +} + +D3DBLENDOP CShaderShadowDX8::BlendOpValue( ShaderBlendOp_t blendOp ) const +{ + switch( blendOp ) + { + case SHADER_BLEND_OP_ADD: + return D3DBLENDOP_ADD; + + case SHADER_BLEND_OP_SUBTRACT: + return D3DBLENDOP_SUBTRACT; + + case SHADER_BLEND_OP_REVSUBTRACT: + return D3DBLENDOP_REVSUBTRACT; + + case SHADER_BLEND_OP_MIN: + return D3DBLENDOP_MIN; + + case SHADER_BLEND_OP_MAX: + return D3DBLENDOP_MAX; + } + + Warning( "BlendOp: invalid op\n" ); + return D3DBLENDOP_ADD; +} + +void CShaderShadowDX8::BlendFunc( ShaderBlendFactor_t srcFactor, ShaderBlendFactor_t dstFactor ) +{ + D3DBLEND d3dSrcFactor = BlendFuncValue( srcFactor ); + D3DBLEND d3dDstFactor = BlendFuncValue( dstFactor ); + m_SrcBlend = d3dSrcFactor; + m_DestBlend = d3dDstFactor; +} + +// GR - separate alpha blend +void CShaderShadowDX8::BlendFuncSeparateAlpha( ShaderBlendFactor_t srcFactor, ShaderBlendFactor_t dstFactor ) +{ + D3DBLEND d3dSrcFactor = BlendFuncValue( srcFactor ); + D3DBLEND d3dDstFactor = BlendFuncValue( dstFactor ); + m_SrcBlendAlpha = d3dSrcFactor; + m_DestBlendAlpha = d3dDstFactor; +} + +void CShaderShadowDX8::BlendOp( ShaderBlendOp_t blendOp ) +{ + m_BlendOp = BlendOpValue( blendOp ); +} + +void CShaderShadowDX8::BlendOpSeparateAlpha( ShaderBlendOp_t blendOp ) +{ + m_BlendOpAlpha = BlendOpValue( blendOp ); +} + +//----------------------------------------------------------------------------- +// Polygon fill mode states +//----------------------------------------------------------------------------- +void CShaderShadowDX8::PolyMode( ShaderPolyModeFace_t face, ShaderPolyMode_t polyMode ) +{ + // DX8 can't handle different modes on front and back faces +// FIXME: Assert( face == SHADER_POLYMODEFACE_FRONT_AND_BACK ); + if (face == SHADER_POLYMODEFACE_BACK) + return; + + D3DFILLMODE fillMode; + switch( polyMode ) + { + case SHADER_POLYMODE_POINT: + fillMode = D3DFILL_POINT; + break; + case SHADER_POLYMODE_LINE: + fillMode = D3DFILL_WIREFRAME; + break; + case SHADER_POLYMODE_FILL: + fillMode = D3DFILL_SOLID; + break; + default: + Warning( "PolyMode: invalid poly mode\n" ); + return; + } + + m_ShadowState.m_FillMode = fillMode; +} + + +//----------------------------------------------------------------------------- +// Backface cull states +//----------------------------------------------------------------------------- +void CShaderShadowDX8::EnableCulling( bool bEnable ) +{ + m_ShadowState.m_CullEnable = bEnable; +} + + +//----------------------------------------------------------------------------- +// Alpha to coverage +//----------------------------------------------------------------------------- +void CShaderShadowDX8::EnableAlphaToCoverage( bool bEnable ) +{ + m_ShadowState.m_EnableAlphaToCoverage = bEnable; +} + + +//----------------------------------------------------------------------------- +// Indicates we've got a constant color specified +//----------------------------------------------------------------------------- +bool CShaderShadowDX8::HasConstantColor() const +{ + return m_HasConstantColor; +} + +void CShaderShadowDX8::EnableConstantColor( bool bEnable ) +{ + m_HasConstantColor = bEnable; +} + + +//----------------------------------------------------------------------------- +// A simpler method of dealing with alpha modulation +//----------------------------------------------------------------------------- +void CShaderShadowDX8::EnableAlphaPipe( bool bEnable ) +{ + m_AlphaPipe = bEnable; +} + +void CShaderShadowDX8::EnableConstantAlpha( bool bEnable ) +{ + m_HasConstantAlpha = bEnable; +} + +void CShaderShadowDX8::EnableVertexAlpha( bool bEnable ) +{ + m_HasVertexAlpha = bEnable; +} + +void CShaderShadowDX8::EnableTextureAlpha( TextureStage_t stage, bool bEnable ) +{ + if ( stage < m_pHardwareConfig->GetSamplerCount() ) + { + m_TextureStage[stage].m_TextureAlphaEnable = bEnable; + } +} + + +//----------------------------------------------------------------------------- +// Indicates we're going to light the model +//----------------------------------------------------------------------------- +void CShaderShadowDX8::EnableLighting( bool bEnable ) +{ + m_ShadowState.m_Lighting = bEnable; +} + + +//----------------------------------------------------------------------------- +// Enables specular lighting (lighting has also got to be enabled) +//----------------------------------------------------------------------------- +void CShaderShadowDX8::EnableSpecular( bool bEnable ) +{ + m_ShadowState.m_SpecularEnable = bEnable; +} + +//----------------------------------------------------------------------------- +// Enables auto-conversion from linear to gamma space on write to framebuffer. +//----------------------------------------------------------------------------- +void CShaderShadowDX8::EnableSRGBWrite( bool bEnable ) +{ + if ( m_pHardwareConfig->SupportsSRGB() ) + { + m_ShadowState.m_SRGBWriteEnable = bEnable; + } + else + { + m_ShadowState.m_SRGBWriteEnable = false; + } +} + +//----------------------------------------------------------------------------- +// Activate/deactivate skinning +//----------------------------------------------------------------------------- +void CShaderShadowDX8::EnableVertexBlend( bool bEnable ) +{ + // Activate/deactivate skinning. Indexed blending is automatically + // enabled if it's available for this hardware. When blending is enabled, + // we allocate enough room for 3 weights (max allowed) + if ((m_pHardwareConfig->MaxBlendMatrices() > 0) || (!bEnable)) + { + m_ShadowState.m_VertexBlendEnable = bEnable; + } +} + + +//----------------------------------------------------------------------------- +// Texturemapping state +//----------------------------------------------------------------------------- +void CShaderShadowDX8::EnableTexture( Sampler_t sampler, bool bEnable ) +{ + if ( sampler < m_pHardwareConfig->GetSamplerCount() ) + { + m_SamplerState[sampler].m_TextureEnable = bEnable; + } + else + { + Warning( "Attempting to bind a texture to an invalid sampler (%d)!\n", sampler ); + } +} + +void CShaderShadowDX8::EnableSRGBRead( Sampler_t sampler, bool bEnable ) +{ + if ( !m_pHardwareConfig->SupportsSRGB() ) + { + m_ShadowState.m_SamplerState[sampler].m_SRGBReadEnable = false; + return; + } + + if ( sampler < m_pHardwareConfig->GetSamplerCount() ) + { + m_ShadowState.m_SamplerState[sampler].m_SRGBReadEnable = bEnable; + } + else + { + Warning( "Attempting set SRGBRead state on an invalid sampler (%d)!\n", sampler ); + } +} + +void CShaderShadowDX8::SetShadowDepthFiltering( Sampler_t stage ) +{ +#ifdef DX_TO_GL_ABSTRACTION + if ( stage < m_pHardwareConfig->GetSamplerCount() ) + { + m_ShadowState.m_SamplerState[stage].m_ShadowFilterEnable = true; + return; + } +#else + if ( !m_pHardwareConfig->SupportsFetch4() ) + { + m_ShadowState.m_SamplerState[stage].m_Fetch4Enable = false; + return; + } + + if ( stage < m_pHardwareConfig->GetSamplerCount() ) + { + m_ShadowState.m_SamplerState[stage].m_Fetch4Enable = true; + return; + } +#endif + + Warning( "Attempting set shadow filtering state on an invalid sampler (%d)!\n", stage ); +} + + +//----------------------------------------------------------------------------- +// Binds texture coordinates to a particular stage... +//----------------------------------------------------------------------------- +void CShaderShadowDX8::TextureCoordinate( TextureStage_t stage, int useTexCoord ) +{ + if ( stage < m_pHardwareConfig->GetTextureStageCount() ) + { + m_TextureStage[stage].m_TexCoordinate = useTexCoord; + + // Need to recompute the texCoordIndex, since that's affected by this + RecomputeTexCoordIndex(stage); + } +} + + +//----------------------------------------------------------------------------- +// Automatic texture coordinate generation +//----------------------------------------------------------------------------- +void CShaderShadowDX8::RecomputeTexCoordIndex( TextureStage_t stage ) +{ + int texCoordIndex = m_TextureStage[stage].m_TexCoordinate; + if (m_TextureStage[stage].m_TexGenEnable) + texCoordIndex |= m_TextureStage[stage].m_TexCoordIndex; + m_ShadowState.m_TextureStage[stage].m_TexCoordIndex = texCoordIndex; +} + + +//----------------------------------------------------------------------------- +// Automatic texture coordinate generation +//----------------------------------------------------------------------------- +void CShaderShadowDX8::EnableTexGen( TextureStage_t stage, bool bEnable ) +{ + if ( stage >= m_pHardwareConfig->GetTextureStageCount() ) + { + Assert( 0 ); + return; + } + + m_TextureStage[stage].m_TexGenEnable = bEnable; + RecomputeTexCoordIndex(stage); +} + +//----------------------------------------------------------------------------- +// Automatic texture coordinate generation +//----------------------------------------------------------------------------- +void CShaderShadowDX8::TexGen( TextureStage_t stage, ShaderTexGenParam_t param ) +{ +#ifdef FIXED_FUNCTION_PIPELINE + if ( stage >= m_pHardwareConfig->GetTextureStageCount() ) + return; + + switch( param ) + { + case SHADER_TEXGENPARAM_OBJECT_LINEAR: + m_TextureStage[stage].m_TexCoordIndex = 0; + break; + case SHADER_TEXGENPARAM_EYE_LINEAR: + m_TextureStage[stage].m_TexCoordIndex = D3DTSS_TCI_CAMERASPACEPOSITION; + break; + case SHADER_TEXGENPARAM_SPHERE_MAP: + if ( m_pHardwareConfig->SupportsSpheremapping() ) + { + m_TextureStage[stage].m_TexCoordIndex = D3DTSS_TCI_SPHEREMAP; + } + else + { + m_TextureStage[stage].m_TexCoordIndex = D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR; + } + break; + case SHADER_TEXGENPARAM_CAMERASPACEREFLECTIONVECTOR: + m_TextureStage[stage].m_TexCoordIndex = D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR; + break; + case SHADER_TEXGENPARAM_CAMERASPACENORMAL: + m_TextureStage[stage].m_TexCoordIndex = D3DTSS_TCI_CAMERASPACENORMAL; + break; + } + + // Set the board state... + RecomputeTexCoordIndex(stage); +#endif +} + + +//----------------------------------------------------------------------------- +// Overbrighting +//----------------------------------------------------------------------------- +void CShaderShadowDX8::OverbrightValue( TextureStage_t stage, float value ) +{ + if ( m_pHardwareConfig->SupportsOverbright() && + ( stage < m_pHardwareConfig->GetTextureStageCount() ) ) + { + m_TextureStage[stage].m_OverbrightVal = value; + } +} + + + + +//----------------------------------------------------------------------------- +// alternate method of specifying per-texture unit stuff, more flexible and more complicated +// Can be used to specify different operation per channel (alpha/color)... +//----------------------------------------------------------------------------- +void CShaderShadowDX8::EnableCustomPixelPipe( bool bEnable ) +{ + m_CustomTextureStageState = bEnable; +} + +void CShaderShadowDX8::CustomTextureStages( int stageCount ) +{ + m_CustomTextureStages = stageCount; + Assert( stageCount <= m_pHardwareConfig->GetTextureStageCount() ); + if ( stageCount > m_pHardwareConfig->GetTextureStageCount() ) + stageCount = m_pHardwareConfig->GetTextureStageCount(); +} + +void CShaderShadowDX8::CustomTextureOperation( TextureStage_t stage, + ShaderTexChannel_t channel, ShaderTexOp_t op, ShaderTexArg_t arg1, ShaderTexArg_t arg2 ) +{ + m_TextureStage[stage].m_Op[channel]= op; + m_TextureStage[stage].m_Arg[channel][0] = arg1; + m_TextureStage[stage].m_Arg[channel][1] = arg2; +} + + +//----------------------------------------------------------------------------- +// Compute the vertex format from vertex descriptor flags +//----------------------------------------------------------------------------- +void CShaderShadowDX8::VertexShaderVertexFormat( unsigned int nFlags, + int nTexCoordCount, int* pTexCoordDimensions, int nUserDataSize ) +{ + // Code that creates a Mesh should specify whether it contains bone weights+indices, *not* the shader. + Assert( ( nFlags & VERTEX_BONE_INDEX ) == 0 ); + nFlags &= ~VERTEX_BONE_INDEX; + + // This indicates we're using a vertex shader + nFlags |= VERTEX_FORMAT_VERTEX_SHADER; + m_ShadowShaderState.m_VertexUsage = MeshMgr()->ComputeVertexFormat( nFlags, nTexCoordCount, + pTexCoordDimensions, 0, nUserDataSize ); + m_ShadowState.m_UsingFixedFunction = false; + + // Avoid an error if vertex stream 0 is too narrow + if ( CVertexBufferBase::VertexFormatSize( m_ShadowShaderState.m_VertexUsage ) <= 16 ) + { + // FIXME: this is only necessary because we + // (a) put the flex normal/position stream in ALL vertex decls + // (b) bind stream 0's VB to stream 2 if there is no actual flex data + // ...it would be far more sensible to not add stream 2 to all vertex decls. + static bool bComplained = false; + if( !bComplained ) + { + Warning( "ERROR: shader asking for a too-narrow vertex format - you will see errors if running with debug D3D DLLs!\n\tPadding the vertex format with extra texcoords\n\tWill not warn again.\n" ); + bComplained = true; + } + // All vertex formats should contain position... + Assert( nFlags & VERTEX_POSITION ); + nFlags |= VERTEX_POSITION; + // This error should occur only if we have zero texcoords, or if we have a single, 1-D texcoord + Assert( ( nTexCoordCount == 0 ) || + ( ( nTexCoordCount == 1 ) && pTexCoordDimensions && ( pTexCoordDimensions[0] == 1 ) ) ); + nTexCoordCount = 1; + m_ShadowShaderState.m_VertexUsage = MeshMgr()->ComputeVertexFormat( nFlags, nTexCoordCount, NULL, 0, nUserDataSize ); + } +} + + +//----------------------------------------------------------------------------- +// Compute the vertex format from vertex descriptor flags +//----------------------------------------------------------------------------- +void CShaderShadowDX8::SetMorphFormat( MorphFormat_t flags ) +{ + m_ShadowShaderState.m_MorphUsage = flags; +} + +//----------------------------------------------------------------------------- +// Pixel and vertex shader methods +//----------------------------------------------------------------------------- +void CShaderShadowDX8::SetVertexShader( const char* pFileName, int nStaticVshIndex ) +{ + char debugLabel[500] = ""; +#ifdef DX_TO_GL_ABSTRACTION + Q_snprintf( debugLabel, sizeof(debugLabel), "vs-file %s vs-index %d", pFileName, nStaticVshIndex ); +#endif + + m_ShadowShaderState.m_VertexShader = ShaderManager()->CreateVertexShader( pFileName, nStaticVshIndex, debugLabel ); + m_ShadowShaderState.m_nStaticVshIndex = nStaticVshIndex; +} + +void CShaderShadowDX8::SetPixelShader( const char* pFileName, int nStaticPshIndex ) +{ + char debugLabel[500] = ""; +#ifdef DX_TO_GL_ABSTRACTION + Q_snprintf( debugLabel, sizeof(debugLabel), "ps-file %s ps-index %d", pFileName, nStaticPshIndex ); +#endif + + m_ShadowShaderState.m_PixelShader = ShaderManager()->CreatePixelShader( pFileName, nStaticPshIndex, debugLabel ); + m_ShadowShaderState.m_nStaticPshIndex = nStaticPshIndex; +} + + +//----------------------------------------------------------------------------- +// NOTE: See Version 5 of this file for NVidia 8-stage shader stuff +//----------------------------------------------------------------------------- +inline bool CShaderShadowDX8::IsUsingTextureCoordinates( Sampler_t sampler ) const +{ + return m_SamplerState[sampler].m_TextureEnable; +} + +inline D3DTEXTUREOP CShaderShadowDX8::OverbrightBlendValue( TextureStage_t stage ) +{ + D3DTEXTUREOP colorop; + if (m_TextureStage[stage].m_OverbrightVal < 2.0F) + colorop = D3DTOP_MODULATE; + else if (m_TextureStage[stage].m_OverbrightVal < 4.0F) + colorop = D3DTOP_MODULATE2X; + else + colorop = D3DTOP_MODULATE4X; + return colorop; +} + +static inline int ComputeArg( ShaderTexArg_t arg ) +{ + switch(arg) + { + case SHADER_TEXARG_TEXTURE: + return D3DTA_TEXTURE; + + case SHADER_TEXARG_ZERO: + return D3DTA_SPECULAR | D3DTA_COMPLEMENT; + + case SHADER_TEXARG_ONE: + return D3DTA_SPECULAR; + + case SHADER_TEXARG_TEXTUREALPHA: + return D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE; + + case SHADER_TEXARG_INVTEXTUREALPHA: + return D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT; + + case SHADER_TEXARG_NONE: + case SHADER_TEXARG_VERTEXCOLOR: + return D3DTA_DIFFUSE; + + case SHADER_TEXARG_SPECULARCOLOR: + return D3DTA_SPECULAR; + + case SHADER_TEXARG_CONSTANTCOLOR: + return D3DTA_TFACTOR; + + case SHADER_TEXARG_PREVIOUSSTAGE: + return D3DTA_CURRENT; + } + + Assert(0); + return D3DTA_TEXTURE; +} + +static inline D3DTEXTUREOP ComputeOp( ShaderTexOp_t op ) +{ + switch(op) + { + case SHADER_TEXOP_MODULATE: + return D3DTOP_MODULATE; + + case SHADER_TEXOP_MODULATE2X: + return D3DTOP_MODULATE2X; + + case SHADER_TEXOP_MODULATE4X: + return D3DTOP_MODULATE4X; + + case SHADER_TEXOP_SELECTARG1: + return D3DTOP_SELECTARG1; + + case SHADER_TEXOP_SELECTARG2: + return D3DTOP_SELECTARG2; + + case SHADER_TEXOP_ADD: + return D3DTOP_ADD; + + case SHADER_TEXOP_SUBTRACT: + return D3DTOP_SUBTRACT; + + case SHADER_TEXOP_ADDSIGNED2X: + return D3DTOP_ADDSIGNED2X; + + case SHADER_TEXOP_BLEND_CONSTANTALPHA: + return D3DTOP_BLENDFACTORALPHA; + + case SHADER_TEXOP_BLEND_PREVIOUSSTAGEALPHA: + return D3DTOP_BLENDCURRENTALPHA; + + case SHADER_TEXOP_BLEND_TEXTUREALPHA: + return D3DTOP_BLENDTEXTUREALPHA; + + case SHADER_TEXOP_MODULATECOLOR_ADDALPHA: + return D3DTOP_MODULATECOLOR_ADDALPHA; + + case SHADER_TEXOP_MODULATEINVCOLOR_ADDALPHA: + return D3DTOP_MODULATEINVCOLOR_ADDALPHA; + + case SHADER_TEXOP_DOTPRODUCT3: + return D3DTOP_DOTPRODUCT3; + + case SHADER_TEXOP_DISABLE: + return D3DTOP_DISABLE; + } + + Assert(0); + return D3DTOP_MODULATE; +} + +void CShaderShadowDX8::ConfigureCustomFVFVertexShader( unsigned int flags ) +{ + int i; + for ( i = 0; i < m_CustomTextureStages; ++i) + { + m_ShadowState.m_TextureStage[i].m_ColorArg1 = ComputeArg( m_TextureStage[i].m_Arg[0][0] ); + m_ShadowState.m_TextureStage[i].m_ColorArg2 = ComputeArg( m_TextureStage[i].m_Arg[0][1] ); + m_ShadowState.m_TextureStage[i].m_AlphaArg1 = ComputeArg( m_TextureStage[i].m_Arg[1][0] ); + m_ShadowState.m_TextureStage[i].m_AlphaArg2 = ComputeArg( m_TextureStage[i].m_Arg[1][1] ); + m_ShadowState.m_TextureStage[i].m_ColorOp = ComputeOp( m_TextureStage[i].m_Op[0] ); + m_ShadowState.m_TextureStage[i].m_AlphaOp = ComputeOp( m_TextureStage[i].m_Op[1] ); + } + + // Deal with texture stage 1 -> n + for ( i = m_CustomTextureStages; i < m_pHardwareConfig->GetTextureStageCount(); ++i ) + { + m_ShadowState.m_TextureStage[i].m_ColorArg1 = D3DTA_TEXTURE; + m_ShadowState.m_TextureStage[i].m_ColorArg2 = D3DTA_CURRENT; + m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TEXTURE; + m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_CURRENT; + m_ShadowState.m_TextureStage[i].m_ColorOp = D3DTOP_DISABLE; + m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_DISABLE; + } +} + + +//----------------------------------------------------------------------------- +// Sets up the alpha texture stage state +//----------------------------------------------------------------------------- +void CShaderShadowDX8::ConfigureAlphaPipe( unsigned int flags ) +{ + // Are we using color? + bool isUsingVertexAlpha = m_HasVertexAlpha && ((flags & SHADER_DRAW_COLOR) != 0); + bool isUsingConstantAlpha = m_HasConstantAlpha; + + int lastTextureStage = m_pHardwareConfig->GetTextureStageCount() - 1; + while ( lastTextureStage >= 0 ) + { + if ( m_TextureStage[lastTextureStage].m_TextureAlphaEnable ) + break; + --lastTextureStage; + } + + for ( int i = 0; i < m_pHardwareConfig->GetTextureStageCount(); ++i ) + { + m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_MODULATE; + if ( m_TextureStage[i].m_TextureAlphaEnable ) + { + if (i == 0) + { + m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TEXTURE; + m_ShadowState.m_TextureStage[i].m_AlphaArg2 = + isUsingConstantAlpha ? D3DTA_TFACTOR : D3DTA_DIFFUSE; + if (!isUsingConstantAlpha && !isUsingVertexAlpha) + m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_SELECTARG1; + if (isUsingConstantAlpha) + isUsingConstantAlpha = false; + else if (isUsingVertexAlpha) + isUsingVertexAlpha = false; + } + else + { + // Deal with texture stage 0 + m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TEXTURE; + m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_CURRENT; + } + } + else + { + // Blat out unused stages + if ((i > lastTextureStage) && !isUsingVertexAlpha && !isUsingConstantAlpha) + { + m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TEXTURE; + m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_CURRENT; + m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_DISABLE; + continue; + } + + // No texture coordinates; try to fold in vertex or constant alpha + if (i == 0) + { + m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TFACTOR; + m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_DIFFUSE; + if (isUsingVertexAlpha) + { + m_ShadowState.m_TextureStage[i].m_AlphaOp = + isUsingConstantAlpha ? D3DTOP_MODULATE : D3DTOP_SELECTARG2; + } + else + { + m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_SELECTARG1; + } + isUsingVertexAlpha = false; + isUsingConstantAlpha = false; + } + else + { + m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_CURRENT; + if (isUsingConstantAlpha) + { + m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_TFACTOR; + isUsingConstantAlpha = false; + } + else if (isUsingVertexAlpha) + { + m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_DIFFUSE; + isUsingVertexAlpha = false; + } + else + { + m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_DIFFUSE; + m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_SELECTARG1; + } + } + } + } +} + + +//----------------------------------------------------------------------------- +// Sets up the texture stage state +//----------------------------------------------------------------------------- +void CShaderShadowDX8::ConfigureFVFVertexShader( unsigned int flags ) +{ + // For non-modulation, we can't really use the path below... + if (m_CustomTextureStageState) + { + ConfigureCustomFVFVertexShader( flags ); + return; + } + + // Deal with texture stage 0 + m_ShadowState.m_TextureStage[0].m_ColorArg1 = D3DTA_TEXTURE; + m_ShadowState.m_TextureStage[0].m_ColorArg2 = D3DTA_DIFFUSE; + m_ShadowState.m_TextureStage[0].m_AlphaArg1 = D3DTA_TEXTURE; + m_ShadowState.m_TextureStage[0].m_AlphaArg2 = D3DTA_DIFFUSE; + + // Are we using color? + bool isUsingVertexColor = (flags & SHADER_DRAW_COLOR) != 0; + bool isUsingConstantColor = (flags & SHADER_HAS_CONSTANT_COLOR) != 0; + + // Are we using texture coordinates? + if ( IsUsingTextureCoordinates( SHADER_SAMPLER0 ) ) + { + if (isUsingVertexColor) + { + m_ShadowState.m_TextureStage[0].m_ColorOp = OverbrightBlendValue(SHADER_TEXTURE_STAGE0); + m_ShadowState.m_TextureStage[0].m_AlphaOp = D3DTOP_MODULATE; + } + else + { + // Just blend in the constant color here, and don't blend it in below + m_ShadowState.m_TextureStage[0].m_ColorArg2 = D3DTA_TFACTOR; + m_ShadowState.m_TextureStage[0].m_AlphaArg2 = D3DTA_TFACTOR; + isUsingConstantColor = false; + + m_ShadowState.m_TextureStage[0].m_ColorOp = OverbrightBlendValue(SHADER_TEXTURE_STAGE0); + m_ShadowState.m_TextureStage[0].m_AlphaOp = D3DTOP_MODULATE; + } + } + else + { + // Are we using color? + if (isUsingVertexColor) + { + // Color, but no texture + if ( m_TextureStage[0].m_OverbrightVal < 2.0f ) + { + // Use diffuse * constant color, if we have a constant color + if (isUsingConstantColor) + { + m_ShadowState.m_TextureStage[0].m_ColorArg1 = D3DTA_TFACTOR; + m_ShadowState.m_TextureStage[0].m_AlphaArg1 = D3DTA_TFACTOR; + m_ShadowState.m_TextureStage[0].m_ColorOp = OverbrightBlendValue((TextureStage_t)0); + m_ShadowState.m_TextureStage[0].m_AlphaOp = D3DTOP_MODULATE; + + // This'll make sure we don't apply the constant color again below + isUsingConstantColor = false; + } + else + { + m_ShadowState.m_TextureStage[0].m_ColorOp = D3DTOP_SELECTARG2; + m_ShadowState.m_TextureStage[0].m_AlphaOp = D3DTOP_SELECTARG2; + } + } + else if (m_TextureStage[0].m_OverbrightVal < 4.0f) + { + // Produce diffuse + diffuse + m_ShadowState.m_TextureStage[0].m_ColorArg1 = D3DTA_DIFFUSE; + m_ShadowState.m_TextureStage[0].m_ColorOp = D3DTOP_ADD; + m_ShadowState.m_TextureStage[0].m_AlphaOp = D3DTOP_SELECTARG2; + } + else + { + // no 4x overbright yet! + Assert(0); + } + } + else + { + // No texture, no color + if (isUsingConstantColor) + { + m_ShadowState.m_TextureStage[0].m_ColorArg1 = D3DTA_TFACTOR; + m_ShadowState.m_TextureStage[0].m_AlphaArg1 = D3DTA_TFACTOR; + m_ShadowState.m_TextureStage[0].m_ColorOp = D3DTOP_SELECTARG1; + m_ShadowState.m_TextureStage[0].m_AlphaOp = D3DTOP_SELECTARG1; + + // This'll make sure we don't apply the constant color again below + isUsingConstantColor = false; + } + else + { + // Deal with texture stage 0 + m_ShadowState.m_TextureStage[0].m_ColorArg1 = D3DTA_TFACTOR; + m_ShadowState.m_TextureStage[0].m_AlphaArg1 = D3DTA_TFACTOR; + m_ShadowState.m_TextureStage[0].m_ColorOp = D3DTOP_SELECTARG1; + m_ShadowState.m_TextureStage[0].m_AlphaOp = D3DTOP_SELECTARG1; + } + } + } + + // Deal with texture stage 1 -> n + int lastUsedTextureStage = 0; + for ( int i = 1; i < m_pHardwareConfig->GetTextureStageCount(); ++i ) + { + m_ShadowState.m_TextureStage[i].m_ColorArg1 = D3DTA_TEXTURE; + m_ShadowState.m_TextureStage[i].m_ColorArg2 = D3DTA_CURRENT; + m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TEXTURE; + m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_CURRENT; + + // Not doing anything? Disable the stage + if ( !IsUsingTextureCoordinates( (Sampler_t)i ) ) + { + if (m_TextureStage[i].m_OverbrightVal < 2.0f) + { + m_ShadowState.m_TextureStage[i].m_ColorOp = D3DTOP_DISABLE; + m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_DISABLE; + } + else + { + // Here, we're modulating. Add in the constant color if we need to... + m_ShadowState.m_TextureStage[i].m_ColorArg1 = D3DTA_TFACTOR; + m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TFACTOR; + + m_ShadowState.m_TextureStage[i].m_ColorOp = OverbrightBlendValue((TextureStage_t)i); + m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_MODULATE; + + isUsingConstantColor = false; + lastUsedTextureStage = i; + } + } + else + { + // Here, we're modulating. Keep track of the last modulation stage, + // cause the constant color modulation comes in the stage after that + lastUsedTextureStage = i; + m_ShadowState.m_TextureStage[i].m_ColorOp = OverbrightBlendValue((TextureStage_t)i); + m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_MODULATE; + } + } + + // massive amounts of suck: gotta overbright here if we really + // wanted to overbright stage0 but couldn't because of the add. + // This isn't totally correct, but there's no way around putting it here + // because we can't texture out of stage2 on low or medium end hardware + m_ShadowShaderState.m_ModulateConstantColor = false; + if (isUsingConstantColor) + { + ++lastUsedTextureStage; + + if (isUsingConstantColor && + (lastUsedTextureStage >= m_pHardwareConfig->GetTextureStageCount())) + { + // This is the case where we'd want to modulate in a particular texture + // stage, but we can't because there aren't enough. In this case, we're gonna + // need to do the modulation in the per-vertex color. + m_ShadowShaderState.m_ModulateConstantColor = true; + } + else + { + AssertOnce (lastUsedTextureStage < 2); + + // Here, we've got enough texture stages to do the modulation + m_ShadowState.m_TextureStage[lastUsedTextureStage].m_ColorArg1 = D3DTA_TFACTOR; + m_ShadowState.m_TextureStage[lastUsedTextureStage].m_ColorArg2 = D3DTA_CURRENT; + m_ShadowState.m_TextureStage[lastUsedTextureStage].m_AlphaArg1 = D3DTA_TFACTOR; + m_ShadowState.m_TextureStage[lastUsedTextureStage].m_AlphaArg2 = D3DTA_CURRENT; + m_ShadowState.m_TextureStage[lastUsedTextureStage].m_ColorOp = D3DTOP_MODULATE; + m_ShadowState.m_TextureStage[lastUsedTextureStage].m_AlphaOp = D3DTOP_MODULATE; + } + } + + // Overwrite the alpha stuff if we asked to independently control it + if (m_AlphaPipe) + { + ConfigureAlphaPipe( flags ); + } +} + + +//----------------------------------------------------------------------------- +// Makes sure we report if we're getting garbage. +//----------------------------------------------------------------------------- +void CShaderShadowDX8::DrawFlags( unsigned int flags ) +{ + m_DrawFlags = flags; + m_ShadowState.m_UsingFixedFunction = true; +} + + +//----------------------------------------------------------------------------- +// Compute texture coordinates +//----------------------------------------------------------------------------- +void CShaderShadowDX8::ConfigureTextureCoordinates( unsigned int flags ) +{ + // default... + for (int i = 0; i < m_pHardwareConfig->GetTextureStageCount(); ++i) + { + TextureCoordinate( (TextureStage_t)i, i ); + } + + if (flags & SHADER_DRAW_TEXCOORD0) + { + Assert( (flags & SHADER_DRAW_LIGHTMAP_TEXCOORD0) == 0 ); + TextureCoordinate( SHADER_TEXTURE_STAGE0, 0 ); + } + else if (flags & SHADER_DRAW_LIGHTMAP_TEXCOORD0) + { + TextureCoordinate( SHADER_TEXTURE_STAGE0, 1 ); + } + else if (flags & SHADER_DRAW_SECONDARY_TEXCOORD0 ) + { + TextureCoordinate( SHADER_TEXTURE_STAGE0, 2 ); + } + + if (flags & SHADER_DRAW_TEXCOORD1) + { + Assert( (flags & SHADER_DRAW_LIGHTMAP_TEXCOORD1) == 0 ); + TextureCoordinate( SHADER_TEXTURE_STAGE1, 0 ); + } + else if (flags & SHADER_DRAW_LIGHTMAP_TEXCOORD1) + { + TextureCoordinate( SHADER_TEXTURE_STAGE1, 1 ); + } + else if (flags & SHADER_DRAW_SECONDARY_TEXCOORD1 ) + { + TextureCoordinate( SHADER_TEXTURE_STAGE1, 2 ); + } +} + + +//----------------------------------------------------------------------------- +// Converts draw flags into vertex format +//----------------------------------------------------------------------------- +VertexFormat_t CShaderShadowDX8::FlagsToVertexFormat( int flags ) const +{ + // Flags -1 occurs when there's an error condition; + // we'll just give em the max space and let them fill it in. + int formatFlags = 0; + int texCoordSize[VERTEX_MAX_TEXTURE_COORDINATES] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + int userDataSize = 0; + int numBones = 0; + + // Flags -1 occurs when there's an error condition; + // we'll just give em the max space and let them fill it in. + if (flags == -1) + { + formatFlags = VERTEX_POSITION | VERTEX_NORMAL | VERTEX_COLOR | + VERTEX_TANGENT_S | VERTEX_TANGENT_T; + texCoordSize[0] = texCoordSize[1] = texCoordSize[2] = 2; + } + else + { + if (flags & SHADER_DRAW_POSITION) + formatFlags |= VERTEX_POSITION; + + if (flags & SHADER_DRAW_NORMAL) + formatFlags |= VERTEX_NORMAL; + + if (flags & SHADER_DRAW_COLOR) + formatFlags |= VERTEX_COLOR; + + if( flags & SHADER_DRAW_SPECULAR ) + formatFlags |= VERTEX_SPECULAR; + + if (flags & SHADER_TEXCOORD_MASK) + { + // normal texture coords into texture 0 + texCoordSize[0] = 2; + } + + if (flags & SHADER_LIGHTMAP_TEXCOORD_MASK) + { + // lightmaps go into texcoord 1 + texCoordSize[1] = 2; + } + + if (flags & SHADER_SECONDARY_TEXCOORD_MASK) + { + // any texgen, or secondary texture coordinate is put into texcoord 2 + texCoordSize[2] = 2; + } + } + + // Hardware skinning... always store space for up to 3 bones + // and always assume index blend enabled if available + if (m_ShadowState.m_VertexBlendEnable) + { + if (HardwareConfig()->MaxBlendMatrixIndices() > 0) + formatFlags |= VERTEX_BONE_INDEX; + + if (HardwareConfig()->MaxBlendMatrices() > 2) + numBones = 2; // the third bone weight is implied + else + numBones = HardwareConfig()->MaxBlendMatrices() - 1; + } + + return MeshMgr()->ComputeVertexFormat( formatFlags, VERTEX_MAX_TEXTURE_COORDINATES, + texCoordSize, numBones, userDataSize ); +} + + +//----------------------------------------------------------------------------- +// Computes shadow state based on bunches of other parameters +//----------------------------------------------------------------------------- +void CShaderShadowDX8::ComputeAggregateShadowState( ) +{ + unsigned int flags = 0; + + // Initialize the texture stage usage; this may get changed later + for (int i = 0; i < m_pHardwareConfig->GetSamplerCount(); ++i) + { + m_ShadowState.m_SamplerState[i].m_TextureEnable = + IsUsingTextureCoordinates( (Sampler_t)i ); + + // Deal with the alpha pipe + if ( m_ShadowState.m_UsingFixedFunction && m_AlphaPipe ) + { + if ( m_TextureStage[i].m_TextureAlphaEnable ) + { + m_ShadowState.m_SamplerState[i].m_TextureEnable = true; + } + } + } + + // Always use the same alpha src + dest if it's disabled + // NOTE: This is essential for stateblocks to work + if ( m_ShadowState.m_AlphaBlendEnable ) + { + m_ShadowState.m_SrcBlend = m_SrcBlend; + m_ShadowState.m_DestBlend = m_DestBlend; + m_ShadowState.m_BlendOp = m_BlendOp; + } + else + { + m_ShadowState.m_SrcBlend = D3DBLEND_ONE; + m_ShadowState.m_DestBlend = D3DBLEND_ZERO; + m_ShadowState.m_BlendOp = D3DBLENDOP_ADD; + } + + // GR + if (m_ShadowState.m_SeparateAlphaBlendEnable) + { + m_ShadowState.m_SrcBlendAlpha = m_SrcBlendAlpha; + m_ShadowState.m_DestBlendAlpha = m_DestBlendAlpha; + m_ShadowState.m_BlendOpAlpha = m_BlendOpAlpha; + } + else + { + m_ShadowState.m_SrcBlendAlpha = D3DBLEND_ONE; + m_ShadowState.m_DestBlendAlpha = D3DBLEND_ZERO; + m_ShadowState.m_BlendOpAlpha = D3DBLENDOP_ADD; + } + + // Use the same func if it's disabled + if (m_ShadowState.m_AlphaTestEnable) + { + // If alpha test is enabled, just use the values set + m_ShadowState.m_AlphaFunc = m_AlphaFunc; + m_ShadowState.m_AlphaRef = m_AlphaRef; + } + else + { + // A default value + m_ShadowState.m_AlphaFunc = D3DCMP_GREATEREQUAL; + m_ShadowState.m_AlphaRef = 0; + + // If not alpha testing and doing a standard alpha blend, force on alpha testing + if ( m_ShadowState.m_AlphaBlendEnable ) + { + if ( ( m_ShadowState.m_SrcBlend == D3DBLEND_SRCALPHA ) && ( m_ShadowState.m_DestBlend == D3DBLEND_INVSRCALPHA ) ) + { + m_ShadowState.m_AlphaFunc = D3DCMP_GREATEREQUAL; + m_ShadowState.m_AlphaRef = 1; + } + } + } + if ( m_ShadowState.m_UsingFixedFunction ) + { + flags = m_DrawFlags; + + // We need to take this bad boy into account + if (HasConstantColor()) + flags |= SHADER_HAS_CONSTANT_COLOR; + + // We need to take lighting into account.. + if ( m_ShadowState.m_Lighting ) + flags |= SHADER_DRAW_NORMAL; + + if (m_ShadowState.m_Lighting) + flags |= SHADER_DRAW_COLOR; + + // Look for inconsistency in the shadow state (can't have texgen & + // SHADER_DRAW_TEXCOORD or SHADER_DRAW_SECONDARY_TEXCOORD0 on the same stage) + if (flags & (SHADER_DRAW_TEXCOORD0 | SHADER_DRAW_SECONDARY_TEXCOORD0)) + { + Assert( (m_ShadowState.m_TextureStage[0].m_TexCoordIndex & 0xFFFF0000) == 0 ); + } + if (flags & (SHADER_DRAW_TEXCOORD1 | SHADER_DRAW_SECONDARY_TEXCOORD1)) + { + Assert( (m_ShadowState.m_TextureStage[1].m_TexCoordIndex & 0xFFFF0000) == 0 ); + } + if (flags & (SHADER_DRAW_TEXCOORD2 | SHADER_DRAW_SECONDARY_TEXCOORD2)) + { + Assert( (m_ShadowState.m_TextureStage[2].m_TexCoordIndex & 0xFFFF0000) == 0 ); + } + if (flags & (SHADER_DRAW_TEXCOORD3 | SHADER_DRAW_SECONDARY_TEXCOORD3)) + { + Assert( (m_ShadowState.m_TextureStage[3].m_TexCoordIndex & 0xFFFF0000) == 0 ); + } + + // Vertex usage has already been set for pixel + vertex shaders + m_ShadowShaderState.m_VertexUsage = FlagsToVertexFormat( flags ); + + // Configure the texture stages + ConfigureFVFVertexShader(flags); + +#if 0 +//#ifdef _DEBUG + // NOTE: This must be true for stateblocks to work + for ( i = 0; i < m_pHardwareConfig->GetTextureStageCount(); ++i ) + { + if ( m_ShadowState.m_TextureStage[i].m_ColorOp == D3DTOP_DISABLE ) + { + Assert( m_ShadowState.m_TextureStage[i].m_ColorArg1 == D3DTA_TEXTURE ); + Assert( m_ShadowState.m_TextureStage[i].m_ColorArg2 == ((i == 0) ? D3DTA_DIFFUSE : D3DTA_CURRENT) ); + } + + if ( m_ShadowState.m_TextureStage[i].m_AlphaOp == D3DTOP_DISABLE ) + { + Assert( m_ShadowState.m_TextureStage[i].m_AlphaArg1 == D3DTA_TEXTURE ); + Assert( m_ShadowState.m_TextureStage[i].m_AlphaArg2 == ((i == 0) ? D3DTA_DIFFUSE : D3DTA_CURRENT) ); + } + } +#endif + } + else + { + // Pixel shaders, disable everything so as to prevent unnecessary state changes.... + for ( int i = 0; i < m_pHardwareConfig->GetTextureStageCount(); ++i ) + { + m_ShadowState.m_TextureStage[i].m_ColorArg1 = D3DTA_TEXTURE; + m_ShadowState.m_TextureStage[i].m_ColorArg2 = (i == 0) ? D3DTA_DIFFUSE : D3DTA_CURRENT; + m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TEXTURE; + m_ShadowState.m_TextureStage[i].m_AlphaArg2 = (i == 0) ? D3DTA_DIFFUSE : D3DTA_CURRENT; + m_ShadowState.m_TextureStage[i].m_ColorOp = D3DTOP_DISABLE; + m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_DISABLE; + m_ShadowState.m_TextureStage[i].m_TexCoordIndex = i; + } + m_ShadowState.m_Lighting = false; + m_ShadowState.m_SpecularEnable = false; + m_ShadowState.m_VertexBlendEnable = false; + m_ShadowShaderState.m_ModulateConstantColor = false; + } + + // Compute texture coordinates + ConfigureTextureCoordinates(flags); + + // Alpha to coverage + if ( m_ShadowState.m_EnableAlphaToCoverage ) + { + // Only allow this to be enabled if blending is disabled and testing is enabled + if ( ( m_ShadowState.m_AlphaBlendEnable == true ) || ( m_ShadowState.m_AlphaTestEnable == false ) ) + { + m_ShadowState.m_EnableAlphaToCoverage = false; + } + } +} + +void CShaderShadowDX8::FogMode( ShaderFogMode_t fogMode ) +{ + Assert( fogMode >= 0 && fogMode < SHADER_FOGMODE_NUMFOGMODES ); + m_ShadowState.m_FogMode = fogMode; +} + +void CShaderShadowDX8::DisableFogGammaCorrection( bool bDisable ) +{ + m_ShadowState.m_bDisableFogGammaCorrection = bDisable; +} + +void CShaderShadowDX8::SetDiffuseMaterialSource( ShaderMaterialSource_t materialSource ) +{ + COMPILE_TIME_ASSERT( ( int )D3DMCS_MATERIAL == ( int )SHADER_MATERIALSOURCE_MATERIAL ); + COMPILE_TIME_ASSERT( ( int )D3DMCS_COLOR1 == ( int )SHADER_MATERIALSOURCE_COLOR1 ); + COMPILE_TIME_ASSERT( ( int )D3DMCS_COLOR2 == ( int )SHADER_MATERIALSOURCE_COLOR2 ); + Assert( materialSource == SHADER_MATERIALSOURCE_MATERIAL || + materialSource == SHADER_MATERIALSOURCE_COLOR1 || + materialSource == SHADER_MATERIALSOURCE_COLOR2 ); + m_ShadowState.m_DiffuseMaterialSource = ( D3DMATERIALCOLORSOURCE )materialSource; +} |