]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
fix incredibly stupid bug in Memory_Init, it was clearing the pool chain AFTER alloca...
[xonotic/darkplaces.git] / r_shadow.c
index 8eb69cbfd82d5f6b35b6fa75f5ba04510ad5cdac..2f4a68e91b2567666402df352f9e37ee13e809a3 100644 (file)
@@ -217,8 +217,6 @@ cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization
 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_shadow_glsl lighting)"};
-cvar_t r_shadow_visiblelighting = {0, "r_shadow_visiblelighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
-cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0", "shows areas shadowed by lights, useful for finding out why some areas of a map render slowly (bright blue = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
 cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1", "enables use of OpenGL 2.0 pixel shaders for lighting"};
 cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "0", "enables offset mapping effect (also known as parallax mapping or sometimes as virtual displacement mapping, not as good as relief mapping or silohuette mapping but much faster), can cause strange artifacts on many textures, requires bumpmaps for depth information (normalmaps can have depth information as alpha channel, but most do not)"};
 cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "-0.04", "how deep the offset mapping effect is, and whether it is inward or outward"};
@@ -241,8 +239,6 @@ dlight_t *r_shadow_selectedlight;
 dlight_t r_shadow_bufferlight;
 vec3_t r_editlights_cursorlocation;
 
-rtexture_t *lighttextures[5];
-
 extern int con_vislines;
 
 typedef struct cubemapinfo_s
@@ -265,6 +261,9 @@ static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
 #define SHADERPERMUTATION_GEFORCEFX (1<<6)
 #define SHADERPERMUTATION_COUNT (1<<7)
 
+// indicates if we have tried compiling this shader permutation yet
+qboolean r_shadow_program_compiledlight[SHADERPERMUTATION_COUNT];
+// GLSL program object number, or 0 if compile failed
 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
 
 void R_Shadow_UncompileWorldLights(void);
@@ -434,7 +433,9 @@ const char *builtinshader_light_frag =
 "\n"
 "      // calculate shading\n"
 "      myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
-"      myhvec3 color = myhvec3(texture2D(Texture_Color, TexCoord));\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"
@@ -454,6 +455,97 @@ const char *builtinshader_light_frag =
 "}\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];
