From 2a1615321fd8f4a44b97d5b980bb15a4a2132292 Mon Sep 17 00:00:00 2001
From: havoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Tue, 27 Dec 2005 10:10:55 +0000
Subject: [PATCH] reworked rtlighting code to handle transparent water lighting
 and transparent model lighting (doesn't properly handle alpha textures
 though)

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5871 d7cf8633-e32d-0410-b094-e92efae38249
---
 cl_particles.c |   8 +-
 client.h       |   6 +
 gl_rmain.c     |  50 +++---
 gl_rsurf.c     |  97 ++++++-----
 meshqueue.c    |  38 +++--
 meshqueue.h    |   4 +-
 model_shared.h |   6 +-
 r_explosion.c  |   7 +-
 r_lightning.c  |   6 +-
 r_shadow.c     | 446 ++++++++++++++++++++++++++++---------------------
 r_shadow.h     |  25 ++-
 r_sprites.c    |   6 +-
 12 files changed, 406 insertions(+), 293 deletions(-)

diff --git a/cl_particles.c b/cl_particles.c
index 7b56f914..d49affc9 100644
--- a/cl_particles.c
+++ b/cl_particles.c
@@ -2064,9 +2064,9 @@ float particle_vertex3f[12], particle_texcoord2f[8];
 void R_DrawParticle(particle_t *p)
 {
 #else
-void R_DrawParticleCallback(const void *calldata1, int calldata2)
+void R_DrawParticle_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
 {
-	const particle_t *p = (particle_t *)calldata1;
+	const particle_t *p = particles + surfacenumber;
 	rmeshstate_t m;
 #endif
 	pblend_t blendmode;
@@ -2257,9 +2257,9 @@ void R_DrawParticles (void)
 			if (DotProduct(p->org, r_viewforward) >= minparticledist || p->type->orientation == PARTICLE_BEAM)
 			{
 				if (p->type == particletype + pt_decal)
-					R_DrawParticleCallback(p, 0);
+					R_DrawParticle_TransparentCallback(0, i, 0);
 				else
-					R_MeshQueue_AddTransparent(p->org, R_DrawParticleCallback, p, 0);
+					R_MeshQueue_AddTransparent(p->org, R_DrawParticle_TransparentCallback, NULL, i, NULL);
 			}
 		}
 	}
diff --git a/client.h b/client.h
index c52361e2..1f815d72 100644
--- a/client.h
+++ b/client.h
@@ -117,6 +117,12 @@ typedef struct rtlight_s
 	// squared cullradius
 	//vec_t cullradius2;
 
+	// rendering properties, updated each time a light is rendered
+	// this is rtlight->color * d_lightstylevalue
+	vec3_t currentcolor;
+	// this is R_Shadow_Cubemap(rtlight->cubemapname)
+	rtexture_t *currentcubemap;
+
 	// lightmap renderer stuff (remove someday!)
 	// the size of the light
 	vec_t lightmap_cullradius;
diff --git a/gl_rmain.c b/gl_rmain.c
index d1291faa..485b446d 100644
--- a/gl_rmain.c
+++ b/gl_rmain.c
@@ -1281,9 +1281,8 @@ float nomodelcolor4f[6*4] =
 	0.5f, 0.0f, 0.0f, 1.0f
 };
 
-void R_DrawNoModelCallback(const void *calldata1, int calldata2)
+void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
 {
-	const entity_render_t *ent = (entity_render_t *)calldata1;
 	int i;
 	float f1, f2, *c;
 	float color4f[6*4];
@@ -1339,7 +1338,7 @@ void R_DrawNoModelCallback(const void *calldata1, int calldata2)
 void R_DrawNoModel(entity_render_t *ent)
 {
 	//if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
-		R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
+		R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModel_TransparentCallback, ent, 0, r_shadow_rtlight);
 	//else
 	//	R_DrawNoModelCallback(ent, 0);
 }
@@ -1507,7 +1506,6 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
 {
 	// FIXME: identify models using a better check than ent->model->brush.shadowmesh
 	//int lightmode = ((ent->effects & EF_FULLBRIGHT) || ent->model->brush.shadowmesh) ? 0 : 2;
-	float currentalpha;
 
 	{
 		texture_t *texture = t;
@@ -1530,14 +1528,14 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
 	}
 
 	t->currentmaterialflags = t->basematerialflags;
-	currentalpha = ent->alpha;
+	t->currentalpha = ent->alpha;
 	if (t->basematerialflags & MATERIALFLAG_WATERALPHA)
-		currentalpha *= r_wateralpha.value;
+		t->currentalpha *= r_wateralpha.value;
 	if (!(ent->flags & RENDER_LIGHT))
 		t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
 	if (ent->effects & EF_ADDITIVE)
 		t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_TRANSPARENT;
-	else if (currentalpha < 1)
+	else if (t->currentalpha < 1)
 		t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
 	if (ent->effects & EF_NODEPTHTEST)
 		t->currentmaterialflags |= MATERIALFLAG_NODEPTHTEST;
@@ -1586,11 +1584,12 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
 				currentbasetexture = (ent->colormap < 0 && t->skin.merged) ? t->skin.merged : t->skin.base;
 				if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
 				{
-					R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0], ent->colormod[1], ent->colormod[2], currentalpha);
+					// fullbright is not affected by r_lightmapintensity
+					R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0], ent->colormod[1], ent->colormod[2], t->currentalpha);
 					if (ent->colormap >= 0 && t->skin.pants)
-						R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.pants, &t->currenttexmatrix, ent->colormap_pantscolor[0], ent->colormap_pantscolor[1], ent->colormap_pantscolor[2], currentalpha);
+						R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.pants, &t->currenttexmatrix, ent->colormap_pantscolor[0], ent->colormap_pantscolor[1], ent->colormap_pantscolor[2], t->currentalpha);
 					if (ent->colormap >= 0 && t->skin.shirt)
-						R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0], ent->colormap_shirtcolor[1], ent->colormap_shirtcolor[2], currentalpha);
+						R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0], ent->colormap_shirtcolor[1], ent->colormap_shirtcolor[2], t->currentalpha);
 				}
 				else
 				{
@@ -1601,32 +1600,30 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
 					// applied to the color
 					if (ent->model->type == mod_brushq3)
 						colorscale *= r_refdef.lightstylevalue[0] * (1.0f / 256.0f);
-					// transparent and fullbright are not affected by r_lightmapintensity
-					if (!(t->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
-						colorscale *= r_lightmapintensity;
+					colorscale *= r_lightmapintensity;
 					if (r_textureunits.integer >= 2 && gl_combine.integer)
-						R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE_COMBINE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * colorscale, ent->colormod[1] * colorscale, ent->colormod[2] * colorscale, currentalpha);
+						R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE_COMBINE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * colorscale, ent->colormod[1] * colorscale, ent->colormod[2] * colorscale, t->currentalpha);
 					else if ((t->currentmaterialflags & MATERIALFLAG_TRANSPARENT) == 0)
-						R_Texture_AddLayer(t, true, GL_ONE, GL_ZERO, TEXTURELAYERTYPE_LITTEXTURE_MULTIPASS, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * colorscale * 0.5f, ent->colormod[1] * colorscale * 0.5f, ent->colormod[2] * colorscale * 0.5f, currentalpha);
+						R_Texture_AddLayer(t, true, GL_ONE, GL_ZERO, TEXTURELAYERTYPE_LITTEXTURE_MULTIPASS, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * colorscale * 0.5f, ent->colormod[1] * colorscale * 0.5f, ent->colormod[2] * colorscale * 0.5f, t->currentalpha);
 					else
-						R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE_VERTEX, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * colorscale, ent->colormod[1] * colorscale, ent->colormod[2] * colorscale, currentalpha);
+						R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE_VERTEX, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * colorscale, ent->colormod[1] * colorscale, ent->colormod[2] * colorscale, t->currentalpha);
 					if (r_ambient.value >= (1.0f/64.0f))
-						R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * r_ambient.value * (1.0f / 64.0f), ent->colormod[1] * r_ambient.value * (1.0f / 64.0f), ent->colormod[2] * r_ambient.value * (1.0f / 64.0f), currentalpha);
+						R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * r_ambient.value * (1.0f / 64.0f), ent->colormod[1] * r_ambient.value * (1.0f / 64.0f), ent->colormod[2] * r_ambient.value * (1.0f / 64.0f), t->currentalpha);
 					if (ent->colormap >= 0 && t->skin.pants)
 					{
-						R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE_VERTEX, t->skin.pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * colorscale, ent->colormap_pantscolor[1] * colorscale, ent->colormap_pantscolor[2] * colorscale, currentalpha);
+						R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE_VERTEX, t->skin.pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * colorscale, ent->colormap_pantscolor[1] * colorscale, ent->colormap_pantscolor[2] * colorscale, t->currentalpha);
 						if (r_ambient.value >= (1.0f/64.0f))
