]> de.git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
cleaned up portions of rtlighting system, allowing GLSL lighting to use very few...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 3 May 2005 18:33:21 +0000 (18:33 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 3 May 2005 18:33:21 +0000 (18:33 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5218 d7cf8633-e32d-0410-b094-e92efae38249

client.h
gl_models.c
gl_rmain.c
gl_rsurf.c
model_alias.c
model_brush.c
model_shared.h
r_shadow.c
r_shadow.h

index 425f4a83d84fd9fcff04105dd84ba3d8e6a73b38..cbdd0d1db721ae1c13c709501d28e8cfe01e70fb 100644 (file)
--- a/client.h
+++ b/client.h
@@ -83,11 +83,6 @@ typedef struct rtlight_s
        // core properties
        // matrix for transforming world coordinates to light filter coordinates
        matrix4x4_t matrix_worldtolight;
        // core properties
        // matrix for transforming world coordinates to light filter coordinates
        matrix4x4_t matrix_worldtolight;
-       // based on worldtolight this transforms -1 to +1 to 0 to 1 for purposes
-       // of attenuation texturing in full 3D (Z result often ignored)
-       matrix4x4_t matrix_worldtoattenuationxyz;
-       // this transforms only the Z to S, and T is always 0.5
-       matrix4x4_t matrix_worldtoattenuationz;
        // typically 1 1 1, can be lower (dim) or higher (overbright)
        vec3_t color;
        // size of the light (remove?)
        // typically 1 1 1, can be lower (dim) or higher (overbright)
        vec3_t color;
        // size of the light (remove?)
index c727b5f988c8c222dfcd4b2c1842fbd4a7a23fc1..886cb85985865d37a558e11c3a790a7c4c73e1ca 100644 (file)
@@ -283,7 +283,6 @@ void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightor
        projectdistance = lightradius + ent->model->radius;// - sqrt(DotProduct(relativelightorigin, relativelightorigin));
        if (projectdistance > 0.1)
        {
        projectdistance = lightradius + ent->model->radius;// - sqrt(DotProduct(relativelightorigin, relativelightorigin));
        if (projectdistance > 0.1)
        {
-               R_Mesh_Matrix(&ent->matrix);
                for (meshnum = 0, mesh = ent->model->alias.aliasdata_meshes;meshnum < ent->model->alias.aliasnum_meshes;meshnum++, mesh++)
                {
                        texture = R_FetchAliasSkin(ent, mesh);
                for (meshnum = 0, mesh = ent->model->alias.aliasdata_meshes;meshnum < ent->model->alias.aliasnum_meshes;meshnum++, mesh++)
                {
                        texture = R_FetchAliasSkin(ent, mesh);
@@ -304,7 +303,7 @@ void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightor
        }
 }
 
        }
 }
 
-void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int numsurfaces, const int *surfacelist, int visiblelighting)
+void R_Model_Alias_DrawLight(entity_render_t *ent, float *lightcolor, int numsurfaces, const int *surfacelist)
 {
        int c, meshnum;
        float fog, ifog, lightcolorbase[3], lightcolorpants[3], lightcolorshirt[3];
 {
        int c, meshnum;
        float fog, ifog, lightcolorbase[3], lightcolorpants[3], lightcolorshirt[3];
@@ -314,8 +313,6 @@ void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v
        aliasmesh_t *mesh;
        texture_t *texture;
 
        aliasmesh_t *mesh;
        texture_t *texture;
 
-       R_Mesh_Matrix(&ent->matrix);
-
        fog = 0;
        if (fogenabled)
        {
        fog = 0;
        if (fogenabled)
        {
@@ -386,7 +383,7 @@ void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v
                        Mod_BuildTextureVectorsAndNormals(0, mesh->num_vertices, mesh->num_triangles, vertex3f, mesh->data_texcoord2f, mesh->data_element3i, svector3f, tvector3f, normal3f);
                }
                c_alias_polys += mesh->num_triangles;
                        Mod_BuildTextureVectorsAndNormals(0, mesh->num_vertices, mesh->num_triangles, vertex3f, mesh->data_texcoord2f, mesh->data_element3i, svector3f, tvector3f, normal3f);
                }
                c_alias_polys += mesh->num_triangles;
-               R_Shadow_RenderLighting(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, vertex3f, svector3f, tvector3f, normal3f, mesh->data_texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorbase, lightcolorpants, lightcolorshirt, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, (ent->colormap >= 0 || !texture->skin.merged) ? texture->skin.base : texture->skin.merged, ent->colormap >= 0 ? texture->skin.pants : 0, ent->colormap >= 0 ? texture->skin.shirt : 0, texture->skin.nmap, texture->skin.gloss, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
+               R_Shadow_RenderLighting(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, vertex3f, svector3f, tvector3f, normal3f, mesh->data_texcoord2f, lightcolorbase, lightcolorpants, lightcolorshirt, (ent->colormap >= 0 || !texture->skin.merged) ? texture->skin.base : texture->skin.merged, ent->colormap >= 0 ? texture->skin.pants : 0, ent->colormap >= 0 ? texture->skin.shirt : 0, texture->skin.nmap, texture->skin.gloss);
        }
 }
 
        }
 }
 
index f46df91638a6d3f15d0e8b6227ee548e2e7d6b1d..4042819641c1d090b85f198a6ee4d531265886f4 100644 (file)
@@ -1002,7 +1002,7 @@ void R_RenderScene(void)
                S_ExtraUpdate ();
 
        GL_ShowTrisColor(0, 0, 0.033, 1);
                S_ExtraUpdate ();
 
        GL_ShowTrisColor(0, 0, 0.033, 1);
-       R_ShadowVolumeLighting(false, false);
+       R_ShadowVolumeLighting(false);
        R_TimeReport("rtlights");
 
        // don't let sound skip if going slow
        R_TimeReport("rtlights");
 
        // don't let sound skip if going slow
@@ -1034,8 +1034,8 @@ void R_RenderScene(void)
 
        if ((r_shadow_visiblelighting.integer || r_shadow_visiblevolumes.integer) && !r_showtrispass)
        {
 
        if ((r_shadow_visiblelighting.integer || r_shadow_visiblevolumes.integer) && !r_showtrispass)
        {
-               R_ShadowVolumeLighting(r_shadow_visiblelighting.integer, r_shadow_visiblevolumes.integer);
-               R_TimeReport("shadowvolume");
+               R_ShadowVolumeLighting(true);
+               R_TimeReport("visiblevolume");
        }
 
        GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
        }
 
        GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
index 13b197a4ca1f790cbecc2478917ec5f506a5a4ba..69d5d8c2c7014a5dc29af78dd4266b36ec3b02c7 100644 (file)
@@ -1856,7 +1856,6 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin,
        int surfacelistindex;
        if (r_drawcollisionbrushes.integer < 2)
        {
        int surfacelistindex;
        if (r_drawcollisionbrushes.integer < 2)
        {
-               R_Mesh_Matrix(&ent->matrix);
                R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles);
                if (!r_shadow_compilingrtlight)
                        R_UpdateAllTextureInfo(ent);
                R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles);
                if (!r_shadow_compilingrtlight)
                        R_UpdateAllTextureInfo(ent);
@@ -1873,7 +1872,7 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin,
        }
 }
 
        }
 }
 
-void R_Q1BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int numsurfaces, const int *surfacelist, int visiblelighting)
+void R_Q1BSP_DrawLight(entity_render_t *ent, float *lightcolor, int numsurfaces, const int *surfacelist)
 {
        model_t *model = ent->model;
        msurface_t *surface;
 {
        model_t *model = ent->model;
        msurface_t *surface;
@@ -1908,7 +1907,7 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t
                                                v[0] = vertex3f + e[0] * 3;
                                                v[1] = vertex3f + e[1] * 3;
                                                v[2] = vertex3f + e[2] * 3;
                                                v[0] = vertex3f + e[0] * 3;
                                                v[1] = vertex3f + e[1] * 3;
                                                v[2] = vertex3f + e[2] * 3;
-                                               if (PointInfrontOfTriangle(relativelightorigin, 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])))
+                                               if (PointInfrontOfTriangle(r_shadow_compilingrtlight->shadoworigin, 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])))
                                                        Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_light, surface->texture->skin.base, surface->texture->skin.gloss, surface->texture->skin.nmap, surface->groupmesh->data_vertex3f, surface->groupmesh->data_svector3f, surface->groupmesh->data_tvector3f, surface->groupmesh->data_normal3f, surface->groupmesh->data_texcoordtexture2f, 1, e);
                                        }
 #else
                                                        Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_light, surface->texture->skin.base, surface->texture->skin.gloss, surface->texture->skin.nmap, surface->groupmesh->data_vertex3f, surface->groupmesh->data_svector3f, surface->groupmesh->data_tvector3f, surface->groupmesh->data_normal3f, surface->groupmesh->data_texcoordtexture2f, 1, e);
                                        }
 #else
@@ -1924,7 +1923,7 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t
                                {
                                        if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
                                                qglDisable(GL_CULL_FACE);
                                {
                                        if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
                                                qglDisable(GL_CULL_FACE);
-                                       R_Shadow_RenderLighting(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle), surface->groupmesh->data_vertex3f, surface->groupmesh->data_svector3f, surface->groupmesh->data_tvector3f, surface->groupmesh->data_normal3f, surface->groupmesh->data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightcolor, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, NULL, NULL, t->skin.nmap, t->skin.gloss, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
+                                       R_Shadow_RenderLighting(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle), surface->groupmesh->data_vertex3f, surface->groupmesh->data_svector3f, surface->groupmesh->data_tvector3f, surface->groupmesh->data_normal3f, surface->groupmesh->data_texcoordtexture2f, lightcolor, vec3_origin, vec3_origin, t->skin.base, NULL, NULL, t->skin.nmap, t->skin.gloss);
                                        if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
                                                qglEnable(GL_CULL_FACE);
                                }
                                        if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
                                                qglEnable(GL_CULL_FACE);
                                }
index 1549bc3d2baf50f3f5599e5a7ad0f4d942741f12..c0c785622c23eff821ee584a5b6d2e815777b59b 100644 (file)
@@ -414,7 +414,7 @@ static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfi
 #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)\n", loadmodel->name, VALUE, MIN, MAX);
 extern void R_Model_Alias_Draw(entity_render_t *ent);
 extern void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs);
 #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)\n", loadmodel->name, VALUE, MIN, MAX);
 extern void R_Model_Alias_Draw(entity_render_t *ent);
 extern void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs);
