+ 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
+
+void R_GLSL_Restart_f(void)
+{
+ unsigned int i, limit;
+ if (glslshaderstring && glslshaderstring != builtinshaderstring)
+ Mem_Free(glslshaderstring);
+ glslshaderstring = NULL;
+ if (cgshaderstring && cgshaderstring != builtincgshaderstring)
+ Mem_Free(cgshaderstring);
+ cgshaderstring = NULL;
+ if (hlslshaderstring && hlslshaderstring != builtincgshaderstring)
+ Mem_Free(hlslshaderstring);
+ hlslshaderstring = NULL;
+ switch(vid.renderpath)
+ {
+ case RENDERPATH_D3D9:
+#ifdef SUPPORTD3D
+ {
+ r_hlsl_permutation_t *p;
+ r_hlsl_permutation = NULL;
+// cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_VERTEX));CHECKCGERROR CHECKGLERROR
+// cgGLUnbindProgram(cgGLGetLatestProfile(CG_GL_VERTEX));CHECKCGERROR CHECKGLERROR
+// cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_FRAGMENT));CHECKCGERROR CHECKGLERROR
+// cgGLUnbindProgram(cgGLGetLatestProfile(CG_GL_FRAGMENT));CHECKCGERROR CHECKGLERROR
+ limit = Mem_ExpandableArray_IndexRange(&r_hlsl_permutationarray);
+ for (i = 0;i < limit;i++)
+ {
+ if ((p = (r_hlsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_hlsl_permutationarray, i)))
+ {
+ if (p->vertexshader)
+ IDirect3DVertexShader9_Release(p->vertexshader);
+ if (p->pixelshader)
+ IDirect3DPixelShader9_Release(p->pixelshader);
+ Mem_ExpandableArray_FreeRecord(&r_hlsl_permutationarray, (void*)p);
+ }
+ }
+ memset(r_hlsl_permutationhash, 0, sizeof(r_hlsl_permutationhash));
+ }
+#endif
+ break;
+ case RENDERPATH_D3D10:
+ Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;
+ case RENDERPATH_D3D11:
+ Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;
+ case RENDERPATH_GL20:
+ {
+ r_glsl_permutation_t *p;
+ r_glsl_permutation = NULL;
+ limit = Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
+ for (i = 0;i < limit;i++)
+ {
+ if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
+ {
+ GL_Backend_FreeProgram(p->program);
+ Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
+ }
+ }
+ memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
+ }
+ break;
+ case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+ {
+ r_cg_permutation_t *p;
+ r_cg_permutation = NULL;
+ cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_VERTEX));CHECKCGERROR CHECKGLERROR
+ cgGLUnbindProgram(cgGLGetLatestProfile(CG_GL_VERTEX));CHECKCGERROR CHECKGLERROR
+ cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_FRAGMENT));CHECKCGERROR CHECKGLERROR
+ cgGLUnbindProgram(cgGLGetLatestProfile(CG_GL_FRAGMENT));CHECKCGERROR CHECKGLERROR
+ limit = Mem_ExpandableArray_IndexRange(&r_cg_permutationarray);
+ for (i = 0;i < limit;i++)
+ {
+ if ((p = (r_cg_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_cg_permutationarray, i)))
+ {
+ if (p->vprogram)
+ cgDestroyProgram(p->vprogram);
+ if (p->fprogram)
+ cgDestroyProgram(p->fprogram);
+ Mem_ExpandableArray_FreeRecord(&r_cg_permutationarray, (void*)p);
+ }
+ }
+ memset(r_cg_permutationhash, 0, sizeof(r_cg_permutationhash));
+ }
+#endif
+ break;
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL11:
+ break;
+ }
+}
+
+void R_GLSL_DumpShader_f(void)
+{
+ int i;
+ qfile_t *file;
+
+ file = FS_OpenRealFile("glsl/default.glsl", "w", false);
+ if (file)
+ {
+ FS_Print(file, "/* The engine may define the following macros:\n");
+ FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
+ for (i = 0;i < SHADERMODE_COUNT;i++)
+ FS_Print(file, glslshadermodeinfo[i].pretext);
+ for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
+ FS_Print(file, shaderpermutationinfo[i].pretext);
+ FS_Print(file, "*/\n");
+ FS_Print(file, builtinshaderstring);
+ FS_Close(file);
+ Con_Printf("glsl/default.glsl written\n");
+ }
+ else
+ Con_Printf("failed to write to glsl/default.glsl\n");
+
+#ifdef SUPPORTCG
+ file = FS_OpenRealFile("cg/default.cg", "w", false);
+ if (file)
+ {
+ FS_Print(file, "/* The engine may define the following macros:\n");
+ FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
+ for (i = 0;i < SHADERMODE_COUNT;i++)
+ FS_Print(file, cgshadermodeinfo[i].pretext);
+ for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
+ FS_Print(file, shaderpermutationinfo[i].pretext);
+ FS_Print(file, "*/\n");
+ FS_Print(file, builtincgshaderstring);
+ FS_Close(file);
+ Con_Printf("cg/default.cg written\n");
+ }
+ else
+ Con_Printf("failed to write to cg/default.cg\n");
+#endif
+
+#ifdef SUPPORTD3D
+ file = FS_OpenRealFile("hlsl/default.hlsl", "w", false);
+ if (file)
+ {
+ FS_Print(file, "/* The engine may define the following macros:\n");
+ FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
+ for (i = 0;i < SHADERMODE_COUNT;i++)
+ FS_Print(file, hlslshadermodeinfo[i].pretext);
+ for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
+ FS_Print(file, shaderpermutationinfo[i].pretext);
+ FS_Print(file, "*/\n");
+ FS_Print(file, builtincgshaderstring);
+ FS_Close(file);
+ Con_Printf("hlsl/default.hlsl written\n");
+ }
+ else
+ Con_Printf("failed to write to hlsl/default.hlsl\n");
+#endif
+}
+
+void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale)
+{
+ if (!second)
+ texturemode = GL_MODULATE;
+ switch (vid.renderpath)
+ {
+ case RENDERPATH_D3D9:
+#ifdef SUPPORTD3D
+ R_SetupShader_SetPermutationHLSL(SHADERMODE_GENERIC, (first ? SHADERPERMUTATION_DIFFUSE : 0) | (second ? SHADERPERMUTATION_SPECULAR : 0) | (r_shadow_glossexact.integer ? SHADERPERMUTATION_EXACTSPECULARMATH : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
+ R_Mesh_TexBind(GL20TU_FIRST , first );
+ R_Mesh_TexBind(GL20TU_SECOND, second);
+#endif
+ break;
+ case RENDERPATH_D3D10:
+ Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;
+ case RENDERPATH_D3D11:
+ Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;
+ case RENDERPATH_GL20:
+ R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, (first ? SHADERPERMUTATION_DIFFUSE : 0) | (second ? SHADERPERMUTATION_SPECULAR : 0) | (r_shadow_glossexact.integer ? SHADERPERMUTATION_EXACTSPECULARMATH : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
+ R_Mesh_TexBind(GL20TU_FIRST , first );
+ R_Mesh_TexBind(GL20TU_SECOND, second);
+ break;
+ case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+ CHECKCGERROR
+ R_SetupShader_SetPermutationCG(SHADERMODE_GENERIC, (first ? SHADERPERMUTATION_DIFFUSE : 0) | (second ? SHADERPERMUTATION_SPECULAR : 0) | (r_shadow_glossexact.integer ? SHADERPERMUTATION_EXACTSPECULARMATH : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
+ if (r_cg_permutation->fp_Texture_First ) CG_BindTexture(r_cg_permutation->fp_Texture_First , first );CHECKCGERROR
+ if (r_cg_permutation->fp_Texture_Second) CG_BindTexture(r_cg_permutation->fp_Texture_Second, second);CHECKCGERROR
+#endif
+ break;
+ case RENDERPATH_GL13:
+ R_Mesh_TexBind(0, first );
+ R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+ R_Mesh_TexBind(1, second);
+ if (second)
+ R_Mesh_TexCombine(1, texturemode, texturemode, rgbscale, 1);
+ break;
+ case RENDERPATH_GL11:
+ R_Mesh_TexBind(0, first );
+ break;
+ }
+}
+
+void R_SetupShader_DepthOrShadow(void)
+{
+ switch (vid.renderpath)
+ {
+ case RENDERPATH_D3D9:
+#ifdef SUPPORTD3D
+ R_SetupShader_SetPermutationHLSL(SHADERMODE_DEPTH_OR_SHADOW, 0);
+#endif
+ break;
+ case RENDERPATH_D3D10:
+ Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;
+ case RENDERPATH_D3D11:
+ Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;
+ case RENDERPATH_GL20:
+ R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, 0);
+ break;
+ case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+ R_SetupShader_SetPermutationCG(SHADERMODE_DEPTH_OR_SHADOW, 0);
+#endif
+ break;
+ case RENDERPATH_GL13:
+ R_Mesh_TexBind(0, 0);
+ R_Mesh_TexBind(1, 0);
+ break;
+ case RENDERPATH_GL11:
+ R_Mesh_TexBind(0, 0);
+ break;
+ }
+}
+
+void R_SetupShader_ShowDepth(void)
+{
+ switch (vid.renderpath)
+ {
+ case RENDERPATH_D3D9:
+#ifdef SUPPORTHLSL
+ R_SetupShader_SetPermutationHLSL(SHADERMODE_SHOWDEPTH, 0);
+#endif
+ break;
+ case RENDERPATH_D3D10:
+ Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;
+ case RENDERPATH_D3D11:
+ Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;