-							R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * r_ambient.value * (1.0f / 64.0f), ent->colormap_pantscolor[1] * r_ambient.value * (1.0f / 64.0f), ent->colormap_pantscolor[2] * r_ambient.value * (1.0f / 64.0f), currentalpha);
+							R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * r_ambient.value * (1.0f / 64.0f), ent->colormap_pantscolor[1] * r_ambient.value * (1.0f / 64.0f), ent->colormap_pantscolor[2] * r_ambient.value * (1.0f / 64.0f), t->currentalpha);
 					}
 					if (ent->colormap >= 0 && t->skin.shirt)
 					{
-						R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE_VERTEX, t->skin.shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * colorscale, ent->colormap_shirtcolor[1] * colorscale, ent->colormap_shirtcolor[2] * colorscale, currentalpha);
+						R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE_VERTEX, t->skin.shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * colorscale, ent->colormap_shirtcolor[1] * colorscale, ent->colormap_shirtcolor[2] * colorscale, t->currentalpha);
 						if (r_ambient.value >= (1.0f/64.0f))
-							R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * r_ambient.value * (1.0f / 64.0f), ent->colormap_shirtcolor[1] * r_ambient.value * (1.0f / 64.0f), ent->colormap_shirtcolor[2] * r_ambient.value * (1.0f / 64.0f), currentalpha);
+							R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * r_ambient.value * (1.0f / 64.0f), ent->colormap_shirtcolor[1] * r_ambient.value * (1.0f / 64.0f), ent->colormap_shirtcolor[2] * r_ambient.value * (1.0f / 64.0f), t->currentalpha);
 					}
 				}
 				if (t->skin.glow != NULL)
-					R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.glow, &t->currenttexmatrix, 1, 1, 1, currentalpha);
+					R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.glow, &t->currenttexmatrix, 1, 1, 1, t->currentalpha);
 				if (fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
 				{
 					// if this is opaque use alpha blend which will darken the earlier
@@ -1640,7 +1637,7 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
 					// were darkened by fog already, and we should not add fog color
 					// (because the background was not darkened, there is no fog color
 					// that was lost behind it).
-					R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_TRANSPARENT) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->skin.fog, &r_identitymatrix, fogcolor[0], fogcolor[1], fogcolor[2], currentalpha);
+					R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_TRANSPARENT) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->skin.fog, &r_identitymatrix, fogcolor[0], fogcolor[1], fogcolor[2], t->currentalpha);
 				}
 			}
 		}
@@ -2181,10 +2178,9 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
 		qglEnable(GL_CULL_FACE);
 }
 
-static void RSurfShader_Transparent_Callback(const void *calldata1, int calldata2)
+static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
 {
-	const entity_render_t *ent = (entity_render_t *)calldata1;
-	const msurface_t *surface = ent->model->data_surfaces + calldata2;
+	const msurface_t *surface = ent->model->data_surfaces + surfacenumber;
 	vec3_t modelorg;
 	texture_t *texture;
 
@@ -2215,7 +2211,7 @@ void R_QueueTextureSurfaceList(entity_render_t *ent, texture_t *texture, int tex
 				tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
 				tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
 				Matrix4x4_Transform(&ent->matrix, tempcenter, center);
-				R_MeshQueue_AddTransparent(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_vieworigin : center, RSurfShader_Transparent_Callback, ent, surface - ent->model->data_surfaces);
+				R_MeshQueue_AddTransparent(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_vieworigin : center, R_DrawSurface_TransparentCallback, ent, surface - ent->model->data_surfaces, r_shadow_rtlight);
 			}
 		}
 	}
diff --git a/gl_rsurf.c b/gl_rsurf.c
index 786e738b..1ebb0c88 100644
--- a/gl_rsurf.c
+++ b/gl_rsurf.c
@@ -294,12 +294,12 @@ void R_Stain (const vec3_t origin, float radius, int cr1, int cg1, int cb1, int
 =============================================================
 */
 
-static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
+static void R_DrawPortal_Callback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
 {
+	const mportal_t *portal = (mportal_t *)ent;
 	int i;
 	float *v;
 	rmeshstate_t m;
-	const mportal_t *portal = (mportal_t *)calldata1;
 	GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 	GL_DepthMask(false);
 	GL_DepthTest(true);
@@ -309,7 +309,7 @@ static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
 	m.pointer_vertex = varray_vertex3f;
 	R_Mesh_State(&m);
 
-	i = calldata2;
+	i = surfacenumber;
 	GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f),
 			 ((i & 0x0038) >> 3) * (1.0f / 7.0f),
 			 ((i & 0x01C0) >> 6) * (1.0f / 7.0f),
@@ -330,7 +330,7 @@ static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
 // LordHavoc: this is just a nice debugging tool, very slow
 static void R_DrawPortals(void)
 {
-	int i, leafnum;//, portalnum;
+	int i, leafnum;
 	mportal_t *portal;
 	float center[3], f;
 	model_t *model = r_refdef.worldmodel;
@@ -351,8 +351,7 @@ static void R_DrawPortals(void)
 						VectorAdd(center, portal->points[i].position, center);
 					f = ixtable[portal->numpoints];
 					VectorScale(center, f, center);
-					//R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, portal, portalnum);
-					R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, portal, leafnum);
+					R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, (entity_render_t *)portal, leafnum, r_shadow_rtlight);
 				}
 			}
 		}
@@ -603,7 +602,6 @@ void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node)
 				{
 					msurface_t *surface = info->model->data_surfaces + surfaceindex;
 					if (BoxesOverlap(info->lightmins, info->lightmaxs, surface->mins, surface->maxs))
-					if ((surface->texture->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT)) == MATERIALFLAG_WALL)
 					{
 						int triangleindex, t;
 						const int *e;
@@ -768,9 +766,23 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin,
 	}
 }
 
+static void R_Q1BSP_DrawLight_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+{
+	msurface_t *surface = ent->model->data_surfaces + surfacenumber;
+	texture_t *texture = surface->texture;
+	R_UpdateTextureInfo(ent, texture);
+	texture = texture->currentframe;
+	R_Shadow_RenderMode_Begin();
+	R_Shadow_RenderMode_ActiveLight((rtlight_t *)rtlight);
+	R_Shadow_RenderMode_Lighting(false, true);
+	R_Shadow_SetupEntityLight(ent);
+	R_Shadow_RenderSurfacesLighting(ent, texture, 1, &surface);
+	R_Shadow_RenderMode_End();
+}
+
 #define RSURF_MAX_BATCHSURFACES 1024
 
-void R_Q1BSP_DrawLight(entity_render_t *ent, float *lightcolorbase, float *lightcolorpants, float *lightcolorshirt, int numsurfaces, const int *surfacelist)
+void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surfacelist)
 {
 	model_t *model = ent->model;
 	msurface_t *surface;
@@ -779,14 +791,9 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, float *lightcolorbase, float *light
 	msurface_t *batchsurfacelist[RSURF_MAX_BATCHSURFACES];
 	vec3_t modelorg;
 	texture_t *tex;
-	rtexture_t *basetexture = NULL;
-	rtexture_t *glosstexture = NULL;
-	float specularscale = 0;
 	qboolean skip;
 	if (r_drawcollisionbrushes.integer >= 2)
 		return;
-	if (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt) < 0.0001)
-		return;
 	R_UpdateAllTextureInfo(ent);
 	Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
 	tex = NULL;
@@ -803,46 +810,50 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, float *lightcolorbase, float *light
 		{
 			if (batchnumsurfaces > 0)
 			{
-				R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
+				if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
+				{
+					int batchsurfaceindex;
+					for (batchsurfaceindex = 0;batchsurfaceindex < batchnumsurfaces;batchsurfaceindex++)
+					{
+						msurface_t *batchsurface = batchsurfacelist[batchsurfaceindex];
+						vec3_t tempcenter, center;
+						tempcenter[0] = (batchsurface->mins[0] + batchsurface->maxs[0]) * 0.5f;
+						tempcenter[1] = (batchsurface->mins[1] + batchsurface->maxs[1]) * 0.5f;
+						tempcenter[2] = (batchsurface->mins[2] + batchsurface->maxs[2]) * 0.5f;
+						Matrix4x4_Transform(&ent->matrix, tempcenter, center);
+						R_MeshQueue_AddTransparent(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_vieworigin : center, R_Q1BSP_DrawLight_TransparentCallback, ent, batchsurface - ent->model->data_surfaces, r_shadow_rtlight);
+					}
+				}
+				else
+					R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist);
 				batchnumsurfaces = 0;
 			}
 			tex = surface->texture;
 			texture = surface->texture->currentframe;
