]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
implemented and debugged BIH (Bounding Interval Hierarchy) code, more
[xonotic/darkplaces.git] / r_shadow.c
index b0467c282f7f3935d9bb1e17b0b0c6fd97ef0b5a..b47711144f1845bff441a76804743a8b248ef7f4 100644 (file)
@@ -140,8 +140,6 @@ demonstrated by the game Doom3.
 #include "portals.h"
 #include "image.h"
 
-#define R_SHADOW_SHADOWMAP_NUMCUBEMAPS 8
-
 extern void R_Shadow_EditLights_Init(void);
 
 typedef enum r_shadow_rendermode_e
@@ -154,7 +152,9 @@ typedef enum r_shadow_rendermode_e
        R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
        R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
        R_SHADOW_RENDERMODE_LIGHT_VERTEX,
-       R_SHADOW_RENDERMODE_LIGHT_DOT3,
+       R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
+       R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
+       R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
        R_SHADOW_RENDERMODE_LIGHT_GLSL,
        R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
        R_SHADOW_RENDERMODE_VISIBLELIGHTING,
@@ -180,6 +180,7 @@ r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_N
 qboolean r_shadow_usingshadowmaprect;
 qboolean r_shadow_usingshadowmap2d;
 qboolean r_shadow_usingshadowmapcube;
+qboolean r_shadow_usingshadowmaportho;
 int r_shadow_shadowmapside;
 float r_shadow_shadowmap_texturescale[2];
 float r_shadow_shadowmap_parameters[4];
@@ -194,13 +195,15 @@ GLuint r_shadow_fbo2d;
 r_shadow_shadowmode_t r_shadow_shadowmode;
 int r_shadow_shadowmapfilterquality;
 int r_shadow_shadowmaptexturetype;
-int r_shadow_shadowmapprecision;
+int r_shadow_shadowmapdepthbits;
 int r_shadow_shadowmapmaxsize;
 qboolean r_shadow_shadowmapvsdct;
 qboolean r_shadow_shadowmapsampler;
 int r_shadow_shadowmappcf;
 int r_shadow_shadowmapborder;
+matrix4x4_t r_shadow_shadowmapmatrix;
 int r_shadow_lightscissor[4];
+qboolean r_shadow_usingdeferredprepass;
 
 int maxshadowtriangles;
 int *shadowelements;
@@ -243,7 +246,7 @@ rtexturepool_t *r_shadow_texturepool;
 rtexture_t *r_shadow_attenuationgradienttexture;
 rtexture_t *r_shadow_attenuation2dtexture;
 rtexture_t *r_shadow_attenuation3dtexture;
-rtexture_t *r_shadow_lightcorona;
+skinframe_t *r_shadow_lightcorona;
 rtexture_t *r_shadow_shadowmaprectangletexture;
 rtexture_t *r_shadow_shadowmap2dtexture;
 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
@@ -251,15 +254,29 @@ rtexture_t *r_shadow_shadowmapvsdcttexture;
 int r_shadow_shadowmapsize; // changes for each light based on distance
 int r_shadow_shadowmaplod; // changes for each light based on distance
 
+GLuint r_shadow_prepassgeometryfbo;
+GLuint r_shadow_prepasslightingfbo;
+int r_shadow_prepass_width;
+int r_shadow_prepass_height;
+rtexture_t *r_shadow_prepassgeometrydepthtexture;
+rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
+rtexture_t *r_shadow_prepasslightingdiffusetexture;
+rtexture_t *r_shadow_prepasslightingspeculartexture;
+
 // lights are reloaded when this changes
 char r_shadow_mapname[MAX_QPATH];
 
 // used only for light filters (cubemaps)
 rtexturepool_t *r_shadow_filters_texturepool;
 
+static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
+
 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
+cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
+cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "2", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
+//cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
@@ -271,8 +288,7 @@ cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdivid
 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
-cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
-cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
+cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
@@ -283,28 +299,27 @@ cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_
 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
-cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
-cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
+cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
+cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "0", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"};
 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
-cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "24", "requested minimum shadowmap texture precision"};
+cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
-cvar_t r_shadow_shadowmapping_quality = {CVAR_SAVE, "r_shadow_shadowmapping_quality", "0", "Makes shadowmaps to have initial resolution of this number of pixels per light source radius unit. Like, light with radius 200 will have initial shadowmaps with resolution 200. This overrides default LOD-based shadowmaps resolution formula. Might be good in some situations but futher testing is required."};
-cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
-cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
+cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
+//cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
+//cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
-cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
-cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"};
+cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
@@ -337,17 +352,6 @@ vec3_t r_editlights_cursorlocation;
 
 extern int con_vislines;
 
-typedef struct cubemapinfo_s
-{
-       char basename[64];
-       rtexture_t *texture;
-}
-cubemapinfo_t;
-
-#define MAX_CUBEMAPS 256
-static int numcubemaps;
-static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
-
 void R_Shadow_UncompileWorldLights(void);
 void R_Shadow_ClearWorldLights(void);
 void R_Shadow_SaveWorldLights(void);
@@ -358,83 +362,105 @@ void R_Shadow_EditLights_Reload_f(void);
 void R_Shadow_ValidateCvars(void);
 static void R_Shadow_MakeTextures(void);
 
-// VorteX: custom editor light sprites
 #define EDLIGHTSPRSIZE                 8
-cachepic_t *r_editlights_sprcursor;
-cachepic_t *r_editlights_sprlight;
-cachepic_t *r_editlights_sprnoshadowlight;
-cachepic_t *r_editlights_sprcubemaplight;
-cachepic_t *r_editlights_sprcubemapnoshadowlight;
-cachepic_t *r_editlights_sprselection;
+skinframe_t *r_editlights_sprcursor;
+skinframe_t *r_editlights_sprlight;
+skinframe_t *r_editlights_sprnoshadowlight;
+skinframe_t *r_editlights_sprcubemaplight;
+skinframe_t *r_editlights_sprcubemapnoshadowlight;
+skinframe_t *r_editlights_sprselection;
 
 void R_Shadow_SetShadowMode(void)
 {
-       r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
+       r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
        r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
        r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
        r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
-       r_shadow_shadowmapprecision = r_shadow_shadowmapping_precision.integer;
+       r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
        r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
        r_shadow_shadowmaplod = -1;
        r_shadow_shadowmapsize = 0;
        r_shadow_shadowmapsampler = false;
        r_shadow_shadowmappcf = 0;
        r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
-       if(r_shadow_shadowmapping.integer && r_glsl.integer && gl_support_fragment_shader && gl_support_ext_framebuffer_object)
+       switch(vid.renderpath)
        {
-               if(r_shadow_shadowmapfilterquality < 0)
+       case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
+               if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
                {
-                       if(strstr(gl_vendor, "NVIDIA")) 
+                       if(r_shadow_shadowmapfilterquality < 0)
                        {
-                               r_shadow_shadowmapsampler = gl_support_arb_shadow;
-                               r_shadow_shadowmappcf = 1;
+                               if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
+                                       r_shadow_shadowmappcf = 1;
+                               else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) 
+                               {
+                                       r_shadow_shadowmapsampler = vid.support.arb_shadow;
+                                       r_shadow_shadowmappcf = 1;
+                               }
+                               else if(strstr(gl_vendor, "ATI")) 
+                                       r_shadow_shadowmappcf = 1;
+                               else 
+                                       r_shadow_shadowmapsampler = vid.support.arb_shadow;
                        }
-                       else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) 
-                               r_shadow_shadowmappcf = 1;
-                       else if(strstr(gl_vendor, "ATI")) 
-                               r_shadow_shadowmappcf = 1;
                        else 
-                               r_shadow_shadowmapsampler = gl_support_arb_shadow;
-               }
-               else 
-               {
-                       switch (r_shadow_shadowmapfilterquality)
                        {
+                               switch (r_shadow_shadowmapfilterquality)
+                               {
+                               case 1:
+                                       r_shadow_shadowmapsampler = vid.support.arb_shadow;
+                                       break;
+                               case 2:
+                                       r_shadow_shadowmapsampler = vid.support.arb_shadow;
+                                       r_shadow_shadowmappcf = 1;
+                                       break;
+                               case 3:
+                                       r_shadow_shadowmappcf = 1;
+                                       break;
+                               case 4:
+                                       r_shadow_shadowmappcf = 2;
+                                       break;
+                               }
+                       }
+                       switch (r_shadow_shadowmaptexturetype)
+                       {
+                       case 0:
+                               r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
+                               break;
                        case 1:
-                               r_shadow_shadowmapsampler = gl_support_arb_shadow;
+                               r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
                                break;
                        case 2:
-                               r_shadow_shadowmapsampler = gl_support_arb_shadow;
-                               r_shadow_shadowmappcf = 1;
+                               r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
                                break;
-                       case 3:
-                               r_shadow_shadowmappcf = 1;
-                               break;
-                       case 4:
-                               r_shadow_shadowmappcf = 2;
+                       default:
+                               if((vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
+                                       r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
+                               else if(vid.support.arb_texture_rectangle) 
+                                       r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
+                               else
+                                       r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
                                break;
                        }
                }
-        switch (r_shadow_shadowmaptexturetype)
-        {
-        case 0:
-            r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
-            break;
-        case 1:
-            r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
-            break;
-        case 2:
-            r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
-            break;
-        default:
-                       if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
-                               r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
-                       else if(gl_texturerectangle) 
-                               r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
-                       else
-                               r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
-            break;
-               }
+               break;
+       case RENDERPATH_GL13:
+               break;
+       case RENDERPATH_GL11:
+               break;
+       }
+}
+
+qboolean R_Shadow_ShadowMappingEnabled(void)
+{
+       switch (r_shadow_shadowmode)
+       {
+       case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
+       case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
+       case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
+               return true;
+       default:
+               return false;
        }
 }
 
@@ -444,20 +470,22 @@ void R_Shadow_FreeShadowMaps(void)
 
        R_Shadow_SetShadowMode();
 
+       if (!vid.support.ext_framebuffer_object || !vid.support.arb_fragment_shader)
+               return;
+
+       CHECKGLERROR
+
        if (r_shadow_fborectangle)
-               qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
+               qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
        r_shadow_fborectangle = 0;
-       CHECKGLERROR
 
        if (r_shadow_fbo2d)
-               qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
+               qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
        r_shadow_fbo2d = 0;
-       CHECKGLERROR
        for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
                if (r_shadow_fbocubeside[i])
-                       qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);
+                       qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);CHECKGLERROR
        memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
-       CHECKGLERROR
 
        if (r_shadow_shadowmaprectangletexture)
                R_FreeTexture(r_shadow_shadowmaprectangletexture);
@@ -482,7 +510,6 @@ void R_Shadow_FreeShadowMaps(void)
 void r_shadow_start(void)
 {
        // allocate vertex processing arrays
-       numcubemaps = 0;
        r_shadow_attenuationgradienttexture = NULL;
        r_shadow_attenuation2dtexture = NULL;
        r_shadow_attenuation3dtexture = NULL;
@@ -496,7 +523,7 @@ void r_shadow_start(void)
        r_shadow_shadowmaplod = 0;
        r_shadow_shadowmapfilterquality = -1;
        r_shadow_shadowmaptexturetype = -1;
-       r_shadow_shadowmapprecision = 0;
+       r_shadow_shadowmapdepthbits = 0;
        r_shadow_shadowmapvsdct = false;
        r_shadow_shadowmapsampler = false;
        r_shadow_shadowmappcf = 0;
@@ -539,8 +566,12 @@ void r_shadow_start(void)
        r_shadow_buffer_shadowtrispvs = NULL;
        r_shadow_buffer_numlighttrispvsbytes = 0;
        r_shadow_buffer_lighttrispvs = NULL;
+
+       r_shadow_usingdeferredprepass = false;
+       r_shadow_prepass_width = r_shadow_prepass_height = 0;
 }
 
+static void R_Shadow_FreeDeferred(void);
 void r_shadow_shutdown(void)
 {
        CHECKGLERROR
@@ -548,8 +579,12 @@ void r_shadow_shutdown(void)
 
        R_Shadow_FreeShadowMaps();
 
+       r_shadow_usingdeferredprepass = false;
+       if (r_shadow_prepass_width)
+               R_Shadow_FreeDeferred();
+       r_shadow_prepass_width = r_shadow_prepass_height = 0;
+
        CHECKGLERROR
-       numcubemaps = 0;
        r_shadow_attenuationgradienttexture = NULL;
        r_shadow_attenuation2dtexture = NULL;
        r_shadow_attenuation3dtexture = NULL;
@@ -617,51 +652,26 @@ void r_shadow_shutdown(void)
 
 void r_shadow_newmap(void)
 {
+       if (r_shadow_lightcorona)                 R_SkinFrame_MarkUsed(r_shadow_lightcorona);
+       if (r_editlights_sprcursor)               R_SkinFrame_MarkUsed(r_editlights_sprcursor);
+       if (r_editlights_sprlight)                R_SkinFrame_MarkUsed(r_editlights_sprlight);
+       if (r_editlights_sprnoshadowlight)        R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
+       if (r_editlights_sprcubemaplight)         R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
+       if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
+       if (r_editlights_sprselection)            R_SkinFrame_MarkUsed(r_editlights_sprselection);
        if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
                R_Shadow_EditLights_Reload_f();
 }
 
-void R_Shadow_Help_f(void)
-{
-       Con_Printf(
-"Documentation on r_shadow system:\n"
-"Settings:\n"
-"r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
-"r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
-"r_shadow_debuglight : render only this light number (-1 = all)\n"
-"r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
-"r_shadow_gloss2intensity : brightness of forced gloss\n"
-"r_shadow_glossintensity : brightness of textured gloss\n"
-"r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
-"r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
-"r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
-"r_shadow_lightradiusscale : scale rendering radius of all lights\n"
-"r_shadow_portallight : use portal visibility for static light precomputation\n"
-"r_shadow_projectdistance : shadow volume projection distance\n"
-"r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
-"r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
-"r_shadow_realtime_world : use high quality world lighting mode\n"
-"r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
-"r_shadow_realtime_world_shadows : cast shadows from world lights\n"
-"r_shadow_realtime_world_compile : compile surface/visibility information\n"
-"r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
-"r_shadow_scissor : use scissor optimization\n"
-"r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
-"r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
-"r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
-"r_showlighting : useful for performance testing; bright = slow!\n"
-"r_showshadowvolumes : useful for performance testing; bright = slow!\n"
-"Commands:\n"
-"r_shadow_help : this help\n"
-       );
-}
-
 void R_Shadow_Init(void)
 {
        Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
        Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
        Cvar_RegisterVariable(&r_shadow_usenormalmap);
        Cvar_RegisterVariable(&r_shadow_debuglight);
+       Cvar_RegisterVariable(&r_shadow_deferred);
+       Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
+//     Cvar_RegisterVariable(&r_shadow_deferred_fp);
        Cvar_RegisterVariable(&r_shadow_gloss);
        Cvar_RegisterVariable(&r_shadow_gloss2intensity);
        Cvar_RegisterVariable(&r_shadow_glossintensity);
@@ -672,7 +682,6 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
        Cvar_RegisterVariable(&r_shadow_lightintensityscale);
        Cvar_RegisterVariable(&r_shadow_lightradiusscale);
-       Cvar_RegisterVariable(&r_shadow_portallight);
        Cvar_RegisterVariable(&r_shadow_projectdistance);
        Cvar_RegisterVariable(&r_shadow_frontsidecasting);
        Cvar_RegisterVariable(&r_shadow_realtime_dlight);
@@ -691,18 +700,17 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
+       Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
-       Cvar_RegisterVariable(&r_shadow_shadowmapping_quality);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
-       Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
-       Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
+//     Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
+//     Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
-       Cvar_RegisterVariable(&r_shadow_culltriangles);
        Cvar_RegisterVariable(&r_shadow_polygonfactor);
        Cvar_RegisterVariable(&r_shadow_polygonoffset);
        Cvar_RegisterVariable(&r_shadow_texture3d);
@@ -717,7 +725,6 @@ void R_Shadow_Init(void)
                Cvar_SetValue("r_shadow_gloss", 2);
                Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
        }
-       Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
        R_Shadow_EditLights_Init();
        Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
        maxshadowtriangles = 0;
@@ -1307,6 +1314,12 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f,
                tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
                Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
        }
