area51/Support/Render/shader_mgr.inl
Andrew Sampson 431f72b93a source
2021-08-27 19:22:41 -07:00

1648 lines
57 KiB
C++

//=============================================================================
//
// XBOX Specific Shader Management Routines
//
//=============================================================================
#include "render/lightmgr.hpp"
#include "render/platform_render.hpp"
#include "entropy/xbox/xbox_private.hpp"
//#include "UI\ui_text.hpp"
//#include "UI\ui_manager.hpp"
//#include "UI\ui_font.hpp"
#include <xgraphics.h>
#include "xbox_render.hpp"
#include "Xbox\LeastSquares.hpp"
//=============================================================================
//=============================================================================
// Shader manager methods
//=============================================================================
//=============================================================================
//=============================================================================
static DWORD s_dwRigidDesc[]=
{
D3DVSD_STREAM( 0 ) ,
D3DVSD_REG ( 0, D3DVSDT_FLOAT3 ) , // v0-position
D3DVSD_REG ( 1, D3DVSDT_NORMPACKED3 ) , // v1-normal
D3DVSD_REG ( 2, D3DVSDT_FLOAT2 ) , // v3-uv
D3DVSD_STREAM( 1 ),
D3DVSD_REG ( 3, D3DVSDT_D3DCOLOR ) , // colour
D3DVSD_END( )
};
//=============================================================================
static DWORD s_dwSkinDesc[]=
{
D3DVSD_STREAM( 0 ) ,
D3DVSD_REG ( 0, D3DVSDT_FLOAT3 ) , // v0-position
D3DVSD_REG ( 1, D3DVSDT_NORMPACKED3 ) , // v1-normal
D3DVSD_REG ( 2, D3DVSDT_FLOAT4 ) , // v2-uv/weights
D3DVSD_REG ( 3, D3DVSDT_FLOAT2 ) , // v3-bones
D3DVSD_END( )
};
//=============================================================================
static vector4 s_FogColour[5];
static f32 s_FogStart;
//////////////////////////////////////////////////////////////////////////////
//
// MATERIAL DESCRIPTIONS: Only these configurations can be used at runtime.
// This table saves us from having to build every possible combination.
//
//////////////////////////////////////////////////////////////////////////////
#define SHADER_ROOT "C:\\GameData\\A51\\Release\\Xbox"
#define SIZEOF(label) (sizeof(label)/sizeof(label[0]))
#define ENDL(label) }data[SIZEOF(::s_##label##_Name)];
#define LEAF(label) struct label: public leaf{
//////////////////////////////////////////////////////////////////////////////
struct filedesc
{
const char* pName;
const char* pLabel;
u32 Flags;
};
//////////////////////////////////////////////////////////////////////////////
//
// The NULL,NULL means pass through, stage ignored.
static const filedesc s_oPos_Name[]={ { NULL , NULL ,0 },
// c92 to c95 = L2C .....................
// c00 to c03 = L2W .....................
{ "VS0000","oPos_Rigid" ,0 },
// c92 to c95 = L2C .....................
// c00 to c79 = Matrix palette ..........
{ "VS0001","oPos_Skin" ,0 } };
static const filedesc s_oD0__Name[]={ { NULL , NULL ,0 },
// c84 to c87 = Light colours ...........
// c88 to c91 = Light directions ........
{ "VS0002","oD0_DirectLight" ,0 },
// c84 to c89 = Point light pos/rgb pairs
{ "VS0003","oD0_PointLight" ,0 },
{ "VS0004","oD0_BlackLight" ,0 },
{ "VS0021","oD0_WhiteLight" ,0 },
{ "VS0005","oD0_Diffuse" ,0 } };
static const filedesc s_oAmb_Name[]={ { NULL , NULL ,0 },
{ NULL, "oD0_Ambient" ,0 } };
static const filedesc s_oT0__Name[]={ { NULL , NULL ,0 },
// c-8 to c-9 = Scrolling UVs ...........
{ "VS0007","oT0_Normal" ,0 },
// c-2 to c-5 = Local to eyespace .......
// c-8 to c-9 = Scrolling UVs ...........
{ "VS0008","oT0_Cube" ,0 },
// c-2 to c-5 = Local to eye ............
// c-8 to c-9 = Scrolling UVs ...........
// c-1 = Special consts ..........
{ "VS0009","oT0_Env" ,0 },
// c-1 = Special consts ..........
// c-2 = Distortion consts .......
// c-3 to c-5 = Local to eye ............
{ "VS0017","oT0_Distortion" ,0 },
// c-1 = Special consts ..........
// c-2 = Intensity consts ........
{ "VS0025","oT0_Intensity" ,0 } };
static const filedesc s_oT3__Name[]={ { NULL , NULL ,0 },
// c-33 to c-36 = World to projector ....
// c-32 = Flashlight pos ........
{ "VS0010","oT3_Flashlight" ,0 } };
static const filedesc s_oSt__Name[]={ { NULL , NULL ,0 },
// c-28 to c-31 = Shadow projector ......
// c-27 = Shadow colour .........
{ "VS0011","oSt_CastShadowRigid" ,0 },
// c 00 to c 79 = Matrix palette ........
// c-28 to c-31 = Shadow projector ......
{ "VS0012","oSt_CastShadowSkin" ,0 } };
static const filedesc s_oSi__Name[]={ { NULL , NULL ,0 },
// c-31 to c-28 = Shadow projector ......
// c-26 = UV scale
{ "VS0016","oT0_ShadowCreate" ,0 },
// c-24 to c-26 = Shadow mirroring ......
{ "VS0013","oT1_ShadowInsert" ,0 },
// c-24 to c-26 = Shadow mirroring ......
{ "VS0014","oT2_ShadowInsert" ,0 },
// c-24 to c-26 = Shadow mirroring ......
{ "VS0015","oT3_ShadowInsert" ,0 },
// c-28 to c-31 = Shadow projector ......
{ "VS0026","oT1_ShadowProject" ,0 },
// c-29 to c-32 = Shadow projector ......
// c-33 to c-36 = Shadow projector ......
{ "VS0027","oT2_ShadowProject" ,0 },
// c-1 = Special consts ..........
{ "VS0028","oT0_ProjectBack" ,0 } };
static const filedesc s_oLm__Name[]={ { NULL , NULL ,0 },
// c84 to c89 = Light pos/colour ........
// c-3 = Active lights ...........
{ "VS0020","oT0_LightMapCreate" ,0 } };
static const filedesc s_oD1__Name[]={ { NULL , NULL ,0 },
{ "VS0018","oD1_Fog" ,0 } };
static const filedesc s_oBlt_Name[]={ { NULL , NULL ,0 },
{ "VS0019","Blitter" ,0 } };
/* Vertex shader namespace.
This provides a nice clean spot to put my shader tree and
differentiate it from the pixel shader tree.
*/
#define MAX_SHADERS 256
namespace vs
{
struct detail
{
desc Flags;
shader Shader;
}
Details[MAX_SHADERS];
u32 OldSize;
u8* pSpace;
u32 Count;
u32 Size;
}
#if COMPILE_SHADERS
// Workspace for compiling shaders
char s_Work[16384];
#endif
//////////////////////////////////////////////////////////////////////////////
static const filedesc s_Mat_Name[]={ { NULL , NULL , 0 },
{ "PS0000","bDiffusePerPixelIllum" , kTEX0 },
{ "PS0001","bDiffusePerPixelEnvAdd" , kTEX0 | kTEX1 },
{ "PS0002","bDiffusePerPixelEnv" , kTEX0 | kTEX1 },
{ "PS0003","bAlphaPerPixelIllum" , kTEX0 },
{ "PS0004","bAlphaPerPolyIllum" , kTEX0 },
{ "PS0005","bAlphaPerPolyEnv" , kTEX0 | kTEX1 },
{ "PS0007","bDiffuse" , kTEX0 },
{ "PS0008","bAlpha" , kTEX0 },
{ "PS0013","bDiffusePerPixelIllum bProj" , kTEX0 | kTEX3 },
{ "PS0014","bDiffusePerPixelEnvAdd bProj" , kTEX0 | kTEX1 | kTEX3 },
{ "PS0015","bDiffusePerPixelEnv bProj" , kTEX0 | kTEX1 | kTEX3 },
{ "PS0016","bAlphaPerPixelIllum bProj" , kTEX0 | kTEX3 },
{ "PS0017","bAlphaPerPolyIllum bProj" , kTEX0 | kTEX3 },
{ "PS0018","bAlphaPerPolyEnv bProj" , kTEX0 | kTEX1 | kTEX3 },
{ "PS0021","bDiffuse bProj" , kTEX0 | kTEX3 },
{ "PS0022","bAlpha bProj" , kTEX0 | kTEX3 } };
static const filedesc s_Det_Name[]={ { NULL , NULL , 0 },
{ "PS0006","bDetailMap" , kTEX2 } };
static const filedesc s_Blr_Name[]={ { NULL , NULL , 0 },
{ "PS0028","bDepthBlur" , kTEX0 | kTEX1 | kTEX3 } };
static const filedesc s_Sha_Name[]={ { NULL , NULL , 0 },
{ "PS0024","oT1Shadow" , kTEX1 },
{ "PS0025","oT2Shadow" , kTEX2 },
{ "PS0026","oT3Shadow" , kTEX3 },
{ "PS0027","oT0Shadow" , kTEX0 },
{ "PS0037","oT1Project" , kTEX0 | kTEX1 },
{ "PS0038","oT2Project" , kTEX0 | kTEX1 | kTEX2 },
{ "PS0042","oT1ProjectToLightMap" , kTEX0 | kTEX1 },
{ "PS0043","oT1ProjectToLightMap" , kTEX0 | kTEX1 | kTEX2 } };
static const filedesc s_Dis_Name[]={ { NULL , NULL , 0 },
{ "PS0029","bDistortion" , kTEX0 },
{ "PS0036","bDistortionEnv" , kTEX0 | kTEX1 } };
static const filedesc s_Ppl_Name[]={ { NULL , NULL , 0 },
{ "PS0032","bPerPixelLit" , kTEX0 | kTEX1 | kTEX2 },
{ "PS0044","bPerPixelLitFog" , },
{ "PS0040","bPerPixelLitProj" , kTEX0 | kTEX1 | kTEX2 | kTEX3 } };
static const filedesc s_Ppt_Name[]={ { NULL , NULL , 0 },
{ NULL ,"bPerPixelLitPunchthru" , kTEX3 } };
static const filedesc s_BxT_Name[]={ { NULL , NULL , 0 },
{ "PS0033","bRgbaByTex0" , kTEX0 } };
static const filedesc s_Pur_Name[]={ { NULL , NULL , 0 },
{ NULL , NULL , 0 } };
static const filedesc s_Dec_Name[]={ { NULL , NULL , 0 },
{ "PS0034","bDecal0" , kTEX0 | kTEX1 },
{ "PS0035","bDecal1" , kTEX0 } };
static const filedesc s_Glw_Name[]={ { NULL , NULL , 0 },
{ "PS0030","bForcedGlow" , 0 } };
static const filedesc s_Xfc_Name[]={ { NULL , "xfc_Std" , 0 },
{ NULL , "xfc_Fog" , 0 } };
static const filedesc s_Blt_Name[]={ { NULL , NULL , 0 },
{ "PS0009","bBltPostFx" , kTEX0 | kTEX1 | kTEX2 | kTEX3 },
{ "PS0020","bBltFinal" , kTEX0 },
{ "PS0039","bBltx2" , kTEX0 | kTEX1 },
{ "PS0031","bBlt" , kTEX0 } };
/* Pixel shader tree.
This tree enables very rapid shader searches.
*/
namespace ps
{
struct detail
{
desc Flags;
shader Shader;
}
Details[MAX_SHADERS];
u32 OldSize;
u8* pSpace;
u32 Count;
u32 Size;
}
///////////////////////////////////////////////////////////////////////////////
//
// This routine loads up the 136 shader addresses on the GPU. It does so by
// examining the combination bits, loading shader fragments if necessary,
// and selecting the proper entry point.
//
///////////////////////////////////////////////////////////////////////////////
static void LoadShader( const char* pFilename )
{
char* pBuffer; if( pFilename )
{
#if 1
HANDLE SectionHandle = XGetSectionHandle( pFilename );
ASSERT(SectionHandle != INVALID_HANDLE_VALUE );
DWORD SectionSize = XGetSectionSize( SectionHandle );
char* SectionData = (char*)XLoadSectionByHandle( SectionHandle );
s32 Length = x_strlen( s_Work );
x_memcpy( s_Work+Length,SectionData,SectionSize );
XFreeSectionByHandle( SectionHandle );
x_strcat( s_Work,"\n" );
#else
// load shader fragment ***********************************************
X_FILE* hFile= x_fopen( xfs( "%s\\%s",SHADER_ROOT,pFilename),"r" );
ASSERT( hFile );
{
s32 Size = x_flength( hFile );
pBuffer = new char[ Size+1 ];
x_fread( pBuffer,Size,1,hFile );
pBuffer[Size]=0;
}
x_fclose( hFile );
// concatenate to output buffer ***************************************
x_strcat( s_Work,pBuffer );
x_strcat( s_Work,"\n" );
delete[]pBuffer;
#endif
}
}
///////////////////////////////////////////////////////////////////////////
static s32 PSCmp( const void* pl,const void* pr )
{
return( ((ps::detail*)pl)->Flags.Mask > ((ps::detail*)pr)->Flags.Mask );
}
///////////////////////////////////////////////////////////////////////////
template< class t,class a >s32 search( t& Flags,a* Details,s32 n )
{
s32 high,i,low;
for( low=-1,high=n;high-low>1; )
{
i = (high+low)/2;
if( Flags.Mask <= Details[i].Flags.Mask )
high = i;
else
low = i;
}
if( Flags.Mask==Details[high].Flags.Mask )
return high;
return -1;
}
///////////////////////////////////////////////////////////////////////////////
static bool GetShader( ps::path& Path,shader*& pShader )
{
// binary search for shader ***********************************************
s32 i=search( Path.Flags,ps::Details,ps::Count );
if( i>-1 )
{
#ifdef X_DEBUG
ASSERT( ps::Details[i].Flags.Mask==Path.Flags.Mask );
if( i<MAX_SHADERS-1 )ASSERT( ps::Details[i].Flags.Mask != ps::Details[i+1].Flags.Mask );
if( i>1 )ASSERT( ps::Details[i].Flags.Mask != ps::Details[i-1].Flags.Mask );
#endif
pShader = &ps::Details[i].Shader;
return true;
}
// get samplers ***********************************************************
#if COMPILE_SHADERS
u8 Flags = 0;
{
if(Path.iLink[ 0])Flags |= s_Mat_Name[Path.iLink[ 0]].Flags;
if(Path.iLink[ 1])Flags |= s_Det_Name[Path.iLink[ 1]].Flags;
if(Path.iLink[ 2])Flags |= s_Blr_Name[Path.iLink[ 2]].Flags;
if(Path.iLink[ 3])Flags |= s_Sha_Name[Path.iLink[ 3]].Flags;
if(Path.iLink[ 4])Flags |= s_Dis_Name[Path.iLink[ 4]].Flags;
if(Path.iLink[ 5])Flags |= s_Glw_Name[Path.iLink[ 5]].Flags;
if(Path.iLink[ 6])Flags |= s_Blt_Name[Path.iLink[ 6]].Flags;
if(Path.iLink[ 7])Flags |= s_BxT_Name[Path.iLink[ 7]].Flags;
if(Path.iLink[ 8])Flags |= s_Pur_Name[Path.iLink[ 8]].Flags;
if(Path.iLink[ 9])Flags |= s_Dec_Name[Path.iLink[ 9]].Flags;
if(Path.iLink[10])Flags |= s_Ppl_Name[Path.iLink[10]].Flags;
if(Path.iLink[12])Flags |= s_Ppt_Name[Path.iLink[12]].Flags;
}
// Stitch pixel shader fragments ******************************************
shader& Shader = ps::Details[ps::Count].Shader;
{
x_memset( s_Work,0,sizeof(s_Work) );
x_strcpy( s_Work,"xps.1.1\n\n" );
if( SWITCH_USE_TEXTURES )
{
// validating tweaks ..............................................
if( Path.Flags.bFogPunchthru )
Flags |= kTEX0;
if( Path.Flags.bTexelModded )
Flags |= kTEX0;
if( Path.Flags.bDiffusePerPolyEnvAdd )
{
Flags |= kTEX0;
Flags |= kTEX1;
}
if( Path.Flags.bTexelOnly )
{
Flags |= kTEX0;
Flags |= kTEX1;
}
if( Path.Flags.oT3LightMap )
Flags |= kTEX3;
if( Path.Flags.oT3_Mask )
Flags |= kTEX3;
if( Path.Flags.bFogPass )
Flags |= kTEX0;
if( Path.Flags.oT3_Mask )
Flags |= kTEX3;
if( Path.Flags.oT3_Proj )
{
Flags |= kTEX0;
Flags |= kTEX3;
}
if( Path.Flags.bCloth )
{
Flags |= kTEX0;
Flags |= kTEX3;
}
// determine sampling .............................................
if( Flags & kTEX0 ) x_strcat( s_Work,"tex t0\n" );
if( Flags & kTEX1 ) x_strcat( s_Work,"tex t1\n" );
if( Flags & kTEX2 ) x_strcat( s_Work,"tex t2\n" );
if( Flags & kTEX3 ) x_strcat( s_Work,"tex t3\n" );
Path.ts = Flags;
// special purpose tweaks .........................................
if( Path.Flags.oV0_Tint )
x_strcat( s_Work,"mul v0.rgb,v0.rgb,c11.rgb\n" );
if( Path.Flags.bTexelModded )
x_strcat( s_Work,"mul r0,t0,v0\n" );
if( Path.Flags.bTexelOnly )
// todo: rename bTexelOnly to bAlphakill or something
x_strcat( s_Work,"mov r0,t1\n" );
if( Path.Flags.bShadow )
x_strcat( s_Work,"mov r0,c0\n" );
if( Path.Flags.bFogPass )
x_strcat( s_Work,"mov r0.rgb,c0.rgb + mov r0.a,t0.a\n" );
if( Path.Flags.bFogNoPpl )
x_strcat( s_Work,"mov r0.rgb,c0.rgb + mov r0.a,v1.a\n" );
if( Path.Flags.oT3_Mask )
x_strcat( s_Work,"mov r0,t3\n" );
if( Path.Flags.oT3_Proj )
x_strcat( s_Work,"mov_d2 r0,t3.b\n" );
// second pass cases ..............................................
if( Path.Flags.bLitProjPunchthru )
x_strcat( s_Work,"mov_d2 r0,t3.b\n" );
if( Path.Flags.bShadowZFog )
x_strcat( s_Work,"mov r0.rgb,v1_sat + mov r0.a,c0.a\n" );
if( Path.Flags.bApplyZFog )
x_strcat( s_Work,"mov r0,v1_sat\n" );
if( Path.Flags.bCloth )
x_strcat( s_Work,"mul r0.rgb,v0.rgb,t0.rgb\n" );
if( Path.Flags.bFogPunchthru )
x_strcat( s_Work,"mad r0,t0,v0,v1_sat\n" );
// add shader body ................................................
if(Path.iLink[ 7])LoadShader( s_BxT_Name[Path.iLink[ 7]].pName ); // must be first
if(Path.iLink[ 0])LoadShader( s_Mat_Name[Path.iLink[ 0]].pName );
if(Path.iLink[ 1])LoadShader( s_Det_Name[Path.iLink[ 1]].pName );
if(Path.iLink[ 2])LoadShader( s_Blr_Name[Path.iLink[ 2]].pName );
if(Path.iLink[ 4])LoadShader( s_Dis_Name[Path.iLink[ 4]].pName );
if(Path.iLink[ 5])LoadShader( s_Glw_Name[Path.iLink[ 5]].pName );
if(Path.iLink[ 6])LoadShader( s_Blt_Name[Path.iLink[ 6]].pName );
if(Path.iLink[ 8])LoadShader( s_Pur_Name[Path.iLink[ 8]].pName );
if(Path.iLink[ 9])LoadShader( s_Dec_Name[Path.iLink[ 9]].pName );
if(Path.iLink[10])LoadShader( s_Ppl_Name[Path.iLink[10]].pName );
if(Path.iLink[12])LoadShader( s_Ppt_Name[Path.iLink[12]].pName );
if(Path.iLink[ 3])LoadShader( s_Sha_Name[Path.iLink[ 3]].pName );
// Diffuse per poly code ..........................................
if( Path.Flags.bDiffusePerPolyEnvAdd )
{
x_strcat( s_Work,"mad r0.rgb,t1.rgb,c2.a,t0.rgb\n" );
}
if( Path.Flags.bDiffusePerPolyEnv )
{
// TODO: Is this material used? If so, then we need to add
// support for it.
}
// final combiners ................................................
if( Path.Flags.xfc_Sat )
x_strcat( s_Work,"mov_x2 r0.rgb,r0.rgb\n" );
if( Path.Flags.xfc_Half )
// Halve both rgb and a so post effect doesn't screw up glow
x_strcat( s_Work,"mov_d2 r0.rgb,r0.rgb\n" );
if( Path.Flags.bPerPixelLitPunchthru )
// Needs at least one blend instruction
x_strcat( s_Work,"mov r0.rgb,t3.rgb + mov r0.a,v1.a\n" );
else
{
if( Path.Flags.xfc_Fog )
x_strcat( s_Work,"xfc v1.a,v1,r0,zero,zero,zero,r0.a\n" );
if( Path.Flags.xfc_Std )
x_strcat( s_Work,"xfc zero,zero,r0,zero,zero,zero,r0.a\n" );
}
}
else
{
x_strcat( s_Work,"mov r0,v0\n" );
x_strcat( s_Work,"xfc zero,zero,r0,zero,zero,zero,r0.a\n" );
}
}
Path.compile( s_Work,Shader );
// add new shader object **********************************************
ASSERT( ps::Count < MAX_SHADERS );
ps::Details[ps::Count++].Flags.Mask = Path.Flags.Mask;
ps::Size += Shader.Microcode.size;
x_qsort(
ps::Details,
ps::Count,
sizeof( ps::detail ),
PSCmp
);
return GetShader( Path,pShader );
#else
pShader = NULL;
return false;
#endif
}
///////////////////////////////////////////////////////////////////////////////
static void GetShader( ps::path& Path )
{
#if COMPILE_SHADERS
shader* pShader; GetShader( Path,pShader );
#endif
}
///////////////////////////////////////////////////////////////////////////
static s32 CmpShader( const void* pl,const void* pr )
{
return( ((vs::detail*)pl)->Flags.Mask > ((vs::detail*)pr)->Flags.Mask );
}
///////////////////////////////////////////////////////////////////////////////
static bool GetShader( vs::path& Path,shader*& pShader )
{
// binary search for shader **********************************************
s32 i=search( Path.Flags,vs::Details,vs::Count );
if( i>-1 )
{
#ifdef X_DEBUG
ASSERT( vs::Details[i].Flags.Mask==Path.Flags.Mask );
if( i<MAX_SHADERS-1 )ASSERT( vs::Details[i].Flags.Mask != vs::Details[i+1].Flags.Mask );
if( i>1 )ASSERT( vs::Details[i].Flags.Mask != vs::Details[i-1].Flags.Mask );
#endif
pShader = &vs::Details[i].Shader;
return true;
}
// build shader script ***************************************************
#if COMPILE_SHADERS
shader& Shader = vs::Details[vs::Count].Shader;
{
x_memset( s_Work,0,sizeof(s_Work) );
x_strcpy( s_Work,"xvs.1.1\n\n" );
// main sequence fragments ............................................
if(Path.iLink[0])LoadShader( s_oPos_Name[Path.iLink[0]].pName );
if(Path.iLink[6])LoadShader( s_oLm__Name[Path.iLink[6]].pName );
if(Path.iLink[1])LoadShader( s_oD0__Name[Path.iLink[1]].pName );
if(Path.iLink[2])LoadShader( s_oT0__Name[Path.iLink[2]].pName );
if(Path.iLink[3])LoadShader( s_oT3__Name[Path.iLink[3]].pName );
if(Path.iLink[4])LoadShader( s_oSt__Name[Path.iLink[4]].pName );
if(Path.iLink[5])LoadShader( s_oSi__Name[Path.iLink[5]].pName );
if(Path.iLink[7])LoadShader( s_oD1__Name[Path.iLink[7]].pName );
if(Path.iLink[8])LoadShader( s_oBlt_Name[Path.iLink[8]].pName );
// handle detail map ..................................................
if( Path.Flags.bDetailMap )
x_strcat( s_Work,"mul oT2.xy,v2,c-9.zw\n" );
if( Path.Flags.bPunchthru || Path.Flags.oT3_Mask )
x_strcat( s_Work,"mov oT3.xy,v2.xy\n" );
}
Path.compile( s_Work,Shader );
// add new shader object **************************************************
ASSERT( vs::Count < MAX_SHADERS );
vs::Details[vs::Count++].Flags.Mask = Path.Flags.Mask;
vs::Size += Shader.Microcode.size;
x_qsort(
vs::Details,
vs::Count,
sizeof( vs::detail ),
PSCmp
);
return GetShader( Path,pShader );
#else
pShader = NULL;
return false;
#endif
}
///////////////////////////////////////////////////////////////////////////////
static void GetShader( vs::path& Path )
{
#if COMPILE_SHADERS
shader* pShader; GetShader( Path,pShader );
#endif
}
//////////////////////////////////////////////////////////////////////////////
__declspec( naked )__forceinline s32 __fastcall BitScan( u32 Bits )
{
__asm
{
test ecx,ecx
jne ou
mov eax,ecx
ret
ou: bsf eax,ecx
inc eax
ret
}
}
//////////////////////////////////////////////////////////////////////////////
vs::path::path( vs::desc& VSDesc )
{
iLink[0]=BitScan( VSDesc.oPos );
iLink[1]=BitScan( VSDesc.oD0 );
iLink[2]=BitScan( VSDesc.oT0 );
iLink[3]=BitScan( VSDesc.oT3 );
iLink[4]=BitScan( VSDesc.oSt );
iLink[5]=BitScan( VSDesc.iShadow );
iLink[6]=BitScan( VSDesc.iLightMap );
iLink[7]=BitScan( VSDesc.oD1 );
iLink[8]=BitScan( VSDesc.oBlt );
Flags.Mask = VSDesc.Mask;
}
//////////////////////////////////////////////////////////////////////////////
static u32 GetMatID( ps::desc& PSDesc )
{
return u32( PSDesc.MaterialID<<(PSDesc.bProj*8) );
}
//////////////////////////////////////////////////////////////////////////////
ps::path::path( ps::desc& PSDesc )
{
id = GetMatID( PSDesc );
iLink[ 0]=BitScan( id );
iLink[ 1]=BitScan( PSDesc.bDetailMap );
iLink[ 2]=BitScan( PSDesc.bDepthBlur );
iLink[ 3]=BitScan( PSDesc.iShadow );
iLink[ 4]=BitScan( PSDesc.Distortion );
iLink[ 5]=BitScan( PSDesc.bForcedGlow );
iLink[ 6]=BitScan( PSDesc.BltId );
iLink[ 7]=BitScan( PSDesc.bRgbaByTex0 );
iLink[ 8]=BitScan( PSDesc.bTexelModded );
iLink[ 9]=BitScan( PSDesc.Decal );
iLink[10]=BitScan( PSDesc.LightMap )&3;
iLink[12]=BitScan( PSDesc.bPerPixelLitPunchthru );
iLink[11]=BitScan( PSDesc.XfcId );
ts = 0;
ts |= s_Mat_Name[iLink[ 0]].Flags;
ts |= s_Det_Name[iLink[ 1]].Flags;
ts |= s_Blr_Name[iLink[ 2]].Flags;
ts |= s_Sha_Name[iLink[ 3]].Flags;
ts |= s_Dis_Name[iLink[ 4]].Flags;
ts |= s_Glw_Name[iLink[ 5]].Flags;
ts |= s_Blt_Name[iLink[ 6]].Flags;
ts |= s_BxT_Name[iLink[ 7]].Flags;
ts |= s_Pur_Name[iLink[ 8]].Flags;
ts |= s_Dec_Name[iLink[ 9]].Flags;
ts |= s_Ppl_Name[iLink[10]].Flags;
ts |= s_Ppl_Name[iLink[12]].Flags;
Flags.Mask = PSDesc.Mask;
}
//////////////////////////////////////////////////////////////////////////////
static void SetShader( vs::desc& VSFlags,XGBuffer& Microcode )
{
s32 o = vs::Count++;
s32 i = search( VSFlags,vs::Details,o );
ASSERT( i==-1 );
{
u32* pDesc=
VSFlags.oPos_Rigid
? (u32*)s_dwRigidDesc
: (u32*)s_dwSkinDesc
;
vs::detail& Detail = vs::Details[o];
Detail.Flags.Mask = VSFlags.Mask;
Detail.Shader.shader::shader(
SASMT_VERTEXSHADER,
Microcode,
pDesc
);
x_qsort(
vs::Details,
vs::Count,
sizeof( vs::detail ),
CmpShader
);
}
}
//////////////////////////////////////////////////////////////////////////////
static void SetShader( ps::desc& PSFlags,XGBuffer& Microcode )
{
s32 o = ps::Count++;
s32 i = search( PSFlags,ps::Details,o );
ASSERT( i==-1 );
{
ps::detail& Detail = ps::Details[o];
Detail.Flags.Mask = PSFlags.Mask;
Detail.Shader.shader::shader(
SASMT_PIXELSHADER,
Microcode,
NULL
);
x_qsort(
ps::Details,
ps::Count,
sizeof( ps::detail ),
CmpShader
);
}
}
///////////////////////////////////////////////////////////////////////////////
shader_mgr::shader_mgr( void )
{
// clear flags ............................................................
x_memset( this,0,sizeof( shader_mgr ));
// Allocate PIP texture ...................................................
m_PIP_Texture = g_TextureFactory.Create( "kPIP" , // Resource name
0 , // Pitch
PropW(700) , // Width
PropH(700) , // Height
m_PIP_Target , // Surface
D3DFMT_LIN_A8R8G8B8 ); // Diffuse buffer format
m_VRAM_PipID = vram_Register( m_PIP_Texture );
m_pPipData = (void*)(m_PIP_Target->Data|0x80000000);
// load cached shaders ....................................................
#if !PRELOAD_SHADERS
{
X_FILE* hFile;
// load pixel shader **************************************************
hFile = x_fopen( xfs( "%s\\shaders.psl",SHADER_ROOT),"r" );
if( !hFile )
{
// blue screen of death: indicates shader not found
g_pd3dDevice->Clear( 0,0,D3DCLEAR_TARGET,D3DCOLOR_RGBA( 0,0,128,0),0.0f,0 );
g_pd3dDevice->Present( 0,0,0,0 );
__asm int 3
}
else
{
// read inventory of details ......................................
x_fread( &ps::Count,sizeof(u32),1,hFile );
x_fread( &ps::Size ,sizeof(u32),1,hFile );
x_fread( ps::Details,sizeof(ps::detail),ps::Count,hFile );
u32* InfoTable = new u32 [ps::Count*2];
x_fread( InfoTable,sizeof(u32)*2,ps::Count,hFile );
ps::pSpace = (u8*)x_malloc(ps::Size);
x_fread( ps::pSpace,ps::Size,1,hFile );
x_fclose( hFile );
// hookup all the shaders .........................................
u32* pInfo = InfoTable;
for( u32 i=0;i<ps::Count;i++ )
{
XGBuffer Microcode;
Microcode.pData = ps::pSpace+(pInfo++)[0];
Microcode.size = (pInfo++)[0];
Microcode.refCount = 0;
ps::Details[i].Shader.shader::shader(
SASMT_PIXELSHADER,
Microcode,
NULL
);
}
delete[]InfoTable;
}
// load vertex shader *************************************************
hFile = x_fopen( xfs( "%s\\shaders.vsl",SHADER_ROOT),"r" );
if( !hFile )
{
// green screen of death: indicates shader not found
g_pd3dDevice->Clear( 0,0,D3DCLEAR_TARGET,D3DCOLOR_RGBA( 0,128,0,0),0.0f,0 );
g_pd3dDevice->Present( 0,0,0,0 );
__asm int 3
}
else
{
// read inventory of details ......................................
x_fread( &vs::Count,sizeof(u32),1,hFile );
x_fread( &vs::Size ,sizeof(u32),1,hFile );
x_fread( vs::Details,sizeof(vs::detail),vs::Count,hFile );
u32* InfoTable = new u32 [vs::Count*2];
x_fread( InfoTable,sizeof(u32)*2,vs::Count,hFile );
vs::pSpace = (u8*)x_malloc(vs::Size);
x_fread( vs::pSpace,vs::Size,1,hFile );
x_fclose( hFile );
// hookup all the shaders .........................................
u32* pInfo = InfoTable;
for( u32 i=0;i<vs::Count;i++ )
{
XGBuffer Microcode;
Microcode.pData = vs::pSpace+(pInfo++)[0];
Microcode.size = (pInfo++)[0];
Microcode.refCount = 0;
u32* pDesc =
vs::Details[i].Flags.oPos_Rigid
? (u32*)s_dwRigidDesc
: (u32*)s_dwSkinDesc
;
vs::Details[i].Shader.shader::shader(
SASMT_VERTEXSHADER,
Microcode,
pDesc
);
}
delete[]InfoTable;
}
}
#endif
}
///////////////////////////////////////////////////////////////////////////////
shader_mgr::~shader_mgr( void )
{
}
///////////////////////////////////////////////////////////////////////////////
s32 shader_mgr::SetPerPixelPointLights( const lights* pLights,const matrix4& L2W )
{
s32 iResult = 0;
{
matrix4 Mtx( L2W );
Mtx.InvertRT( );
f32 Enabled[4]={0,0,0,0};
vector4 Const[6];
vector4 Color[4];
x_memset( &Const,0,sizeof( Const ));
x_memset( &Color,0,sizeof( Color ));
s32 n = pLights ? pLights->Count:0;
if( n )
{
ASSERT( n<=3 );
iResult = n;
for( s32 i=0;i<n;i++ )
{
lights::point& Light = pLights->pPoint[i];
f32 R = Light.Pos.GetW();
{
Light.Pos.GetW() = 1.0f;
Const[i*2+0] = Mtx.Transform( Light.Pos );
Const[i*2+0].GetW() = R;
Light.Pos.GetW() = R;
Const[i*2+1].GetX() = 1.0f/(2*R); // 1/2r
Const[i*2+1].GetY() = 1.0f/(2*R);
Const[i*2+1].GetZ() = 1.0f/(2*R);
Const[i*2+1].GetW() = R;
}
Color[i] = Light.Col;
Color[i].GetW()=1.0f;
Enabled[i] = 1.0f;
}
}
else
{
Color[0].GetW()=1.0f;
}
g_pd3dDevice->SetVertexShaderConstant( 84,Const ,6 );
g_pd3dDevice->SetVertexShaderConstant( -3,Enabled,1 );
static f32 Scale=0.75f;
Color[3].GetW()=Scale;
g_pd3dDevice->SetPixelShaderConstant( 0,Color,4 );
}
return iResult;
}
///////////////////////////////////////////////////////////////////////////
s32 shader_mgr::SetPointLights( const lights* pLights,const matrix4& L2W )
{
ASSERT( pLights );
s32 iResult = 0;
{
matrix4 Mtx( L2W );
Mtx.InvertRT( );
vector4 Const[6];
x_memset( &Const,0,sizeof( Const ));
f32 Extra[4]=
{
0.5f,
0.0f,
0.0f,
1.0f
};
s32 n = pLights->Count;
if( n )
{
ASSERT( n<=3 );
iResult = n;
for( s32 i=0;i<n;i++ )
{
lights::point& Light = pLights->pPoint[i];
{
f32 R = Light.Pos.GetW();
Light.Pos.GetW() = 1.0f;
Const[i*2+0] = Mtx.Transform( Light.Pos );
Const[i*2+0].GetW() = R;
Light.Pos.GetW() = R;
}
f32 R = Light.Col.GetX();
f32 G = Light.Col.GetY();
f32 B = Light.Col.GetZ();
Const[i*2+1].GetX() = R;
Const[i*2+1].GetY() = G;
Const[i*2+1].GetZ() = B;
Const[i*2+1].GetW() = 1.0f;
}
g_pd3dDevice->SetVertexShaderConstant( 84,Const,6 );
g_pd3dDevice->SetVertexShaderConstant( -1,Extra,1 );
}
}
return iResult;
}
//////////////////////////////////////////////////////////////////////////////
//
// The matrices for the direction and colour are loaded transposed.
void shader_mgr::SetDirLights( const lights* pLights )
{
ASSERT( pLights );
{
matrix4 Mtx[2];
x_memset( &Mtx,0,sizeof( Mtx ));
s32 i,n = pLights->Count;
ASSERT( n<=4 );
for( i=0;i<n;i++ )
{
lights::dir& Light = pLights->pDir[i];
Mtx[0](i,0)=Light.Dir.GetX();
Mtx[0](i,1)=Light.Dir.GetY();
Mtx[0](i,2)=Light.Dir.GetZ();
f32 R = Light.Col.GetX();
f32 G = Light.Col.GetY();
f32 B = Light.Col.GetZ();
Mtx[1](0,i)=R;
Mtx[1](1,i)=G;
Mtx[1](2,i)=B;
Mtx[1](3,i)=0.0f;
}
g_pd3dDevice->SetVertexShaderConstant( 84,Mtx,8 );
}
}
///////////////////////////////////////////////////////////////////////////////
void shader_mgr::Begin( void )
{
// Set big constant mode **************************************************
g_pd3dDevice->SetShaderConstantMode( D3DSCM_192CONSTANTS );
m_bFullControl = TRUE;
m_VSFlags.clear();
m_PSFlags.clear();
// Fog effects( x=0 full fog } ********************************************
g_RenderState.Set( D3DRS_FOGCOLOR ,D3DCOLOR_RGBA( 0,0,0,0 ));
g_RenderState.Set( D3DRS_FOGTABLEMODE,D3DFOG_NONE );
g_RenderState.Set( D3DRS_FOGENABLE ,FALSE );
}
//////////////////////////////////////////////////////////////////////////////
void shader_mgr::SetCustomFogPalette( const texture::handle& Texture,xbool bSwitchNow,s32 PaletteIndex )
{
(void)Texture;
(void)bSwitchNow;
(void)PaletteIndex;
if( SWITCH_USE_FOG )
{
s32 i;
ASSERT( PaletteIndex < 4 && PaletteIndex >= 0 );
m_FogIndex = PaletteIndex;
static const u32 W = 8;
static const u32 H = 8;
u8 FogColour[W*H*4];
// If we don't have a valid texture, then fade to zero alpha
texture* pTex = Texture.GetPointer();
if( pTex == NULL )
{
x_memset( FogColour, 0, sizeof(FogColour) );
}
else
{
s32 VRAMID = pTex->m_Bitmap.GetVRAMID();
texture_factory::handle Handle = vram_GetSurface( VRAMID );
u8* pColor = (u8*)Handle->GetPtr();
// Otherwise unswizzle the image
ASSERT( pTex->m_Bitmap.GetWidth ()==W );
ASSERT( pTex->m_Bitmap.GetHeight()==H );
XGUnswizzleRect( pColor,W,H,NULL,FogColour,W*4,NULL,4 );
}
// now do the transitioning
u32 ColorTotal[4] = { 0, 0, 0, 0 };
u8* pSrc = FogColour;
u8* pDst = m_FogPalette[PaletteIndex];
if( bSwitchNow )
{
for( i = 0; i < W*H*4; i+= 4 )
{
s32 j;
for( j = 0; j < 4; j++ )
{
pDst[j] = pSrc[j];
ColorTotal[j] += pDst[j];
}
pSrc += 4;
pDst += 4;
}
}
else
{
for( i = 0; i < W*H*4; i+=4 )
{
s32 j;
for( j = 0; j < 4; j++ )
{
if( pSrc[j] > pDst[j] )
pDst[j]++;
else if( pSrc[j] < pDst[j] )
pDst[j]--;
ColorTotal[j] += pDst[j];
}
pSrc += 4;
pDst += 4;
}
}
// Store out the average color. Ideally we'd use a polynomial for that, too, but
// the average color will be much more efficient.
ColorTotal[0] /= (W*H);
ColorTotal[1] /= (W*H);
ColorTotal[2] /= (W*H);
ColorTotal[3] /= (W*H);
s_FogColour[PaletteIndex].Set(
f32(ColorTotal[2])/255.0f,
f32(ColorTotal[1])/255.0f,
f32(ColorTotal[0])/255.0f,
f32(ColorTotal[3])/255.0f );
// store out the useful constants that will be used in the math below
static const f32 PS2ZConst = 0.5f * (f32)((s32)1<<19);
const view* pView = eng_GetView();
f32 ZNear, ZFar;
pView->GetZLimits( ZNear, ZFar );
f32 Numer = (2.0f * PS2ZConst * ZNear * ZFar) / (ZFar - ZNear);
f32 DenomOffset = -PS2ZConst + (PS2ZConst * (ZFar + ZNear)) / (ZFar - ZNear);
f32 XboxQ = ZFar / (ZFar - ZNear);
f32 PS2ScreenZ, XboxScreenZ;
static f32 Scale = 1/16.0f;
// figure out where fog starts on ps2 and map that into the xbox z range
f32 PS2ZValue = (f32)(0xffff) * Scale;
f32 Denom = PS2ZValue + DenomOffset;
ASSERT( x_abs(Denom) > 0.001f );
f32 ViewZValue = Numer / Denom;
f32 XBoxZValue = ViewZValue * XboxQ - ZNear * XboxQ;
ASSERT( ViewZValue > 0.001f );
// XBoxZValue /= ViewZValue;
s_FogStart = XBoxZValue;
// So for each texel color, figure out where that maps to in the ps2 screen space.
// Work backwards to figure out the z value in view space, then put it into xbox
// clip space. This is what we will feed into the polynomial approximation for
// the fog. f(z) = a + b*z + c*(z^2) + d*(z^3)
least_squares AlphaApprox;
AlphaApprox.Setup(3);
static const f32 NSamples = 512.0f;
const f32 StepSize = (ZFar-ZNear)/NSamples;
for( f32 ViewZ = ZNear; ViewZ <= ZFar; ViewZ += StepSize )
{
// Calculate Z in PS2 space ***************************************
PS2ScreenZ = (ViewZ*(ZFar+ZNear)/(ZFar-ZNear));
PS2ScreenZ -= ((2.0f*ZFar*ZNear)/(ZFar-ZNear));
PS2ScreenZ /= ViewZ;
PS2ScreenZ *= -PS2ZConst;
PS2ScreenZ += PS2ZConst;
// Calculate Z in Xbox space **************************************
XboxScreenZ = (ViewZ*XboxQ)-(ZNear*XboxQ);
// XboxScreenZ /= ViewZ;
// Get colour from bitmap *****************************************
f32 A;//,R,G,B;
u32 UPS2SZ = u32(PS2ScreenZ*16.0f+0.5f);
if( UPS2SZ <= 0xFFFF )
{
u32 ClutIX = (((UPS2SZ >> 8) & 0x000000FF)/4);
A = f32(m_FogPalette[PaletteIndex][ClutIX*4+3])/255.0f;
}
else
{
A = 0.0f;
}
// Approximations *************************************************
AlphaApprox.AddSample( XboxScreenZ,A );
}
// Solve the least-squares polynomial approximation and store the
// coefficients out for use in the shader.
if( !AlphaApprox.Solve() )
{
AlphaApprox.SetCoeff( 0, f32(FogColour[3]) / 255.0f );
AlphaApprox.SetCoeff( 1, 0.0f );
AlphaApprox.SetCoeff( 2, 0.0f );
AlphaApprox.SetCoeff( 3, 0.0f );
}
m_FogConst[PaletteIndex].Set( AlphaApprox.GetCoeff(0),
AlphaApprox.GetCoeff(1),
AlphaApprox.GetCoeff(2),
AlphaApprox.GetCoeff(3) );
}
}
//////////////////////////////////////////////////////////////////////////////
void shader_mgr::End( void )
{
g_pd3dDevice->SetShaderConstantMode( D3DSCM_96CONSTANTS );
g_RenderState.Set( D3DRS_SPECULARENABLE,FALSE );
g_RenderState.Set( D3DRS_FOGENABLE, FALSE );
m_bFullControl = FALSE;
m_PSFlags.clear();
m_VSFlags.clear();
for( s32 i=0;i<4;i++ )
g_Texture.Clear( i );
}
//////////////////////////////////////////////////////////////////////////////
void shader_mgr::SetPixelShader( shader_style Style )
{
vs::desc VSFlags;
ps::desc PSFlags;
VSFlags.clear();
PSFlags.clear();
switch( Style )
{
case kREMOVE:
g_pd3dDevice->SetPixelShader( NULL );
m_PSFlags.clear();
return;
case kCAST_SHADOW:
PSFlags.bShadow = true;
break;
case kDISTORT_BACK:
PSFlags.bDiffuse = true;
PSFlags.xfc_Std = true;
break;
case kSHADOW_BLUR:
PSFlags.bTexelModded = true;
break;
case kFINISH_FRAME:
PSFlags.bBltFinal = true;
break;
case kT0_MASK_T1:
PSFlags.bTexelOnly = true;
PSFlags.xfc_Std = true;
break;
case kFULL_POST_EFFECT:
PSFlags.bBltPostFx = true;
break;
case kDIFFUSE_SAT:
PSFlags.bBltx2 = true;
break;
case kDIFFUSE:
PSFlags.bBlt = true;
break;
}
Link( 0,NULL,VSFlags,NULL,PSFlags,0 );
}
//////////////////////////////////////////////////////////////////////////////
static vector4 s_C0( 0.0f,0.0f,0.0f,1.0f );
static vector4 s_C1( 0.5f,0.5f,0.5f,0.5f );
static vector4 s_C2( 0.0f,0.0f,0.0f,0.0f );
static vector4 s_C3( 0.0f,0.0f,0.0f,0.0f );
const vector4 s_C5( 0.0f,0.0f,0.0f,1.0f );
static void LoadConstants( ps::desc PSFlags,f32 FixedAlpha )
{
// Diffuse consts /////////////////////////////////////////////////////////
if( PSFlags.bPerPixelLitPunchthru )
{
s_C0.GetW()=0.0f;
const f32 Scalar = 0.5f/255.0f;
s_C0.GetZ()=0.5f-Scalar; // adjust for rounding error in pixel shader hardware
s_C1.GetW()=1.0f;
}
else
{
if( PSFlags.bShadow ||
PSFlags.bDiffuse &&
! PSFlags.bPerPixelLitProj &&
! g_pPipeline->m_bAlphaBlend )
{
s_C0.GetW()=0.0f;
s_C0.GetZ()=0.0f;
}
else
{
s_C0.GetW()=1.0f;
s_C0.GetZ()=0.0f;
}
s_C1.GetW()=0.5f;
}
// Alpha fading ///////////////////////////////////////////////////////////
g_pd3dDevice->SetPixelShaderConstant( 5,s_C5,1 );
// Env mapping ////////////////////////////////////////////////////////////
if( !(PSFlags.bDiffusePerPixelEnv || PSFlags.bDiffusePerPixelEnvAdd) && (PSFlags.bAlphaPerPolyEnv) )
{
s_C0.GetW()=FixedAlpha;
s_C0.GetZ()=1.0f;
}
if( PSFlags.bDiffusePerPolyEnvAdd )
{
f32 Const[4] = { 0.0f,0.0f,0.0f,FixedAlpha };
g_pd3dDevice->SetPixelShaderConstant( 2,Const,1 );
}
// Shadow consts //////////////////////////////////////////////////////////
if( PSFlags.oT1Shadow || PSFlags.oT2Shadow || PSFlags.oT3Shadow )
{
s_C0.GetW()=0.5f;
}
g_pd3dDevice->SetPixelShaderConstant( 0,&s_C0,1 );
g_pd3dDevice->SetPixelShaderConstant( 1,&s_C1,1 );
// Forced glows ///////////////////////////////////////////////////////////
if( PSFlags.bForcedGlow )
{
static f32 Ambient[4]={ 1.0f,1.0f,1.0f,1.0f };
g_pd3dDevice->SetPixelShaderConstant( 6,Ambient,1 );
g_RenderState.Set(
D3DRS_COLORWRITEENABLE,
D3DCOLORWRITEENABLE_ALL
);
}
// Detail map consts //////////////////////////////////////////////////////
if( PSFlags.bDetailMap )
{
static const f32 Int = 4.0f;
s_C2.GetW()=Int;
}
}
///////////////////////////////////////////////////////////////////////////////
u32 shader_mgr::Link( vs::desc& VSFlags,ps::desc& PSFlags,bool bAllocTop )
{
m_CanContinue = true;
u32 Address = 0;
// SPEED UP Z-BUFFER WRITES ***********************************************
if( g_RenderState.Get(D3DRS_COLORWRITEENABLE)==0 )
m_PSFlags.clear();
// COMPILE AND/OR LINK VERTEX SHADERS *************************************
if( VSFlags.Mask )
{
// if flags change relink ---------------------------------------------
if( VSFlags.Mask != m_VSFlags.Mask )
{
shader* pShader; if( GetShader( vs::path( VSFlags ),pShader ))
{
if( bAllocTop )
{
u32 ShaderSize = *((u32*)pShader->Microcode.pData)>>16;
Address = 136-ShaderSize;
}
// double paranoid shader verification ........................
#ifdef X_DEBUG
{
s32 i=search( VSFlags,vs::Details,vs::Count );
ASSERT( vs::Details[i].Flags.Mask==VSFlags.Mask );
}
#endif
// Load stitched shader .......................................
ASSERT( pShader->Handle );
g_pd3dDevice->LoadVertexShaderProgram(( const DWORD* )pShader->Microcode.pData,Address );
g_pd3dDevice->SelectVertexShader( pShader->Handle,Address );
}
else
{
m_CanContinue = false;
}
}
// upload important constants -----------------------------------------
static f32 Lum = 0.05f;
g_pd3dDevice->SetVertexShaderConstant( -50,vector4( Lum,Lum,Lum,0.0f ),1 );
if( VSFlags.oD0_WhiteLight )
{
vector4 Light(
m_WhiteConst,
m_WhiteConst,
m_WhiteConst,
m_WhiteConst
);
g_pd3dDevice->SetVertexShaderConstant( -7,Light,1 );
}
// remember these flags -----------------------------------------------
m_VSFlags.Mask = VSFlags.Mask;
}
else
{
m_VSFlags.clear();
g_pd3dDevice->SetVertexShader( NULL );
}
// COMPILE AND/OR LINK PIXEL SHADERS **************************************
if( PSFlags.Mask )
{
if( PSFlags.Mask != m_PSFlags.Mask )
{
// special force diffuse case -------------------------------------
if( (!PSFlags.MaterialID) && (PSFlags.bForcedGlow) )
{
PSFlags.bDiffuse = true;
}
// get pixel shader object ----------------------------------------
shader* pShader; if( GetShader( ps::path( PSFlags ),pShader ))
{
ASSERT( pShader->Handle );
g_pd3dDevice->SetPixelShader( pShader->Handle );
// double paranoid shader verification ........................
#ifdef X_DEBUG
{
s32 i=search( PSFlags,ps::Details,ps::Count );
ASSERT( ps::Details[i].Flags.Mask==PSFlags.Mask );
}
#endif
}
else
{
m_CanContinue = false;
}
// always remember flags ------------------------------------------
m_PSFlags = PSFlags;
}
LoadConstants( PSFlags,m_FixedAlpha );
}
else
{
g_pd3dDevice->SetPixelShader( NULL );
m_PSFlags.clear();
}
// DEFAULT TO DIFFUSE (This is bad) ****************************************
if( !m_CanContinue )
{
// Construct diffuse only material ....................................
ps::desc PS; PS.clear();
vs::desc VS; VS.clear();
g_TextureStageState.Set( 0,D3DTSS_ALPHAKILL,D3DTALPHAKILL_DISABLE );
g_RenderState.Set( D3DRS_ALPHABLENDENABLE,FALSE );
VS.oPos = m_VSFlags.oPos;
VS.oT0_Normal = true;
PS.bDiffuse = true;
PS.xfc_Std = true;
// Grab shader and link with it .......................................
Address = Link( VS,PS );
}
return Address;
}
///////////////////////////////////////////////////////////////////////////////
u32 shader_mgr::Link( u32 MtxCount,const matrix4* pMtx,vs::desc& VSFlags,const vector4* pAmbient,ps::desc& PSFlags,bool bAllocTop )
{
u32 Address = Link( VSFlags,PSFlags,bAllocTop );
if( VSFlags.Mask )
{
s32 ConstAddr = 96;
u32 i;
for( i=0;i<MtxCount;i++ )
{
ConstAddr-=4;
ASSERT( ConstAddr >= 83 );
matrix4 Mtx( pMtx[i] );
g_pd3dDevice->SetVertexShaderConstant( ConstAddr,&Mtx,4 );
}
if( !pAmbient )
{
const vector4 Void( 1.0f,1.0f,1.0f,1.0f );
pAmbient = &Void;
}
g_pd3dDevice->SetVertexShaderConstant( 83,pAmbient,1 );
}
return Address;
}
//=============================================================================
void shader_mgr::ConstSanityCheck( void )
{
//#ifdef X_DEBUG
// f32 CmpFogTable[4*MAX_FOG_SIZE];
// g_pd3dDevice->GetVertexShaderConstant( -94,CmpFogTable,MAX_FOG_SIZE );
// ASSERT( !x_memcmp( CmpFogTable,m_FogConst,4*MAX_FOG_SIZE ));
//#endif
}
//=============================================================================
s32 shader_mgr::InsertShadow( ps::desc& PSFlags,texture_factory::handle Handle )
{
s32 iShadow;
// find first unused stage ................................
ps::path Path( PSFlags );
{
if( !(Path.ts & kTEX0) ) iShadow=0; else
if( !(Path.ts & kTEX1) ) iShadow=1; else
if( !(Path.ts & kTEX2) ) iShadow=2; else
if( !(Path.ts & kTEX3) ) iShadow=3; else return 0;
}
// add sampler statements .................................................
g_TextureStageState.Set( iShadow, D3DTSS_ALPHAKILL, D3DTALPHAKILL_DISABLE );
g_TextureStageState.Set( iShadow, D3DTSS_ADDRESSU , D3DTADDRESS_CLAMP );
g_TextureStageState.Set( iShadow, D3DTSS_ADDRESSV , D3DTADDRESS_CLAMP );
g_TextureStageState.Set( iShadow, D3DTSS_ADDRESSW , D3DTADDRESS_CLAMP );
g_Texture .Set( iShadow, Handle );
return iShadow;
}
//=============================================================================
//=============================================================================
// Shader methods
//=============================================================================
//=============================================================================
//////////////////////////////////////////////////////////////////////////////
shader::shader( u32 dwType,XGBuffer& MC,u32* pShaderDesc ): Microcode( MC )
{
Id = dwType;
Size = Microcode.GetBufferSize( );
switch( Id )
{
case SASMT_VERTEXSHADER:
if( pShaderDesc )
{
LPDWORD pdwBuffer=(LPDWORD)Microcode.GetBufferPointer();
g_pd3dDevice->CreateVertexShader(
(DWORD*)pShaderDesc,
pdwBuffer,
(DWORD*)&Handle,
0
);
}
break;
case SASMT_PIXELSHADER:
{
const D3DPIXELSHADERDEF* pBuffer=( const D3DPIXELSHADERDEF* )Microcode.GetBufferPointer();
g_pd3dDevice->CreatePixelShader( pBuffer,(DWORD*)&Handle );
break;
}
default:
ASSERT(0);
break;
}
}
//////////////////////////////////////////////////////////////////////////////
shader::~shader( void )
{
}