-			// FIXME: transparent surfaces need to be lit later
-			skip = (texture->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_TRANSPARENT)) != MATERIALFLAG_WALL;
+			skip = (texture->currentmaterialflags & MATERIALFLAG_SKY) != 0;
 			if (skip)
 				continue;
-			if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
-				qglDisable(GL_CULL_FACE);
-			else
-				qglEnable(GL_CULL_FACE);
-			glosstexture = r_texture_black;
-			specularscale = 0;
-			if (texture->skin.gloss)
-			{
-				if (r_shadow_gloss.integer >= 1 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
-				{
-					glosstexture = texture->skin.gloss;
-					specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
-				}
-			}
-			else
-			{
-				if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
-				{
-					glosstexture = r_texture_white;
-					specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
-				}
-			}
-			basetexture = (ent->colormap < 0 && texture->skin.merged) ? texture->skin.merged : texture->skin.base;
-			if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
-				skip = true;
 		}
 		if (!skip && surface->num_triangles)
 		{
 			if (batchnumsurfaces == RSURF_MAX_BATCHSURFACES)
 			{
-				R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
+				if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
+				{
+					int batchsurfaceindex;
+					for (batchsurfaceindex = 0;batchsurfaceindex < batchnumsurfaces;batchsurfaceindex++)
+					{
+						msurface_t *batchsurface = batchsurfacelist[batchsurfaceindex];
+						vec3_t tempcenter, center;
+						tempcenter[0] = (batchsurface->mins[0] + batchsurface->maxs[0]) * 0.5f;
+						tempcenter[1] = (batchsurface->mins[1] + batchsurface->maxs[1]) * 0.5f;
+						tempcenter[2] = (batchsurface->mins[2] + batchsurface->maxs[2]) * 0.5f;
+						Matrix4x4_Transform(&ent->matrix, tempcenter, center);
+						R_MeshQueue_AddTransparent(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_vieworigin : center, R_Q1BSP_DrawLight_TransparentCallback, ent, batchsurface - ent->model->data_surfaces, r_shadow_rtlight);
+					}
+				}
+				else
+					R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist);
 				batchnumsurfaces = 0;
 			}
 			batchsurfacelist[batchnumsurfaces++] = surface;
@@ -850,7 +861,7 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, float *lightcolorbase, float *light
 	}
 	if (batchnumsurfaces > 0)
 	{
-		R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
+		R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist);
 		batchnumsurfaces = 0;
 	}
 	qglEnable(GL_CULL_FACE);
diff --git a/meshqueue.c b/meshqueue.c
index b176bf4d..a9b7ac0b 100644
--- a/meshqueue.c
+++ b/meshqueue.c
@@ -9,9 +9,10 @@ cvar_t r_meshqueue_sort = {0, "r_meshqueue_sort", "0"};
 typedef struct meshqueue_s
 {
 	struct meshqueue_s *next;
-	void (*callback)(const void *data1, int data2);
-	const void *data1;
-	int data2;
+	void (*callback)(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight);
+	const entity_render_t *ent;
+	int surfacenumber;
+	const rtlight_t *rtlight;
 	float dist;
 }
 meshqueue_t;
@@ -40,7 +41,7 @@ void R_MeshQueue_Render(void)
 	if (!mq_count)
 		return;
 	for (mq = mq_listhead;mq;mq = mq->next)
-		mq->callback(mq->data1, mq->data2);
+		mq->callback(mq->ent, mq->surfacenumber, mq->rtlight);
 	mq_count = 0;
 	mq_listhead = NULL;
 }
@@ -58,20 +59,21 @@ static void R_MeshQueue_EnlargeTransparentArray(int newtotal)
 	mqt_total = newtotal;
 }
 
-void R_MeshQueue_Add(void (*callback)(const void *data1, int data2), const void *data1, int data2)
+void R_MeshQueue_Add(void (*callback)(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
 {
 	meshqueue_t *mq, **mqnext;
 	if (r_meshqueue_immediaterender.integer)
 	{
-		callback(data1, data2);
+		callback(ent, surfacenumber, rtlight);
 		return;
 	}
 	if (mq_count >= mq_total)
 		R_MeshQueue_Render();
 	mq = &mq_array[mq_count++];
 	mq->callback = callback;
-	mq->data1 = data1;
-	mq->data2 = data2;
+	mq->ent = ent;
+	mq->surfacenumber = surfacenumber;
+	mq->rtlight = rtlight;
 
 	if (r_meshqueue_sort.integer)
 	{
@@ -80,12 +82,17 @@ void R_MeshQueue_Add(void (*callback)(const void *data1, int data2), const void
 		{
 			if (mq->callback == (*mqnext)->callback)
 			{
-				if (mq->data1 == (*mqnext)->data1)
+				if (mq->ent == (*mqnext)->ent)
 				{
-					if (mq->data2 <= (*mqnext)->data2)
+					if (mq->surfacenumber == (*mqnext)->surfacenumber)
+					{
+						if (mq->rtlight <= (*mqnext)->rtlight)
+							break;
+					}
+					else if (mq->surfacenumber < (*mqnext)->surfacenumber)
 						break;
 				}
-				else if (mq->data1 < (*mqnext)->data1)
+				else if (mq->ent < (*mqnext)->ent)
 					break;
 			}
 			else if (mq->callback < (*mqnext)->callback)
@@ -101,15 +108,16 @@ void R_MeshQueue_Add(void (*callback)(const void *data1, int data2), const void
 	*mqnext = mq;
 }
 
-void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const void *data1, int data2), const void *data1, int data2)
+void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
 {
 	meshqueue_t *mq;
 	if (mqt_count >= mqt_total)
 		R_MeshQueue_EnlargeTransparentArray(mqt_total + 100);
 	mq = &mqt_array[mqt_count++];
 	mq->callback = callback;
-	mq->data1 = data1;
-	mq->data2 = data2;
+	mq->ent = ent;
+	mq->surfacenumber = surfacenumber;
+	mq->rtlight = rtlight;
 	mq->dist = DotProduct(center, r_viewforward) - mqt_viewplanedist;
 	mq->next = NULL;
 	mqt_viewmaxdist = max(mqt_viewmaxdist, mq->dist);
@@ -143,7 +151,7 @@ void R_MeshQueue_RenderTransparent(void)
 	for (i = 4095;i >= 0;i--)
 		if (hash[i])
 			for (mqt = hash[i];mqt;mqt = mqt->next)
-				mqt->callback(mqt->data1, mqt->data2);
+				mqt->callback(mqt->ent, mqt->surfacenumber, mqt->rtlight);
 	mqt_count = 0;
 }
 
diff --git a/meshqueue.h b/meshqueue.h
index ed587e14..fd6cce45 100644
--- a/meshqueue.h
+++ b/meshqueue.h
@@ -3,8 +3,8 @@
 #define MESHQUEUE_H
 
 void R_MeshQueue_Init(void);
-void R_MeshQueue_Add(void (*callback)(const void *data1, int data2), const void *data1, int data2);
-void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const void *data1, int data2), const void *data1, int data2);
+void R_MeshQueue_Add(void (*callback)(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight);
+void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight);
 void R_MeshQueue_BeginScene(void);
 void R_MeshQueue_Render(void);
 void R_MeshQueue_RenderTransparent(void);
diff --git a/model_shared.h b/model_shared.h
index 60c315fc..aa64aa20 100644
--- a/model_shared.h
+++ b/model_shared.h
@@ -203,6 +203,8 @@ typedef struct texture_s
 	// (this is an optimization in the renderer)
 	int animated;
 
+	// the current alpha of this texture (may be affected by r_wateralpha)
+	float currentalpha;
 	// the current texture frame in animation
 	struct texture_s *currentframe;
 	// current texture transform matrix (used for water scrolling)
@@ -555,7 +557,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)
-	void(*DrawLight)(struct entity_render_s *ent, vec3_t lightcolorbase, vec3_t lightcolorpants, vec3_t lightcolorshirt, int numsurfaces, const int *surfacelist);
+	void(*DrawLight)(struct entity_render_s *ent, 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 some types of model
@@ -655,7 +657,7 @@ void R_Q1BSP_Draw(struct entity_render_s *ent);
 void R_Q1BSP_GetLightInfo(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer);
 void R_Q1BSP_CompileShadowVolume(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist);
 void R_Q1BSP_DrawShadowVolume(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs);
-void R_Q1BSP_DrawLight(struct entity_render_s *ent, vec3_t lightcolorbase, vec3_t lightcolorpants, vec3_t lightcolorshirt, int numsurfaces, const int *surfacelist);
+void R_Q1BSP_DrawLight(struct entity_render_s *ent, int numsurfaces, const int *surfacelist);
 
 // alias models
 struct frameblend_s;
diff --git a/r_explosion.c b/r_explosion.c
index 7bf4e183..000fc692 100644
--- a/r_explosion.c
+++ b/r_explosion.c
@@ -180,13 +180,12 @@ void R_NewExplosion(vec3_t org)
 	}
 }
 
