]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
changed behavior of r_showtris (now only affects geometry in the game view, not sky...
[xonotic/darkplaces.git] / r_shadow.c
index 7f39f3253bb93af21a0a21b1a680fa0f647bcf95..f4b0524ae44b0e493c01b756193fcd6dda88370f 100644 (file)
@@ -142,20 +142,22 @@ demonstrated by the game Doom3.
 
 extern void R_Shadow_EditLights_Init(void);
 
-typedef enum r_shadowstage_e
+typedef enum r_shadow_rendermode_e
 {
-       R_SHADOWSTAGE_NONE,
-       R_SHADOWSTAGE_STENCIL,
-       R_SHADOWSTAGE_STENCILTWOSIDE,
-       R_SHADOWSTAGE_LIGHT_VERTEX,
-       R_SHADOWSTAGE_LIGHT_DOT3,
-       R_SHADOWSTAGE_LIGHT_GLSL,
-       R_SHADOWSTAGE_VISIBLEVOLUMES,
-       R_SHADOWSTAGE_VISIBLELIGHTING,
+       R_SHADOW_RENDERMODE_NONE,
+       R_SHADOW_RENDERMODE_STENCIL,
+       R_SHADOW_RENDERMODE_STENCILTWOSIDE,
+       R_SHADOW_RENDERMODE_LIGHT_VERTEX,
+       R_SHADOW_RENDERMODE_LIGHT_DOT3,
+       R_SHADOW_RENDERMODE_LIGHT_GLSL,
+       R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
+       R_SHADOW_RENDERMODE_VISIBLELIGHTING,
 }
-r_shadowstage_t;
+r_shadow_rendermode_t;
 
-r_shadowstage_t r_shadowstage = R_SHADOWSTAGE_NONE;
+r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
+r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
+r_shadow_rendermode_t r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_NONE;
 
 mempool_t *r_shadow_mempool;
 
@@ -174,11 +176,11 @@ int *vertexremap;
 int vertexupdatenum;
 
 int r_shadow_buffer_numleafpvsbytes;
-qbyte *r_shadow_buffer_leafpvs;
+unsigned char *r_shadow_buffer_leafpvs;
 int *r_shadow_buffer_leaflist;
 
 int r_shadow_buffer_numsurfacepvsbytes;
-qbyte *r_shadow_buffer_surfacepvs;
+unsigned char *r_shadow_buffer_surfacepvs;
 int *r_shadow_buffer_surfacelist;
 
 rtexturepool_t *r_shadow_texturepool;
@@ -191,46 +193,43 @@ char r_shadow_mapname[MAX_QPATH];
 // used only for light filters (cubemaps)
 rtexturepool_t *r_shadow_filters_texturepool;
 
-cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
-cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
-cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
-cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
-cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
-cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
-cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
-cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
-cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
-cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
-cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
-cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
-cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1"};
-cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0"};
-cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
-cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
-cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
-cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
-cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1"};
-cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1"};
-cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
-cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
-cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
-cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
-cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
-cvar_t r_shadow_visiblelighting = {0, "r_shadow_visiblelighting", "0"};
-cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
-cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1"};
-cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "0"};
-cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "-0.04"};
-cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "0.04"};
-cvar_t r_shadow_glsl_usehalffloat = {0, "r_shadow_glsl_usehalffloat", "0"};
-cvar_t r_shadow_glsl_surfacenormalize = {0, "r_shadow_glsl_surfacenormalize", "1"};
-cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
-cvar_t r_editlights = {0, "r_editlights", "0"};
-cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024"};
-cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0"};
-cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4"};
-cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4"};
-cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
+cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
+cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
+cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
+cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
+cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
+cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
+cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_shadow_glsl lighting)"};
+cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_shadow_glsl lighting)"};
+cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
+cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
+cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
+cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
+cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
+cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal culling optimizations on dynamic lights (slow!  you probably don't want this!)"};
+cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
+cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1", "enables shadows from dynamic lights when using full world lighting"};
+cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
+cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
+cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
+cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
+cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
+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_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"};
+cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "0.04", "pushes the effect closer/further"};
+cvar_t r_shadow_glsl_usehalffloat = {0, "r_shadow_glsl_usehalffloat", "0", "use half and hvec variables in GLSL shader for a speed gain (NVIDIA only)"};
+cvar_t r_shadow_glsl_surfacenormalize = {0, "r_shadow_glsl_surfacenormalize", "1", "normalize bumpmap texels in GLSL shader, produces a more rounded look on small bumps and dents"};
+cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
+cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
+cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
+cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
+cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
+cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
+cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
 
 float r_shadow_attenpower, r_shadow_attenscale;
 
@@ -255,13 +254,14 @@ cubemapinfo_t;
 static int numcubemaps;
 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
 
-#define SHADERPERMUTATION_SPECULAR (1<<0)
-#define SHADERPERMUTATION_FOG (1<<1)
-#define SHADERPERMUTATION_CUBEFILTER (1<<2)
-#define SHADERPERMUTATION_OFFSETMAPPING (1<<3)
-#define SHADERPERMUTATION_SURFACENORMALIZE (1<<4)
-#define SHADERPERMUTATION_GEFORCEFX (1<<5)
-#define SHADERPERMUTATION_COUNT (1<<6)
+#define SHADERPERMUTATION_COLORMAPPING (1<<0)
+#define SHADERPERMUTATION_SPECULAR (1<<1)
+#define SHADERPERMUTATION_FOG (1<<2)
+#define SHADERPERMUTATION_CUBEFILTER (1<<3)
+#define SHADERPERMUTATION_OFFSETMAPPING (1<<4)
+#define SHADERPERMUTATION_SURFACENORMALIZE (1<<5)
+#define SHADERPERMUTATION_GEFORCEFX (1<<6)
+#define SHADERPERMUTATION_COUNT (1<<7)
 
 GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
 
@@ -280,10 +280,23 @@ 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 vec3 CubeVector;\n"
+"varying myhvec3 CubeVector;\n"
 "varying vec3 LightVector;\n"
 "\n"
 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
@@ -306,16 +319,16 @@ const char *builtinshader_light_vert =
 "      // (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"
+"      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"
+"      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"
@@ -358,8 +371,15 @@ const char *builtinshader_light_frag =
 "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"
@@ -371,7 +391,7 @@ const char *builtinshader_light_frag =
 "#endif\n"
 "\n"
 "varying vec2 TexCoord;\n"
-"varying vec3 CubeVector;\n"
+"varying myhvec3 CubeVector;\n"
 "varying vec3 LightVector;\n"
 "#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
 "varying vec3 EyeVector;\n"
@@ -412,10 +432,16 @@ const char *builtinshader_light_frag =
 "\n"
 "      // calculate shading\n"
 "      myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
-"      myhvec3 color = myhvec3(texture2D(Texture_Color, TexCoord)) * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\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"
+"      color += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower);\n"
 "#endif\n"
 "\n"
 "#ifdef USECUBEFILTER\n"
@@ -468,36 +494,49 @@ void r_shadow_start(void)
                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);
-               fragstring = (char *)FS_LoadFile("glsl/light.frag", tempmempool, false);
+               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)
                        {
@@ -506,13 +545,14 @@ void r_shadow_start(void)
                                        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 %s %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" : "", i & 16 ? "surfacenormalize" : "", i & 32 ? "geforcefx" : "", "glsl/light");
+                               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]);
@@ -530,6 +570,8 @@ void r_shadow_start(void)
                        {
                                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)
@@ -631,10 +673,9 @@ void R_Shadow_Help_f(void)
 "r_shadow_scissor : use scissor optimization\n"
 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
-"r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\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"
        );
@@ -665,10 +706,7 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_scissor);
        Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
        Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
-       Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
        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);
@@ -681,7 +719,7 @@ void R_Shadow_Init(void)
                Cvar_SetValue("r_shadow_gloss", 2);
                Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
        }
-       Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
+       Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
        R_Shadow_EditLights_Init();
        r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
        r_shadow_worldlightchain = NULL;
@@ -749,7 +787,7 @@ static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
                if (r_shadow_buffer_leaflist)
                        Mem_Free(r_shadow_buffer_leaflist);
                r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
-               r_shadow_buffer_leafpvs = (qbyte *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
+               r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
                r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
        }
        if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
@@ -759,7 +797,7 @@ static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
                if (r_shadow_buffer_surfacelist)
                        Mem_Free(r_shadow_buffer_surfacelist);
                r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
-               r_shadow_buffer_surfacepvs = (qbyte *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
+               r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
                r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
        }
 }
@@ -978,7 +1016,7 @@ void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *verte
        m.pointer_vertex = vertex3f;
        R_Mesh_State(&m);
        GL_LockArrays(0, numvertices);
