-void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
-
-const char *builtinshader_light_vert =
-"// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
-"// written by Forest 'LordHavoc' Hale\n"
-"\n"
-"// use half floats if available for math performance\n"
-"#ifdef GEFORCEFX\n"
-"#define myhalf half\n"
-"#define myhvec2 hvec2\n"
-"#define myhvec3 hvec3\n"
-"#define myhvec4 hvec4\n"
-"#else\n"
-"#define myhalf float\n"
-"#define myhvec2 vec2\n"
-"#define myhvec3 vec3\n"
-"#define myhvec4 vec4\n"
-"#endif\n"
-"\n"
-"uniform vec3 LightPosition;\n"
-"\n"
-"varying vec2 TexCoord;\n"
-"varying myhvec3 CubeVector;\n"
-"varying vec3 LightVector;\n"
-"\n"
-"#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
-"uniform vec3 EyePosition;\n"
-"varying vec3 EyeVector;\n"
-"#endif\n"
-"\n"
-"// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
-"\n"
-"void main(void)\n"
-"{\n"
-" // copy the surface texcoord\n"
-" TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
-"\n"
-" // transform vertex position into light attenuation/cubemap space\n"
-" // (-1 to +1 across the light box)\n"
-" CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
-"\n"
-" // transform unnormalized light direction into tangent space\n"
-" // (we use unnormalized to ensure that it interpolates correctly and then\n"
-" // normalize it per pixel)\n"
-" vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
-" LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
-" LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
-" LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
-"\n"
-"#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
-" // transform unnormalized eye direction into tangent space\n"
-" vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
-" EyeVector.x = dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
-" EyeVector.y = dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
-" EyeVector.z = dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
-"#endif\n"
-"\n"
-" // transform vertex to camera space, using ftransform to match non-VS\n"
-" // rendering\n"
-" gl_Position = ftransform();\n"
-"}\n"
-;
-
-const char *builtinshader_light_frag =
-"// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
-"// written by Forest 'LordHavoc' Hale\n"
-"\n"
-"// use half floats if available for math performance\n"
-"#ifdef GEFORCEFX\n"
-"#define myhalf half\n"
-"#define myhvec2 hvec2\n"
-"#define myhvec3 hvec3\n"
-"#define myhvec4 hvec4\n"
-"#else\n"
-"#define myhalf float\n"
-"#define myhvec2 vec2\n"
-"#define myhvec3 vec3\n"
-"#define myhvec4 vec4\n"
-"#endif\n"
-"\n"
-"uniform myhvec3 LightColor;\n"
-"#ifdef USEOFFSETMAPPING\n"
-"uniform myhalf OffsetMapping_Scale;\n"
-"uniform myhalf OffsetMapping_Bias;\n"
-"#endif\n"
-"#ifdef USESPECULAR\n"
-"uniform myhalf SpecularPower;\n"
-"#endif\n"
-"#ifdef USEFOG\n"
-"uniform myhalf FogRangeRecip;\n"
-"#endif\n"
-"uniform myhalf AmbientScale;\n"
-"uniform myhalf DiffuseScale;\n"
-"#ifdef USESPECULAR\n"
-"uniform myhalf SpecularScale;\n"
-"#endif\n"
-"\n"
-"#ifdef USECOLORMAPPING\n"
-"uniform myhvec3 Color_Pants;\n"
-"uniform myhvec3 Color_Shirt;\n"
-"#endif\n"
-"\n"
-"uniform sampler2D Texture_Normal;\n"
-"uniform sampler2D Texture_Color;\n"
-"uniform sampler2D Texture_Pants;\n"
-"uniform sampler2D Texture_Shirt;\n"
-"#ifdef USESPECULAR\n"
-"uniform sampler2D Texture_Gloss;\n"
-"#endif\n"
-"#ifdef USECUBEFILTER\n"
-"uniform samplerCube Texture_Cube;\n"
-"#endif\n"
-"#ifdef USEFOG\n"
-"uniform sampler2D Texture_FogMask;\n"
-"#endif\n"
-"\n"
-"varying vec2 TexCoord;\n"
-"varying myhvec3 CubeVector;\n"
-"varying vec3 LightVector;\n"
-"#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
-"varying vec3 EyeVector;\n"
-"#endif\n"
-"\n"
-"void main(void)\n"
-"{\n"
-" // attenuation\n"
-" //\n"
-" // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
-" // center and sharp falloff at the edge, this is about the most efficient\n"
-" // we can get away with as far as providing illumination.\n"
-" //\n"
-" // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
-" // provide significant illumination, large = slow = pain.\n"
-" myhalf colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
-"\n"
-"#ifdef USEFOG\n"
-" // apply fog\n"
-" colorscale *= texture2D(Texture_FogMask, myhvec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
-"#endif\n"
-"\n"
-"#ifdef USEOFFSETMAPPING\n"
-" // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
-" myhvec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
-" myhvec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
-" TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
-" TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
-"#define TexCoord TexCoordOffset\n"
-"#endif\n"
-"\n"
-" // get the surface normal\n"
-"#ifdef SURFACENORMALIZE\n"
-" myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - 0.5);\n"
-"#else\n"
-" myhvec3 surfacenormal = -1.0 + 2.0 * myhvec3(texture2D(Texture_Normal, TexCoord));\n"
-"#endif\n"
-"\n"
-" // calculate shading\n"
-" myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
-" myhvec4 texturecolor = myhvec4(texture2D(Texture_Color, TexCoord));\n"
-" colorscale *= texturecolor.a;\n"
-" myhvec3 color = myhvec3(texturecolor);\n"
-"#ifdef USECOLORMAPPING\n"
-" color += myhvec3(texture2D(Texture_Pants, TexCoord)) * Color_Pants + myhvec3(texture2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
-"#endif\n"
-" color *= (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
-"#ifdef USESPECULAR\n"
-" myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
-" color += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower);\n"
-"#endif\n"
-"\n"
-"#ifdef USECUBEFILTER\n"
-" // apply light cubemap filter\n"
-" color *= myhvec3(textureCube(Texture_Cube, CubeVector));\n"
-"#endif\n"
-"\n"
-" // calculate fragment color (apply light color and attenuation/fog scaling)\n"
-" gl_FragColor = myhvec4(color * LightColor * colorscale, 1);\n"
-"}\n"
-;
-
-int R_Shadow_CompileShaderPermutation(int permutation)
-{
- char *vertstring, *fragstring;
- int vertstrings_count;
- int fragstrings_count;
- const char *vertstrings_list[SHADERPERMUTATION_COUNT+1];
- const char *fragstrings_list[SHADERPERMUTATION_COUNT+1];
- char permutationname[256];
- if (r_shadow_program_compiledlight[permutation])
- return r_shadow_program_light[permutation];
- r_shadow_program_compiledlight[permutation] = true;
- vertstring = (char *)FS_LoadFile("glsl/light.vert", tempmempool, false, NULL);
- fragstring = (char *)FS_LoadFile("glsl/light.frag", tempmempool, false, NULL);
- vertstrings_count = 0;
- fragstrings_count = 0;
- permutationname[0] = 0;
- if (permutation & SHADERPERMUTATION_COLORMAPPING)
- {
- vertstrings_list[vertstrings_count++] = "#define USECOLORMAPPING\n";
- fragstrings_list[fragstrings_count++] = "#define USECOLORMAPPING\n";
- strlcat(permutationname, " colormapping", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_SPECULAR)
- {
- vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
- fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
- strlcat(permutationname, " specular", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_FOG)
- {
- vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
- fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
- strlcat(permutationname, " fog", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_CUBEFILTER)
- {
- vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
- fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
- strlcat(permutationname, " cubefilter", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_OFFSETMAPPING)
- {
- vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
- fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
- strlcat(permutationname, " offsetmapping", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_SURFACENORMALIZE)
- {
- vertstrings_list[vertstrings_count++] = "#define SURFACENORMALIZE\n";
- fragstrings_list[fragstrings_count++] = "#define SURFACENORMALIZE\n";
- strlcat(permutationname, " surfacenormalize", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_GEFORCEFX)
- {
- vertstrings_list[vertstrings_count++] = "#define GEFORCEFX\n";
- fragstrings_list[fragstrings_count++] = "#define GEFORCEFX\n";
- strlcat(permutationname, " halffloat", sizeof(permutationname));
- }
- vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
- fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
- r_shadow_program_light[permutation] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
- if (r_shadow_program_light[permutation])
- {
- qglUseProgramObjectARB(r_shadow_program_light[permutation]);
- qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Normal"), 0);CHECKGLERROR
- qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Color"), 1);CHECKGLERROR
- if (permutation & SHADERPERMUTATION_SPECULAR)
- {
- qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Gloss"), 2);CHECKGLERROR
- }
- if (permutation & SHADERPERMUTATION_CUBEFILTER)
- {
- qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Cube"), 3);CHECKGLERROR
- }
- if (permutation & SHADERPERMUTATION_FOG)
- {
- qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_FogMask"), 4);CHECKGLERROR
- }
- qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Pants"), 5);CHECKGLERROR
- qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Shirt"), 6);CHECKGLERROR
- qglUseProgramObjectARB(0);
- }
- else
- Con_Printf("permutation%s failed for shader %s, some features may not work properly!\n", permutationname, "glsl/light");
- if (fragstring)
- Mem_Free(fragstring);
- if (vertstring)
- Mem_Free(vertstring);
- return r_shadow_program_light[permutation];
-}