-static void R_DrawExplosionCallback(const void *calldata1, int calldata2)
+static void R_DrawExplosion_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
 {
+	const explosion_t *e = explosion + surfacenumber;
 	int numtriangles, numverts;
 	float alpha;
 	rmeshstate_t m;
-	const explosion_t *e;
-	e = (explosion_t *)calldata1;
 
 	GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
 	GL_DepthMask(false);
@@ -258,6 +257,6 @@ void R_DrawExplosions(void)
 		return;
 	for (i = 0;i < MAX_EXPLOSIONS;i++)
 		if (r_refdef.time < explosion[i].endtime)
-			R_MeshQueue_AddTransparent(explosion[i].origin, R_DrawExplosionCallback, &explosion[i], 0);
+			R_MeshQueue_AddTransparent(explosion[i].origin, R_DrawExplosion_TransparentCallback, NULL, i, NULL);
 }
 
diff --git a/r_lightning.c b/r_lightning.c
index c11ad9fd..4309170f 100644
--- a/r_lightning.c
+++ b/r_lightning.c
@@ -229,9 +229,9 @@ void R_FogLightningBeam_Vertex3f_Color4f(const float *v, float *c, int numverts,
 
 float beamrepeatscale;
 
-void R_DrawLightningBeamCallback(const void *calldata1, int calldata2)
+void R_DrawLightningBeam_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
 {
-	const beam_t *b = (beam_t *)calldata1;
+	const beam_t *b = cl_beams + surfacenumber;
 	rmeshstate_t m;
 	vec3_t beamdir, right, up, offset;
 	float length, t1, t2;
@@ -343,7 +343,7 @@ void R_DrawLightningBeams(void)
 		{
 			VectorAdd(b->start, b->end, org);
 			VectorScale(org, 0.5f, org);
-			R_MeshQueue_AddTransparent(org, R_DrawLightningBeamCallback, b, 0);
+			R_MeshQueue_AddTransparent(org, R_DrawLightningBeam_TransparentCallback, NULL, i, NULL);
 		}
 	}
 }
diff --git a/r_shadow.c b/r_shadow.c
index c1f71e14..1631a3ad 100644
--- a/r_shadow.c
+++ b/r_shadow.c
@@ -142,20 +142,22 @@ demonstrated by the game Doom3.
 
 extern void R_Shadow_EditLights_Init(void);
 
-typedef enum r_shadowstage_e
+typedef enum r_shadow_rendermode_e
 {
-	R_SHADOWSTAGE_NONE,
-	R_SHADOWSTAGE_STENCIL,
-	R_SHADOWSTAGE_STENCILTWOSIDE,
-	R_SHADOWSTAGE_LIGHT_VERTEX,
-	R_SHADOWSTAGE_LIGHT_DOT3,
-	R_SHADOWSTAGE_LIGHT_GLSL,
-	R_SHADOWSTAGE_VISIBLEVOLUMES,
-	R_SHADOWSTAGE_VISIBLELIGHTING,
+	R_SHADOW_RENDERMODE_NONE,
+	R_SHADOW_RENDERMODE_STENCIL,
+	R_SHADOW_RENDERMODE_STENCILTWOSIDE,
+	R_SHADOW_RENDERMODE_LIGHT_VERTEX,
+	R_SHADOW_RENDERMODE_LIGHT_DOT3,
+	R_SHADOW_RENDERMODE_LIGHT_GLSL,
+	R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
+	R_SHADOW_RENDERMODE_VISIBLELIGHTING,
 }
-r_shadowstage_t;
+r_shadow_rendermode_t;
 
-r_shadowstage_t r_shadowstage = R_SHADOWSTAGE_NONE;
+r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
+r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
+r_shadow_rendermode_t r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_NONE;
 
 mempool_t *r_shadow_mempool;
 
@@ -991,7 +993,7 @@ void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *verte
 	m.pointer_vertex = vertex3f;
 	R_Mesh_State(&m);
 	GL_LockArrays(0, numvertices);
-	if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
+	if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
 	{
 		// decrement stencil if backface is behind depthbuffer
 		qglCullFace(GL_BACK); // quake is backwards, this culls front faces
@@ -1072,32 +1074,24 @@ void R_Shadow_ValidateCvars(void)
 
 // light currently being rendered
 rtlight_t *r_shadow_rtlight;
-// light filter cubemap being used by the light
-static rtexture_t *r_shadow_lightcubemap;
 
 // this is the location of the eye in entity space
-static vec3_t r_shadow_entityeyeorigin;
+vec3_t r_shadow_entityeyeorigin;
 // this is the location of the light in entity space
-static vec3_t r_shadow_entitylightorigin;
+vec3_t r_shadow_entitylightorigin;
 // this transforms entity coordinates to light filter cubemap coordinates
 // (also often used for other purposes)
-static matrix4x4_t r_shadow_entitytolight;
+matrix4x4_t r_shadow_entitytolight;
 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
 // of attenuation texturing in full 3D (Z result often ignored)
-static matrix4x4_t r_shadow_entitytoattenuationxyz;
+matrix4x4_t r_shadow_entitytoattenuationxyz;
 // this transforms only the Z to S, and T is always 0.5
-static matrix4x4_t r_shadow_entitytoattenuationz;
-// rtlight->color * r_refdef.lightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormod * ent->alpha
-static vec3_t r_shadow_entitylightcolorbase;
-// rtlight->color * r_refdef.lightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormap_pantscolor * ent->alpha
-static vec3_t r_shadow_entitylightcolorpants;
-// rtlight->color * r_refdef.lightstylevalue[rtlight->style] / 256 * r_shadow_lightintensityscale.value * ent->colormap_shirtcolor * ent->alpha
-static vec3_t r_shadow_entitylightcolorshirt;
+matrix4x4_t r_shadow_entitytoattenuationz;
 
 static int r_shadow_lightpermutation;
 static int r_shadow_lightprog;
 
-void R_Shadow_Stage_Begin(void)
+void R_Shadow_RenderMode_Begin(void)
 {
 	rmeshstate_t m;
 
@@ -1110,42 +1104,55 @@ void R_Shadow_Stage_Begin(void)
 		R_Shadow_MakeTextures();
 
 	memset(&m, 0, sizeof(m));
+	R_Mesh_State(&m);
 	GL_BlendFunc(GL_ONE, GL_ZERO);
 	GL_DepthMask(false);
 	GL_DepthTest(true);
-	R_Mesh_State(&m);
 	GL_Color(0, 0, 0, 1);
 	qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
 	qglEnable(GL_CULL_FACE);
 	GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
-	r_shadowstage = R_SHADOWSTAGE_NONE;
+
+	r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
+
+	if (gl_ext_stenciltwoside.integer)
+		r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
+	else
+		r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
+
+	if (r_shadow_glsl.integer && r_shadow_program_light[0])
+		r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
+	else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
+		r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
+	else
+		r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
 }
 
-void R_Shadow_Stage_ActiveLight(rtlight_t *rtlight)
+void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
 {
 	r_shadow_rtlight = rtlight;
 }
 
-void R_Shadow_Stage_Reset(void)
+void R_Shadow_RenderMode_Reset(void)
 {
 	rmeshstate_t m;
-	if (gl_support_stenciltwoside)
-		qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
-	if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
+	if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
 	{
 		qglUseProgramObjectARB(0);
-		// HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering in 6xxx drivers
+		// HACK HACK HACK: work around for bug in NVIDIAI 6xxx drivers that causes GL_OUT_OF_MEMORY and/or software rendering
 		qglBegin(GL_TRIANGLES);
 		qglEnd();
 		CHECKGLERROR
 	}
+	else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
+		qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
 	memset(&m, 0, sizeof(m));
 	R_Mesh_State(&m);
 }
 
-void R_Shadow_Stage_StencilShadowVolumes(void)
+void R_Shadow_RenderMode_StencilShadowVolumes(void)
 {
-	R_Shadow_Stage_Reset();
+	R_Shadow_RenderMode_Reset();
 	GL_Color(1, 1, 1, 1);
 	GL_ColorMask(0, 0, 0, 0);
 	GL_BlendFunc(GL_ONE, GL_ZERO);
@@ -1163,9 +1170,9 @@ void R_Shadow_Stage_StencilShadowVolumes(void)
 	qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
 	qglEnable(GL_STENCIL_TEST);
 	qglStencilFunc(GL_ALWAYS, 128, ~0);
-	if (gl_ext_stenciltwoside.integer)
+	r_shadow_rendermode = r_shadow_shadowingrendermode;
+	if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
 	{
-		r_shadowstage = R_SHADOWSTAGE_STENCILTWOSIDE;
 		qglDisable(GL_CULL_FACE);
 		qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
 		qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
@@ -1177,7 +1184,6 @@ void R_Shadow_Stage_StencilShadowVolumes(void)
 	}
 	else
 	{
-		r_shadowstage = R_SHADOWSTAGE_STENCIL;
 		qglEnable(GL_CULL_FACE);
 		qglStencilMask(~0);
 		// this is changed by every shadow render so its value here is unimportant
@@ -1187,10 +1193,9 @@ void R_Shadow_Stage_StencilShadowVolumes(void)
 	renderstats.lights_clears++;
 }
 
-void R_Shadow_Stage_Lighting(int stenciltest)
+void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
 {
-	rmeshstate_t m;
-	R_Shadow_Stage_Reset();
+	R_Shadow_RenderMode_Reset();
 	GL_BlendFunc(GL_ONE, GL_ONE);
 	GL_DepthMask(false);
 	GL_DepthTest(true);
@@ -1198,10 +1203,13 @@ void R_Shadow_Stage_Lighting(int stenciltest)
 	//qglDisable(GL_POLYGON_OFFSET_FILL);
 	GL_Color(1, 1, 1, 1);
 	GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
-	qglDepthFunc(GL_EQUAL);
+	if (transparent)
+		qglDepthFunc(GL_LEQUAL);
+	else
+		qglDepthFunc(GL_EQUAL);
 	qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
 	qglEnable(GL_CULL_FACE);
-	if (r_shadowstage == R_SHADOWSTAGE_STENCIL || r_shadowstage == R_SHADOWSTAGE_STENCILTWOSIDE)
+	if (stenciltest)
 		qglEnable(GL_STENCIL_TEST);
 	else
 		qglDisable(GL_STENCIL_TEST);
@@ -1210,22 +1218,21 @@ void R_Shadow_Stage_Lighting(int stenciltest)
 	// only draw light where this geometry was already rendered AND the
 	// stencil is 128 (values other than this mean shadow)
 	qglStencilFunc(GL_EQUAL, 128, ~0);
-	if (r_shadow_glsl.integer && r_shadow_program_light[0])
+	r_shadow_rendermode = r_shadow_lightingrendermode;
+	// do global setup needed for the chosen lighting mode
+	if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
 	{
-		r_shadowstage = R_SHADOWSTAGE_LIGHT_GLSL;
-		memset(&m, 0, sizeof(m));
-		m.pointer_vertex = varray_vertex3f;
-		m.pointer_texcoord[0] = varray_texcoord2f[0];
-		m.pointer_texcoord3f[1] = varray_svector3f;
-		m.pointer_texcoord3f[2] = varray_tvector3f;
-		m.pointer_texcoord3f[3] = varray_normal3f;
-		m.tex[0] = R_GetTexture(r_texture_blanknormalmap); // normal
-		m.tex[1] = R_GetTexture(r_texture_white); // diffuse
-		m.tex[2] = R_GetTexture(r_texture_white); // gloss
-		m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap); // light filter
-		m.tex[4] = R_GetTexture(r_texture_fogattenuation); // fog
-		//m.texmatrix[3] = r_shadow_entitytolight; // light filter matrix
-		R_Mesh_State(&m);
+		R_Mesh_VertexPointer(varray_vertex3f);
+		R_Mesh_TexCoordPointer(0, 2, varray_texcoord2f[0]);
+		R_Mesh_TexCoordPointer(1, 3, varray_svector3f);
+		R_Mesh_TexCoordPointer(2, 3, varray_tvector3f);
+		R_Mesh_TexCoordPointer(3, 3, varray_normal3f);
+		R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
+		R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
+		R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
+		R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
+		R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
+		//R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
 		GL_BlendFunc(GL_ONE, GL_ONE);
 		GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
 		CHECKGLERROR
@@ -1237,7 +1244,7 @@ void R_Shadow_Stage_Lighting(int stenciltest)
 			r_shadow_lightpermutation |= SHADERPERMUTATION_FOG;
 		if (r_shadow_rtlight->specularscale && r_shadow_gloss.integer >= 1 && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR])
 			r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR;
-		if (r_shadow_lightcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
+		if (r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER])
 			r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER;
 		if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING])
 			r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING;