-       if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
+       if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
        {
                // decrement stencil if backface is behind depthbuffer
                qglCullFace(GL_BACK); // quake is backwards, this culls front faces
@@ -996,14 +1034,14 @@ static void R_Shadow_MakeTextures(void)
 {
        int x, y, z, d;
        float v[3], intensity;
-       qbyte *data;
+       unsigned char *data;
        R_FreeTexturePool(&r_shadow_texturepool);
        r_shadow_texturepool = R_AllocTexturePool();
        r_shadow_attenpower = r_shadow_lightattenuationpower.value;
        r_shadow_attenscale = r_shadow_lightattenuationscale.value;
 #define ATTEN2DSIZE 64
 #define ATTEN3DSIZE 32
-       data = (qbyte *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
+       data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
        for (y = 0;y < ATTEN2DSIZE;y++)
        {
                for (x = 0;x < ATTEN2DSIZE;x++)
@@ -1059,32 +1097,24 @@ void R_Shadow_ValidateCvars(void)
 
 // light currently being rendered
 rtlight_t *r_shadow_rtlight;
-// light filter cubemap being used by the light
-static rtexture_t *r_shadow_lightcubemap;
 
 // this is the location of the eye in entity space
-static vec3_t r_shadow_entityeyeorigin;
+vec3_t r_shadow_entityeyeorigin;
 // this is the location of the light in entity space
-static vec3_t r_shadow_entitylightorigin;
+vec3_t r_shadow_entitylightorigin;
 // this transforms entity coordinates to light filter cubemap coordinates
 // (also often used for other purposes)
-static matrix4x4_t r_shadow_entitytolight;
+matrix4x4_t r_shadow_entitytolight;
 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
 // of attenuation texturing in full 3D (Z result often ignored)
-static matrix4x4_t r_shadow_entitytoattenuationxyz;
+matrix4x4_t r_shadow_entitytoattenuationxyz;
 // this transforms only the Z to S, and T is always 0.5
-static matrix4x4_t r_shadow_entitytoattenuationz;
-// rtlight->color * r_refdef.lightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormod * ent->alpha
-static vec3_t r_shadow_entitylightcolorbase;
-// rtlight->color * r_refdef.lightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormap_pantscolor * ent->alpha
-static vec3_t r_shadow_entitylightcolorpants;
-// rtlight->color * r_refdef.lightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormap_shirtcolor * ent->alpha
-static vec3_t r_shadow_entitylightcolorshirt;
+matrix4x4_t r_shadow_entitytoattenuationz;
 
 static int r_shadow_lightpermutation;
 static int r_shadow_lightprog;
 
-void R_Shadow_Stage_Begin(void)
+void R_Shadow_RenderMode_Begin(void)
 {
        rmeshstate_t m;
 
@@ -1097,48 +1127,62 @@ void R_Shadow_Stage_Begin(void)
                R_Shadow_MakeTextures();
 
        memset(&m, 0, sizeof(m));
+       R_Mesh_State(&m);
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(false);
        GL_DepthTest(true);
-       R_Mesh_State(&m);
        GL_Color(0, 0, 0, 1);
        qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
        qglEnable(GL_CULL_FACE);
        GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
-       r_shadowstage = R_SHADOWSTAGE_NONE;
+
+       r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
+
+       if (gl_ext_stenciltwoside.integer)
+               r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
+       else
+               r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
+
+       if (r_shadow_glsl.integer && r_shadow_program_light[0])
+               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;
+       else
+               r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
 }
 
-void R_Shadow_Stage_ActiveLight(rtlight_t *rtlight)
+void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
 {
        r_shadow_rtlight = rtlight;
 }
 
-void R_Shadow_Stage_Reset(void)
+void R_Shadow_RenderMode_Reset(void)
 {
        rmeshstate_t m;
-       if (gl_support_stenciltwoside)
-               qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
-       if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
+       if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
        {
                qglUseProgramObjectARB(0);
-               // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering in 6xxx drivers
+               // HACK HACK HACK: work around for bug in NVIDIAI 6xxx drivers that causes GL_OUT_OF_MEMORY and/or software rendering
                qglBegin(GL_TRIANGLES);
                qglEnd();
                CHECKGLERROR
        }
+       else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
+               qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
        memset(&m, 0, sizeof(m));
        R_Mesh_State(&m);
 }
 
-void R_Shadow_Stage_StencilShadowVolumes(void)
+void R_Shadow_RenderMode_StencilShadowVolumes(void)
 {
-       R_Shadow_Stage_Reset();
+       R_Shadow_RenderMode_Reset();
        GL_Color(1, 1, 1, 1);
        GL_ColorMask(0, 0, 0, 0);
        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);
@@ -1150,9 +1194,9 @@ void R_Shadow_Stage_StencilShadowVolumes(void)
        qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
        qglEnable(GL_STENCIL_TEST);
        qglStencilFunc(GL_ALWAYS, 128, ~0);
-       if (gl_ext_stenciltwoside.integer)
+       r_shadow_rendermode = r_shadow_shadowingrendermode;
+       if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
        {
-               r_shadowstage = R_SHADOWSTAGE_STENCILTWOSIDE;
                qglDisable(GL_CULL_FACE);
                qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
                qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
@@ -1164,7 +1208,6 @@ void R_Shadow_Stage_StencilShadowVolumes(void)
        }
        else
        {
-               r_shadowstage = R_SHADOWSTAGE_STENCIL;
                qglEnable(GL_CULL_FACE);
                qglStencilMask(~0);
                // this is changed by every shadow render so its value here is unimportant
@@ -1174,21 +1217,24 @@ void R_Shadow_Stage_StencilShadowVolumes(void)
        renderstats.lights_clears++;
 }
 
-void R_Shadow_Stage_Lighting(int stenciltest)
+void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
 {
-       rmeshstate_t m;
-       R_Shadow_Stage_Reset();
+       R_Shadow_RenderMode_Reset();
        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);
-       qglDepthFunc(GL_EQUAL);
+       if (transparent)
+               qglDepthFunc(GL_LEQUAL);
+       else
+               qglDepthFunc(GL_EQUAL);
        qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
        qglEnable(GL_CULL_FACE);
-       if (r_shadowstage == R_SHADOWSTAGE_STENCIL || r_shadowstage == R_SHADOWSTAGE_STENCILTWOSIDE)
+       if (stenciltest)
                qglEnable(GL_STENCIL_TEST);
        else
                qglDisable(GL_STENCIL_TEST);
@@ -1197,130 +1243,92 @@ void R_Shadow_Stage_Lighting(int stenciltest)
        // only draw light where this geometry was already rendered AND the
        // stencil is 128 (values other than this mean shadow)
        qglStencilFunc(GL_EQUAL, 128, ~0);
-       if (r_shadow_glsl.integer && r_shadow_program_light[0])
+       r_shadow_rendermode = r_shadow_lightingrendermode;
+       // do global setup needed for the chosen lighting mode
+       if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
        {
-               r_shadowstage = R_SHADOWSTAGE_LIGHT_GLSL;
-               memset(&m, 0, sizeof(m));
-               m.pointer_vertex = varray_vertex3f;
-               m.pointer_texcoord[0] = varray_texcoord2f[0];
-               m.pointer_texcoord3f[1] = varray_svector3f;
-               m.pointer_texcoord3f[2] = varray_tvector3f;
-               m.pointer_texcoord3f[3] = varray_normal3f;
-               m.tex[0] = R_GetTexture(r_texture_blanknormalmap); // normal
-               m.tex[1] = R_GetTexture(r_texture_white); // diffuse
-               m.tex[2] = R_GetTexture(r_texture_white); // gloss
-               m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap); // light filter
-               // TODO: support fog (after renderer is converted to texture fog)
-               m.tex[4] = R_GetTexture(r_texture_white); // fog
-               //m.texmatrix[3] = r_shadow_entitytolight; // light filter matrix
-               R_Mesh_State(&m);
+               R_Mesh_VertexPointer(varray_vertex3f);
+               R_Mesh_TexCoordPointer(0, 2, varray_texcoord2f[0]);
+               R_Mesh_TexCoordPointer(1, 3, varray_svector3f);
+               R_Mesh_TexCoordPointer(2, 3, varray_tvector3f);
+               R_Mesh_TexCoordPointer(3, 3, varray_normal3f);
+               R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
+               R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
+               R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
+               R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
+               R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
+               R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
+               R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
+               //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
                GL_BlendFunc(GL_ONE, GL_ONE);
                GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
                CHECKGLERROR
-               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 (r_shadow_rtlight->specularscale && r_shadow_gloss.integer >= 1 && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR])
-                       r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
-               //if (fog && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_FOG])
-               //      r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
-               if (r_shadow_lightcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
-                       r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
-               if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING])
-                       r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
-               if (r_shadow_glsl_surfacenormalize.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SURFACENORMALIZE])
-                       r_shadow_lightpermutation |= SHADERPERMUTATION_SURFACENORMALIZE;
-               if (r_shadow_glsl_usehalffloat.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_GEFORCEFX])
-                       r_shadow_lightpermutation |= SHADERPERMUTATION_GEFORCEFX;
-               r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
-               qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR
-               // TODO: support fog (after renderer is converted to texture fog)
-               if (r_shadow_lightpermutation & SHADERPERMUTATION_FOG)
-               {
-                       qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "FogRangeRecip"), 0);CHECKGLERROR
-               }
-               qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "AmbientScale"), r_shadow_rtlight->ambientscale);CHECKGLERROR
-               qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "DiffuseScale"), r_shadow_rtlight->diffusescale);CHECKGLERROR
-               if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
-               {
-                       qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularPower"), 8);CHECKGLERROR
-                       qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), r_shadow_rtlight->specularscale);CHECKGLERROR
-               }
-               //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
-               //qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
-               //if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
-               //{
-               //      qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
-               //}
-               if (r_shadow_lightpermutation & SHADERPERMUTATION_OFFSETMAPPING)
-               {
-                       qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
-                       qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
-               }
        }
-       else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
-               r_shadowstage = R_SHADOWSTAGE_LIGHT_DOT3;
-       else
-               r_shadowstage = R_SHADOWSTAGE_LIGHT_VERTEX;
 }
 
-void R_Shadow_Stage_VisibleShadowVolumes(void)
+void R_Shadow_RenderMode_VisibleShadowVolumes(void)
 {
-       R_Shadow_Stage_Reset();
+       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);
        qglCullFace(GL_FRONT); // this culls back
        qglDisable(GL_CULL_FACE);
        qglDisable(GL_STENCIL_TEST);
-       r_shadowstage = R_SHADOWSTAGE_VISIBLEVOLUMES;
+       r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
 }
 
