"// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
"// written by Forest 'LordHavoc' Hale\n"
"\n"
-"uniform vec3 LightColor;\n"
-"\n"
-"#ifdef USEOFFSETMAPPING\n"
-"uniform float OffsetMapping_Scale;\n"
-"uniform float OffsetMapping_Bias;\n"
-"#endif\n"
-"#ifdef USESPECULAR\n"
-"uniform float SpecularPower;\n"
-"#endif\n"
-"#ifdef USEFOG\n"
-"uniform float FogRangeRecip;\n"
-"#endif\n"
-"uniform float AmbientScale;\n"
-"uniform float DiffuseScale;\n"
-"#ifdef USESPECULAR\n"
-"uniform float SpecularScale;\n"
-"#endif\n"
-"\n"
-"uniform sampler2D Texture_Normal;\n"
-"uniform sampler2D Texture_Color;\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"
+"uniform vec3 LightPosition;\n"
"\n"
"varying vec2 TexCoord;\n"
"varying vec3 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"
-" // 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"
-" float colorscale = clamp(1.0 - dot(CubeVector, CubeVector), 0.0, 1.0);\n"
-"\n"
-"#ifdef USEFOG\n"
-" // apply fog\n"
-" colorscale *= texture2D(Texture_FogMask, vec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
-"#endif\n"
+" // copy the surface texcoord\n"
+" TexCoord = gl_MultiTexCoord0.st;\n"
"\n"
-"#ifdef USEOFFSETMAPPING\n"
-" vec2 OffsetVector = normalize(EyeVector).xy * vec2(-1, 1);\n"
-" vec2 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"
-" TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
-"#define TexCoord TexCoordOffset\n"
-"#endif\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"
-" // get the texels - with a blendmap we'd need to blend multiple here\n"
-" vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
-" vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
-"#ifdef USESPECULAR\n"
-" vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
-"#endif\n"
-"\n"
-" // calculate shading\n"
-" vec3 diffusenormal = normalize(LightVector);\n"
-" vec3 color = colortexel * (AmbientScale + DiffuseScale * clamp(dot(surfacenormal, diffusenormal), 0.0, 1.0));\n"
-"#ifdef USESPECULAR\n"
-" color += glosstexel * (SpecularScale * pow(clamp(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0, 1.0), SpecularPower));\n"
-"#endif\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"
-"#ifdef USECUBEFILTER\n"
-" // apply light cubemap filter\n"
-" color *= vec3(textureCube(Texture_Cube, CubeVector));\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"
-" // calculate fragment color\n"
-" gl_FragColor = vec4(LightColor * color * colorscale, 1);\n"
+" // transform vertex to camera space, using ftransform to match non-VS\n"
+" // rendering\n"
+" gl_Position = ftransform();\n"
"}\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"
-" float colorscale = clamp(1.0 - dot(CubeVector, CubeVector), 0.0, 1.0);\n"
+" float colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
"\n"
"#ifdef USEFOG\n"
" // apply fog\n"
"#endif\n"
"\n"
"#ifdef USEOFFSETMAPPING\n"
-" vec2 OffsetVector = normalize(EyeVector).xy * vec2(-1, 1);\n"
-" TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
-" TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
-" TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
-" TexCoord += OffsetVector * (texture2D(Texture_Normal, TexCoord).w * OffsetMapping_Scale + OffsetMapping_Bias);\n"
-"#endif\n"
-"\n"
-"#ifdef USECUBEFILTER\n"
-" // apply light cubemap filter\n"
-" LightColor *= vec3(textureCube(Texture_Cube, CubeVector));\n"
+" // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
+" vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
+" vec2 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 texels - with a blendmap we'd need to blend multiple here\n"
-" vec3 surfacenormal = vec3(texture2D(Texture_Normal, TexCoord)) * 2.0 - 1.0;\n"
+" vec3 surfacenormal = -1.0 + 2.0 * vec3(texture2D(Texture_Normal, TexCoord));\n"
" vec3 colortexel = vec3(texture2D(Texture_Color, TexCoord));\n"
"#ifdef USESPECULAR\n"
" vec3 glosstexel = vec3(texture2D(Texture_Gloss, TexCoord));\n"
"\n"
" // calculate shading\n"
" vec3 diffusenormal = normalize(LightVector);\n"
-" vec3 color = colortexel * (AmbientScale + DiffuseScale * clamp(dot(surfacenormal, diffusenormal), 0.0, 1.0));\n"
+" vec3 color = colortexel * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
"#ifdef USESPECULAR\n"
-" color += glosstexel * (SpecularScale * pow(clamp(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0, 1.0), SpecularPower));\n"
+" color += glosstexel * (SpecularScale * pow(max(dot(surfacenormal, normalize(diffusenormal + normalize(EyeVector))), 0.0), SpecularPower));\n"
+"#endif\n"
+"\n"
+"#ifdef USECUBEFILTER\n"
+" // apply light cubemap filter\n"
+" color *= vec3(textureCube(Texture_Cube, CubeVector));\n"
"#endif\n"
"\n"
" // calculate fragment color\n"
vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
+ if (!r_shadow_program_light[i])
+ {
+ Con_Printf("permutation %s %s %s %s failed for shader %s, some features may not work properly!\n", i & 1 ? "specular" : "", i & 2 ? "fog" : "", i & 4 ? "cubefilter" : "", i & 8 ? "offsetmapping" : "", "glsl/light");
+ continue;
+ }
qglUseProgramObjectARB(r_shadow_program_light[i]);
qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
CHECKGLERROR
perm = 0;
- if (specularscale)
+ // only add a feature to the permutation if that permutation exists
+ // (otherwise it might end up not using a shader at all, which looks
+ // worse than using less features)
+ if (specularscale && r_shadow_program_light[perm | SHADERPERMUTATION_SPECULAR])
perm |= SHADERPERMUTATION_SPECULAR;
- //if (fog)
+ //if (fog && r_shadow_program_light[perm | SHADERPERMUTATION_FOG])
// perm |= SHADERPERMUTATION_FOG;
- if (lightcubemap)
+ if (lightcubemap && r_shadow_program_light[perm | SHADERPERMUTATION_CUBEFILTER])
perm |= SHADERPERMUTATION_CUBEFILTER;
- if (r_shadow_glsl_offsetmapping.integer)
+ if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[perm | SHADERPERMUTATION_OFFSETMAPPING])
perm |= SHADERPERMUTATION_OFFSETMAPPING;
prog = r_shadow_program_light[perm];
- qglUseProgramObjectARB(r_shadow_program_light[perm]);CHECKGLERROR
+ qglUseProgramObjectARB(prog);CHECKGLERROR
// TODO: support fog (after renderer is converted to texture fog)
if (perm & SHADERPERMUTATION_FOG)
{
}
if (perm & SHADERPERMUTATION_OFFSETMAPPING)
{
- // these are * 0.25 because the offsetmapping shader does the process 4 times
- qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value * 0.25);CHECKGLERROR
- qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value * 0.25);CHECKGLERROR
+ qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
+ qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
}
CHECKGLERROR
GL_LockArrays(0, numverts);
for (i = 0;i < 6;i++)
{
// generate an image name based on the base and and suffix
- snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
+ dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
// load it
if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
{
light->corona = corona;
if (!cubemapname)
cubemapname = "";
- strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
+ strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
light->coronasizescale = coronasizescale;
light->ambientscale = ambientscale;
light->diffusescale = diffusescale;