]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
optimizations to surface rendering setup
[xonotic/darkplaces.git] / r_shadow.c
index f42ddc563c82ca596cacb90c566f41b1d17a0260..6383a67b7913993222b735486a03ecedeeb5e536 100644 (file)
@@ -142,26 +142,29 @@ 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;
-
-int maxshadowelements;
+int maxshadowtriangles;
 int *shadowelements;
 
+int maxshadowvertices;
+float *shadowvertex3f;
+
 int maxshadowmark;
 int numshadowmark;
 int *shadowmark;
@@ -174,11 +177,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 +194,37 @@ 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_glsl lighting)"};
+cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_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_glsl lighting)"};
+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;
 
@@ -240,8 +234,6 @@ dlight_t *r_shadow_selectedlight;
 dlight_t r_shadow_bufferlight;
 vec3_t r_editlights_cursorlocation;
 
-rtexture_t *lighttextures[5];
-
 extern int con_vislines;
 
 typedef struct cubemapinfo_s
@@ -255,16 +247,6 @@ 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)
-
-GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT];
-
 void R_Shadow_UncompileWorldLights(void);
 void R_Shadow_ClearWorldLights(void);
 void R_Shadow_SaveWorldLights(void);
@@ -276,159 +258,8 @@ void R_Shadow_ValidateCvars(void);
 static void R_Shadow_MakeTextures(void);
 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
 