-extern void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int numsurfaces, const int *surfacelist, int visiblelighting);
+extern void R_Model_Alias_DrawLight(entity_render_t *ent, float *lightcolor, int numsurfaces, const int *surfacelist);
 void Mod_IDP0_Load(model_t *mod, void *buffer)
 {
        int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
 void Mod_IDP0_Load(model_t *mod, void *buffer)
 {
        int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
index 5166a99f56867ac57c044d90a0f9180be258d743..89bae0de70d1eb19ea9c933a6d54f5f094539983 100644 (file)
@@ -2922,7 +2922,7 @@ extern void R_Q1BSP_DrawSky(entity_render_t *ent);
 extern void R_Q1BSP_Draw(entity_render_t *ent);
 extern void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, qbyte *outleafpvs, int *outnumleafspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer);
 extern void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs);
 extern void R_Q1BSP_Draw(entity_render_t *ent);
 extern void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, qbyte *outleafpvs, int *outnumleafspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer);
 extern void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs);
-extern void R_Q1BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int numsurfaces, const int *surfacelist, int visiblelighting);
+extern void R_Q1BSP_DrawLight(entity_render_t *ent, float *lightcolor, int numsurfaces, const int *surfacelist);
 void Mod_Q1BSP_Load(model_t *mod, void *buffer)
 {
        int i, j, k;
 void Mod_Q1BSP_Load(model_t *mod, void *buffer)
 {
        int i, j, k;
index c9aed8759276575f529889f215d0e2b421705959..a89536290c022eeccabf7609405d812ed2387153 100644 (file)
@@ -406,7 +406,7 @@ typedef struct model_s
        // draw a shadow volume for the model based on light source
        void(*DrawShadowVolume)(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs);
        // draw the lighting on a model (through stencil)
        // draw a shadow volume for the model based on light source
        void(*DrawShadowVolume)(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs);
        // draw the lighting on a model (through stencil)
-       void(*DrawLight)(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int numsurfaces, const int *surfacelist, int visiblelighting);
+       void(*DrawLight)(struct entity_render_s *ent, float *lightcolor, int numsurfaces, const int *surfacelist);
        // trace a box against this model
        void (*TraceBox)(struct model_s *model, int frame, struct trace_s *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs, int hitsupercontentsmask);
        // fields belonging to each type of model
        // trace a box against this model
        void (*TraceBox)(struct model_s *model, int frame, struct trace_s *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs, int hitsupercontentsmask);
        // fields belonging to each type of model
index 8c6972d1da1038dd6fdddae05004978d08e4fe5c..2779a310075d149acf878ba885af6cf4e8c72259 100644 (file)
@@ -29,7 +29,7 @@ shadows do not lie.
 
 Terminology: Stencil Light Volume (sometimes called Light Volumes)
 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
 
 Terminology: Stencil Light Volume (sometimes called Light Volumes)
 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
-areas in shadow it contanis the areas in light, this can only be built
+areas in shadow it contains the areas in light, this can only be built
 quickly for certain limited cases (such as portal visibility from a point),
 but is quite useful for some effects (sunlight coming from sky polygons is
 one possible example, translucent occluders is another example).
 quickly for certain limited cases (such as portal visibility from a point),
 but is quite useful for some effects (sunlight coming from sky polygons is
 one possible example, translucent occluders is another example).
@@ -119,12 +119,20 @@ the (currently upcoming) game Doom3.
 
 extern void R_Shadow_EditLights_Init(void);
 
 
 extern void R_Shadow_EditLights_Init(void);
 
-#define SHADOWSTAGE_NONE 0
-#define SHADOWSTAGE_STENCIL 1
-#define SHADOWSTAGE_LIGHT 2
-#define SHADOWSTAGE_STENCILTWOSIDE 3
+typedef enum r_shadowstage_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_shadowstage_t;
 
 
-int r_shadowstage = SHADOWSTAGE_NONE;
+r_shadowstage_t r_shadowstage = R_SHADOWSTAGE_NONE;
 
 mempool_t *r_shadow_mempool;
 
 
 mempool_t *r_shadow_mempool;
 
@@ -162,7 +170,6 @@ 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_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
-cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
 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_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"};
@@ -191,8 +198,8 @@ 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", "1"};
 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", "1"};
-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_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 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 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"};
@@ -583,7 +590,6 @@ void R_Shadow_Init(void)
 {
        Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
        Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
 {
        Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
        Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
-       Cvar_RegisterVariable(&r_shadow_cull);
        Cvar_RegisterVariable(&r_shadow_debuglight);
        Cvar_RegisterVariable(&r_shadow_gloss);
        Cvar_RegisterVariable(&r_shadow_gloss2intensity);
        Cvar_RegisterVariable(&r_shadow_debuglight);
        Cvar_RegisterVariable(&r_shadow_gloss);
        Cvar_RegisterVariable(&r_shadow_gloss2intensity);
@@ -915,7 +921,7 @@ void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *verte
        m.pointer_vertex = vertex3f;
        R_Mesh_State(&m);
        GL_LockArrays(0, numvertices);
        m.pointer_vertex = vertex3f;
        R_Mesh_State(&m);
        GL_LockArrays(0, numvertices);
-       if (r_shadowstage == SHADOWSTAGE_STENCIL)
+       if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
        {
                // increment stencil if backface is behind depthbuffer
                qglCullFace(GL_BACK); // quake is backwards, this culls front faces
        {
                // increment stencil if backface is behind depthbuffer
                qglCullFace(GL_BACK); // quake is backwards, this culls front faces
@@ -998,6 +1004,29 @@ void R_Shadow_ValidateCvars(void)
                Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
 }
 
                Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
 }
 
+// light currently being rendered
+static 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;
+// this is the location of the light in entity space
+static 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;
+// 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;
+// 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;
+
+static int r_shadow_lightpermutation;
+static int r_shadow_lightprog;
+
 void R_Shadow_Stage_Begin(void)
 {
        rmeshstate_t m;
 void R_Shadow_Stage_Begin(void)
 {
        rmeshstate_t m;
@@ -1019,14 +1048,34 @@ void R_Shadow_Stage_Begin(void)
        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);
        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 = SHADOWSTAGE_NONE;
+       r_shadowstage = R_SHADOWSTAGE_NONE;
+}
+
+void R_Shadow_Stage_ActiveLight(rtlight_t *rtlight)
+{
+       r_shadow_rtlight = rtlight;
 }
 
 }
 
-void R_Shadow_Stage_ShadowVolumes(void)
+void R_Shadow_Stage_Reset(void)
 {
        rmeshstate_t m;
 {
        rmeshstate_t m;
+       if (gl_support_stenciltwoside)
+               qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
+       if (r_shadowstage == R_SHADOWSTAGE_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
+               qglBegin(GL_TRIANGLES);
+               qglEnd();
+               CHECKGLERROR
+       }
        memset(&m, 0, sizeof(m));
        R_Mesh_State(&m);
        memset(&m, 0, sizeof(m));
        R_Mesh_State(&m);
+}
+
+void R_Shadow_Stage_StencilShadowVolumes(void)
+{
+       R_Shadow_Stage_Reset();
        GL_Color(1, 1, 1, 1);
        GL_ColorMask(0, 0, 0, 0);
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_Color(1, 1, 1, 1);
        GL_ColorMask(0, 0, 0, 0);
        GL_BlendFunc(GL_ONE, GL_ZERO);
@@ -1040,37 +1089,38 @@ void R_Shadow_Stage_ShadowVolumes(void)
        //}
        //else
        //      qglDisable(GL_POLYGON_OFFSET_FILL);
        //}
        //else
        //      qglDisable(GL_POLYGON_OFFSET_FILL);
-       qglDepthFunc(GL_LESS);
+       qglDepthFunc(GL_GEQUAL);
        qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
        qglEnable(GL_STENCIL_TEST);
        qglStencilFunc(GL_ALWAYS, 128, ~0);
        if (gl_ext_stenciltwoside.integer)
        {
        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_shadowstage = SHADOWSTAGE_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
                qglStencilMask(~0);
                qglDisable(GL_CULL_FACE);
                qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
                qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
                qglStencilMask(~0);
-               qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
+               qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
                qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
                qglStencilMask(~0);
                qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
                qglStencilMask(~0);
-               qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
+               qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
        }
        else
        {
        }
        else
        {
-               r_shadowstage = SHADOWSTAGE_STENCIL;
+               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);
        }
                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++;
 }
 
 }
 
-void R_Shadow_Stage_Light(int shadowtest)
+void R_Shadow_Stage_Lighting(int stenciltest)
 {
        rmeshstate_t m;
 {
        rmeshstate_t m;
-       memset(&m, 0, sizeof(m));
-       R_Mesh_State(&m);
+       R_Shadow_Stage_Reset();
        GL_BlendFunc(GL_ONE, GL_ONE);
        GL_DepthMask(false);
        GL_DepthTest(true);
        GL_BlendFunc(GL_ONE, GL_ONE);
        GL_DepthMask(false);
        GL_DepthTest(true);
@@ -1081,25 +1131,118 @@ void R_Shadow_Stage_Light(int shadowtest)
        qglDepthFunc(GL_EQUAL);
        qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
        qglEnable(GL_CULL_FACE);
        qglDepthFunc(GL_EQUAL);
        qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
        qglEnable(GL_CULL_FACE);
-       if (shadowtest)
+       if (r_shadowstage == R_SHADOWSTAGE_STENCIL || r_shadowstage == R_SHADOWSTAGE_STENCILTWOSIDE)
                qglEnable(GL_STENCIL_TEST);
        else
                qglDisable(GL_STENCIL_TEST);
                qglEnable(GL_STENCIL_TEST);
        else
                qglDisable(GL_STENCIL_TEST);
-       if (gl_support_stenciltwoside)
-               qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
        qglStencilMask(~0);
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        // 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);
        qglStencilMask(~0);
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        // 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);
-       r_shadowstage = SHADOWSTAGE_LIGHT;
+       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);
+               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_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;
+               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 && gl_combine.integer && gl_stencil)
+               r_shadowstage = R_SHADOWSTAGE_LIGHT_DOT3;
+       else
+               r_shadowstage = R_SHADOWSTAGE_LIGHT_VERTEX;
+}
+
+void R_Shadow_Stage_VisibleShadowVolumes(void)
+{
+       R_Shadow_Stage_Reset();
+       GL_BlendFunc(GL_ONE, GL_ONE);
+       GL_DepthMask(false);
+       GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
+       qglPolygonOffset(0, 0);
+       GL_Color(0.0, 0.0125, 0.1, 1);
+       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
+       qglDepthFunc(GL_GEQUAL);
+       qglCullFace(GL_FRONT); // this culls back
+       qglDisable(GL_CULL_FACE);
+       qglDisable(GL_STENCIL_TEST);
+       r_shadowstage = R_SHADOWSTAGE_VISIBLEVOLUMES;
+}
+
+void R_Shadow_Stage_VisibleLighting(int stenciltest)
+{
+       R_Shadow_Stage_Reset();
+       GL_BlendFunc(GL_ONE, GL_ONE);
+       GL_DepthMask(false);
+       GL_DepthTest(r_shadow_visiblelighting.integer < 2);
+       qglPolygonOffset(0, 0);
+       GL_Color(0.1, 0.0125, 0, 1);
+       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
+       qglDepthFunc(GL_EQUAL);
+       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;
 }
 
 void R_Shadow_Stage_End(void)
 {
 }
 
 void R_Shadow_Stage_End(void)
 {
-       rmeshstate_t m;
-       memset(&m, 0, sizeof(m));
-       R_Mesh_State(&m);
+       R_Shadow_Stage_Reset();
+       R_Shadow_Stage_ActiveLight(NULL);
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(true);
        GL_DepthTest(true);
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(true);
        GL_DepthTest(true);
@@ -1116,7 +1259,7 @@ void R_Shadow_Stage_End(void)
                qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
        qglStencilMask(~0);
        qglStencilFunc(GL_ALWAYS, 128, ~0);
                qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
        qglStencilMask(~0);
        qglStencilFunc(GL_ALWAYS, 128, ~0);
-       r_shadowstage = SHADOWSTAGE_NONE;
+       r_shadowstage = R_SHADOWSTAGE_NONE;
 }
 
 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
 }
 
 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
