From c10cd5ef15e3211797e91900f6ada528faa93e92 Mon Sep 17 00:00:00 2001
From: havoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Sun, 14 Nov 2004 23:31:36 +0000
Subject: [PATCH] upgraded rtlights format to have separate ambient, diffuse,
 and specular intensity scales, and also coronasize, this also allows
 corona-only lights by setting all scales to 0, and added
 normalmode/realtimemode flags so that lights can appear in normal mode, not
 just realtime mode (primarily useful for adding corona effects to a normal
 level) added ambient light support to RenderLighting (non-bumpmapped diffuse)
 some dlights now use ambientscale (this has not been exposed as a qc
 extension yet, qc lights remain the same)

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@4753 d7cf8633-e32d-0410-b094-e92efae38249
---
 cgamevm.c      |   2 +-
 cl_parse.c     |  34 ++--
 client.h       |  35 +++-
 gl_models.c    |   6 +-
 gl_rmain.c     |   2 +-
 gl_rsurf.c     |   8 +-
 model_alias.c  |   2 +-
 model_brush.c  |   4 +-
 model_shared.h |   2 +-
 r_light.c      |  20 +-
 r_shadow.c     | 486 +++++++++++++++++++++++++++++++++++++++++++------
 r_shadow.h     |   4 +-
 12 files changed, 505 insertions(+), 100 deletions(-)

diff --git a/cgamevm.c b/cgamevm.c
index 277c7eb0..ed2bc411 100644
--- a/cgamevm.c
+++ b/cgamevm.c
@@ -169,7 +169,7 @@ void CGVM_Draw_Light(const cgdrawlight_t *l)
 {
 	matrix4x4_t matrix;
 	Matrix4x4_CreateTranslate(&matrix, l->origin[0], l->origin[1], l->origin[2]);
-	CL_AllocDlight(NULL, &matrix, l->radius, l->color[0], l->color[1], l->color[2], 0, 0, 0, 0, true, 1);
+	CL_AllocDlight(NULL, &matrix, l->radius, l->color[0], l->color[1], l->color[2], 0, 0, 0, 0, true, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 }
 
 void *CGVM_Malloc(const int size)
diff --git a/cl_parse.c b/cl_parse.c
index 6f8c5dd8..9baf8c13 100644
--- a/cl_parse.c
+++ b/cl_parse.c
@@ -922,7 +922,7 @@ void CL_ParseTempEntity(void)
 		MSG_ReadVector(pos, cl.protocol);
 		CL_FindNonSolidLocation(pos, pos, 4);
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 100, 0.12f, 0.50f, 0.12f, 500, 0.2, 0, 0, false, 1);
+		CL_AllocDlight(NULL, &tempmatrix, 100, 0.12f, 0.50f, 0.12f, 500, 0.2, 0, 0, false, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		CL_RunParticleEffect(pos, vec3_origin, 20, 30);
 		S_StartSound(-1, 0, cl_sfx_wizhit, pos, 1, 1);
 		break;
@@ -932,7 +932,7 @@ void CL_ParseTempEntity(void)
 		MSG_ReadVector(pos, cl.protocol);
 		CL_FindNonSolidLocation(pos, pos, 4);
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 100, 0.50f, 0.30f, 0.10f, 500, 0.2, 0, 0, false, 1);
+		CL_AllocDlight(NULL, &tempmatrix, 100, 0.50f, 0.30f, 0.10f, 500, 0.2, 0, 0, false, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		CL_RunParticleEffect(pos, vec3_origin, 226, 20);
 		S_StartSound(-1, 0, cl_sfx_knighthit, pos, 1, 1);
 		break;
@@ -972,7 +972,7 @@ void CL_ParseTempEntity(void)
 			CL_BulletMark(pos);
 		}
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, 0, true, 1);
+		CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, 0, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
 		if (rand() % 5)
 			S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
@@ -1023,7 +1023,7 @@ void CL_ParseTempEntity(void)
 			CL_BulletMark(pos);
 		}
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, 0, true, 1);
+		CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, 0, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		if (rand() % 5)
 			S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
 		else
@@ -1062,7 +1062,7 @@ void CL_ParseTempEntity(void)
 		MSG_ReadVector(pos, cl.protocol);
 		CL_FindNonSolidLocation(pos, pos, 4);
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
+		CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		CL_PlasmaBurn(pos);
 		break;
 		// LordHavoc: added for improved gore
@@ -1123,7 +1123,7 @@ void CL_ParseTempEntity(void)
 		CL_Smoke(pos, vec3_origin, 15);
 		CL_BulletMark(pos);
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, 0, true, 1);
+		CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, 0, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		break;
 
 	case TE_EXPLOSION:
@@ -1133,7 +1133,7 @@ void CL_ParseTempEntity(void)
 		CL_ParticleExplosion(pos);
 		// LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 350, 4.0f, 2.0f, 0.50f, 700, 0.5, 0, 0, true, 1);
+		CL_AllocDlight(NULL, &tempmatrix, 350, 4.0f, 2.0f, 0.50f, 700, 0.5, 0, 0, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
 		break;
 
@@ -1143,7 +1143,7 @@ void CL_ParseTempEntity(void)
 		CL_FindNonSolidLocation(pos, pos, 10);
 		CL_ParticleExplosion(pos);
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, 0, 0, true, 1);
+		CL_AllocDlight(NULL, &tempmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, 0, 0, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
 		break;
 
@@ -1156,7 +1156,7 @@ void CL_ParseTempEntity(void)
 		color[0] = MSG_ReadCoord(cl.protocol) * (2.0f / 1.0f);
 		color[1] = MSG_ReadCoord(cl.protocol) * (2.0f / 1.0f);
 		color[2] = MSG_ReadCoord(cl.protocol) * (2.0f / 1.0f);
-		CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);	
+		CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);	
 		S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
 		break;
 