+}
+
 void r_shadow_start(void)
 {
        int i;
@@ -486,98 +578,9 @@ void r_shadow_start(void)
        r_shadow_buffer_surfacepvs = NULL;
        r_shadow_buffer_surfacelist = NULL;
        for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
+       {
+               r_shadow_program_compiledlight[i] = false;
                r_shadow_program_light[i] = 0;
-       if (gl_support_fragment_shader)
-       {
-               char *vertstring, *fragstring;
-               int vertstrings_count;
-               int fragstrings_count;
-               const char *vertstrings_list[SHADERPERMUTATION_COUNT+1];
-               const char *fragstrings_list[SHADERPERMUTATION_COUNT+1];
-               vertstring = (char *)FS_LoadFile("glsl/light.vert", tempmempool, false, NULL);
-               fragstring = (char *)FS_LoadFile("glsl/light.frag", tempmempool, false, NULL);
-               for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
-               {
-                       char permutationname[256];
-                       vertstrings_count = 0;
-                       fragstrings_count = 0;
-                       permutationname[0] = 0;
-                       if (i & SHADERPERMUTATION_COLORMAPPING)
-                       {
-                               vertstrings_list[vertstrings_count++] = "#define USECOLORMAPPING\n";
-                               fragstrings_list[fragstrings_count++] = "#define USECOLORMAPPING\n";
-                               strlcat(permutationname, " colormapping", sizeof(permutationname));
-                       }
-                       if (i & SHADERPERMUTATION_SPECULAR)
-                       {
-                               vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
-                               fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
-                               strlcat(permutationname, " specular", sizeof(permutationname));
-                       }
-                       if (i & SHADERPERMUTATION_FOG)
-                       {
-                               vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
-                               fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
-                               strlcat(permutationname, " fog", sizeof(permutationname));
-                       }
-                       if (i & SHADERPERMUTATION_CUBEFILTER)
-                       {
-                               vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
-                               fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
-                               strlcat(permutationname, " cubefilter", sizeof(permutationname));
-                       }
-                       if (i & SHADERPERMUTATION_OFFSETMAPPING)
-                       {
-                               vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
-                               fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
-                               strlcat(permutationname, " offsetmapping", sizeof(permutationname));
-                       }
-                       if (i & SHADERPERMUTATION_SURFACENORMALIZE)
-                       {
-                               vertstrings_list[vertstrings_count++] = "#define SURFACENORMALIZE\n";
-                               fragstrings_list[fragstrings_count++] = "#define SURFACENORMALIZE\n";
-                               strlcat(permutationname, " surfacenormalize", sizeof(permutationname));
-                       }
-                       if (i & SHADERPERMUTATION_GEFORCEFX)
-                       {
-                               // if the extension does not exist, don't try to compile it
-                               if (!gl_support_half_float)
-                                       continue;
-                               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[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
-                       if (!r_shadow_program_light[i])
-                       {
-                               Con_Printf("permutation%s failed for shader %s, some features may not work properly!\n", permutationname, "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
-                       if (i & SHADERPERMUTATION_SPECULAR)
-                       {
-                               qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
-                       }
-                       if (i & SHADERPERMUTATION_CUBEFILTER)
-                       {
-                               qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
-                       }
-                       if (i & SHADERPERMUTATION_FOG)
-                       {
-                               qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
-                       }
-                       qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Pants"), 5);CHECKGLERROR
-                       qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Shirt"), 6);CHECKGLERROR
-               }
-               qglUseProgramObjectARB(0);
-               if (fragstring)
-                       Mem_Free(fragstring);
-               if (vertstring)
-                       Mem_Free(vertstring);
        }
 }
 
@@ -674,8 +677,8 @@ void R_Shadow_Help_f(void)
 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
-"r_shadow_visiblelighting : useful for performance testing; bright = slow!\n"
-"r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
+"r_showlighting : useful for performance testing; bright = slow!\n"
+"r_showshadowvolumes : useful for performance testing; bright = slow!\n"
 "Commands:\n"
 "r_shadow_help : this help\n"
        );
@@ -707,8 +710,6 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
        Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
        Cvar_RegisterVariable(&r_shadow_texture3d);
-       Cvar_RegisterVariable(&r_shadow_visiblelighting);
-       Cvar_RegisterVariable(&r_shadow_visiblevolumes);
        Cvar_RegisterVariable(&r_shadow_glsl);
        Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping);
        Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_scale);
@@ -1145,7 +1146,7 @@ void R_Shadow_RenderMode_Begin(void)
        else
                r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
 
-       if (r_shadow_glsl.integer && r_shadow_program_light[0])
+       if (r_shadow_glsl.integer && gl_support_fragment_shader)
                r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
        else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
                r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
@@ -1183,7 +1184,8 @@ void R_Shadow_RenderMode_StencilShadowVolumes(void)
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(false);
        GL_DepthTest(true);
-       qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
+       if (!r_showtrispass)
+               qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
        //if (r_shadow_shadow_polygonoffset.value != 0)
        //{
        //      qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
@@ -1224,7 +1226,8 @@ void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
        GL_BlendFunc(GL_ONE, GL_ONE);
        GL_DepthMask(false);
        GL_DepthTest(true);
-       qglPolygonOffset(0, 0);
+       if (!r_showtrispass)
+               qglPolygonOffset(0, 0);
        //qglDisable(GL_POLYGON_OFFSET_FILL);
        GL_Color(1, 1, 1, 1);
        GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
@@ -1271,8 +1274,9 @@ void R_Shadow_RenderMode_VisibleShadowVolumes(void)
        R_Shadow_RenderMode_Reset();
        GL_BlendFunc(GL_ONE, GL_ONE);
        GL_DepthMask(false);
-       GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
-       qglPolygonOffset(0, 0);
+       GL_DepthTest(!r_showdisabledepthtest.integer);
+       if (!r_showtrispass)
+               qglPolygonOffset(0, 0);
        GL_Color(0.0, 0.0125, 0.1, 1);
        GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
        qglDepthFunc(GL_GEQUAL);
@@ -1287,8 +1291,9 @@ void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transpar
        R_Shadow_RenderMode_Reset();
        GL_BlendFunc(GL_ONE, GL_ONE);
        GL_DepthMask(false);
-       GL_DepthTest(r_shadow_visiblelighting.integer < 2);
-       qglPolygonOffset(0, 0);
+       GL_DepthTest(!r_showdisabledepthtest.integer);
+       if (!r_showtrispass)
+               qglPolygonOffset(0, 0);
        GL_Color(0.1, 0.0125, 0, 1);
        GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
        if (transparent)
@@ -1311,7 +1316,8 @@ void R_Shadow_RenderMode_End(void)
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(true);
        GL_DepthTest(true);
-       qglPolygonOffset(0, 0);
+       if (!r_showtrispass)
+               qglPolygonOffset(0, 0);
        //qglDisable(GL_POLYGON_OFFSET_FILL);
        GL_Color(1, 1, 1, 1);
        GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
@@ -1422,7 +1428,7 @@ extern float *rsurface_vertex3f;
 extern float *rsurface_svector3f;
 extern float *rsurface_tvector3f;
 extern float *rsurface_normal3f;
-extern void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg);
+extern void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg, qboolean generatenormals, qboolean generatetangents);
 
 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
 {
@@ -1587,66 +1593,72 @@ static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out3f, int numve
        }
 }
 