@@ -1290,16 +1433,16 @@ int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        return false;
 }
 
        return false;
 }
 
-static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
+static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
 {
        float *color4f = varray_color4f;
        float dist, dot, intensity, v[3], n[3];
        for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
        {
 {
        float *color4f = varray_color4f;
        float dist, dot, intensity, v[3], n[3];
        for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
        {
-               Matrix4x4_Transform(m, vertex3f, v);
+               Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
                if ((dist = DotProduct(v, v)) < 1)
                {
                if ((dist = DotProduct(v, v)) < 1)
                {
-                       Matrix4x4_Transform3x3(m, normal3f, n);
+                       Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
                        if ((dot = DotProduct(n, v)) > 0)
                        {
                                dist = sqrt(dist);
                        if ((dot = DotProduct(n, v)) > 0)
                        {
                                dist = sqrt(dist);
@@ -1322,16 +1465,16 @@ static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *
        }
 }
 
        }
 }
 
-static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
+static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
 {
        float *color4f = varray_color4f;
        float dist, dot, intensity, v[3], n[3];
        for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
        {
 {
        float *color4f = varray_color4f;
        float dist, dot, intensity, v[3], n[3];
        for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
        {
-               Matrix4x4_Transform(m, vertex3f, v);
+               Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
                if ((dist = fabs(v[2])) < 1)
                {
                if ((dist = fabs(v[2])) < 1)
                {
-                       Matrix4x4_Transform3x3(m, normal3f, n);
+                       Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
                        if ((dot = DotProduct(n, v)) > 0)
                        {
                                intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
                        if ((dot = DotProduct(n, v)) > 0)
                        {
                                intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
@@ -1353,14 +1496,14 @@ static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *ve
        }
 }
 
        }
 }
 
-static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
+static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor)
 {
        float *color4f = varray_color4f;
        float dot, intensity, v[3], n[3];
        for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
        {
 {
        float *color4f = varray_color4f;
        float dot, intensity, v[3], n[3];
        for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
        {
-               Matrix4x4_Transform(m, vertex3f, v);
-               Matrix4x4_Transform3x3(m, normal3f, n);
+               Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
+               Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
                if ((dot = DotProduct(n, v)) > 0)
                {
                        intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
                if ((dot = DotProduct(n, v)) > 0)
                {
                        intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
@@ -1375,13 +1518,13 @@ static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const fl
        }
 }
 
        }
 }
 
-static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
+static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
 {
        float *color4f = varray_color4f;
        float dist, intensity, v[3];
        for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
        {
 {
        float *color4f = varray_color4f;
        float dist, intensity, v[3];
        for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
        {
-               Matrix4x4_Transform(m, vertex3f, v);
+               Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
                if ((dist = DotProduct(v, v)) < 1)
                {
                        dist = sqrt(dist);
                if ((dist = DotProduct(v, v)) < 1)
                {
                        dist = sqrt(dist);
@@ -1397,13 +1540,13 @@ static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float
        }
 }
 
        }
 }
 
-static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
+static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor)
 {
        float *color4f = varray_color4f;
        float dist, intensity, v[3];
        for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
        {
 {
        float *color4f = varray_color4f;
        float dist, intensity, v[3];
        for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
        {
-               Matrix4x4_Transform(m, vertex3f, v);
+               Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
                if ((dist = fabs(v[2])) < 1)
                {
                        intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
                if ((dist = fabs(v[2])) < 1)
                {
                        intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
@@ -1482,36 +1625,35 @@ static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out3f, int numve
        }
 }
 
        }
 }
 
-void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *relativelightorigin, const float *relativeeyeorigin, const float *lightcolorbase, const float *lightcolorpants, const float *lightcolorshirt, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int visiblelighting)
+void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *lightcolorbase, const float *lightcolorpants, const float *lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *bumptexture, rtexture_t *glosstexture)
 {
        int renders;
 {
        int renders;
-       float color[3], color2[3], colorscale;
+       float color[3], color2[3], colorscale, specularscale;
        rmeshstate_t m;
        rmeshstate_t m;
-       if (glosstexture && r_shadow_gloss.integer >= 1 && r_shadow_glossintensity.value > 0 && specularscale > 0)
-               specularscale = specularscale * r_shadow_glossintensity.value;
-       else if (!glosstexture && r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && specularscale > 0)
+       // FIXME: support EF_NODEPTHTEST
+       if (!basetexture)
+               basetexture = r_texture_white;
+       if (!bumptexture)
+               bumptexture = r_texture_blanknormalmap;
+       if (!pantstexture)
+               lightcolorpants = vec3_origin;
+       if (!shirttexture)
+               lightcolorshirt = vec3_origin;
+       if (glosstexture && r_shadow_gloss.integer >= 1 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
+               specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
+       else if (!glosstexture && r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
        {
                glosstexture = r_texture_white;
        {
                glosstexture = r_texture_white;
-               specularscale = specularscale * r_shadow_gloss2intensity.value;
+               specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
        }
        else
        {
                glosstexture = r_texture_black;
                specularscale = 0;
        }
        }
        else
        {
                glosstexture = r_texture_black;
                specularscale = 0;
        }
-       if (!basetexture)
-               basetexture = r_texture_white;
-       if (!bumptexture)
-               bumptexture = r_texture_blanknormalmap;
-       if (!lightcolorbase)
-               lightcolorbase = vec3_origin;
-       if (!lightcolorpants)
-               lightcolorpants = vec3_origin;
-       if (!lightcolorshirt)
-               lightcolorshirt = vec3_origin;
-       if ((ambientscale + diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
+       if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) <= 0.001)
                return;
                return;
-       if (visiblelighting)
+       if (r_shadowstage == R_SHADOWSTAGE_VISIBLELIGHTING)
        {
                int passes = 0;
                if (r_shadow_glsl.integer && r_shadow_program_light[0])
        {
                int passes = 0;
                if (r_shadow_glsl.integer && r_shadow_program_light[0])
@@ -1519,27 +1661,23 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
                {
                        // TODO: add direct pants/shirt rendering
                else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
                {
                        // TODO: add direct pants/shirt rendering
-                       if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
-                               R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
-                       if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
-                               R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
-                       if (!bumptexture)
-                               bumptexture = r_texture_blanknormalmap;
-                       if (!glosstexture)
-                               glosstexture = r_texture_white;
-                       if (ambientscale)
+                       if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
+                               R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
+                       if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
+                               R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
+                       if (r_shadow_rtlight->ambientscale)
                        {
                        {
-                               colorscale = ambientscale;
-                               if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
+                               colorscale = r_shadow_rtlight->ambientscale;
+                               if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
                                {
                                }
                                {
                                }
-                               else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
+                               else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
                                {
                                }
                                {
                                }
-                               else if (r_textureunits.integer >= 4 && lightcubemap)
+                               else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
                                {
                                }
                                {
                                }
-                               else if (r_textureunits.integer >= 3 && !lightcubemap)
+                               else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
                                {
                                }
                                else
                                {
                                }
                                else
@@ -1548,20 +1686,20 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
                                        passes++;
                        }
                                for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
                                        passes++;
                        }
-                       if (diffusescale)
+                       if (r_shadow_rtlight->diffusescale)
                        {
                        {
-                               colorscale = diffusescale;
+                               colorscale = r_shadow_rtlight->diffusescale;
                                if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
                                {
                                        // 3/2 3D combine path (Geforce3, Radeon 8500)
                                        passes++;
                                }
                                if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
                                {
                                        // 3/2 3D combine path (Geforce3, Radeon 8500)
                                        passes++;
                                }
-                               else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
+                               else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
                                {
                                        // 1/2/2 3D combine path (original Radeon)
                                        passes += 2;
                                }
                                {
                                        // 1/2/2 3D combine path (original Radeon)
                                        passes += 2;
                                }
-                               else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
+                               else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
                                {
                                        // 2/2 3D combine path (original Radeon)
                                        passes++;
                                {
                                        // 2/2 3D combine path (original Radeon)
                                        passes++;
@@ -1585,9 +1723,9 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                //if (gl_support_blendsquare)
                                {
                                        colorscale = specularscale;
                                //if (gl_support_blendsquare)
                                {
                                        colorscale = specularscale;
-                                       if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
+                                       if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
                                                passes += 4;
                                                passes += 4;
-                                       else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
+                                       else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
                                                passes += 3;
                                        else
                                                passes += 4;
                                                passes += 3;
                                        else
                                                passes += 4;
@@ -1600,19 +1738,19 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                else
                {
                        // TODO: add direct pants/shirt rendering
                else
                {
                        // TODO: add direct pants/shirt rendering
-                       if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
-                               R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
-                       if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
-                               R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
-                       if (ambientscale)
+                       if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
+                               R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
+                       if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
+                               R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
+                       if (r_shadow_rtlight->ambientscale)
                        {
                        {
-                               VectorScale(lightcolorbase, ambientscale, color2);
+                               VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
                                for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
                                        passes++;
                        }
                                for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
                                        passes++;
                        }
-                       if (diffusescale)
+                       if (r_shadow_rtlight->diffusescale)
                        {
                        {
-                               VectorScale(lightcolorbase, diffusescale, color2);
+                               VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
                                for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
                                        passes++;
                        }
                                for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
                                        passes++;
                        }
@@ -1629,111 +1767,56 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                }
                return;
        }
                }
                return;
        }
-       // FIXME: support EF_NODEPTHTEST
-       GL_DepthMask(false);
-       GL_DepthTest(true);
-       if (r_shadow_glsl.integer && r_shadow_program_light[0])
+       else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
        {
        {
-               unsigned int perm, prog;
                // GLSL shader path (GFFX5200, Radeon 9500)
                // GLSL shader path (GFFX5200, Radeon 9500)
-               memset(&m, 0, sizeof(m));
-               m.pointer_vertex = vertex3f;
-               m.pointer_texcoord[0] = texcoord2f;
-               m.pointer_texcoord3f[1] = svector3f;
-               m.pointer_texcoord3f[2] = tvector3f;
-               m.pointer_texcoord3f[3] = normal3f;
-               m.tex[0] = R_GetTexture(bumptexture);
-               m.tex[1] = R_GetTexture(basetexture);
-               m.tex[2] = R_GetTexture(glosstexture);
-               m.texcubemap[3] = R_GetTexture(lightcubemap);
-               // TODO: support fog (after renderer is converted to texture fog)
-               m.tex[4] = R_GetTexture(r_texture_white);
-               m.texmatrix[3] = *matrix_modeltolight;
-               R_Mesh_State(&m);
-               GL_BlendFunc(GL_ONE, GL_ONE);
-               GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
-               CHECKGLERROR
-               perm = 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 (specularscale && r_shadow_program_light[perm | SHADERPERMUTATION_SPECULAR])
-                       perm |= SHADERPERMUTATION_SPECULAR;
-               //if (fog && r_shadow_program_light[perm | SHADERPERMUTATION_FOG])
-               //      perm |= SHADERPERMUTATION_FOG;
-               if (lightcubemap && r_shadow_program_light[perm | SHADERPERMUTATION_CUBEFILTER])
-                       perm |= SHADERPERMUTATION_CUBEFILTER;
-               if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[perm | SHADERPERMUTATION_OFFSETMAPPING])
-                       perm |= SHADERPERMUTATION_OFFSETMAPPING;
-               prog = r_shadow_program_light[perm];
-               qglUseProgramObjectARB(prog);CHECKGLERROR
-               // TODO: support fog (after renderer is converted to texture fog)
-               if (perm & SHADERPERMUTATION_FOG)
-               {
-                       qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
-               }
-               qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
-               qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
-               if (perm & SHADERPERMUTATION_SPECULAR)
-               {
-                       qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
-                       qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
-               }
-               qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
-               qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
-               if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
-               {
-                       qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
-               }
-               if (perm & SHADERPERMUTATION_OFFSETMAPPING)
+               R_Mesh_VertexPointer(vertex3f);
+               R_Mesh_TexCoordPointer(0, 2, texcoord2f);
+               R_Mesh_TexCoordPointer(1, 3, svector3f);
+               R_Mesh_TexCoordPointer(2, 3, tvector3f);
+               R_Mesh_TexCoordPointer(3, 3, normal3f);
+               R_Mesh_TexBind(0, R_GetTexture(bumptexture));
+               R_Mesh_TexBind(1, R_GetTexture(basetexture));
+               R_Mesh_TexBind(2, R_GetTexture(glosstexture));
+               if (r_shadow_lightpermutation & SHADERPERMUTATION_SPECULAR)
                {
                {
-                       qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
-                       qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
+                       qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "SpecularScale"), specularscale);CHECKGLERROR
                }
                }
-               CHECKGLERROR
+               qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
                GL_LockArrays(firstvertex, numvertices);
                R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
                c_rt_lightmeshes++;
                c_rt_lighttris += numtriangles;
                // TODO: add direct pants/shirt rendering
                GL_LockArrays(firstvertex, numvertices);
                R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
                c_rt_lightmeshes++;
                c_rt_lighttris += numtriangles;
                // TODO: add direct pants/shirt rendering
-               if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
+               if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
                {
                        R_Mesh_TexBind(1, R_GetTexture(pantstexture));
                {
                        R_Mesh_TexBind(1, R_GetTexture(pantstexture));
-                       qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
+                       qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
                        R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
                }
                        R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
                }
-               if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
+               if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
                {
                        R_Mesh_TexBind(1, R_GetTexture(shirttexture));
                {
                        R_Mesh_TexBind(1, R_GetTexture(shirttexture));
-                       qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
+                       qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
                        R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
                }
                GL_LockArrays(0, 0);
                        R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
                }
                GL_LockArrays(0, 0);
-               qglUseProgramObjectARB(0);
-               // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
-               qglBegin(GL_TRIANGLES);
-               qglEnd();
-               CHECKGLERROR
        }
        }
-       else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
+       else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_DOT3)
        {
                // TODO: add direct pants/shirt rendering
        {
                // TODO: add direct pants/shirt rendering
-               if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
-                       R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
-               if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
-                       R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
-               if (!bumptexture)
-                       bumptexture = r_texture_blanknormalmap;
-               if (!glosstexture)
-                       glosstexture = r_texture_white;
-               if (ambientscale)
+               if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
+                       R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
+               if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
+                       R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
+               if (r_shadow_rtlight->ambientscale)
                {
                        GL_Color(1,1,1,1);
                {
                        GL_Color(1,1,1,1);
-                       colorscale = ambientscale;
+                       colorscale = r_shadow_rtlight->ambientscale;
                        // colorscale accounts for how much we multiply the brightness
                        // during combine.
                        //
                        // colorscale accounts for how much we multiply the brightness
                        // during combine.
                        //
@@ -1741,7 +1824,7 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                        // performed to get more brightness than otherwise possible.
                        //
                        // Limit mult to 64 for sanity sake.
                        // performed to get more brightness than otherwise possible.
                        //
                        // Limit mult to 64 for sanity sake.
-                       if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
+                       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));
                        {
                                // 3 3D combine path (Geforce3, Radeon 8500)
                                memset(&m, 0, sizeof(m));
@@ -1749,24 +1832,24 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
                                m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
-                               m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+                               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
                                m.pointer_texcoord3f[0] = varray_texcoord3f[0];
 #else
                                m.pointer_texcoord3f[0] = varray_texcoord3f[0];
-                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
                                m.tex[1] = R_GetTexture(basetexture);
                                m.pointer_texcoord[1] = texcoord2f;
 #endif
                                m.tex[1] = R_GetTexture(basetexture);
                                m.pointer_texcoord[1] = texcoord2f;
-                               m.texcubemap[2] = R_GetTexture(lightcubemap);
+                               m.texcubemap[2] = R_GetTexture(r_shadow_lightcubemap);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[2] = vertex3f;
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[2] = vertex3f;
-                               m.texmatrix[2] = *matrix_modeltolight;
+                               m.texmatrix[2] = r_shadow_entitytolight;
 #else
                                m.pointer_texcoord3f[2] = varray_texcoord3f[2];
 #else
                                m.pointer_texcoord3f[2] = varray_texcoord3f[2];
-                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
+                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
 #endif
                                GL_BlendFunc(GL_ONE, GL_ONE);
                        }
 #endif
                                GL_BlendFunc(GL_ONE, GL_ONE);
                        }
-                       else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
+                       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));
                        {
                                // 2 3D combine path (Geforce3, original Radeon)
                                memset(&m, 0, sizeof(m));
@@ -1774,16 +1857,16 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
                                m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
-                               m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+                               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
                                m.pointer_texcoord3f[0] = varray_texcoord3f[0];
 #else
                                m.pointer_texcoord3f[0] = varray_texcoord3f[0];
-                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
                                m.tex[1] = R_GetTexture(basetexture);
                                m.pointer_texcoord[1] = texcoord2f;
                                GL_BlendFunc(GL_ONE, GL_ONE);
                        }
 #endif
                                m.tex[1] = R_GetTexture(basetexture);
                                m.pointer_texcoord[1] = texcoord2f;
                                GL_BlendFunc(GL_ONE, GL_ONE);
                        }
-                       else if (r_textureunits.integer >= 4 && lightcubemap)
+                       else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
                        {
                                // 4 2D combine path (Geforce3, Radeon 8500)
                                memset(&m, 0, sizeof(m));
                        {
                                // 4 2D combine path (Geforce3, Radeon 8500)
                                memset(&m, 0, sizeof(m));
@@ -1791,35 +1874,35 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
                                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
-                               m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+                               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
                                m.pointer_texcoord[0] = varray_texcoord2f[0];
 #else
                                m.pointer_texcoord[0] = varray_texcoord2f[0];
-                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
                                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
 #endif
                                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
-                               m.texmatrix[1] = *matrix_modeltoattenuationz;
+                               m.texmatrix[1] = r_shadow_entitytoattenuationz;
 #else
                                m.pointer_texcoord[1] = varray_texcoord2f[1];
 #else
                                m.pointer_texcoord[1] = varray_texcoord2f[1];
-                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
+                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
 #endif
                                m.tex[2] = R_GetTexture(basetexture);
                                m.pointer_texcoord[2] = texcoord2f;
 #endif
                                m.tex[2] = R_GetTexture(basetexture);
                                m.pointer_texcoord[2] = texcoord2f;
-                               if (lightcubemap)
+                               if (r_shadow_lightcubemap != r_texture_whitecube)
                                {
                                {
-                                       m.texcubemap[3] = R_GetTexture(lightcubemap);
+                                       m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[3] = vertex3f;
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[3] = vertex3f;
-                                       m.texmatrix[3] = *matrix_modeltolight;
+                                       m.texmatrix[3] = r_shadow_entitytolight;
 #else
                                        m.pointer_texcoord3f[3] = varray_texcoord3f[3];
 #else
                                        m.pointer_texcoord3f[3] = varray_texcoord3f[3];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
+                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
 #endif
                                }
                                GL_BlendFunc(GL_ONE, GL_ONE);
                        }
 #endif
                                }
                                GL_BlendFunc(GL_ONE, GL_ONE);
                        }
-                       else if (r_textureunits.integer >= 3 && !lightcubemap)
+                       else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
                        {
                                // 3 2D combine path (Geforce3, original Radeon)
                                memset(&m, 0, sizeof(m));
                        {
                                // 3 2D combine path (Geforce3, original Radeon)
                                memset(&m, 0, sizeof(m));
@@ -1827,18 +1910,18 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
                                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
-                               m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+                               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
                                m.pointer_texcoord[0] = varray_texcoord2f[0];
 #else
                                m.pointer_texcoord[0] = varray_texcoord2f[0];
-                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
                                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
 #endif
                                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
-                               m.texmatrix[1] = *matrix_modeltoattenuationz;
+                               m.texmatrix[1] = r_shadow_entitytoattenuationz;
 #else
                                m.pointer_texcoord[1] = varray_texcoord2f[1];
 #else
                                m.pointer_texcoord[1] = varray_texcoord2f[1];
-                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
+                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
 #endif
                                m.tex[2] = R_GetTexture(basetexture);
                                m.pointer_texcoord[2] = texcoord2f;
 #endif
                                m.tex[2] = R_GetTexture(basetexture);
                                m.pointer_texcoord[2] = texcoord2f;
@@ -1852,18 +1935,18 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
                                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
-                               m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+                               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
                                m.pointer_texcoord[0] = varray_texcoord2f[0];
 #else
                                m.pointer_texcoord[0] = varray_texcoord2f[0];
-                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
                                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
 #endif
                                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
-                               m.texmatrix[1] = *matrix_modeltoattenuationz;
+                               m.texmatrix[1] = r_shadow_entitytoattenuationz;
 #else
                                m.pointer_texcoord[1] = varray_texcoord2f[1];
 #else
                                m.pointer_texcoord[1] = varray_texcoord2f[1];
-                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
+                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
 #endif
                                R_Mesh_State(&m);
                                GL_ColorMask(0,0,0,1);
 #endif
                                R_Mesh_State(&m);
                                GL_ColorMask(0,0,0,1);
@@ -1878,15 +1961,15 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.pointer_vertex = vertex3f;
                                m.tex[0] = R_GetTexture(basetexture);
                                m.pointer_texcoord[0] = texcoord2f;
                                m.pointer_vertex = vertex3f;
                                m.tex[0] = R_GetTexture(basetexture);
                                m.pointer_texcoord[0] = texcoord2f;
-                               if (lightcubemap)
+                               if (r_shadow_lightcubemap != r_texture_whitecube)
                                {
                                {
-                                       m.texcubemap[1] = R_GetTexture(lightcubemap);
+                                       m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
-                                       m.texmatrix[1] = *matrix_modeltolight;
+                                       m.texmatrix[1] = r_shadow_entitytolight;
 #else
                                        m.pointer_texcoord3f[1] = varray_texcoord3f[1];
 #else
                                        m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
+                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
 #endif
                                }
                                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
 #endif
                                }
                                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
@@ -1905,10 +1988,10 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                        }
                        GL_LockArrays(0, 0);
                }
                        }
                        GL_LockArrays(0, 0);
                }
-               if (diffusescale)
+               if (r_shadow_rtlight->diffusescale)
                {
                        GL_Color(1,1,1,1);
                {
                        GL_Color(1,1,1,1);
-                       colorscale = diffusescale;
+                       colorscale = r_shadow_rtlight->diffusescale;
                        // colorscale accounts for how much we multiply the brightness
                        // during combine.
                        //
                        // colorscale accounts for how much we multiply the brightness
                        // during combine.
                        //
@@ -1927,14 +2010,14 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                                m.pointer_texcoord3f[1] = varray_texcoord3f[1];
                                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 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
+                               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
                                m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[2] = vertex3f;
                                m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[2] = vertex3f;
-                               m.texmatrix[2] = *matrix_modeltoattenuationxyz;
+                               m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
 #else
                                m.pointer_texcoord3f[2] = varray_texcoord3f[2];
 #else
                                m.pointer_texcoord3f[2] = varray_texcoord3f[2];
-                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
                                R_Mesh_State(&m);
                                GL_ColorMask(0,0,0,1);
 #endif
                                R_Mesh_State(&m);
                                GL_ColorMask(0,0,0,1);
@@ -1949,20 +2032,20 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.pointer_vertex = vertex3f;
                                m.tex[0] = R_GetTexture(basetexture);
                                m.pointer_texcoord[0] = texcoord2f;
                                m.pointer_vertex = vertex3f;
                                m.tex[0] = R_GetTexture(basetexture);
                                m.pointer_texcoord[0] = texcoord2f;
-                               if (lightcubemap)
+                               if (r_shadow_lightcubemap != r_texture_whitecube)
                                {
                                {
-                                       m.texcubemap[1] = R_GetTexture(lightcubemap);
+                                       m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
-                                       m.texmatrix[1] = *matrix_modeltolight;
+                                       m.texmatrix[1] = r_shadow_entitytolight;
 #else
                                        m.pointer_texcoord3f[1] = varray_texcoord3f[1];
 #else
                                        m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
+                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
 #endif
                                }
                                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                        }
 #endif
                                }
                                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                        }
-                       else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
+                       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));
                        {
                                // 1/2/2 3D combine path (original Radeon)
                                memset(&m, 0, sizeof(m));
@@ -1970,10 +2053,10 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
                                m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
-                               m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+                               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
                                m.pointer_texcoord3f[0] = varray_texcoord3f[0];
 #else
                                m.pointer_texcoord3f[0] = varray_texcoord3f[0];
-                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
                                R_Mesh_State(&m);
                                GL_ColorMask(0,0,0,1);
 #endif
                                R_Mesh_State(&m);
                                GL_ColorMask(0,0,0,1);
@@ -1992,7 +2075,7 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                                m.pointer_texcoord3f[1] = varray_texcoord3f[1];
                                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 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
+                               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
                                R_Mesh_State(&m);
                                GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
                                GL_LockArrays(firstvertex, numvertices);
                                R_Mesh_State(&m);
                                GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
                                GL_LockArrays(firstvertex, numvertices);
@@ -2005,20 +2088,20 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.pointer_vertex = vertex3f;
                                m.tex[0] = R_GetTexture(basetexture);
                                m.pointer_texcoord[0] = texcoord2f;
                                m.pointer_vertex = vertex3f;
                                m.tex[0] = R_GetTexture(basetexture);
                                m.pointer_texcoord[0] = texcoord2f;
-                               if (lightcubemap)
+                               if (r_shadow_lightcubemap != r_texture_whitecube)
                                {
                                {
-                                       m.texcubemap[1] = R_GetTexture(lightcubemap);
+                                       m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
-                                       m.texmatrix[1] = *matrix_modeltolight;
+                                       m.texmatrix[1] = r_shadow_entitytolight;
 #else
                                        m.pointer_texcoord3f[1] = varray_texcoord3f[1];
 #else
                                        m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
+                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
 #endif
                                }
                                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                        }
 #endif
                                }
                                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                        }
-                       else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
+                       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));
                        {
                                // 2/2 3D combine path (original Radeon)
                                memset(&m, 0, sizeof(m));
@@ -2029,7 +2112,7 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                                m.pointer_texcoord3f[1] = varray_texcoord3f[1];
                                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 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
+                               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
                                R_Mesh_State(&m);
                                GL_ColorMask(0,0,0,1);
                                GL_BlendFunc(GL_ONE, GL_ZERO);
                                R_Mesh_State(&m);
                                GL_ColorMask(0,0,0,1);
                                GL_BlendFunc(GL_ONE, GL_ZERO);
@@ -2046,10 +2129,10 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
                                m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
-                               m.texmatrix[1] = *matrix_modeltoattenuationxyz;
+                               m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
 #else
                                m.pointer_texcoord3f[1] = varray_texcoord3f[1];
 #else
                                m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
                                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                        }
 #endif
                                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                        }
@@ -2064,22 +2147,22 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                                m.pointer_texcoord3f[1] = varray_texcoord3f[1];
                                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 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
+                               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
                                m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[2] = vertex3f;
                                m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[2] = vertex3f;
-                               m.texmatrix[2] = *matrix_modeltoattenuationxyz;
+                               m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
 #else
                                m.pointer_texcoord[2] = varray_texcoord2f[2];
 #else
                                m.pointer_texcoord[2] = varray_texcoord2f[2];
-                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
                                m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[3] = vertex3f;
 #endif
                                m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[3] = vertex3f;
-                               m.texmatrix[3] = *matrix_modeltoattenuationz;
+                               m.texmatrix[3] = r_shadow_entitytoattenuationz;
 #else
                                m.pointer_texcoord[3] = varray_texcoord2f[3];
 #else
                                m.pointer_texcoord[3] = varray_texcoord2f[3];
-                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
+                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
 #endif
                                R_Mesh_State(&m);
                                GL_ColorMask(0,0,0,1);
 #endif
                                R_Mesh_State(&m);
                                GL_ColorMask(0,0,0,1);
@@ -2094,15 +2177,15 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.pointer_vertex = vertex3f;
                                m.tex[0] = R_GetTexture(basetexture);
                                m.pointer_texcoord[0] = texcoord2f;
                                m.pointer_vertex = vertex3f;
                                m.tex[0] = R_GetTexture(basetexture);
                                m.pointer_texcoord[0] = texcoord2f;
-                               if (lightcubemap)
+                               if (r_shadow_lightcubemap != r_texture_whitecube)
                                {
                                {
-                                       m.texcubemap[1] = R_GetTexture(lightcubemap);
+                                       m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
-                                       m.texmatrix[1] = *matrix_modeltolight;
+                                       m.texmatrix[1] = r_shadow_entitytolight;
 #else
                                        m.pointer_texcoord3f[1] = varray_texcoord3f[1];
 #else
                                        m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
+                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
 #endif
                                }
                                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
 #endif
                                }
                                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
@@ -2115,18 +2198,18 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
                                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[0] = vertex3f;
-                               m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+                               m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
                                m.pointer_texcoord[0] = varray_texcoord2f[0];
 #else
                                m.pointer_texcoord[0] = varray_texcoord2f[0];
-                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
                                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
 #endif
                                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
-                               m.texmatrix[1] = *matrix_modeltoattenuationz;
+                               m.texmatrix[1] = r_shadow_entitytoattenuationz;
 #else
                                m.pointer_texcoord[1] = varray_texcoord2f[1];
 #else
                                m.pointer_texcoord[1] = varray_texcoord2f[1];
-                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
+                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
 #endif
                                R_Mesh_State(&m);
                                GL_ColorMask(0,0,0,1);
 #endif
                                R_Mesh_State(&m);
                                GL_ColorMask(0,0,0,1);
@@ -2145,7 +2228,7 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                                m.pointer_texcoord3f[1] = varray_texcoord3f[1];
                                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 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin);
+                               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin);
                                R_Mesh_State(&m);
                                GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
                                GL_LockArrays(firstvertex, numvertices);
                                R_Mesh_State(&m);
                                GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
                                GL_LockArrays(firstvertex, numvertices);
@@ -2158,15 +2241,15 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.pointer_vertex = vertex3f;
                                m.tex[0] = R_GetTexture(basetexture);
                                m.pointer_texcoord[0] = texcoord2f;
                                m.pointer_vertex = vertex3f;
                                m.tex[0] = R_GetTexture(basetexture);
                                m.pointer_texcoord[0] = texcoord2f;
-                               if (lightcubemap)
+                               if (r_shadow_lightcubemap != r_texture_whitecube)
                                {
                                {
-                                       m.texcubemap[1] = R_GetTexture(lightcubemap);
+                                       m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
-                                       m.texmatrix[1] = *matrix_modeltolight;
+                                       m.texmatrix[1] = r_shadow_entitytolight;
 #else
                                        m.pointer_texcoord3f[1] = varray_texcoord3f[1];
 #else
                                        m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
+                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
 #endif
                                }
                                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
 #endif
                                }
                                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
@@ -2192,7 +2275,7 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                        {
                                colorscale = specularscale;
                                GL_Color(1,1,1,1);
                        {
                                colorscale = specularscale;
                                GL_Color(1,1,1,1);
-                               if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
+                               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));
                                {
                                        // 2/0/0/1/2 3D combine blendsquare path
                                        memset(&m, 0, sizeof(m));
@@ -2202,7 +2285,7 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                        m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                                        m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                                        m.pointer_texcoord3f[1] = varray_texcoord3f[1];
                                        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 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
+                                       R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
                                        R_Mesh_State(&m);
                                        GL_ColorMask(0,0,0,1);
                                        // this squares the result
                                        R_Mesh_State(&m);
                                        GL_ColorMask(0,0,0,1);
                                        // this squares the result
@@ -2236,10 +2319,10 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                        m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[0] = vertex3f;
                                        m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[0] = vertex3f;
-                                       m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+                                       m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
                                        m.pointer_texcoord3f[0] = varray_texcoord3f[0];
 #else
                                        m.pointer_texcoord3f[0] = varray_texcoord3f[0];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
                                        R_Mesh_State(&m);
                                        GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
 #endif
                                        R_Mesh_State(&m);
                                        GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
@@ -2253,20 +2336,20 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                        m.pointer_vertex = vertex3f;
                                        m.tex[0] = R_GetTexture(glosstexture);
                                        m.pointer_texcoord[0] = texcoord2f;
                                        m.pointer_vertex = vertex3f;
                                        m.tex[0] = R_GetTexture(glosstexture);
                                        m.pointer_texcoord[0] = texcoord2f;
-                                       if (lightcubemap)
+                                       if (r_shadow_lightcubemap != r_texture_whitecube)
                                        {
                                        {
-                                               m.texcubemap[1] = R_GetTexture(lightcubemap);
+                                               m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
 #ifdef USETEXMATRIX
                                                m.pointer_texcoord3f[1] = vertex3f;
 #ifdef USETEXMATRIX
                                                m.pointer_texcoord3f[1] = vertex3f;
-                                               m.texmatrix[1] = *matrix_modeltolight;
+                                               m.texmatrix[1] = r_shadow_entitytolight;
 #else
                                                m.pointer_texcoord3f[1] = varray_texcoord3f[1];
 #else
                                                m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
+                                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
 #endif
                                        }
                                        GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                                }
 #endif
                                        }
                                        GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                                }
-                               else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
+                               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));
                                {
                                        // 2/0/0/2 3D combine blendsquare path
                                        memset(&m, 0, sizeof(m));
@@ -2276,7 +2359,7 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                        m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                                        m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                                        m.pointer_texcoord3f[1] = varray_texcoord3f[1];
                                        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 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
+                                       R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
                                        R_Mesh_State(&m);
                                        GL_ColorMask(0,0,0,1);
                                        // this squares the result
                                        R_Mesh_State(&m);
                                        GL_ColorMask(0,0,0,1);
                                        // this squares the result
@@ -2312,10 +2395,10 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                        m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
                                        m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
-                                       m.texmatrix[1] = *matrix_modeltoattenuationxyz;
+                                       m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
 #else
                                        m.pointer_texcoord3f[1] = varray_texcoord3f[1];
 #else
                                        m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+                                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
                                        GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                                }
 #endif
                                        GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                                }
@@ -2329,7 +2412,7 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                        m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                                        m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                                        m.pointer_texcoord3f[1] = varray_texcoord3f[1];
                                        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 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, relativelightorigin, relativeeyeorigin);
+                                       R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, svector3f + 3 * firstvertex, tvector3f + 3 * firstvertex, normal3f + 3 * firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
                                        R_Mesh_State(&m);
                                        GL_ColorMask(0,0,0,1);
                                        // this squares the result
                                        R_Mesh_State(&m);
                                        GL_ColorMask(0,0,0,1);
                                        // this squares the result
@@ -2363,18 +2446,18 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                        m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[0] = vertex3f;
                                        m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[0] = vertex3f;
-                                       m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+                                       m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
 #else
                                        m.pointer_texcoord[0] = varray_texcoord2f[0];
 #else
                                        m.pointer_texcoord[0] = varray_texcoord2f[0];
-                                       R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+                                       R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
                                        m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
 #endif
                                        m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[1] = vertex3f;
-                                       m.texmatrix[1] = *matrix_modeltoattenuationz;
+                                       m.texmatrix[1] = r_shadow_entitytoattenuationz;
 #else
                                        m.pointer_texcoord[1] = varray_texcoord2f[1];
 #else
                                        m.pointer_texcoord[1] = varray_texcoord2f[1];
-                                       R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
+                                       R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
 #endif
                                        R_Mesh_State(&m);
                                        GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
 #endif
                                        R_Mesh_State(&m);
                                        GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
@@ -2388,15 +2471,15 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                        m.pointer_vertex = vertex3f;
                                        m.tex[0] = R_GetTexture(glosstexture);
                                        m.pointer_texcoord[0] = texcoord2f;
                                        m.pointer_vertex = vertex3f;
                                        m.tex[0] = R_GetTexture(glosstexture);
                                        m.pointer_texcoord[0] = texcoord2f;
-                                       if (lightcubemap)
+                                       if (r_shadow_lightcubemap != r_texture_whitecube)
                                        {
                                        {
-                                               m.texcubemap[1] = R_GetTexture(lightcubemap);
+                                               m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
 #ifdef USETEXMATRIX
                                                m.pointer_texcoord3f[1] = vertex3f;
 #ifdef USETEXMATRIX
                                                m.pointer_texcoord3f[1] = vertex3f;
-                                               m.texmatrix[1] = *matrix_modeltolight;
+                                               m.texmatrix[1] = r_shadow_entitytolight;
 #else
                                                m.pointer_texcoord3f[1] = varray_texcoord3f[1];
 #else
                                                m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
+                                               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytolight);
 #endif
                                        }
                                        GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
 #endif
                                        }
                                        GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
