]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
implemented Shadow Volume BSP based culling of lit surfaces, this is slightly better...
[xonotic/darkplaces.git] / r_shadow.c
index e1a736e4e317e3af85658085aa4be9b76daedbac..76ed116fdea7eec7811dac0f75140beab139eea8 100644 (file)
@@ -146,6 +146,7 @@ typedef enum r_shadow_rendermode_e
 {
        R_SHADOW_RENDERMODE_NONE,
        R_SHADOW_RENDERMODE_STENCIL,
+       R_SHADOW_RENDERMODE_SEPARATESTENCIL,
        R_SHADOW_RENDERMODE_STENCILTWOSIDE,
        R_SHADOW_RENDERMODE_LIGHT_VERTEX,
        R_SHADOW_RENDERMODE_LIGHT_DOT3,
@@ -184,6 +185,10 @@ int r_shadow_buffer_numsurfacepvsbytes;
 unsigned char *r_shadow_buffer_surfacepvs;
 int *r_shadow_buffer_surfacelist;
 
+// current light's cull box (copied out of an rtlight or calculated by GetLightInfo)
+vec3_t r_shadow_rtlight_cullmins;
+vec3_t r_shadow_rtlight_cullmaxs;
+
 rtexturepool_t *r_shadow_texturepool;
 rtexture_t *r_shadow_attenuation2dtexture;
 rtexture_t *r_shadow_attenuation3dtexture;
@@ -198,8 +203,9 @@ cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0
 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_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.5", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
+cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "2", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
+cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
 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"};
@@ -207,17 +213,19 @@ cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culli
 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_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
 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_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
 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_separatestencil = {0, "gl_ext_separatetencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
 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"};
@@ -359,7 +367,6 @@ void R_Shadow_Help_f(void)
 "r_shadow_projectdistance : shadow volume projection distance\n"
 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
-"r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
 "r_shadow_realtime_world : use high quality world lighting mode\n"
 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
@@ -385,6 +392,7 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_gloss);
        Cvar_RegisterVariable(&r_shadow_gloss2intensity);
        Cvar_RegisterVariable(&r_shadow_glossintensity);
+       Cvar_RegisterVariable(&r_shadow_glossexponent);
        Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
        Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
        Cvar_RegisterVariable(&r_shadow_lightintensityscale);
@@ -392,17 +400,19 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_projectdistance);
        Cvar_RegisterVariable(&r_shadow_realtime_dlight);
        Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
-       Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
+       Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
        Cvar_RegisterVariable(&r_shadow_realtime_world);
        Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
        Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
        Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
        Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
        Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
+       Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
        Cvar_RegisterVariable(&r_shadow_scissor);
        Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
        Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
        Cvar_RegisterVariable(&r_shadow_texture3d);
+       Cvar_RegisterVariable(&gl_ext_separatestencil);
        Cvar_RegisterVariable(&gl_ext_stenciltwoside);
        if (gamemode == GAME_TENEBRAE)
        {
@@ -524,12 +534,18 @@ void R_Shadow_PrepareShadowMark(int numtris)
        numshadowmark = 0;
 }
 