@@ -1169,7 +1169,7 @@ void CL_ParseTempEntity(void)
 		color[1] = MSG_ReadByte() * (2.0f / 255.0f);
 		color[2] = MSG_ReadByte() * (2.0f / 255.0f);
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
+		CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
 		break;
 
@@ -1182,14 +1182,14 @@ void CL_ParseTempEntity(void)
 		S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
 		S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, 0, 0, true, 1);
+		CL_AllocDlight(NULL, &tempmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, 0, 0, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		break;
 
 	case TE_SMALLFLASH:
 		MSG_ReadVector(pos, cl.protocol);
 		CL_FindNonSolidLocation(pos, pos, 10);
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 200, 2, 2, 2, 1000, 0.2, 0, 0, true, 1);
+		CL_AllocDlight(NULL, &tempmatrix, 200, 2, 2, 2, 1000, 0.2, 0, 0, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		break;
 
 	case TE_CUSTOMFLASH:
@@ -1201,7 +1201,7 @@ void CL_ParseTempEntity(void)
 		color[1] = MSG_ReadByte() * (2.0f / 255.0f);
 		color[2] = MSG_ReadByte() * (2.0f / 255.0f);
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, 0, true, 1);
+		CL_AllocDlight(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, 0, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		break;
 
 	case TE_FLAMEJET:
@@ -1254,7 +1254,7 @@ void CL_ParseTempEntity(void)
 	case TE_TELEPORT:
 		MSG_ReadVector(pos, cl.protocol);
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f, 0, 0, true, 1);
+		CL_AllocDlight(NULL, &tempmatrix, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f, 0, 0, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 //		CL_TeleportSplash(pos);
 		break;
 
@@ -1270,7 +1270,7 @@ void CL_ParseTempEntity(void)
 		color[1] = tempcolor[1] * (2.0f / 255.0f);
 		color[2] = tempcolor[2] * (2.0f / 255.0f);
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
+		CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
 		break;
 
@@ -1295,7 +1295,7 @@ void CL_ParseTempEntity(void)
 		CL_FindNonSolidLocation(pos, pos, 10);
 		CL_ParticleExplosion(pos);
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 500, 2.5f, 2.0f, 1.0f, 500, 9999, 0, 0, true, 1);
+		CL_AllocDlight(NULL, &tempmatrix, 500, 2.5f, 2.0f, 1.0f, 500, 9999, 0, 0, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
 		break;
 
@@ -1306,7 +1306,7 @@ void CL_ParseTempEntity(void)
 		CL_FindNonSolidLocation(pos, pos, 5);
 		CL_Tei_PlasmaHit(pos, dir, count);
 		Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-		CL_AllocDlight(NULL, &tempmatrix, 500, 0.6, 1.2, 2.0f, 2000, 9999, 0, 0, true, 1);
+		CL_AllocDlight(NULL, &tempmatrix, 500, 0.6, 1.2, 2.0f, 2000, 9999, 0, 0, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 		break;
 
 	default:
diff --git a/client.h b/client.h
index 70c2b66a..45dc560f 100644
--- a/client.h
+++ b/client.h
@@ -31,6 +31,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // max lights shining on one entity
 #define MAXENTLIGHTS 128
 
+// flags for rtlight rendering
+#define LIGHTFLAG_NORMALMODE 1
+#define LIGHTFLAG_REALTIMEMODE 2
+
 extern int cl_max_entities;
 extern int cl_max_static_entities;
 extern int cl_max_temp_entities;
@@ -90,12 +94,22 @@ typedef struct rtlight_s
 	vec_t radius;
 	// light filter
 	char cubemapname[64];
+	// light style to monitor for brightness
+	int style;
 	// whether light should render shadows
 	int shadow;
 	// intensity of corona to render
 	vec_t corona;
-	// light style to monitor for brightness
-	int style;
+	// radius scale of corona to render (1.0 means same as light radius)
+	vec_t coronasizescale;
+	// ambient intensity to render
+	vec_t ambientscale;
+	// diffuse intensity to render
+	vec_t diffusescale;
+	// specular intensity to render
+	vec_t specularscale;
+	// LIGHTFLAG_* flags
+	int flags;
 	
 	// generated properties
 	// used only for shadow volumes
@@ -180,6 +194,21 @@ typedef struct dlight_s
 	// corona intensity
 	// (worldlight: saved to .rtlights file)
 	vec_t corona;
+	// radius scale of corona to render (1.0 means same as light radius)
+	// (worldlight: saved to .rtlights file)
+	vec_t coronasizescale;
+	// ambient intensity to render
+	// (worldlight: saved to .rtlights file)
+	vec_t ambientscale;
+	// diffuse intensity to render
+	// (worldlight: saved to .rtlights file)
+	vec_t diffusescale;
+	// specular intensity to render
+	// (worldlight: saved to .rtlights file)
+	vec_t specularscale;
+	// LIGHTFLAG_* flags
+	// (worldlight: saved to .rtlights file)
+	int flags;
 	// linked list of world lights
 	// (worldlight only)
 	struct dlight_s *next;
@@ -616,7 +645,7 @@ extern lightstyle_t *cl_lightstyle;
 
 extern client_state_t cl;
 
-extern void CL_AllocDlight (entity_render_t *ent, matrix4x4_t *matrix, float radius, float red, float green, float blue, float decay, float lifetime, int cubemapnum, int style, int shadowenable, vec_t corona);
+extern void CL_AllocDlight (entity_render_t *ent, matrix4x4_t *matrix, float radius, float red, float green, float blue, float decay, float lifetime, int cubemapnum, int style, int shadowenable, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags);
 extern void CL_DecayLights (void);
 
 //=============================================================================
diff --git a/gl_models.c b/gl_models.c
index c5f20054..5bd5f03e 100644
--- a/gl_models.c
+++ b/gl_models.c
@@ -229,7 +229,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)
+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 c, meshnum, layernum;
 	float fog, ifog, lightcolor2[3];
@@ -294,7 +294,7 @@ void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v
 			if (layer->flags & ALIASLAYER_SPECULAR)
 			{
 				c_alias_polys += mesh->num_triangles;
-				R_Shadow_RenderLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, vertex3f, svector3f, tvector3f, normal3f, mesh->data_texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, layer->texture, lightcubemap, LIGHTING_SPECULAR);
+				R_Shadow_RenderLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, vertex3f, svector3f, tvector3f, normal3f, mesh->data_texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, layer->texture, lightcubemap, 0, 0, specularscale);
 			}
 			else if (layer->flags & ALIASLAYER_DIFFUSE)
 			{
@@ -323,7 +323,7 @@ void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v
 					lightcolor2[2] *= bcolor[2] * (1.0f / 255.0f);
 				}
 				c_alias_polys += mesh->num_triangles;
