]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
added r_worldleafvisible flags array for more exact visibility checking (VIS_CullBox...
[xonotic/darkplaces.git] / r_shadow.c
index a386f0333772766875c3ba6ceb4f64f55af6044e..8a82f06411c73ad8e78c3f84dfbf5f9a9c68680b 100644 (file)
@@ -251,90 +251,47 @@ const char *builtinshader_light_vert =
 "// 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"
-"\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"
+"      // copy the surface texcoord\n"
+"      TexCoord = gl_MultiTexCoord0.st;\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"
+"      // 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"
-"      // 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"
 ;
 
@@ -389,7 +346,7 @@ const char *builtinshader_light_frag =
 "      //\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"
@@ -397,20 +354,16 @@ const char *builtinshader_light_frag =
 "#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"
@@ -418,9 +371,14 @@ const char *builtinshader_light_frag =
 "\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"
@@ -500,6 +458,11 @@ void r_shadow_start(void)
                        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
@@ -1665,16 +1628,19 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                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)
                {
@@ -1695,9 +1661,8 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
                }
                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);
@@ -2762,7 +2727,7 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
        if (numclusters)
        {
                for (i = 0;i < numclusters;i++)
-                       if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
+                       if (r_worldleafvisible[clusterlist[i]])
                                break;
                if (i == numclusters)
                        return;
@@ -2986,7 +2951,7 @@ rtexture_t *R_Shadow_LoadCubemap(const char *basename)
                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)))
                        {
@@ -3079,7 +3044,7 @@ void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, ve
        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;
@@ -3181,7 +3146,7 @@ void R_Shadow_SelectLightInView(void)
 void R_Shadow_LoadWorldLights(void)
 {
        int n, a, style, shadow, flags;
-       char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
+       char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
        float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
        if (r_refdef.worldmodel == NULL)
        {
@@ -3214,11 +3179,11 @@ void R_Shadow_LoadWorldLights(void)
                        }
                        */
                        t = s;
-                       while (*s && *s != '\n')
+                       while (*s && *s != '\n' && *s != '\r')
                                s++;
                        if (!*s)
                                break;
-                       *s = 0;
+                       tempchar = *s;
                        shadow = true;
                        // check for modifier flags
                        if (*t == '!')
@@ -3226,7 +3191,9 @@ void R_Shadow_LoadWorldLights(void)
                                shadow = false;
                                t++;
                        }
+                       *s = 0;
                        a = sscanf(t, "%f %f %f %f %f %f %f %d %s %f %f %f %f %f %f %f %f %i", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname, &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
+                       *s = tempchar;
                        if (a < 18)
                                flags = LIGHTFLAG_REALTIMEMODE;
                        if (a < 17)
@@ -3249,7 +3216,6 @@ void R_Shadow_LoadWorldLights(void)
                                cubemapname[strlen(cubemapname)-1] = 0;
                                strcpy(cubemapname, cubemapname + 1);
                        }
-                       *s = '\n';
                        if (a < 8)
                        {
                                Con_Printf("found %d parameters on line %i, should be 8 or more parameters (origin[0] origin[1] origin[2] radius color[0] color[1] color[2] style \"cubemapname\" corona angles[0] angles[1] angles[2] coronasizescale ambientscale diffusescale specularscale flags)\n", a, n + 1);
@@ -3258,7 +3224,10 @@ void R_Shadow_LoadWorldLights(void)
                        VectorScale(color, r_editlights_rtlightscolorscale.value, color);
                        radius *= r_editlights_rtlightssizescale.value;
                        R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
-                       s++;
+                       if (*s == '\r')
+                               s++;
+                       if (*s == '\n')
+                               s++;
                        n++;
                }
                if (*s)
@@ -3320,7 +3289,7 @@ void R_Shadow_SaveWorldLights(void)
 void R_Shadow_LoadLightsFile(void)
 {
        int n, a, style;
-       char name[MAX_QPATH], *lightsstring, *s, *t;
+       char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
        float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
        if (r_refdef.worldmodel == NULL)
        {
@@ -3337,13 +3306,14 @@ void R_Shadow_LoadLightsFile(void)
                while (*s)
                {
                        t = s;
-                       while (*s && *s != '\n')
+                       while (*s && *s != '\n' && *s != '\r')
                                s++;
                        if (!*s)
                                break;
+                       tempchar = *s;
                        *s = 0;
                        a = sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d", &origin[0], &origin[1], &origin[2], &falloff, &color[0], &color[1], &color[2], &subtract, &spotdir[0], &spotdir[1], &spotdir[2], &spotcone, &distbias, &style);
-                       *s = '\n';
+                       *s = tempchar;
                        if (a < 14)
                        {
                                Con_Printf("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1);
@@ -3353,7 +3323,10 @@ void R_Shadow_LoadLightsFile(void)
                        radius = bound(15, radius, 4096);
                        VectorScale(color, (2.0f / (8388608.0f)), color);
                        R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
-                       s++;
+                       if (*s == '\r')
+                               s++;
+                       if (*s == '\n')
+                               s++;
                        n++;
                }
                if (*s)