-int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
+int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
 {
        int i, j;
        int outtriangles = 0, outvertices = 0;
        const int *element;
        const float *vertex;
+       float ratio, direction[3], projectvector[3];
+
+       if (projectdirection)
+               VectorScale(projectdirection, projectdistance, projectvector);
+       else
+               VectorClear(projectvector);
 
        if (maxvertexupdate < innumvertices)
        {
@@ -553,26 +569,49 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *
        for (i = 0;i < numshadowmarktris;i++)
                shadowmark[shadowmarktris[i]] = shadowmarkcount;
 
-       for (i = 0;i < numshadowmarktris;i++)
+       // create the vertices
+       if (projectdirection)
        {
-               element = inelement3i + shadowmarktris[i] * 3;
-               // make sure the vertices are created
-               for (j = 0;j < 3;j++)
+               for (i = 0;i < numshadowmarktris;i++)
                {
-                       if (vertexupdate[element[j]] != vertexupdatenum)
+                       element = inelement3i + shadowmarktris[i] * 3;
+                       for (j = 0;j < 3;j++)
                        {
-                               float ratio, direction[3];
-                               vertexupdate[element[j]] = vertexupdatenum;
-                               vertexremap[element[j]] = outvertices;
-                               vertex = invertex3f + element[j] * 3;
-                               // project one copy of the vertex to the sphere radius of the light
-                               // (FIXME: would projecting it to the light box be better?)
-                               VectorSubtract(vertex, projectorigin, direction);
-                               ratio = projectdistance / VectorLength(direction);
-                               VectorCopy(vertex, outvertex3f);
-                               VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
-                               outvertex3f += 6;
-                               outvertices += 2;
+                               if (vertexupdate[element[j]] != vertexupdatenum)
+                               {
+                                       vertexupdate[element[j]] = vertexupdatenum;
+                                       vertexremap[element[j]] = outvertices;
+                                       vertex = invertex3f + element[j] * 3;
+                                       // project one copy of the vertex according to projectvector
+                                       VectorCopy(vertex, outvertex3f);
+                                       VectorAdd(vertex, projectvector, (outvertex3f + 3));
+                                       outvertex3f += 6;
+                                       outvertices += 2;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               for (i = 0;i < numshadowmarktris;i++)
+               {
+                       element = inelement3i + shadowmarktris[i] * 3;
+                       for (j = 0;j < 3;j++)
+                       {
+                               if (vertexupdate[element[j]] != vertexupdatenum)
+                               {
+                                       vertexupdate[element[j]] = vertexupdatenum;
+                                       vertexremap[element[j]] = outvertices;
+                                       vertex = invertex3f + element[j] * 3;
+                                       // project one copy of the vertex to the sphere radius of the light
+                                       // (FIXME: would projecting it to the light box be better?)
+                                       VectorSubtract(vertex, projectorigin, direction);
+                                       ratio = projectdistance / VectorLength(direction);
+                                       VectorCopy(vertex, outvertex3f);
+                                       VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
+                                       outvertex3f += 6;
+                                       outvertices += 2;
+                               }
                        }
                }
        }
@@ -645,12 +684,12 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *
        return outtriangles;
 }
 
-void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, int nummarktris, const int *marktris)
+void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris)
 {
        int tris, outverts;
        if (projectdistance < 0.1)
        {
-               Con_Printf("R_Shadow_Volume: projectdistance %f\n");
+               Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
                return;
        }
        if (!numverts || !nummarktris)
@@ -658,16 +697,17 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f,
        // make sure shadowelements is big enough for this volume
        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;
+       tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
+       r_refdef.stats.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)
+void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
 {
        int t, tend;
        const int *e;
        const float *v[3];
+       float normal[3];
        if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
                return;
        tend = firsttriangle + numtris;
@@ -676,26 +716,59 @@ void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *inv
         && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
        {
                // surface box entirely inside light box, no box cull
-               for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
-                       if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
-                               shadowmarklist[numshadowmark++] = t;
+               if (projectdirection)
+               {
+                       for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+                       {
+                               TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
+                               if (DotProduct(normal, projectdirection) < 0)
+                                       shadowmarklist[numshadowmark++] = t;
+                       }
+               }
+               else
+               {
+                       for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+                               if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
+                                       shadowmarklist[numshadowmark++] = t;
+               }
        }
        else
        {
                // surface box not entirely inside light box, cull each triangle
-               for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+               if (projectdirection)
                {
-                       v[0] = invertex3f + e[0] * 3;
-                       v[1] = invertex3f + e[1] * 3;
-                       v[2] = invertex3f + e[2] * 3;
-                       if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
-                        && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
-                        && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
-                        && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
-                        && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
-                        && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
-                        && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
-                               shadowmarklist[numshadowmark++] = t;
+                       for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+                       {
+                               v[0] = invertex3f + e[0] * 3;
+                               v[1] = invertex3f + e[1] * 3;
+                               v[2] = invertex3f + e[2] * 3;
+                               TriangleNormal(v[0], v[1], v[2], normal);
+                               if (DotProduct(normal, projectdirection) < 0
+                                && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
+                                && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
+                                && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
+                                && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
+                                && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
+                                && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
+                                       shadowmarklist[numshadowmark++] = t;
+                       }
+               }
+               else
+               {
+                       for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+                       {
+                               v[0] = invertex3f + e[0] * 3;
+                               v[1] = invertex3f + e[1] * 3;
+                               v[2] = invertex3f + e[2] * 3;
+                               if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
+                                && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
+                                && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
+                                && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
+                                && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
+                                && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
+                                && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
+                                       shadowmarklist[numshadowmark++] = t;
+                       }
                }
        }
 }
@@ -708,18 +781,18 @@ void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *verte
                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;
+       r_refdef.stats.lights_shadowtriangles += numtriangles;
        CHECKGLERROR
        R_Mesh_VertexPointer(vertex3f);
        GL_LockArrays(0, numvertices);
        if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
        {
                // decrement stencil if backface is behind depthbuffer
-               qglCullFace(GL_BACK);CHECKGLERROR // quake is backwards, this culls front faces
+               GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
                qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
                R_Mesh_Draw(0, numvertices, numtriangles, element3i);
                // increment stencil if frontface is behind depthbuffer
-               qglCullFace(GL_FRONT);CHECKGLERROR // quake is backwards, this culls back faces
+               GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
                qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
        }
        R_Mesh_Draw(0, numvertices, numtriangles, element3i);
@@ -757,7 +830,7 @@ static void R_Shadow_MakeTextures(void)
                }
        }
        r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
-       if (r_shadow_texture3d.integer)
+       if (r_shadow_texture3d.integer && gl_texture3d)
        {
                for (z = 0;z < ATTEN3DSIZE;z++)
                {
@@ -788,6 +861,8 @@ void R_Shadow_ValidateCvars(void)
 {
        if (r_shadow_texture3d.integer && !gl_texture3d)
                Cvar_SetValueQuick(&r_shadow_texture3d, 0);
+       if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
+               Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
        if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
                Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
 }
@@ -820,16 +895,16 @@ void R_Shadow_RenderMode_Begin(void)
        R_Mesh_ColorPointer(NULL);
        R_Mesh_ResetTextureState();
        GL_BlendFunc(GL_ONE, GL_ZERO);
-       GL_DepthMask(false);
        GL_DepthTest(true);
+       GL_DepthMask(false);
        GL_Color(0, 0, 0, 1);
-       qglCullFace(GL_FRONT);CHECKGLERROR // quake is backwards, this culls back faces
-       qglEnable(GL_CULL_FACE);CHECKGLERROR
-       GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
+       GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
 
        r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
 
-       if (gl_ext_stenciltwoside.integer)
+       if (gl_ext_separatestencil.integer)
+               r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
+       else if (gl_ext_stenciltwoside.integer)
                r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
        else
                r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
@@ -860,26 +935,38 @@ void R_Shadow_RenderMode_Reset(void)
        }
        R_Mesh_ColorPointer(NULL);
        R_Mesh_ResetTextureState();
+       GL_DepthTest(true);
+       GL_DepthMask(false);
+       qglDepthFunc(GL_LEQUAL);CHECKGLERROR
+       qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
+       qglDisable(GL_STENCIL_TEST);CHECKGLERROR
+       qglStencilMask(~0);CHECKGLERROR
+       qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
+       qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
+       GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
+       GL_Color(1, 1, 1, 1);
+       GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
+       GL_BlendFunc(GL_ONE, GL_ZERO);
 }
 
 void R_Shadow_RenderMode_StencilShadowVolumes(void)
 {
        CHECKGLERROR
        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_shadowpolygonfactor, r_shadowpolygonoffset);CHECKGLERROR
+       qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
        qglDepthFunc(GL_LESS);CHECKGLERROR
-       qglCullFace(GL_FRONT);CHECKGLERROR // quake is backwards, this culls back faces
        qglEnable(GL_STENCIL_TEST);CHECKGLERROR
-       qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
        r_shadow_rendermode = r_shadow_shadowingrendermode;
-       if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
+       if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
+       {
+               GL_CullFace(GL_NONE);
+               qglStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR // quake is backwards, this is front faces
+               qglStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR // quake is backwards, this is back faces
+       }
+       else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
        {
-               qglDisable(GL_CULL_FACE);CHECKGLERROR
+               GL_CullFace(GL_NONE);
                qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
                qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
                qglStencilMask(~0);CHECKGLERROR
@@ -888,15 +975,8 @@ void R_Shadow_RenderMode_StencilShadowVolumes(void)
                qglStencilMask(~0);CHECKGLERROR
                qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
        }
-       else
-       {
-               qglEnable(GL_CULL_FACE);CHECKGLERROR
-               qglStencilMask(~0);CHECKGLERROR
-               // this is changed by every shadow render so its value here is unimportant
-               qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
-       }
        GL_Clear(GL_STENCIL_BUFFER_BIT);
-       renderstats.lights_clears++;
+       r_refdef.stats.lights_clears++;
 }
 
 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