-void R_Shadow_Stage_VisibleLighting(int stenciltest)
+void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
 {
-       R_Shadow_Stage_Reset();
+       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);
-       qglDepthFunc(GL_EQUAL);
+       if (transparent)
+               qglDepthFunc(GL_LEQUAL);
+       else
+               qglDepthFunc(GL_EQUAL);
        qglCullFace(GL_FRONT); // this culls back
        qglEnable(GL_CULL_FACE);
        if (stenciltest)
                qglEnable(GL_STENCIL_TEST);
        else
                qglDisable(GL_STENCIL_TEST);
-       r_shadowstage = R_SHADOWSTAGE_VISIBLELIGHTING;
+       r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
 }
 
-void R_Shadow_Stage_End(void)
+void R_Shadow_RenderMode_End(void)
 {
-       R_Shadow_Stage_Reset();
-       R_Shadow_Stage_ActiveLight(NULL);
+       R_Shadow_RenderMode_Reset();
+       R_Shadow_RenderMode_ActiveLight(NULL);
        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);
        GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
        qglDepthFunc(GL_LEQUAL);
        qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
+       qglEnable(GL_CULL_FACE);
        qglDisable(GL_STENCIL_TEST);
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        if (gl_support_stenciltwoside)
                qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
        qglStencilMask(~0);
        qglStencilFunc(GL_ALWAYS, 128, ~0);
-       r_shadowstage = R_SHADOWSTAGE_NONE;
+       r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
 }
 
 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
@@ -1419,105 +1427,102 @@ 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);
 
-static void R_Shadow_VertexShadingWithXYZAttenuation(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor, float reduce)
+static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
 {
        int numverts = surface->num_vertices;
        float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
        float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
        float *color4f = varray_color4f + 4 * surface->num_firstvertex;
        float dist, dot, distintensity, shadeintensity, v[3], n[3];
-       for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
+       if (r_textureunits.integer >= 3)
        {
-               Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
-               if ((dist = DotProduct(v, v)) < 1)
+               for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
                {
-                       dist = sqrt(dist);
-                       distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
+                       Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
                        Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
-                       if ((dot = DotProduct(n, v)) > 0)
+                       if ((dot = DotProduct(n, v)) < 0)
                        {
-                               shadeintensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
-                               color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity - reduce;
-                               color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity - reduce;
-                               color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity - reduce;
+                               shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
+                               color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
+                               color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
+                               color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
+                               if (fogenabled)
+                               {
+                                       float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
+                                       VectorScale(color4f, f, color4f);
+                               }
                        }
                        else
-                       {
-                               color4f[0] = ambientcolor[0] * distintensity - reduce;
-                               color4f[1] = ambientcolor[1] * distintensity - reduce;
-                               color4f[2] = ambientcolor[2] * distintensity - reduce;
-                       }
-                       color4f[0] = bound(0, color4f[0], 1);
-                       color4f[1] = bound(0, color4f[1], 1);
-                       color4f[2] = bound(0, color4f[2], 1);
+                               VectorClear(color4f);
+                       color4f[3] = 1;
                }
-               else
-                       VectorClear(color4f);
-               color4f[3] = 1;
        }
-}
-
-static void R_Shadow_VertexShadingWithZAttenuation(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor, float reduce)
-{
-       int numverts = surface->num_vertices;
-       float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
-       float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
-       float *color4f = varray_color4f + 4 * surface->num_firstvertex;
-       float dist, dot, distintensity, shadeintensity, v[3], n[3];
-       for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
+       else if (r_textureunits.integer >= 2)
        {
-               Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
-               if ((dist = fabs(v[2])) < 1)
+               for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
                {
-                       distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
-                       Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
-                       if ((dot = DotProduct(n, v)) > 0)
+                       Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
+                       if ((dist = fabs(v[2])) < 1)
                        {
-                               shadeintensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
-                               color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity - reduce;
-                               color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity - reduce;
-                               color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity - reduce;
+                               distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
+                               Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
+                               if ((dot = DotProduct(n, v)) < 0)
+                               {
+                                       shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
+                                       color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
+                                       color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
+                                       color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
+                               }
+                               else
+                               {
+                                       color4f[0] = ambientcolor[0] * distintensity;
+                                       color4f[1] = ambientcolor[1] * distintensity;
+                                       color4f[2] = ambientcolor[2] * distintensity;
+                               }
+                               if (fogenabled)
+                               {
+                                       float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
+                                       VectorScale(color4f, f, color4f);
+                               }
                        }
                        else
-                       {
-                               color4f[0] = ambientcolor[0] * distintensity - reduce;
-                               color4f[1] = ambientcolor[1] * distintensity - reduce;
-                               color4f[2] = ambientcolor[2] * distintensity - reduce;
-                       }
-                       color4f[0] = bound(0, color4f[0], 1);
-                       color4f[1] = bound(0, color4f[1], 1);
-                       color4f[2] = bound(0, color4f[2], 1);
+                               VectorClear(color4f);
+                       color4f[3] = 1;
                }
-               else
-                       VectorClear(color4f);
-               color4f[3] = 1;
        }
-}
-
-static void R_Shadow_VertexShading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor, float reduce)
-{
-       int numverts = surface->num_vertices;
-       float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
-       float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
-       float *color4f = varray_color4f + 4 * surface->num_firstvertex;
-       float dot, shadeintensity, v[3], n[3];
-       for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
+       else
        {
-               Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
-               Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
-               if ((dot = DotProduct(n, v)) > 0)
+               for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
                {
-                       shadeintensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
-                       color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) - reduce;
-                       color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) - reduce;
-                       color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) - reduce;
-                       color4f[0] = bound(0, color4f[0], 1);
-                       color4f[1] = bound(0, color4f[1], 1);
-                       color4f[2] = bound(0, color4f[2], 1);
+                       Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
+                       if ((dist = DotProduct(v, v)) < 1)
+                       {
+                               dist = sqrt(dist);
+                               distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
+                               Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
+                               if ((dot = DotProduct(n, v)) < 0)
+                               {
+                                       shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
+                                       color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
+                                       color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
+                                       color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
+                               }
+                               else
+                               {
+                                       color4f[0] = ambientcolor[0] * distintensity;
+                                       color4f[1] = ambientcolor[1] * distintensity;
+                                       color4f[2] = ambientcolor[2] * distintensity;
+                               }
+                               if (fogenabled)
+                               {
+                                       float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
+                                       VectorScale(color4f, f, color4f);
+                               }
+                       }
+                       else
+                               VectorClear(color4f);
+                       color4f[3] = 1;
                }
-               else
-                       VectorClear(color4f);
-               color4f[3] = 1;
        }
 }
 
@@ -1559,7 +1564,7 @@ static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(float *out3f, int numver
        float lightdir[3];
        for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
        {
-               VectorSubtract(vertex3f, relativelightorigin, lightdir);
+               VectorSubtract(relativelightorigin, vertex3f, lightdir);
                // the cubemap normalizes this for us
                out3f[0] = DotProduct(svector3f, lightdir);
                out3f[1] = DotProduct(tvector3f, lightdir);
@@ -1573,9 +1578,9 @@ static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out3f, int numve
        float lightdir[3], eyedir[3], halfdir[3];
        for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
        {
-               VectorSubtract(vertex3f, relativelightorigin, lightdir);
+               VectorSubtract(relativelightorigin, vertex3f, lightdir);
                VectorNormalize(lightdir);
-               VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
+               VectorSubtract(relativeeyeorigin, vertex3f, eyedir);
                VectorNormalize(eyedir);
                VectorAdd(lightdir, eyedir, halfdir);
                // the cubemap normalizes this for us
@@ -1585,65 +1590,91 @@ 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, const vec3_t modelorg)
+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, modelorg);
+               RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
                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, const vec3_t modelorg)
+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 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;
-       // TODO: add direct pants/shirt rendering
-       if (doambientpants || dodiffusepants)
-               R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorpants, vec3_origin, vec3_origin, pantstexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
-       if (doambientshirt || dodiffuseshirt)
-               R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
-       if (!doambientbase && !dodiffusebase && !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])
+               r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
+       if ((dopants || doshirt) && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_COLORMAPPING])
+               r_shadow_lightpermutation |= SHADERPERMUTATION_COLORMAPPING;
+       if (specularscale > 0 && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR])
+               r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
+       if (r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
+               r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
+       if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING])
+               r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
+       if (r_shadow_glsl_surfacenormalize.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SURFACENORMALIZE])
+               r_shadow_lightpermutation |= SHADERPERMUTATION_SURFACENORMALIZE;
+       if (r_shadow_glsl_usehalffloat.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_GEFORCEFX])
+               r_shadow_lightpermutation |= SHADERPERMUTATION_GEFORCEFX;
+       r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation];
+       qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR
        R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
+       R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
        R_Mesh_TexBind(0, R_GetTexture(normalmaptexture));
        R_Mesh_TexBind(1, R_GetTexture(basetexture));
-       R_Mesh_TexBind(2, R_GetTexture(glosstexture));
+       qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
+       if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
+       {
+               qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
+       }
+       qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
+       if (r_shadow_lightpermutation & SHADERPERMUTATION_COLORMAPPING)
+       {
+               R_Mesh_TexBind(5, R_GetTexture(pantstexture));
+               R_Mesh_TexBind(6, R_GetTexture(shirttexture));
+               qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "Color_Pants"), ent->colormap_pantscolor[0], ent->colormap_pantscolor[1], ent->colormap_pantscolor[2]);CHECKGLERROR
+               qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "Color_Shirt"), ent->colormap_shirtcolor[0], ent->colormap_shirtcolor[1], ent->colormap_shirtcolor[2]);CHECKGLERROR
+       }
+       if (r_shadow_lightpermutation & SHADERPERMUTATION_FOG)
+       {
+               qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "FogRangeRecip"), fograngerecip);CHECKGLERROR
+       }
+       qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "AmbientScale"), r_shadow_rtlight->ambientscale);CHECKGLERROR
+       qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "DiffuseScale"), r_shadow_rtlight->diffusescale);CHECKGLERROR
        if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
        {
+               R_Mesh_TexBind(2, R_GetTexture(glosstexture));
+               qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularPower"), 8);CHECKGLERROR
                qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
        }