-const char *builtinshader_light_vert =
-"// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
-"// written by Forest 'LordHavoc' Hale\n"
-"\n"
-"uniform vec3 LightPosition;\n"
-"\n"
-"varying vec2 TexCoord;\n"
-"varying vec3 CubeVector;\n"
-"varying vec3 LightVector;\n"
-"\n"
-"#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
-"uniform vec3 EyePosition;\n"
-"varying vec3 EyeVector;\n"
-"#endif\n"
-"\n"
-"// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
-"\n"
-"void main(void)\n"
-"{\n"
-"      // copy the surface texcoord\n"
-"      TexCoord = vec2(gl_TextureMatrix[0] * glMultiTexCoord0);\n"
-"\n"
-"      // transform vertex position into light attenuation/cubemap space\n"
-"      // (-1 to +1 across the light box)\n"
-"      CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
-"\n"
-"      // transform unnormalized light direction into tangent space\n"
-"      // (we use unnormalized to ensure that it interpolates correctly and then\n"
-"      //  normalize it per pixel)\n"
-"      vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
-"      LightVector.x = -dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
-"      LightVector.y = -dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
-"      LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
-"\n"
-"#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
-"      // transform unnormalized eye direction into tangent space\n"
-"      vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
-"      EyeVector.x = -dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
-"      EyeVector.y = -dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
-"      EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
-"#endif\n"
-"\n"
-"      // transform vertex to camera space, using ftransform to match non-VS\n"
-"      // rendering\n"
-"      gl_Position = ftransform();\n"
-"}\n"
-;
-
-const char *builtinshader_light_frag =
-"// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
-"// written by Forest 'LordHavoc' Hale\n"
-"\n"
-"// use half floats on GEFORCEFX for math performance, otherwise don't\n"
-"#ifndef GEFORCEFX\n"
-"#define half float\n"
-"#define hvec2 vec2\n"
-"#define hvec3 vec3\n"
-"#define hvec4 vec4\n"
-"#endif\n"
-"\n"
-"uniform hvec3 LightColor;\n"
-"#ifdef USEOFFSETMAPPING\n"
-"uniform half OffsetMapping_Scale;\n"
-"uniform half OffsetMapping_Bias;\n"
-"#endif\n"
-"#ifdef USESPECULAR\n"
-"uniform half SpecularPower;\n"
-"#endif\n"
-"#ifdef USEFOG\n"
-"uniform half FogRangeRecip;\n"
-"#endif\n"
-"uniform half AmbientScale;\n"
-"uniform half DiffuseScale;\n"
-"#ifdef USESPECULAR\n"
-"uniform half SpecularScale;\n"
-"#endif\n"
-"\n"
-"uniform sampler2D Texture_Normal;\n"
-"uniform sampler2D Texture_Color;\n"
-"#ifdef USESPECULAR\n"
-"uniform sampler2D Texture_Gloss;\n"
-"#endif\n"
-"#ifdef USECUBEFILTER\n"
-"uniform samplerCube Texture_Cube;\n"
-"#endif\n"
-"#ifdef USEFOG\n"
-"uniform sampler2D Texture_FogMask;\n"
-"#endif\n"
-"\n"
-"varying vec2 TexCoord;\n"
-"varying vec3 CubeVector;\n"
-"varying vec3 LightVector;\n"
-"#if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)\n"
-"varying vec3 EyeVector;\n"
-"#endif\n"
-"\n"
-"void main(void)\n"
-"{\n"
-"      // attenuation\n"
-"      //\n"
-"      // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
-"      // center and sharp falloff at the edge, this is about the most efficient\n"
-"      // we can get away with as far as providing illumination.\n"
-"      //\n"
-"      // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
-"      // provide significant illumination, large = slow = pain.\n"
-"      half colorscale = max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
-"\n"
-"#ifdef USEFOG\n"
-"      // apply fog\n"
-"      colorscale *= texture2D(Texture_FogMask, hvec2(length(EyeVector)*FogRangeRecip, 0)).x;\n"
-"#endif\n"
-"\n"
-"#ifdef USEOFFSETMAPPING\n"
-"      // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
-"      hvec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
-"      hvec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
-"      TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
-"      TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
-"#define TexCoord TexCoordOffset\n"
-"#endif\n"
-"\n"
-"      // get the surface normal\n"
-"#ifdef SURFACENORMALIZE\n"
-"      hvec3 surfacenormal = normalize(hvec3(texture2D(Texture_Normal, TexCoord)) - 0.5);\n"
-"#else\n"
-"      hvec3 surfacenormal = -1.0 + 2.0 * hvec3(texture2D(Texture_Normal, TexCoord));\n"
-"#endif\n"
-"\n"
-"      // calculate shading\n"
-"      hvec3 diffusenormal = hvec3(normalize(LightVector));\n"
-"      hvec3 color = hvec3(texture2D(Texture_Color, TexCoord)) * (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
-"#ifdef USESPECULAR\n"
-"      hvec3 specularnormal = hvec3(normalize(diffusenormal + hvec3(normalize(EyeVector))));\n"
-"      color += hvec3(texture2D(Texture_Gloss, TexCoord)) * (SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower));\n"
-"#endif\n"
-"\n"
-"#ifdef USECUBEFILTER\n"
-"      // apply light cubemap filter\n"
-"      color *= hvec3(textureCube(Texture_Cube, CubeVector));\n"
-"#endif\n"
-"\n"
-"      // calculate fragment color (apply light color and attenuation/fog scaling)\n"
-"      gl_FragColor = hvec4(color * LightColor * colorscale, 1);\n"
-"}\n"
-;
-
 void r_shadow_start(void)
 {
-       int i;
-       // use half float math where available (speed gain on NVIDIA GFFX and GF6)
-       if (gl_support_half_float)
-               Cvar_SetValue("r_shadow_glsl_usehalffloat", 1);
        // allocate vertex processing arrays
        numcubemaps = 0;
        r_shadow_attenuation2dtexture = NULL;
@@ -437,8 +268,10 @@ void r_shadow_start(void)
        r_shadow_filters_texturepool = NULL;
        R_Shadow_ValidateCvars();
        R_Shadow_MakeTextures();
-       maxshadowelements = 0;
+       maxshadowtriangles = 0;
        shadowelements = NULL;
+       maxshadowvertices = 0;
+       shadowvertex3f = NULL;
        maxvertexupdate = 0;
        vertexupdate = NULL;
        vertexremap = NULL;
@@ -454,104 +287,23 @@ void r_shadow_start(void)
        r_shadow_buffer_numsurfacepvsbytes = 0;
        r_shadow_buffer_surfacepvs = NULL;
        r_shadow_buffer_surfacelist = NULL;
-       for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
-               r_shadow_program_light[i] = 0;
-       if (gl_support_fragment_shader)
-       {
-               char *vertstring, *fragstring;
-               int vertstrings_count;
-               int fragstrings_count;
-               const char *vertstrings_list[SHADERPERMUTATION_COUNT+1];
-               const char *fragstrings_list[SHADERPERMUTATION_COUNT+1];
-               vertstring = (char *)FS_LoadFile("glsl/light.vert", tempmempool, false);
-               fragstring = (char *)FS_LoadFile("glsl/light.frag", tempmempool, false);
-               for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
-               {
-                       vertstrings_count = 0;
-                       fragstrings_count = 0;
-                       if (i & SHADERPERMUTATION_SPECULAR)
-                       {
-                               vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
-                               fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
-                       }
-                       if (i & SHADERPERMUTATION_FOG)
-                       {
-                               vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
-                               fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
-                       }
-                       if (i & SHADERPERMUTATION_CUBEFILTER)
-                       {
-                               vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
-                               fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
-                       }
-                       if (i & SHADERPERMUTATION_OFFSETMAPPING)
-                       {
-                               vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
-                               fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
-                       }
-                       if (i & SHADERPERMUTATION_SURFACENORMALIZE)
-                       {
-                               vertstrings_list[vertstrings_count++] = "#define SURFACENORMALIZE\n";
-                               fragstrings_list[fragstrings_count++] = "#define SURFACENORMALIZE\n";
-                       }
-                       if (i & SHADERPERMUTATION_GEFORCEFX)
-                       {
-                               vertstrings_list[vertstrings_count++] = "#define GEFORCEFX\n";
-                               fragstrings_list[fragstrings_count++] = "#define GEFORCEFX\n";
-                       }
-                       vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert;
-                       fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag;
-                       r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
-                       if (!r_shadow_program_light[i])
-                       {
-                               Con_Printf("permutation %s %s %s %s %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");
-                               continue;
-                       }
-                       qglUseProgramObjectARB(r_shadow_program_light[i]);
-                       qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR
-                       qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR
-                       if (i & SHADERPERMUTATION_SPECULAR)
-                       {
-                               qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR
-                       }
-                       if (i & SHADERPERMUTATION_CUBEFILTER)
-                       {
-                               qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR
-                       }
-                       if (i & SHADERPERMUTATION_FOG)
-                       {
-                               qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR
-                       }
-               }
-               qglUseProgramObjectARB(0);
-               if (fragstring)
-                       Mem_Free(fragstring);
-               if (vertstring)
-                       Mem_Free(vertstring);
-       }
 }
 
 void r_shadow_shutdown(void)
 {
-       int i;
        R_Shadow_UncompileWorldLights();
-       for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
-       {
-               if (r_shadow_program_light[i])
-               {
-                       GL_Backend_FreeProgram(r_shadow_program_light[i]);
-                       r_shadow_program_light[i] = 0;
-               }
-       }
        numcubemaps = 0;
        r_shadow_attenuation2dtexture = NULL;
        r_shadow_attenuation3dtexture = NULL;
        R_FreeTexturePool(&r_shadow_texturepool);
        R_FreeTexturePool(&r_shadow_filters_texturepool);
-       maxshadowelements = 0;
+       maxshadowtriangles = 0;
        if (shadowelements)
                Mem_Free(shadowelements);
        shadowelements = NULL;
+       if (shadowvertex3f)
+               Mem_Free(shadowvertex3f);
+       shadowvertex3f = NULL;
        maxvertexupdate = 0;
        if (vertexupdate)
                Mem_Free(vertexupdate);
@@ -614,19 +366,12 @@ void R_Shadow_Help_f(void)
 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
-"r_shadow_glsl : use OpenGL Shading Language for lighting\n"
-"r_shadow_glsl_offsetmapping : enables Offset Mapping bumpmap enhancement\n"
-"r_shadow_glsl_offsetmapping_scale : controls depth of Offset Mapping\n"
-"r_shadow_glsl_offsetmapping_bias : should be negative half of scale\n"
-"r_shadow_glsl_usehalffloat : use lower quality lighting\n"
-"r_shadow_glsl_surfacenormalize : makes bumpmapping slightly higher quality\n"
 "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"
        );