@@ -904,35 +984,17 @@ void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
        CHECKGLERROR
        R_Shadow_RenderMode_Reset();
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
-       GL_DepthMask(false);
-       GL_DepthTest(true);
-       qglPolygonOffset(r_polygonfactor, r_polygonoffset);CHECKGLERROR
-       //qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
-       GL_Color(1, 1, 1, 1);
-       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
-       if (transparent)
-       {
-               qglDepthFunc(GL_LEQUAL);CHECKGLERROR
-       }
-       else
+       if (!transparent)
        {
                qglDepthFunc(GL_EQUAL);CHECKGLERROR
        }
-       qglCullFace(GL_FRONT);CHECKGLERROR // quake is backwards, this culls back faces
-       qglEnable(GL_CULL_FACE);CHECKGLERROR
        if (stenciltest)
        {
                qglEnable(GL_STENCIL_TEST);CHECKGLERROR
+               // 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);CHECKGLERROR
        }
-       else
-       {
-               qglDisable(GL_STENCIL_TEST);CHECKGLERROR
-       }
-       qglStencilMask(~0);CHECKGLERROR
-       qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
-       // 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);CHECKGLERROR
        r_shadow_rendermode = r_shadow_lightingrendermode;
        // do global setup needed for the chosen lighting mode
        if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