-static void R_Shadow_RenderSurfacesLighting_VisibleLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale)
+static void R_Shadow_RenderSurfacesLighting_VisibleLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
 {
        // used to display how many times a surface is lit for level design purposes
        int surfacelistindex;
        rmeshstate_t m;
-       qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
-       qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
-       qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
-       qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
-       qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
-       qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
-       qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
-       if (!doambientbase && !dodiffusebase && !doambientpants && !dodiffusepants && !doambientshirt && !dodiffuseshirt && !dospecular)
-               return;
        GL_Color(0.1, 0.025, 0, 1);
        memset(&m, 0, sizeof(m));
        R_Mesh_State(&m);
        for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
        {
                const msurface_t *surface = surfacelist[surfacelistindex];
-               RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
+               RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, false, false);
                GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
                R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);
                GL_LockArrays(0, 0);
        }
 }
 
-static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale)
+static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
 {
        // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
        int surfacelistindex;
-       qboolean dobase = (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
-       qboolean dopants = (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
-       qboolean doshirt = (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
-       qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
-       if (!dobase && !dopants && !doshirt && !dospecular)
-               return;
        // select a permutation of the lighting shader appropriate to this
        // combination of texture, entity, light source, and fogging, only use the
        // minimum features necessary to avoid wasting rendering time in the
        // fragment shader on features that are not being used
        r_shadow_lightpermutation = 0;
-       // 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 (fogenabled && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_FOG])
+       if (fogenabled)
                r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
-       if ((dopants || doshirt) && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_COLORMAPPING])
+       if ((dopants || doshirt))
                r_shadow_lightpermutation |= SHADERPERMUTATION_COLORMAPPING;
-       if (specularscale > 0 && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR])
+       if (specularscale > 0)
                r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
-       if (r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
+       if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
-       if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING])
+       if (r_shadow_glsl_offsetmapping.integer)
                r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
-       if (r_shadow_glsl_surfacenormalize.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SURFACENORMALIZE])
+       if (r_shadow_glsl_surfacenormalize.integer)
                r_shadow_lightpermutation |= SHADERPERMUTATION_SURFACENORMALIZE;
-       if (r_shadow_glsl_usehalffloat.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_GEFORCEFX])
+       if (r_shadow_glsl_usehalffloat.integer)
                r_shadow_lightpermutation |= SHADERPERMUTATION_GEFORCEFX;
        r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
+       if (!r_shadow_lightprog)
+       {
+               if (!r_shadow_program_compiledlight[r_shadow_lightpermutation])
+                       r_shadow_lightprog = R_Shadow_CompileShaderPermutation(r_shadow_lightpermutation);
+               if (!r_shadow_lightprog)
+               {
+                       // remove features until we find a valid permutation
+                       int i;
+                       for (i = SHADERPERMUTATION_COUNT-1;;i>>=1)
+                       {
+                               // reduce i more quickly whenever it would not remove any bits
+                               if (r_shadow_lightpermutation < i)
+                                       continue;
+                               r_shadow_lightpermutation &= i;
+                               if (!r_shadow_program_compiledlight[r_shadow_lightpermutation])
+                                       R_Shadow_CompileShaderPermutation(r_shadow_lightpermutation);
+                               r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
+                               if (r_shadow_lightprog)
+                                       break;
+                               if (!i)
+                                       return; // utterly failed
+                       }
+               }
+       }
        qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR
        R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
        R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