@@ -2416,17 +2499,17 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                        }
                }
        }
                        }
                }
        }
-       else
+       else if (r_shadowstage == R_SHADOWSTAGE_LIGHT_VERTEX)
        {
                // TODO: add direct pants/shirt rendering
        {
                // TODO: add direct pants/shirt rendering
-               if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
-                       R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
-               if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
-                       R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
-               if (ambientscale)
+               if (pantstexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorpants) > 0.001)
+                       R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorpants, vec3_origin, vec3_origin, pantstexture, NULL, NULL, bumptexture, NULL);
+               if (shirttexture && (r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
+                       R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, NULL, NULL, bumptexture, NULL);
+               if (r_shadow_rtlight->ambientscale)
                {
                        GL_BlendFunc(GL_ONE, GL_ONE);
                {
                        GL_BlendFunc(GL_ONE, GL_ONE);
-                       VectorScale(lightcolorbase, ambientscale, color2);
+                       VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, color2);
                        memset(&m, 0, sizeof(m));
                        m.pointer_vertex = vertex3f;
                        m.tex[0] = R_GetTexture(basetexture);
                        memset(&m, 0, sizeof(m));
                        m.pointer_vertex = vertex3f;
                        m.tex[0] = R_GetTexture(basetexture);
@@ -2437,10 +2520,10 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
                                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
-                               m.texmatrix[1] = *matrix_modeltoattenuationxyz;
+                               m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
 #else
                                m.pointer_texcoord[1] = varray_texcoord2f[1];
 #else
                                m.pointer_texcoord[1] = varray_texcoord2f[1];
-                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
                                if (r_textureunits.integer >= 3)
                                {
 #endif
                                if (r_textureunits.integer >= 3)
                                {
@@ -2448,10 +2531,10 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                        m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[2] = vertex3f;
                                        m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[2] = vertex3f;
-                                       m.texmatrix[2] = *matrix_modeltoattenuationz;
+                                       m.texmatrix[2] = r_shadow_entitytoattenuationz;
 #else
                                        m.pointer_texcoord[2] = varray_texcoord2f[2];
 #else
                                        m.pointer_texcoord[2] = varray_texcoord2f[2];
-                                       R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
+                                       R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
 #endif
                                }
                        }
 #endif
                                }
                        }