-       qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
+       if (r_shadow_lightpermutation & SHADERPERMUTATION_OFFSETMAPPING)
+       {
+               qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
+               qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
+       }
        for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
        {
                const msurface_t *surface = surfacelist[surfacelistindex];
                const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
-               RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+               RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
                if (!rsurface_svector3f)
                {
                        rsurface_svector3f = varray_svector3f;
@@ -1661,727 +1692,806 @@ static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *en
        }
 }
 
-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, const vec3_t modelorg)
+static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
 {
-       // ARB path (any Geforce, any Radeon)
-       int surfacelistindex;
        int renders;
-       float color2[3], colorscale;
+       float color2[3];
        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;
-       // TODO: add direct pants/shirt rendering
-       if (doambientpants || dodiffusepants)
-               R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorpants, vec3_origin, vec3_origin, pantstexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
-       if (doambientshirt || dodiffuseshirt)
-               R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
-       if (!doambientbase && !dodiffusebase && !dospecular)
-               return;
-       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+       const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
+       GL_Color(1,1,1,1);
+       // colorscale accounts for how much we multiply the brightness
+       // during combine.
+       //
+       // mult is how many times the final pass of the lighting will be
+       // performed to get more brightness than otherwise possible.
+       //
+       // Limit mult to 64 for sanity sake.
+       if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
        {
-               const msurface_t *surface = surfacelist[surfacelistindex];
-               const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
-               RSurf_SetVertexPointer(ent, texture, surface, modelorg);
-               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)
-               {
-                       GL_Color(1,1,1,1);
-                       colorscale = r_shadow_rtlight->ambientscale;
-                       // colorscale accounts for how much we multiply the brightness
-                       // during combine.
-                       //
-                       // mult is how many times the final pass of the lighting will be
-                       // performed to get more brightness than otherwise possible.
-                       //
-                       // Limit mult to 64 for sanity sake.
-                       if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
-                       {
-                               // 3 3D combine path (Geforce3, Radeon 8500)
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
+               // 3 3D combine path (Geforce3, Radeon 8500)
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[0] = rsurface_vertex3f;
-                               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
-                               m.pointer_texcoord3f[0] = varray_texcoord3f[0];
-                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
+               m.pointer_texcoord3f[0] = varray_texcoord3f[0];
+               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
-                               m.tex[1] = R_GetTexture(basetexture);
-                               m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
-                               m.texmatrix[1] = texture->currenttexmatrix;
-                               m.texcubemap[2] = R_GetTexture(r_shadow_lightcubemap);
+               m.tex[1] = R_GetTexture(basetexture);
+               m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[1] = texture->currenttexmatrix;
+               m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[2] = rsurface_vertex3f;
-                               m.texmatrix[2] = r_shadow_entitytolight;
+               m.pointer_texcoord3f[2] = rsurface_vertex3f;
+               m.texmatrix[2] = r_shadow_entitytolight;
 #else
-                               m.pointer_texcoord3f[2] = varray_texcoord3f[2];
-                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
+               m.pointer_texcoord3f[2] = varray_texcoord3f[2];
+               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
 #endif
-                               GL_BlendFunc(GL_ONE, GL_ONE);
-                       }
-                       else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
-                       {
-                               // 2 3D combine path (Geforce3, original Radeon)
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
+               GL_BlendFunc(GL_ONE, GL_ONE);
+       }
+       else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
+       {
+               // 2 3D combine path (Geforce3, original Radeon)
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[0] = rsurface_vertex3f;
-                               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
-                               m.pointer_texcoord3f[0] = varray_texcoord3f[0];
-                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
+               m.pointer_texcoord3f[0] = varray_texcoord3f[0];
+               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
-                               m.tex[1] = R_GetTexture(basetexture);
-                               m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
-                               m.texmatrix[1] = texture->currenttexmatrix;
-                               GL_BlendFunc(GL_ONE, GL_ONE);
-                       }
-                       else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
-                       {
-                               // 4 2D combine path (Geforce3, Radeon 8500)
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.tex[1] = R_GetTexture(basetexture);
+               m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[1] = texture->currenttexmatrix;
+               GL_BlendFunc(GL_ONE, GL_ONE);
+       }
+       else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
+       {
+               // 4 2D combine path (Geforce3, Radeon 8500)
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[0] = rsurface_vertex3f;
-                               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
-                               m.pointer_texcoord[0] = varray_texcoord2f[0];
-                               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
+               m.pointer_texcoord[0] = varray_texcoord2f[0];
+               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
-                               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[1] = rsurface_vertex3f;
-                               m.texmatrix[1] = r_shadow_entitytoattenuationz;
+               m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.texmatrix[1] = r_shadow_entitytoattenuationz;
 #else
-                               m.pointer_texcoord[1] = varray_texcoord2f[1];
-                               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
+               m.pointer_texcoord[1] = varray_texcoord2f[1];
+               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
 #endif
-                               m.tex[2] = R_GetTexture(basetexture);
-                               m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
-                               m.texmatrix[2] = texture->currenttexmatrix;
-                               if (r_shadow_lightcubemap != r_texture_whitecube)
-                               {
-                                       m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap);
+               m.tex[2] = R_GetTexture(basetexture);
+               m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[2] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
+               {
+                       m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
-                                       m.pointer_texcoord3f[3] = rsurface_vertex3f;
-                                       m.texmatrix[3] = r_shadow_entitytolight;
+                       m.pointer_texcoord3f[3] = rsurface_vertex3f;
+                       m.texmatrix[3] = r_shadow_entitytolight;
 #else
-                                       m.pointer_texcoord3f[3] = varray_texcoord3f[3];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
+                       m.pointer_texcoord3f[3] = varray_texcoord3f[3];
+                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
 #endif
-                               }
-                               GL_BlendFunc(GL_ONE, GL_ONE);
-                       }
-                       else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
-                       {
-                               // 3 2D combine path (Geforce3, original Radeon)
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+               }
+               GL_BlendFunc(GL_ONE, GL_ONE);
+       }
+       else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
+       {
+               // 3 2D combine path (Geforce3, original Radeon)
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[0] = rsurface_vertex3f;
-                               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
-                               m.pointer_texcoord[0] = varray_texcoord2f[0];
-                               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
+               m.pointer_texcoord[0] = varray_texcoord2f[0];
+               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
-                               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[1] = rsurface_vertex3f;
-                               m.texmatrix[1] = r_shadow_entitytoattenuationz;
+               m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.texmatrix[1] = r_shadow_entitytoattenuationz;
 #else
-                               m.pointer_texcoord[1] = varray_texcoord2f[1];
-                               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
+               m.pointer_texcoord[1] = varray_texcoord2f[1];
+               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
 #endif
-                               m.tex[2] = R_GetTexture(basetexture);
-                               m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
-                               m.texmatrix[2] = texture->currenttexmatrix;
-                               GL_BlendFunc(GL_ONE, GL_ONE);
-                       }
-                       else
-                       {
-                               // 2/2/2 2D combine path (any dot3 card)
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.tex[2] = R_GetTexture(basetexture);
+               m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[2] = texture->currenttexmatrix;
+               GL_BlendFunc(GL_ONE, GL_ONE);
+       }
+       else
+       {
+               // 2/2/2 2D combine path (any dot3 card)
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[0] = rsurface_vertex3f;
-                               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
-                               m.pointer_texcoord[0] = varray_texcoord2f[0];
-                               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
+               m.pointer_texcoord[0] = varray_texcoord2f[0];
+               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
-                               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[1] = rsurface_vertex3f;
-                               m.texmatrix[1] = r_shadow_entitytoattenuationz;
+               m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.texmatrix[1] = r_shadow_entitytoattenuationz;
 #else
-                               m.pointer_texcoord[1] = varray_texcoord2f[1];
-                               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
+               m.pointer_texcoord[1] = varray_texcoord2f[1];
+               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
 #endif
-                               R_Mesh_State(&m);
-                               GL_ColorMask(0,0,0,1);
-                               GL_BlendFunc(GL_ONE, GL_ZERO);
-                               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                               GL_LockArrays(0, 0);
+               R_Mesh_State(&m);
+               GL_ColorMask(0,0,0,1);
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
 
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex[0] = R_GetTexture(basetexture);
-                               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                               m.texmatrix[0] = texture->currenttexmatrix;
-                               if (r_shadow_lightcubemap != r_texture_whitecube)
-                               {
-                                       m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(basetexture);
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
+               {
+                       m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
-                                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
-                                       m.texmatrix[1] = r_shadow_entitytolight;
+                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.texmatrix[1] = r_shadow_entitytolight;
 #else
-                                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
+                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
 #endif
-                               }
-                               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-                       }
-                       // this final code is shared
-                       R_Mesh_State(&m);
-                       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
-                       VectorScale(lightcolorbase, colorscale, color2);
-                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                       for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
-                       {
-                               GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
-                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                       }
-                       GL_LockArrays(0, 0);
                }
-               if (dodiffusebase)
-               {
-                       GL_Color(1,1,1,1);
-                       colorscale = r_shadow_rtlight->diffusescale;
-                       // colorscale accounts for how much we multiply the brightness
-                       // during combine.
-                       //
-                       // mult is how many times the final pass of the lighting will be
-                       // performed to get more brightness than otherwise possible.
-                       //
-                       // Limit mult to 64 for sanity sake.
-                       if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
-                       {
-                               // 3/2 3D combine path (Geforce3, Radeon 8500)
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex[0] = R_GetTexture(normalmaptexture);
-                               m.texcombinergb[0] = GL_REPLACE;
-                               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                               m.texmatrix[0] = texture->currenttexmatrix;
-                               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-                               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-                               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
-                               m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
+               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
+       }
+       // this final code is shared
+       R_Mesh_State(&m);
+       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
+       VectorScale(lightcolorbase, colorscale, color2);
+       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+       for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
+       {
+               GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+       }
+       GL_LockArrays(0, 0);
+}
+
+static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
+{
+       int renders;
+       float color2[3];
+       rmeshstate_t m;
+       const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
+       GL_Color(1,1,1,1);
+       // colorscale accounts for how much we multiply the brightness
+       // during combine.
+       //
+       // mult is how many times the final pass of the lighting will be
+       // performed to get more brightness than otherwise possible.
+       //
+       // Limit mult to 64 for sanity sake.
+       if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
+       {
+               // 3/2 3D combine path (Geforce3, Radeon 8500)
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(normalmaptexture);
+               m.texcombinergb[0] = GL_REPLACE;
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
+               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
+               m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[2] = rsurface_vertex3f;
-                               m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
+               m.pointer_texcoord3f[2] = rsurface_vertex3f;
+               m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
 #else
-                               m.pointer_texcoord3f[2] = varray_texcoord3f[2];
-                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
+               m.pointer_texcoord3f[2] = varray_texcoord3f[2];
+               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
-                               R_Mesh_State(&m);
-                               GL_ColorMask(0,0,0,1);
-                               GL_BlendFunc(GL_ONE, GL_ZERO);
-                               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                               GL_LockArrays(0, 0);
+               R_Mesh_State(&m);
+               GL_ColorMask(0,0,0,1);
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
 
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex[0] = R_GetTexture(basetexture);
-                               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                               m.texmatrix[0] = texture->currenttexmatrix;
-                               if (r_shadow_lightcubemap != r_texture_whitecube)
-                               {
-                                       m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(basetexture);
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
+               {
+                       m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
-                                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
-                                       m.texmatrix[1] = r_shadow_entitytolight;
+                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.texmatrix[1] = r_shadow_entitytolight;
 #else
-                                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
+                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
 #endif
-                               }
-                               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-                       }
-                       else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
-                       {
-                               // 1/2/2 3D combine path (original Radeon)
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
+               }
+               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
+       }
+       else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
+       {
+               // 1/2/2 3D combine path (original Radeon)
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[0] = rsurface_vertex3f;
-                               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
-                               m.pointer_texcoord3f[0] = varray_texcoord3f[0];
-                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
+               m.pointer_texcoord3f[0] = varray_texcoord3f[0];
+               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
-                               R_Mesh_State(&m);
-                               GL_ColorMask(0,0,0,1);
-                               GL_BlendFunc(GL_ONE, GL_ZERO);
-                               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                               GL_LockArrays(0, 0);
+               R_Mesh_State(&m);
+               GL_ColorMask(0,0,0,1);
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
 
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex[0] = R_GetTexture(normalmaptexture);
-                               m.texcombinergb[0] = GL_REPLACE;
-                               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                               m.texmatrix[0] = texture->currenttexmatrix;
-                               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-                               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-                               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
-                               R_Mesh_State(&m);
-                               GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-                               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                               GL_LockArrays(0, 0);
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(normalmaptexture);
+               m.texcombinergb[0] = GL_REPLACE;
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
+               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
+               R_Mesh_State(&m);
+               GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
 
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex[0] = R_GetTexture(basetexture);
-                               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                               m.texmatrix[0] = texture->currenttexmatrix;
-                               if (r_shadow_lightcubemap != r_texture_whitecube)
-                               {
-                                       m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(basetexture);
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
+               {
+                       m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
-                                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
-                                       m.texmatrix[1] = r_shadow_entitytolight;
+                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.texmatrix[1] = r_shadow_entitytolight;
 #else
-                                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
+                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
 #endif
-                               }
-                               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-                       }
-                       else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
-                       {
-                               // 2/2 3D combine path (original Radeon)
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex[0] = R_GetTexture(normalmaptexture);
-                               m.texcombinergb[0] = GL_REPLACE;
-                               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                               m.texmatrix[0] = texture->currenttexmatrix;
-                               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-                               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-                               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
-                               R_Mesh_State(&m);
-                               GL_ColorMask(0,0,0,1);
-                               GL_BlendFunc(GL_ONE, GL_ZERO);
-                               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                               GL_LockArrays(0, 0);
+               }
+               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
+       }
+       else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
+       {
+               // 2/2 3D combine path (original Radeon)
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(normalmaptexture);
+               m.texcombinergb[0] = GL_REPLACE;
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
+               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
+               R_Mesh_State(&m);
+               GL_ColorMask(0,0,0,1);
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
 
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex[0] = R_GetTexture(basetexture);
-                               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                               m.texmatrix[0] = texture->currenttexmatrix;
-                               m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(basetexture);
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[1] = rsurface_vertex3f;
-                               m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
+               m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
 #else
-                               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
+               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
-                               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-                       }
-                       else if (r_textureunits.integer >= 4)
-                       {
-                               // 4/2 2D combine path (Geforce3, Radeon 8500)
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex[0] = R_GetTexture(normalmaptexture);
-                               m.texcombinergb[0] = GL_REPLACE;
-                               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                               m.texmatrix[0] = texture->currenttexmatrix;
-                               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-                               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-                               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
-                               m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
+               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
+       }
+       else if (r_textureunits.integer >= 4)
+       {
+               // 4/2 2D combine path (Geforce3, Radeon 8500)
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(normalmaptexture);
+               m.texcombinergb[0] = GL_REPLACE;
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
+               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
+               m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[2] = rsurface_vertex3f;
-                               m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
+               m.pointer_texcoord3f[2] = rsurface_vertex3f;
+               m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
 #else
-                               m.pointer_texcoord[2] = varray_texcoord2f[2];
-                               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
+               m.pointer_texcoord[2] = varray_texcoord2f[2];
+               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
-                               m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[3] = rsurface_vertex3f;
-                               m.texmatrix[3] = r_shadow_entitytoattenuationz;
+               m.pointer_texcoord3f[3] = rsurface_vertex3f;
+               m.texmatrix[3] = r_shadow_entitytoattenuationz;
 #else
-                               m.pointer_texcoord[3] = varray_texcoord2f[3];
-                               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
+               m.pointer_texcoord[3] = varray_texcoord2f[3];
+               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
 #endif
-                               R_Mesh_State(&m);
-                               GL_ColorMask(0,0,0,1);
-                               GL_BlendFunc(GL_ONE, GL_ZERO);
-                               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                               GL_LockArrays(0, 0);
+               R_Mesh_State(&m);
+               GL_ColorMask(0,0,0,1);
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
 
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex[0] = R_GetTexture(basetexture);
-                               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                               m.texmatrix[0] = texture->currenttexmatrix;
-                               if (r_shadow_lightcubemap != r_texture_whitecube)
-                               {
-                                       m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(basetexture);
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
+               {
+                       m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
-                                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
-                                       m.texmatrix[1] = r_shadow_entitytolight;
+                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.texmatrix[1] = r_shadow_entitytolight;
 #else
-                                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
+                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
 #endif
-                               }
-                               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-                       }
-                       else
-                       {
-                               // 2/2/2 2D combine path (any dot3 card)
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[0] = rsurface_vertex3f;
-                               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
-#else
-                               m.pointer_texcoord[0] = varray_texcoord2f[0];
-                               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
+               }
+               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
+       }
+       else
+       {
+               // 2/2/2 2D combine path (any dot3 card)
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+#ifdef USETEXMATRIX
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+#else
+               m.pointer_texcoord[0] = varray_texcoord2f[0];
+               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
-                               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
-                               m.pointer_texcoord3f[1] = rsurface_vertex3f;
-                               m.texmatrix[1] = r_shadow_entitytoattenuationz;
+               m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.texmatrix[1] = r_shadow_entitytoattenuationz;
 #else
-                               m.pointer_texcoord[1] = varray_texcoord2f[1];
-                               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
+               m.pointer_texcoord[1] = varray_texcoord2f[1];
+               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
 #endif
-                               R_Mesh_State(&m);
-                               GL_ColorMask(0,0,0,1);
-                               GL_BlendFunc(GL_ONE, GL_ZERO);
-                               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                               GL_LockArrays(0, 0);
+               R_Mesh_State(&m);
+               GL_ColorMask(0,0,0,1);
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
 
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex[0] = R_GetTexture(normalmaptexture);
-                               m.texcombinergb[0] = GL_REPLACE;
-                               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                               m.texmatrix[0] = texture->currenttexmatrix;
-                               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-                               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-                               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
-                               R_Mesh_State(&m);
-                               GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-                               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                               GL_LockArrays(0, 0);
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(normalmaptexture);
+               m.texcombinergb[0] = GL_REPLACE;
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
+               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
+               R_Mesh_State(&m);
+               GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
 
-                               memset(&m, 0, sizeof(m));
-                               m.pointer_vertex = rsurface_vertex3f;
-                               m.tex[0] = R_GetTexture(basetexture);
-                               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                               m.texmatrix[0] = texture->currenttexmatrix;
-                               if (r_shadow_lightcubemap != r_texture_whitecube)
-                               {
-                                       m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(basetexture);
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
+               {
+                       m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
-                                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
-                                       m.texmatrix[1] = r_shadow_entitytolight;
+                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.texmatrix[1] = r_shadow_entitytolight;
 #else
-                                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
+                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
 #endif
-                               }
-                               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-                       }
-                       // this final code is shared
-                       R_Mesh_State(&m);
-                       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
-                       VectorScale(lightcolorbase, colorscale, color2);
-                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                       for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
-                       {
-                               GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
-                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                       }
-                       GL_LockArrays(0, 0);
                }
-               if (dospecular)
-               {
-                       // FIXME: detect blendsquare!
-                       //if (gl_support_blendsquare)
-                       {
-                               colorscale = specularscale;
-                               GL_Color(1,1,1,1);
-                               if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
-                               {
-                                       // 2/0/0/1/2 3D combine blendsquare path
-                                       memset(&m, 0, sizeof(m));
-                                       m.pointer_vertex = rsurface_vertex3f;
-                                       m.tex[0] = R_GetTexture(normalmaptexture);
-                                       m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                                       m.texmatrix[0] = texture->currenttexmatrix;
-                                       m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-                                       m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-                                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                       R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
-                                       R_Mesh_State(&m);
-                                       GL_ColorMask(0,0,0,1);
-                                       // this squares the result
-                                       GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
-                                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                                       GL_LockArrays(0, 0);
-
-                                       memset(&m, 0, sizeof(m));
-                                       m.pointer_vertex = rsurface_vertex3f;
-                                       R_Mesh_State(&m);
-                                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                                       // square alpha in framebuffer a few times to make it shiny
-                                       GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
-                                       // these comments are a test run through this math for intensity 0.5
-                                       // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
-                                       // 0.25 * 0.25 = 0.0625 (this is another pass)
-                                       // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
-                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                                       GL_LockArrays(0, 0);
-
-                                       memset(&m, 0, sizeof(m));
-                                       m.pointer_vertex = rsurface_vertex3f;
-                                       m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
+               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
+       }
+       // this final code is shared
+       R_Mesh_State(&m);
+       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
+       VectorScale(lightcolorbase, colorscale, color2);
+       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+       for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
+       {
+               GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+       }
+       GL_LockArrays(0, 0);
+}
+
+static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
+{
+       int renders;
+       float color2[3];
+       rmeshstate_t m;
+       const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
+       // FIXME: detect blendsquare!
+       //if (!gl_support_blendsquare)
+       //      return;
+       GL_Color(1,1,1,1);
+       if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
+       {
+               // 2/0/0/1/2 3D combine blendsquare path
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(normalmaptexture);
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
+               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+               R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
+               R_Mesh_State(&m);
+               GL_ColorMask(0,0,0,1);
+               // this squares the result
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
+
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               R_Mesh_State(&m);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               // square alpha in framebuffer a few times to make it shiny
+               GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
+               // these comments are a test run through this math for intensity 0.5
+               // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
+               // 0.25 * 0.25 = 0.0625 (this is another pass)
+               // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
+
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
-                                       m.pointer_texcoord3f[0] = rsurface_vertex3f;
-                                       m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
-                                       m.pointer_texcoord3f[0] = varray_texcoord3f[0];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
+               m.pointer_texcoord3f[0] = varray_texcoord3f[0];
+               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
-                                       R_Mesh_State(&m);
-                                       GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-                                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                                       GL_LockArrays(0, 0);
-
-                                       memset(&m, 0, sizeof(m));
-                                       m.pointer_vertex = rsurface_vertex3f;
-                                       m.tex[0] = R_GetTexture(glosstexture);
-                                       m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                                       m.texmatrix[0] = texture->currenttexmatrix;
-                                       if (r_shadow_lightcubemap != r_texture_whitecube)
-                                       {
-                                               m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
+               R_Mesh_State(&m);
+               GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
+
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(glosstexture);
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
+               {
+                       m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
-                                               m.pointer_texcoord3f[1] = rsurface_vertex3f;
-                                               m.texmatrix[1] = r_shadow_entitytolight;
+                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.texmatrix[1] = r_shadow_entitytolight;
 #else
-                                               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
+                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
 #endif
-                                       }
-                                       GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-                               }
-                               else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
-                               {
-                                       // 2/0/0/2 3D combine blendsquare path
-                                       memset(&m, 0, sizeof(m));
-                                       m.pointer_vertex = rsurface_vertex3f;
-                                       m.tex[0] = R_GetTexture(normalmaptexture);
-                                       m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                                       m.texmatrix[0] = texture->currenttexmatrix;
-                                       m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-                                       m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-                                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                       R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
-                                       R_Mesh_State(&m);
-                                       GL_ColorMask(0,0,0,1);
-                                       // this squares the result
-                                       GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
-                                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                                       GL_LockArrays(0, 0);
-
-                                       memset(&m, 0, sizeof(m));
-                                       m.pointer_vertex = rsurface_vertex3f;
-                                       R_Mesh_State(&m);
-                                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                                       // square alpha in framebuffer a few times to make it shiny
-                                       GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
-                                       // these comments are a test run through this math for intensity 0.5
-                                       // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
-                                       // 0.25 * 0.25 = 0.0625 (this is another pass)
-                                       // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
-                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                                       GL_LockArrays(0, 0);
-
-                                       memset(&m, 0, sizeof(m));
-                                       m.pointer_vertex = rsurface_vertex3f;
-                                       m.tex[0] = R_GetTexture(glosstexture);
-                                       m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                                       m.texmatrix[0] = texture->currenttexmatrix;
-                                       m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
+               }
+               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
+       }
+       else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
+       {
+               // 2/0/0/2 3D combine blendsquare path
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(normalmaptexture);
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
+               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+               R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
+               R_Mesh_State(&m);
+               GL_ColorMask(0,0,0,1);
+               // this squares the result
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
+
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               R_Mesh_State(&m);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               // square alpha in framebuffer a few times to make it shiny
+               GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
+               // these comments are a test run through this math for intensity 0.5
+               // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
+               // 0.25 * 0.25 = 0.0625 (this is another pass)
+               // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
+
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(glosstexture);
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
-                                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
-                                       m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
+               m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
 #else
-                                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
+               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
-                                       GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-                               }
-                               else
-                               {
-                                       // 2/0/0/2/2 2D combine blendsquare path
-                                       memset(&m, 0, sizeof(m));
-                                       m.pointer_vertex = rsurface_vertex3f;
-                                       m.tex[0] = R_GetTexture(normalmaptexture);
-                                       m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                                       m.texmatrix[0] = texture->currenttexmatrix;
-                                       m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-                                       m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-                                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                       R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
-                                       R_Mesh_State(&m);
-                                       GL_ColorMask(0,0,0,1);
-                                       // this squares the result
-                                       GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
-                                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                                       GL_LockArrays(0, 0);
-
-                                       memset(&m, 0, sizeof(m));
-                                       m.pointer_vertex = rsurface_vertex3f;
-                                       R_Mesh_State(&m);
-                                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                                       // square alpha in framebuffer a few times to make it shiny
-                                       GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
-                                       // these comments are a test run through this math for intensity 0.5
-                                       // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
-                                       // 0.25 * 0.25 = 0.0625 (this is another pass)
-                                       // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
-                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                                       GL_LockArrays(0, 0);
-
-                                       memset(&m, 0, sizeof(m));
-                                       m.pointer_vertex = rsurface_vertex3f;
-                                       m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
+       }
+       else
+       {
+               // 2/0/0/2/2 2D combine blendsquare path
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(normalmaptexture);
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
+               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+               R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
+               R_Mesh_State(&m);
+               GL_ColorMask(0,0,0,1);
+               // this squares the result
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
+
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               R_Mesh_State(&m);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               // square alpha in framebuffer a few times to make it shiny
+               GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
+               // these comments are a test run through this math for intensity 0.5
+               // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
+               // 0.25 * 0.25 = 0.0625 (this is another pass)
+               // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
+
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
-                                       m.pointer_texcoord3f[0] = rsurface_vertex3f;
-                                       m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
-                                       m.pointer_texcoord[0] = varray_texcoord2f[0];
-                                       R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
+               m.pointer_texcoord[0] = varray_texcoord2f[0];
+               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
-                                       m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
-                                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
-                                       m.texmatrix[1] = r_shadow_entitytoattenuationz;
+               m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.texmatrix[1] = r_shadow_entitytoattenuationz;
 #else
-                                       m.pointer_texcoord[1] = varray_texcoord2f[1];
-                                       R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
+               m.pointer_texcoord[1] = varray_texcoord2f[1];
+               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
 #endif
-                                       R_Mesh_State(&m);
-                                       GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-                                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                                       GL_LockArrays(0, 0);
-
-                                       memset(&m, 0, sizeof(m));
-                                       m.pointer_vertex = rsurface_vertex3f;
-                                       m.tex[0] = R_GetTexture(glosstexture);
-                                       m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-                                       m.texmatrix[0] = texture->currenttexmatrix;
-                                       if (r_shadow_lightcubemap != r_texture_whitecube)
-                                       {
-                                               m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
+               R_Mesh_State(&m);
+               GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
+
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = rsurface_vertex3f;
+               m.tex[0] = R_GetTexture(glosstexture);
+               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
+               {
+                       m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
-                                               m.pointer_texcoord3f[1] = rsurface_vertex3f;
-                                               m.texmatrix[1] = r_shadow_entitytolight;
+                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.texmatrix[1] = r_shadow_entitytolight;
 #else
-                                               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
+                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
 #endif
-                                       }
-                                       GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-                               }
-                               R_Mesh_State(&m);
-                               GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
-                               VectorScale(lightcolorbase, colorscale, color2);
+               }
+               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
+       }
+       R_Mesh_State(&m);
+       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
+       VectorScale(lightcolorbase, colorscale, color2);
+       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+       for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
+       {
+               GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+       }
+       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, qboolean dopants, qboolean doshirt)
+{
+       // ARB path (any Geforce, any Radeon)
+       int surfacelistindex;
+       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 (doambient)
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale);
+               if (dodiffuse)
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorbase, basetexture, 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);
+       }
+}
+
+void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const msurface_t *surface, vec3_t diffusecolor2, vec3_t ambientcolor2)
+{
+       int renders;
+       const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
+       R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
+       for (renders = 0;renders < 64 && (ambientcolor2[0] > renders || ambientcolor2[1] > renders || ambientcolor2[2] > renders || diffusecolor2[0] > renders || diffusecolor2[1] > renders || diffusecolor2[2] > renders);renders++)
+       {
+               int i;
+               float *c;
+#if 1
+               // due to low fillrate on the cards this vertex lighting path is
+               // designed for, we manually cull all triangles that do not
+               // contain a lit vertex
+               int draw;
+               const int *e;
+               int newnumtriangles;
+               int *newe;
+               int newelements[3072];
+               draw = false;
+               newnumtriangles = 0;
+               newe = newelements;
+               for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
+               {
+                       if (newnumtriangles >= 1024)
+                       {
                                GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                               for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
-                               {
-                                       GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
-                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                               }
+                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
                                GL_LockArrays(0, 0);
+                               newnumtriangles = 0;
+                               newe = newelements;
                        }
+                       if (VectorLength2(varray_color4f + e[0] * 4) + VectorLength2(varray_color4f + e[1] * 4) + VectorLength2(varray_color4f + e[2] * 4) >= 0.01)
+                       {
+                               newe[0] = e[0];
+                               newe[1] = e[1];
+                               newe[2] = e[2];
+                               newnumtriangles++;
+                               newe += 3;
+                               draw = true;
+                       }
+               }
+               if (newnumtriangles >= 1)
+               {
+                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
+                       GL_LockArrays(0, 0);
+                       draw = true;
+               }
+               if (!draw)
+                       break;
+#else
+               for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
+                       if (VectorLength2(c))
+                               goto goodpass;
+               break;
+goodpass:
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_LockArrays(0, 0);
+#endif
+               // now reduce the intensity for the next overbright pass
+               for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
+               {
+                       c[0] = max(0, c[0] - 1);
+                       c[1] = max(0, c[1] - 1);
+                       c[2] = max(0, c[2] - 1);
                }
        }
 }
 