@@ -1686,14 +1698,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *en
        {
                const msurface_t *surface = surfacelist[surfacelistindex];
                const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
-               RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
-               if (!rsurface_svector3f)
-               {
-                       rsurface_svector3f = varray_svector3f;
-                       rsurface_tvector3f = varray_tvector3f;
-                       rsurface_normal3f = varray_normal3f;
-                       Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, r_smoothnormals_areaweighting.integer);
-               }
+               RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, false, true);
                R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
                R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
                R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
@@ -2377,42 +2382,37 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(const entity
        GL_LockArrays(0, 0);
 }
 
-static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale)
+static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
 {
        // ARB path (any Geforce, any Radeon)
        int surfacelistindex;
-       qboolean doambientbase = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
-       qboolean dodiffusebase = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorbase) > 0.00001 && basetexture != r_texture_black;
-       qboolean doambientpants = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
-       qboolean dodiffusepants = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorpants) > 0.00001 && pantstexture != r_texture_black;
-       qboolean doambientshirt = r_shadow_rtlight->ambientscale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
-       qboolean dodiffuseshirt = r_shadow_rtlight->diffusescale * VectorLength2(lightcolorshirt) > 0.00001 && shirttexture != r_texture_black;
-       qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
-       if (!doambientbase && !dodiffusebase && !doambientpants && !dodiffusepants && !doambientshirt && !dodiffuseshirt && !dospecular)
+       qboolean doambient = r_shadow_rtlight->ambientscale > 0;
+       qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
+       qboolean dospecular = specularscale > 0;
+       if (!doambient && !dodiffuse && !dospecular)
                return;
        for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
        {
                const msurface_t *surface = surfacelist[surfacelistindex];
-               RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
-               if (!rsurface_svector3f)
-               {
-                       rsurface_svector3f = varray_svector3f;
-                       rsurface_tvector3f = varray_tvector3f;
-                       rsurface_normal3f = varray_normal3f;
-                       Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, r_smoothnormals_areaweighting.integer);
-               }
-               if (doambientbase)
+               RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, false, true);
+               if (doambient)
                        R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale);
-               if (doambientpants)
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale);
-               if (doambientshirt)
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale);
-               if (dodiffusebase)
+               if (dodiffuse)
                        R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale);
-               if (dodiffusepants)
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale);
-               if (dodiffuseshirt)
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale);
+               if (dopants)
+               {
+                       if (doambient)
+                               R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale);
+                       if (dodiffuse)
+                               R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale);
+               }
+               if (doshirt)
+               {
+                       if (doambient)
+                               R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale);
+                       if (dodiffuse)
+                               R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale);
+               }
                if (dospecular)
                        R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(ent, texture, surface, lightcolorbase, glosstexture, normalmaptexture, specularscale);
        }
@@ -2488,33 +2488,19 @@ goodpass:
        }
 }
 
-static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale)
+static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
 {
        int surfacelistindex;
        float ambientcolorbase[3], diffusecolorbase[3];
        float ambientcolorpants[3], diffusecolorpants[3];
        float ambientcolorshirt[3], diffusecolorshirt[3];
        rmeshstate_t m;
-       qboolean dobase  = basetexture != r_texture_black;
-       qboolean dopants = pantstexture != r_texture_black;
-       qboolean doshirt = shirttexture != r_texture_black;
-       if (!dobase && !dopants && !doshirt)
-               return;
-       if (dobase)
-       {
-               VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2, ambientcolorbase);
-               VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2, diffusecolorbase);
-       }
-       if (dopants)
-       {
-               VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2, ambientcolorpants);
-               VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2, diffusecolorpants);
-       }
-       if (doshirt)
-       {
-               VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2, ambientcolorshirt);
-               VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2, diffusecolorshirt);
-       }
+       VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2, ambientcolorbase);
+       VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2, diffusecolorbase);
+       VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2, ambientcolorpants);
+       VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2, diffusecolorpants);
+       VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2, ambientcolorshirt);
+       VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2, diffusecolorshirt);
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
        memset(&m, 0, sizeof(m));
        m.tex[0] = R_GetTexture(basetexture);