+       else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
+       {
+               tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
+               R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
+               R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
+       }
        else
        {
                // decide which type of shadow to generate and set stencil mode
@@ -1320,7 +1333,6 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f,
                r_refdef.stats.lights_shadowtriangles += tris;
                CHECKGLERROR
                R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
-               GL_LockArrays(0, outverts);
                if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
                {
                        // increment stencil if frontface is infront of depthbuffer
@@ -1342,7 +1354,6 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f,
                        qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
                }
                R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
-               GL_LockArrays(0, 0);
                CHECKGLERROR
        }
 }
@@ -1496,19 +1507,48 @@ int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
        }
        // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
        // check if frustum corners/origin cross plane sides
+#if 1
+    // infinite version, assumes frustum corners merely give direction and extend to infinite distance
+    Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
+    dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
+    masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
+    masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
+    dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
+    masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
+    masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
+    dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
+    masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
+    masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
+    for (i = 0;i < 4;i++)
+    {
+        Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
+        VectorSubtract(n, p, n);
+        dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
+        if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
+        if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
+        dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
+        if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
+        if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
+        dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
+        if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
+        if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
+    }
+#else
+    // finite version, assumes corners are a finite distance from origin dependent on far plane
        for (i = 0;i < 5;i++)
        {
                Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
-               dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
+               dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
                masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
                masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
-               dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
+               dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
                masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
                masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
-               dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
+               dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
                masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
                masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
        }
+#endif
        return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
 }
 
@@ -1675,7 +1715,7 @@ static void R_Shadow_MakeTextures_MakeCorona(void)
                        pixels[y][x][3] = 255;
                }
        }
-       r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
+       r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
 }
 
 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
@@ -1691,6 +1731,7 @@ static void R_Shadow_MakeTextures(void)
        int x, y, z;
        float intensity, dist;
        unsigned int *data;
+       R_Shadow_FreeShadowMaps();
        R_FreeTexturePool(&r_shadow_texturepool);
        r_shadow_texturepool = R_AllocTexturePool();
        r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
@@ -1706,20 +1747,20 @@ static void R_Shadow_MakeTextures(void)
        // 1D gradient texture
        for (x = 0;x < ATTEN1DSIZE;x++)
                data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
-       r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
+       r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
        // 2D circle texture
        for (y = 0;y < ATTEN2DSIZE;y++)
                for (x = 0;x < ATTEN2DSIZE;x++)
                        data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0);
-       r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
+       r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
        // 3D sphere texture
-       if (r_shadow_texture3d.integer && gl_texture3d)
+       if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
        {
                for (z = 0;z < ATTEN3DSIZE;z++)
                        for (y = 0;y < ATTEN3DSIZE;y++)
                                for (x = 0;x < ATTEN3DSIZE;x++)
                                        data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375));
-               r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
+               r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
        }
        else
                r_shadow_attenuation3dtexture = NULL;
@@ -1728,21 +1769,123 @@ static void R_Shadow_MakeTextures(void)
        R_Shadow_MakeTextures_MakeCorona();
 
        // Editor light sprites
-       r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
-       r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
-       r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
-       r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
-       r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
-       r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
+       r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
+       "................"
+       ".3............3."
+       "..5...2332...5.."
+       "...7.3....3.7..."
+       "....7......7...."
+       "...3.7....7.3..."
+       "..2...7..7...2.."
+       "..3..........3.."
+       "..3..........3.."
+       "..2...7..7...2.."
+       "...3.7....7.3..."
+       "....7......7...."
+       "...7.3....3.7..."
+       "..5...2332...5.."
+       ".3............3."
+       "................"
+       , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
+       r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
+       "................"
+       "................"
+       "......1111......"
+       "....11233211...."
+       "...1234554321..."
+       "...1356776531..."
+       "..124677776421.."
+       "..135777777531.."
+       "..135777777531.."
+       "..124677776421.."
+       "...1356776531..."
+       "...1234554321..."
+       "....11233211...."
+       "......1111......"
+       "................"
+       "................"
+       , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
+       r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
+       "................"
+       "................"
+       "......1111......"
+       "....11233211...."
+       "...1234554321..."
+       "...1356226531..."
+       "..12462..26421.."
+       "..1352....2531.."
+       "..1352....2531.."
+       "..12462..26421.."
+       "...1356226531..."
+       "...1234554321..."
+       "....11233211...."
+       "......1111......"
+       "................"
+       "................"
+       , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
+       r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
+       "................"
+       "................"
+       "......2772......"
+       "....27755772...."
+       "..277533335772.."
+       "..753333333357.."
+       "..777533335777.."
+       "..735775577537.."
+       "..733357753337.."
+       "..733337733337.."
+       "..753337733357.."
+       "..277537735772.."
+       "....27777772...."
+       "......2772......"
+       "................"
+       "................"
+       , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
+       r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
+       "................"
+       "................"
+       "......2772......"
+       "....27722772...."
+       "..2772....2772.."
+       "..72........27.."
+       "..7772....2777.."
+       "..7.27722772.7.."
+       "..7...2772...7.."
+       "..7....77....7.."
+       "..72...77...27.."
+       "..2772.77.2772.."
+       "....27777772...."
+       "......2772......"
+       "................"
+       "................"
+       , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
+       r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
+       "................"
+       ".777752..257777."
+       ".742........247."
+       ".72..........27."
+       ".7............7."
+       ".5............5."
+       ".2............2."
+       "................"
+       "................"
+       ".2............2."
+       ".5............5."
+       ".7............7."
+       ".72..........27."
+       ".742........247."
+       ".777752..257777."
+       "................"
+       , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
 }
 
 void R_Shadow_ValidateCvars(void)
 {
-       if (r_shadow_texture3d.integer && !gl_texture3d)
+       if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
                Cvar_SetValueQuick(&r_shadow_texture3d, 0);
-       if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
+       if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
                Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
-       if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
+       if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
                Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
 }
 
@@ -1773,12 +1916,12 @@ void R_Shadow_RenderMode_Begin(void)
 
        r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
 
-       if (gl_ext_separatestencil.integer)
+       if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
        {
                r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
                r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
        }
-       else if (gl_ext_stenciltwoside.integer)
+       else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
        {
                r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
                r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
@@ -1789,12 +1932,24 @@ void R_Shadow_RenderMode_Begin(void)
                r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
        }
 
-       if (r_glsl.integer && gl_support_fragment_shader)
+       switch(vid.renderpath)
+       {
+       case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
                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;
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
+                       r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
+               else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
+                       r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
+               else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
+                       r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
+               else
+                       r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
+               break;
+       }
 
        CHECKGLERROR
 #if 0
@@ -1819,7 +1974,7 @@ void R_Shadow_RenderMode_Reset(void)
        {
                qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
        }
-       if (gl_support_ext_framebuffer_object)
+       if (vid.support.ext_framebuffer_object)
        {
                qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
        }
@@ -1837,19 +1992,20 @@ void R_Shadow_RenderMode_Reset(void)
        qglDepthFunc(GL_LEQUAL);CHECKGLERROR
        GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
        qglDisable(GL_STENCIL_TEST);CHECKGLERROR
-       qglStencilMask(~0);CHECKGLERROR
+       qglStencilMask(255);CHECKGLERROR
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
-       qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
+       qglStencilFunc(GL_ALWAYS, 128, 255);CHECKGLERROR
        r_refdef.view.cullface_front = r_shadow_cullface_front;
        r_refdef.view.cullface_back = r_shadow_cullface_back;
        GL_CullFace(r_refdef.view.cullface_back);
        GL_Color(1, 1, 1, 1);
        GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
        GL_BlendFunc(GL_ONE, GL_ZERO);
-       R_SetupGenericShader(false);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
        r_shadow_usingshadowmaprect = false;
        r_shadow_usingshadowmapcube = false;
        r_shadow_usingshadowmap2d = false;
+       r_shadow_usingshadowmaportho = false;
        CHECKGLERROR
 }
 
@@ -1869,7 +2025,7 @@ void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
        R_Shadow_RenderMode_Reset();
        GL_ColorMask(0, 0, 0, 0);
        GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
-       R_SetupDepthOrShadowShader();
+       R_SetupShader_DepthOrShadow();
        qglDepthFunc(GL_LESS);CHECKGLERROR
        qglEnable(GL_STENCIL_TEST);CHECKGLERROR
        r_shadow_rendermode = mode;
@@ -1891,20 +2047,20 @@ void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
                GL_CullFace(GL_NONE);
                qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
                qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
-               qglStencilMask(~0);CHECKGLERROR
+               qglStencilMask(255);CHECKGLERROR
                qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
                qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
-               qglStencilMask(~0);CHECKGLERROR
+               qglStencilMask(255);CHECKGLERROR
                qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
                break;
        case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
                GL_CullFace(GL_NONE);
                qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
                qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
-               qglStencilMask(~0);CHECKGLERROR
+               qglStencilMask(255);CHECKGLERROR
                qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
                qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
-               qglStencilMask(~0);CHECKGLERROR
+               qglStencilMask(255);CHECKGLERROR
                qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
                break;
        }
@@ -1927,29 +2083,69 @@ static void R_Shadow_MakeVSDCT(void)
                0,   0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
                0,   0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
        };
-       r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL); 
+       r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
 }
 