-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, const vec3_t modelorg)
+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;
-       int renders;
-       float ambientcolor2[3], diffusecolor2[3];
+       float ambientcolorbase[3], diffusecolorbase[3];
+       float ambientcolorpants[3], diffusecolorpants[3];
+       float ambientcolorshirt[3], diffusecolorshirt[3];
        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;
-       // TODO: add direct pants/shirt rendering
-       if (doambientpants || dodiffusepants)
-               R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorpants, vec3_origin, vec3_origin, pantstexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
-       if (doambientshirt || dodiffuseshirt)
-               R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
-       if (!doambientbase && !dodiffusebase)
-               return;
-       VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, ambientcolor2);
-       VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, diffusecolor2);
-       GL_BlendFunc(GL_ONE, GL_ONE);
+       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);
        if (r_textureunits.integer >= 2)
@@ -2411,8 +2521,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *
        for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
        {
                const msurface_t *surface = surfacelist[surfacelistindex];
-               const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
-               RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+               RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
                if (!rsurface_svector3f)
                {
                        rsurface_svector3f = varray_svector3f;
@@ -2441,41 +2550,129 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *
 #endif
                        }
                }
-               for (renders = 0;renders < 64 && (ambientcolor2[0] > renders || ambientcolor2[1] > renders || ambientcolor2[2] > renders || diffusecolor2[0] > renders || diffusecolor2[1] > renders || diffusecolor2[2] > renders);renders++)
+               R_Mesh_TexBind(0, R_GetTexture(basetexture));
+               R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorbase, ambientcolorbase);
+               if (dopants)
                {
-                       if (r_textureunits.integer >= 3)
-                               R_Shadow_VertexShading(surface, diffusecolor2, ambientcolor2, renders);
-                       else if (r_textureunits.integer >= 2)
-                               R_Shadow_VertexShadingWithZAttenuation(surface, diffusecolor2, ambientcolor2, renders);
-                       else
-                               R_Shadow_VertexShadingWithXYZAttenuation(surface, diffusecolor2, ambientcolor2, renders);
-                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                       GL_LockArrays(0, 0);
+                       R_Mesh_TexBind(0, R_GetTexture(pantstexture));
+                       R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorpants, ambientcolorpants);
+               }
+               if (doshirt)
+               {
+                       R_Mesh_TexBind(0, R_GetTexture(shirttexture));
+                       R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorshirt, ambientcolorshirt);
                }
        }
 }
 