@@ -2545,14 +2531,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *
        for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
        {
                const msurface_t *surface = surfacelist[surfacelistindex];
-               RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
-               if (!rsurface_svector3f)
-               {
-                       rsurface_svector3f = varray_svector3f;
-                       rsurface_tvector3f = varray_tvector3f;
-                       rsurface_normal3f = varray_normal3f;
-                       Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, r_smoothnormals_areaweighting.integer);
-               }
+               RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, true, false);
                // OpenGL 1.1 path (anything)
                R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
                R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
@@ -2574,11 +2553,8 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *
 #endif
                        }
                }
-               if (dobase)
-               {
-                       R_Mesh_TexBind(0, R_GetTexture(basetexture));
-                       R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorbase, ambientcolorbase);
-               }
+               R_Mesh_TexBind(0, R_GetTexture(basetexture));
+               R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorbase, ambientcolorbase);
                if (dopants)
                {
                        R_Mesh_TexBind(0, R_GetTexture(pantstexture));
@@ -2597,8 +2573,11 @@ void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t
        // FIXME: support MATERIALFLAG_NODEPTHTEST
        vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
        rtexture_t *basetexture;
+       rtexture_t *pantstexture;
+       rtexture_t *shirttexture;
        rtexture_t *glosstexture;
        float specularscale;
+       qboolean dopants, doshirt;
        glosstexture = r_texture_black;
        specularscale = 0;
        if (r_shadow_gloss.integer > 0)
@@ -2630,28 +2609,46 @@ void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t
                qglDisable(GL_CULL_FACE);
        else
                qglEnable(GL_CULL_FACE);
-       if ((VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor)) >= (1.0f / 1048576.0f))
-       {
-               lightcolorpants[0] = r_shadow_rtlight->currentcolor[0] * ent->colormap_pantscolor[0] * texture->currentalpha;
-               lightcolorpants[1] = r_shadow_rtlight->currentcolor[1] * ent->colormap_pantscolor[1] * texture->currentalpha;
-               lightcolorpants[2] = r_shadow_rtlight->currentcolor[2] * ent->colormap_pantscolor[2] * texture->currentalpha;
-               lightcolorshirt[0] = r_shadow_rtlight->currentcolor[0] * ent->colormap_shirtcolor[0] * texture->currentalpha;
-               lightcolorshirt[1] = r_shadow_rtlight->currentcolor[1] * ent->colormap_shirtcolor[1] * texture->currentalpha;
-               lightcolorshirt[2] = r_shadow_rtlight->currentcolor[2] * ent->colormap_shirtcolor[2] * texture->currentalpha;
-               basetexture = texture->skin.base;
+       dopants = texture->skin.pants != NULL && VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f);
+       doshirt = texture->skin.shirt != NULL && VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
+       if (dopants + doshirt)
+       {
+               if (dopants)
+               {
+                       lightcolorpants[0] = lightcolorbase[0] * ent->colormap_pantscolor[0];
+                       lightcolorpants[1] = lightcolorbase[1] * ent->colormap_pantscolor[1];
+                       lightcolorpants[2] = lightcolorbase[2] * ent->colormap_pantscolor[2];
+               }
+               else
+               {
+                       pantstexture = r_texture_black;
+                       VectorClear(lightcolorpants);
+               }
+               if (doshirt)
+               {
+                       shirttexture = texture->skin.shirt;
+                       lightcolorshirt[0] = lightcolorbase[0] * ent->colormap_shirtcolor[0];
+                       lightcolorshirt[1] = lightcolorbase[1] * ent->colormap_shirtcolor[1];
+                       lightcolorshirt[2] = lightcolorbase[2] * ent->colormap_shirtcolor[2];
+               }
+               else
+               {
+                       shirttexture = r_texture_black;
+                       VectorClear(lightcolorshirt);
+               }
                switch (r_shadow_rendermode)
                {
                case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
-                       R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
+                       R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, dopants, doshirt);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_GLSL:
-                       R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
+                       R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, dopants, doshirt);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_DOT3:
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, dopants, doshirt);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
-                       R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
+                       R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, dopants, doshirt);
                        break;
                default:
                        Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