@@ -2468,9 +2551,9 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                if (r_textureunits.integer >= 3)
                                        GL_Color(color[0], color[1], color[2], 1);
                                else if (r_textureunits.integer >= 2)
                                if (r_textureunits.integer >= 3)
                                        GL_Color(color[0], color[1], color[2], 1);
                                else if (r_textureunits.integer >= 2)
-                                       R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
+                                       R_Shadow_VertexNoShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
                                else
                                else
-                                       R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color, matrix_modeltolight);
+                                       R_Shadow_VertexNoShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, color);
                                GL_LockArrays(firstvertex, numvertices);
                                R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
                                GL_LockArrays(0, 0);
                                GL_LockArrays(firstvertex, numvertices);
                                R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
                                GL_LockArrays(0, 0);
@@ -2478,10 +2561,10 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                c_rt_lighttris += numtriangles;
                        }
                }
                                c_rt_lighttris += numtriangles;
                        }
                }
-               if (diffusescale)
+               if (r_shadow_rtlight->diffusescale)
                {
                        GL_BlendFunc(GL_ONE, GL_ONE);
                {
                        GL_BlendFunc(GL_ONE, GL_ONE);
-                       VectorScale(lightcolorbase, diffusescale, color2);
+                       VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale, color2);
                        memset(&m, 0, sizeof(m));
                        m.pointer_vertex = vertex3f;
                        m.pointer_color = varray_color4f;
                        memset(&m, 0, sizeof(m));
                        m.pointer_vertex = vertex3f;
                        m.pointer_color = varray_color4f;
@@ -2493,10 +2576,10 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
                                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                m.pointer_texcoord3f[1] = vertex3f;
-                               m.texmatrix[1] = *matrix_modeltoattenuationxyz;
+                               m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
 #else
                                m.pointer_texcoord[1] = varray_texcoord2f[1];
 #else
                                m.pointer_texcoord[1] = varray_texcoord2f[1];
-                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationxyz);
 #endif
                                if (r_textureunits.integer >= 3)
                                {
 #endif
                                if (r_textureunits.integer >= 3)
                                {
@@ -2504,10 +2587,10 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                        m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[2] = vertex3f;
                                        m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
 #ifdef USETEXMATRIX
                                        m.pointer_texcoord3f[2] = vertex3f;
-                                       m.texmatrix[2] = *matrix_modeltoattenuationz;
+                                       m.texmatrix[2] = r_shadow_entitytoattenuationz;
 #else
                                        m.pointer_texcoord[2] = varray_texcoord2f[2];
 #else
                                        m.pointer_texcoord[2] = varray_texcoord2f[2];
-                                       R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
+                                       R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, &r_shadow_entitytoattenuationz);
 #endif
                                }
                        }
 #endif
                                }
                        }