-void R_Shadow_RenderSurfacesLighting(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, const vec3_t modelorg)
+void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist)
 {
        // FIXME: support MATERIALFLAG_NODEPTHTEST
-       switch (r_shadowstage)
+       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)
        {
-       case R_SHADOWSTAGE_VISIBLELIGHTING:
-               R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
-               break;
-       case R_SHADOWSTAGE_LIGHT_GLSL:
-               R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
-               break;
-       case R_SHADOWSTAGE_LIGHT_DOT3:
-               R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
-               break;
-       case R_SHADOWSTAGE_LIGHT_VERTEX:
-               R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
-               break;
-       default:
-               Con_Printf("R_Shadow_RenderLighting: unknown r_shadowstage %i\n", r_shadowstage);
-               break;
+               if (texture->skin.gloss)
+               {
+                       if (r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
+                       {
+                               glosstexture = texture->skin.gloss;
+                               specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
+                       }
+               }
+               else
+               {
+                       if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
+                       {
+                               glosstexture = r_texture_white;
+                               specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
+                       }
+               }
+       }
+       // calculate colors to render this texture with
+       lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * ent->colormod[0] * texture->currentalpha;
+       lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * ent->colormod[1] * texture->currentalpha;
+       lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * ent->colormod[2] * texture->currentalpha;
+       if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
+               return;
+       if ((texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (ent->flags & RENDER_NOCULLFACE))
+               qglDisable(GL_CULL_FACE);
+       else
+               qglEnable(GL_CULL_FACE);
+       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, 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, 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, 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, dopants, doshirt);
+                       break;
+               default:
+                       Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
+                       break;
+               }
+       }
+       else
+       {
+               basetexture = texture->skin.merged ? texture->skin.merged : texture->skin.base;
+               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, 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, 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, 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, false, false);
+                       break;
+               default:
+                       Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
+                       break;
+               }
        }
 }
 
