summaryrefslogtreecommitdiff
path: root/Runtime/GfxDevice/d3d/VertexPipeD3D9.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/GfxDevice/d3d/VertexPipeD3D9.cpp')
-rw-r--r--Runtime/GfxDevice/d3d/VertexPipeD3D9.cpp705
1 files changed, 705 insertions, 0 deletions
diff --git a/Runtime/GfxDevice/d3d/VertexPipeD3D9.cpp b/Runtime/GfxDevice/d3d/VertexPipeD3D9.cpp
new file mode 100644
index 0000000..8a91f74
--- /dev/null
+++ b/Runtime/GfxDevice/d3d/VertexPipeD3D9.cpp
@@ -0,0 +1,705 @@
+#include "UnityPrefix.h"
+#include "VertexPipeD3D9.h"
+#include "ShaderGenerator.h"
+#include "D3D9Utils.h"
+#include "Runtime/GfxDevice/BuiltinShaderParams.h"
+#include "External/DirectX/builds/dx9include/d3dx9.h"
+#include <map>
+
+
+
+#define PRINT_VERTEX_PIPE_STATS 0
+
+#define PRINT_AMD_SHADER_ANALYZER_OUTPUT 0
+
+
+
+
+// GpuProgramsD3D.cpp
+ID3DXBuffer* AssembleD3DShader( const std::string& source );
+
+
+#if PRINT_AMD_SHADER_ANALYZER_OUTPUT
+void PrintAMDShaderAnalyzer( const std::string& source )
+{
+ const char* kPath = "C:\\Program Files\\AMD\\GPU ShaderAnalyzer 1.45\\GPUShaderAnalyzer.exe";
+ const char* kInputPath = "ShaderInput.txt";
+ const char* kOutputPath = "ShaderOutput.txt";
+ DeleteFileA(kInputPath);
+ DeleteFileA(kOutputPath);
+ FILE* fout = fopen(kInputPath, "wt");
+ fwrite(source.c_str(), source.size(), 1, fout);
+ fclose(fout);
+
+ std::string commandLine = std::string(kPath) + " " + kInputPath + " -Analyze " + kOutputPath + " -Module Latest -ASIC HD3870";
+
+ STARTUPINFOA si;
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+
+ PROCESS_INFORMATION pi;
+ ZeroMemory( &pi, sizeof(pi) );
+
+ if( CreateProcessA(
+ NULL, // name of executable module
+ (char*)commandLine.c_str(), // command line string
+ NULL, // process attributes
+ NULL, // thread attributes
+ FALSE, // handle inheritance option
+ 0, // creation flags
+ NULL, // new environment block
+ NULL, // current directory name
+ &si, // startup information
+ &pi ) ) // process information
+ {
+ WaitForSingleObject( pi.hProcess, INFINITE );
+ CloseHandle( pi.hProcess );
+ CloseHandle( pi.hThread );
+
+ FILE* fin = fopen(kOutputPath, "rt");
+ if( fin ) {
+ fseek(fin, 0, SEEK_END);
+ int length = ftell(fin);
+ fseek(fin, 0, SEEK_SET);
+ char* buffer = new char[length+1];
+ memset(buffer, 0,length+1);
+ fread(buffer, length, 1, fin);
+ fclose(fin);
+ }
+ }
+ //DeleteFileA(kInputPath);
+ //DeleteFileA(kOutputPath);
+}
+#endif
+
+
+
+static inline D3DCOLOR ColorToD3D( const float color[4] )
+{
+ return D3DCOLOR_RGBA( NormalizedToByte(color[0]), NormalizedToByte(color[1]), NormalizedToByte(color[2]), NormalizedToByte(color[3]) );
+}
+
+
+static void ResetDeviceVertexPipeStateD3D9 (IDirect3DDevice9* dev, const TransformState& state, const BuiltinShaderParamValues& builtins, const VertexPipeConfig& config, const VertexPipeDataD3D9& data)
+{
+ DebugAssertIf (!dev);
+
+ data.haveToResetDeviceState = false;
+
+ dev->SetTransform( D3DTS_WORLD, (const D3DMATRIX*)state.worldViewMatrix.GetPtr() );
+ Matrix4x4f dummyViewMatrix;
+ dummyViewMatrix.SetIdentity(); dummyViewMatrix.Get(2,2) = -1.0f;
+ dev->SetTransform( D3DTS_VIEW, (const D3DMATRIX*)dummyViewMatrix.GetPtr() );
+ dev->SetTransform( D3DTS_PROJECTION, (const D3DMATRIX*)builtins.GetMatrixParam(kShaderMatProj).GetPtr() );
+
+ dev->SetRenderState( D3DRS_COLORVERTEX, FALSE );
+
+ for( int i = 0; i < kMaxSupportedVertexLights; ++i )
+ dev->LightEnable( i, FALSE );
+
+ dev->SetRenderState( D3DRS_AMBIENT, 0 );
+ dev->SetRenderState( D3DRS_LIGHTING, FALSE );
+ dev->SetRenderState( D3DRS_SPECULARENABLE, FALSE );
+
+ for( int i = 0; i < kMaxSupportedTextureCoords; ++i ) {
+ dev->SetTextureStageState( i, D3DTSS_TEXCOORDINDEX, i );
+ dev->SetTextureStageState( i, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTSS_TCI_PASSTHRU );
+ }
+}
+
+void ResetVertexPipeStateD3D9 (IDirect3DDevice9* dev, TransformState& state, BuiltinShaderParamValues& builtins, VertexPipeConfig& config, VertexPipeDataD3D9& data, VertexPipePrevious& previous)
+{
+ config.Reset();
+ data.Reset();
+ state.Invalidate(builtins);
+ previous.Reset();
+
+ data.haveToResetDeviceState = true;
+ if (dev)
+ ResetDeviceVertexPipeStateD3D9 (dev, state, builtins, config, data);
+}
+
+
+void SetupFixedFunctionD3D9 (
+ IDirect3DDevice9* dev,
+ TransformState& state,
+ BuiltinShaderParamValues& builtins,
+ const VertexPipeConfig& config,
+ const VertexPipeDataD3D9& data,
+ VertexPipePrevious& previous,
+ bool vsActive, bool immediateMode)
+{
+ if (dev && data.haveToResetDeviceState)
+ ResetDeviceVertexPipeStateD3D9 (dev, state, builtins, config, data);
+
+ // matrices
+ if (!vsActive)
+ {
+ D3D9_CALL(dev->SetTransform( D3DTS_WORLD, (const D3DMATRIX*)state.worldViewMatrix.GetPtr() ));
+ }
+
+ // set color material first, then material, then color
+ if( config.colorMaterial != previous.config.colorMaterial )
+ {
+ if( config.colorMaterial != kColorMatDisabled )
+ {
+ D3DMATERIALCOLORSOURCE srcAmbient, srcDiffuse, srcEmission;
+ switch( config.colorMaterial )
+ {
+ case kColorMatEmission:
+ srcAmbient = D3DMCS_MATERIAL;
+ srcDiffuse = D3DMCS_MATERIAL;
+ srcEmission = D3DMCS_COLOR1;
+ break;
+ case kColorMatAmbientAndDiffuse:
+ srcAmbient = D3DMCS_COLOR1;
+ srcDiffuse = D3DMCS_COLOR1;
+ srcEmission = D3DMCS_MATERIAL;
+ break;
+ default:
+ return;
+ }
+ D3D9_CALL(dev->SetRenderState( D3DRS_AMBIENTMATERIALSOURCE, srcAmbient ));
+ D3D9_CALL(dev->SetRenderState( D3DRS_DIFFUSEMATERIALSOURCE, srcDiffuse ));
+ D3D9_CALL(dev->SetRenderState( D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL ));
+ D3D9_CALL(dev->SetRenderState( D3DRS_EMISSIVEMATERIALSOURCE, srcEmission ));
+ D3D9_CALL(dev->SetRenderState( D3DRS_COLORVERTEX, TRUE ));
+ }
+ else
+ {
+ D3D9_CALL(dev->SetRenderState( D3DRS_COLORVERTEX, FALSE ));
+ }
+ }
+
+ // material
+ if( !vsActive && config.hasLighting )
+ D3D9_CALL(dev->SetMaterial( &data.material ));
+
+ // lights
+ D3DLIGHT9 d3dlight;
+ d3dlight.Ambient.r = d3dlight.Ambient.g = d3dlight.Ambient.b = d3dlight.Ambient.a = 0.0f;
+ d3dlight.Falloff = 1.0f;
+ d3dlight.Attenuation0 = 1.0f;
+ d3dlight.Attenuation1 = 0.0f;
+
+ const UInt32 lightsEnabled = (1<<data.vertexLightCount)-1;
+ const UInt32 lightsPrevious = (1<<previous.vertexLightCount)-1;
+ const UInt32 lightsDifferent = lightsPrevious ^ lightsEnabled;
+ UInt32 lightMask = 1;
+ for (int i = 0; i < kMaxSupportedVertexLights; ++i, lightMask <<= 1)
+ {
+ const UInt32 lightDiff = lightsDifferent & lightMask;
+ if( lightsEnabled & lightMask )
+ {
+ const GfxVertexLight& l = data.lights[i];
+ static D3DLIGHTTYPE kD3DTypes[kLightTypeCount] = { D3DLIGHT_SPOT, D3DLIGHT_DIRECTIONAL, D3DLIGHT_POINT };
+ d3dlight.Type = kD3DTypes[l.type];
+ d3dlight.Diffuse = *(const D3DCOLORVALUE*)&l.color;
+ d3dlight.Specular = *(const D3DCOLORVALUE*)&l.color;
+ d3dlight.Position = *(const D3DVECTOR*)&l.position;
+ d3dlight.Direction = *(const D3DVECTOR*)&l.spotDirection;
+ d3dlight.Range = l.range;
+ d3dlight.Attenuation2 = l.quadAtten;
+ d3dlight.Theta = Deg2Rad(l.spotAngle) * 0.5f;
+ d3dlight.Phi = Deg2Rad(l.spotAngle);
+ D3D9_CALL(dev->SetLight (i,&d3dlight));
+ if (lightDiff)
+ D3D9_CALL(dev->LightEnable (i,TRUE));
+ }
+ else
+ {
+ if (lightDiff)
+ D3D9_CALL(dev->LightEnable (i, FALSE));
+ }
+ }
+ previous.vertexLightCount = data.vertexLightCount;
+
+
+ // ambient, lighting & specular
+ if( data.ambient != previous.ambient )
+ {
+ D3D9_CALL(dev->SetRenderState( D3DRS_AMBIENT, ColorToD3D(data.ambient.GetPtr()) ));
+ previous.ambient = data.ambient;
+ }
+ if( config.hasLighting != previous.config.hasLighting )
+ {
+ D3D9_CALL(dev->SetRenderState( D3DRS_LIGHTING, config.hasLighting ? TRUE : FALSE ));
+ }
+ if( config.hasSpecular != previous.config.hasSpecular )
+ {
+ D3D9_CALL(dev->SetRenderState( D3DRS_SPECULARENABLE, config.hasSpecular ? TRUE : FALSE ));
+ }
+ if (config.hasNormalization != previous.config.hasNormalization)
+ {
+ D3D9_CALL(dev->SetRenderState (D3DRS_NORMALIZENORMALS, config.hasNormalization ? TRUE : FALSE));
+ }
+
+
+ UInt32 textureMatrixModes = config.textureMatrixModes;
+ UInt32 projectedTextures = data.projectedTextures;
+ UInt32 textureSources = config.textureSources;
+ for( int i = 0; i < config.texCoordCount; ++i )
+ {
+ // texgen
+ UInt32 texSource = (textureSources >> (i*3)) & 0x7;
+ if( !vsActive )
+ {
+ static DWORD kTexSourceFlags[kTexSourceTypeCount] = { 0, 1, D3DTSS_TCI_SPHEREMAP, D3DTSS_TCI_CAMERASPACEPOSITION, D3DTSS_TCI_CAMERASPACEPOSITION, D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR, D3DTSS_TCI_CAMERASPACENORMAL };
+ DWORD d3dsource = kTexSourceFlags[texSource];
+ if( immediateMode && texSource <= kTexSourceUV1 )
+ d3dsource = i;
+ D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXCOORDINDEX, d3dsource ));
+ }
+ else
+ {
+ D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXCOORDINDEX, i ));
+ }
+
+ // matrix
+ unsigned matmode = (textureMatrixModes >> (i*2)) & 3;
+ static DWORD kTexFlags[kTexMatrixTypeCount] = { D3DTTFF_DISABLE, D3DTTFF_COUNT2, D3DTTFF_COUNT3, D3DTTFF_COUNT4 };
+ DWORD textureTransformFlags = kTexFlags[matmode];
+ if (projectedTextures & (1<<i))
+ textureTransformFlags |= D3DTTFF_PROJECTED;
+ if (vsActive)
+ textureTransformFlags = D3DTTFF_DISABLE;
+ D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXTURETRANSFORMFLAGS, textureTransformFlags ));
+
+ if( !vsActive )
+ {
+ if( texSource == kTexSourceObject )
+ {
+ // D3D has no "object space" texture generation.
+ // So instead we use camera space, and multiply the matrix so it matches:
+ // newMatrix = matrix * inverse(modelview) * mirrorZ
+ // Mirror along Z is required to match OpenGL's generation (eye space Z is negative).
+ Matrix4x4f mv = state.worldViewMatrix;
+ mv.Invert_Full();
+ // Negate Z axis (mv = mv * Scale(1,1,-1))
+ mv.Get(0,2) = -mv.Get(0,2);
+ mv.Get(1,2) = -mv.Get(1,2);
+ mv.Get(2,2) = -mv.Get(2,2);
+ mv.Get(3,2) = -mv.Get(3,2);
+ Matrix4x4f texmat;
+ MultiplyMatrices4x4 (&state.texMatrices[i], &mv, &texmat);
+ D3D9_CALL(dev->SetTransform( (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + i), (const D3DMATRIX*)texmat.GetPtr() ));
+ }
+ else
+ {
+ D3D9_CALL(dev->SetTransform( (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + i), (const D3DMATRIX*)state.texMatrices[i].GetPtr() ));
+ }
+ }
+ }
+ if( config.texCoordCount != previous.config.texCoordCount )
+ {
+ for( int i = config.texCoordCount; i < kMaxSupportedTextureCoords; ++i )
+ {
+ D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXCOORDINDEX, i ));
+ D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ));
+ }
+ }
+
+ if( !vsActive )
+ D3D9_CALL(dev->SetVertexShader(NULL));
+ previous.vertexShader = NULL;
+ previous.config = config;
+}
+
+
+
+
+
+// ----------------------------------------------------------------------
+
+
+
+
+struct VSLightData {
+ Vector4f pos;
+ Vector4f dir;
+ Vector4f color;
+ Vector4f params;
+};
+
+struct ShaderData {
+ IDirect3DVertexShader9* shader;
+ unsigned int usedConstants;
+ std::string text;
+ //std::string debug;
+};
+
+
+struct VertexPipeKeyCompare {
+ union {
+ VertexPipeConfig key;
+ UInt64 asint;
+ } u;
+ VertexPipeKeyCompare() { u.asint = 0; }
+ bool operator <( const VertexPipeKeyCompare& r ) const { return u.asint < r.u.asint; }
+};
+
+typedef std::map<VertexPipeKeyCompare, ShaderData> ShaderCache;
+static ShaderCache g_Shaders;
+
+
+static IDirect3DVertexShader9* GetShaderForConfig( const VertexPipeConfig& config, IDirect3DDevice9* dev, unsigned int& usedConstants )
+{
+ VertexPipeKeyCompare key;
+ key.u.key = config;
+ ShaderCache::iterator it = g_Shaders.find(key);
+ if( it != g_Shaders.end() ) {
+ const ShaderData& sdata = it->second;
+ usedConstants = sdata.usedConstants;
+ return sdata.shader;
+ }
+
+ ShaderGenerator gen;
+ gen.AddFragment( &kVS_Pos );
+
+ // lighting
+ if( config.hasLighting )
+ {
+ // normalize normals?
+ if (config.hasNormalization)
+ gen.AddFragment (&kVS_Normalize_Normal);
+
+ UInt32 hasLightType = config.hasLightType;
+ if( config.hasSpecular )
+ {
+ gen.AddFragment( &kVS_Light_Specular_Pre );
+ if( hasLightType & (1<<kLightDirectional) )
+ gen.AddFragment( &kVS_Light_Specular_Dir );
+ if( hasLightType & (1<<kLightPoint) )
+ gen.AddFragment( &kVS_Light_Specular_Point );
+ if( hasLightType & (1<<kLightSpot) )
+ gen.AddFragment( &kVS_Light_Specular_Spot );
+ }
+ else
+ {
+ gen.AddFragment( &kVS_Light_Diffuse_Pre );
+ if( hasLightType & (1<<kLightDirectional) )
+ gen.AddFragment( &kVS_Light_Diffuse_Dir );
+ if( hasLightType & (1<<kLightPoint) )
+ gen.AddFragment( &kVS_Light_Diffuse_Point );
+ if( hasLightType & (1<<kLightSpot) )
+ gen.AddFragment( &kVS_Light_Diffuse_Spot );
+ }
+
+ const ShaderFragment* frag = NULL;
+ if( config.hasVertexColor ) {
+ switch( config.colorMaterial ) {
+ case kColorMatAmbientAndDiffuse: frag = &kVS_Out_Diffuse_Lighting_ColorDiffuseAmbient; break;
+ case kColorMatEmission: frag = &kVS_Out_Diffuse_Lighting_ColorEmission; break;
+ default: frag = &kVS_Out_Diffuse_Lighting; break;
+ }
+ } else {
+ frag = &kVS_Out_Diffuse_Lighting;
+ }
+ gen.AddFragment( frag );
+
+ if( config.hasSpecular ) {
+ gen.AddFragment( &kVS_Out_Specular_Lighting );
+ }
+
+ }
+ else
+ {
+ if( config.hasVertexColor )
+ gen.AddFragment( &kVS_Out_Diffuse_VertexColor );
+ else
+ gen.AddFragment( &kVS_Out_Diffuse_White );
+ }
+ // texgen
+ static const ShaderFragment* kFragSources[kTexSourceTypeCount] = {
+ &kVS_Load_UV0,
+ &kVS_Load_UV1,
+ &kVS_Temp_SphereMap,
+ &kVS_Temp_ObjSpacePos,
+ &kVS_Temp_CamSpacePos,
+ &kVS_Temp_CamSpaceRefl,
+ &kVS_Temp_CamSpaceN,
+ };
+ static const char* kFragSourceNames[kTexSourceTypeCount] = {
+ "UV0",
+ "UV1",
+ "SPHR",
+ "OPOS",
+ "CPOS",
+ "REFL",
+ "CNOR",
+ };
+ static const ShaderFragment* kFragMatrices[kTexMatrixTypeCount] = {
+ &kVS_Out_TexCoord,
+ &kVS_Out_Matrix2,
+ &kVS_Out_Matrix3,
+ &kVS_Out_Matrix3
+ };
+ for( int i = 0; i < config.texCoordCount; ++i )
+ {
+ unsigned src = (config.textureSources >> (i*3)) & 7;
+ // normalize normals?
+ if (config.hasNormalization)
+ {
+ if (src == kTexSourceSphereMap || src == kTexSourceCubeReflect || src == kTexSourceCubeNormal)
+ gen.AddFragment (&kVS_Normalize_Normal);
+ }
+ gen.AddFragment( kFragSources[src] );
+ }
+ for( int i = 0; i < config.texCoordCount; ++i )
+ {
+ unsigned src = (config.textureSources >> (i*3)) & 7;
+ unsigned matmode = (config.textureMatrixModes >> (i*2)) & 3;
+ gen.AddFragment (kFragMatrices[matmode], kFragSourceNames[src], i);
+ }
+ ShaderData data;
+ data.shader = NULL;
+ gen.GenerateShader( data.text, data.usedConstants );
+
+ ID3DXBuffer* compiledShader = AssembleD3DShader( data.text );
+ if( compiledShader ) {
+ dev->CreateVertexShader( (const DWORD*)compiledShader->GetBufferPointer(), &data.shader );
+ compiledShader->Release();
+ }
+
+ AssertIf(!data.shader);
+ g_Shaders.insert( std::make_pair(key, data) );
+
+ #if PRINT_AMD_SHADER_ANALYZER_OUTPUT
+ PrintAMDShaderAnalyzer( data.text );
+ #endif
+
+ usedConstants = data.usedConstants;
+ return data.shader;
+}
+
+void SetupVertexShaderD3D9 (
+ IDirect3DDevice9* dev,
+ TransformState& state,
+ const BuiltinShaderParamValues& builtins,
+ VertexPipeConfig& config,
+ const VertexPipeDataD3D9& data,
+ VertexPipePrevious& previous,
+ VertexShaderConstantCache& cache,
+ bool vsActive, bool immediateMode)
+{
+ if( vsActive )
+ return;
+
+ D3D9_CALL(dev->SetTransform( D3DTS_WORLD, (const D3DMATRIX*)state.worldViewMatrix.GetPtr() ));
+
+ // figure out which light types do we have
+ if( !config.hasLighting ) {
+ config.hasLightType = 0;
+ } else {
+ UInt32 hasLightType = 0;
+ for (int i = 0; i < data.vertexLightCount; ++i)
+ {
+ hasLightType |= (1<<data.lights[i].type);
+ }
+ config.hasLightType = hasLightType;
+ }
+
+ // create vertex shader
+ unsigned int usedConstants;
+ IDirect3DVertexShader9* shader = GetShaderForConfig(config, dev, usedConstants);
+ AssertIf(!shader);
+
+ // set shader
+ if( shader != previous.vertexShader )
+ {
+ D3D9_CALL(dev->SetVertexShader( shader ));
+ previous.vertexShader = shader;
+ }
+
+ // matrices
+ Matrix4x4f mvp;
+ MultiplyMatrices4x4 (&builtins.GetMatrixParam(kShaderMatProj), &state.worldViewMatrix, &mvp );
+ mvp.Transpose();
+ cache.SetValues( kConstantLocations[kConstMatrixMVP], mvp.GetPtr(), 4 );
+
+ const Matrix4x4f& mv = state.worldViewMatrix;
+ cache.SetValues( kConstantLocations[kConstMatrixMV], mv.GetPtr(), 4 );
+
+ if( usedConstants & (1<<kConstMatrixMV_IT) )
+ {
+ Matrix4x4f matrixTemp;
+ Matrix4x4f::Invert_General3D( mv, matrixTemp );
+ matrixTemp.Transpose();
+ if (data.normalization == kNormalizationScale)
+ {
+ // Inverse transpose of modelview is only used to transform the normals
+ // in our generated shader. We can just stuff mesh scale in there.
+ float scale = Magnitude (state.worldMatrix.GetAxisX());
+ matrixTemp.Get (0, 0) *= scale;
+ matrixTemp.Get (1, 0) *= scale;
+ matrixTemp.Get (2, 0) *= scale;
+ matrixTemp.Get (0, 1) *= scale;
+ matrixTemp.Get (1, 1) *= scale;
+ matrixTemp.Get (2, 1) *= scale;
+ matrixTemp.Get (0, 2) *= scale;
+ matrixTemp.Get (1, 2) *= scale;
+ matrixTemp.Get (2, 2) *= scale;
+ }
+ cache.SetValues( kConstantLocations[kConstMatrixMV_IT], matrixTemp.GetPtr(), 4 );
+ }
+
+ // misc
+ float misc[4] = { 0, 4, 1, 0.5f };
+ cache.SetValues( kConstantLocations[kConstLightMisc], misc, 1 );
+
+ // if lighting is used:
+ if( config.hasLighting )
+ {
+ // ambient
+ if( config.colorMaterial != kColorMatAmbientAndDiffuse )
+ {
+ SimpleVec4 amb;
+ amb.val[0] = data.ambientClamped.val[0] * data.material.Ambient.r;
+ amb.val[1] = data.ambientClamped.val[1] * data.material.Ambient.g;
+ amb.val[2] = data.ambientClamped.val[2] * data.material.Ambient.b;
+ amb.val[3] = data.ambientClamped.val[3] * data.material.Ambient.a;
+ if( config.colorMaterial != kColorMatEmission ) {
+ amb.val[0] += data.material.Emissive.r;
+ amb.val[1] += data.material.Emissive.g;
+ amb.val[2] += data.material.Emissive.b;
+ amb.val[3] += data.material.Emissive.a;
+ }
+ cache.SetValues( kConstantLocations[kConstAmbient], amb.GetPtr(), 1 );
+ }
+ else
+ {
+ cache.SetValues( kConstantLocations[kConstColorMatAmbient], data.ambientClamped.GetPtr(), 1 );
+ cache.SetValues( kConstantLocations[kConstAmbient], &data.material.Emissive.r, 1 );
+ }
+ previous.ambient = data.ambient;
+
+ // material
+ cache.SetValues( kConstantLocations[kConstMatDiffuse], &data.material.Diffuse.r, 1 );
+ D3D9_CALL(dev->SetVertexShaderConstantF( kConstantLocations[kConstMatDiffuse], &data.material.Diffuse.r, 1 ));
+ if( usedConstants & (1<<kConstMatSpecular) )
+ {
+ D3DCOLORVALUE specAndPower = data.material.Specular;
+ specAndPower.a = data.material.Power;
+ cache.SetValues( kConstantLocations[kConstMatSpecular], &specAndPower.r, 1 );
+ }
+
+ // pack the lights
+ int lightCounts[kLightTypeCount];
+ float lightStart[kLightTypeCount];
+ int lightsTotal = 0;
+ float lightsTotalF = 0;
+ memset(lightCounts, 0, sizeof(lightCounts));
+ memset(lightStart, 0, sizeof(lightStart));
+ VSLightData lights[kMaxSupportedVertexLights];
+ for( int t = 0; t < kLightTypeCount; ++t )
+ {
+ lightStart[t] = lightsTotalF;
+ for( int i = 0; i < data.vertexLightCount; ++i )
+ {
+ const GfxVertexLight& src = data.lights[i];
+ if( src.type != t )
+ continue;
+
+ VSLightData& dst = lights[lightsTotal];
+ // position
+ dst.pos.Set( src.position.x, src.position.y, src.position.z, 1.0f );
+ // direction
+ dst.dir.Set( -src.spotDirection.x, -src.spotDirection.y, -src.spotDirection.z, 0.0f );
+ // color
+ dst.color.Set( src.color.x, src.color.y, src.color.z, 1.0f );
+ // params: 1/(cos(theta/2)-cos(phi/2), cos(phi/2), range^2, d^2 attenuation
+ float sqrRange = src.range * src.range;
+ if( src.type == kLightSpot )
+ {
+ float cosTheta = cosf(Deg2Rad(src.spotAngle)*0.25f);
+ float cosPhi = cosf(Deg2Rad(src.spotAngle)*0.5f);
+ float cosDiff = cosTheta - cosPhi;
+ dst.params.Set(
+ cosDiff != 0.0f ? 1.0f / cosDiff : 0.0f,
+ cosPhi,
+ src.range * src.range,
+ src.quadAtten
+ );
+ }
+ else
+ {
+ dst.params.Set(
+ 0.0f,
+ 0.0f,
+ src.range * src.range,
+ src.quadAtten
+ );
+ }
+
+ ++lightCounts[t];
+ ++lightsTotal;
+ ++lightsTotalF;
+ }
+ }
+
+ // light indices
+ int miscI[kLightTypeCount][4];
+ for( int t = 0; t < kLightTypeCount; ++t ) {
+ miscI[t][0] = lightCounts[t];
+ miscI[t][1] = 0;
+ miscI[t][2] = 0;
+ miscI[t][3] = 0;
+ }
+ D3D9_CALL(dev->SetVertexShaderConstantI( 0, miscI[0], kLightTypeCount ));
+
+ if (lightsTotal)
+ cache.SetValues( 60, (const float*)lights, 4*lightsTotal );
+ misc[0] = lightStart[0] * 4.0f;
+ misc[1] = lightStart[1] * 4.0f;
+ misc[2] = lightStart[2] * 4.0f;
+ misc[3] = 0.0f;
+ cache.SetValues(kConstantLocations[kConstLightIndexes], misc, 1);
+ }
+
+ // texture matrices & transform flags
+ UInt32 matrixModes = config.textureMatrixModes;
+ UInt32 projectedTextures = data.projectedTextures;
+ UInt32 textureSources = config.textureSources;
+ for( int i = 0; i < config.texCoordCount; ++i )
+ {
+ unsigned matmode = (matrixModes >> (i*2)) & 0x3;
+ if( matmode != kTexMatrixNone )
+ {
+ cache.SetValues(kConstantLocations[kConstMatrixTexture]+i*4, state.texMatrices[i].GetPtr(), 4);
+ }
+ D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXCOORDINDEX, i ));
+ // projected texture flag
+ DWORD textureTransformFlags = (projectedTextures & (1<<i)) ? D3DTTFF_PROJECTED : D3DTTFF_DISABLE;
+ D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXTURETRANSFORMFLAGS, textureTransformFlags ));
+ }
+
+ if( config.texCoordCount != previous.config.texCoordCount )
+ {
+ for( int i = config.texCoordCount; i < kMaxSupportedTextureCoords; ++i )
+ {
+ D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXCOORDINDEX, i ));
+ D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ));
+ }
+ }
+
+ previous.config = config;
+}
+
+
+void CleanupVertexShadersD3D9 ()
+{
+ #if PRINT_VERTEX_PIPE_STATS
+ printf_console("Vertex pipe shader cache: %i shaders generated\n", g_Shaders.size());
+ #endif
+ ShaderCache::iterator it, itEnd = g_Shaders.end();
+ for( it = g_Shaders.begin(); it != itEnd; ++it )
+ {
+ IDirect3DVertexShader9* vs = it->second.shader;
+ if( vs ) {
+ ULONG refCount = vs->Release();
+ AssertIf( refCount != 0 );
+ }
+ }
+ g_Shaders.clear ();
+}
+