-void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
+static void R_Shadow_MakeShadowMap(int side, int size)
 {
        int status;
-       int maxsize;
+       switch (r_shadow_shadowmode)
+       {
+       case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
+               if (r_shadow_shadowmap2dtexture) return;
+               r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
+               qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
+               qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
+               qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
+               break;
+       case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
+               if (r_shadow_shadowmaprectangletexture) return;
+               r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
+               qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
+               qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
+               qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
+               break;
+       case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
+               if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) return;
+               r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
+               qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
+               qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
+               qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
+               break;
+       default:
+               return;
+       }
+       // render depth into the fbo, do not render color at all
+       qglDrawBuffer(GL_NONE);CHECKGLERROR
+       qglReadBuffer(GL_NONE);CHECKGLERROR
+       status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
+       if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
+       {
+               Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
+               Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
+               Cvar_SetValueQuick(&r_shadow_deferred, 0);
+       }
+}
+       
+void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
+{
        float nearclip, farclip, bias;
        r_viewport_t viewport;
+       int flipped;
        GLuint fbo = 0;
        CHECKGLERROR
-       maxsize = r_shadow_shadowmapmaxsize;
        nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
        farclip = 1.0f;
        bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
-       r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
-       r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
+       r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
+       r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
        r_shadow_shadowmapside = side;
        r_shadow_shadowmapsize = size;
-       if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
+       switch (r_shadow_shadowmode)
        {
+       case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
                r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
-               r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
+               r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
                R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
                if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
 
@@ -1957,34 +2153,16 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
                if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
                        R_Shadow_MakeVSDCT();
                if (!r_shadow_shadowmap2dtexture)
-               {
-#if 1
-                       int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
-                       r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
-                       qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
-                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
-                       qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
-            // render depth into the fbo, do not render color at all
-                       qglDrawBuffer(GL_NONE);CHECKGLERROR
-                       qglReadBuffer(GL_NONE);CHECKGLERROR
-                       status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
-                       if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
-                       {
-                               Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
-                               Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
-                       }
-#endif
-               }
+                       R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
                CHECKGLERROR
                if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
                r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
                r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
                r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
-       }
-       else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
-       {
+               break;
+       case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
                r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
-               r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
+               r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
                R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
                if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
 
@@ -1992,71 +2170,41 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
                if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
                        R_Shadow_MakeVSDCT();
                if (!r_shadow_shadowmaprectangletexture)
-               {
-#if 1
-                       r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
-                       qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
-                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
-                       qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
-                       // render depth into the fbo, do not render color at all
-                       qglDrawBuffer(GL_NONE);CHECKGLERROR
-                       qglReadBuffer(GL_NONE);CHECKGLERROR
-                       status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
-                       if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
-                       {
-                               Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
-                               Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
-                       }
-#endif
-               }
+                       R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
                CHECKGLERROR
                if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
                r_shadow_shadowmap_texturescale[0] = 1.0f;
                r_shadow_shadowmap_texturescale[1] = 1.0f;
                r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
-       }
-       else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
-       {
+               break;
+       case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
                r_shadow_shadowmap_parameters[0] = 1.0f;
-               r_shadow_shadowmap_parameters[1] = 1.0f;
+               r_shadow_shadowmap_parameters[2] = 1.0f;
                R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
                if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
 
                // simple cube approach
                if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
-               {
- #if 1
-                       r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
-                       qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
-                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
-                       qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
-                       // render depth into the fbo, do not render color at all
-                       qglDrawBuffer(GL_NONE);CHECKGLERROR
-                       qglReadBuffer(GL_NONE);CHECKGLERROR
-                       status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
-                       if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
-                       {
-                               Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
-                               Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
-                       }
- #endif
-               }
+                       R_Shadow_MakeShadowMap(side, size);
                CHECKGLERROR
                if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
                r_shadow_shadowmap_texturescale[0] = 0.0f;
                r_shadow_shadowmap_texturescale[1] = 0.0f;
                r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
+               break;
+       default:
+               break;
        }
 
        R_Shadow_RenderMode_Reset();
        if (fbo)
        {
                qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
-               R_SetupDepthOrShadowShader();
+               R_SetupShader_DepthOrShadow();
        }
        else
        {
-               R_SetupShowDepthShader();
+               R_SetupShader_ShowDepth();
                qglClearColor(1,1,1,1);CHECKGLERROR
        }
        CHECKGLERROR
@@ -2068,25 +2216,47 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
 
 init_done:
        R_SetViewport(&viewport);
-       GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
-       if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
+       switch (r_shadow_rendermode)
        {
-               int flipped = (side&1)^(side>>2);
+       case R_SHADOW_RENDERMODE_SHADOWMAP2D:
+       case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
+               flipped = (side & 1) ^ (side >> 2);
                r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
                r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
                GL_CullFace(r_refdef.view.cullface_back);
-       }
-       else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
-       {
+               if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
+               {
+                       // get tightest scissor rectangle that encloses all viewports in the clear mask
+                       int x1 = clear & 0x15 ? 0 : size;
+                       int x2 = clear & 0x2A ? 2 * size : size;
+                       int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
+                       int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
+                       GL_Scissor(x1, y1, x2 - x1, y2 - y1);
+                       GL_Clear(GL_DEPTH_BUFFER_BIT);
+               }
+               GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
+               break;
+       case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
                qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
+               GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
+               if (clear)
+                       GL_Clear(GL_DEPTH_BUFFER_BIT);
+               break;
+       default:
+               break;
        }
-       if (clear)
-               qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |  GL_STENCIL_BUFFER_BIT);
        CHECKGLERROR
 }
 
 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
 {
+       if (transparent)
+       {
+               r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
+               r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
+               r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
+               r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
+       }
        CHECKGLERROR
        R_Shadow_RenderMode_Reset();
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
@@ -2099,47 +2269,112 @@ void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qb
                qglEnable(GL_STENCIL_TEST);CHECKGLERROR
                // only draw light where this geometry was already rendered AND the
                // stencil is 128 (values other than this mean shadow)
-               qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
+               qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
        }
        r_shadow_rendermode = r_shadow_lightingrendermode;
        // do global setup needed for the chosen lighting mode
        if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
        {
-               R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
                GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
                CHECKGLERROR
+       }
+       if (shadowmapping)
+       {
+               switch (r_shadow_shadowmode)
+               {
+               case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
+                       r_shadow_usingshadowmap2d = true;
+                       break;
+               case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
+                       r_shadow_usingshadowmaprect = true;
+                       break;
+               case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
+                       r_shadow_usingshadowmapcube = true;
+                       break;
+               default:
+                       break;
+               }
+       }
+       R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
+       CHECKGLERROR
+}
+
+static const unsigned short bboxelements[36] =
+{
+       5, 1, 3, 5, 3, 7,
+       6, 2, 0, 6, 0, 4,
+       7, 3, 2, 7, 2, 6,
+       4, 0, 1, 4, 1, 5,
+       4, 5, 7, 4, 7, 6,
+       1, 0, 2, 1, 2, 3,
+};
+
+static const float bboxpoints[8][3] =
+{
+       {-1,-1,-1},
+       { 1,-1,-1},
+       {-1, 1,-1},
+       { 1, 1,-1},
+       {-1,-1, 1},
+       { 1,-1, 1},
+       {-1, 1, 1},
+       { 1, 1, 1},
+};
+
+void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
+{
+       int i;
+       float vertex3f[8*3];
+       const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
+       CHECKGLERROR
+       R_Shadow_RenderMode_Reset();
+       r_shadow_rendermode = r_shadow_lightingrendermode;
+       // do global setup needed for the chosen lighting mode
+       {
+               R_EntityMatrix(&identitymatrix);
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+               if (stenciltest)
+               {
+                       qglEnable(GL_STENCIL_TEST);CHECKGLERROR
+                       // only draw light where this geometry was already rendered AND the
+                       // stencil is 128 (values other than this mean shadow)
+                       qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
+               }
+               qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
                if (shadowmapping)
                {
-                       if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
+                       switch (r_shadow_shadowmode)
                        {
+                       case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
                                r_shadow_usingshadowmap2d = true;
-                               R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
-                               CHECKGLERROR
-                       }
-                       else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
-                       {
+                               break;
+                       case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
                                r_shadow_usingshadowmaprect = true;
-                               R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
-                               CHECKGLERROR
-                       }
-                       else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
-                       {
+                               break;
+                       case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
                                r_shadow_usingshadowmapcube = true;
-                               R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
-                               CHECKGLERROR
-                       }
-
-                       if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
-                       {
-                               R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
-                               CHECKGLERROR
+                               break;
+                       default:
+                               break;
                        }
                }
+
+               // render the lighting
+               R_SetupShader_DeferredLight(rsurface.rtlight);
+               for (i = 0;i < 8;i++)
+                       Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
+               CHECKGLERROR
+               R_Mesh_VertexPointer(vertex3f, 0, 0);
+               R_Mesh_ColorPointer(NULL, 0, 0);
+               GL_ColorMask(1,1,1,1);
+               GL_DepthMask(false);
+               GL_DepthRange(0, 1);
+               GL_PolygonOffset(0, 0);
+               GL_DepthTest(true);
+               qglDepthFunc(GL_GREATER);CHECKGLERROR
+               GL_CullFace(r_refdef.view.cullface_back);
+               R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
        }
-       else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
-               R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
-       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
-       CHECKGLERROR
 }
 
 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
@@ -2170,7 +2405,7 @@ void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transpar
        if (stenciltest)
        {
                qglEnable(GL_STENCIL_TEST);CHECKGLERROR
-               qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
+               qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
        }
        r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
 }
@@ -2321,12 +2556,14 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
 
 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
 {
-       float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
-       float *normal3f = rsurface.normal3f + 3 * firstvertex;
+       const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
+       const float *normal3f = rsurface.normal3f + 3 * firstvertex;
        float *color4f = rsurface.array_color4f + 4 * firstvertex;
        float dist, dot, distintensity, shadeintensity, v[3], n[3];
-       if (r_textureunits.integer >= 3)
+       switch (r_shadow_rendermode)
        {
+       case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
+       case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
                if (VectorLength2(diffusecolor) > 0)
                {
                        for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
@@ -2343,7 +2580,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
                                if (r_refdef.fogenabled)
                                {
                                        float f;
-                                       f = FogPoint_Model(vertex3f);
+                                       f = RSurf_FogVertex(vertex3f);
                                        VectorScale(color4f, f, color4f);
                                }
                                color4f[3] = 1;
@@ -2358,15 +2595,14 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
                                {
                                        float f;
                                        Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
-                                       f = FogPoint_Model(vertex3f);
+                                       f = RSurf_FogVertex(vertex3f);
                                        VectorScale(color4f, f, color4f);
                                }
                                color4f[3] = 1;
                        }
                }
-       }
-       else if (r_textureunits.integer >= 2)
-       {
+               break;
+       case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
                if (VectorLength2(diffusecolor) > 0)
                {
                        for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
@@ -2391,7 +2627,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
                                        if (r_refdef.fogenabled)
                                        {
                                                float f;
-                                               f = FogPoint_Model(vertex3f);
+                                               f = RSurf_FogVertex(vertex3f);
                                                VectorScale(color4f, f, color4f);
                                        }
                                }
@@ -2413,7 +2649,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
                                        if (r_refdef.fogenabled)
                                        {
                                                float f;
-                                               f = FogPoint_Model(vertex3f);
+                                               f = RSurf_FogVertex(vertex3f);
                                                VectorScale(color4f, f, color4f);
                                        }
                                }
@@ -2422,9 +2658,8 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
                                color4f[3] = 1;
                        }
                }
-       }
-       else
-       {
+               break;
+       case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
                if (VectorLength2(diffusecolor) > 0)
                {
                        for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
@@ -2450,7 +2685,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
                                        if (r_refdef.fogenabled)
                                        {
                                                float f;
-                                               f = FogPoint_Model(vertex3f);
+                                               f = RSurf_FogVertex(vertex3f);
                                                VectorScale(color4f, f, color4f);
                                        }
                                }
@@ -2473,7 +2708,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
                                        if (r_refdef.fogenabled)
                                        {
                                                float f;
-                                               f = FogPoint_Model(vertex3f);
+                                               f = RSurf_FogVertex(vertex3f);
                                                VectorScale(color4f, f, color4f);
                                        }
                                }
@@ -2482,91 +2717,22 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
                                color4f[3] = 1;
                        }
                }
+               break;
+       default:
+               break;
        }
 }
 
-// TODO: use glTexGen instead of feeding vertices to texcoordpointer?
-
-static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
-{
-       int i;
-       float       *out3f     = rsurface.array_texcoord3f + 3 * firstvertex;
-       const float *vertex3f  = rsurface.vertex3f         + 3 * firstvertex;
-       const float *svector3f = rsurface.svector3f        + 3 * firstvertex;
-       const float *tvector3f = rsurface.tvector3f        + 3 * firstvertex;
-       const float *normal3f  = rsurface.normal3f         + 3 * firstvertex;
-       float lightdir[3];
-       for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
-       {
-               VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
-               // the cubemap normalizes this for us
-               out3f[0] = DotProduct(svector3f, lightdir);
-               out3f[1] = DotProduct(tvector3f, lightdir);
-               out3f[2] = DotProduct(normal3f, lightdir);
-       }
-}
-
-static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
-{
-       int i;
-       float       *out3f     = rsurface.array_texcoord3f + 3 * firstvertex;
-       const float *vertex3f  = rsurface.vertex3f         + 3 * firstvertex;
-       const float *svector3f = rsurface.svector3f        + 3 * firstvertex;
-       const float *tvector3f = rsurface.tvector3f        + 3 * firstvertex;
-       const float *normal3f  = rsurface.normal3f         + 3 * firstvertex;
-       float lightdir[3], eyedir[3], halfdir[3];
-       for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
-       {
-               VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
-               VectorNormalize(lightdir);
-               VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
-               VectorNormalize(eyedir);
-               VectorAdd(lightdir, eyedir, halfdir);
-               // the cubemap normalizes this for us
-               out3f[0] = DotProduct(svector3f, halfdir);
-               out3f[1] = DotProduct(tvector3f, halfdir);
-               out3f[2] = DotProduct(normal3f, halfdir);
-       }
-}
-
-static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
+static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject)
 {
        // used to display how many times a surface is lit for level design purposes
        R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
 }
 
-static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
+static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
 {
        // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
-       R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
-       if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
-               R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
-       else
-               R_Mesh_ColorPointer(NULL, 0, 0);
-       R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
-       R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
-       R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
-       R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
-       R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
-       if (rsurface.texture->backgroundcurrentskinframe)
-       {
-               R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
-               R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
-               R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
-               R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
-       }
-       //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
-       R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
-       if(rsurface.texture->colormapping)
-       {
-               R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
-               R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
-       }
-       R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
-       R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
-       R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
-       R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
-       R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
+       R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
        if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
        {
                qglDepthFunc(GL_EQUAL);CHECKGLERROR
@@ -2578,628 +2744,33 @@ static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices,
        }
 }
 