@@ -1259,7 +1266,7 @@ void R_Shadow_Stage_Lighting(int stenciltest)
 			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, "LightColor"), r_shadow_entitylightcolorbase[0], r_shadow_entitylightcolorbase[1], r_shadow_entitylightcolorbase[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))
 		//{
@@ -1271,15 +1278,11 @@ void R_Shadow_Stage_Lighting(int stenciltest)
 			qglUniform1fARB(qglGetUniformLocationARB(r_shadow_lightprog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
 		}
 	}
-	else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
-		r_shadowstage = R_SHADOWSTAGE_LIGHT_DOT3;
-	else
-		r_shadowstage = R_SHADOWSTAGE_LIGHT_VERTEX;
 }
 
-void R_Shadow_Stage_VisibleShadowVolumes(void)
+void R_Shadow_RenderMode_VisibleShadowVolumes(void)
 {
-	R_Shadow_Stage_Reset();
+	R_Shadow_RenderMode_Reset();
 	GL_BlendFunc(GL_ONE, GL_ONE);
 	GL_DepthMask(false);
 	GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
@@ -1290,32 +1293,35 @@ void R_Shadow_Stage_VisibleShadowVolumes(void)
 	qglCullFace(GL_FRONT); // this culls back
 	qglDisable(GL_CULL_FACE);
 	qglDisable(GL_STENCIL_TEST);
-	r_shadowstage = R_SHADOWSTAGE_VISIBLEVOLUMES;
+	r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
 }
 
-void R_Shadow_Stage_VisibleLighting(int stenciltest)
+void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
 {
-	R_Shadow_Stage_Reset();
+	R_Shadow_RenderMode_Reset();
 	GL_BlendFunc(GL_ONE, GL_ONE);
 	GL_DepthMask(false);
 	GL_DepthTest(r_shadow_visiblelighting.integer < 2);
 	qglPolygonOffset(0, 0);
 	GL_Color(0.1, 0.0125, 0, 1);
 	GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
-	qglDepthFunc(GL_EQUAL);
+	if (transparent)
+		qglDepthFunc(GL_LEQUAL);
+	else
+		qglDepthFunc(GL_EQUAL);
 	qglCullFace(GL_FRONT); // this culls back
 	qglEnable(GL_CULL_FACE);
 	if (stenciltest)
 		qglEnable(GL_STENCIL_TEST);
 	else
 		qglDisable(GL_STENCIL_TEST);
-	r_shadowstage = R_SHADOWSTAGE_VISIBLELIGHTING;
+	r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
 }
 
-void R_Shadow_Stage_End(void)
+void R_Shadow_RenderMode_End(void)
 {
-	R_Shadow_Stage_Reset();
-	R_Shadow_Stage_ActiveLight(NULL);
+	R_Shadow_RenderMode_Reset();
+	R_Shadow_RenderMode_ActiveLight(NULL);
 	GL_BlendFunc(GL_ONE, GL_ZERO);
 	GL_DepthMask(true);
 	GL_DepthTest(true);
@@ -1326,13 +1332,14 @@ void R_Shadow_Stage_End(void)
 	GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
 	qglDepthFunc(GL_LEQUAL);
 	qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
+	qglEnable(GL_CULL_FACE);
 	qglDisable(GL_STENCIL_TEST);
 	qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
 	if (gl_support_stenciltwoside)
 		qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
 	qglStencilMask(~0);
 	qglStencilFunc(GL_ALWAYS, 128, ~0);
-	r_shadowstage = R_SHADOWSTAGE_NONE;
+	r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
 }
 
 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
@@ -1431,7 +1438,7 @@ extern float *rsurface_tvector3f;
 extern float *rsurface_normal3f;
 extern void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg);
 
-static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor, float reduce, const vec3_t modelorg)
+static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor, float reduce)
 {
 	int numverts = surface->num_vertices;
 	float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
@@ -1452,7 +1459,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_
 				color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) - reduce;
 				if (fogenabled)
 				{
-					float f = VERTEXFOGTABLE(VectorDistance(v, modelorg));
+					float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
 					VectorScale(color4f, f, color4f);
 				}
 			}
@@ -1485,7 +1492,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_
 				}
 				if (fogenabled)
 				{
-					float f = VERTEXFOGTABLE(VectorDistance(v, modelorg));
+					float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
 					VectorScale(color4f, f, color4f);
 				}
 			}
@@ -1519,7 +1526,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_
 				}
 				if (fogenabled)
 				{
-					float f = VERTEXFOGTABLE(VectorDistance(v, modelorg));
+					float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
 					VectorScale(color4f, f, color4f);
 				}
 			}