@@ -657,28 +402,20 @@ 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);
-       Cvar_RegisterVariable(&r_shadow_glsl_offsetmapping_bias);
-       Cvar_RegisterVariable(&r_shadow_glsl_usehalffloat);
-       Cvar_RegisterVariable(&r_shadow_glsl_surfacenormalize);
        Cvar_RegisterVariable(&gl_ext_stenciltwoside);
        if (gamemode == GAME_TENEBRAE)
        {
                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;
-       maxshadowelements = 0;
+       maxshadowtriangles = 0;
        shadowelements = NULL;
+       maxshadowvertices = 0;
+       shadowvertex3f = NULL;
        maxvertexupdate = 0;
        vertexupdate = NULL;
        vertexremap = NULL;
@@ -717,17 +454,24 @@ matrix4x4_t matrix_attenuationz =
        }
 };
 
-int *R_Shadow_ResizeShadowElements(int numtris)
+void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
 {
        // make sure shadowelements is big enough for this volume
-       if (maxshadowelements < numtris * 24)
+       if (maxshadowtriangles < numtriangles)
        {
-               maxshadowelements = numtris * 24;
+               maxshadowtriangles = numtriangles;
                if (shadowelements)
                        Mem_Free(shadowelements);
-               shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
+               shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
+       }
+       // make sure shadowvertex3f is big enough for this volume
+       if (maxshadowvertices < numvertices)
+       {
+               maxshadowvertices = numvertices;
+               if (shadowvertex3f)
+                       Mem_Free(shadowvertex3f);
+               shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
        }
-       return shadowelements;
 }
 
 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
@@ -741,8 +485,8 @@ 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 = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
-               r_shadow_buffer_leaflist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
+               r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
+               r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
        }
        if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
        {
@@ -751,8 +495,8 @@ 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 = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
-               r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
+               r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
+               r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
        }
 }
 
@@ -766,8 +510,8 @@ void R_Shadow_PrepareShadowMark(int numtris)
                        Mem_Free(shadowmark);
                if (shadowmarklist)
                        Mem_Free(shadowmarklist);
-               shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
-               shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
+               shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
+               shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
                shadowmarkcount = 0;
        }
        shadowmarkcount++;
@@ -794,8 +538,8 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *
                        Mem_Free(vertexupdate);
                if (vertexremap)
                        Mem_Free(vertexremap);
-               vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
-               vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
+               vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
+               vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
                vertexupdatenum = 0;
        }
        vertexupdatenum++;
@@ -912,10 +656,11 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f,
        if (!numverts || !nummarktris)
                return;
        // make sure shadowelements is big enough for this volume
-       if (maxshadowelements < nummarktris * 24)
-               R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
-       tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
-       R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
+       if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
+               R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
+       tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdistance, nummarktris, marktris);
+       renderstats.lights_dynamicshadowtriangles += tris;
+       R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
 }
 
 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
@@ -961,28 +706,25 @@ void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *verte
        if (r_shadow_compilingrtlight)
        {
                // if we're compiling an rtlight, capture the mesh
-               Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
+               Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
                return;
        }
+       renderstats.lights_shadowtriangles += numtriangles;
        memset(&m, 0, sizeof(m));
        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
                qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
                R_Mesh_Draw(0, numvertices, numtriangles, element3i);
