]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
remove support for GL_EXT_compiled_vertex_array extension
[xonotic/darkplaces.git] / r_shadow.c
index 7674fb506bc666bcd498218f258168e7db593741..56c387f986c6d9b1d86581d9ea136244f2a8f2ee 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
@@ -203,6 +201,7 @@ qboolean r_shadow_shadowmapsampler;
 int r_shadow_shadowmappcf;
 int r_shadow_shadowmapborder;
 int r_shadow_lightscissor[4];
+qboolean r_shadow_usingdeferredprepass;
 
 int maxshadowtriangles;
 int *shadowelements;
@@ -253,15 +252,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"};
@@ -273,8 +286,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"};
@@ -285,8 +297,8 @@ 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"};
@@ -303,7 +315,6 @@ cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nea
 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 OpenGL 2.0 render path)"};
@@ -383,7 +394,8 @@ void R_Shadow_SetShadowMode(void)
        switch(vid.renderpath)
        {
        case RENDERPATH_GL20:
-               if(r_shadow_shadowmapping.integer && vid.support.ext_framebuffer_object)
+       case RENDERPATH_CGGL:
+               if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
                {
                        if(r_shadow_shadowmapfilterquality < 0)
                        {
@@ -550,8 +562,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
@@ -559,6 +575,11 @@ 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;
@@ -645,6 +666,9 @@ void R_Shadow_Init(void)
        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);
@@ -655,7 +679,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);
@@ -685,7 +708,6 @@ void R_Shadow_Init(void)
        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);
@@ -1308,7 +1330,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
@@ -1330,7 +1351,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
        }
 }
@@ -1663,7 +1683,7 @@ static void R_Shadow_MakeTextures_MakeCorona(void)
                        pixels[y][x][3] = 255;
                }
        }
-       r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_PRECACHE | TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
+       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)
@@ -1695,12 +1715,12 @@ 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 && vid.support.ext_texture_3d)
        {
@@ -1708,7 +1728,7 @@ static void R_Shadow_MakeTextures(void)
                        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;
@@ -1717,7 +1737,7 @@ static void R_Shadow_MakeTextures(void)
        R_Shadow_MakeTextures_MakeCorona();
 
        // Editor light sprites
-       r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
+       r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
        "................"
        ".3............3."
        "..5...2332...5.."
@@ -1735,7 +1755,7 @@ static void R_Shadow_MakeTextures(void)
        ".3............3."
        "................"
        , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
-       r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
+       r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
        "................"
        "................"
        "......1111......"
@@ -1753,7 +1773,7 @@ static void R_Shadow_MakeTextures(void)
        "................"
        "................"
        , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
-       r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
+       r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
        "................"
        "................"
        "......1111......"
@@ -1771,7 +1791,7 @@ static void R_Shadow_MakeTextures(void)
        "................"
        "................"
        , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
-       r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
+       r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
        "................"
        "................"
        "......2772......"
@@ -1789,7 +1809,7 @@ static void R_Shadow_MakeTextures(void)
        "................"
        "................"
        , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
-       r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
+       r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
        "................"
        "................"
        "......2772......"
@@ -1807,7 +1827,7 @@ static void R_Shadow_MakeTextures(void)
        "................"
        "................"
        , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
-       r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
+       r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
        "................"
        ".777752..257777."
        ".742........247."
@@ -1883,6 +1903,7 @@ void R_Shadow_RenderMode_Begin(void)
        switch(vid.renderpath)
        {
        case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
                r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
                break;
        case RENDERPATH_GL13:
@@ -1948,7 +1969,7 @@ void R_Shadow_RenderMode_Reset(void)
        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;
@@ -1971,7 +1992,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;
@@ -2029,7 +2050,7 @@ 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)
@@ -2070,10 +2091,11 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
                        qglDrawBuffer(GL_NONE);CHECKGLERROR
                        qglReadBuffer(GL_NONE);CHECKGLERROR
                        status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
-                       if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
+                       if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
                        {
                                Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
                                Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
+                               Cvar_SetValueQuick(&r_shadow_deferred, 0);
                        }
 #endif
                }
@@ -2104,10 +2126,11 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
                        qglDrawBuffer(GL_NONE);CHECKGLERROR
                        qglReadBuffer(GL_NONE);CHECKGLERROR
                        status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
-                       if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
+                       if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
                        {
                                Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
                                Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
+                               Cvar_SetValueQuick(&r_shadow_deferred, 0);
                        }
 #endif
                }
@@ -2136,10 +2159,11 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
                        qglDrawBuffer(GL_NONE);CHECKGLERROR
                        qglReadBuffer(GL_NONE);CHECKGLERROR
                        status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
-                       if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
+                       if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
                        {
                                Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
                                Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
+                               Cvar_SetValueQuick(&r_shadow_deferred, 0);
                        }
  #endif
                }
@@ -2154,11 +2178,11 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
        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