-static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, float r, float g, float b)
+static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
 {
-       // shared final code for all the dot3 layers
        int renders;
-       GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
-       for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
-       {
-               GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
-               R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-       }
-}
-
-static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
-{
-       rmeshstate_t m;
-       // 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.
-       GL_Color(1,1,1,1);
-       if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
-       {
-               // 3 3D combine path (Geforce3, Radeon 8500)
-               memset(&m, 0, sizeof(m));
-               m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
-               m.pointer_texcoord3f[0] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[0] = rsurface.entitytoattenuationxyz;
-               m.tex[1] = R_GetTexture(basetexture);
-               m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[1] = rsurface.texture->currenttexmatrix;
-               m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
-               m.pointer_texcoord3f[2] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[2] = rsurface.entitytolight;
-               GL_BlendFunc(GL_ONE, GL_ONE);
-       }
-       else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
-       {
-               // 2 3D combine path (Geforce3, original Radeon)
-               memset(&m, 0, sizeof(m));
-               m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
-               m.pointer_texcoord3f[0] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[0] = rsurface.entitytoattenuationxyz;
-               m.tex[1] = R_GetTexture(basetexture);
-               m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[1] = rsurface.texture->currenttexmatrix;
-               GL_BlendFunc(GL_ONE, GL_ONE);
-       }
-       else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
-       {
-               // 4 2D combine path (Geforce3, Radeon 8500)
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.pointer_texcoord3f[0] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[0] = rsurface.entitytoattenuationxyz;
-               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.pointer_texcoord3f[1] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[1] = rsurface.entitytoattenuationz;
-               m.tex[2] = R_GetTexture(basetexture);
-               m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[2] = rsurface.texture->currenttexmatrix;
-               if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
-               {
-                       m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
-                       m.pointer_texcoord3f[3] = rsurface.vertex3f;
-                       m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
-                       m.texmatrix[3] = rsurface.entitytolight;
-               }
-               GL_BlendFunc(GL_ONE, GL_ONE);
-       }
-       else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
-       {
-               // 3 2D combine path (Geforce3, original Radeon)
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.pointer_texcoord3f[0] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[0] = rsurface.entitytoattenuationxyz;
-               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.pointer_texcoord3f[1] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[1] = rsurface.entitytoattenuationz;
-               m.tex[2] = R_GetTexture(basetexture);
-               m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[2] = rsurface.texture->currenttexmatrix;
-               GL_BlendFunc(GL_ONE, GL_ONE);
-       }
-       else
+       int i;
+       int stop;
+       int newfirstvertex;
+       int newlastvertex;
+       int newnumtriangles;
+       int *newe;
+       const int *e;
+       float *c;
+       int maxtriangles = 4096;
+       static int newelements[4096*3];
+       R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
+       for (renders = 0;renders < 4;renders++)
        {
-               // 2/2/2 2D combine path (any dot3 card)
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.pointer_texcoord3f[0] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[0] = rsurface.entitytoattenuationxyz;
-               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.pointer_texcoord3f[1] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[1] = rsurface.entitytoattenuationz;
-               R_Mesh_TextureState(&m);
-               GL_ColorMask(0,0,0,1);
-               GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // second pass
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(basetexture);
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
-               {
-                       m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
-                       m.pointer_texcoord3f[1] = rsurface.vertex3f;
-                       m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
-                       m.texmatrix[1] = rsurface.entitytolight;
-               }
-               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-       }
-       // this final code is shared
-       R_Mesh_TextureState(&m);
-       R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
-}
-
-static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
-{
-       rmeshstate_t m;
-       // 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.
-       GL_Color(1,1,1,1);
-       // generate normalization cubemap texcoords
-       R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
-       if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
-       {
-               // 3/2 3D combine path (Geforce3, Radeon 8500)
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(normalmaptexture);
-               m.texcombinergb[0] = GL_REPLACE;
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
-               m.pointer_texcoord_bufferobject[1] = 0;
-               m.pointer_texcoord_bufferoffset[1] = 0;
-               m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
-               m.pointer_texcoord3f[2] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[2] = rsurface.entitytoattenuationxyz;
-               R_Mesh_TextureState(&m);
-               GL_ColorMask(0,0,0,1);
-               GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // second pass
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(basetexture);
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
-               {
-                       m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
-                       m.pointer_texcoord3f[1] = rsurface.vertex3f;
-                       m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
-                       m.texmatrix[1] = rsurface.entitytolight;
-               }
-               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-       }
-       else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
-       {
-               // 1/2/2 3D combine path (original Radeon)
-               memset(&m, 0, sizeof(m));
-               m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
-               m.pointer_texcoord3f[0] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[0] = rsurface.entitytoattenuationxyz;
-               R_Mesh_TextureState(&m);
-               GL_ColorMask(0,0,0,1);
-               GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // second pass
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(normalmaptexture);
-               m.texcombinergb[0] = GL_REPLACE;
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
-               m.pointer_texcoord_bufferobject[1] = 0;
-               m.pointer_texcoord_bufferoffset[1] = 0;
-               R_Mesh_TextureState(&m);
-               GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // second pass
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(basetexture);
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
-               {
-                       m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
-                       m.pointer_texcoord3f[1] = rsurface.vertex3f;
-                       m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
-                       m.texmatrix[1] = rsurface.entitytolight;
-               }
-               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-       }
-       else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
-       {
-               // 2/2 3D combine path (original Radeon)
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(normalmaptexture);
-               m.texcombinergb[0] = GL_REPLACE;
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
-               m.pointer_texcoord_bufferobject[1] = 0;
-               m.pointer_texcoord_bufferoffset[1] = 0;
-               R_Mesh_TextureState(&m);
-               GL_ColorMask(0,0,0,1);
-               GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // second pass
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(basetexture);
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
-               m.pointer_texcoord3f[1] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[1] = rsurface.entitytoattenuationxyz;
-               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-       }
-       else if (r_textureunits.integer >= 4)
-       {
-               // 4/2 2D combine path (Geforce3, Radeon 8500)
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(normalmaptexture);
-               m.texcombinergb[0] = GL_REPLACE;
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
-               m.pointer_texcoord_bufferobject[1] = 0;
-               m.pointer_texcoord_bufferoffset[1] = 0;
-               m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.pointer_texcoord3f[2] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[2] = rsurface.entitytoattenuationxyz;
-               m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.pointer_texcoord3f[3] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[3] = rsurface.entitytoattenuationz;
-               R_Mesh_TextureState(&m);
-               GL_ColorMask(0,0,0,1);
-               GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // second pass
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(basetexture);
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
-               {
-                       m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
-                       m.pointer_texcoord3f[1] = rsurface.vertex3f;
-                       m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
-                       m.texmatrix[1] = rsurface.entitytolight;
-               }
-               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-       }
-       else
-       {
-               // 2/2/2 2D combine path (any dot3 card)
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.pointer_texcoord3f[0] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[0] = rsurface.entitytoattenuationxyz;
-               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.pointer_texcoord3f[1] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[1] = rsurface.entitytoattenuationz;
-               R_Mesh_TextureState(&m);
-               GL_ColorMask(0,0,0,1);
-               GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // second pass
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(normalmaptexture);
-               m.texcombinergb[0] = GL_REPLACE;
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
-               m.pointer_texcoord_bufferobject[1] = 0;
-               m.pointer_texcoord_bufferoffset[1] = 0;
-               R_Mesh_TextureState(&m);
-               GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // second pass
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(basetexture);
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
-               {
-                       m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
-                       m.pointer_texcoord3f[1] = rsurface.vertex3f;
-                       m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
-                       m.texmatrix[1] = rsurface.entitytolight;
-               }
-               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-       }
-       // this final code is shared
-       R_Mesh_TextureState(&m);
-       R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
-}
-
-static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
-{
-       float glossexponent;
-       rmeshstate_t m;
-       // FIXME: detect blendsquare!
-       //if (!gl_support_blendsquare)
-       //      return;
-       GL_Color(1,1,1,1);
-       // generate normalization cubemap texcoords
-       R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
-       if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
-       {
-               // 2/0/0/1/2 3D combine blendsquare path
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(normalmaptexture);
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
-               m.pointer_texcoord_bufferobject[1] = 0;
-               m.pointer_texcoord_bufferoffset[1] = 0;
-               R_Mesh_TextureState(&m);
-               GL_ColorMask(0,0,0,1);
-               // this squares the result
-               GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // second and third pass
-               R_Mesh_ResetTextureState();
-               // square alpha in framebuffer a few times to make it shiny
-               GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
-               for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
-                       R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // fourth pass
-               memset(&m, 0, sizeof(m));
-               m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
-               m.pointer_texcoord3f[0] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[0] = rsurface.entitytoattenuationxyz;
-               R_Mesh_TextureState(&m);
-               GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // fifth pass
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(glosstexture);
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
-               {
-                       m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
-                       m.pointer_texcoord3f[1] = rsurface.vertex3f;
-                       m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
-                       m.texmatrix[1] = rsurface.entitytolight;
-               }
-               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-       }
-       else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
-       {
-               // 2/0/0/2 3D combine blendsquare path
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(normalmaptexture);
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
-               m.pointer_texcoord_bufferobject[1] = 0;
-               m.pointer_texcoord_bufferoffset[1] = 0;
-               R_Mesh_TextureState(&m);
-               GL_ColorMask(0,0,0,1);
-               // this squares the result
-               GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // second and third pass
-               R_Mesh_ResetTextureState();
-               // square alpha in framebuffer a few times to make it shiny
-               GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
-               for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
-                       R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // fourth pass
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(glosstexture);
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
-               m.pointer_texcoord3f[1] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[1] = rsurface.entitytoattenuationxyz;
-               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-       }
-       else
-       {
-               // 2/0/0/2/2 2D combine blendsquare path
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(normalmaptexture);
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
-               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
-               m.pointer_texcoord_bufferobject[1] = 0;
-               m.pointer_texcoord_bufferoffset[1] = 0;
-               R_Mesh_TextureState(&m);
-               GL_ColorMask(0,0,0,1);
-               // this squares the result
-               GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // second and third pass
-               R_Mesh_ResetTextureState();
-               // square alpha in framebuffer a few times to make it shiny
-               GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
-               for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
-                       R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // fourth pass
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.pointer_texcoord3f[0] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[0] = rsurface.entitytoattenuationxyz;
-               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.pointer_texcoord3f[1] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
-               m.texmatrix[1] = rsurface.entitytoattenuationz;
-               R_Mesh_TextureState(&m);
-               GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
-
-               // fifth pass
-               memset(&m, 0, sizeof(m));
-               m.tex[0] = R_GetTexture(glosstexture);
-               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-               m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-               if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
-               {
-                       m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
-                       m.pointer_texcoord3f[1] = rsurface.vertex3f;
-                       m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
-                       m.texmatrix[1] = rsurface.entitytolight;
-               }
-               GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
-       }
-       // this final code is shared
-       R_Mesh_TextureState(&m);
-       R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
-}
-
-static void R_Shadow_RenderLighting_Light_Dot3(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
-{
-       // ARB path (any Geforce, any Radeon)
-       qboolean doambient = ambientscale > 0;
-       qboolean dodiffuse = diffusescale > 0;
-       qboolean dospecular = specularscale > 0;
-       if (!doambient && !dodiffuse && !dospecular)
-               return;
-       R_Mesh_ColorPointer(NULL, 0, 0);
-       if (doambient)
-               R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
-       if (dodiffuse)
-               R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
-       if (dopants)
-       {
-               if (doambient)
-                       R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
-               if (dodiffuse)
-                       R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
-       }
-       if (doshirt)
-       {
-               if (doambient)
-                       R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
-               if (dodiffuse)
-                       R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
-       }
-       if (dospecular)
-               R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
-}
-
-static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
-{
-       int renders;
-       int i;
-       int stop;
-       int newfirstvertex;
-       int newlastvertex;
-       int newnumtriangles;
-       int *newe;
-       const int *e;
-       float *c;
-       int maxtriangles = 4096;
-       int newelements[4096*3];
-       R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
-       for (renders = 0;renders < 64;renders++)
-       {
-               stop = true;
-               newfirstvertex = 0;
-               newlastvertex = 0;
-               newnumtriangles = 0;
-               newe = newelements;
-               // due to low fillrate on the cards this vertex lighting path is
-               // designed for, we manually cull all triangles that do not
-               // contain a lit vertex
-               // this builds batches of triangles from multiple surfaces and
-               // renders them at once
-               for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
+               stop = true;
+               newfirstvertex = 0;
+               newlastvertex = 0;
+               newnumtriangles = 0;
+               newe = newelements;
+               // due to low fillrate on the cards this vertex lighting path is
+               // designed for, we manually cull all triangles that do not
+               // contain a lit vertex
+               // this builds batches of triangles from multiple surfaces and
+               // renders them at once
+               for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
                {
                        if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
                        {
@@ -3262,54 +2833,67 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve
        }
 }
 
-static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
+static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale)
 {
        // OpenGL 1.1 path (anything)
        float ambientcolorbase[3], diffusecolorbase[3];
        float ambientcolorpants[3], diffusecolorpants[3];
        float ambientcolorshirt[3], diffusecolorshirt[3];
-       rmeshstate_t m;
-       VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
-       VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
-       VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
-       VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
-       VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
-       VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
-       memset(&m, 0, sizeof(m));
-       m.tex[0] = R_GetTexture(basetexture);
-       m.texmatrix[0] = rsurface.texture->currenttexmatrix;
-       m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-       m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-       m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-       if (r_textureunits.integer >= 2)
-       {
-               // voodoo2 or TNT
-               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.texmatrix[1] = rsurface.entitytoattenuationxyz;
-               m.pointer_texcoord3f[1] = rsurface.vertex3f;
-               m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
-               m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
-               if (r_textureunits.integer >= 3)
-               {
-                       // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
-                       m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
-                       m.texmatrix[2] = rsurface.entitytoattenuationz;
-                       m.pointer_texcoord3f[2] = rsurface.vertex3f;
-                       m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
-               }
+       const float *surfacecolor = rsurface.texture->dlightcolor;
+       const float *surfacepants = rsurface.colormap_pantscolor;
+       const float *surfaceshirt = rsurface.colormap_shirtcolor;
+       rtexture_t *basetexture = rsurface.texture->basetexture;
+       rtexture_t *pantstexture = rsurface.texture->pantstexture;
+       rtexture_t *shirttexture = rsurface.texture->shirttexture;
+       qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
+       qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
+       ambientscale *= 2 * r_refdef.view.colorscale;
+       diffusescale *= 2 * r_refdef.view.colorscale;
+       ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
+       diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
+       ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
+       diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
+       ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
+       diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
+       R_Mesh_TexBind(0, basetexture);
+       R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
+       R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+       R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+       switch(r_shadow_rendermode)
+       {
+       case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
+               R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
+               R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
+               R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
+               R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
+               break;
+       case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
+               R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
+               R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
+               R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
+               R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
+               // fall through
+       case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
+               R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
+               R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
+               R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
+               R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
+               break;
+       case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
+               break;
+       default:
+               break;
        }
-       R_Mesh_TextureState(&m);
-       //R_Mesh_TexBind(0, R_GetTexture(basetexture));
+       //R_Mesh_TexBind(0, basetexture);
        R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
        if (dopants)
        {
-               R_Mesh_TexBind(0, R_GetTexture(pantstexture));
+               R_Mesh_TexBind(0, pantstexture);
                R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
        }
        if (doshirt)
        {
-               R_Mesh_TexBind(0, R_GetTexture(shirttexture));
+               R_Mesh_TexBind(0, shirttexture);
                R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
        }
 }
@@ -3318,12 +2902,9 @@ extern cvar_t gl_lightmaps;
 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject)
 {
        float ambientscale, diffusescale, specularscale;
-       vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
-       rtexture_t *nmap;
-       // calculate colors to render this texture with
-       lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
-       lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
-       lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
+       qboolean negated;
+       float lightcolor[3];
+       VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
        ambientscale = rsurface.rtlight->ambientscale;
        diffusescale = rsurface.rtlight->diffusescale;
        specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
@@ -3333,74 +2914,36 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle
                diffusescale = 0;
                specularscale = 0;
        }
-       if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
+       if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
                return;
-       RSurf_SetupDepthAndCulling();
-       nmap = rsurface.texture->currentskinframe->nmap;
-       if (gl_lightmaps.integer)
-               nmap = r_texture_blanknormalmap;
-       if (rsurface.texture->colormapping && !gl_lightmaps.integer)
-       {
-               qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
-               qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
-               if (dopants)
-               {
-                       lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
-                       lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
-                       lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
-               }
-               else
-                       VectorClear(lightcolorpants);
-               if (doshirt)
-               {
-                       lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
-                       lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
-                       lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
-               }
-               else
-                       VectorClear(lightcolorshirt);
-               switch (r_shadow_rendermode)
-               {
-               case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
-                       GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
-                       R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
-                       break;
-               case R_SHADOW_RENDERMODE_LIGHT_GLSL:
-                       R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
-                       break;
-               case R_SHADOW_RENDERMODE_LIGHT_DOT3:
-                       R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
-                       break;
-               case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
-                       R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
-                       break;
-               default:
-                       Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
-                       break;
-               }
+       negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
+       if(negated)
+       {
+               VectorNegate(lightcolor, lightcolor);
+               qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
        }
-       else
+       RSurf_SetupDepthAndCulling();
+       switch (r_shadow_rendermode)
        {
-               switch (r_shadow_rendermode)
-               {
-               case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
-                       GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
-                       R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
-                       break;
-               case R_SHADOW_RENDERMODE_LIGHT_GLSL:
-                       R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
-                       break;
-               case R_SHADOW_RENDERMODE_LIGHT_DOT3:
-                       R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
-                       break;
-               case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
-                       R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
-                       break;
-               default:
-                       Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
-                       break;
-               }
+       case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
+               GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
+               R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
+               break;
+       case R_SHADOW_RENDERMODE_LIGHT_GLSL:
+               R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale);
+               break;
+       case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
+       case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
+       case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
+       case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
+               R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale);
+               break;
+       default:
+               Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
+               break;
        }
+       if(negated)
+               qglBlendEquationEXT(GL_FUNC_ADD_EXT);
 }
 
 void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, int shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