-				R_Shadow_RenderLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, vertex3f, svector3f, tvector3f, normal3f, mesh->data_texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, layer->texture, lightcubemap, LIGHTING_DIFFUSE);
+				R_Shadow_RenderLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, vertex3f, svector3f, tvector3f, normal3f, mesh->data_texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, layer->texture, lightcubemap, ambientscale, diffusescale, 0);
 			}
 		}
 	}
diff --git a/gl_rmain.c b/gl_rmain.c
index ec4d0dac..45314004 100644
--- a/gl_rmain.c
+++ b/gl_rmain.c
@@ -588,7 +588,7 @@ void R_RenderView(void)
 	r_view_matrix = r_refdef.viewentitymatrix;
 	GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
 	r_rtworld = r_shadow_realtime_world.integer;
-	r_rtworldshadows = r_rtworld && r_shadow_realtime_world_shadows.integer && gl_stencil;
+	r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
 	r_rtdlight = r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer;
 	r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
 	r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
diff --git a/gl_rsurf.c b/gl_rsurf.c
index ad5594e2..f8909668 100644
--- a/gl_rsurf.c
+++ b/gl_rsurf.c
@@ -1855,7 +1855,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, int numsurfaces, const int *surfacelist)
+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)
 {
 	model_t *model = ent->model;
 	vec3_t lightmins, lightmaxs, modelorg;
@@ -1888,7 +1888,7 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t
 				t = surface->texinfo->texture->currentframe;
 				// FIXME: transparent surfaces need to be lit later
 				if (t->flags & SURF_LIGHTMAP && t->rendertype == SURFRENDER_OPAQUE)
-					R_Shadow_RenderLighting(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i, surface->mesh.data_vertex3f, surface->mesh.data_svector3f, surface->mesh.data_tvector3f, surface->mesh.data_normal3f, surface->mesh.data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, t->skin.gloss, lightcubemap, LIGHTING_DIFFUSE | LIGHTING_SPECULAR);
+					R_Shadow_RenderLighting(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i, surface->mesh.data_vertex3f, surface->mesh.data_svector3f, surface->mesh.data_tvector3f, surface->mesh.data_normal3f, surface->mesh.data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, t->skin.gloss, lightcubemap, ambientscale, diffusescale, specularscale);
 			}
 		}
 	}
@@ -2556,7 +2556,7 @@ void R_Q3BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin,
 	}
 }
 
-void R_Q3BSP_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, int numsurfaces, const int *surfacelist)
+void R_Q3BSP_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)
 {
 	model_t *model = ent->model;
 	vec3_t lightmins, lightmaxs, modelorg;
@@ -2584,7 +2584,7 @@ void R_Q3BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t
 			{
 				if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
 					qglDisable(GL_CULL_FACE);
-				R_Shadow_RenderLighting(surface->num_vertices, surface->num_triangles, surface->data_element3i, surface->data_vertex3f, surface->data_svector3f, surface->data_tvector3f, surface->data_normal3f, surface->data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, surface->texture->skin.base, surface->texture->skin.nmap, surface->texture->skin.gloss, lightcubemap, LIGHTING_DIFFUSE | LIGHTING_SPECULAR);
+				R_Shadow_RenderLighting(surface->num_vertices, surface->num_triangles, surface->data_element3i, surface->data_vertex3f, surface->data_svector3f, surface->data_tvector3f, surface->data_normal3f, surface->data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, surface->texture->skin.base, surface->texture->skin.nmap, surface->texture->skin.gloss, lightcubemap, ambientscale, diffusescale, specularscale);
 				if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
 					qglEnable(GL_CULL_FACE);
 			}
diff --git a/model_alias.c b/model_alias.c
index fc92cc06..d72ea3c9 100644
--- a/model_alias.c
+++ b/model_alias.c
@@ -407,7 +407,7 @@ void Mod_BuildAliasSkinsFromSkinFiles(aliasskin_t *skin, skinfile_t *skinfile, c
 #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);
-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, int numsurfaces, const int *surfacelist);
+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);
 void Mod_IDP0_Load(model_t *mod, void *buffer)
 {
 	int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
diff --git a/model_brush.c b/model_brush.c
index b65fe41e..7835687d 100644
--- a/model_brush.c
+++ b/model_brush.c
@@ -2941,7 +2941,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 *outclusterlist, qbyte *outclusterpvs, int *outnumclusterspointer, 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);
-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, int numsurfaces, const int *surfacelist);
+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);
 void Mod_Q1BSP_Load(model_t *mod, void *buffer)
 {
 	int i, j, k;
@@ -5677,7 +5677,7 @@ extern void R_Q3BSP_DrawSky(struct entity_render_s *ent);
 extern void R_Q3BSP_Draw(struct entity_render_s *ent);
 extern void R_Q3BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outclusterlist, qbyte *outclusterpvs, int *outnumclusterspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer);
 extern void R_Q3BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist);