@@ -2214,40 +2238,90 @@ void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qb
        // do global setup needed for the chosen lighting mode
        if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
        {
-               R_Mesh_TexBindAll(GL20TU_CUBE, 0, 0, R_GetTexture(rsurface.rtlight->currentcubemap), 0); // light filter
                GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
                CHECKGLERROR
+       }
+       if (shadowmapping)
+       {
+               if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
+                       r_shadow_usingshadowmap2d = true;
+               else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
+                       r_shadow_usingshadowmaprect = true;
+               else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
+                       r_shadow_usingshadowmapcube = true;
+       }
+       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, ~0);CHECKGLERROR
+               }
+               qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
                if (shadowmapping)
                {
                        if (r_shadow_shadowmode == 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)
-                       {
                                r_shadow_usingshadowmaprect = true;
-                               R_Mesh_TexBindAll(GL20TU_SHADOWMAPRECT, 0, 0, 0, R_GetTexture(r_shadow_shadowmaprectangletexture));
-                               CHECKGLERROR
-                       }
                        else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
-                       {
                                r_shadow_usingshadowmapcube = true;
-                               R_Mesh_TexBindAll(GL20TU_SHADOWMAPCUBE, 0, 0, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);
-                               CHECKGLERROR
-                       }
-
-                       if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
-                       {
-                               R_Mesh_TexBindAll(GL20TU_CUBEPROJECTION, 0, 0, R_GetTexture(r_shadow_shadowmapvsdcttexture), 0);
-                               CHECKGLERROR
-                       }
                }
+
+               // 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);
        }
-       R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
-       //GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
-       CHECKGLERROR
 }
 
 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
@@ -2596,44 +2670,16 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
        }
 }
 
-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_TexBindAll(GL20TU_CUBE, 0, 0, R_GetTexture(rsurface.rtlight->currentcubemap), 0);
-       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
@@ -2657,7 +2703,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve
        const int *e;
        float *c;
        int maxtriangles = 4096;
-       int newelements[4096*3];
+       static int newelements[4096*3];
        R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
        for (renders = 0;renders < 64;renders++)
        {
@@ -2734,90 +2780,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);
+       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:
-               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;
-               m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
-               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;
-               R_Mesh_TextureState(&m);
+               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:
-               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;
-               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;
-               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;
-               R_Mesh_TextureState(&m);
-               break;
+               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:
-               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;
-               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;
-               R_Mesh_TextureState(&m);
+               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:
-               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;
-               R_Mesh_TextureState(&m);
                break;
        default:
                break;
        }
-       //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);
        }
 }
@@ -2827,12 +2850,8 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle
 {
        float ambientscale, diffusescale, specularscale;
        qboolean negated;
-       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];
+       float lightcolor[3];
+       VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
        ambientscale = rsurface.rtlight->ambientscale;
        diffusescale = rsurface.rtlight->diffusescale;
        specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
@@ -2842,79 +2861,33 @@ 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;
-       negated = (lightcolorbase[0] + lightcolorbase[1] + lightcolorbase[2] < 0) && vid.support.ext_blend_subtract;
+       negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
        if(negated)
        {
-               VectorNegate(lightcolorbase, lightcolorbase);
+               VectorNegate(lightcolor, lightcolor);
                qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
        }
        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_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, 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;
-               }
-       }
-       else
+       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_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, 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);
@@ -3064,8 +3037,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)
@@ -3328,7 +3301,6 @@ void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, co
                {
                        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
@@ -3350,12 +3322,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++)
                {
@@ -3376,8 +3348,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;
@@ -3397,23 +3370,15 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent)
 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);
-       switch(r_shadow_lightingrendermode)
-       {
-       case R_SHADOW_RENDERMODE_LIGHT_GLSL:
-               R_Mesh_TexMatrix(3, &rsurface.entitytolight);
-               break;
-       default:
-               break;
-       }
 }
 
-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;
@@ -3425,16 +3390,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);
-       switch(r_shadow_lightingrendermode)
-       {
-       case R_SHADOW_RENDERMODE_LIGHT_GLSL:
-               R_Mesh_TexMatrix(3, &rsurface.entitytolight);
-               break;
-       default:
-               break;
-       }
 
-       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
 }
@@ -3452,7 +3409,7 @@ void R_Shadow_DrawEntityLight(entity_render_t *ent)
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
-void R_CacheRTLight(rtlight_t *rtlight)
+void R_Shadow_PrepareLight(rtlight_t *rtlight)
 {
        int i;
        float f;
@@ -3571,67 +3528,64 @@ void R_CacheRTLight(rtlight_t *rtlight)
        numshadowentities_noselfshadow = 0;
 
        // 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, 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))
+                       // 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 (!(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_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_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_noselfshadow[numshadowentities_noselfshadow++] = ent;
-                                       else
-                                               shadowentities[numshadowentities++] = ent;
-                               }
+                               if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
+                                       shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
+                               else
+                                       shadowentities[numshadowentities++] = ent;
                        }
                }
        }
@@ -3648,10 +3602,10 @@ void R_CacheRTLight(rtlight_t *rtlight)
 
        // cache all the animated entities that cast a shadow but are not visible
        for (i = 0;i < numshadowentities;i++)