@@ -949,7 +1011,7 @@ void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
                R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
                //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);
+               GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
                CHECKGLERROR
        }
 }
@@ -959,15 +1021,10 @@ void R_Shadow_RenderMode_VisibleShadowVolumes(void)
        CHECKGLERROR
        R_Shadow_RenderMode_Reset();
        GL_BlendFunc(GL_ONE, GL_ONE);
-       GL_DepthMask(false);
-       GL_DepthTest(!r_showdisabledepthtest.integer);
-       qglPolygonOffset(r_polygonfactor, r_polygonoffset);CHECKGLERROR
-       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);CHECKGLERROR
-       qglCullFace(GL_FRONT);CHECKGLERROR // this culls back
-       qglDisable(GL_CULL_FACE);CHECKGLERROR
-       qglDisable(GL_STENCIL_TEST);CHECKGLERROR
+       GL_DepthTest(r_showshadowvolumes.integer < 2);
+       GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
+       qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
+       GL_CullFace(GL_NONE);
        r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
 }
 
@@ -976,28 +1033,16 @@ void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transpar
        CHECKGLERROR
        R_Shadow_RenderMode_Reset();
        GL_BlendFunc(GL_ONE, GL_ONE);
-       GL_DepthMask(false);
-       GL_DepthTest(!r_showdisabledepthtest.integer);
-       qglPolygonOffset(r_polygonfactor, r_polygonoffset);CHECKGLERROR
-       GL_Color(0.1, 0.0125, 0, 1);
-       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
-       if (transparent)
-       {
-               qglDepthFunc(GL_LEQUAL);CHECKGLERROR
-       }
-       else
+       GL_DepthTest(r_showlighting.integer < 2);
+       GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
+       if (!transparent)
        {
                qglDepthFunc(GL_EQUAL);CHECKGLERROR
        }
-       qglCullFace(GL_FRONT);CHECKGLERROR // this culls back
-       qglEnable(GL_CULL_FACE);CHECKGLERROR
        if (stenciltest)
        {
                qglEnable(GL_STENCIL_TEST);CHECKGLERROR
-       }
-       else
-       {
-               qglDisable(GL_STENCIL_TEST);CHECKGLERROR
+               qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
        }
        r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
 }
@@ -1007,25 +1052,8 @@ void R_Shadow_RenderMode_End(void)
        CHECKGLERROR
        R_Shadow_RenderMode_Reset();
        R_Shadow_RenderMode_ActiveLight(NULL);
-       GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(true);
-       GL_DepthTest(true);
-       qglPolygonOffset(r_polygonfactor, r_polygonoffset);CHECKGLERROR
-       //qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
-       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);CHECKGLERROR
-       qglCullFace(GL_FRONT);CHECKGLERROR // quake is backwards, this culls back faces
-       qglEnable(GL_CULL_FACE);CHECKGLERROR
-       qglDisable(GL_STENCIL_TEST);CHECKGLERROR
-       qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
-       if (gl_support_stenciltwoside)
-       {
-               qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
-       }
-       qglStencilMask(~0);CHECKGLERROR
-       qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
+       GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
        r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
 }
 
@@ -1039,18 +1067,18 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        float vertex3f[256*3];
 
        // if view is inside the light box, just say yes it's visible
-       if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
+       if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
        {
-               GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
+               GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
                return false;
        }
 
        // create a temporary brush describing the area the light can affect in worldspace
-       VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
-       VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
-       VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
-       VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
-       VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
+       VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
+       VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
+       VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
+       VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
+       VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
        VectorSet   (planes[ 5].normal,  1, 0, 0);         planes[ 5].dist =  maxs[0];
        VectorSet   (planes[ 6].normal, -1, 0, 0);         planes[ 6].dist = -mins[0];
        VectorSet   (planes[ 7].normal, 0,  1, 0);         planes[ 7].dist =  maxs[1];
@@ -1075,6 +1103,7 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        // if that mesh is not empty, check what area of the screen it covers
        x1 = y1 = x2 = y2 = 0;
        v[3] = 1.0f;