@@ -2518,11 +2601,11 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                                color[1] = bound(0, color2[1], 1);
                                color[2] = bound(0, color2[2], 1);
                                if (r_textureunits.integer >= 3)
                                color[1] = bound(0, color2[1], 1);
                                color[2] = bound(0, color2[2], 1);
                                if (r_textureunits.integer >= 3)
-                                       R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
+                                       R_Shadow_VertexShading(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
                                else if (r_textureunits.integer >= 2)
                                else if (r_textureunits.integer >= 2)
-                                       R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
+                                       R_Shadow_VertexShadingWithZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
                                else
                                else
-                                       R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color, matrix_modeltolight);
+                                       R_Shadow_VertexShadingWithXYZAttenuation(numvertices, vertex3f + 3 * firstvertex, normal3f + 3 * firstvertex, color);
                                GL_LockArrays(firstvertex, numvertices);
                                R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
                                GL_LockArrays(0, 0);
                                GL_LockArrays(firstvertex, numvertices);
                                R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
                                GL_LockArrays(0, 0);
@@ -2572,8 +2655,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;
        for (k = 0;k < 3;k++)
                for (j = 0;j < 4;j++)
                        rtlight->matrix_worldtolight.m[k][j] *= scale;
-       Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
-       Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
 
        rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
        rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
 
        rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
        rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