-               c_rt_shadowmeshes++;
-               c_rt_shadowtris += numtriangles;
                // increment stencil if frontface is behind depthbuffer
                qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
                qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
        }
        R_Mesh_Draw(0, numvertices, numtriangles, element3i);
-       c_rt_shadowmeshes++;
-       c_rt_shadowtris += numtriangles;
        GL_LockArrays(0, 0);
 }
 
@@ -990,14 +732,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 = 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++)
@@ -1053,28 +795,21 @@ 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_dlightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormod * ent->alpha
-static vec3_t r_shadow_entitylightcolor;
+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;
 
@@ -1087,62 +822,68 @@ 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_glsl.integer && gl_support_fragment_shader)
+               r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
+       else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
+               r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
+       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_shadow_shadow_polygonoffset.value != 0)
-       //{
-       //      qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
-       //      qglEnable(GL_POLYGON_OFFSET_FILL);
-       //}
-       //else
-       //      qglDisable(GL_POLYGON_OFFSET_FILL);
+       qglPolygonOffset(r_shadowpolygonfactor, r_shadowpolygonoffset);
        qglDepthFunc(GL_LESS);
        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
@@ -1154,31 +895,32 @@ 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
                qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        }
        GL_Clear(GL_STENCIL_BUFFER_BIT);
-       c_rt_clears++;
+       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();
-       GL_BlendFunc(GL_ONE, GL_ONE);
+       R_Shadow_RenderMode_Reset();
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
        GL_DepthMask(false);
        GL_DepthTest(true);
-       qglPolygonOffset(0, 0);
+       qglPolygonOffset(r_polygonfactor, r_polygonoffset);
        //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);
@@ -1187,130 +929,84 @@ 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_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);
-               GL_BlendFunc(GL_ONE, GL_ONE);
+       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_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_SRC_ALPHA, 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);
+       qglPolygonOffset(r_polygonfactor, r_polygonoffset);
        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);
+       qglPolygonOffset(r_polygonfactor, r_polygonoffset);
        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);
+       qglPolygonOffset(r_polygonfactor, r_polygonoffset);
        //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)
@@ -1399,149 +1095,110 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        GL_Scissor(ix1, vid.height - iy2, ix2 - ix1, iy2 - iy1);
        //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
        //qglEnable(GL_SCISSOR_TEST);
-       c_rt_scissored++;
+       renderstats.lights_scissored++;
        return false;
 }
 
-extern float *rsurface_vertex3f;
-extern float *rsurface_svector3f;
-extern float *rsurface_tvector3f;
-extern float *rsurface_normal3f;
-extern void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg);
-
-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 *color4f = rsurface_array_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;
        }
 }
 
 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
-#define USETEXMATRIX
-
-#ifndef USETEXMATRIX
-// this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
-// if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
-static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
-{
-       do
-       {
-               tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
-               tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
-               tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
-               vertex3f += 3;
-               tc3f += 3;
-       }
-       while (--numverts);
-}
-
-static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
-{
-       do
-       {
-               tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
-               tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
-               vertex3f += 3;
-               tc2f += 2;
-       }
-       while (--numverts);
-}
-#endif
 
 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin)
 {
@@ -1549,7 +1206,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);
@@ -1563,9 +1220,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
@@ -1575,953 +1232,841 @@ 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;
+       model_t *model = ent->model;
        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);
+       RSurf_SetPointersForPass(false, false);
        for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
        {
                const msurface_t *surface = surfacelist[surfacelistindex];
-               RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+               if (rsurface_dynamicvertex)
+                       RSurf_PrepareDynamicSurfaceVertices(surface);
                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);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, model->surfmesh.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;
-       //qboolean dowatershader = (texture->currentmaterialflags & MATERIALFLAG_WATER) && r_watershader.value;
-       // 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;
-       R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
-       R_Mesh_TexBind(0, R_GetTexture(normalmaptexture));
-       R_Mesh_TexBind(1, R_GetTexture(basetexture));
-       R_Mesh_TexBind(2, R_GetTexture(glosstexture));
-       if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
-       {
-               qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
-       }
-       qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
+       model_t *model = ent->model;
+       R_SetupSurfaceShader(ent, texture, r_shadow_entityeyeorigin, lightcolorbase, false);
+       RSurf_SetPointersForPass(false, true);
        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);
-               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);
-               }
-               R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+               const int *elements = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
+               if (rsurface_dynamicvertex)
+                       RSurf_PrepareDynamicSurfaceVertices(surface);
+               R_Mesh_TexCoordPointer(0, 2, model->surfmesh.data_texcoordtexture2f);
                R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
                R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
                R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
                GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
                R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-               c_rt_lightmeshes++;
-               c_rt_lighttris += surface->num_triangles;
                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, 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;