@@ -3478,8 +3021,7 @@ void R_RTLight_Compile(rtlight_t *rtlight)
        {
                // this variable must be set for the CompileShadowVolume/CompileShadowMap code
                r_shadow_compilingrtlight = rtlight;
-               R_Shadow_EnlargeLeafSurfaceTrisBuffer(model->brush.num_leafs, model->num_surfaces, model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles, model->surfmesh.num_triangles);
-               model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs);
+               model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, 0, NULL);
                numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
                numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
                numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
@@ -3548,8 +3090,8 @@ void R_RTLight_Compile(rtlight_t *rtlight)
                        if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
                                shadowtris++;
 
-       if (developer.integer >= 10)
-               Con_Printf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles, %i zpass/%i zfail compiled shadow volume triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris, shadowzpasstris, shadowzfailtris);
+       if (developer_extra.integer)
+               Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles, %i zpass/%i zfail compiled shadow volume triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris, shadowzpasstris, shadowzfailtris);
 }
 
 void R_RTLight_Uncompile(rtlight_t *rtlight)
@@ -3601,9 +3143,9 @@ void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
        int i, j;
        mplane_t plane;
        // reset the count of frustum planes
-       // see rsurface.rtlight_frustumplanes definition for how much this array
+       // see rtlight->cached_frustumplanes definition for how much this array
        // can hold
-       rsurface.rtlight_numfrustumplanes = 0;
+       rtlight->cached_numfrustumplanes = 0;
 
        // haven't implemented a culling path for ortho rendering
        if (!r_refdef.view.useperspective)
@@ -3614,7 +3156,7 @@ void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
                                break;
                if (i == 4)
                        for (i = 0;i < 4;i++)
-                               rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
+                               rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
                return;
        }
 
@@ -3636,11 +3178,11 @@ void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
                if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
                        continue;
                // copy the plane
-               rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
+               rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
        }
        // if all the standard frustum planes were accepted, the light is onscreen
        // otherwise we need to generate some more planes below...
-       if (rsurface.rtlight_numfrustumplanes < 4)
+       if (rtlight->cached_numfrustumplanes < 4)
        {
                // at least one of the stock frustum planes failed, so we need to
                // create one or two custom planes to enclose the light origin
@@ -3671,12 +3213,12 @@ void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
                        // we have created a valid plane, compute extra info
                        PlaneClassify(&plane);
                        // copy the plane
-                       rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
+                       rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
 #if 1
                        // if we've found 5 frustum planes then we have constructed a
                        // proper split-side case and do not need to keep searching for
                        // planes to enclose the light origin
-                       if (rsurface.rtlight_numfrustumplanes == 5)
+                       if (rtlight->cached_numfrustumplanes == 5)
                                break;
 #endif
                }
@@ -3684,9 +3226,9 @@ void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
 #endif
 
 #if 0
-       for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
+       for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
        {
-               plane = rsurface.rtlight_frustumplanes[i];
+               plane = rtlight->cached_frustumplanes[i];
                Con_Printf("light %p plane #%i %f %f %f : %f (%f %f %f %f %f)\n", rtlight, i, plane.normal[0], plane.normal[1], plane.normal[2], plane.dist, PlaneDiff(r_refdef.view.frustumcorner[0], &plane), PlaneDiff(r_refdef.view.frustumcorner[1], &plane), PlaneDiff(r_refdef.view.frustumcorner[2], &plane), PlaneDiff(r_refdef.view.frustumcorner[3], &plane), PlaneDiff(rtlight->shadoworigin, &plane));
        }
 #endif
@@ -3706,7 +3248,7 @@ void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
                        VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
                        plane.dist = VectorNormalizeLength(plane.normal);
                        plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
-                       rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
+                       rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
                }
        }
 #endif
@@ -3717,8 +3259,8 @@ void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
        {
                VectorClear(plane.normal);
                plane.normal[i >> 1] = (i & 1) ? -1 : 1;
-               plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
-               rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
+               plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
+               rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
        }
 #endif
 
@@ -3729,33 +3271,33 @@ void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
        vec_t bestdist;
        // reduce all plane distances to tightly fit the rtlight cull box, which
        // is in worldspace
-       VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
-       VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
-       VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
-       VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
-       VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
-       VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
-       VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
-       VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
-       oldnum = rsurface.rtlight_numfrustumplanes;
-       rsurface.rtlight_numfrustumplanes = 0;
+       VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
+       VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
+       VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
+       VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
+       VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
+       VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
+       VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
+       VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
+       oldnum = rtlight->cached_numfrustumplanes;
+       rtlight->cached_numfrustumplanes = 0;
        for (j = 0;j < oldnum;j++)
        {
                // find the nearest point on the box to this plane
-               bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
+               bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
                for (i = 1;i < 8;i++)
                {
-                       dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
+                       dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
                        if (bestdist > dist)
                                bestdist = dist;
                }
-               Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, rsurface.rtlight_frustumplanes[j].normal[0], rsurface.rtlight_frustumplanes[j].normal[1], rsurface.rtlight_frustumplanes[j].normal[2], rsurface.rtlight_frustumplanes[j].dist, bestdist);
+               Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, rtlight->cached_frustumplanes[j].normal[0], rtlight->cached_frustumplanes[j].normal[1], rtlight->cached_frustumplanes[j].normal[2], rtlight->cached_frustumplanes[j].dist, bestdist);
                // if the nearest point is near or behind the plane, we want this
                // plane, otherwise the plane is useless as it won't cull anything
-               if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
+               if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
                {
-                       PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
-                       rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
+                       PlaneClassify(&rtlight->cached_frustumplanes[j]);
+                       rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
                }
        }
        }
@@ -3784,14 +3326,14 @@ void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const
         CHECKGLERROR
     }
        else if (r_refdef.scene.worldentity->model)
-               r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, surfacesides, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
+               r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, surfacesides, rsurface.rtlight->cached_cullmins, rsurface.rtlight->cached_cullmaxs);
 
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
 {
-       qboolean zpass;
+       qboolean zpass = false;
        shadowmesh_t *mesh;
        int t, tend;
        int surfacelistindex;
@@ -3802,14 +3344,16 @@ void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, co
        if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
        {
                CHECKGLERROR
-               zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
-               R_Shadow_RenderMode_StencilShadowVolumes(zpass);
+               if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
+               {
+                       zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
+                       R_Shadow_RenderMode_StencilShadowVolumes(zpass);
+               }
                mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
                for (;mesh;mesh = mesh->next)
                {
                        r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
                        R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
-                       GL_LockArrays(0, mesh->numverts);
                        if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
                        {
                                // increment stencil if frontface is infront of depthbuffer
@@ -3831,12 +3375,12 @@ void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, co
                                qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
                        }
                        R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
-                       GL_LockArrays(0, 0);
                }
                CHECKGLERROR
        }
-       else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
+       else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
        {
+               // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
                R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
                for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
                {
@@ -3848,7 +3392,7 @@ void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, co
                R_Shadow_VolumeFromList(r_refdef.scene.worldmodel->brush.shadowmesh->numverts, r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles, r_refdef.scene.worldmodel->brush.shadowmesh->vertex3f, r_refdef.scene.worldmodel->brush.shadowmesh->element3i, r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius + r_refdef.scene.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist, r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
        }
        else if (numsurfaces)
-               r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
+               r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight->cached_cullmins, rsurface.rtlight->cached_cullmaxs);
 
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
@@ -3857,8 +3401,9 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent)
 {
        vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
        vec_t relativeshadowradius;
-       RSurf_ActiveModelEntity(ent, false, false);
+       RSurf_ActiveModelEntity(ent, false, false, false);
        Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
+       // we need to re-init the shader for each entity because the matrix changed
        relativeshadowradius = rsurface.rtlight->radius / ent->scale;
        relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
        relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
@@ -3866,29 +3411,32 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent)
        relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
        relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
        relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
-       if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
+       switch (r_shadow_rendermode)
        {
+       case R_SHADOW_RENDERMODE_SHADOWMAP2D:
+       case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
+       case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
                ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
-       }
-       else
+               break;
+       default:
                ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
+               break;
+       }
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
 {
        // set up properties for rendering light onto this entity
-       RSurf_ActiveModelEntity(ent, true, true);
+       RSurf_ActiveModelEntity(ent, true, true, false);
        GL_AlphaTest(false);
        Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
        Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
        Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
        Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
-       if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
-               R_Mesh_TexMatrix(3, &rsurface.entitytolight);
 }
 
-void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
+void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
 {
        if (!r_refdef.scene.worldmodel->DrawLight)
                return;
@@ -3900,10 +3448,8 @@ void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned c
        Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
        Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
        VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
-       if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
-               R_Mesh_TexMatrix(3, &rsurface.entitytolight);
 
-       r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
+       r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
 
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
@@ -3921,26 +3467,26 @@ void R_Shadow_DrawEntityLight(entity_render_t *ent)
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
-void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
+void R_Shadow_PrepareLight(rtlight_t *rtlight)
 {
        int i;
        float f;
        int numleafs, numsurfaces;
        int *leaflist, *surfacelist;
-       unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
+       unsigned char *leafpvs;
+       unsigned char *shadowtrispvs;
+       unsigned char *lighttrispvs;
+       //unsigned char *surfacesides;
        int numlightentities;
        int numlightentities_noselfshadow;
        int numshadowentities;
        int numshadowentities_noselfshadow;
        static entity_render_t *lightentities[MAX_EDICTS];
+       static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
        static entity_render_t *shadowentities[MAX_EDICTS];
-       static unsigned char entitysides[MAX_EDICTS];
-       int lightentities_noselfshadow;
-       int shadowentities_noselfshadow;
-       vec3_t nearestpoint;
-       vec_t distance;
-       qboolean castshadows;
-       int lodlinear;
+       static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
+
+       rtlight->draw = false;
 
        // 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)
@@ -3959,7 +3505,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        }
 
        // load cubemap
-       rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
+       rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
 
        // look up the light style value at this time
        f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
@@ -3980,8 +3526,10 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
                return;
 
-       VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
-       VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
+       VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
+       VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
+
+       R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
 
        if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
        {
@@ -3992,7 +3540,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                leafpvs = rtlight->static_leafpvs;
                numsurfaces = rtlight->static_numsurfaces;
                surfacelist = rtlight->static_surfacelist;
-               surfacesides = NULL;
+               //surfacesides = NULL;
                shadowtrispvs = rtlight->static_shadowtrispvs;
                lighttrispvs = rtlight->static_lighttrispvs;
        }
@@ -4000,16 +3548,16 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        {
                // dynamic light, world available and can receive realtime lighting
                // calculate lit surfaces and leafs
-               R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
-               r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs);
+               r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cached_cullmins, rtlight->cached_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes);
+               R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
                leaflist = r_shadow_buffer_leaflist;
                leafpvs = r_shadow_buffer_leafpvs;
                surfacelist = r_shadow_buffer_surfacelist;
-               surfacesides = r_shadow_buffer_surfacesides;
+               //surfacesides = r_shadow_buffer_surfacesides;
                shadowtrispvs = r_shadow_buffer_shadowtrispvs;
                lighttrispvs = r_shadow_buffer_lighttrispvs;
                // if the reduced leaf bounds are offscreen, skip it
-               if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
+               if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
                        return;
        }
        else
@@ -4020,7 +3568,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                leafpvs = NULL;
                numsurfaces = 0;
                surfacelist = NULL;
-               surfacesides = NULL;
+               //surfacesides = NULL;
                shadowtrispvs = NULL;
                lighttrispvs = NULL;
        }
@@ -4033,88 +3581,166 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                if (i == numleafs)
                        return;
        }
-       // set up a scissor rectangle for this light
-       if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
-               return;
-
-       R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
 
        // make a list of lit entities and shadow casting entities
        numlightentities = 0;
        numlightentities_noselfshadow = 0;
-       lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
        numshadowentities = 0;
        numshadowentities_noselfshadow = 0;
-       shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
 
        // add dynamic entities that are lit by the light