@@ -2533,7 +2730,7 @@ void R_RTLight_Compile(rtlight_t *rtlight)
        int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
        entity_render_t *ent = r_refdef.worldentity;
        model_t *model = r_refdef.worldmodel;
-       qbyte *data;
+       unsigned char *data;
 
        // compile the light
        rtlight->compiled = true;
@@ -2557,11 +2754,11 @@ void R_RTLight_Compile(rtlight_t *rtlight)
                R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
                model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
                numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
-               data = (qbyte *)Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
+               data = (unsigned char *)Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
                rtlight->static_numleafs = numleafs;
                rtlight->static_numleafpvsbytes = numleafpvsbytes;
                rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
-               rtlight->static_leafpvs = (qbyte *)data;data += numleafpvsbytes;
+               rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
                rtlight->static_numsurfaces = numsurfaces;
                rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
                if (numleafs)
@@ -2623,22 +2820,22 @@ void R_Shadow_UncompileWorldLights(void)
                R_RTLight_Uncompile(&light->rtlight);
 }
 
-void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
 {
        vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
        vec_t relativeshadowradius;
        if (ent == r_refdef.worldentity)
        {
-               if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
+               if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
                {
                        shadowmesh_t *mesh;
                        R_Mesh_Matrix(&ent->matrix);
-                       for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
+                       for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
                        {
                                renderstats.lights_shadowtriangles += mesh->numtriangles;
                                R_Mesh_VertexPointer(mesh->vertex3f);
                                GL_LockArrays(0, mesh->numverts);
-                               if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
+                               if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
                                {
                                        // decrement stencil if backface is behind depthbuffer
                                        qglCullFace(GL_BACK); // quake is backwards, this culls front faces
@@ -2655,13 +2852,13 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int num
                else if (numsurfaces)
                {
                        R_Mesh_Matrix(&ent->matrix);
-                       ent->model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
+                       ent->model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
                }
        }
        else
        {
-               Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativeshadoworigin);
-               relativeshadowradius = rtlight->radius / ent->scale;
+               Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
+               relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
                relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
                relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
                relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
@@ -2673,77 +2870,66 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int num
        }
 }
 
-void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t lightcolor, int numsurfaces, int *surfacelist)
+void R_Shadow_SetupEntityLight(const entity_render_t *ent)
 {
        // set up properties for rendering light onto this entity
-       r_shadow_entitylightcolorbase[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
-       r_shadow_entitylightcolorbase[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
-       r_shadow_entitylightcolorbase[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
-       r_shadow_entitylightcolorpants[0] = lightcolor[0] * ent->colormap_pantscolor[0] * ent->alpha;
-       r_shadow_entitylightcolorpants[1] = lightcolor[1] * ent->colormap_pantscolor[1] * ent->alpha;
-       r_shadow_entitylightcolorpants[2] = lightcolor[2] * ent->colormap_pantscolor[2] * ent->alpha;
-       r_shadow_entitylightcolorshirt[0] = lightcolor[0] * ent->colormap_shirtcolor[0] * ent->alpha;
-       r_shadow_entitylightcolorshirt[1] = lightcolor[1] * ent->colormap_shirtcolor[1] * ent->alpha;
-       r_shadow_entitylightcolorshirt[2] = lightcolor[2] * ent->colormap_shirtcolor[2] * ent->alpha;
-       Matrix4x4_Concat(&r_shadow_entitytolight, &rtlight->matrix_worldtolight, &ent->matrix);
+       Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
        Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
        Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
-       Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, r_shadow_entitylightorigin);
+       Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
        Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
        R_Mesh_Matrix(&ent->matrix);
-       if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
-       {
-               R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_lightcubemap));
-               R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
-               qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightPosition"), r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);CHECKGLERROR
-               if (r_shadow_lightpermutation & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
-               {
-                       qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
-               }
-       }
+}
+
+void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
+{
+       R_Shadow_SetupEntityLight(ent);
        if (ent == r_refdef.worldentity)
-               ent->model->DrawLight(ent, r_shadow_entitylightcolorbase, r_shadow_entitylightcolorpants, r_shadow_entitylightcolorshirt, numsurfaces, surfacelist);
+               ent->model->DrawLight(ent, numsurfaces, surfacelist);
        else
-               ent->model->DrawLight(ent, r_shadow_entitylightcolorbase, r_shadow_entitylightcolorpants, r_shadow_entitylightcolorshirt, ent->model->nummodelsurfaces, ent->model->surfacelist);
+               ent->model->DrawLight(ent, ent->model->nummodelsurfaces, ent->model->surfacelist);
 }
 
 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
 {
        int i, usestencil;
        float f;
-       vec3_t lightcolor;
        int numleafs, numsurfaces;
        int *leaflist, *surfacelist;
-       qbyte *leafpvs;
+       unsigned char *leafpvs;
        int numlightentities;
        int numshadowentities;
        entity_render_t *lightentities[MAX_EDICTS];
        entity_render_t *shadowentities[MAX_EDICTS];
 
-       // skip lights that don't light (corona only lights)
-       if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < (1.0f / 32768.0f))
+       // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
+       // skip lights that are basically invisible (color 0 0 0)
+       if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
                return;
 
+       // loading is done before visibility checks because loading should happen
+       // all at once at the start of a level, not when it stalls gameplay.
+       // (especially important to benchmarks)
+       // compile light
+       if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
+               R_RTLight_Compile(rtlight);
+       // load cubemap
+       rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
+
+       // look up the light style value at this time
        f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
-       VectorScale(rtlight->color, f, lightcolor);
-       if (VectorLength2(lightcolor) < (1.0f / 32768.0f))
-               return;
+       VectorScale(rtlight->color, f, rtlight->currentcolor);
        /*
        if (rtlight->selected)
        {
                f = 2 + sin(realtime * M_PI * 4.0);
-               VectorScale(lightcolor, f, lightcolor);
+               VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
        }
        */
 
-       // loading is done before visibility checks because loading should happen
-       // all at once at the start of a level, not when it stalls gameplay.
-       // (especially important to benchmarks)
-       // compile light
-       if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
-               R_RTLight_Compile(rtlight);
-       // load cubemap
-       r_shadow_lightcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
+       // if lightstyle is currently off, don't draw the light
+       if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
+               return;
 
        // if the light box is offscreen, skip it
        if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
@@ -2794,12 +2980,16 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
                return;
 
+       // make a list of lit entities and shadow casting entities
        numlightentities = 0;
-       if (numsurfaces)
-               lightentities[numlightentities++] = r_refdef.worldentity;
        numshadowentities = 0;
+       // don't count the world unless some surfaces are actually lit
        if (numsurfaces)
+       {
+               lightentities[numlightentities++] = r_refdef.worldentity;
                shadowentities[numshadowentities++] = r_refdef.worldentity;
+       }
+       // add dynamic entities that are lit by the light
        if (r_drawentities.integer)
        {
                for (i = 0;i < r_refdef.numentities;i++)
@@ -2823,37 +3013,53 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        if (!numlightentities)
                return;
 
-       R_Shadow_Stage_ActiveLight(rtlight);
+       // 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++;
 
        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_Stage_StencilShadowVolumes();
-               for (i = 0;i < numshadowentities;i++)
-                       R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
-       }
-
-       if (numlightentities && !visible)
-       {
-               R_Shadow_Stage_Lighting(usestencil);
-               for (i = 0;i < numlightentities;i++)
-                       R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, 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);
+               }
 
-       if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
-       {
-               R_Shadow_Stage_VisibleShadowVolumes();
-               for (i = 0;i < numshadowentities;i++)
-                       R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, 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);
+               }
        }
 