@@ -2664,16 +2661,16 @@ void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t
                switch (r_shadow_rendermode)
                {
                case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
-                       R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale);
+                       R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale, false, false);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_GLSL:
-                       R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale);
+                       R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale, false, false);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_DOT3:
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale, false, false);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
-                       R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale);
+                       R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale, false, false);
                        break;
                default:
                        Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
@@ -3003,6 +3000,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                        entity_render_t *ent = r_refdef.entities[i];
                        if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
                         && ent->model
+                        && !(ent->flags & RENDER_TRANSPARENT)
                         && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
                        {
                                // about the VectorDistance2 - light emitting entities should not cast their own shadow
@@ -3018,46 +3016,53 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        if (!numlightentities)
                return;
 
+       // don't let sound skip if going slow
+       if (r_refdef.extraupdate)
+               S_ExtraUpdate ();
+
        // make this the active rtlight for rendering purposes
        R_Shadow_RenderMode_ActiveLight(rtlight);
        // count this light in the r_speeds
        renderstats.lights++;
 
-       // draw stencil shadow volumes to mask off pixels that are in shadow
-       // so that they won't receive lighting
        usestencil = false;
-       if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
+       if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
        {
-               usestencil = true;
-               R_Shadow_RenderMode_StencilShadowVolumes();
-               for (i = 0;i < numshadowentities;i++)
-                       R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
+               // draw stencil shadow volumes to mask off pixels that are in shadow
+               // so that they won't receive lighting
+               if (gl_stencil)
+               {
+                       usestencil = true;
+                       R_Shadow_RenderMode_StencilShadowVolumes();
+                       for (i = 0;i < numshadowentities;i++)
+                               R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
+               }
+
+               // optionally draw visible shape of the shadow volumes
+               // for performance analysis by level designers
+               if (r_showshadowvolumes.integer)
+               {
+                       R_Shadow_RenderMode_VisibleShadowVolumes();
+                       for (i = 0;i < numshadowentities;i++)
+                               R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
+               }
        }
 
-       // draw lighting in the unmasked areas
-       if (numlightentities && !visible)
+       if (numlightentities)
        {
+               // draw lighting in the unmasked areas
                R_Shadow_RenderMode_Lighting(usestencil, false);
                for (i = 0;i < numlightentities;i++)
                        R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
-       }
-
-       // optionally draw visible shape of the shadow volumes
-       // for performance analysis by level designers
-       if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
-       {
-               R_Shadow_RenderMode_VisibleShadowVolumes();
-               for (i = 0;i < numshadowentities;i++)
-                       R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
-       }
 
-       // optionally draw the illuminated areas
-       // for performance analysis by level designers
-       if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
-       {
-               R_Shadow_RenderMode_VisibleLighting(usestencil, false);
-               for (i = 0;i < numlightentities;i++)
-                       R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
+               // optionally draw the illuminated areas
+               // for performance analysis by level designers
+               if (r_showlighting.integer)
+               {
+                       R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
+                       for (i = 0;i < numlightentities;i++)
+                               R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
+               }
        }
 }
 
@@ -3280,7 +3285,7 @@ void R_Shadow_SelectLight(dlight_t *light)
 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
 {
        float scale = r_editlights_cursorgrid.value * 0.5f;
-       R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[0], NULL, false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
+       R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[0]->tex, NULL, false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
 }
 
 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
@@ -3292,24 +3297,16 @@ void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, in
                intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
        if (!light->shadow)
                intensity *= 0.5f;
-       R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[surfacenumber], NULL, false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
+       R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacenumber]->tex, NULL, false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
 }
 
 void R_Shadow_DrawLightSprites(void)
 {
        int i;
-       cachepic_t *pic;
        dlight_t *light;
 
-       for (i = 0;i < 5;i++)
-       {
-               lighttextures[i] = NULL;
-               if ((pic = Draw_CachePic(va("gfx/crosshair%i", i + 1), true)))
-                       lighttextures[i] = pic->tex;
-       }
-
        for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
-               R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, i % 5, &light->rtlight);
+               R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, i % NUMCROSSHAIRS, &light->rtlight);
        R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
 }