+       //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
        for (i = 0;i < mesh.numvertices;i++)
        {
                VectorCopy(mesh.vertex3f + i * 3, v);
@@ -1102,20 +1131,20 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
 
        // clamp it to the screen
-       if (ix1 < r_view_x) ix1 = r_view_x;
-       if (iy1 < r_view_y) iy1 = r_view_y;
-       if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
-       if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
+       if (ix1 < r_view.x) ix1 = r_view.x;
+       if (iy1 < r_view.y) iy1 = r_view.y;
+       if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
+       if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
 
        // if it is inside out, it's not visible
        if (ix2 <= ix1 || iy2 <= iy1)
                return true;
 
        // the light area is visible, set up the scissor rectangle
-       GL_Scissor(ix1, vid.height - iy2, ix2 - ix1, iy2 - iy1);
+       GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
        //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
        //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
-       renderstats.lights_scissored++;
+       r_refdef.stats.lights_scissored++;
        return false;
 }
 
@@ -1138,7 +1167,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_
                                color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
                                color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
                                color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
-                               if (fogenabled)
+                               if (r_refdef.fogenabled)
                                {
                                        float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
                                        VectorScale(color4f, f, color4f);
@@ -1171,7 +1200,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_
                                        color4f[1] = ambientcolor[1] * distintensity;
                                        color4f[2] = ambientcolor[2] * distintensity;
                                }
-                               if (fogenabled)
+                               if (r_refdef.fogenabled)
                                {
                                        float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
                                        VectorScale(color4f, f, color4f);
@@ -1205,7 +1234,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_
                                        color4f[1] = ambientcolor[1] * distintensity;
                                        color4f[2] = ambientcolor[2] * distintensity;
                                }