-       if (r_drawentities.integer)
+       for (i = 0;i < r_refdef.scene.numentities;i++)
        {
-               for (i = 0;i < r_refdef.scene.numentities;i++)
+               dp_model_t *model;
+               entity_render_t *ent = r_refdef.scene.entities[i];
+               vec3_t org;
+               if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
+                       continue;
+               // skip the object entirely if it is not within the valid
+               // shadow-casting region (which includes the lit region)
+               if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
+                       continue;
+               if (!(model = ent->model))
+                       continue;
+               if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
                {
-                       dp_model_t *model;
-                       entity_render_t *ent = r_refdef.scene.entities[i];
-                       vec3_t org;
-                       if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
+                       // this entity wants to receive light, is visible, and is
+                       // inside the light box
+                       // TODO: check if the surfaces in the model can receive light
+                       // so now check if it's in a leaf seen by the light
+                       if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
                                continue;
-                       // skip the object entirely if it is not within the valid
-                       // shadow-casting region (which includes the lit region)
-                       if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
-                               continue;
-                       if (!(model = ent->model))
-                               continue;
-                       if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
+                       if (ent->flags & RENDER_NOSELFSHADOW)
+                               lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
+                       else
+                               lightentities[numlightentities++] = ent;
+                       // since it is lit, it probably also casts a shadow...
+                       // about the VectorDistance2 - light emitting entities should not cast their own shadow
+                       Matrix4x4_OriginFromMatrix(&ent->matrix, org);
+                       if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
                        {
-                               // this entity wants to receive light, is visible, and is
-                               // inside the light box
-                               // TODO: check if the surfaces in the model can receive light
-                               // so now check if it's in a leaf seen by the light
-                               if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
-                                       continue;
-                               if (ent->flags & RENDER_NOSELFSHADOW)
-                                       lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent;
+                               // note: exterior models without the RENDER_NOSELFSHADOW
+                               // flag still create a RENDER_NOSELFSHADOW shadow but
+                               // are lit normally, this means that they are
+                               // self-shadowing but do not shadow other
+                               // RENDER_NOSELFSHADOW entities such as the gun
+                               // (very weird, but keeps the player shadow off the gun)
+                               if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
+                                       shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
                                else
-                                       lightentities[numlightentities++] = ent;
-                               // since it is lit, it probably also casts a shadow...
-                               // about the VectorDistance2 - light emitting entities should not cast their own shadow
-                               Matrix4x4_OriginFromMatrix(&ent->matrix, org);
-                               if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
-                               {
-                                       // note: exterior models without the RENDER_NOSELFSHADOW
-                                       // flag still create a RENDER_NOSELFSHADOW shadow but
-                                       // are lit normally, this means that they are
-                                       // self-shadowing but do not shadow other
-                                       // RENDER_NOSELFSHADOW entities such as the gun
-                                       // (very weird, but keeps the player shadow off the gun)
-                                       if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
-                                               shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
-                                       else
-                                               shadowentities[numshadowentities++] = ent;
-                               }
+                                       shadowentities[numshadowentities++] = ent;
                        }
-                       else if (ent->flags & RENDER_SHADOW)
+               }
+               else if (ent->flags & RENDER_SHADOW)
+               {
+                       // this entity is not receiving light, but may still need to
+                       // cast a shadow...
+                       // TODO: check if the surfaces in the model can cast shadow
+                       // now check if it is in a leaf seen by the light
+                       if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
+                               continue;
+                       // about the VectorDistance2 - light emitting entities should not cast their own shadow
+                       Matrix4x4_OriginFromMatrix(&ent->matrix, org);
+                       if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
                        {
-                               // this entity is not receiving light, but may still need to
-                               // cast a shadow...
-                               // TODO: check if the surfaces in the model can cast shadow
-                               // now check if it is in a leaf seen by the light
-                               if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
-                                       continue;
-                               // about the VectorDistance2 - light emitting entities should not cast their own shadow
-                               Matrix4x4_OriginFromMatrix(&ent->matrix, org);
-                               if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
-                               {
-                                       if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
-                                               shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
-                                       else
-                                               shadowentities[numshadowentities++] = ent;
-                               }
+                               if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
+                                       shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
+                               else
+                                       shadowentities[numshadowentities++] = ent;
                        }
                }
        }
 
        // return if there's nothing at all to light
-       if (!numlightentities && !numsurfaces)
+       if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
+               return;
+
+       // count this light in the r_speeds
+       r_refdef.stats.lights++;
+
+       // flag it as worth drawing later
+       rtlight->draw = true;
+
+       // cache all the animated entities that cast a shadow but are not visible
+       for (i = 0;i < numshadowentities;i++)
+               if (!shadowentities[i]->animcache_vertex3f)
+                       R_AnimCache_GetEntity(shadowentities[i], false, false);
+       for (i = 0;i < numshadowentities_noselfshadow;i++)
+               if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
+                       R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
+
+       // allocate some temporary memory for rendering this light later in the frame
+       // reusable buffers need to be copied, static data can be used as-is
+       rtlight->cached_numlightentities               = numlightentities;
+       rtlight->cached_numlightentities_noselfshadow  = numlightentities_noselfshadow;
+       rtlight->cached_numshadowentities              = numshadowentities;
+       rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
+       rtlight->cached_numsurfaces                    = numsurfaces;
+       rtlight->cached_lightentities                  = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
+       rtlight->cached_lightentities_noselfshadow     = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
+       rtlight->cached_shadowentities                 = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
+       rtlight->cached_shadowentities_noselfshadow    = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
+       if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
+       {
+               int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
+               int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
+               rtlight->cached_shadowtrispvs                  =   (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
+               rtlight->cached_lighttrispvs                   =   (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
+               rtlight->cached_surfacelist                    =              (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
+       }
+       else
+       {
+               // compiled light data
+               rtlight->cached_shadowtrispvs = shadowtrispvs;
+               rtlight->cached_lighttrispvs = lighttrispvs;
+               rtlight->cached_surfacelist = surfacelist;
+       }
+}
+
+void R_Shadow_DrawLight(rtlight_t *rtlight)
+{
+       int i;
+       int numsurfaces;
+       unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
+       int numlightentities;
+       int numlightentities_noselfshadow;
+       int numshadowentities;
+       int numshadowentities_noselfshadow;
+       entity_render_t **lightentities;
+       entity_render_t **lightentities_noselfshadow;
+       entity_render_t **shadowentities;
+       entity_render_t **shadowentities_noselfshadow;
+       int *surfacelist;
+       static unsigned char entitysides[MAX_EDICTS];
+       static unsigned char entitysides_noselfshadow[MAX_EDICTS];
+       vec3_t nearestpoint;
+       vec_t distance;
+       qboolean castshadows;
+       int lodlinear;
+
+       // check if we cached this light this frame (meaning it is worth drawing)
+       if (!rtlight->draw)
+               return;
+
+       // if R_FrameData_Store ran out of space we skip anything dependent on it
+       if (r_framedata_failed)
+               return;
+
+       numlightentities = rtlight->cached_numlightentities;
+       numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
+       numshadowentities = rtlight->cached_numshadowentities;
+       numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
+       numsurfaces = rtlight->cached_numsurfaces;
+       lightentities = rtlight->cached_lightentities;
+       lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
+       shadowentities = rtlight->cached_shadowentities;
+       shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
+       shadowtrispvs = rtlight->cached_shadowtrispvs;
+       lighttrispvs = rtlight->cached_lighttrispvs;
+       surfacelist = rtlight->cached_surfacelist;
+
+       // set up a scissor rectangle for this light
+       if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
                return;
 
        // don't let sound skip if going slow
@@ -4123,8 +3749,6 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
 
        // make this the active rtlight for rendering purposes
        R_Shadow_RenderMode_ActiveLight(rtlight);
-       // count this light in the r_speeds
-       r_refdef.stats.lights++;
 
        if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
        {
@@ -4136,7 +3760,8 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                for (i = 0;i < numshadowentities;i++)
                        R_Shadow_DrawEntityShadow(shadowentities[i]);
                for (i = 0;i < numshadowentities_noselfshadow;i++)
-                       R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
+                       R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
+               R_Shadow_RenderMode_VisibleLighting(false, false);
        }
 
        if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
@@ -4149,7 +3774,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                for (i = 0;i < numlightentities;i++)
                        R_Shadow_DrawEntityLight(lightentities[i]);
                for (i = 0;i < numlightentities_noselfshadow;i++)
-                       R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
+                       R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
        }
 
        castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
@@ -4159,12 +3784,9 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
        distance = VectorDistance(nearestpoint, r_refdef.view.origin);
 
-       // VorteX: loosy quality mode, might be good in some situations
-       if (r_shadow_shadowmapping_quality.value)
-               lodlinear = ( rtlight->radius * r_shadow_shadowmapping_quality.value ) / pow ( max(1.0f,(distance/rtlight->radius)), 0.5 );
-       else
-               lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
-       lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
+       lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
+       //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
+       lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
 
        if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
        {
@@ -4178,13 +3800,17 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
 
                r_shadow_shadowmaplod = 0;
                for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
-                       if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
+                       if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
                                r_shadow_shadowmaplod = i;
 
-               size = r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
-               size = bound(1, size, 2048);
+               if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
+                       size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
+               else
+                       size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
+                       
                borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
 
+               surfacesides = NULL;
                if (numsurfaces)
                {
                        if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
@@ -4194,6 +3820,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                        }
                        else
                        {
+                               surfacesides = r_shadow_buffer_surfacesides;
                                for(i = 0;i < numsurfaces;i++)
                                {
                                        msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
@@ -4209,7 +3836,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                                receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
                        if (receivermask < 0x3F)
                                for(i = 0; i < numlightentities_noselfshadow;i++)
-                                       receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
+                                       receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
                }
 
                receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
@@ -4219,7 +3846,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                        for (i = 0;i < numshadowentities;i++)
                                castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
                        for (i = 0;i < numshadowentities_noselfshadow;i++)
-                               castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); 
+                               castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); 
                }
 
                //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
@@ -4227,7 +3854,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                // render shadow casters into 6 sided depth texture
                for (side = 0;side < 6;side++) if (receivermask & (1 << side))
                {
-                       R_Shadow_RenderMode_ShadowMap(side, true, size);
+                       R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
                        if (! (castermask & (1 << side))) continue;
                        if (numsurfaces)
                                R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
@@ -4241,17 +3868,17 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                        // draw lighting in the unmasked areas
                        R_Shadow_RenderMode_Lighting(false, false, true);
                        for (i = 0;i < numlightentities_noselfshadow;i++)
-                               R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
+                               R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
                }
 
                // render shadow casters into 6 sided depth texture
-               if (numshadowentities_noselfshadow) 
+               if (numshadowentities_noselfshadow)
                {
                        for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
                        {
-                               R_Shadow_RenderMode_ShadowMap(side, false, size);
-                               for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] & (1 << side))
-                                       R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
+                               R_Shadow_RenderMode_ShadowMap(side, 0, size);
+                               for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
+                                       R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
                        }
                }
 
@@ -4264,81 +3891,308 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                for (i = 0;i < numlightentities;i++)
                        R_Shadow_DrawEntityLight(lightentities[i]);
        }
-       else if (castshadows && gl_stencil)
+       else if (castshadows && vid.stencil)
        {
                // draw stencil shadow volumes to mask off pixels that are in shadow
                // so that they won't receive lighting
                GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
                R_Shadow_ClearStencil();
+
                if (numsurfaces)
                        R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
                for (i = 0;i < numshadowentities;i++)
                        R_Shadow_DrawEntityShadow(shadowentities[i]);
-               if (numlightentities_noselfshadow)
-               {
-                       // draw lighting in the unmasked areas
-                       R_Shadow_RenderMode_Lighting(true, false, false);
-                       for (i = 0;i < numlightentities_noselfshadow;i++)
-                               R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
 
-                       // optionally draw the illuminated areas
-                       // for performance analysis by level designers
-                       if (r_showlighting.integer && r_refdef.view.showdebug)
-                       {
-                               R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
-                               for (i = 0;i < numlightentities_noselfshadow;i++)
-                                       R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
-                       }
-               }
+               // draw lighting in the unmasked areas
+               R_Shadow_RenderMode_Lighting(true, false, false);
+               for (i = 0;i < numlightentities_noselfshadow;i++)
+                       R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
+
                for (i = 0;i < numshadowentities_noselfshadow;i++)
-                       R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
+                       R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
 
-               if (numsurfaces + numlightentities)
-               {
-                       // draw lighting in the unmasked areas
-                       R_Shadow_RenderMode_Lighting(true, false, false);
-                       if (numsurfaces)
-                               R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
-                       for (i = 0;i < numlightentities;i++)
-                               R_Shadow_DrawEntityLight(lightentities[i]);
-               }
+               // draw lighting in the unmasked areas
+               R_Shadow_RenderMode_Lighting(true, false, false);
+               if (numsurfaces)
+                       R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
+               for (i = 0;i < numlightentities;i++)
+                       R_Shadow_DrawEntityLight(lightentities[i]);
+       }
+       else
+       {
+               // draw lighting in the unmasked areas
+               R_Shadow_RenderMode_Lighting(false, false, false);
+               if (numsurfaces)
+                       R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
+               for (i = 0;i < numlightentities;i++)
+                       R_Shadow_DrawEntityLight(lightentities[i]);
+               for (i = 0;i < numlightentities_noselfshadow;i++)
+                       R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
+       }
+
+       if (r_shadow_usingdeferredprepass)
+       {
+               // when rendering deferred lighting, we simply rasterize the box
+               if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
+                       R_Shadow_RenderMode_DrawDeferredLight(false, true);
+               else if (castshadows && vid.stencil)
+                       R_Shadow_RenderMode_DrawDeferredLight(true, false);
+               else
+                       R_Shadow_RenderMode_DrawDeferredLight(false, false);
+       }
+}
+
+static void R_Shadow_FreeDeferred(void)
+{
+       if (r_shadow_prepassgeometryfbo)
+               qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
+       r_shadow_prepassgeometryfbo = 0;
+
+       if (r_shadow_prepasslightingfbo)
+               qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
+       r_shadow_prepasslightingfbo = 0;
+
+       if (r_shadow_prepassgeometrydepthtexture)
+               R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
+       r_shadow_prepassgeometrydepthtexture = NULL;
+
+       if (r_shadow_prepassgeometrynormalmaptexture)
+               R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
+       r_shadow_prepassgeometrynormalmaptexture = NULL;
+
+       if (r_shadow_prepasslightingdiffusetexture)
+               R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
+       r_shadow_prepasslightingdiffusetexture = NULL;
+
+       if (r_shadow_prepasslightingspeculartexture)
+               R_FreeTexture(r_shadow_prepasslightingspeculartexture);
+       r_shadow_prepasslightingspeculartexture = NULL;
+}
+
+void R_Shadow_DrawPrepass(void)
+{
+       int i;
+       int flag;
+       int lnum;
+       size_t lightindex;
+       dlight_t *light;
+       size_t range;
+       entity_render_t *ent;
+
+       GL_AlphaTest(false);
+       R_Mesh_ColorPointer(NULL, 0, 0);
+       R_Mesh_ResetTextureState();
+       GL_DepthMask(true);
+       GL_ColorMask(1,1,1,1);
+       GL_BlendFunc(GL_ONE, GL_ZERO);
+       GL_Color(1,1,1,1);
+       GL_DepthTest(true);
+       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
+       qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
+       GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
+
+       if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
+               r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
+       if (r_timereport_active)
+               R_TimeReport("prepassworld");
+
+       for (i = 0;i < r_refdef.scene.numentities;i++)
+       {
+               if (!r_refdef.viewcache.entityvisible[i])
+                       continue;
+               ent = r_refdef.scene.entities[i];
+               if (ent->model && ent->model->DrawPrepass != NULL)
+                       ent->model->DrawPrepass(ent);
+       }
+
+       if (r_timereport_active)
+               R_TimeReport("prepassmodels");
+
+       GL_DepthMask(false);
+       GL_ColorMask(1,1,1,1);
+       GL_Color(1,1,1,1);
+       GL_DepthTest(true);
+       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
+       qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
+       GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
+       if (r_refdef.fogenabled)
+               qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
+
+       R_Shadow_RenderMode_Begin();
+
+       flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
+       if (r_shadow_debuglight.integer >= 0)
+       {
+               lightindex = r_shadow_debuglight.integer;
+               light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+               if (light && (light->flags & flag))
+                       R_Shadow_DrawLight(&light->rtlight);
        }
        else
        {
-               if (numsurfaces + numlightentities)
+               range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
+               for (lightindex = 0;lightindex < range;lightindex++)
                {
-                       // draw lighting in the unmasked areas
-                       R_Shadow_RenderMode_Lighting(false, false, false);
-                       if (numsurfaces)
-                               R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
-                       for (i = 0;i < numlightentities;i++)
-                               R_Shadow_DrawEntityLight(lightentities[i]);
-                       for (i = 0;i < numlightentities_noselfshadow;i++)
-                               R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
+                       light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+                       if (light && (light->flags & flag))
+                               R_Shadow_DrawLight(&light->rtlight);
                }
        }
+       if (r_refdef.scene.rtdlight)
+               for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
+                       R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
+
+       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
+       if (r_refdef.fogenabled)
+               qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
+
+       R_Shadow_RenderMode_End();
+
+       if (r_timereport_active)
+               R_TimeReport("prepasslights");
 }
 
 void R_Shadow_DrawLightSprites(void);