@@ -1594,7 +1601,7 @@ static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out3f, int numve
 	}
 }
 
-static void R_Shadow_RenderSurfacesLighting_VisibleLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg)
+static void R_Shadow_RenderSurfacesLighting_VisibleLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale)
 {
 	// used to display how many times a surface is lit for level design purposes
 	int surfacelistindex;
@@ -1614,14 +1621,14 @@ static void R_Shadow_RenderSurfacesLighting_VisibleLighting(const entity_render_
 	for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
 	{
 		const msurface_t *surface = surfacelist[surfacelistindex];
-		RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+		RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
 		GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
 		R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);
 		GL_LockArrays(0, 0);
 	}
 }
 
-static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg)
+static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale)
 {
 	// ARB2 GLSL shader path (GFFX5200, Radeon 9500)
 	int surfacelistindex;
@@ -1631,9 +1638,9 @@ static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *en
 	qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
 	// TODO: add direct pants/shirt rendering
 	if (dopants)
-		R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorpants, vec3_origin, vec3_origin, pantstexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
+		R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorpants, vec3_origin, vec3_origin, pantstexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0);
 	if (doshirt)
-		R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
+		R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0);
 	if (!dobase && !dospecular)
 		return;
 	R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
@@ -1649,7 +1656,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *en
 	{
 		const msurface_t *surface = surfacelist[surfacelistindex];
 		const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
-		RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+		RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
 		if (!rsurface_svector3f)
 		{
 			rsurface_svector3f = varray_svector3f;
@@ -1667,7 +1674,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *en
 	}
 }
 
-static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg)
+static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale)
 {
 	// ARB path (any Geforce, any Radeon)
 	int surfacelistindex;
@@ -1683,16 +1690,16 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 	qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
 	// TODO: add direct pants/shirt rendering
 	if (doambientpants || dodiffusepants)
-		R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorpants, vec3_origin, vec3_origin, pantstexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
+		R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorpants, vec3_origin, vec3_origin, pantstexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0);
 	if (doambientshirt || dodiffuseshirt)
-		R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
+		R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0);
 	if (!doambientbase && !dodiffusebase && !dospecular)
 		return;
 	for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
 	{
 		const msurface_t *surface = surfacelist[surfacelistindex];
 		const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
-		RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+		RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
 		if (!rsurface_svector3f)
 		{
 			rsurface_svector3f = varray_svector3f;
@@ -1711,7 +1718,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 			// performed to get more brightness than otherwise possible.
 			//
 			// Limit mult to 64 for sanity sake.
-			if (r_shadow_texture3d.integer && r_shadow_lightcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
+			if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
 			{
 				// 3 3D combine path (Geforce3, Radeon 8500)
 				memset(&m, 0, sizeof(m));
@@ -1727,7 +1734,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 				m.tex[1] = R_GetTexture(basetexture);
 				m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
 				m.texmatrix[1] = texture->currenttexmatrix;
-				m.texcubemap[2] = R_GetTexture(r_shadow_lightcubemap);
+				m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
 				m.pointer_texcoord3f[2] = rsurface_vertex3f;
 				m.texmatrix[2] = r_shadow_entitytolight;
@@ -1737,7 +1744,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 #endif
 				GL_BlendFunc(GL_ONE, GL_ONE);
 			}
-			else if (r_shadow_texture3d.integer && r_shadow_lightcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
+			else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
 			{
 				// 2 3D combine path (Geforce3, original Radeon)
 				memset(&m, 0, sizeof(m));
@@ -1755,7 +1762,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 				m.texmatrix[1] = texture->currenttexmatrix;
 				GL_BlendFunc(GL_ONE, GL_ONE);
 			}
-			else if (r_textureunits.integer >= 4 && r_shadow_lightcubemap != r_texture_whitecube)
+			else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
 			{
 				// 4 2D combine path (Geforce3, Radeon 8500)
 				memset(&m, 0, sizeof(m));
@@ -1779,9 +1786,9 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 				m.tex[2] = R_GetTexture(basetexture);
 				m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
 				m.texmatrix[2] = texture->currenttexmatrix;
-				if (r_shadow_lightcubemap != r_texture_whitecube)
+				if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
 				{
-					m.texcubemap[3] = R_GetTexture(r_shadow_lightcubemap);
+					m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
 					m.pointer_texcoord3f[3] = rsurface_vertex3f;
 					m.texmatrix[3] = r_shadow_entitytolight;
@@ -1792,7 +1799,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 				}
 				GL_BlendFunc(GL_ONE, GL_ONE);
 			}
-			else if (r_textureunits.integer >= 3 && r_shadow_lightcubemap == r_texture_whitecube)
+			else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
 			{
 				// 3 2D combine path (Geforce3, original Radeon)
 				memset(&m, 0, sizeof(m));
@@ -1851,9 +1858,9 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 				m.tex[0] = R_GetTexture(basetexture);
 				m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
 				m.texmatrix[0] = texture->currenttexmatrix;
-				if (r_shadow_lightcubemap != r_texture_whitecube)
+				if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
 				{
-					m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
+					m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
 					m.pointer_texcoord3f[1] = rsurface_vertex3f;
 					m.texmatrix[1] = r_shadow_entitytolight;
@@ -1920,9 +1927,9 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 				m.tex[0] = R_GetTexture(basetexture);
 				m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
 				m.texmatrix[0] = texture->currenttexmatrix;
-				if (r_shadow_lightcubemap != r_texture_whitecube)
+				if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
 				{
-					m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
+					m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
 					m.pointer_texcoord3f[1] = rsurface_vertex3f;
 					m.texmatrix[1] = r_shadow_entitytolight;
@@ -1933,7 +1940,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 				}
 				GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
 			}
-			else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube)
+			else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
 			{
 				// 1/2/2 3D combine path (original Radeon)
 				memset(&m, 0, sizeof(m));
@@ -1974,9 +1981,9 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 				m.tex[0] = R_GetTexture(basetexture);
 				m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
 				m.texmatrix[0] = texture->currenttexmatrix;
-				if (r_shadow_lightcubemap != r_texture_whitecube)
+				if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
 				{
-					m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
+					m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
 					m.pointer_texcoord3f[1] = rsurface_vertex3f;
 					m.texmatrix[1] = r_shadow_entitytolight;
@@ -1987,7 +1994,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 				}
 				GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
 			}
-			else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube)
+			else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
 			{
 				// 2/2 3D combine path (original Radeon)
 				memset(&m, 0, sizeof(m));
@@ -2063,9 +2070,9 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 				m.tex[0] = R_GetTexture(basetexture);
 				m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
 				m.texmatrix[0] = texture->currenttexmatrix;
-				if (r_shadow_lightcubemap != r_texture_whitecube)
+				if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
 				{
-					m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
+					m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
 					m.pointer_texcoord3f[1] = rsurface_vertex3f;
 					m.texmatrix[1] = r_shadow_entitytolight;
@@ -2125,9 +2132,9 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 				m.tex[0] = R_GetTexture(basetexture);
 				m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
 				m.texmatrix[0] = texture->currenttexmatrix;
-				if (r_shadow_lightcubemap != r_texture_whitecube)
+				if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
 				{
-					m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
+					m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
 					m.pointer_texcoord3f[1] = rsurface_vertex3f;
 					m.texmatrix[1] = r_shadow_entitytolight;
@@ -2157,7 +2164,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 			{
 				colorscale = specularscale;
 				GL_Color(1,1,1,1);
-				if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
+				if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
 				{
 					// 2/0/0/1/2 3D combine blendsquare path
 					memset(&m, 0, sizeof(m));
@@ -2212,9 +2219,9 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 					m.tex[0] = R_GetTexture(glosstexture);
 					m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
 					m.texmatrix[0] = texture->currenttexmatrix;
-					if (r_shadow_lightcubemap != r_texture_whitecube)
+					if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
 					{
-						m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
+						m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
 						m.pointer_texcoord3f[1] = rsurface_vertex3f;
 						m.texmatrix[1] = r_shadow_entitytolight;
@@ -2225,7 +2232,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 					}
 					GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
 				}
-				else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_lightcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
+				else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
 				{
 					// 2/0/0/2 3D combine blendsquare path
 					memset(&m, 0, sizeof(m));
@@ -2337,9 +2344,9 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 					m.tex[0] = R_GetTexture(glosstexture);
 					m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
 					m.texmatrix[0] = texture->currenttexmatrix;
-					if (r_shadow_lightcubemap != r_texture_whitecube)
+					if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
 					{
-						m.texcubemap[1] = R_GetTexture(r_shadow_lightcubemap);
+						m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
 #ifdef USETEXMATRIX
 						m.pointer_texcoord3f[1] = rsurface_vertex3f;
 						m.texmatrix[1] = r_shadow_entitytolight;
@@ -2365,7 +2372,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *en
 	}
 }
 
-static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg)
+static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale)
 {
 	int surfacelistindex;
 	int renders;
@@ -2380,9 +2387,9 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *
 	//qboolean dospecular = specularscale * VectorLength2(lightcolorbase) > 0.00001 && glosstexture != r_texture_black;
 	// TODO: add direct pants/shirt rendering
 	if (doambientpants || dodiffusepants)
-		R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorpants, vec3_origin, vec3_origin, pantstexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
+		R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorpants, vec3_origin, vec3_origin, pantstexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0);
 	if (doambientshirt || dodiffuseshirt)
-		R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0, modelorg);
+		R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorshirt, vec3_origin, vec3_origin, shirttexture, r_texture_black, r_texture_black, normalmaptexture, r_texture_black, 0);
 	if (!doambientbase && !dodiffusebase)
 		return;
 	VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale, ambientcolor2);
@@ -2418,7 +2425,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *
 	{
 		const msurface_t *surface = surfacelist[surfacelistindex];
 		const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
-		RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+		RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin);
 		if (!rsurface_svector3f)
 		{
 			rsurface_svector3f = varray_svector3f;
@@ -2447,7 +2454,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *
 #endif
 			}
 		}
-		R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2, 0, modelorg);
+		R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2, 0);
 		for (renders = 0;renders < 64 && (ambientcolor2[0] > renders || ambientcolor2[1] > renders || ambientcolor2[2] > renders || diffusecolor2[0] > renders || diffusecolor2[1] > renders || diffusecolor2[2] > renders);renders++)
 		{
 			int i;
@@ -2514,25 +2521,76 @@ goodpass:
 	}
 }
 