-               if (shadowentities[i]->animcacheindex < 0)
+               if (!shadowentities[i]->animcache_vertex3f)
                        R_AnimCache_GetEntity(shadowentities[i], false, false);
        for (i = 0;i < numshadowentities_noselfshadow;i++)
-               if (shadowentities_noselfshadow[i]->animcacheindex < 0)
+               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
@@ -3667,8 +3621,10 @@ void R_CacheRTLight(rtlight_t *rtlight)
        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)
        {
-               rtlight->cached_shadowtrispvs                  =   (unsigned char *)R_FrameData_Store(r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, shadowtrispvs);
-               rtlight->cached_lighttrispvs                   =   (unsigned char *)R_FrameData_Store(r_refdef.scene.worldmodel->surfmesh.num_triangles, lighttrispvs);
+               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
@@ -3680,7 +3636,7 @@ void R_CacheRTLight(rtlight_t *rtlight)
        }
 }
 
-void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
+void R_Shadow_DrawLight(rtlight_t *rtlight)
 {
        int i;
        int numsurfaces;
@@ -3855,7 +3811,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                }
 
                // 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))
                        {
@@ -3912,18 +3868,96 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                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);
+       }
 }
 
-void R_PrepareRTLights(void)
+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;
-       float f;
+       entity_render_t *ent;
 
-       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);
+       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)
@@ -3931,7 +3965,7 @@ void R_PrepareRTLights(void)
                lightindex = r_shadow_debuglight.integer;
                light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
                if (light && (light->flags & flag))
-                       R_CacheRTLight(&light->rtlight);
+                       R_Shadow_DrawLight(&light->rtlight);
        }
        else
        {
@@ -3940,27 +3974,25 @@ void R_PrepareRTLights(void)
                {
                        light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
                        if (light && (light->flags & flag))
-                               R_CacheRTLight(&light->rtlight);
+                               R_Shadow_DrawLight(&light->rtlight);
                }
        }
        if (r_refdef.scene.rtdlight)
-       {
                for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
-                       R_CacheRTLight(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);
-               }
-       }
+                       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;
@@ -3968,9 +4000,10 @@ void R_ShadowVolumeLighting(qboolean visible)
        dlight_t *light;
        size_t range;
        float f;
+       GLenum status;
 
        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_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 || 
@@ -3978,10 +4011,74 @@ void R_ShadowVolumeLighting(qboolean visible)
                r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
                R_Shadow_FreeShadowMaps();
 
-       if (r_editlights.integer)
-               R_Shadow_DrawLightSprites();
+       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.support.arb_texture_rectangle || 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;
+               }
 
-       R_Shadow_RenderMode_Begin();
+               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_LoadTextureShadowMapRectangle(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
+                       r_shadow_prepassgeometrynormalmaptexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
+                       r_shadow_prepasslightingdiffusetexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
+                       r_shadow_prepasslightingspeculartexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_BGRA, 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_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
+                       qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
+                       // render depth into one texture and normalmap into the other
+                       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_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
+                       qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
+                       qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, 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
+                       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)
@@ -3989,7 +4086,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_PrepareLight(&light->rtlight);
        }
        else
        {
@@ -3998,13 +4095,13 @@ 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_PrepareLight(&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_PrepareLight(r_refdef.scene.lights[lnum]);
        }
        else if(gl_flashblend.integer)
        {
@@ -4016,6 +4113,42 @@ void R_ShadowVolumeLighting(qboolean visible)
                }
        }
 
+       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();
+
+       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
+       {
+               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_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]);
+
        R_Shadow_RenderMode_End();
 }
 
@@ -4039,7 +4172,7 @@ void R_DrawModelShadows(void)
        vec3_t relativeshadowmins, relativeshadowmaxs;
        vec3_t tmp, shadowdir;
 
-       if (!r_drawentities.integer || !vid.stencil)
+       if (!r_refdef.scene.numentities || !vid.stencil)
                return;
 
        CHECKGLERROR
@@ -4105,7 +4238,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
                }
@@ -4118,12 +4251,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);
@@ -4223,13 +4356,13 @@ void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
                }
                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);
+               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;
@@ -4242,7 +4375,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
 
@@ -4273,7 +4406,7 @@ void R_DrawCoronas(void)
                GL_DepthTest(true);
                R_Mesh_ColorPointer(NULL, 0, 0);
                R_Mesh_ResetTextureState();
-               R_SetupGenericShader(false);
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
        }
        for (lightindex = 0;lightindex < range;lightindex++)
        {
@@ -4419,7 +4552,7 @@ rtexture_t *R_Shadow_LoadCubemap(const char *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);
+               cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
                Mem_Free(cubemappixels);
        }
        else
@@ -4550,7 +4683,7 @@ void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const r
        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);
+       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)
@@ -4586,13 +4719,13 @@ void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, co
                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);
+       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)
        {
                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);
+               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?
        }
 }
@@ -5546,26 +5679,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)
@@ -5754,7 +5887,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