-                               if (fogenabled)
+                               if (r_refdef.fogenabled)
                                {
                                        float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
                                        VectorScale(color4f, f, color4f);
@@ -1275,7 +1304,7 @@ static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int numsurfaces, msurfa
 static void R_Shadow_RenderSurfacesLighting_VisibleLighting(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
-       GL_Color(0.1, 0.025, 0, 1);
+       GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
        R_Mesh_ColorPointer(NULL);
        R_Mesh_ResetTextureState();
        RSurf_PrepareVerticesForBatch(false, false, numsurfaces, surfacelist);
@@ -1308,7 +1337,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(int numsurfaces,
 {
        // shared final code for all the dot3 layers
        int renders;
-       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
+       GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
        for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
        {
                GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
@@ -1624,6 +1653,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(int numsurfac
 
 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
 {
+       float glossexponent;
        rmeshstate_t m;
        // FIXME: detect blendsquare!
        //if (!gl_support_blendsquare)
@@ -1652,12 +1682,8 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(int numsurfa
                R_Mesh_ResetTextureState();
                // 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)
-               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
-               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
+               for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
+                       RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
                // fourth pass
@@ -1704,12 +1730,8 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(int numsurfa
                R_Mesh_ResetTextureState();
                // 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)
-               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
-               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
+               for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
+                       RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
                // fourth pass
@@ -1743,12 +1765,8 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(int numsurfa
                R_Mesh_ResetTextureState();
                // 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)
-               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
-               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
+               for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
+                       RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
                // fourth pass
@@ -1793,25 +1811,25 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(int numsurfaces, msurface
        RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
        R_Mesh_ColorPointer(NULL);
        if (doambient)
-               R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale);
+               R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
        if (dodiffuse)
-               R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale);
+               R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
        if (dopants)
        {
                if (doambient)
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
                if (dodiffuse)
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
        }
        if (doshirt)
        {
                if (doambient)
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
                if (dodiffuse)
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
        }
        if (dospecular)
-               R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(numsurfaces, surfacelist, lightcolorbase, glosstexture, normalmaptexture, specularscale);
+               R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(numsurfaces, surfacelist, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
 }
 
 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const model_t *model, int numsurfaces, msurface_t **surfacelist, vec3_t diffusecolor2, vec3_t ambientcolor2)
@@ -1928,12 +1946,12 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex(int numsurfaces, msurfa
        float ambientcolorpants[3], diffusecolorpants[3];
        float ambientcolorshirt[3], diffusecolorshirt[3];
        rmeshstate_t m;
-       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);
+       VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorbase);
+       VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorbase);
+       VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorpants);
+       VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorpants);
+       VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
+       VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
        R_Mesh_ColorPointer(rsurface_array_color4f);
        memset(&m, 0, sizeof(m));
@@ -1980,18 +1998,12 @@ void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist)
        lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
        if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
                return;
-       if ((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE))
-       {
-               qglDisable(GL_CULL_FACE);CHECKGLERROR
-       }
-       else
-       {
-               qglEnable(GL_CULL_FACE);CHECKGLERROR
-       }
+       GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
+       GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
        if (rsurface_texture->colormapping)
        {
-               qboolean dopants = rsurface_texture->skin.pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
-               qboolean doshirt = rsurface_texture->skin.shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
+               qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
+               qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
                if (dopants)
                {
                        lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
@@ -2011,16 +2023,17 @@ void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist)
                switch (r_shadow_rendermode)
                {
                case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
-                       R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->skin.pants, rsurface_texture->skin.shirt, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
+                       GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
+                       R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_GLSL:
-                       R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->skin.pants, rsurface_texture->skin.shirt, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
+                       R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_DOT3:
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->skin.pants, rsurface_texture->skin.shirt, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
-                       R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->skin.pants, rsurface_texture->skin.shirt, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
+                       R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
                        break;
                default:
                        Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
@@ -2032,16 +2045,17 @@ void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist)
                switch (r_shadow_rendermode)
                {
                case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
-                       R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
+                       GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
+                       R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_GLSL:
-                       R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
+                       R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_DOT3:
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
-                       R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
+                       R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
                        break;
                default:
                        Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
@@ -2052,8 +2066,7 @@ void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist)
 
 void R_RTLight_Update(dlight_t *light, int isstatic)
 {
-       int j, k;
-       float scale;
+       double scale;
        rtlight_t *rtlight = &light->rtlight;
        R_RTLight_Uncompile(rtlight);
        memset(rtlight, 0, sizeof(*rtlight));
@@ -2071,7 +2084,7 @@ void R_RTLight_Update(dlight_t *light, int isstatic)
        rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
        rtlight->cubemapname[0] = 0;
        if (light->cubemapname[0])
-               strcpy(rtlight->cubemapname, light->cubemapname);
+               strlcpy(rtlight->cubemapname, light->cubemapname, sizeof(rtlight->cubemapname));
        else if (light->cubemapnum > 0)
                sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
        rtlight->shadow = light->shadow;
@@ -2084,12 +2097,11 @@ void R_RTLight_Update(dlight_t *light, int isstatic)
        rtlight->specularscale = light->specularscale;
        rtlight->flags = light->flags;
        Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
-       // ConcatScale won't work here because this needs to scale rotate and
-       // translate, not just rotate
-       scale = 1.0f / rtlight->radius;
-       for (k = 0;k < 3;k++)
-               for (j = 0;j < 4;j++)
-                       rtlight->matrix_worldtolight.m[k][j] *= scale;
+       // this has to scale both rotate and translate because this is an already
+       // inverted matrix (it transforms from world to light space, not the other
+       // way around)
+       scale = 1.0 / rtlight->radius;
+       Matrix4x4_Scale(&rtlight->matrix_worldtolight, scale, scale);
 }
 
 // compiles rtlight geometry
@@ -2137,7 +2149,7 @@ void R_RTLight_Compile(rtlight_t *rtlight)
                if (numsurfaces)
                        memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
                if (model->CompileShadowVolume && rtlight->shadow)
-                       model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
+                       model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
                // now we're done compiling the rtlight
                r_shadow_compilingrtlight = NULL;
        }
@@ -2204,17 +2216,17 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfa
                        CHECKGLERROR
                        for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
                        {
-                               renderstats.lights_shadowtriangles += mesh->numtriangles;
+                               r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
                                R_Mesh_VertexPointer(mesh->vertex3f);
                                GL_LockArrays(0, mesh->numverts);
                                if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
                                {
                                        // decrement stencil if backface is behind depthbuffer
-                                       qglCullFace(GL_BACK);CHECKGLERROR // quake is backwards, this culls front faces
+                                       GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
                                        qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
                                        R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
                                        // increment stencil if frontface is behind depthbuffer
-                                       qglCullFace(GL_FRONT);CHECKGLERROR // quake is backwards, this culls back faces
+                                       GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
                                        qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
                                }
                                R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
@@ -2225,7 +2237,7 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfa
                else if (numsurfaces)
                {
                        R_Mesh_Matrix(&ent->matrix);
-                       model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
+                       model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs);
                }
        }
        else
@@ -2239,7 +2251,7 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfa
                relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
                relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
                R_Mesh_Matrix(&ent->matrix);
-               model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
+               model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
        }
 }
 
@@ -2312,6 +2324,9 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
                return;
 
+       VectorCopy(rtlight->cullmins, r_shadow_rtlight_cullmins);
+       VectorCopy(rtlight->cullmaxs, r_shadow_rtlight_cullmaxs);
+
        if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
        {
                // compiled light, world available and can receive realtime lighting
@@ -2327,12 +2342,12 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                // dynamic light, world available and can receive realtime lighting
                // calculate lit surfaces and leafs
                R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
-               r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, 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);
+               r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
                leaflist = r_shadow_buffer_leaflist;
                leafpvs = r_shadow_buffer_leafpvs;
                surfacelist = r_shadow_buffer_surfacelist;
                // if the reduced leaf bounds are offscreen, skip it
-               if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
+               if (R_CullBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
                        return;
        }
        else