+       model_t *model = ent->model;
+       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 = model->surfmesh.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)
+       {
+               // 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);
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               m.tex[1] = R_GetTexture(basetexture);
+               m.pointer_texcoord[1] = model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[1] = texture->currenttexmatrix;
+               m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
+               m.pointer_texcoord3f[2] = rsurface_vertex3f;
+               m.texmatrix[2] = r_shadow_entitytolight;
+               GL_BlendFunc(GL_ONE, GL_ONE);
+       }
+       else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
        {
-               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)
+               // 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);
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               m.tex[1] = R_GetTexture(basetexture);
+               m.pointer_texcoord[1] = model->surfmesh.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);
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.texmatrix[1] = r_shadow_entitytoattenuationz;
+               m.tex[2] = R_GetTexture(basetexture);
+               m.pointer_texcoord[2] = model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[2] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
-                       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);
+                       m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
+                       m.pointer_texcoord3f[3] = rsurface_vertex3f;
+                       m.texmatrix[3] = r_shadow_entitytolight;
                }
-               if (doambientbase)
+               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);
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.texmatrix[1] = r_shadow_entitytoattenuationz;
+               m.tex[2] = R_GetTexture(basetexture);
+               m.pointer_texcoord[2] = model->surfmesh.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.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.texmatrix[1] = r_shadow_entitytoattenuationz;
+               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] = model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
-                       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);
-#ifdef USETEXMATRIX
-                               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);
-#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);
-#ifdef USETEXMATRIX
-                               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);
-#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);
-#ifdef USETEXMATRIX
-                               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);
-#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);
-#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);
-#ifdef USETEXMATRIX
-                               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);
-#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);
-#ifdef USETEXMATRIX
-                                       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);
-#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);
-#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);
-#ifdef USETEXMATRIX
-                               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);
-#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);
-#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);
-#ifdef USETEXMATRIX
-                               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);
-#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);
-                               c_rt_lightmeshes++;
-                               c_rt_lighttris += surface->num_triangles;
-
-                               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);
-#ifdef USETEXMATRIX
-                                       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);
-#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);
-                               c_rt_lightmeshes++;
-                               c_rt_lighttris += surface->num_triangles;
-                       }
-                       GL_LockArrays(0, 0);
+                       m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
+                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.texmatrix[1] = r_shadow_entitytolight;
                }
-               if (dodiffusebase)
+               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;
+       model_t *model = ent->model;
+       float color2[3];
+       rmeshstate_t m;
+       const int *elements = model->surfmesh.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] = model->surfmesh.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] = rsurface_array_texcoord3f;
+               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(rsurface_array_texcoord3f + 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);
+               m.pointer_texcoord3f[2] = rsurface_vertex3f;
+               m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
+               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] = model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
-                       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);
-#ifdef USETEXMATRIX
-                               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);
-#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);
-                               c_rt_lightmeshes++;
-                               c_rt_lighttris += surface->num_triangles;
-
-                               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);
-#ifdef USETEXMATRIX
-                                       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);
-#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);
-#ifdef USETEXMATRIX
-                               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);
-#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);
-                               c_rt_lightmeshes++;
-                               c_rt_lighttris += surface->num_triangles;
-
-                               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);
-                               c_rt_lightmeshes++;
-                               c_rt_lighttris += surface->num_triangles;
-
-                               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);
-#ifdef USETEXMATRIX
-                                       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);
-#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);
-                               c_rt_lightmeshes++;
-                               c_rt_lighttris += surface->num_triangles;
-
-                               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;
-#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);
-#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);
-#ifdef USETEXMATRIX
-                               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);
-#endif
-                               m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
-                               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);
-#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);
-                               c_rt_lightmeshes++;
-                               c_rt_lighttris += surface->num_triangles;
-
-                               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);
-#ifdef USETEXMATRIX
-                                       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);
-#endif
-                               }
-                               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-                       }
-                       else
+                       m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
+                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.texmatrix[1] = r_shadow_entitytolight;
+               }
+               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);
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               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] = model->surfmesh.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] = rsurface_array_texcoord3f;
+               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(rsurface_array_texcoord3f + 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] = model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
+               {
+                       m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
+                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.texmatrix[1] = r_shadow_entitytolight;
+               }
+               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] = model->surfmesh.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] = rsurface_array_texcoord3f;
+               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(rsurface_array_texcoord3f + 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] = model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
+               m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
+               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] = model->surfmesh.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] = rsurface_array_texcoord3f;
+               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(rsurface_array_texcoord3f + 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);
+               m.pointer_texcoord3f[2] = rsurface_vertex3f;
+               m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
+               m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.pointer_texcoord3f[3] = rsurface_vertex3f;
+               m.texmatrix[3] = r_shadow_entitytoattenuationz;
+               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] = model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
+               {
+                       m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
+                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.texmatrix[1] = r_shadow_entitytolight;
+               }
+               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);
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.texmatrix[1] = r_shadow_entitytoattenuationz;
+               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] = model->surfmesh.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] = rsurface_array_texcoord3f;
+               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(rsurface_array_texcoord3f + 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] = model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
+               {
+                       m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
+                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.texmatrix[1] = r_shadow_entitytolight;
+               }
+               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;
+       model_t *model = ent->model;
+       float color2[3];
+       rmeshstate_t m;
+       const int *elements = model->surfmesh.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] = model->surfmesh.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] = rsurface_array_texcoord3f;
+               R_Shadow_GenTexCoords_Specular_NormalCubeMap(rsurface_array_texcoord3f + 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);
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               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] = model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
+               {
+                       m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
+                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.texmatrix[1] = r_shadow_entitytolight;
+               }
+               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] = model->surfmesh.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] = rsurface_array_texcoord3f;
+               R_Shadow_GenTexCoords_Specular_NormalCubeMap(rsurface_array_texcoord3f + 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] = model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
+               m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
+               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] = model->surfmesh.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] = rsurface_array_texcoord3f;
+               R_Shadow_GenTexCoords_Specular_NormalCubeMap(rsurface_array_texcoord3f + 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);
+               m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
+               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.texmatrix[1] = r_shadow_entitytoattenuationz;
+               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] = model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = texture->currenttexmatrix;
+               if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
+               {
+                       m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
+                       m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.texmatrix[1] = r_shadow_entitytolight;
+               }
+               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;
+       RSurf_SetPointersForPass(false, true);
+       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+       {
+               const msurface_t *surface = surfacelist[surfacelistindex];
+               if (rsurface_dynamicvertex)
+                       RSurf_PrepareDynamicSurfaceVertices(surface);
+               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 model_t *model, const msurface_t *surface, vec3_t diffusecolor2, vec3_t ambientcolor2)
+{
+       int renders;
+       const int *elements = model->surfmesh.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)
                        {
-                               // 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);
-#ifdef USETEXMATRIX
-                               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);
-#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);
+                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
                                GL_LockArrays(0, 0);