-extern void R_Q3BSP_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, int numsurfaces, const int *surfacelist);
+extern void R_Q3BSP_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);
 void Mod_Q3BSP_Load(model_t *mod, void *buffer)
 {
 	int i, j, numshadowmeshtriangles;
diff --git a/model_shared.h b/model_shared.h
index b5ac7bb5..67fc4ff1 100644
--- a/model_shared.h
+++ b/model_shared.h
@@ -599,7 +599,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);
 	// 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, int numsurfaces, const int *surfacelist);
+	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);
 	// 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
diff --git a/r_light.c b/r_light.c
index 908b5aa6..e3f53cb0 100644
--- a/r_light.c
+++ b/r_light.c
@@ -128,31 +128,29 @@ void R_UpdateLights(void)
 
 void R_DrawCoronas(void)
 {
-	int i, lnum;
+	int i, lnum, flag;
 	float cscale, scale, viewdist, dist;
 	dlight_t *light;
 	if (r_coronas.value < 0.01)
 		return;
 	R_Mesh_Matrix(&r_identitymatrix);
 	viewdist = DotProduct(r_vieworigin, r_viewforward);
-	if (r_rtworld)
+	flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
+	for (lnum = 0, light = r_shadow_worldlightchain;light;light = light->next, lnum++)
 	{
-		for (lnum = 0, light = r_shadow_worldlightchain;light;light = light->next, lnum++)
+		if ((light->flags & flag) && light->corona * r_coronas.value > 0 && (r_shadow_debuglight.integer < 0 || r_shadow_debuglight.integer == lnum) && (dist = (DotProduct(light->rtlight.shadoworigin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceLine(light->rtlight.shadoworigin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1)
 		{
-			if (light->rtlight.corona * r_coronas.value > 0 && (r_shadow_debuglight.integer < 0 || r_shadow_debuglight.integer == lnum) && (dist = (DotProduct(light->rtlight.shadoworigin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceLine(light->rtlight.shadoworigin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1)
-			{
-				cscale = light->rtlight.corona * r_coronas.value * 0.25f;
-				scale = light->rtlight.radius * 0.25f;
-				R_DrawSprite(GL_ONE, GL_ONE, lightcorona, true, light->rtlight.shadoworigin, r_viewright, r_viewup, scale, -scale, -scale, scale, light->rtlight.color[0] * cscale, light->rtlight.color[1] * cscale, light->rtlight.color[2] * cscale, 1);
-			}
+			cscale = light->rtlight.corona * r_coronas.value * 0.25f;
+			scale = light->rtlight.radius * light->rtlight.coronasizescale;
+			R_DrawSprite(GL_ONE, GL_ONE, lightcorona, true, light->rtlight.shadoworigin, r_viewright, r_viewup, scale, -scale, -scale, scale, light->rtlight.color[0] * cscale, light->rtlight.color[1] * cscale, light->rtlight.color[2] * cscale, 1);
 		}
 	}
 	for (i = 0, light = r_dlight;i < r_numdlights;i++, light++)
 	{
-		if (light->corona * r_coronas.value > 0 && (dist = (DotProduct(light->origin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1)
+		if ((light->flags & flag) && light->corona * r_coronas.value > 0 && (dist = (DotProduct(light->origin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1)
 		{
 			cscale = light->corona * r_coronas.value * 0.25f;
-			scale = light->radius * 0.25f;
+			scale = light->rtlight.radius * light->rtlight.coronasizescale;
 			if (gl_flashblend.integer)
 			{
 				cscale *= 4.0f;
diff --git a/r_shadow.c b/r_shadow.c
index 1559078f..8bc97703 100644
--- a/r_shadow.c
+++ b/r_shadow.c
@@ -1225,6 +1225,49 @@ 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)
+{
+	float *color4f = varray_color4f;
+	float dist, intensity, v[3];
+	for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
+	{
+		Matrix4x4_Transform(m, vertex3f, v);
+		if ((dist = DotProduct(v, v)) < 1)
+		{
+			dist = sqrt(dist);
+			intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
+			VectorScale(lightcolor, intensity, color4f);
+			color4f[3] = 1;
+		}
+		else
+		{
+			VectorClear(color4f);
+			color4f[3] = 1;
+		}
+	}
+}
+
+static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
+{
+	float *color4f = varray_color4f;
+	float dist, intensity, v[3];
+	for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
+	{
+		Matrix4x4_Transform(m, vertex3f, v);
+		if ((dist = fabs(v[2])) < 1)
+		{
+			intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
+			VectorScale(lightcolor, intensity, color4f);
+			color4f[3] = 1;
+		}
+		else
+		{
+			VectorClear(color4f);
+			color4f[3] = 1;
+		}
+	}
+}
+
 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
 #define USETEXMATRIX
 
@@ -1289,7 +1332,7 @@ static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out3f, int numve
 	}
 }
 
-void R_Shadow_RenderLighting(int numverts, 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 *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, int lighting)
+void R_Shadow_RenderLighting(int numverts, 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 *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale)
 {
 	int renders;
 	float color[3], color2[3], colorscale;
@@ -1303,10 +1346,181 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
 	GL_DepthTest(true);
 	if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
 	{
-		if (lighting & LIGHTING_DIFFUSE)
+		if (ambientscale)
+		{
+			GL_Color(1,1,1,1);
+			colorscale = r_shadow_lightintensityscale.value * ambientscale;
+			// colorscale accounts for how much we multiply the brightness
+			// during combine.
+			//
+			// mult is how many times the final pass of the lighting will be
+			// performed to get more brightness than otherwise possible.
+			//
+			// Limit mult to 64 for sanity sake.
+			if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
+			{
+				// 3 3D combine path (Geforce3, Radeon 8500)
+				memset(&m, 0, sizeof(m));
+				m.pointer_vertex = vertex3f;
+				m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
+#ifdef USETEXMATRIX
+				m.pointer_texcoord3f[0] = vertex3f;
+				m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+#else
+				m.pointer_texcoord3f[0] = varray_texcoord3f[0];
+				R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
+#endif
+				m.tex[1] = R_GetTexture(basetexture);
+				m.pointer_texcoord[1] = texcoord2f;
+				m.texcubemap[2] = R_GetTexture(lightcubemap);
+#ifdef USETEXMATRIX
+				m.pointer_texcoord3f[2] = vertex3f;
+				m.texmatrix[2] = *matrix_modeltolight;
+#else
+				m.pointer_texcoord3f[2] = varray_texcoord3f[2];
+				R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltolight);
+#endif
+			}
+			else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
+			{
+				// 2 3D combine path (Geforce3, original Radeon)
+				memset(&m, 0, sizeof(m));
+				m.pointer_vertex = vertex3f;
+				m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
+#ifdef USETEXMATRIX
+				m.pointer_texcoord3f[0] = vertex3f;
+				m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+#else
+				m.pointer_texcoord3f[0] = varray_texcoord3f[0];
+				R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
+#endif
+				m.tex[1] = R_GetTexture(basetexture);
+				m.pointer_texcoord[1] = texcoord2f;
+			}
+			else if (r_textureunits.integer >= 4 && lightcubemap)
+			{
+				// 4 2D combine path (Geforce3, Radeon 8500)
+				memset(&m, 0, sizeof(m));
+				m.pointer_vertex = vertex3f;
+				m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+#ifdef USETEXMATRIX
+				m.pointer_texcoord3f[0] = vertex3f;
+				m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+#else
+				m.pointer_texcoord[0] = varray_texcoord2f[0];
+				R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
+#endif
+				m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+#ifdef USETEXMATRIX
+				m.pointer_texcoord3f[1] = vertex3f;
+				m.texmatrix[1] = *matrix_modeltoattenuationz;
+#else
+				m.pointer_texcoord[1] = varray_texcoord2f[1];
+				R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
+#endif
+				m.tex[2] = R_GetTexture(basetexture);
+				m.pointer_texcoord[2] = texcoord2f;
+				if (lightcubemap)
+				{
+					m.texcubemap[3] = R_GetTexture(lightcubemap);
+#ifdef USETEXMATRIX
+					m.pointer_texcoord3f[3] = vertex3f;
+					m.texmatrix[3] = *matrix_modeltolight;
+#else
+					m.pointer_texcoord3f[3] = varray_texcoord3f[3];
+					R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3], numverts, vertex3f, matrix_modeltolight);
+#endif
+				}
+			}
+			else if (r_textureunits.integer >= 3 && !lightcubemap)
+			{
+				// 3 2D combine path (Geforce3, original Radeon)
+				memset(&m, 0, sizeof(m));
+				m.pointer_vertex = vertex3f;
+				m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+#ifdef USETEXMATRIX
+				m.pointer_texcoord3f[0] = vertex3f;
+				m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+#else
+				m.pointer_texcoord[0] = varray_texcoord2f[0];
+				R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
+#endif
+				m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+#ifdef USETEXMATRIX
+				m.pointer_texcoord3f[1] = vertex3f;
+				m.texmatrix[1] = *matrix_modeltoattenuationz;
+#else
+				m.pointer_texcoord[1] = varray_texcoord2f[1];
+				R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
+#endif
+				m.tex[2] = R_GetTexture(basetexture);
+				m.pointer_texcoord[2] = texcoord2f;
+			}
+			else
+			{
+				// 2/2/2 2D combine path (any dot3 card)
+				memset(&m, 0, sizeof(m));
+				m.pointer_vertex = vertex3f;
+				m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+#ifdef USETEXMATRIX
+				m.pointer_texcoord3f[0] = vertex3f;
+				m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+#else
+				m.pointer_texcoord[0] = varray_texcoord2f[0];
+				R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
+#endif
+				m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+#ifdef USETEXMATRIX
+				m.pointer_texcoord3f[1] = vertex3f;
+				m.texmatrix[1] = *matrix_modeltoattenuationz;
+#else
+				m.pointer_texcoord[1] = varray_texcoord2f[1];
+				R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
+#endif
+				R_Mesh_State(&m);
+				GL_ColorMask(0,0,0,1);
+				GL_BlendFunc(GL_ONE, GL_ZERO);
+				GL_LockArrays(0, numverts);
+				R_Mesh_Draw(numverts, numtriangles, elements);
+				GL_LockArrays(0, 0);
+				c_rt_lightmeshes++;
+				c_rt_lighttris += numtriangles;
+	
+				memset(&m, 0, sizeof(m));
+				m.pointer_vertex = vertex3f;
+				m.tex[0] = R_GetTexture(basetexture);
+				m.pointer_texcoord[0] = texcoord2f;
+				if (lightcubemap)
+				{
+					m.texcubemap[1] = R_GetTexture(lightcubemap);
+#ifdef USETEXMATRIX
+					m.pointer_texcoord3f[1] = vertex3f;
+					m.texmatrix[1] = *matrix_modeltolight;
+#else
+					m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+					R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
+#endif
+				}
+			}
+			// this final code is shared
+			R_Mesh_State(&m);
+			GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
+			GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
+			VectorScale(lightcolor, colorscale, color2);
+			for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
+			{
+				GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
+				GL_LockArrays(0, numverts);
+				R_Mesh_Draw(numverts, numtriangles, elements);
+				GL_LockArrays(0, 0);
+				c_rt_lightmeshes++;
+				c_rt_lighttris += numtriangles;
+			}
+		}
+		if (diffusescale)
 		{
 			GL_Color(1,1,1,1);
-			colorscale = r_shadow_lightintensityscale.value;
+			colorscale = r_shadow_lightintensityscale.value * diffusescale;
 			// colorscale accounts for how much we multiply the brightness
 			// during combine.
 			//
@@ -1579,12 +1793,12 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
 				c_rt_lighttris += numtriangles;
 			}
 		}
-		if ((lighting & LIGHTING_SPECULAR) && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
+		if (specularscale && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
 		{
 			// FIXME: detect blendsquare!
 			//if (gl_support_blendsquare)
 			{
-				colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value;
+				colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value * specularscale;
 				if (glosstexture == r_shadow_blankglosstexture)
 					colorscale *= r_shadow_gloss2intensity.value;
 				GL_Color(1,1,1,1);
@@ -1812,10 +2026,70 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements
 	}
 	else
 	{
-		if (lighting & LIGHTING_DIFFUSE)
+		if (ambientscale)
+		{
+			GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+			VectorScale(lightcolor, r_shadow_lightintensityscale.value * ambientscale, color2);
+			memset(&m, 0, sizeof(m));
+			m.pointer_vertex = vertex3f;
+			m.tex[0] = R_GetTexture(basetexture);
+			m.pointer_texcoord[0] = texcoord2f;
+			if (r_textureunits.integer >= 2)
+			{
+				// voodoo2
+				m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+#ifdef USETEXMATRIX
+				m.pointer_texcoord3f[1] = vertex3f;
+				m.texmatrix[1] = *matrix_modeltoattenuationxyz;
+#else
+				m.pointer_texcoord[1] = varray_texcoord2f[1];
+				R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
+#endif
+				if (r_textureunits.integer >= 3)
+				{
+					// Geforce3/Radeon class but not using dot3
+					m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
+#ifdef USETEXMATRIX
+					m.pointer_texcoord3f[2] = vertex3f;
+					m.texmatrix[2] = *matrix_modeltoattenuationz;
+#else
+					m.pointer_texcoord[2] = varray_texcoord2f[2];
+					R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
+#endif
+				}
+			}
+			R_Mesh_State(&m);
+			for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
+			{
+				color[0] = bound(0, color2[0], 1);
+				color[1] = bound(0, color2[1], 1);
+				color[2] = bound(0, color2[2], 1);
+				if (r_textureunits.integer >= 3)
+				{
+					GL_Color(color[0], color[1], color[2], 1);
+					m.pointer_color = NULL;
+				}
+				else if (r_textureunits.integer >= 2)
+				{
+					R_Shadow_VertexNoShadingWithZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
+					m.pointer_color = varray_color4f;
+				}
+				else
+				{
+					R_Shadow_VertexNoShadingWithXYZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
+					m.pointer_color = varray_color4f;
+				}
+				GL_LockArrays(0, numverts);
+				R_Mesh_Draw(numverts, numtriangles, elements);
+				GL_LockArrays(0, 0);
+				c_rt_lightmeshes++;
+				c_rt_lighttris += numtriangles;
+			}
+		}
+		if (diffusescale)
 		{
 			GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
-			VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
+			VectorScale(lightcolor, r_shadow_lightintensityscale.value * diffusescale, color2);
 			memset(&m, 0, sizeof(m));
 			m.pointer_vertex = vertex3f;
 			m.pointer_color = varray_color4f;
@@ -1894,6 +2168,11 @@ void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int i
 	rtlight->corona = light->corona;
 	rtlight->style = light->style;
 	rtlight->isstatic = isstatic;
+	rtlight->coronasizescale = light->coronasizescale;
+	rtlight->ambientscale = light->ambientscale;
+	rtlight->diffusescale = light->diffusescale;
+	rtlight->specularscale = light->specularscale;
+	rtlight->flags = light->flags;
 	Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
 	// ConcatScale won't work here because this needs to scale rotate and
 	// translate, not just rotate
@@ -1956,7 +2235,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);
-			model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, numsurfaces, r_shadow_buffer_surfacelist);
+			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);
 			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
@@ -2191,10 +2470,10 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
 			{
 				R_Mesh_Matrix(&ent->matrix);
 				for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
-					R_Shadow_RenderLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, mesh->map_specular, cubemaptexture, LIGHTING_DIFFUSE | LIGHTING_SPECULAR);
+					R_Shadow_RenderLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, mesh->map_specular, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale);
 			}
 			else
-				ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, numsurfaces, surfacelist);
+				ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
 		}
 		if (r_drawentities.integer)
 		{
@@ -2211,7 +2490,7 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
 					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, ent->model->nummodelsurfaces, ent->model->surfacelist);
+					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);
 				}
 			}
 		}
@@ -2220,7 +2499,7 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
 
 void R_ShadowVolumeLighting(int visiblevolumes)
 {
-	int lnum;
+	int lnum, flag;
 	dlight_t *light;
 	rmeshstate_t m;
 
@@ -2240,18 +2519,17 @@ void R_ShadowVolumeLighting(int visiblevolumes)
 	}
 	else
 		R_Shadow_Stage_Begin();
-	if (r_rtworld)
+	flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
+	if (r_shadow_debuglight.integer >= 0)
 	{
-		if (r_shadow_debuglight.integer >= 0)
-		{
-			for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
-				if (lnum == r_shadow_debuglight.integer)
-					R_DrawRTLight(&light->rtlight, visiblevolumes);
-		}
-		else
-			for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
+		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, visiblevolumes);
 	}
+	else
+		for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
+			if (light->flags & flag)
+				R_DrawRTLight(&light->rtlight, visiblevolumes);
 	if (r_rtdlight)
 		for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
 			R_DrawRTLight(&light->rtlight, visiblevolumes);
@@ -2392,7 +2670,7 @@ dlight_t *R_Shadow_NewWorldLight(void)
 	return light;
 }
 
-void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname)
+void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
 {
 	VectorCopy(origin, light->origin);
 	light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
@@ -2413,6 +2691,11 @@ void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, ve
 	if (!cubemapname)
 		cubemapname = "";
 	strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
+	light->coronasizescale = coronasizescale;
+	light->ambientscale = ambientscale;
+	light->diffusescale = diffusescale;
+	light->specularscale = specularscale;
+	light->flags = flags;
 	Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
 
 	R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
@@ -2508,9 +2791,9 @@ void R_Shadow_SelectLightInView(void)
 
 void R_Shadow_LoadWorldLights(void)
 {
-	int n, a, style, shadow;
+	int n, a, style, shadow, flags;
 	char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
-	float origin[3], radius, color[3], angles[3], corona;
+	float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
 	if (cl.worldmodel == NULL)
 	{
 		Con_Print("No map loaded.\n");
@@ -2554,7 +2837,17 @@ void R_Shadow_LoadWorldLights(void)
 				shadow = false;
 				t++;
 			}
-			a = sscanf(t, "%f %f %f %f %f %f %f %d %s %f %f %f %f", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname, &corona, &angles[0], &angles[1], &angles[2]);
+			a = sscanf(t, "%f %f %f %f %f %f %f %d %s %f %f %f %f %f %f %f %f %i", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname, &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
+			if (a < 18)
+				flags = LIGHTFLAG_REALTIMEMODE;
+			if (a < 17)
+				specularscale = 1;
+			if (a < 16)
+				diffusescale = 1;
+			if (a < 15)
+				ambientscale = 0;
+			if (a < 14)
+				coronasizescale = 0.25f;
 			if (a < 13)
 				VectorClear(angles);
 			if (a < 10)
@@ -2564,12 +2857,12 @@ void R_Shadow_LoadWorldLights(void)
 			*s = '\n';
 			if (a < 8)
 			{
-				Con_Printf("found %d parameters on line %i, should be 8 or more parameters (origin[0] origin[1] origin[2] radius color[0] color[1] color[2] style \"cubemapname\" corona angles[0] angles[1] angles[2])\n", a, n + 1);
+				Con_Printf("found %d parameters on line %i, should be 8 or more parameters (origin[0] origin[1] origin[2] radius color[0] color[1] color[2] style \"cubemapname\" corona angles[0] angles[1] angles[2] coronasizescale ambientscale diffusescale specularscale flags)\n", a, n + 1);
 				break;
 			}
 			VectorScale(color, r_editlights_rtlightscolorscale.value, color);
 			radius *= r_editlights_rtlightssizescale.value;
-			R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname);
+			R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
 			s++;
 			n++;
 		}
@@ -2599,6 +2892,8 @@ void R_Shadow_SaveWorldLights(void)
 	buf = NULL;
 	for (light = r_shadow_worldlightchain;light;light = light->next)
 	{
+		if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
+			sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f %f %f %f %f %i\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2], light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
 		if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
 			sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
 		else
@@ -2662,7 +2957,7 @@ void R_Shadow_LoadLightsFile(void)
 			radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
 			radius = bound(15, radius, 4096);
 			VectorScale(color, (2.0f / (8388608.0f)), color);
-			R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL);
+			R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
 			s++;
 			n++;
 		}
@@ -2886,7 +3181,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
 		}
 		VectorAdd(origin, originhack, origin);
 		if (radius >= 1)
-			R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
+			R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
 	}
 	if (entfiledata)
 		Mem_Free(entfiledata);
@@ -2979,14 +3274,14 @@ void R_Shadow_EditLights_Spawn_f(void)
 		return;
 	}
 	color[0] = color[1] = color[2] = 1;