@@ -2634,7 +2715,7 @@ void R_RTLight_Compile(rtlight_t *rtlight)
                if (model->DrawLight)
                {
                        rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
                if (model->DrawLight)
                {
                        rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
-                       model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, 0, 0, 0, numsurfaces, r_shadow_buffer_surfacelist, 0);
+                       model->DrawLight(ent, vec3_origin, numsurfaces, r_shadow_buffer_surfacelist);
                        rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
                }
                // switch back to rendering when DrawShadowVolume or DrawLight is called
                        rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
                }
                // switch back to rendering when DrawShadowVolume or DrawLight is called
@@ -2703,20 +2784,108 @@ void R_Shadow_UncompileWorldLights(void)
                R_RTLight_Uncompile(&light->rtlight);
 }
 
                R_RTLight_Uncompile(&light->rtlight);
 }
 
-void R_DrawRTLight(rtlight_t *rtlight, int visiblelighting, int visiblevolumes)
+void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+{
+       vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
+       vec_t relativeshadowradius;
+       if (ent == r_refdef.worldentity)
+       {
+               if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
+               {
+                       shadowmesh_t *mesh;
+                       R_Mesh_Matrix(&ent->matrix);
+                       for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
+                       {
+                               R_Mesh_VertexPointer(mesh->vertex3f);
+                               GL_LockArrays(0, mesh->numverts);
+                               if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
+                               {
+                                       // increment stencil if backface is behind depthbuffer
+                                       qglCullFace(GL_BACK); // quake is backwards, this culls front 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;
+                                       // decrement stencil if frontface is behind depthbuffer
+                                       qglCullFace(GL_FRONT); // quake is backwards, this culls back 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;
+                               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);
+               }
+       }
+       else
+       {
+               Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativeshadoworigin);
+               relativeshadowradius = rtlight->radius / ent->scale;
+               relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
+               relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
+               relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
+               relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
+               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);
+       }
+}
+
+void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t lightcolor, int numsurfaces, int *surfacelist)
+{
+       shadowmesh_t *mesh;
+       // set up properties for rendering light onto this entity
+       r_shadow_entitylightcolor[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
+       r_shadow_entitylightcolor[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
+       r_shadow_entitylightcolor[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
+       Matrix4x4_Concat(&r_shadow_entitytolight, &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_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
+               }
+       }
+       if (ent == r_refdef.worldentity)
+       {
+               if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compilelight.integer)
+               {
+                       for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
+                               R_Shadow_RenderLighting(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, r_shadow_entitylightcolor, vec3_origin, vec3_origin, mesh->map_diffuse, NULL, NULL, mesh->map_normal, mesh->map_specular);
+               }
+               else
+                       ent->model->DrawLight(ent, r_shadow_entitylightcolor, numsurfaces, surfacelist);
+       }
+       else
+               ent->model->DrawLight(ent, r_shadow_entitylightcolor, ent->model->nummodelsurfaces, ent->model->surfacelist);
+}
+
+void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
 {
 {
-       int i, shadow, usestencil;
-       entity_render_t *ent;
+       int i, usestencil;
        float f;
        float f;
-       vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
-       rtexture_t *cubemaptexture;
-       matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
+       vec3_t lightcolor;
        int numleafs, numsurfaces;
        int *leaflist, *surfacelist;
        qbyte *leafpvs;
        int numleafs, numsurfaces;
        int *leaflist, *surfacelist;
        qbyte *leafpvs;
-       vec3_t cullmins, cullmaxs, relativelightmins, relativelightmaxs;
-       shadowmesh_t *mesh;
-       rmeshstate_t m;
+       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 < 0.01)
 
        // skip lights that don't light (corona only lights)
        if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
@@ -2737,26 +2906,16 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblelighting, int visiblevolumes)
        // 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)
        // loading is done before visibility checks because loading should happen
        // all at once at the start of a level, not when it stalls gameplay.
        // (especially important to benchmarks)
+       // compile light
        if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
                R_RTLight_Compile(rtlight);
        if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
                R_RTLight_Compile(rtlight);
-       if (rtlight->cubemapname[0])
-               cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
-       else
-               cubemaptexture = NULL;
-
-       cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
-       cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
-       cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
-       cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
-       cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
-       cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
-       if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
+       // load cubemap
+       r_shadow_lightcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
+
+       // if the light box is offscreen, skip it
+       if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
                return;
                return;
-       numleafs = 0;
-       leaflist = NULL;
-       leafpvs = NULL;
-       numsurfaces = 0;
-       surfacelist = NULL;
+
        if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
        {
                // compiled light, world available and can receive realtime lighting
        if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
        {
                // compiled light, world available and can receive realtime lighting
@@ -2766,25 +2925,29 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblelighting, int visiblevolumes)
                leafpvs = rtlight->static_leafpvs;
                numsurfaces = rtlight->static_numsurfaces;
                surfacelist = rtlight->static_surfacelist;
                leafpvs = rtlight->static_leafpvs;
                numsurfaces = rtlight->static_numsurfaces;
                surfacelist = rtlight->static_surfacelist;
-               VectorCopy(rtlight->cullmins, cullmins);
-               VectorCopy(rtlight->cullmaxs, cullmaxs);
        }
        else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
        {
                // dynamic light, world available and can receive realtime lighting
        }
        else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
        {
                // dynamic light, world available and can receive realtime lighting
-               // if the light box is offscreen, skip it right away
-               if (R_CullBox(cullmins, cullmaxs))
-                       return;
                // calculate lit surfaces and leafs
                R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->brush.num_surfaces);
                // calculate lit surfaces and leafs
                R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->brush.num_surfaces);
-               r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, cullmins, 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, rtlight->cullmins, 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;
                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))
+                       return;
+       }
+       else
+       {
+               // no world
+               numleafs = 0;
+               leaflist = NULL;
+               leafpvs = NULL;
+               numsurfaces = 0;
+               surfacelist = NULL;
        }
        }
-       // if the reduced leaf bounds are offscreen, skip it
-       if (R_CullBox(cullmins, cullmaxs))
-               return;
        // check if light is illuminating any visible leafs
        if (numleafs)
        {
        // check if light is illuminating any visible leafs
        if (numleafs)
        {
@@ -2795,189 +2958,98 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblelighting, int visiblevolumes)
                        return;
        }
        // set up a scissor rectangle for this light
                        return;
        }
        // set up a scissor rectangle for this light