-void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg)
+void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist)
 {
 	// FIXME: support MATERIALFLAG_NODEPTHTEST
-	switch (r_shadowstage)
+	vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
+	rtexture_t *basetexture;
+	rtexture_t *glosstexture;
+	float specularscale;
+	if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
+		qglDisable(GL_CULL_FACE);
+	else
+		qglEnable(GL_CULL_FACE);
+	glosstexture = r_texture_black;
+	specularscale = 0;
+	if (r_shadow_gloss.integer > 0)
+	{
+		if (texture->skin.gloss)
+		{
+			if (r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
+			{
+				glosstexture = texture->skin.gloss;
+				specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
+			}
+		}
+		else
+		{
+			if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
+			{
+				glosstexture = r_texture_white;
+				specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
+			}
+		}
+	}
+	// calculate colors to render this texture with
+	lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * ent->colormod[0] * texture->currentalpha;
+	lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * ent->colormod[1] * texture->currentalpha;
+	lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * ent->colormod[2] * texture->currentalpha;
+	lightcolorpants[0] = r_shadow_rtlight->currentcolor[0] * ent->colormap_pantscolor[0] * texture->currentalpha;
+	lightcolorpants[1] = r_shadow_rtlight->currentcolor[1] * ent->colormap_pantscolor[1] * texture->currentalpha;
+	lightcolorpants[2] = r_shadow_rtlight->currentcolor[2] * ent->colormap_pantscolor[2] * texture->currentalpha;
+	lightcolorshirt[0] = r_shadow_rtlight->currentcolor[0] * ent->colormap_shirtcolor[0] * texture->currentalpha;
+	lightcolorshirt[1] = r_shadow_rtlight->currentcolor[1] * ent->colormap_shirtcolor[1] * texture->currentalpha;
+	lightcolorshirt[2] = r_shadow_rtlight->currentcolor[2] * ent->colormap_shirtcolor[2] * texture->currentalpha;
+	if (ent->colormap >= 0)
+	{
+		basetexture = texture->skin.base;
+		if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
+			return;
+	}
+	else
+	{
+		basetexture = texture->skin.merged ? texture->skin.merged : texture->skin.base;
+		if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
+			return;
+	}
+	switch (r_shadow_rendermode)
 	{
-	case R_SHADOWSTAGE_VISIBLELIGHTING:
-		R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
+	case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
+		R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
 		break;
-	case R_SHADOWSTAGE_LIGHT_GLSL:
-		R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
+	case R_SHADOW_RENDERMODE_LIGHT_GLSL:
+		R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
 		break;
-	case R_SHADOWSTAGE_LIGHT_DOT3:
-		R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
+	case R_SHADOW_RENDERMODE_LIGHT_DOT3:
+		R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
 		break;
-	case R_SHADOWSTAGE_LIGHT_VERTEX:
-		R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
+	case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
+		R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale);
 		break;
 	default:
-		Con_Printf("R_Shadow_RenderLighting: unknown r_shadowstage %i\n", r_shadowstage);
+		Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
 		break;
 	}
 }
@@ -2681,22 +2739,22 @@ void R_Shadow_UncompileWorldLights(void)
 		R_RTLight_Uncompile(&light->rtlight);
 }
 
-void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
 {
 	vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
 	vec_t relativeshadowradius;
 	if (ent == r_refdef.worldentity)
 	{
-		if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
+		if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
 		{
 			shadowmesh_t *mesh;
 			R_Mesh_Matrix(&ent->matrix);
-			for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
+			for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
 			{
 				renderstats.lights_shadowtriangles += mesh->numtriangles;
 				R_Mesh_VertexPointer(mesh->vertex3f);
 				GL_LockArrays(0, mesh->numverts);
-				if (r_shadowstage == R_SHADOWSTAGE_STENCIL)
+				if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
 				{
 					// decrement stencil if backface is behind depthbuffer
 					qglCullFace(GL_BACK); // quake is backwards, this culls front faces
@@ -2713,13 +2771,13 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int num
 		else if (numsurfaces)
 		{
 			R_Mesh_Matrix(&ent->matrix);
-			ent->model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, surfacelist, rtlight->cullmins, rtlight->cullmaxs);
+			ent->model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
 		}
 	}
 	else
 	{
-		Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativeshadoworigin);
-		relativeshadowradius = rtlight->radius / ent->scale;
+		Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
+		relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
 		relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
 		relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
 		relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
@@ -2731,27 +2789,17 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent, rtlight_t *rtlight, int num
 	}
 }
 
-void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t lightcolor, int numsurfaces, int *surfacelist)
+void R_Shadow_SetupEntityLight(const entity_render_t *ent)
 {
 	// set up properties for rendering light onto this entity
-	r_shadow_entitylightcolorbase[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
-	r_shadow_entitylightcolorbase[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
-	r_shadow_entitylightcolorbase[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
-	r_shadow_entitylightcolorpants[0] = lightcolor[0] * ent->colormap_pantscolor[0] * ent->alpha;
-	r_shadow_entitylightcolorpants[1] = lightcolor[1] * ent->colormap_pantscolor[1] * ent->alpha;
-	r_shadow_entitylightcolorpants[2] = lightcolor[2] * ent->colormap_pantscolor[2] * ent->alpha;
-	r_shadow_entitylightcolorshirt[0] = lightcolor[0] * ent->colormap_shirtcolor[0] * ent->alpha;
-	r_shadow_entitylightcolorshirt[1] = lightcolor[1] * ent->colormap_shirtcolor[1] * ent->alpha;
-	r_shadow_entitylightcolorshirt[2] = lightcolor[2] * ent->colormap_shirtcolor[2] * ent->alpha;
-	Matrix4x4_Concat(&r_shadow_entitytolight, &rtlight->matrix_worldtolight, &ent->matrix);
+	Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
 	Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
 	Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
-	Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, r_shadow_entitylightorigin);
+	Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
 	Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
 	R_Mesh_Matrix(&ent->matrix);
-	if (r_shadowstage == R_SHADOWSTAGE_LIGHT_GLSL)
+	if (r_shadow_rendermode == R_SHADOW_RENDERMODE_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))
@@ -2759,17 +2807,21 @@ void R_Shadow_DrawEntityLight(entity_render_t *ent, rtlight_t *rtlight, vec3_t l
 			qglUniform3fARB(qglGetUniformLocationARB(r_shadow_lightprog, "EyePosition"), r_shadow_entityeyeorigin[0], r_shadow_entityeyeorigin[1], r_shadow_entityeyeorigin[2]);CHECKGLERROR
 		}
 	}
+}
+
+void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
+{
+	R_Shadow_SetupEntityLight(ent);
 	if (ent == r_refdef.worldentity)
-		ent->model->DrawLight(ent, r_shadow_entitylightcolorbase, r_shadow_entitylightcolorpants, r_shadow_entitylightcolorshirt, numsurfaces, surfacelist);
+		ent->model->DrawLight(ent, numsurfaces, surfacelist);
 	else
-		ent->model->DrawLight(ent, r_shadow_entitylightcolorbase, r_shadow_entitylightcolorpants, r_shadow_entitylightcolorshirt, ent->model->nummodelsurfaces, ent->model->surfacelist);
+		ent->model->DrawLight(ent, ent->model->nummodelsurfaces, ent->model->surfacelist);
 }
 
 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
 {
 	int i, usestencil;
 	float f;
-	vec3_t lightcolor;
 	int numleafs, numsurfaces;
 	int *leaflist, *surfacelist;
 	unsigned char *leafpvs;
@@ -2778,30 +2830,34 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
 	entity_render_t *lightentities[MAX_EDICTS];
 	entity_render_t *shadowentities[MAX_EDICTS];
 
-	// skip lights that don't light (corona only lights)
-	if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < (1.0f / 32768.0f))
+	// skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
+	// skip lights that are basically invisible (color 0 0 0)
+	if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
 		return;
 