@@ -2348,13 +2363,13 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        if (numleafs)
        {
                for (i = 0;i < numleafs;i++)
-                       if (r_worldleafvisible[leaflist[i]])
+                       if (r_viewcache.world_leafvisible[leaflist[i]])
                                break;
                if (i == numleafs)
                        return;
        }
        // set up a scissor rectangle for this light
-       if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
+       if (R_Shadow_ScissorForBBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
                return;
 
        // make a list of lit entities and shadow casting entities
@@ -2373,15 +2388,17 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                {
                        model_t *model;
                        entity_render_t *ent = r_refdef.entities[i];
-                       if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
+                       if (BoxesOverlap(ent->mins, ent->maxs, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs)
                         && (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) && model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
+                               vec3_t org;
+                               Matrix4x4_OriginFromMatrix(&ent->matrix, org);
+                               if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
                                        shadowentities[numshadowentities++] = ent;
-                               if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && model->DrawLight)
+                               if (r_viewcache.entityvisible[i] && (ent->flags & RENDER_LIGHT) && model->DrawLight)
                                        lightentities[numlightentities++] = ent;
                        }
                }
@@ -2398,10 +2415,10 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        // make this the active rtlight for rendering purposes
        R_Shadow_RenderMode_ActiveLight(rtlight);
        // count this light in the r_speeds
-       renderstats.lights++;
+       r_refdef.stats.lights++;
 
        usestencil = false;
-       if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
+       if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
        {
                // draw stencil shadow volumes to mask off pixels that are in shadow
                // so that they won't receive lighting
@@ -2451,7 +2468,7 @@ void R_ShadowVolumeLighting(qboolean visible)
 
        R_Shadow_RenderMode_Begin();
 
-       flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
+       flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
        if (r_shadow_debuglight.integer >= 0)
        {
                for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
@@ -2462,13 +2479,101 @@ void R_ShadowVolumeLighting(qboolean visible)
                for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
                        if (light->flags & flag)
                                R_DrawRTLight(&light->rtlight, visible);
-       if (r_rtdlight)
+       if (r_refdef.rtdlight)
                for (lnum = 0;lnum < r_refdef.numlights;lnum++)
                        R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
 
        R_Shadow_RenderMode_End();
 }
 
+extern void R_SetupView(const matrix4x4_t *matrix);
+extern cvar_t r_shadows_throwdistance;
+void R_DrawModelShadows(void)
+{
+       int i;
+       float relativethrowdistance;
+       entity_render_t *ent;
+       vec3_t relativelightorigin;
+       vec3_t relativelightdirection;
+       vec3_t relativeshadowmins, relativeshadowmaxs;
+       float vertex3f[12];
+
+       if (!r_drawentities.integer || !gl_stencil)
+               return;
+
+       CHECKGLERROR
+       GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
+
+       r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
+
+       if (gl_ext_separatestencil.integer)
+               r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
+       else if (gl_ext_stenciltwoside.integer)
+               r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
+       else
+               r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
+
+       R_Shadow_RenderMode_StencilShadowVolumes();
+
+       for (i = 0;i < r_refdef.numentities;i++)
+       {
+               ent = r_refdef.entities[i];
+               // cast shadows from anything that is not a submodel of the map
+               if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
+               {
+                       relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
+                       VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
+                       VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
+                       VectorNegate(ent->modellight_lightdir, relativelightdirection);
+                       VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
+                       R_Mesh_Matrix(&ent->matrix);
+                       ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
+               }
+       }
+
+       // not really the right mode, but this will disable any silly stencil features
+       R_Shadow_RenderMode_VisibleLighting(true, true);
+
+       // vertex coordinates for a quad that covers the screen exactly
+       vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
+       vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
+       vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
+       vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
+
+       // set up ortho view for rendering this pass
+       GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
+       GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
+       GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
+       GL_ScissorTest(true);
+       R_Mesh_Matrix(&identitymatrix);
+       R_Mesh_ResetTextureState();
+       R_Mesh_VertexPointer(vertex3f);
+       R_Mesh_ColorPointer(NULL);
+
+       // set up a 50% darkening blend on shadowed areas
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       GL_DepthTest(false);
+       GL_DepthMask(false);
+       qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
+       GL_Color(0, 0, 0, 0.5);
+       GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
+       qglDepthFunc(GL_ALWAYS);CHECKGLERROR
+       qglEnable(GL_STENCIL_TEST);CHECKGLERROR
+       qglStencilMask(~0);CHECKGLERROR
+       qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
+       qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
+
+       // apply the blend to the shadowed areas
+       R_Mesh_Draw(0, 4, 2, polygonelements);
+
+       // restoring the perspective view is done by R_RenderScene
+       //R_SetupView(&r_view.matrix);
+
+       // restore other state to normal
+       R_Shadow_RenderMode_End();
+}
+
+
 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
 typedef struct suffixinfo_s
 {
@@ -2576,7 +2681,7 @@ rtexture_t *R_Shadow_Cubemap(const char *basename)
        if (i >= MAX_CUBEMAPS)
                return r_texture_whitecube;
        numcubemaps++;
-       strcpy(cubemaps[i].basename, basename);
+       strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
        cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
        if (!cubemaps[i].texture)
                cubemaps[i].texture = r_texture_whitecube;
@@ -2661,7 +2766,7 @@ void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const r
 {
        // this is never batched (there can be only one)
        float scale = r_editlights_cursorgrid.value * 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);
+       R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[1]->tex, NULL, false, r_editlights_cursorlocation, r_view.right, r_view.up, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
 }
 
 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
@@ -2675,7 +2780,7 @@ void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, co
                intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
        if (!light->shadow)
                intensity *= 0.5f;
-       R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacelist[0]]->tex, NULL, false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
+       R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacelist[0]]->tex, NULL, false, light->origin, r_view.right, r_view.up, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
 }
 
 void R_Shadow_DrawLightSprites(void)