-       if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
+       if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
                return;
 
                return;
 
-       c_rt_lights++;
-
-       shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
-       usestencil = false;
-
-       if (shadow && ((gl_stencil && !visiblelighting) || visiblevolumes))
+       numlightentities = 0;
+       if (numsurfaces)
+               lightentities[numlightentities++] = r_refdef.worldentity;
+       numshadowentities = 0;
+       if (numsurfaces)
+               shadowentities[numshadowentities++] = r_refdef.worldentity;
+       if (r_drawentities.integer)
        {
        {
-               if (visiblevolumes)
-               {
-                       qglDisable(GL_CULL_FACE);
-                       GL_DepthTest(visiblevolumes < 2);
-                       GL_Color(0.0, 0.0125, 0.1, 1);
-               }
-               else
-               {
-                       R_Shadow_Stage_ShadowVolumes();
-                       GL_Clear(GL_STENCIL_BUFFER_BIT);
-                       c_rt_clears++;
-                       usestencil = true;
-               }
-               ent = r_refdef.worldentity;
-               if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
+               for (i = 0;i < r_refdef.numentities;i++)
                {
                {
-                       memset(&m, 0, sizeof(m));
-                       R_Mesh_Matrix(&ent->matrix);
-                       for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
+                       entity_render_t *ent = r_refdef.entities[i];
+                       if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
+                        && ent->model
+                        && !(ent->flags & RENDER_TRANSPARENT)
+                        && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
                        {
                        {
-                               m.pointer_vertex = mesh->vertex3f;
-                               R_Mesh_State(&m);
-                               GL_LockArrays(0, mesh->numverts);
-                               if (r_shadowstage == SHADOWSTAGE_STENCIL)
-                               {
-                                       // increment stencil if backface is behind depthbuffer
-                                       qglCullFace(GL_BACK); // quake is backwards, this culls front 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;
-                                       // decrement stencil if frontface is behind depthbuffer
-                                       qglCullFace(GL_FRONT); // quake is backwards, this culls back 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;
-                               GL_LockArrays(0, 0);
-                       }
-               }
-               else if (numsurfaces)
-               {
-                       Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
-                       ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
-               }
-               if (r_drawentities.integer)
-               {
-                       for (i = 0;i < r_refdef.numentities;i++)
-                       {
-                               ent = r_refdef.entities[i];
-                               // rough checks
-                               if (r_shadow_cull.integer)
-                               {
-                                       if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
-                                               continue;
-                                       if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingLeafPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
-                                               continue;
-                               }
-                               if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
-                                       continue;
-                               Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
-                               // light emitting entities should not cast their own shadow
-                               if (VectorLength2(relativelightorigin) < 0.1)
-                                       continue;
-                               relativelightmins[0] = relativelightorigin[0] - rtlight->radius;
-                               relativelightmins[1] = relativelightorigin[1] - rtlight->radius;
-                               relativelightmins[2] = relativelightorigin[2] - rtlight->radius;
-                               relativelightmaxs[0] = relativelightorigin[0] + rtlight->radius;
-                               relativelightmaxs[1] = relativelightorigin[1] + rtlight->radius;
-                               relativelightmaxs[2] = relativelightorigin[2] + rtlight->radius;
-                               ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativelightmins, relativelightmaxs);
+                               // 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)
+                                       shadowentities[numshadowentities++] = ent;
+                               if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
+                                       lightentities[numlightentities++] = ent;
                        }
                }
        }
 
                        }
                }
        }
 
-       if (visiblelighting || !visiblevolumes)
+       // return if there's nothing at all to light
+       if (!numlightentities)
+               return;
+
+       R_Shadow_Stage_ActiveLight(rtlight);
+       c_rt_lights++;
+
+       usestencil = false;
+       if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
        {
        {
-               if (visiblelighting)
-               {
-                       qglEnable(GL_CULL_FACE);
-                       GL_DepthTest(visiblelighting < 2);
-                       GL_Color(0.1, 0.0125, 0, 1);
-               }
-               else
-                       R_Shadow_Stage_Light(usestencil);
+               usestencil = true;
+               R_Shadow_Stage_StencilShadowVolumes();
+               for (i = 0;i < numshadowentities;i++)
+                       R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
+       }
 
 
-               ent = r_refdef.worldentity;
-               if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
-               {
-                       lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
-                       lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
-                       lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
-                       Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
-                       Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
-                       Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
-                       Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
-                       Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
-                       if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compilelight.integer)
-                       {
-                               R_Mesh_Matrix(&ent->matrix);
-                               for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
-                                       R_Shadow_RenderLighting(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, NULL, NULL, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, NULL, NULL, mesh->map_normal, mesh->map_specular, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, visiblelighting);
-                       }
-                       else
-                               ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist, visiblelighting);
-               }
-               if (r_drawentities.integer)
-               {
-                       for (i = 0;i < r_refdef.numentities;i++)
-                       {
-                               ent = r_refdef.entities[i];
-                               // can't draw transparent entity lighting here because
-                               // transparent meshes are deferred for later
-                               if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & (RENDER_LIGHT | RENDER_TRANSPARENT)) == RENDER_LIGHT)
-                               {
-                                       lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
-                                       lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
-                                       lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
-                                       Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
-                                       Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
-                                       Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
-                                       Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
-                                       Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
-                                       ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, ent->model->nummodelsurfaces, ent->model->surfacelist, visiblelighting);
-                               }
-                       }
-               }
+       if (numlightentities && !visible)
+       {
+               R_Shadow_Stage_Lighting(usestencil);
+               for (i = 0;i < numlightentities;i++)
+                       R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, 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);
+       }
+
+       if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
+       {
+               R_Shadow_Stage_VisibleLighting(usestencil);
+               for (i = 0;i < numlightentities;i++)
+                       R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
        }
 }
 
        }
 }
 
-void R_ShadowVolumeLighting(int visiblelighting, int visiblevolumes)
+void R_ShadowVolumeLighting(qboolean visible)
 {
        int lnum, flag;
        dlight_t *light;
 {
        int lnum, flag;
        dlight_t *light;
-       rmeshstate_t m;
 
        if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
                R_Shadow_EditLights_Reload_f();
 
 
        if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
                R_Shadow_EditLights_Reload_f();
 
-       if (visiblelighting || visiblevolumes)
-       {
-               memset(&m, 0, sizeof(m));
-               R_Mesh_State(&m);
+       R_Shadow_Stage_Begin();
 
 
-               GL_BlendFunc(GL_ONE, GL_ONE);
-               GL_DepthMask(false);
-               qglCullFace(GL_FRONT); // this culls back
-       }
-       else
-               R_Shadow_Stage_Begin();
        flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
        if (r_shadow_debuglight.integer >= 0)
        {
                for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
                        if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
        flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
        if (r_shadow_debuglight.integer >= 0)
        {
                for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
                        if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
-                               R_DrawRTLight(&light->rtlight, visiblelighting, visiblevolumes);
+                               R_DrawRTLight(&light->rtlight, visible);
        }
        else
                for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
                        if (light->flags & flag)
        }
        else
                for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
                        if (light->flags & flag)
-                               R_DrawRTLight(&light->rtlight, visiblelighting, visiblevolumes);
+                               R_DrawRTLight(&light->rtlight, visible);
        if (r_rtdlight)
                for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
        if (r_rtdlight)
                for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
-                       R_DrawRTLight(&light->rtlight, visiblelighting, visiblevolumes);
+                       R_DrawRTLight(&light->rtlight, visible);
 
 
-       if (visiblelighting || visiblevolumes)
-       {
-               qglEnable(GL_CULL_FACE);
-               GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
-       }
-       else
-               R_Shadow_Stage_End();
+       R_Shadow_Stage_End();
 }
 
 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
 }
 
 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
@@ -3085,7 +3157,7 @@ rtexture_t *R_Shadow_Cubemap(const char *basename)
                if (!strcasecmp(cubemaps[i].basename, basename))
                        return cubemaps[i].texture;
        if (i >= MAX_CUBEMAPS)
                if (!strcasecmp(cubemaps[i].basename, basename))
                        return cubemaps[i].texture;
        if (i >= MAX_CUBEMAPS)
-               return NULL;
+               return r_texture_whitecube;
        numcubemaps++;
        strcpy(cubemaps[i].basename, basename);
        cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
        numcubemaps++;
        strcpy(cubemaps[i].basename, basename);
        cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
index 99417461da2b8b77abf30cbc1dc777323ed6adc7..b3679465ae18abc8bac82abdba4c39d7c87d512c 100644 (file)
@@ -4,7 +4,6 @@
 
 extern cvar_t r_shadow_bumpscale_basetexture;
 extern cvar_t r_shadow_bumpscale_bumpmap;
 
 extern cvar_t r_shadow_bumpscale_basetexture;
 extern cvar_t r_shadow_bumpscale_bumpmap;
-extern cvar_t r_shadow_cull;
 extern cvar_t r_shadow_debuglight;
 extern cvar_t r_shadow_gloss;
 extern cvar_t r_shadow_gloss2intensity;
 extern cvar_t r_shadow_debuglight;
 extern cvar_t r_shadow_gloss;
 extern cvar_t r_shadow_gloss2intensity;
@@ -38,8 +37,7 @@ extern mempool_t *r_shadow_mempool;
 void R_Shadow_Init(void);
 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_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_Init(void);
 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_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_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *relativelightorigin, const float *relativeeyeorigin, const float *lightcolorbase, const float *lightcolorpants, const float *lightcolorshirt, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int visiblelighting);
-void R_Shadow_ClearStencil(void);
+void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *lightcolorbase, const float *lightcolorpants, const float *lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *bumptexture, rtexture_t *glosstexture);
 
 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i);
 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs);
 
 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i);
 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs);
@@ -60,7 +58,7 @@ void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int i
 void R_RTLight_Compile(rtlight_t *rtlight);
 void R_RTLight_Uncompile(rtlight_t *rtlight);
 
 void R_RTLight_Compile(rtlight_t *rtlight);
 void R_RTLight_Uncompile(rtlight_t *rtlight);
 
-void R_ShadowVolumeLighting(int visiblelighting, int visiblevolumes);
+void R_ShadowVolumeLighting(qboolean visible);
 
 int *R_Shadow_ResizeShadowElements(int numtris);
 
 
 int *R_Shadow_ResizeShadowElements(int numtris);