-void R_ShadowVolumeLighting(qboolean visible)
+void R_Shadow_PrepareLights(void)
 {
        int flag;
        int lnum;
        size_t lightindex;
        dlight_t *light;
        size_t range;
+       float f;
+       GLenum status;
 
-       if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) || 
-               (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer && r_glsl.integer && gl_support_fragment_shader && gl_support_ext_framebuffer_object) || 
+       if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
+               (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
                r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) || 
                r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
                r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || 
-               r_shadow_shadowmapprecision != r_shadow_shadowmapping_precision.integer || 
+               r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || 
                r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
                R_Shadow_FreeShadowMaps();
 
+       r_shadow_usingshadowmaportho = false;
+
+       switch (vid.renderpath)
+       {
+       case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
+               if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
+               {
+                       r_shadow_usingdeferredprepass = false;
+                       if (r_shadow_prepass_width)
+                               R_Shadow_FreeDeferred();
+                       r_shadow_prepass_width = r_shadow_prepass_height = 0;
+                       break;
+               }
+
+               if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
+               {
+                       R_Shadow_FreeDeferred();
+
+                       r_shadow_usingdeferredprepass = true;
+                       r_shadow_prepass_width = vid.width;
+                       r_shadow_prepass_height = vid.height;
+                       r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
+                       r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
+                       r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
+                       r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
+
+                       // set up the geometry pass fbo (depth + normalmap)
+                       qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
+                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
+                       qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
+                       qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
+                       // render depth into one texture and normalmap into the other
+                       if (qglDrawBuffersARB)
+                       {
+                               qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
+                               qglReadBuffer(GL_NONE);CHECKGLERROR
+                       }
+                       status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
+                       if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+                       {
+                               Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
+                               Cvar_SetValueQuick(&r_shadow_deferred, 0);
+                               r_shadow_usingdeferredprepass = false;
+                       }
+
+                       // set up the lighting pass fbo (diffuse + specular)
+                       qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
+                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
+                       qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
+                       qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
+                       qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
+                       // render diffuse into one texture and specular into another,
+                       // with depth and normalmap bound as textures,
+                       // with depth bound as attachment as well
+                       if (qglDrawBuffersARB)
+                       {
+                               qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
+                               qglReadBuffer(GL_NONE);CHECKGLERROR
+                       }
+                       status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
+                       if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+                       {
+                               Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
+                               Cvar_SetValueQuick(&r_shadow_deferred, 0);
+                               r_shadow_usingdeferredprepass = false;
+                       }
+               }
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               r_shadow_usingdeferredprepass = false;
+               break;
+       }
+
+       R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
+
+       flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
+       if (r_shadow_debuglight.integer >= 0)
+       {
+               lightindex = r_shadow_debuglight.integer;
+               light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+               if (light && (light->flags & flag))
+                       R_Shadow_PrepareLight(&light->rtlight);
+       }
+       else
+       {
+               range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
+               for (lightindex = 0;lightindex < range;lightindex++)
+               {
+                       light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+                       if (light && (light->flags & flag))
+                               R_Shadow_PrepareLight(&light->rtlight);
+               }
+       }
+       if (r_refdef.scene.rtdlight)
+       {
+               for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
+                       R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
+       }
+       else if(gl_flashblend.integer)
+       {
+               for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
+               {
+                       rtlight_t *rtlight = r_refdef.scene.lights[lnum];
+                       f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
+                       VectorScale(rtlight->color, f, rtlight->currentcolor);
+               }
+       }
+
        if (r_editlights.integer)
                R_Shadow_DrawLightSprites();
+}
+
+void R_Shadow_DrawLights(void)
+{
+       int flag;
+       int lnum;
+       size_t lightindex;
+       dlight_t *light;
+       size_t range;
 
        R_Shadow_RenderMode_Begin();
 
@@ -4348,7 +4202,7 @@ void R_ShadowVolumeLighting(qboolean visible)
                lightindex = r_shadow_debuglight.integer;
                light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
                if (light && (light->flags & flag))
-                       R_DrawRTLight(&light->rtlight, visible);
+                       R_Shadow_DrawLight(&light->rtlight);
        }
        else
        {
@@ -4357,12 +4211,12 @@ void R_ShadowVolumeLighting(qboolean visible)
                {
                        light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
                        if (light && (light->flags & flag))
-                               R_DrawRTLight(&light->rtlight, visible);
+                               R_Shadow_DrawLight(&light->rtlight);
                }
        }
        if (r_refdef.scene.rtdlight)
                for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
-                       R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
+                       R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
 
        R_Shadow_RenderMode_End();
 }
@@ -4377,6 +4231,241 @@ extern cvar_t r_shadows_drawafterrtlighting;
 extern cvar_t r_shadows_castfrombmodels;
 extern cvar_t r_shadows_throwdistance;
 extern cvar_t r_shadows_throwdirection;
+extern cvar_t r_shadows_focus;
+extern cvar_t r_shadows_shadowmapscale;
+
+void R_Shadow_PrepareModelShadows(void)
+{
+       int i;
+       float scale, size, radius, dot1, dot2;
+       vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
+       entity_render_t *ent;
+
+       if (!r_refdef.scene.numentities)
+               return;
+
+       switch (r_shadow_shadowmode)
+       {
+       case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
+       case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
+               break;
+       case R_SHADOW_SHADOWMODE_STENCIL:
+               for (i = 0;i < r_refdef.scene.numentities;i++)
+               {
+                       ent = r_refdef.scene.entities[i];
+                       if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
+                               R_AnimCache_GetEntity(ent, false, false);
+               }
+               return;
+       default:
+               return;
+       }
+
+       size = 2*r_shadow_shadowmapmaxsize;
+       scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
+       radius = 0.5f * size / scale;
+
+       Math_atov(r_shadows_throwdirection.string, shadowdir);
+       VectorNormalize(shadowdir);
+       dot1 = DotProduct(r_refdef.view.forward, shadowdir);
+       dot2 = DotProduct(r_refdef.view.up, shadowdir);
+       if (fabs(dot1) <= fabs(dot2))
+               VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
+       else
+               VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
+       VectorNormalize(shadowforward);
+       CrossProduct(shadowdir, shadowforward, shadowright);
+       Math_atov(r_shadows_focus.string, shadowfocus);
+       VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
+       VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
+       VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
+       VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
+       if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
+               dot1 = 1;
+       VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
+
+       shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
+       shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
+       shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
+       shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
+       shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
+       shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
+
+       for (i = 0;i < r_refdef.scene.numentities;i++)
+       {
+               ent = r_refdef.scene.entities[i];
+               if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
+                       continue;
+               // cast shadows from anything of the map (submodels are optional)
+               if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
+                       R_AnimCache_GetEntity(ent, false, false);
+       }
+}
+
+void R_DrawModelShadowMaps(void)
+{
+       int i;
+       float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
+       entity_render_t *ent;
+       vec3_t relativelightorigin;
+       vec3_t relativelightdirection, relativeforward, relativeright;
+       vec3_t relativeshadowmins, relativeshadowmaxs;
+       vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
+       float m[12];
+       matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
+       r_viewport_t viewport;
+       GLuint fbo = 0;
+
+       if (!r_refdef.scene.numentities)
+               return;
+
+       switch (r_shadow_shadowmode)
+       {
+       case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
+       case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
+               break;
+       default:
+               return;
+       }
+
+       CHECKGLERROR
+       R_ResetViewRendering3D();
+       R_Shadow_RenderMode_Begin();
+       R_Shadow_RenderMode_ActiveLight(NULL);
+
+       switch (r_shadow_shadowmode)
+       {
+       case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
+               if (!r_shadow_shadowmap2dtexture)
+                       R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
+               fbo = r_shadow_fbo2d;
+               r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
+               r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
+               r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
+               break;
+       case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
+               if (!r_shadow_shadowmaprectangletexture)
+                       R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
+               fbo = r_shadow_fborectangle;
+               r_shadow_shadowmap_texturescale[0] = 1.0f;
+               r_shadow_shadowmap_texturescale[1] = 1.0f;
+               r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
+               break;
+       default:
+               break;
+       }
+
+       size = 2*r_shadow_shadowmapmaxsize;
+       scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
+       radius = 0.5f / scale;
+       nearclip = -r_shadows_throwdistance.value;
+       farclip = r_shadows_throwdistance.value;
+       bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
+
+       r_shadow_shadowmap_parameters[0] = size;
+       r_shadow_shadowmap_parameters[1] = size;
+       r_shadow_shadowmap_parameters[2] = 1.0;
+       r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
+
+       Math_atov(r_shadows_throwdirection.string, shadowdir);
+       VectorNormalize(shadowdir);
+       Math_atov(r_shadows_focus.string, shadowfocus);
+       VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
+       VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
+       VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
+       VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
+       dot1 = DotProduct(r_refdef.view.forward, shadowdir);
+       dot2 = DotProduct(r_refdef.view.up, shadowdir);
+       if (fabs(dot1) <= fabs(dot2)) 
+               VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
+       else
+               VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
+       VectorNormalize(shadowforward);
+       VectorM(scale, shadowforward, &m[0]);
+       if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
+               dot1 = 1;
+       m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
+       CrossProduct(shadowdir, shadowforward, shadowright);
+       VectorM(scale, shadowright, &m[4]);
+       m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
+       VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
+       m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
+       Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
+       Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
+       R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL); 
+
+       VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
+#if 0
+       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
+       R_SetupShader_ShowDepth();
+#else
+       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
+       R_SetupShader_DepthOrShadow();
+#endif
+       CHECKGLERROR
+       GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
+       GL_DepthMask(true);
+       GL_DepthTest(true);
+       R_SetViewport(&viewport);
+       GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
+       qglClearDepth(1);
+#if 0
+       qglClearColor(1,1,1,1);
+       GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+#else
+       GL_Clear(GL_DEPTH_BUFFER_BIT);
+#endif
+       GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
+       CHECKGLERROR
+
+       for (i = 0;i < r_refdef.scene.numentities;i++)
+       {
+               ent = r_refdef.scene.entities[i];
+
+               // cast shadows from anything of the map (submodels are optional)
+               if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
+               {
+                       relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
+                       Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
+                       Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
+                       Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
+                       Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
+                       relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
+                       relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
+                       relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
+                       relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
+                       relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
+                       relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
+                       RSurf_ActiveModelEntity(ent, false, false, false);
+                       ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
+                       rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
+               }
+       }
+
+       R_Shadow_RenderMode_End();
+
+       Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
+       Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
+       Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); 
+       Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
+       Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
+       Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
+
+       r_shadow_usingshadowmaportho = true;
+       switch (r_shadow_shadowmode)
+       {
+       case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
+               r_shadow_usingshadowmap2d = true;
+               break;
+       case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
+               r_shadow_usingshadowmaprect = true;
+               break;
+       default:
+               break;
+       }
+}
+
 void R_DrawModelShadows(void)
 {
        int i;
@@ -4387,7 +4476,7 @@ void R_DrawModelShadows(void)
        vec3_t relativeshadowmins, relativeshadowmaxs;
        vec3_t tmp, shadowdir;
 
-       if (!r_drawentities.integer || !gl_stencil)
+       if (!r_refdef.scene.numentities || !vid.stencil || r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL)
                return;
 
        CHECKGLERROR
@@ -4453,7 +4542,7 @@ void R_DrawModelShadows(void)
                        }
 
                        VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
-                       RSurf_ActiveModelEntity(ent, false, false);
+                       RSurf_ActiveModelEntity(ent, false, false, false);
                        ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
                        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
                }
@@ -4466,12 +4555,12 @@ void R_DrawModelShadows(void)
        //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
        //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
        //GL_ScissorTest(true);
-       //R_Mesh_Matrix(&identitymatrix);
+       //R_EntityMatrix(&identitymatrix);
        //R_Mesh_ResetTextureState();
        R_ResetViewRendering2D();
        R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
        R_Mesh_ColorPointer(NULL, 0, 0);
-       R_SetupGenericShader(false);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
 
        // set up a darkening blend on shadowed areas
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -4483,12 +4572,12 @@ void R_DrawModelShadows(void)
        //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
        //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
        qglEnable(GL_STENCIL_TEST);CHECKGLERROR
-       qglStencilMask(~0);CHECKGLERROR
+       qglStencilMask(255);CHECKGLERROR
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
-       qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
+       qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
 
        // apply the blend to the shadowed areas
-       R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
+       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
 
        // restore the viewport
        R_SetViewport(&r_refdef.view.viewport);
@@ -4501,8 +4590,9 @@ void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
 {
        float zdist;
        vec3_t centerorigin;
+       float vertex3f[12];
        // if it's too close, skip it
-       if (VectorLength(rtlight->color) < (1.0f / 256.0f))
+       if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
                return;
        zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
        if (zdist < 32)
@@ -4511,23 +4601,30 @@ void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
        {
                rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
                rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
+               // we count potential samples in the middle of the screen, we count actual samples at the light location, this allows counting potential samples of off-screen lights
                VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
 
                CHECKGLERROR
-               // NOTE: we can't disable depth testing using R_DrawSprite's depthdisable argument, which calls GL_DepthTest, as that's broken in the ATI drivers
+               // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
                qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
                qglDepthFunc(GL_ALWAYS);
-               R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, false, false, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1);
+               R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
+               R_Mesh_VertexPointer(vertex3f, 0, 0);
+               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
                qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
                qglDepthFunc(GL_LEQUAL);
                qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
-               R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, false, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1);
+               R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
+               R_Mesh_VertexPointer(vertex3f, 0, 0);
+               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
                qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
                CHECKGLERROR
        }
        rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
 }
 