-                               c_rt_lightmeshes++;
-                               c_rt_lighttris += surface->num_triangles;
-
-                               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);
-                               c_rt_lightmeshes++;
-                               c_rt_lighttris += surface->num_triangles;
-
-                               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);
-#ifdef USETEXMATRIX
-                                       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);
-#endif
-                               }
-                               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
+                               newnumtriangles = 0;
+                               newe = newelements;
                        }
-                       // 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]--)
+                       if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
                        {
-                               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);
-                               c_rt_lightmeshes++;
-                               c_rt_lighttris += surface->num_triangles;
+                               newe[0] = e[0];
+                               newe[1] = e[1];
+                               newe[2] = e[2];
+                               newnumtriangles++;
+                               newe += 3;
+                               draw = true;
                        }
-                       GL_LockArrays(0, 0);
                }
-               if (dospecular)
+               if (newnumtriangles >= 1)
                {
-                       // 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);
-                                       c_rt_lightmeshes++;
-                                       c_rt_lighttris += surface->num_triangles;
-
-                                       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);
-                                       c_rt_lightmeshes++;
-                                       c_rt_lighttris += surface->num_triangles;
-                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                                       c_rt_lightmeshes++;
-                                       c_rt_lighttris += surface->num_triangles;
-                                       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;
-#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);
-#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);
-                                       c_rt_lightmeshes++;
-                                       c_rt_lighttris += surface->num_triangles;
-
-                                       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);
-#ifdef USETEXMATRIX
-                                               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);
-#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);
-                                       c_rt_lightmeshes++;
-                                       c_rt_lighttris += surface->num_triangles;
-
-                                       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);
-                                       c_rt_lightmeshes++;
-                                       c_rt_lighttris += surface->num_triangles;
-                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                                       c_rt_lightmeshes++;
-                                       c_rt_lighttris += surface->num_triangles;
-                                       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;
-#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);
-#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);
-                                       c_rt_lightmeshes++;
-                                       c_rt_lighttris += surface->num_triangles;
-
-                                       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);
-                                       c_rt_lightmeshes++;
-                                       c_rt_lighttris += surface->num_triangles;
-                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-                                       c_rt_lightmeshes++;
-                                       c_rt_lighttris += surface->num_triangles;
-                                       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;
-#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);
-#ifdef USETEXMATRIX
-                                       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);
-#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);
-                                       c_rt_lightmeshes++;
-                                       c_rt_lighttris += surface->num_triangles;
-
-                                       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);
-#ifdef USETEXMATRIX
-                                               m.pointer_texcoord3f[1] = rsurface_vertex3f;
-                                               m.texmatrix[1] = r_shadow_entitytolight;
+                       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
-                                               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);
+               for (i = 0, c = rsurface_array_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
-                                       }
-                                       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);
-                                       c_rt_lightmeshes++;
-                                       c_rt_lighttris += surface->num_triangles;
-                               }
-                               GL_LockArrays(0, 0);
-                       }
+               // now reduce the intensity for the next overbright pass
+               for (i = 0, c = rsurface_array_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];
+       model_t *model = ent->model;
+       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)
        {
                // voodoo2
                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
-#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_entitytoattenuationxyz);
-#endif
                if (r_textureunits.integer >= 3)
                {
                        // Geforce3/Radeon class but not using dot3
                        m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                        m.texmatrix[2] = r_shadow_entitytoattenuationz;
-#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_entitytoattenuationz);
-#endif
                }
        }
-       m.pointer_color = varray_color4f;
+       m.pointer_color = rsurface_array_color4f;
        R_Mesh_State(&m);
+       RSurf_SetPointersForPass(true, false);
        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);
-               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 (rsurface_dynamicvertex)
+                       RSurf_PrepareDynamicSurfaceVertices(surface);
                // OpenGL 1.1 path (anything)