@@ -2696,12 +2801,12 @@ void R_Shadow_SelectLightInView(void)
        bestrating = 0;
        for (light = r_shadow_worldlightchain;light;light = light->next)
        {
-               VectorSubtract(light->origin, r_vieworigin, temp);
-               rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
+               VectorSubtract(light->origin, r_view.origin, temp);
+               rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
                if (rating >= 0.95)
                {
                        rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
-                       if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
+                       if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_view.origin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
                        {
                                bestrating = rating;
                                best = light;
@@ -2781,8 +2886,10 @@ void R_Shadow_LoadWorldLights(void)
                        // remove quotes on cubemapname
                        if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
                        {
-                               cubemapname[strlen(cubemapname)-1] = 0;
-                               strcpy(cubemapname, cubemapname + 1);
+                               size_t namelen;
+                               namelen = strlen(cubemapname) - 2;
+                               memmove(cubemapname, cubemapname + 1, namelen);
+                               cubemapname[namelen] = '\0';
                        }
                        if (a < 8)
                        {
@@ -2926,7 +3033,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                data = r_refdef.worldmodel->brush.entities;
        if (!data)
                return;
-       for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
+       for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
        {
                type = LIGHTTYPE_MINUSX;
                origin[0] = origin[1] = origin[2] = 0;
@@ -2944,19 +3051,19 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                islight = false;
                while (1)
                {
-                       if (!COM_ParseToken(&data, false))
+                       if (!COM_ParseTokenConsole(&data))
                                break; // error
                        if (com_token[0] == '}')
                                break; // end of entity
                        if (com_token[0] == '_')
-                               strcpy(key, com_token + 1);
+                               strlcpy(key, com_token + 1, sizeof(key));
                        else
-                               strcpy(key, com_token);
+                               strlcpy(key, com_token, sizeof(key));
                        while (key[strlen(key)-1] == ' ') // remove trailing spaces
                                key[strlen(key)-1] = 0;
-                       if (!COM_ParseToken(&data, false))
+                       if (!COM_ParseTokenConsole(&data))
                                break; // error
-                       strcpy(value, com_token);
+                       strlcpy(value, com_token, sizeof(value));
 
                        // now that we have the key pair worked out...
                        if (!strcmp("light", key))
@@ -3127,8 +3234,8 @@ void R_Shadow_SetCursorLocationForView(void)
        vec_t dist, push;
        vec3_t dest, endpos;
        trace_t trace;
-       VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
-       trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
+       VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
+       trace = CL_TraceBox(r_view.origin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
        if (trace.fraction < 1)
        {
                dist = trace.fraction * r_editlights_cursordistance.value;
@@ -3136,7 +3243,7 @@ void R_Shadow_SetCursorLocationForView(void)
                if (push > dist)
                        push = dist;
                push = -push;
-               VectorMA(trace.endpos, push, r_viewforward, endpos);
+               VectorMA(trace.endpos, push, r_view.forward, endpos);
                VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
        }
        else
@@ -3431,7 +3538,7 @@ void R_Shadow_EditLights_Edit_f(void)
                        return;
                }
                if (Cmd_Argc() == 3)
-                       strcpy(cubemapname, Cmd_Argv(2));
+                       strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
                else
                        cubemapname[0] = 0;
        }
@@ -3701,7 +3808,7 @@ void R_Shadow_EditLights_CopyInfo_f(void)
        r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
        r_shadow_bufferlight.style = r_shadow_selectedlight->style;
        if (r_shadow_selectedlight->cubemapname)
-               strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
+               strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
        else
                r_shadow_bufferlight.cubemapname[0] = 0;
        r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;