+#ifdef SUPPORTD3D
+
+#ifdef SUPPORTD3D
+#include <d3d9.h>
+extern LPDIRECT3DDEVICE9 vid_d3d9dev;
+extern D3DCAPS9 vid_d3d9caps;
+#endif
+
+struct r_hlsl_permutation_s;
+typedef struct r_hlsl_permutation_s
+{
+ /// hash lookup data
+ struct r_hlsl_permutation_s *hashnext;
+ unsigned int mode;
+ unsigned int permutation;
+
+ /// indicates if we have tried compiling this permutation already
+ qboolean compiled;
+ /// NULL if compilation failed
+ IDirect3DVertexShader9 *vertexshader;
+ IDirect3DPixelShader9 *pixelshader;
+}
+r_hlsl_permutation_t;
+
+typedef enum D3DVSREGISTER_e
+{
+ D3DVSREGISTER_TexMatrix = 0, // float4x4
+ D3DVSREGISTER_BackgroundTexMatrix = 4, // float4x4
+ D3DVSREGISTER_ModelViewProjectionMatrix = 8, // float4x4
+ D3DVSREGISTER_ModelViewMatrix = 12, // float4x4
+ D3DVSREGISTER_ShadowMapMatrix = 16, // float4x4
+ D3DVSREGISTER_ModelToLight = 20, // float4x4
+ D3DVSREGISTER_EyePosition = 24,
+ D3DVSREGISTER_FogPlane = 25,
+ D3DVSREGISTER_LightDir = 26,
+ D3DVSREGISTER_LightPosition = 27,
+}
+D3DVSREGISTER_t;
+
+typedef enum D3DPSREGISTER_e
+{
+ D3DPSREGISTER_Alpha = 0,
+ D3DPSREGISTER_BloomBlur_Parameters = 1,
+ D3DPSREGISTER_ClientTime = 2,
+ D3DPSREGISTER_Color_Ambient = 3,
+ D3DPSREGISTER_Color_Diffuse = 4,
+ D3DPSREGISTER_Color_Specular = 5,
+ D3DPSREGISTER_Color_Glow = 6,
+ D3DPSREGISTER_Color_Pants = 7,
+ D3DPSREGISTER_Color_Shirt = 8,
+ D3DPSREGISTER_DeferredColor_Ambient = 9,
+ D3DPSREGISTER_DeferredColor_Diffuse = 10,
+ D3DPSREGISTER_DeferredColor_Specular = 11,
+ D3DPSREGISTER_DeferredMod_Diffuse = 12,
+ D3DPSREGISTER_DeferredMod_Specular = 13,
+ D3DPSREGISTER_DistortScaleRefractReflect = 14,
+ D3DPSREGISTER_EyePosition = 15, // unused
+ D3DPSREGISTER_FogColor = 16,
+ D3DPSREGISTER_FogHeightFade = 17,
+ D3DPSREGISTER_FogPlane = 18,
+ D3DPSREGISTER_FogPlaneViewDist = 19,
+ D3DPSREGISTER_FogRangeRecip = 20,
+ D3DPSREGISTER_LightColor = 21,
+ D3DPSREGISTER_LightDir = 22, // unused
+ D3DPSREGISTER_LightPosition = 23,
+ D3DPSREGISTER_OffsetMapping_Scale = 24,
+ D3DPSREGISTER_PixelSize = 25,
+ D3DPSREGISTER_ReflectColor = 26,
+ D3DPSREGISTER_ReflectFactor = 27,
+ D3DPSREGISTER_ReflectOffset = 28,
+ D3DPSREGISTER_RefractColor = 29,
+ D3DPSREGISTER_Saturation = 30,
+ D3DPSREGISTER_ScreenCenterRefractReflect = 31,
+ D3DPSREGISTER_ScreenScaleRefractReflect = 32,
+ D3DPSREGISTER_ScreenToDepth = 33,
+ D3DPSREGISTER_ShadowMap_Parameters = 34,
+ D3DPSREGISTER_ShadowMap_TextureScale = 35,
+ D3DPSREGISTER_SpecularPower = 36,
+ D3DPSREGISTER_UserVec1 = 37,
+ D3DPSREGISTER_UserVec2 = 38,
+ D3DPSREGISTER_UserVec3 = 39,
+ D3DPSREGISTER_UserVec4 = 40,
+ D3DPSREGISTER_ViewTintColor = 41,
+ D3DPSREGISTER_PixelToScreenTexCoord = 42,
+ D3DPSREGISTER_BloomColorSubtract = 43,
+ D3DPSREGISTER_ViewToLight = 44, // float4x4
+ D3DPSREGISTER_ModelToReflectCube = 48, // float4x4
+ // next at 52
+}
+D3DPSREGISTER_t;
+
+/// information about each possible shader permutation
+r_hlsl_permutation_t *r_hlsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
+/// currently selected permutation
+r_hlsl_permutation_t *r_hlsl_permutation;
+/// storage for permutations linked in the hash table
+memexpandablearray_t r_hlsl_permutationarray;
+
+static r_hlsl_permutation_t *R_HLSL_FindPermutation(unsigned int mode, unsigned int permutation)
+{
+ //unsigned int hashdepth = 0;
+ unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
+ r_hlsl_permutation_t *p;
+ for (p = r_hlsl_permutationhash[mode][hashindex];p;p = p->hashnext)
+ {
+ if (p->mode == mode && p->permutation == permutation)
+ {
+ //if (hashdepth > 10)
+ // Con_Printf("R_HLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
+ return p;
+ }
+ //hashdepth++;
+ }
+ p = (r_hlsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_hlsl_permutationarray);
+ p->mode = mode;
+ p->permutation = permutation;
+ p->hashnext = r_hlsl_permutationhash[mode][hashindex];
+ r_hlsl_permutationhash[mode][hashindex] = p;
+ //if (hashdepth > 10)
+ // Con_Printf("R_HLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
+ return p;
+}
+
+static char *R_HLSL_GetText(const char *filename, qboolean printfromdisknotice)
+{
+ char *shaderstring;
+ if (!filename || !filename[0])
+ return NULL;
+ if (!strcmp(filename, "hlsl/default.hlsl"))
+ {
+ if (!hlslshaderstring)
+ {
+ hlslshaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
+ if (hlslshaderstring)
+ Con_DPrintf("Loading shaders from file %s...\n", filename);
+ else
+ hlslshaderstring = (char *)builtincgshaderstring;
+ }
+ shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(hlslshaderstring) + 1);
+ memcpy(shaderstring, hlslshaderstring, strlen(hlslshaderstring) + 1);
+ return shaderstring;
+ }
+ shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
+ if (shaderstring)
+ {
+ if (printfromdisknotice)
+ Con_DPrintf("from disk %s... ", filename);
+ return shaderstring;
+ }
+ return shaderstring;
+}
+
+#include <d3dx9.h>
+#include <d3dx9mesh.h>
+#pragma comment(lib, "d3dx9.lib")
+
+static void R_HLSL_CacheShader(r_hlsl_permutation_t *p, const char *cachename, const char *vertstring, const char *fragstring)
+{
+ DWORD *vsbin = NULL;
+ DWORD *psbin = NULL;
+ fs_offset_t vsbinsize;
+ fs_offset_t psbinsize;
+// IDirect3DVertexShader9 *vs = NULL;
+// IDirect3DPixelShader9 *ps = NULL;
+ ID3DXBuffer *vslog = NULL;
+ ID3DXBuffer *vsbuffer = NULL;
+ ID3DXConstantTable *vsconstanttable = NULL;
+ ID3DXBuffer *pslog = NULL;
+ ID3DXBuffer *psbuffer = NULL;
+ ID3DXConstantTable *psconstanttable = NULL;
+ int vsresult = 0;
+ int psresult = 0;
+ char temp[MAX_INPUTLINE];
+ const char *vsversion = "vs_3_0", *psversion = "ps_3_0";
+ if (p->permutation & SHADERPERMUTATION_OFFSETMAPPING) {vsversion = "vs_3_0";psversion = "ps_3_0";}
+ if (p->permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) {vsversion = "vs_3_0";psversion = "ps_3_0";}
+ vsbin = (DWORD *)FS_LoadFile(va("%s.vsbin", cachename), r_main_mempool, true, &vsbinsize);
+ psbin = (DWORD *)FS_LoadFile(va("%s.psbin", cachename), r_main_mempool, true, &psbinsize);
+ if ((!vsbin && vertstring) || (!psbin && fragstring))
+ {
+ vsbin = (DWORD *)Mem_Realloc(tempmempool, vsbin, 0);
+ psbin = (DWORD *)Mem_Realloc(tempmempool, psbin, 0);
+ if (vertstring && vertstring[0])
+ {
+ vsresult = D3DXCompileShader(vertstring, strlen(vertstring), NULL, NULL, "main", vsversion, 0, &vsbuffer, &vslog, &vsconstanttable);
+ if (vsbuffer)
+ {
+ vsbinsize = vsbuffer->GetBufferSize();
+ vsbin = (DWORD *)Mem_Alloc(tempmempool, vsbinsize);
+ memcpy(vsbin, vsbuffer->GetBufferPointer(), vsbinsize);
+ vsbuffer->Release();
+ }
+ if (vslog)
+ {
+ strlcpy(temp, (const char *)vslog->GetBufferPointer(), min(sizeof(temp), vslog->GetBufferSize()));
+ Con_Printf("HLSL vertex shader compile output for %s follows:\n%s\n", cachename, temp);
+ vslog->Release();
+ }
+ }
+ if (fragstring && fragstring[0])
+ {
+ psresult = D3DXCompileShader(fragstring, strlen(fragstring), NULL, NULL, "main", psversion, 0, &psbuffer, &pslog, &psconstanttable);
+ if (psbuffer)
+ {
+ psbinsize = psbuffer->GetBufferSize();
+ psbin = (DWORD *)Mem_Alloc(tempmempool, psbinsize);
+ memcpy(psbin, psbuffer->GetBufferPointer(), psbinsize);
+ psbuffer->Release();
+ }
+ if (pslog)
+ {
+ strlcpy(temp, (const char *)pslog->GetBufferPointer(), min(sizeof(temp), pslog->GetBufferSize()));
+ Con_Printf("HLSL pixel shader compile output for %s follows:\n%s\n", cachename, temp);
+ pslog->Release();
+ }
+ }
+ }
+ if (vsbin)
+ {
+ vsresult = IDirect3DDevice9_CreateVertexShader(vid_d3d9dev, vsbin, &p->vertexshader);
+ if (FAILED(vsresult))
+ Con_Printf("HLSL CreateVertexShader failed for %s (hresult = %8x)\n", cachename, vsresult);
+ }
+ if (psbin)
+ {
+ psresult = IDirect3DDevice9_CreatePixelShader(vid_d3d9dev, psbin, &p->pixelshader);
+ if (FAILED(psresult))
+ Con_Printf("HLSL CreatePixelShader failed for %s (hresult = %8x)\n", cachename, psresult);
+ }
+ // free the shader data
+ vsbin = (DWORD *)Mem_Realloc(tempmempool, vsbin, 0);
+ psbin = (DWORD *)Mem_Realloc(tempmempool, psbin, 0);
+}
+
+static void R_HLSL_CompilePermutation(r_hlsl_permutation_t *p, unsigned int mode, unsigned int permutation)
+{
+ int i;
+ shadermodeinfo_t *modeinfo = hlslshadermodeinfo + mode;
+ int vertstrings_count = 0, vertstring_length = 0;
+ int geomstrings_count = 0, geomstring_length = 0;
+ int fragstrings_count = 0, fragstring_length = 0;
+ char *t;
+ char *vertexstring, *geometrystring, *fragmentstring;
+ char *vertstring, *geomstring, *fragstring;
+ const char *vertstrings_list[32+3];
+ const char *geomstrings_list[32+3];
+ const char *fragstrings_list[32+3];
+ char permutationname[256];
+ char cachename[256];
+
+ if (p->compiled)
+ return;
+ p->compiled = true;
+ p->vertexshader = NULL;
+ p->pixelshader = NULL;
+
+ permutationname[0] = 0;
+ cachename[0] = 0;
+ vertexstring = R_HLSL_GetText(modeinfo->vertexfilename, true);
+ geometrystring = R_HLSL_GetText(modeinfo->geometryfilename, false);
+ fragmentstring = R_HLSL_GetText(modeinfo->fragmentfilename, false);
+
+ strlcat(permutationname, modeinfo->vertexfilename, sizeof(permutationname));
+ strlcat(cachename, "hlsl/", sizeof(cachename));
+
+ // define HLSL so that the shader can tell apart the HLSL compiler and the Cg compiler
+ vertstrings_list[vertstrings_count++] = "#define HLSL\n";
+ geomstrings_list[geomstrings_count++] = "#define HLSL\n";
+ fragstrings_list[fragstrings_count++] = "#define HLSL\n";
+
+ // the first pretext is which type of shader to compile as
+ // (later these will all be bound together as a program object)
+ vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
+ geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
+ fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
+
+ // the second pretext is the mode (for example a light source)
+ vertstrings_list[vertstrings_count++] = modeinfo->pretext;
+ geomstrings_list[geomstrings_count++] = modeinfo->pretext;
+ fragstrings_list[fragstrings_count++] = modeinfo->pretext;
+ strlcat(permutationname, modeinfo->name, sizeof(permutationname));
+ strlcat(cachename, modeinfo->name, sizeof(cachename));
+
+ // now add all the permutation pretexts
+ for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
+ {
+ if (permutation & (1<<i))
+ {
+ vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
+ geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
+ fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
+ strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
+ strlcat(cachename, shaderpermutationinfo[i].name, sizeof(cachename));
+ }
+ else
+ {
+ // keep line numbers correct
+ vertstrings_list[vertstrings_count++] = "\n";
+ geomstrings_list[geomstrings_count++] = "\n";
+ fragstrings_list[fragstrings_count++] = "\n";
+ }
+ }
+
+ // replace spaces in the cachename with _ characters
+ for (i = 0;cachename[i];i++)
+ if (cachename[i] == ' ')
+ cachename[i] = '_';
+
+ // now append the shader text itself
+ vertstrings_list[vertstrings_count++] = vertexstring;
+ geomstrings_list[geomstrings_count++] = geometrystring;
+ fragstrings_list[fragstrings_count++] = fragmentstring;
+
+ // if any sources were NULL, clear the respective list
+ if (!vertexstring)
+ vertstrings_count = 0;
+ if (!geometrystring)
+ geomstrings_count = 0;
+ if (!fragmentstring)
+ fragstrings_count = 0;
+
+ vertstring_length = 0;
+ for (i = 0;i < vertstrings_count;i++)
+ vertstring_length += strlen(vertstrings_list[i]);
+ vertstring = t = (char *)Mem_Alloc(tempmempool, vertstring_length + 1);
+ for (i = 0;i < vertstrings_count;t += strlen(vertstrings_list[i]), i++)
+ memcpy(t, vertstrings_list[i], strlen(vertstrings_list[i]));
+
+ geomstring_length = 0;
+ for (i = 0;i < geomstrings_count;i++)
+ geomstring_length += strlen(geomstrings_list[i]);
+ geomstring = t = (char *)Mem_Alloc(tempmempool, geomstring_length + 1);
+ for (i = 0;i < geomstrings_count;t += strlen(geomstrings_list[i]), i++)
+ memcpy(t, geomstrings_list[i], strlen(geomstrings_list[i]));
+
+ fragstring_length = 0;
+ for (i = 0;i < fragstrings_count;i++)
+ fragstring_length += strlen(fragstrings_list[i]);
+ fragstring = t = (char *)Mem_Alloc(tempmempool, fragstring_length + 1);
+ for (i = 0;i < fragstrings_count;t += strlen(fragstrings_list[i]), i++)
+ memcpy(t, fragstrings_list[i], strlen(fragstrings_list[i]));
+
+ // try to load the cached shader, or generate one
+ R_HLSL_CacheShader(p, cachename, vertstring, fragstring);
+
+ if ((p->vertexshader || !vertstring[0]) && (p->pixelshader || !fragstring[0]))
+ Con_DPrintf("^5HLSL shader %s compiled.\n", permutationname);
+ else
+ Con_Printf("^1HLSL shader %s failed! some features may not work properly.\n", permutationname);
+
+ // free the strings
+ if (vertstring)
+ Mem_Free(vertstring);
+ if (geomstring)
+ Mem_Free(geomstring);
+ if (fragstring)
+ Mem_Free(fragstring);
+ if (vertexstring)
+ Mem_Free(vertexstring);
+ if (geometrystring)
+ Mem_Free(geometrystring);
+ if (fragmentstring)
+ Mem_Free(fragmentstring);
+}
+
+static inline void hlslVSSetParameter16f(D3DVSREGISTER_t r, const float *a) {IDirect3DDevice9_SetVertexShaderConstantF(vid_d3d9dev, r, a, 4);}
+static inline void hlslVSSetParameter4fv(D3DVSREGISTER_t r, const float *a) {IDirect3DDevice9_SetVertexShaderConstantF(vid_d3d9dev, r, a, 1);}
+static inline void hlslVSSetParameter4f(D3DVSREGISTER_t r, float x, float y, float z, float w) {float temp[4];Vector4Set(temp, x, y, z, w);IDirect3DDevice9_SetVertexShaderConstantF(vid_d3d9dev, r, temp, 1);}
+static inline void hlslVSSetParameter3f(D3DVSREGISTER_t r, float x, float y, float z) {float temp[4];Vector4Set(temp, x, y, z, 0);IDirect3DDevice9_SetVertexShaderConstantF(vid_d3d9dev, r, temp, 1);}
+static inline void hlslVSSetParameter2f(D3DVSREGISTER_t r, float x, float y) {float temp[4];Vector4Set(temp, x, y, 0, 0);IDirect3DDevice9_SetVertexShaderConstantF(vid_d3d9dev, r, temp, 1);}
+static inline void hlslVSSetParameter1f(D3DVSREGISTER_t r, float x) {float temp[4];Vector4Set(temp, x, 0, 0, 0);IDirect3DDevice9_SetVertexShaderConstantF(vid_d3d9dev, r, temp, 1);}
+
+static inline void hlslPSSetParameter16f(D3DPSREGISTER_t r, const float *a) {IDirect3DDevice9_SetPixelShaderConstantF(vid_d3d9dev, r, a, 4);}
+static inline void hlslPSSetParameter4fv(D3DPSREGISTER_t r, const float *a) {IDirect3DDevice9_SetPixelShaderConstantF(vid_d3d9dev, r, a, 1);}
+static inline void hlslPSSetParameter4f(D3DPSREGISTER_t r, float x, float y, float z, float w) {float temp[4];Vector4Set(temp, x, y, z, w);IDirect3DDevice9_SetPixelShaderConstantF(vid_d3d9dev, r, temp, 1);}
+static inline void hlslPSSetParameter3f(D3DPSREGISTER_t r, float x, float y, float z) {float temp[4];Vector4Set(temp, x, y, z, 0);IDirect3DDevice9_SetPixelShaderConstantF(vid_d3d9dev, r, temp, 1);}
+static inline void hlslPSSetParameter2f(D3DPSREGISTER_t r, float x, float y) {float temp[4];Vector4Set(temp, x, y, 0, 0);IDirect3DDevice9_SetPixelShaderConstantF(vid_d3d9dev, r, temp, 1);}
+static inline void hlslPSSetParameter1f(D3DPSREGISTER_t r, float x) {float temp[4];Vector4Set(temp, x, 0, 0, 0);IDirect3DDevice9_SetPixelShaderConstantF(vid_d3d9dev, r, temp, 1);}
+
+void R_SetupShader_SetPermutationHLSL(unsigned int mode, unsigned int permutation)
+{
+ r_hlsl_permutation_t *perm = R_HLSL_FindPermutation(mode, permutation);
+ if (r_hlsl_permutation != perm)
+ {
+ r_hlsl_permutation = perm;
+ if (!r_hlsl_permutation->vertexshader && !r_hlsl_permutation->pixelshader)
+ {
+ if (!r_hlsl_permutation->compiled)
+ R_HLSL_CompilePermutation(perm, mode, permutation);
+ if (!r_hlsl_permutation->vertexshader && !r_hlsl_permutation->pixelshader)
+ {
+ // remove features until we find a valid permutation
+ int i;
+ for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
+ {
+ // reduce i more quickly whenever it would not remove any bits
+ int j = 1<<(SHADERPERMUTATION_COUNT-1-i);
+ if (!(permutation & j))
+ continue;
+ permutation -= j;
+ r_hlsl_permutation = R_HLSL_FindPermutation(mode, permutation);
+ if (!r_hlsl_permutation->compiled)
+ R_HLSL_CompilePermutation(perm, mode, permutation);
+ if (r_hlsl_permutation->vertexshader || r_hlsl_permutation->pixelshader)
+ break;
+ }
+ if (i >= SHADERPERMUTATION_COUNT)
+ {
+ //Con_Printf("Could not find a working Cg shader for permutation %s %s\n", shadermodeinfo[mode].vertexfilename, shadermodeinfo[mode].pretext);
+ r_hlsl_permutation = R_HLSL_FindPermutation(mode, permutation);
+ return; // no bit left to clear, entire mode is broken
+ }
+ }
+ }
+ IDirect3DDevice9_SetVertexShader(vid_d3d9dev, r_hlsl_permutation->vertexshader);
+ IDirect3DDevice9_SetPixelShader(vid_d3d9dev, r_hlsl_permutation->pixelshader);
+ }
+ hlslVSSetParameter16f(D3DVSREGISTER_ModelViewProjectionMatrix, gl_modelviewprojection16f);
+ hlslVSSetParameter16f(D3DVSREGISTER_ModelViewMatrix, gl_modelview16f);
+ hlslPSSetParameter1f(D3DPSREGISTER_ClientTime, cl.time);
+}
+#endif
+