+static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
+
 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
 {
        vec3_t color;
@@ -4551,12 +4648,25 @@ void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
                if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
                        return;
        }
-       VectorScale(rtlight->color, cscale, color);
+       VectorScale(rtlight->currentcolor, cscale, color);
        if (VectorLength(color) > (1.0f / 256.0f))
-               R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, color[0], color[1], color[2], 1);
+       {
+               float vertex3f[12];
+               qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
+               if(negated)
+               {
+                       VectorNegate(color, color);
+                       qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
+               }
+               R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
+               RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, RENDER_NODEPTHTEST, 0, color[0], color[1], color[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
+               R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
+               if(negated)
+                       qglBlendEquationEXT(GL_FUNC_ADD_EXT);
+       }
 }
 
-void R_DrawCoronas(void)
+void R_Shadow_DrawCoronas(void)
 {
        int i, flag;
        qboolean usequery;
@@ -4569,7 +4679,7 @@ void R_DrawCoronas(void)
        if (r_waterstate.renderingscene)
                return;
        flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
-       R_Mesh_Matrix(&identitymatrix);
+       R_EntityMatrix(&identitymatrix);
 
        range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
 
@@ -4577,20 +4687,30 @@ void R_DrawCoronas(void)
        // use GL_ARB_occlusion_query if available
        // otherwise use raytraces
        r_numqueries = 0;
-       usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
+       usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
        if (usequery)
        {
                GL_ColorMask(0,0,0,0);
                if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
-               if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
+               if (r_maxqueries < MAX_OCCLUSION_QUERIES)
                {
                        i = r_maxqueries;
                        r_maxqueries = (range + r_refdef.scene.numlights) * 4;
-                       r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
+                       r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
                        CHECKGLERROR
                        qglGenQueriesARB(r_maxqueries - i, r_queries + i);
                        CHECKGLERROR
                }
+               RSurf_ActiveWorldEntity();
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_CullFace(GL_NONE);
+               GL_DepthMask(false);
+               GL_DepthRange(0, 1);
+               GL_PolygonOffset(0, 0);
+               GL_DepthTest(true);
+               R_Mesh_ColorPointer(NULL, 0, 0);
+               R_Mesh_ResetTextureState();
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
        }
        for (lightindex = 0;lightindex < range;lightindex++)
        {
@@ -4649,140 +4769,6 @@ void R_DrawCoronas(void)
 
 
 
-//static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
-typedef struct suffixinfo_s
-{
-       char *suffix;
-       qboolean flipx, flipy, flipdiagonal;
-}
-suffixinfo_t;
-static suffixinfo_t suffix[3][6] =
-{
-       {
-               {"px",   false, false, false},
-               {"nx",   false, false, false},
-               {"py",   false, false, false},
-               {"ny",   false, false, false},
-               {"pz",   false, false, false},
-               {"nz",   false, false, false}
-       },
-       {
-               {"posx", false, false, false},
-               {"negx", false, false, false},
-               {"posy", false, false, false},
-               {"negy", false, false, false},
-               {"posz", false, false, false},
-               {"negz", false, false, false}
-       },
-       {
-               {"rt",    true, false,  true},
-               {"lf",   false,  true,  true},
-               {"ft",    true,  true, false},
-               {"bk",   false, false, false},
-               {"up",    true, false,  true},
-               {"dn",    true, false,  true}
-       }
-};
-
-static int componentorder[4] = {0, 1, 2, 3};
-
-rtexture_t *R_Shadow_LoadCubemap(const char *basename)
-{
-       int i, j, cubemapsize;
-       unsigned char *cubemappixels, *image_buffer;
-       rtexture_t *cubemaptexture;
-       char name[256];
-       // must start 0 so the first loadimagepixels has no requested width/height
-       cubemapsize = 0;
-       cubemappixels = NULL;
-       cubemaptexture = NULL;
-       // keep trying different suffix groups (posx, px, rt) until one loads
-       for (j = 0;j < 3 && !cubemappixels;j++)
-       {
-               // load the 6 images in the suffix group
-               for (i = 0;i < 6;i++)
-               {
-                       // generate an image name based on the base and and suffix
-                       dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
-                       // load it
-                       if ((image_buffer = loadimagepixelsbgra(name, false, false)))
-                       {
-                               // an image loaded, make sure width and height are equal
-                               if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
-                               {
-                                       // if this is the first image to load successfully, allocate the cubemap memory
-                                       if (!cubemappixels && image_width >= 1)
-                                       {
-                                               cubemapsize = image_width;
-                                               // note this clears to black, so unavailable sides are black
-                                               cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
-                                       }
-                                       // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
-                                       if (cubemappixels)
-                                               Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
-                               }
-                               else
-                                       Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
-                               // free the image
-                               Mem_Free(image_buffer);
-                       }
-               }
-       }
-       // if a cubemap loaded, upload it
-       if (cubemappixels)
-       {
-               if (developer_loading.integer)
-                       Con_Printf("loading cubemap \"%s\"\n", basename);
-
-               if (!r_shadow_filters_texturepool)
-                       r_shadow_filters_texturepool = R_AllocTexturePool();
-               cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
-               Mem_Free(cubemappixels);
-       }
-       else
-       {
-               Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
-               if (developer_loading.integer)
-               {
-                       Con_Printf("(tried tried images ");
-                       for (j = 0;j < 3;j++)
-                               for (i = 0;i < 6;i++)
-                                       Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
-                       Con_Print(" and was unable to find any of them).\n");
-               }
-       }
-       return cubemaptexture;
-}
-
-rtexture_t *R_Shadow_Cubemap(const char *basename)
-{
-       int i;
-       for (i = 0;i < numcubemaps;i++)
-               if (!strcasecmp(cubemaps[i].basename, basename))
-                       return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
-       if (i >= MAX_CUBEMAPS)
-               return r_texture_whitecube;
-       numcubemaps++;
-       strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
-       cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
-       return cubemaps[i].texture;
-}
-
-void R_Shadow_FreeCubemaps(void)
-{
-       int i;
-       for (i = 0;i < numcubemaps;i++)
-       {
-               if (developer_loading.integer)
-                       Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
-               if (cubemaps[i].texture)
-                       R_FreeTexture(cubemaps[i].texture);
-       }
-
-       numcubemaps = 0;
-       R_FreeTexturePool(&r_shadow_filters_texturepool);
-}
-
 dlight_t *R_Shadow_NewWorldLight(void)
 {
        return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
@@ -4805,9 +4791,14 @@ void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, ve
        light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
        light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
        light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
+       /*
        light->color[0] = max(color[0], 0);
        light->color[1] = max(color[1], 0);
        light->color[2] = max(color[2], 0);
+       */
+       light->color[0] = color[0];
+       light->color[1] = color[1];
+       light->color[2] = color[2];
        light->radius = max(radius, 0);
        light->style = style;
        light->shadow = shadowenable;
@@ -4844,7 +4835,6 @@ void R_Shadow_ClearWorldLights(void)
                        R_Shadow_FreeWorldLight(light);
        }
        r_shadow_selectedlight = NULL;
-       R_Shadow_FreeCubemaps();
 }
 
 void R_Shadow_SelectLight(dlight_t *light)
@@ -4859,7 +4849,10 @@ void R_Shadow_SelectLight(dlight_t *light)
 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
 {
        // this is never batched (there can be only one)
-       R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprcursor->tex, r_editlights_sprcursor->tex, false, false, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE, 1, 1, 1, 1);
+       float vertex3f[12];
+       R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
+       RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
+       R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
 }
 
 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
@@ -4867,12 +4860,16 @@ void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, co
        float intensity;
        float s;
        vec3_t spritecolor;
-       cachepic_t *pic;
+       skinframe_t *skinframe;
+       float vertex3f[12];
 
        // this is never batched (due to the ent parameter changing every time)
        // so numsurfaces == 1 and surfacelist[0] == lightnumber
        const dlight_t *light = (dlight_t *)ent;
        s = EDLIGHTSPRSIZE;
+
+       R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
+
        intensity = 0.5f;
        VectorScale(light->color, intensity, spritecolor);
        if (VectorLength(spritecolor) < 0.1732f)
@@ -4882,18 +4879,24 @@ void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, co
 
        // draw light sprite
        if (light->cubemapname[0] && !light->shadow)
-               pic = r_editlights_sprcubemapnoshadowlight;
+               skinframe = r_editlights_sprcubemapnoshadowlight;
        else if (light->cubemapname[0])
-               pic = r_editlights_sprcubemaplight;
+               skinframe = r_editlights_sprcubemaplight;
        else if (!light->shadow)
-               pic = r_editlights_sprnoshadowlight;
+               skinframe = r_editlights_sprnoshadowlight;
        else
-               pic = r_editlights_sprlight;
-       R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, pic->tex, pic->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, spritecolor[0], spritecolor[1], spritecolor[2], 1);
+               skinframe = r_editlights_sprlight;
+
+       RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, spritecolor[0], spritecolor[1], spritecolor[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
+       R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
+
        // draw selection sprite if light is selected
        if (light->selected)
-               R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprselection->tex, r_editlights_sprselection->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, 1, 1, 1, 1);
-       // VorteX todo: add normalmode/realtime mode light overlay sprites?
+       {
+               RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
+               R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
+               // VorteX todo: add normalmode/realtime mode light overlay sprites?
+       }
 }
 
 void R_Shadow_DrawLightSprites(void)
@@ -4910,6 +4913,26 @@ void R_Shadow_DrawLightSprites(void)
        R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
 }
 
+int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
+{
+       unsigned int range;
+       dlight_t *light;
+       rtlight_t *rtlight;
+       range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
+       if (lightindex >= range)
+               return -1;
+       light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+       if (!light)
+               return 0;
+       rtlight = &light->rtlight;
+       //if (!(rtlight->flags & flag))
+       //      return 0;
+       VectorCopy(rtlight->shadoworigin, origin);
+       *radius = rtlight->radius;
+       VectorCopy(rtlight->color, color);
+       return 1;
+}
+
 void R_Shadow_SelectLightInView(void)
 {
        float bestrating, rating, temp[3];
@@ -5153,7 +5176,14 @@ typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX,
 
 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
 {
-       int entnum, style, islight, skin, pflags, effects, type, n;
+       int entnum;
+       int style;
+       int islight;
+       int skin;
+       int pflags;
+       //int effects;
+       int type;
+       int n;
        char *entfiledata;
        const char *data;
        float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
@@ -5187,7 +5217,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                style = 0;
                skin = 0;
                pflags = 0;
-               effects = 0;
+               //effects = 0;
                islight = false;
                while (1)
                {
@@ -5314,8 +5344,8 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                                skin = (int)atof(value);
                        else if (!strcmp("pflags", key))
                                pflags = (int)atof(value);
-                       else if (!strcmp("effects", key))
-                               effects = (int)atof(value);
+                       //else if (!strcmp("effects", key))
+                       //      effects = (int)atof(value);
                        else if (cl.worldmodel->type == mod_brushq3)
                        {
                                if (!strcmp("scale", key))
@@ -5825,26 +5855,26 @@ void R_Shadow_EditLights_DrawSelectedLightProperties(void)
                        lightnumber = lightindex;
                lightcount++;
        }
-       dpsnprintf(temp, sizeof(temp), "Cursor origin: %.0f %.0f %.0f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8;
-       dpsnprintf(temp, sizeof(temp), "Total lights : %i active (%i total)", lightcount, (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8;
+       dpsnprintf(temp, sizeof(temp), "Cursor origin: %.0f %.0f %.0f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8;
+       dpsnprintf(temp, sizeof(temp), "Total lights : %i active (%i total)", lightcount, (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8;
        y += 8;
        if (r_shadow_selectedlight == NULL)
                return;
-       dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
-       dpsnprintf(temp, sizeof(temp), "Origin       : %.0f %.0f %.0f\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, NULL, true);y += 8;
-       dpsnprintf(temp, sizeof(temp), "Angles       : %.0f %.0f %.0f\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, NULL, true);y += 8;
-       dpsnprintf(temp, sizeof(temp), "Color        : %.2f %.2f %.2f\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, NULL, true);y += 8;
-       dpsnprintf(temp, sizeof(temp), "Radius       : %.0f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
-       dpsnprintf(temp, sizeof(temp), "Corona       : %.0f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
-       dpsnprintf(temp, sizeof(temp), "Style        : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
-       dpsnprintf(temp, sizeof(temp), "Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
-       dpsnprintf(temp, sizeof(temp), "Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
-       dpsnprintf(temp, sizeof(temp), "CoronaSize   : %.2f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
-       dpsnprintf(temp, sizeof(temp), "Ambient      : %.2f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
-       dpsnprintf(temp, sizeof(temp), "Diffuse      : %.2f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
-       dpsnprintf(temp, sizeof(temp), "Specular     : %.2f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
-       dpsnprintf(temp, sizeof(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, NULL, true);y += 8;
-       dpsnprintf(temp, sizeof(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, NULL, true);y += 8;
+       dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
+       dpsnprintf(temp, sizeof(temp), "Origin       : %.0f %.0f %.0f\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, NULL, true, FONT_DEFAULT);y += 8;
+       dpsnprintf(temp, sizeof(temp), "Angles       : %.0f %.0f %.0f\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, NULL, true, FONT_DEFAULT);y += 8;
+       dpsnprintf(temp, sizeof(temp), "Color        : %.2f %.2f %.2f\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, NULL, true, FONT_DEFAULT);y += 8;
+       dpsnprintf(temp, sizeof(temp), "Radius       : %.0f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
+       dpsnprintf(temp, sizeof(temp), "Corona       : %.0f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
+       dpsnprintf(temp, sizeof(temp), "Style        : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
+       dpsnprintf(temp, sizeof(temp), "Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
+       dpsnprintf(temp, sizeof(temp), "Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
+       dpsnprintf(temp, sizeof(temp), "CoronaSize   : %.2f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
+       dpsnprintf(temp, sizeof(temp), "Ambient      : %.2f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
+       dpsnprintf(temp, sizeof(temp), "Diffuse      : %.2f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
+       dpsnprintf(temp, sizeof(temp), "Specular     : %.2f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
+       dpsnprintf(temp, sizeof(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, NULL, true, FONT_DEFAULT);y += 8;
+       dpsnprintf(temp, sizeof(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, NULL, true, FONT_DEFAULT);y += 8;
 }
 
 void R_Shadow_EditLights_ToggleShadow_f(void)
@@ -6033,7 +6063,7 @@ void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffu
 
        if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
        {
-               ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
+               ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
                r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
        }
        else