-       if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
+       if (numlightentities)
        {
-               R_Shadow_Stage_VisibleLighting(usestencil);
+               // draw lighting in the unmasked areas
+               R_Shadow_RenderMode_Lighting(usestencil, false);
                for (i = 0;i < numlightentities;i++)
-                       R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
+                       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);
+               }
        }
 }
 
@@ -2865,7 +3071,7 @@ void R_ShadowVolumeLighting(qboolean visible)
        if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
                R_Shadow_EditLights_Reload_f();
 
-       R_Shadow_Stage_Begin();
+       R_Shadow_RenderMode_Begin();
 
        flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
        if (r_shadow_debuglight.integer >= 0)
@@ -2882,7 +3088,7 @@ void R_ShadowVolumeLighting(qboolean visible)
                for (lnum = 0;lnum < r_refdef.numlights;lnum++)
                        R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
 
-       R_Shadow_Stage_End();
+       R_Shadow_RenderMode_End();
 }
 
 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
@@ -2925,7 +3131,7 @@ static int componentorder[4] = {0, 1, 2, 3};
 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
 {
        int i, j, cubemapsize;
-       qbyte *cubemappixels, *image_rgba;
+       unsigned char *cubemappixels, *image_rgba;
        rtexture_t *cubemaptexture;
        char name[256];
        // must start 0 so the first loadimagepixels has no requested width/height
@@ -2951,7 +3157,7 @@ rtexture_t *R_Shadow_LoadCubemap(const char *basename)
                                        {
                                                cubemapsize = image_width;
                                                // note this clears to black, so unavailable sides are black
-                                               cubemappixels = (qbyte *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
+                                               cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
                                        }
                                        // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
                                        if (cubemappixels)
@@ -3051,7 +3257,7 @@ void R_Shadow_FreeWorldLight(dlight_t *light)
        R_RTLight_Uncompile(&light->rtlight);
        for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
        if (*lightpointer != light)
-               Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
+               Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
        *lightpointer = light->next;
        Mem_Free(light);
 }
@@ -3073,23 +3279,22 @@ void R_Shadow_SelectLight(dlight_t *light)
                r_shadow_selectedlight->selected = true;
 }
 
-void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
+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], false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 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);
 }
 
-void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
+void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
 {
        float intensity;
-       const dlight_t *light;
-       light = (dlight_t *)calldata1;
+       const dlight_t *light = (dlight_t *)ent;
        intensity = 0.5;
        if (light->selected)
                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[calldata2], false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
+       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);
 }
 
 void R_Shadow_DrawLightSprites(void)
@@ -3101,13 +3306,13 @@ void R_Shadow_DrawLightSprites(void)
        for (i = 0;i < 5;i++)
        {
                lighttextures[i] = NULL;
-               if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1), true)))
+               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_DrawLightSpriteCallback, light, i % 5);
-       R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
+               R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, i % 5, &light->rtlight);
+       R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
 }
 
 void R_Shadow_SelectLightInView(void)
@@ -3145,7 +3350,7 @@ void R_Shadow_LoadWorldLights(void)
        }
        FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
        strlcat (name, ".rtlights", sizeof (name));
-       lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
+       lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
        if (lightsstring)
        {
                s = lightsstring;
@@ -3230,7 +3435,7 @@ void R_Shadow_SaveWorldLights(void)
        size_t bufchars, bufmaxchars;
        char *buf, *oldbuf;
        char name[MAX_QPATH];
-       char line[1024];
+       char line[MAX_INPUTLINE];
        if (!r_shadow_worldlightchain)
                return;
        if (r_refdef.worldmodel == NULL)
@@ -3286,7 +3491,7 @@ void R_Shadow_LoadLightsFile(void)
        }
        FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
        strlcat (name, ".lights", sizeof (name));
-       lightsstring = (char *)FS_LoadFile(name, tempmempool, false);
+       lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
        if (lightsstring)
        {
                s = lightsstring;
@@ -3332,7 +3537,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
        char *entfiledata;
        const char *data;
        float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
-       char key[256], value[1024];
+       char key[256], value[MAX_INPUTLINE];
 
        if (r_refdef.worldmodel == NULL)
        {
@@ -3342,7 +3547,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
        // try to load a .ent file first
        FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
        strlcat (key, ".ent", sizeof (key));
-       data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true);
+       data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
        // and if that is not found, fall back to the bsp file entity string
        if (!data)
                data = r_refdef.worldmodel->brush.entities;
@@ -3643,7 +3848,7 @@ void R_Shadow_EditLights_Edit_f(void)
        vec3_t origin, angles, color;
        vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
        int style, shadows, flags, normalmode, realtimemode;
-       char cubemapname[1024];
+       char cubemapname[MAX_INPUTLINE];
        if (!r_editlights.integer)
        {
                Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
@@ -3660,7 +3865,7 @@ void R_Shadow_EditLights_Edit_f(void)
        radius = r_shadow_selectedlight->radius;
        style = r_shadow_selectedlight->style;
        if (r_shadow_selectedlight->cubemapname)
-               strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
+               strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
        else
                cubemapname[0] = 0;
        shadows = r_shadow_selectedlight->shadow;
@@ -4158,19 +4363,19 @@ void R_Shadow_EditLights_Init(void)
        Cvar_RegisterVariable(&r_editlights_cursorpushoff);
        Cvar_RegisterVariable(&r_editlights_cursorgrid);
        Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
-       Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
-       Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
-       Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
-       Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
-       Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
-       Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
-       Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
-       Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
-       Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
-       Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
-       Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
-       Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
-       Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
-       Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);
+       Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
+       Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
+       Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f, "reloads rtlights file (or imports from .lights file or .ent file or the map itself)");
+       Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
+       Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
+       Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
+       Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f, "changes a property on ALL lights at once (tip: use radiusscale and colorscale to alter these properties)");
+       Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
+       Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
+       Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
+       Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
+       Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
+       Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
+       Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)");
 }