-               R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+               R_Mesh_TexCoordPointer(0, 2, model->surfmesh.data_texcoordtexture2f);
                R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
                if (r_textureunits.integer >= 2)
                {
                        // voodoo2 or TNT
-#ifdef USETEXMATRIX
                        R_Mesh_TexCoordPointer(1, 3, rsurface_vertex3f);
-#else
-                       R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
                        if (r_textureunits.integer >= 3)
                        {
                                // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
-#ifdef USETEXMATRIX
                                R_Mesh_TexCoordPointer(2, 3, rsurface_vertex3f);
-#else
-                               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
-#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(model, 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);
-                       c_rt_lightmeshes++;
-                       c_rt_lighttris += surface->num_triangles;
+                       R_Mesh_TexBind(0, R_GetTexture(pantstexture));
+                       R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, surface, diffusecolorpants, ambientcolorpants);
+               }
+               if (doshirt)
+               {
+                       R_Mesh_TexBind(0, R_GetTexture(shirttexture));
+                       R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, 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;
+       // 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) + (r_shadow_rtlight->specularscale * texture->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);
+       RSurf_PrepareForBatch(ent, texture, r_shadow_entityeyeorigin);
+       if (texture->colormapping)
        {
-       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;
+               qboolean dopants = texture->skin.pants != NULL && VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f);
+               qboolean doshirt = texture->skin.shirt != NULL && VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
+               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
+                       VectorClear(lightcolorpants);
+               if (doshirt)
+               {
+                       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
+                       VectorClear(lightcolorshirt);
+               switch (r_shadow_rendermode)
+               {
+               case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
+                       R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
+                       break;
+               case R_SHADOW_RENDERMODE_LIGHT_GLSL:
+                       R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
+                       break;
+               case R_SHADOW_RENDERMODE_LIGHT_DOT3:
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
+                       break;
+               case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
+                       R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
+                       break;
+               default:
+                       Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
+                       break;
+               }
+       }
+       else
+       {
+               switch (r_shadow_rendermode)
+               {
+               case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
+                       R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
+                       break;
+               case R_SHADOW_RENDERMODE_LIGHT_GLSL:
+                       R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
+                       break;
+               case R_SHADOW_RENDERMODE_LIGHT_DOT3:
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
+                       break;
+               case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
+                       R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
+                       break;
+               default:
+                       Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
+                       break;
+               }
        }
 }
 
-void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
+void R_RTLight_Update(dlight_t *light, int isstatic)
 {
        int j, k;
        float scale;
+       rtlight_t *rtlight = &light->rtlight;
        R_RTLight_Uncompile(rtlight);
        memset(rtlight, 0, sizeof(*rtlight));
 
@@ -2557,11 +2102,6 @@ void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int i
        for (k = 0;k < 3;k++)
                for (j = 0;j < 4;j++)
                        rtlight->matrix_worldtolight.m[k][j] *= scale;
-
-       rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
-       rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
-       VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
-       rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
 }
 
 // compiles rtlight geometry
@@ -2571,7 +2111,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;
@@ -2595,13 +2135,13 @@ 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 = Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
+               data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
                rtlight->static_numleafs = numleafs;
                rtlight->static_numleafpvsbytes = numleafpvsbytes;
-               rtlight->static_leaflist = (void *)data;data += sizeof(int) * numleafs;
-               rtlight->static_leafpvs = (void *)data;data += numleafpvsbytes;
+               rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
+               rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
                rtlight->static_numsurfaces = numsurfaces;
-               rtlight->static_surfacelist = (void *)data;data += sizeof(int) * numsurfaces;
+               rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
                if (numleafs)
                        memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
                if (numleafpvsbytes)
@@ -2631,7 +2171,8 @@ void R_RTLight_Compile(rtlight_t *rtlight)
                }
        }
 
-       Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles (in %i meshes)\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], shadowtris, shadowmeshes);
+       if (developer.integer >= 10)
+               Con_Printf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles (in %i meshes)\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], shadowtris, shadowmeshes);
 }
 
 void R_RTLight_Uncompile(rtlight_t *rtlight)
@@ -2661,48 +2202,46 @@ 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)
 {
+       model_t *model = ent->model;
        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
                                        qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
                                        R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
-                                       c_rtcached_shadowmeshes++;
-                                       c_rtcached_shadowtris += mesh->numtriangles;
                                        // increment stencil if frontface is behind depthbuffer
                                        qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
                                        qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
                                }
                                R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
-                               c_rtcached_shadowmeshes++;
-                               c_rtcached_shadowtris += mesh->numtriangles;
                                GL_LockArrays(0, 0);
                        }
                }
                else if (numsurfaces)
                {
                        R_Mesh_Matrix(&ent->matrix);
-                       ent->model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
+                       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;
@@ -2710,67 +2249,50 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int num
                relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
                relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
                R_Mesh_Matrix(&ent->matrix);
-               ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
+               model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
        }
 }
 