-	R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
+	R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
 }
 
 void R_Shadow_EditLights_Edit_f(void)
 {
 	vec3_t origin, angles, color;
-	vec_t radius, corona;
-	int style, shadows;
+	vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
+	int style, shadows, flags, normalmode, realtimemode;
 	char cubemapname[1024];
 	if (!r_editlights.integer)
 	{
@@ -3009,6 +3304,13 @@ void R_Shadow_EditLights_Edit_f(void)
 		cubemapname[0] = 0;
 	shadows = r_shadow_selectedlight->shadow;
 	corona = r_shadow_selectedlight->corona;
+	coronasizescale = r_shadow_selectedlight->coronasizescale;
+	ambientscale = r_shadow_selectedlight->ambientscale;
+	diffusescale = r_shadow_selectedlight->diffusescale;
+	specularscale = r_shadow_selectedlight->specularscale;
+	flags = r_shadow_selectedlight->flags;
+	normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
+	realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
 	if (!strcmp(Cmd_Argv(1), "origin"))
 	{
 		if (Cmd_Argc() != 5)
@@ -3182,21 +3484,82 @@ void R_Shadow_EditLights_Edit_f(void)
 		}
 		corona = atof(Cmd_Argv(2));
 	}
+	else if (!strcmp(Cmd_Argv(1), "coronasize"))
+	{
+		if (Cmd_Argc() != 3)
+		{
+			Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
+			return;
+		}
+		coronasizescale = atof(Cmd_Argv(2));
+	}
+	else if (!strcmp(Cmd_Argv(1), "ambient"))
+	{
+		if (Cmd_Argc() != 3)
+		{
+			Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
+			return;
+		}
+		ambientscale = atof(Cmd_Argv(2));
+	}
+	else if (!strcmp(Cmd_Argv(1), "diffuse"))
+	{
+		if (Cmd_Argc() != 3)
+		{
+			Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
+			return;
+		}
+		diffusescale = atof(Cmd_Argv(2));
+	}
+	else if (!strcmp(Cmd_Argv(1), "specular"))
+	{
+		if (Cmd_Argc() != 3)
+		{
+			Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
+			return;
+		}
+		specularscale = atof(Cmd_Argv(2));
+	}
+	else if (!strcmp(Cmd_Argv(1), "normalmode"))
+	{
+		if (Cmd_Argc() != 3)
+		{
+			Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
+			return;
+		}
+		normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
+	}
+	else if (!strcmp(Cmd_Argv(1), "realtimemode"))
+	{
+		if (Cmd_Argc() != 3)
+		{
+			Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
+			return;
+		}
+		realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
+	}
 	else
 	{
 		Con_Print("usage: r_editlights_edit [property] [value]\n");
 		Con_Print("Selected light's properties:\n");
-		Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
-		Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
-		Con_Printf("Color  : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
-		Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
-		Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
-		Con_Printf("Style  : %i\n", r_shadow_selectedlight->style);
-		Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
-		Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
+		Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
+		Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
+		Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
+		Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
+		Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
+		Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
+		Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
+		Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
+		Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
+		Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
+		Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
+		Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
+		Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
+		Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
 		return;
 	}
-	R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname);
+	flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
+	R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
 }
 
 void R_Shadow_EditLights_EditAll_f(void)