+	// loading is done before visibility checks because loading should happen
+	// all at once at the start of a level, not when it stalls gameplay.
+	// (especially important to benchmarks)
+	// compile light
+	if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
+		R_RTLight_Compile(rtlight);
+	// load cubemap
+	rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
+
+	// look up the light style value at this time
 	f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
-	VectorScale(rtlight->color, f, lightcolor);
-	if (VectorLength2(lightcolor) < (1.0f / 32768.0f))
-		return;
+	VectorScale(rtlight->color, f, rtlight->currentcolor);
 	/*
 	if (rtlight->selected)
 	{
 		f = 2 + sin(realtime * M_PI * 4.0);
-		VectorScale(lightcolor, f, lightcolor);
+		VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
 	}
 	*/
 
-	// loading is done before visibility checks because loading should happen
-	// all at once at the start of a level, not when it stalls gameplay.
-	// (especially important to benchmarks)
-	// compile light
-	if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
-		R_RTLight_Compile(rtlight);
-	// load cubemap
-	r_shadow_lightcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
+	// if lightstyle is currently off, don't draw the light
+	if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
+		return;
 
 	// if the light box is offscreen, skip it
 	if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
@@ -2852,12 +2908,16 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
 	if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
 		return;
 
+	// make a list of lit entities and shadow casting entities
 	numlightentities = 0;
-	if (numsurfaces)
-		lightentities[numlightentities++] = r_refdef.worldentity;
 	numshadowentities = 0;
+	// don't count the world unless some surfaces are actually lit
 	if (numsurfaces)
+	{
+		lightentities[numlightentities++] = r_refdef.worldentity;
 		shadowentities[numshadowentities++] = r_refdef.worldentity;
+	}
+	// add dynamic entities that are lit by the light
 	if (r_drawentities.integer)
 	{
 		for (i = 0;i < r_refdef.numentities;i++)
@@ -2881,37 +2941,46 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
 	if (!numlightentities)
 		return;
 
-	R_Shadow_Stage_ActiveLight(rtlight);
+	// make this the active rtlight for rendering purposes
+	R_Shadow_RenderMode_ActiveLight(rtlight);
+	// count this light in the r_speeds
 	renderstats.lights++;
 
+	// draw stencil shadow volumes to mask off pixels that are in shadow
+	// so that they won't receive lighting
 	usestencil = false;
 	if (numshadowentities && (!visible || r_shadow_visiblelighting.integer == 1) && gl_stencil && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
 	{
 		usestencil = true;
-		R_Shadow_Stage_StencilShadowVolumes();
+		R_Shadow_RenderMode_StencilShadowVolumes();
 		for (i = 0;i < numshadowentities;i++)
-			R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
+			R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
 	}
 
+	// draw lighting in the unmasked areas
 	if (numlightentities && !visible)
 	{
-		R_Shadow_Stage_Lighting(usestencil);
+		R_Shadow_RenderMode_Lighting(usestencil, false);
 		for (i = 0;i < numlightentities;i++)
-			R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
+			R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
 	}
 
+	// optionally draw visible shape of the shadow volumes
+	// for performance analysis by level designers
 	if (numshadowentities && visible && r_shadow_visiblevolumes.integer > 0 && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
 	{
-		R_Shadow_Stage_VisibleShadowVolumes();
+		R_Shadow_RenderMode_VisibleShadowVolumes();
 		for (i = 0;i < numshadowentities;i++)
-			R_Shadow_DrawEntityShadow(shadowentities[i], rtlight, numsurfaces, surfacelist);
+			R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
 	}
 
+	// optionally draw the illuminated areas
+	// for performance analysis by level designers
 	if (numlightentities && visible && r_shadow_visiblelighting.integer > 0)
 	{
-		R_Shadow_Stage_VisibleLighting(usestencil);
+		R_Shadow_RenderMode_VisibleLighting(usestencil, false);
 		for (i = 0;i < numlightentities;i++)
-			R_Shadow_DrawEntityLight(lightentities[i], rtlight, lightcolor, numsurfaces, surfacelist);
+			R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
 	}
 }
 
@@ -2923,7 +2992,7 @@ void R_ShadowVolumeLighting(qboolean visible)
 	if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
 		R_Shadow_EditLights_Reload_f();
 
-	R_Shadow_Stage_Begin();
+	R_Shadow_RenderMode_Begin();
 
 	flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
 	if (r_shadow_debuglight.integer >= 0)
@@ -2940,7 +3009,7 @@ void R_ShadowVolumeLighting(qboolean visible)
 		for (lnum = 0;lnum < r_refdef.numlights;lnum++)
 			R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
 
-	R_Shadow_Stage_End();
+	R_Shadow_RenderMode_End();
 }
 
 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
@@ -3131,23 +3200,22 @@ void R_Shadow_SelectLight(dlight_t *light)
 		r_shadow_selectedlight->selected = true;
 }
 
-void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
+void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
 {
 	float scale = r_editlights_cursorgrid.value * 0.5f;
 	R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[0], NULL, false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
 }
 
-void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
+void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
 {
 	float intensity;
-	const dlight_t *light;
-	light = (dlight_t *)calldata1;
+	const dlight_t *light = (dlight_t *)ent;
 	intensity = 0.5;
 	if (light->selected)
 		intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
 	if (!light->shadow)
 		intensity *= 0.5f;
-	R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[calldata2], NULL, false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
+	R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[surfacenumber], NULL, false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
 }
 
 void R_Shadow_DrawLightSprites(void)
@@ -3164,8 +3232,8 @@ void R_Shadow_DrawLightSprites(void)
 	}
 
 	for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
-		R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
-	R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
+		R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, i % 5, &light->rtlight);
+	R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
 }
 
 void R_Shadow_SelectLightInView(void)
diff --git a/r_shadow.h b/r_shadow.h
index 84078ac5..52fa087a 100644
--- a/r_shadow.h
+++ b/r_shadow.h
@@ -36,10 +36,33 @@ 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_RenderSurfacesLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, const vec3_t modelorg);
+void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist);
+void R_Shadow_RenderMode_Begin(void);
+void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight);
+void R_Shadow_RenderMode_Reset(void);
+void R_Shadow_RenderMode_StencilShadowVolumes(void);
+void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent);
+void R_Shadow_RenderMode_VisibleShadowVolumes(void);
+void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent);
+void R_Shadow_RenderMode_End(void);
+void R_Shadow_SetupEntityLight(const entity_render_t *ent);
+
 // light currently being rendered
 extern rtlight_t *r_shadow_rtlight;
 
+// this is the location of the eye in entity space
+extern vec3_t r_shadow_entityeyeorigin;
+// this is the location of the light in entity space
+extern vec3_t r_shadow_entitylightorigin;
+// this transforms entity coordinates to light filter cubemap coordinates
+// (also often used for other purposes)
+extern 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)
+extern matrix4x4_t r_shadow_entitytoattenuationxyz;
+// this transforms only the Z to S, and T is always 0.5
+extern matrix4x4_t r_shadow_entitytoattenuationz;
+
 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i);
 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs);
 
diff --git a/r_sprites.c b/r_sprites.c
index bd7d0213..70169e12 100644
--- a/r_sprites.c
+++ b/r_sprites.c
@@ -1,9 +1,9 @@
 
 #include "quakedef.h"
+#include "r_shadow.h"
 
-void R_DrawSpriteModelCallback(const void *calldata1, int calldata2)
+void R_Model_Sprite_Draw_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
 {
-	const entity_render_t *ent = (entity_render_t *)calldata1;
 	int i;
 	vec3_t left, up, org, color, diffusecolor, diffusenormal;
 	mspriteframe_t *frame;
@@ -103,6 +103,6 @@ void R_Model_Sprite_Draw(entity_render_t *ent)
 	if (ent->frameblend[0].frame < 0)
 		return;
 
-	R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawSpriteModelCallback, ent, 0);
+	R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_Model_Sprite_Draw_TransparentCallback, ent, 0, r_shadow_rtlight);
 }
 
-- 
2.39.5