-void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t lightcolorbase, int numsurfaces, int *surfacelist)
+void R_Shadow_SetupEntityLight(const entity_render_t *ent)
 {
        // set up properties for rendering light onto this entity
-       r_shadow_entitylightcolor[0] = lightcolorbase[0] * ent->colormod[0] * ent->alpha;
-       r_shadow_entitylightcolor[1] = lightcolorbase[1] * ent->colormod[1] * ent->alpha;
-       r_shadow_entitylightcolor[2] = lightcolorbase[2] * ent->colormod[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)
+{
+       model_t *model = ent->model;
+       if (!model->DrawLight)
+               return;
+       R_Shadow_SetupEntityLight(ent);
        if (ent == r_refdef.worldentity)
-               ent->model->DrawLight(ent, r_shadow_entitylightcolor, numsurfaces, surfacelist);
+               model->DrawLight(ent, numsurfaces, surfacelist);
        else
-               ent->model->DrawLight(ent, r_shadow_entitylightcolor, ent->model->nummodelsurfaces, ent->model->surfacelist);
+               model->DrawLight(ent, model->nummodelsurfaces, 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;
 
-       f = (rtlight->style >= 0 ? d_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;
-       /*
-       if (rtlight->selected)
-       {
-               f = 2 + sin(realtime * M_PI * 4.0);
-               VectorScale(lightcolor, f, lightcolor);
-       }
-       */
-
        // 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)
@@ -2778,7 +2300,22 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        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;
+       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, rtlight->currentcolor);
+       /*
+       if (rtlight->selected)
+       {
+               f = 2 + sin(realtime * M_PI * 4.0);
+               VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
+       }
+       */
+
+       // 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))
@@ -2829,26 +2366,31 @@ 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++)
                {
+                       model_t *model;
                        entity_render_t *ent = r_refdef.entities[i];
                        if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
-                        && ent->model
+                        && (model = ent->model)
                         && !(ent->flags & RENDER_TRANSPARENT)
                         && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
                        {
                                // about the VectorDistance2 - light emitting entities should not cast their own shadow
-                               if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
+                               if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
                                        shadowentities[numshadowentities++] = ent;
-                               if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
+                               if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && model->DrawLight)
                                        lightentities[numlightentities++] = ent;
                        }
                }
@@ -2858,37 +2400,53 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        if (!numlightentities)
                return;
 
-       R_Shadow_Stage_ActiveLight(rtlight);
-       c_rt_lights++;
+       // don't let sound skip if going slow
+       if (r_refdef.extraupdate)
+               S_ExtraUpdate ();
 
-       usestencil = false;
-       if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && 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);
-       }
+       // make this the active rtlight for rendering purposes
+       R_Shadow_RenderMode_ActiveLight(rtlight);
+       // count this light in the r_speeds
+       renderstats.lights++;
 
-       if (numlightentities && !visible)
+       usestencil = false;
+       if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
        {
-               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);
+               }
        }
 }
 
@@ -2900,7 +2458,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)
@@ -2914,10 +2472,10 @@ void R_ShadowVolumeLighting(qboolean visible)
                        if (light->flags & flag)
                                R_DrawRTLight(&light->rtlight, visible);
        if (r_rtdlight)
-               for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
-                       R_DrawRTLight(&light->rtlight, 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"};
@@ -2960,7 +2518,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
@@ -2986,7 +2544,7 @@ rtexture_t *R_Shadow_LoadCubemap(const char *basename)
                                        {
                                                cubemapsize = image_width;
                                                // note this clears to black, so unavailable sides are black
-                                               cubemappixels = 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)
@@ -3043,7 +2601,7 @@ void R_Shadow_FreeCubemaps(void)
 dlight_t *R_Shadow_NewWorldLight(void)
 {
        dlight_t *light;
-       light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
+       light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
        light->next = r_shadow_worldlightchain;
        r_shadow_worldlightchain = light;
        return light;
@@ -3077,7 +2635,7 @@ void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, ve
        light->flags = flags;
        Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
 
-       R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
+       R_RTLight_Update(light, true);
 }
 
 void R_Shadow_FreeWorldLight(dlight_t *light)
@@ -3086,7 +2644,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);
 }
@@ -3108,41 +2666,32 @@ 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, r_crosshairs[1]->tex, 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 = 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, r_crosshairs[surfacenumber]->tex, NULL, false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
 }
 
 void R_Shadow_DrawLightSprites(void)
 {
        int i;
-       cachepic_t *pic;
        dlight_t *light;
 
-       for (i = 0;i < 5;i++)
-       {
-               lighttextures[i] = NULL;
-               if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", 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, 1+(i % 5), &light->rtlight);
+       R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
 }
 
 void R_Shadow_SelectLightInView(void)
@@ -3180,7 +2729,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;
@@ -3265,7 +2814,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)
@@ -3289,7 +2838,7 @@ void R_Shadow_SaveWorldLights(void)
                {
                        bufmaxchars = bufchars + strlen(line) + 2048;
                        oldbuf = buf;
-                       buf = Mem_Alloc(tempmempool, bufmaxchars);
+                       buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
                        if (oldbuf)
                        {
                                if (bufchars)
@@ -3321,7 +2870,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;
@@ -3367,7 +2916,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)
        {
@@ -3377,7 +2926,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;
@@ -3678,7 +3227,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");
@@ -3695,7 +3244,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;
@@ -4193,19 +3742,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)");
 }