@@ -3235,15 +3598,21 @@ void R_Shadow_EditLights_DrawSelectedLightProperties(void)
 	if (r_shadow_selectedlight == NULL)
 		return;
 	sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
-	sprintf(temp, "Origin  %f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
-	sprintf(temp, "Angles  %f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
-	sprintf(temp, "Color   %f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
-	sprintf(temp, "Radius  %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
-	sprintf(temp, "Corona  %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
-	sprintf(temp, "Style   %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
-	sprintf(temp, "Shadows %s", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
-	sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
-}
+	sprintf(temp, "Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+	sprintf(temp, "Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+	sprintf(temp, "Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+	sprintf(temp, "Radius       : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+	sprintf(temp, "Corona       : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+	sprintf(temp, "Style        : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+	sprintf(temp, "Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+	sprintf(temp, "Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+	sprintf(temp, "CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+	sprintf(temp, "Ambient      : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+	sprintf(temp, "Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+	sprintf(temp, "Specular     : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+	sprintf(temp, "NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+	sprintf(temp, "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+}                 
 
 void R_Shadow_EditLights_ToggleShadow_f(void)
 {
@@ -3257,7 +3626,7 @@ void R_Shadow_EditLights_ToggleShadow_f(void)
 		Con_Print("No selected light.\n");
 		return;
 	}
-	R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
+	R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
 }
 
 void R_Shadow_EditLights_ToggleCorona_f(void)
@@ -3272,7 +3641,7 @@ void R_Shadow_EditLights_ToggleCorona_f(void)
 		Con_Print("No selected light.\n");
 		return;
 	}
-	R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
+	R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
 }
 
 void R_Shadow_EditLights_Remove_f(void)
@@ -3334,6 +3703,12 @@ void R_Shadow_EditLights_Help_f(void)
 "cubemap basename : set filter cubemap of light (not yet supported)\n"
 "shadows 1/0 : turn on/off shadows\n"
 "corona n : set corona intensity\n"
+"coronasize n : set corona size (0-1)\n"
+"ambient n : set ambient intensity (0-1)\n"
+"diffuse n : set diffuse intensity (0-1)\n"
+"specular n : set specular intensity (0-1)\n"
+"normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
+"realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
 "<nothing> : print light properties to console\n"
 	);
 }
@@ -3360,6 +3735,11 @@ void R_Shadow_EditLights_CopyInfo_f(void)
 		r_shadow_bufferlight.cubemapname[0] = 0;
 	r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
 	r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
+	r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
+	r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
+	r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
+	r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
+	r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
 }
 
 void R_Shadow_EditLights_PasteInfo_f(void)
@@ -3374,7 +3754,7 @@ void R_Shadow_EditLights_PasteInfo_f(void)
 		Con_Print("No selected light.\n");
 		return;
 	}
-	R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname);
+	R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname, r_shadow_bufferlight.coronasizescale, r_shadow_bufferlight.ambientscale, r_shadow_bufferlight.diffusescale, r_shadow_bufferlight.specularscale, r_shadow_bufferlight.flags);
 }
 
 void R_Shadow_EditLights_Init(void)
diff --git a/r_shadow.h b/r_shadow.h
index 29fd65b8..7abd67a4 100644
--- a/r_shadow.h
+++ b/r_shadow.h
@@ -34,9 +34,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, vec3_t lightmins, vec3_t lightmaxs, vec3_t surfacemins, vec3_t surfacemaxs);
-#define LIGHTING_DIFFUSE 1
-#define LIGHTING_SPECULAR 2
-void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements, const float *vertices, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *relativeeyeorigin, const float *lightcolor, const matrix4x4_t *matrix_worldtolight, const matrix4x4_t *matrix_worldtoattenuationxyz, const matrix4x4_t *matrix_worldtoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, int lightingflags);
+void R_Shadow_RenderLighting(int numverts, 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 *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale);
 void R_Shadow_ClearStencil(void);
 
 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i);
-- 
2.39.5