]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
Refactored R_UpdateEntityLighting to CL_UpdateEntityShading, which sets fields like...
[xonotic/darkplaces.git] / gl_rmain.c
index ffb11d702c8f86790cc5c89a5e70f0f4837dae2c..cd3d41ee4c64281e5111ec0092f396c51b1921f2 100644 (file)
@@ -28,12 +28,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "csprogs.h"
 #include "cl_video.h"
 #include "dpsoftrast.h"
+#include "cl_collision.h"
 
 #ifdef SUPPORTD3D
 #include <d3d9.h>
 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
 #endif
 
+#ifdef WIN32
+// Enable NVIDIA High Performance Graphics while using Integrated Graphics.
+#ifdef __cplusplus
+extern "C" {
+#endif
+__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
+#ifdef __cplusplus
+}
+#endif
+#endif
+
 mempool_t *r_main_mempool;
 rtexturepool_t *r_main_texturepool;
 
@@ -65,10 +77,10 @@ cvar_t r_motionblur_mousefactor_minspeed = {CVAR_SAVE, "r_motionblur_mousefactor
 cvar_t r_motionblur_mousefactor_maxspeed = {CVAR_SAVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
 
 // TODO do we want a r_equalize_entities cvar that works on all ents, or would that be a cheat?
-cvar_t r_equalize_entities_fullbright = {CVAR_SAVE, "r_equalize_entities_fullbright", "0", "render fullbright entities by equalizing their lightness, not by not rendering light"};
-cvar_t r_equalize_entities_minambient = {CVAR_SAVE, "r_equalize_entities_minambient", "0.5", "light equalizing: ensure at least this ambient/diffuse ratio"};
-cvar_t r_equalize_entities_by = {CVAR_SAVE, "r_equalize_entities_by", "0.7", "light equalizing: exponent of dynamics compression (0 = no compression, 1 = full compression)"};
-cvar_t r_equalize_entities_to = {CVAR_SAVE, "r_equalize_entities_to", "0.8", "light equalizing: target light level"};
+cvar_t r_equalize_entities_fullbright = {CVAR_SAVE, "r_equalize_entities_fullbright", "0", "render fullbright entities by equalizing their lightness, not by not rendering light (DEPRECATED)"};
+cvar_t r_equalize_entities_minambient = {CVAR_SAVE, "r_equalize_entities_minambient", "0.5", "light equalizing: ensure at least this ambient/diffuse ratio (DEPRECATED)"};
+cvar_t r_equalize_entities_by = {CVAR_SAVE, "r_equalize_entities_by", "0.7", "light equalizing: exponent of dynamics compression (0 = no compression, 1 = full compression) (DEPRECATED)"};
+cvar_t r_equalize_entities_to = {CVAR_SAVE, "r_equalize_entities_to", "0.8", "light equalizing: target light level (DEPRECATED)"};
 
 cvar_t r_depthfirst = {CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
 cvar_t r_useinfinitefarclip = {CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
@@ -82,6 +94,7 @@ cvar_t r_transparent_sortsurfacesbynearest = {0, "r_transparent_sortsurfacesbyne
 cvar_t r_transparent_useplanardistance = {0, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
 cvar_t r_showoverdraw = {0, "r_showoverdraw", "0", "shows overlapping geometry"};
 cvar_t r_showbboxes = {0, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
+cvar_t r_showbboxes_client = { 0, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)" };
 cvar_t r_showsurfaces = {0, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
 cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
 cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
@@ -98,18 +111,26 @@ cvar_t r_drawworld = {0, "r_drawworld","1", "draw world (most static stuff)"};
 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
 cvar_t r_drawexteriormodel = {0, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
 cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
+cvar_t r_cullentities_trace_entityocclusion = { 0, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull" };
 cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
 cvar_t r_cullentities_trace_tempentitysamples = {0, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
 cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
 cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
+cvar_t r_cullentities_trace_eyejitter = {0, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
 cvar_t r_sortentities = {0, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
 cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
 cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders faster"};
 
-cvar_t r_fakelight = {0, "r_fakelight","0", "render 'fake' lighting instead of real lightmaps"};
-cvar_t r_fakelight_intensity = {0, "r_fakelight_intensity","0.75", "fakelight intensity modifier"};
+cvar_t r_fakelight = {0, "r_fakelight","0", "render 'fake' lighting instead of real lightmaps (DEPRECATED)"};
+cvar_t r_fakelight_intensity = {0, "r_fakelight_intensity","0.75", "fakelight intensity modifier (DEPRECATED)"};
 #define FAKELIGHT_ENABLED (r_fakelight.integer >= 2 || (r_fakelight.integer && r_refdef.scene.worldmodel && !r_refdef.scene.worldmodel->lit))
 
+cvar_t r_fullbright_directed = {0, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
+cvar_t r_fullbright_directed_ambient = {0, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
+cvar_t r_fullbright_directed_diffuse = {0, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
+cvar_t r_fullbright_directed_pitch = {0, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
+cvar_t r_fullbright_directed_pitch_relative = {0, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
+
 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
@@ -120,7 +141,7 @@ cvar_t r_shadows_throwdirection = {CVAR_SAVE, "r_shadows_throwdirection", "0 0 -
 cvar_t r_shadows_drawafterrtlighting = {CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
 cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
 cvar_t r_shadows_focus = {CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
-cvar_t r_shadows_shadowmapscale = {CVAR_SAVE, "r_shadows_shadowmapscale", "1", "increases shadowmap quality (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
+cvar_t r_shadows_shadowmapscale = {CVAR_SAVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
 cvar_t r_shadows_shadowmapbias = {CVAR_SAVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
 cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
 cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
@@ -184,6 +205,7 @@ cvar_t r_glsl_postprocess_uservec3_enable = {CVAR_SAVE, "r_glsl_postprocess_user
 cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
 
 cvar_t r_water = {CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
+cvar_t r_water_cameraentitiesonly = {CVAR_SAVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
 cvar_t r_water_clippingplanebias = {CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
 cvar_t r_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
 cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
@@ -238,12 +260,12 @@ cvar_t r_glsl_saturation_redcompensate = {CVAR_SAVE, "r_glsl_saturation_redcompe
 cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
 
 cvar_t r_framedatasize = {CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
-cvar_t r_bufferdatasize[R_BUFFERDATA_COUNT] =
+cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
 {
-       {CVAR_SAVE, "r_bufferdatasize_vertex", "4", "vertex buffer size for one frame"},
-       {CVAR_SAVE, "r_bufferdatasize_index16", "1", "index buffer size for one frame (16bit indices)"},
-       {CVAR_SAVE, "r_bufferdatasize_index32", "1", "index buffer size for one frame (32bit indices)"},
-       {CVAR_SAVE, "r_bufferdatasize_uniform", "0.25", "uniform buffer size for one frame"},
+       {CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
+       {CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
+       {CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
+       {CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
 };
 
 extern cvar_t v_glslgamma;
@@ -625,9 +647,6 @@ const char *builtinhlslshaderstrings[] =
 0
 };
 
-char *glslshaderstring = NULL;
-char *hlslshaderstring = NULL;
-
 //=======================================================================================================================================================
 
 typedef struct shaderpermutationinfo_s
@@ -639,9 +658,14 @@ shaderpermutationinfo_t;
 
 typedef struct shadermodeinfo_s
 {
-       const char *filename;
+       const char *sourcebasename;
+       const char *extension;
+       const char **builtinshaderstrings;
        const char *pretext;
        const char *name;
+       char *filename;
+       char *builtinstring;
+       int builtincrc;
 }
 shadermodeinfo_t;
 
@@ -678,50 +702,53 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
        {"#define USETRIPPY\n", " trippy"},
        {"#define USEDEPTHRGB\n", " depthrgb"},
        {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
-       {"#define USESKELETAL\n", " skeletal"}
+       {"#define USESKELETAL\n", " skeletal"},
+       {"#define USEOCCLUDE\n", " occlude"}
 };
 
 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
-shadermodeinfo_t glslshadermodeinfo[SHADERMODE_COUNT] =
-{
-       {"glsl/default.glsl", "#define MODE_GENERIC\n", " generic"},
-       {"glsl/default.glsl", "#define MODE_POSTPROCESS\n", " postprocess"},
-       {"glsl/default.glsl", "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
-       {"glsl/default.glsl", "#define MODE_FLATCOLOR\n", " flatcolor"},
-       {"glsl/default.glsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
-       {"glsl/default.glsl", "#define MODE_LIGHTMAP\n", " lightmap"},
-       {"glsl/default.glsl", "#define MODE_FAKELIGHT\n", " fakelight"},
-       {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
-       {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
-       {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
-       {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
-       {"glsl/default.glsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
-       {"glsl/default.glsl", "#define MODE_LIGHTSOURCE\n", " lightsource"},
-       {"glsl/default.glsl", "#define MODE_REFRACTION\n", " refraction"},
-       {"glsl/default.glsl", "#define MODE_WATER\n", " water"},
-       {"glsl/default.glsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
-       {"glsl/default.glsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
-};
-
-shadermodeinfo_t hlslshadermodeinfo[SHADERMODE_COUNT] =
-{
-       {"hlsl/default.hlsl", "#define MODE_GENERIC\n", " generic"},
-       {"hlsl/default.hlsl", "#define MODE_POSTPROCESS\n", " postprocess"},
-       {"hlsl/default.hlsl", "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
-       {"hlsl/default.hlsl", "#define MODE_FLATCOLOR\n", " flatcolor"},
-       {"hlsl/default.hlsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
-       {"hlsl/default.hlsl", "#define MODE_LIGHTMAP\n", " lightmap"},
-       {"hlsl/default.hlsl", "#define MODE_FAKELIGHT\n", " fakelight"},
-       {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
-       {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
-       {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
-       {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
-       {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
-       {"hlsl/default.hlsl", "#define MODE_LIGHTSOURCE\n", " lightsource"},
-       {"hlsl/default.hlsl", "#define MODE_REFRACTION\n", " refraction"},
-       {"hlsl/default.hlsl", "#define MODE_WATER\n", " water"},
-       {"hlsl/default.hlsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
-       {"hlsl/default.hlsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
+shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
+{
+       // SHADERLANGUAGE_GLSL
+       {
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_FAKELIGHT\n", " fakelight"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
+               {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
+       },
+       // SHADERLANGUAGE_HLSL
+       {
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_GENERIC\n", " generic"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_FAKELIGHT\n", " fakelight"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_WATER\n", " water"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
+               {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
+       },
 };
 
 struct r_glsl_permutation_s;
@@ -730,7 +757,7 @@ typedef struct r_glsl_permutation_s
        /// hash lookup data
        struct r_glsl_permutation_s *hashnext;
        unsigned int mode;
-       unsigned int permutation;
+       dpuint64 permutation;
 
        /// indicates if we have tried compiling this permutation already
        qboolean compiled;
@@ -881,8 +908,9 @@ enum
        SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
        SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
        SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
+       SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
 };
-#define SHADERSTATICPARMS_COUNT 13
+#define SHADERSTATICPARMS_COUNT 14
 
 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
 static int shaderstaticparms_count = 0;
@@ -894,7 +922,7 @@ extern qboolean r_shadow_shadowmapsampler;
 extern int r_shadow_shadowmappcf;
 qboolean R_CompileShader_CheckStaticParms(void)
 {
-       static int r_compileshader_staticparms_save[1];
+       static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
        memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
        memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
 
@@ -916,6 +944,8 @@ qboolean R_CompileShader_CheckStaticParms(void)
                if (r_glsl_postprocess_uservec4_enable.integer)
                        R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
        }
+       if (r_fxaa.integer)
+               R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
        if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
                R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
 
@@ -938,7 +968,7 @@ qboolean R_CompileShader_CheckStaticParms(void)
                shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
        else \
                shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
-static void R_CompileShader_AddStaticParms(unsigned int mode, unsigned int permutation)
+static void R_CompileShader_AddStaticParms(unsigned int mode, dpuint64 permutation)
 {
        shaderstaticparms_count = 0;
 
@@ -956,6 +986,7 @@ static void R_CompileShader_AddStaticParms(unsigned int mode, unsigned int permu
        R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
        R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
        R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
+       R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
 }
 
 /// information about each possible shader permutation
@@ -965,7 +996,7 @@ r_glsl_permutation_t *r_glsl_permutation;
 /// storage for permutations linked in the hash table
 memexpandablearray_t r_glsl_permutationarray;
 
-static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, unsigned int permutation)
+static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, dpuint64 permutation)
 {
        //unsigned int hashdepth = 0;
        unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
@@ -1011,63 +1042,50 @@ static char *R_ShaderStrCat(const char **strings)
        return string;
 }
 
-static char *R_GetShaderText(const char *filename, qboolean printfromdisknotice, qboolean builtinonly)
+static char *R_ShaderStrCat(const char **strings);
+static void R_InitShaderModeInfo(void)
 {
-       char *shaderstring;
-       if (!filename || !filename[0])
-               return NULL;
-       // LordHavoc: note that FS_LoadFile appends a 0 byte to make it a valid string, so does R_ShaderStrCat
-       if (!strcmp(filename, "glsl/default.glsl"))
-       {
-               if (builtinonly)
-                       return R_ShaderStrCat(builtinshaderstrings);
-               if (!glslshaderstring)
-               {
-                       glslshaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
-                       if (glslshaderstring)
-                               Con_DPrintf("Loading shaders from file %s...\n", filename);
-                       else
-                               glslshaderstring = R_ShaderStrCat(builtinshaderstrings);
-               }
-               shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(glslshaderstring) + 1);
-               memcpy(shaderstring, glslshaderstring, strlen(glslshaderstring) + 1);
-               return shaderstring;
-       }
-       if (!strcmp(filename, "hlsl/default.hlsl"))
+       int i, language;
+       shadermodeinfo_t *modeinfo;
+       // we have a bunch of things to compute that weren't calculated at engine compile time - all filenames should have a crc of the builtin strings to prevent accidental overrides (any customization must be updated to match engine)
+       for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
        {
-               if (builtinonly)
-                       return R_ShaderStrCat(builtinhlslshaderstrings);
-               if (!hlslshaderstring)
+               for (i = 0; i < SHADERMODE_COUNT; i++)
                {
-                       hlslshaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
-                       if (hlslshaderstring)
-                               Con_DPrintf("Loading shaders from file %s...\n", filename);
-                       else
-                               hlslshaderstring = R_ShaderStrCat(builtinhlslshaderstrings);
+                       char filename[MAX_QPATH];
+                       modeinfo = &shadermodeinfo[language][i];
+                       modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
+                       modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
+                       dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
+                       modeinfo->filename = Mem_strdup(r_main_mempool, filename);
                }
-               shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(hlslshaderstring) + 1);
-               memcpy(shaderstring, hlslshaderstring, strlen(hlslshaderstring) + 1);
-               return shaderstring;
        }
-       // we don't have builtin strings for any other files
-       if (builtinonly)
-               return NULL;
-       shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
+}
+
+static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
+{
+       char *shaderstring;
+       // if the mode has no filename we have to return the builtin string
+       if (builtinonly || !modeinfo->filename)
+               return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
+       // note that FS_LoadFile appends a 0 byte to make it a valid string
+       shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
        if (shaderstring)
        {
                if (printfromdisknotice)
-                       Con_DPrintf("from disk %s... ", filename);
+                       Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
                return shaderstring;
        }
-       return shaderstring;
+       // fall back to builtinstring
+       return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
 }
 
-static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, unsigned int permutation)
+static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, dpuint64 permutation)
 {
        int i;
        int ubibind;
        int sampler;
-       shadermodeinfo_t *modeinfo = glslshadermodeinfo + mode;
+       shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
        char *sourcestring;
        char permutationname[256];
        int vertstrings_count = 0;
@@ -1083,7 +1101,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
        p->program = 0;
 
        permutationname[0] = 0;
-       sourcestring  = R_GetShaderText(modeinfo->filename, true, false);
+       sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
 
        strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
 
@@ -1107,6 +1125,27 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
                fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
        }
+       // if we can do #version 120, we should (this adds the invariant keyword)
+       else if(vid.support.glshaderversion >= 120)
+       {
+               vertstrings_list[vertstrings_count++] = "#version 120\n";
+               geomstrings_list[geomstrings_count++] = "#version 120\n";
+               fragstrings_list[fragstrings_count++] = "#version 120\n";
+               vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
+               geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
+               fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
+       }
+       // GLES also adds several things from GLSL120
+       switch(vid.renderpath)
+       {
+       case RENDERPATH_GLES2:
+               vertstrings_list[vertstrings_count++] = "#define GLES\n";
+               geomstrings_list[geomstrings_count++] = "#define GLES\n";
+               fragstrings_list[fragstrings_count++] = "#define GLES\n";
+               break;
+       default:
+               break;
+       }
 
        // the first pretext is which type of shader to compile as
        // (later these will all be bound together as a program object)
@@ -1123,7 +1162,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
        // now add all the permutation pretexts
        for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
        {
-               if (permutation & (1<<i))
+               if (permutation & (1ll<<i))
                {
                        vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
                        geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
@@ -1163,6 +1202,26 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                // look up all the uniform variable names we care about, so we don't
                // have to look them up every time we set them
 
+#if 0
+               // debugging aid
+               {
+                       GLint activeuniformindex = 0;
+                       GLint numactiveuniforms = 0;
+                       char uniformname[128];
+                       GLsizei uniformnamelength = 0;
+                       GLint uniformsize = 0;
+                       GLenum uniformtype = 0;
+                       memset(uniformname, 0, sizeof(uniformname));
+                       qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
+                       Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
+                       for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
+                       {
+                               qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
+                               Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
+                       }
+               }
+#endif
+
                p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
                p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
                p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
@@ -1311,15 +1370,19 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
                if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
                // get the uniform block indices so we can bind them
+#ifndef USE_GLES2 /* FIXME: GLES3 only */
                if (vid.support.arb_uniform_buffer_object)
                        p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
                else
+#endif
                        p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
                // clear the uniform block bindings
                p->ubibind_Skeletal_Transform12_UniformBlock = -1;
                // bind the uniform blocks in use
                ubibind = 0;
+#ifndef USE_GLES2 /* FIXME: GLES3 only */
                if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
+#endif
                // we're done compiling and setting up the shader, at least until it is used
                CHECKGLERROR
                Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
@@ -1332,7 +1395,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                Mem_Free(sourcestring);
 }
 
-static void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int permutation)
+static void R_SetupShader_SetPermutationGLSL(unsigned int mode, dpuint64 permutation)
 {
        r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
        if (r_glsl_permutation != perm)
@@ -1341,7 +1404,10 @@ static void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int per
                if (!r_glsl_permutation->program)
                {
                        if (!r_glsl_permutation->compiled)
+                       {
+                               Con_DPrintf("Compiling shader mode %u permutation %u\n", mode, permutation);
                                R_GLSL_CompilePermutation(perm, mode, permutation);
+                       }
                        if (!r_glsl_permutation->program)
                        {
                                // remove features until we find a valid permutation
@@ -1349,7 +1415,7 @@ static void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int per
                                for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
                                {
                                        // reduce i more quickly whenever it would not remove any bits
-                                       int j = 1<<(SHADERPERMUTATION_COUNT-1-i);
+                                       dpuint64 j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
                                        if (!(permutation & j))
                                                continue;
                                        permutation -= j;
@@ -1374,6 +1440,7 @@ static void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int per
        if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
        if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
        if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
+       CHECKGLERROR
 }
 
 #ifdef SUPPORTD3D
@@ -1390,7 +1457,7 @@ typedef struct r_hlsl_permutation_s
        /// hash lookup data
        struct r_hlsl_permutation_s *hashnext;
        unsigned int mode;
-       unsigned int permutation;
+       dpuint64 permutation;
 
        /// indicates if we have tried compiling this permutation already
        qboolean compiled;
@@ -1477,7 +1544,7 @@ r_hlsl_permutation_t *r_hlsl_permutation;
 /// storage for permutations linked in the hash table
 memexpandablearray_t r_hlsl_permutationarray;
 
-static r_hlsl_permutation_t *R_HLSL_FindPermutation(unsigned int mode, unsigned int permutation)
+static r_hlsl_permutation_t *R_HLSL_FindPermutation(unsigned int mode, dpuint64 permutation)
 {
        //unsigned int hashdepth = 0;
        unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
@@ -1597,7 +1664,7 @@ static void R_HLSL_CacheShader(r_hlsl_permutation_t *p, const char *cachename, c
                                        vsresult = qD3DXCompileShaderFromFileA(va(vabuf, sizeof(vabuf), "%s/%s_vs.fx", fs_gamedir, cachename), NULL, NULL, "main", vsversion, shaderflags, &vsbuffer, &vslog, &vsconstanttable);
                                }
                                else
-                                       vsresult = qD3DXCompileShader(vertstring, strlen(vertstring), NULL, NULL, "main", vsversion, shaderflags, &vsbuffer, &vslog, &vsconstanttable);
+                                       vsresult = qD3DXCompileShader(vertstring, (unsigned int)strlen(vertstring), NULL, NULL, "main", vsversion, shaderflags, &vsbuffer, &vslog, &vsconstanttable);
                                if (vsbuffer)
                                {
                                        vsbinsize = ID3DXBuffer_GetBufferSize(vsbuffer);
@@ -1620,7 +1687,7 @@ static void R_HLSL_CacheShader(r_hlsl_permutation_t *p, const char *cachename, c
                                        psresult = qD3DXCompileShaderFromFileA(va(vabuf, sizeof(vabuf), "%s/%s_ps.fx", fs_gamedir, cachename), NULL, NULL, "main", psversion, shaderflags, &psbuffer, &pslog, &psconstanttable);
                                }
                                else
-                                       psresult = qD3DXCompileShader(fragstring, strlen(fragstring), NULL, NULL, "main", psversion, shaderflags, &psbuffer, &pslog, &psconstanttable);
+                                       psresult = qD3DXCompileShader(fragstring, (unsigned int)strlen(fragstring), NULL, NULL, "main", psversion, shaderflags, &psbuffer, &pslog, &psconstanttable);
                                if (psbuffer)
                                {
                                        psbinsize = ID3DXBuffer_GetBufferSize(psbuffer);
@@ -1654,10 +1721,10 @@ static void R_HLSL_CacheShader(r_hlsl_permutation_t *p, const char *cachename, c
        psbin = (DWORD *)Mem_Realloc(tempmempool, psbin, 0);
 }
 
-static void R_HLSL_CompilePermutation(r_hlsl_permutation_t *p, unsigned int mode, unsigned int permutation)
+static void R_HLSL_CompilePermutation(r_hlsl_permutation_t *p, unsigned int mode, dpuint64 permutation)
 {
        int i;
-       shadermodeinfo_t *modeinfo = hlslshadermodeinfo + mode;
+       shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_HLSL][mode];
        int vertstring_length = 0;
        int geomstring_length = 0;
        int fragstring_length = 0;
@@ -1681,7 +1748,7 @@ static void R_HLSL_CompilePermutation(r_hlsl_permutation_t *p, unsigned int mode
 
        permutationname[0] = 0;
        cachename[0] = 0;
-       sourcestring = R_GetShaderText(modeinfo->filename, true, false);
+       sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
 
        strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
        strlcat(cachename, "hlsl/", sizeof(cachename));
@@ -1710,7 +1777,7 @@ static void R_HLSL_CompilePermutation(r_hlsl_permutation_t *p, unsigned int mode
        // now add all the permutation pretexts
        for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
        {
-               if (permutation & (1<<i))
+               if (permutation & (1ll<<i))
                {
                        vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
                        geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
@@ -1748,23 +1815,23 @@ static void R_HLSL_CompilePermutation(r_hlsl_permutation_t *p, unsigned int mode
 
        vertstring_length = 0;
        for (i = 0;i < vertstrings_count;i++)
-               vertstring_length += strlen(vertstrings_list[i]);
+               vertstring_length += (int)strlen(vertstrings_list[i]);
        vertstring = t = (char *)Mem_Alloc(tempmempool, vertstring_length + 1);
-       for (i = 0;i < vertstrings_count;t += strlen(vertstrings_list[i]), i++)
+       for (i = 0;i < vertstrings_count;t += (int)strlen(vertstrings_list[i]), i++)
                memcpy(t, vertstrings_list[i], strlen(vertstrings_list[i]));
 
        geomstring_length = 0;
        for (i = 0;i < geomstrings_count;i++)
-               geomstring_length += strlen(geomstrings_list[i]);
+               geomstring_length += (int)strlen(geomstrings_list[i]);
        geomstring = t = (char *)Mem_Alloc(tempmempool, geomstring_length + 1);
-       for (i = 0;i < geomstrings_count;t += strlen(geomstrings_list[i]), i++)
+       for (i = 0;i < geomstrings_count;t += (int)strlen(geomstrings_list[i]), i++)
                memcpy(t, geomstrings_list[i], strlen(geomstrings_list[i]));
 
        fragstring_length = 0;
        for (i = 0;i < fragstrings_count;i++)
-               fragstring_length += strlen(fragstrings_list[i]);
+               fragstring_length += (int)strlen(fragstrings_list[i]);
        fragstring = t = (char *)Mem_Alloc(tempmempool, fragstring_length + 1);
-       for (i = 0;i < fragstrings_count;t += strlen(fragstrings_list[i]), i++)
+       for (i = 0;i < fragstrings_count;t += (int)strlen(fragstrings_list[i]), i++)
                memcpy(t, fragstrings_list[i], strlen(fragstrings_list[i]));
 
        // try to load the cached shader, or generate one
@@ -1800,7 +1867,7 @@ static inline void hlslPSSetParameter3f(D3DPSREGISTER_t r, float x, float y, flo
 static inline void hlslPSSetParameter2f(D3DPSREGISTER_t r, float x, float y) {float temp[4];Vector4Set(temp, x, y, 0, 0);IDirect3DDevice9_SetPixelShaderConstantF(vid_d3d9dev, r, temp, 1);}
 static inline void hlslPSSetParameter1f(D3DPSREGISTER_t r, float x) {float temp[4];Vector4Set(temp, x, 0, 0, 0);IDirect3DDevice9_SetPixelShaderConstantF(vid_d3d9dev, r, temp, 1);}
 
-void R_SetupShader_SetPermutationHLSL(unsigned int mode, unsigned int permutation)
+void R_SetupShader_SetPermutationHLSL(unsigned int mode, dpuint64 permutation)
 {
        r_hlsl_permutation_t *perm = R_HLSL_FindPermutation(mode, permutation);
        if (r_hlsl_permutation != perm)
@@ -1817,7 +1884,7 @@ void R_SetupShader_SetPermutationHLSL(unsigned int mode, unsigned int permutatio
                                for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
                                {
                                        // reduce i more quickly whenever it would not remove any bits
-                                       int j = 1<<(SHADERPERMUTATION_COUNT-1-i);
+                                       dpuint64 j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
                                        if (!(permutation & j))
                                                continue;
                                        permutation -= j;
@@ -1844,7 +1911,7 @@ void R_SetupShader_SetPermutationHLSL(unsigned int mode, unsigned int permutatio
 }
 #endif
 
-static void R_SetupShader_SetPermutationSoft(unsigned int mode, unsigned int permutation)
+static void R_SetupShader_SetPermutationSoft(unsigned int mode, dpuint64 permutation)
 {
        DPSOFTRAST_SetShader(mode, permutation, r_shadow_glossexact.integer);
        DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1, 1, false, gl_modelviewprojection16f);
@@ -1855,12 +1922,6 @@ static void R_SetupShader_SetPermutationSoft(unsigned int mode, unsigned int per
 void R_GLSL_Restart_f(void)
 {
        unsigned int i, limit;
-       if (glslshaderstring)
-               Mem_Free(glslshaderstring);
-       glslshaderstring = NULL;
-       if (hlslshaderstring)
-               Mem_Free(hlslshaderstring);
-       hlslshaderstring = NULL;
        switch(vid.renderpath)
        {
        case RENDERPATH_D3D9:
@@ -1868,7 +1929,7 @@ void R_GLSL_Restart_f(void)
                {
                        r_hlsl_permutation_t *p;
                        r_hlsl_permutation = NULL;
-                       limit = Mem_ExpandableArray_IndexRange(&r_hlsl_permutationarray);
+                       limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_hlsl_permutationarray);
                        for (i = 0;i < limit;i++)
                        {
                                if ((p = (r_hlsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_hlsl_permutationarray, i)))
@@ -1895,7 +1956,7 @@ void R_GLSL_Restart_f(void)
                {
                        r_glsl_permutation_t *p;
                        r_glsl_permutation = NULL;
-                       limit = Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
+                       limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
                        for (i = 0;i < limit;i++)
                        {
                                if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
@@ -1923,9 +1984,9 @@ static void R_GLSL_DumpShader_f(void)
        shadermodeinfo_t *modeinfo;
        qfile_t *file;
 
-       for (language = 0;language < 2;language++)
+       for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
        {
-               modeinfo = (language == 0 ? glslshadermodeinfo : hlslshadermodeinfo);
+               modeinfo = shadermodeinfo[language];
                for (mode = 0;mode < SHADERMODE_COUNT;mode++)
                {
                        // don't dump the same file multiple times (most or all shaders come from the same file)
@@ -1934,7 +1995,7 @@ static void R_GLSL_DumpShader_f(void)
                                        break;
                        if (dupe >= 0)
                                continue;
-                       text = R_GetShaderText(modeinfo[mode].filename, false, true);
+                       text = modeinfo[mode].builtinstring;
                        if (!text)
                                continue;
                        file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
@@ -1953,14 +2014,13 @@ static void R_GLSL_DumpShader_f(void)
                        }
                        else
                                Con_Printf("failed to write to %s\n", modeinfo[mode].filename);
-                       Mem_Free(text);
                }
        }
 }
 
 void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
 {
-       unsigned int permutation = 0;
+       dpuint64 permutation = 0;
        if (r_trippy.integer && !notrippy)
                permutation |= SHADERPERMUTATION_TRIPPY;
        permutation |= SHADERPERMUTATION_VIEWTINT;
@@ -2041,7 +2101,7 @@ void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
 
 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
 {
-       unsigned int permutation = 0;
+       dpuint64 permutation = 0;
        if (r_trippy.integer && !notrippy)
                permutation |= SHADERPERMUTATION_TRIPPY;
        if (depthrgb)
@@ -2067,7 +2127,9 @@ void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean
        case RENDERPATH_GL20:
        case RENDERPATH_GLES2:
                R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
+#ifndef USE_GLES2 /* FIXME: GLES3 only */
                if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
+#endif
                break;
        case RENDERPATH_GL13:
        case RENDERPATH_GLES1:
@@ -2089,14 +2151,15 @@ extern rtexture_t *r_shadow_attenuation2dtexture;
 extern rtexture_t *r_shadow_attenuation3dtexture;
 extern qboolean r_shadow_usingshadowmap2d;
 extern qboolean r_shadow_usingshadowmaportho;
-extern float r_shadow_shadowmap_texturescale[2];
-extern float r_shadow_shadowmap_parameters[4];
+extern float r_shadow_modelshadowmap_texturescale[4];
+extern float r_shadow_modelshadowmap_parameters[4];
+extern float r_shadow_lightshadowmap_texturescale[4];
+extern float r_shadow_lightshadowmap_parameters[4];
 extern qboolean r_shadow_shadowmapvsdct;
 extern rtexture_t *r_shadow_shadowmap2ddepthbuffer;
 extern rtexture_t *r_shadow_shadowmap2ddepthtexture;
 extern rtexture_t *r_shadow_shadowmapvsdcttexture;
 extern matrix4x4_t r_shadow_shadowmapmatrix;
-extern int r_shadow_shadowmaplod; // changes for each light based on distance
 extern int r_shadow_prepass_width;
 extern int r_shadow_prepass_height;
 extern rtexture_t *r_shadow_prepassgeometrydepthbuffer;
@@ -2150,35 +2213,36 @@ static int R_BlendFuncFlags(int src, int dst)
        return r;
 }
 
-void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy)
+void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy)
 {
        // select a permutation of the lighting shader appropriate to this
        // combination of texture, entity, light source, and fogging, only use the
        // minimum features necessary to avoid wasting rendering time in the
        // fragment shader on features that are not being used
-       unsigned int permutation = 0;
+       dpuint64 permutation = 0;
        unsigned int mode = 0;
        int blendfuncflags;
-       static float dummy_colormod[3] = {1, 1, 1};
-       float *colormod = rsurface.colormod;
+       texture_t *t = rsurface.texture;
        float m16f[16];
        matrix4x4_t tempmatrix;
        r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
        if (r_trippy.integer && !notrippy)
                permutation |= SHADERPERMUTATION_TRIPPY;
-       if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
+       if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
                permutation |= SHADERPERMUTATION_ALPHAKILL;
-       if (rsurface.texture->r_water_waterscroll[0] && rsurface.texture->r_water_waterscroll[1])
+       if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
+               permutation |= SHADERPERMUTATION_OCCLUDE;
+       if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
                permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
        if (rsurfacepass == RSURFPASS_BACKGROUND)
        {
                // distorted background
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
+               if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
                {
                        mode = SHADERMODE_WATER;
-                       if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
+                       if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
                                permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
-                       if((r_wateralpha.value < 1) && (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERALPHA))
+                       if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
                        {
                                // this is the right thing to do for wateralpha
                                GL_BlendFunc(GL_ONE, GL_ZERO);
@@ -2191,10 +2255,10 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                        }
                }
-               else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFRACTION)
+               else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
                {
                        mode = SHADERMODE_REFRACTION;
-                       if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
+                       if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
                                permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
                        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                        blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -2211,9 +2275,9 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        }
        else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
        {
-               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f))
+               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
                {
-                       switch(rsurface.texture->offsetmapping)
+                       switch(t->offsetmapping)
                        {
                        case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
                        case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
@@ -2221,7 +2285,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        case OFFSETMAPPING_OFF: break;
                        }
                }
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
+               if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
                // normalmap (deferred prepass), may use alpha test on diffuse
                mode = SHADERMODE_DEFERREDGEOMETRY;
@@ -2232,9 +2296,9 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        }
        else if (rsurfacepass == RSURFPASS_RTLIGHT)
        {
-               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f))
+               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
                {
-                       switch(rsurface.texture->offsetmapping)
+                       switch(t->offsetmapping)
                        {
                        case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
                        case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
@@ -2242,21 +2306,21 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        case OFFSETMAPPING_OFF: break;
                        }
                }
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
+               if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
+               if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
                        permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
                // light source
                mode = SHADERMODE_LIGHTSOURCE;
                if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
                        permutation |= SHADERPERMUTATION_CUBEFILTER;
-               if (diffusescale > 0)
+               if (VectorLength2(rtlightdiffuse) > 0)
                        permutation |= SHADERPERMUTATION_DIFFUSE;
-               if (specularscale > 0)
+               if (VectorLength2(rtlightspecular) > 0)
                        permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
                if (r_refdef.fogenabled)
                        permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
-               if (rsurface.texture->colormapping)
+               if (t->colormapping)
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
                if (r_shadow_usingshadowmap2d)
                {
@@ -2267,69 +2331,18 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        if (r_shadow_shadowmap2ddepthbuffer)
                                permutation |= SHADERPERMUTATION_DEPTHRGB;
                }
-               if (rsurface.texture->reflectmasktexture)
+               if (t->reflectmasktexture)
                        permutation |= SHADERPERMUTATION_REFLECTCUBE;
                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
                blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
                if (vid.allowalphatocoverage)
                        GL_AlphaToCoverage(false);
        }
-       else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
-       {
-               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f))
-               {
-                       switch(rsurface.texture->offsetmapping)
-                       {
-                       case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
-                       case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
-                       case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
-                       case OFFSETMAPPING_OFF: break;
-                       }
-               }
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
-                       permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
-                       permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
-               // unshaded geometry (fullbright or ambient model lighting)
-               mode = SHADERMODE_FLATCOLOR;
-               ambientscale = diffusescale = specularscale = 0;
-               if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
-                       permutation |= SHADERPERMUTATION_GLOW;
-               if (r_refdef.fogenabled)
-                       permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
-               if (rsurface.texture->colormapping)
-                       permutation |= SHADERPERMUTATION_COLORMAPPING;
-               if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
-               {
-                       permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
-                       permutation |= SHADERPERMUTATION_SHADOWMAP2D;
-
-                       if (r_shadow_shadowmap2ddepthbuffer)
-                               permutation |= SHADERPERMUTATION_DEPTHRGB;
-               }
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
-                       permutation |= SHADERPERMUTATION_REFLECTION;
-               if (rsurface.texture->reflectmasktexture)
-                       permutation |= SHADERPERMUTATION_REFLECTCUBE;
-               GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
-               blendfuncflags = R_BlendFuncFlags(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
-               // when using alphatocoverage, we don't need alphakill
-               if (vid.allowalphatocoverage)
-               {
-                       if (r_transparent_alphatocoverage.integer)
-                       {
-                               GL_AlphaToCoverage((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
-                               permutation &= ~SHADERPERMUTATION_ALPHAKILL;
-                       }
-                       else
-                               GL_AlphaToCoverage(false);
-               }
-       }
-       else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT_DIRECTIONAL)
+       else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
        {
-               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f))
+               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
                {
-                       switch(rsurface.texture->offsetmapping)
+                       switch(t->offsetmapping)
                        {
                        case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
                        case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
@@ -2337,78 +2350,21 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        case OFFSETMAPPING_OFF: break;
                        }
                }
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
+               if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
+               if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
                        permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
                // directional model lighting
                mode = SHADERMODE_LIGHTDIRECTION;
-               if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
+               if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
                        permutation |= SHADERPERMUTATION_GLOW;
-               permutation |= SHADERPERMUTATION_DIFFUSE;
-               if (specularscale > 0)
+               if (VectorLength2(t->render_modellight_diffuse))
+                       permutation |= SHADERPERMUTATION_DIFFUSE;
+               if (VectorLength2(t->render_modellight_specular) > 0)
                        permutation |= SHADERPERMUTATION_SPECULAR;
                if (r_refdef.fogenabled)
                        permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
-               if (rsurface.texture->colormapping)
-                       permutation |= SHADERPERMUTATION_COLORMAPPING;
-               if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
-               {
-                       permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
-                       permutation |= SHADERPERMUTATION_SHADOWMAP2D;
-
-                       if (r_shadow_shadowmap2ddepthbuffer)
-                               permutation |= SHADERPERMUTATION_DEPTHRGB;
-               }
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
-                       permutation |= SHADERPERMUTATION_REFLECTION;
-               if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
-                       permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
-               if (rsurface.texture->reflectmasktexture)
-                       permutation |= SHADERPERMUTATION_REFLECTCUBE;
-               if (r_shadow_bouncegridtexture && cl.csqc_vidvars.drawworld)
-               {
-                       permutation |= SHADERPERMUTATION_BOUNCEGRID;
-                       if (r_shadow_bouncegriddirectional)
-                               permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
-               }
-               GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
-               blendfuncflags = R_BlendFuncFlags(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
-               // when using alphatocoverage, we don't need alphakill
-               if (vid.allowalphatocoverage)
-               {
-                       if (r_transparent_alphatocoverage.integer)
-                       {
-                               GL_AlphaToCoverage((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
-                               permutation &= ~SHADERPERMUTATION_ALPHAKILL;
-                       }
-                       else
-                               GL_AlphaToCoverage(false);
-               }
-       }
-       else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
-       {
-               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f))
-               {
-                       switch(rsurface.texture->offsetmapping)
-                       {
-                       case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
-                       case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
-                       case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
-                       case OFFSETMAPPING_OFF: break;
-                       }
-               }
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
-                       permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
-                       permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
-               // ambient model lighting
-               mode = SHADERMODE_LIGHTDIRECTION;
-               if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
-                       permutation |= SHADERPERMUTATION_GLOW;
-               if (r_refdef.fogenabled)
-                       permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
-               if (rsurface.texture->colormapping)
+               if (t->colormapping)
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
                if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
                {
@@ -2418,26 +2374,26 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        if (r_shadow_shadowmap2ddepthbuffer)
                                permutation |= SHADERPERMUTATION_DEPTHRGB;
                }
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
+               if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
-               if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
+               if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
                        permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
-               if (rsurface.texture->reflectmasktexture)
+               if (t->reflectmasktexture)
                        permutation |= SHADERPERMUTATION_REFLECTCUBE;
-               if (r_shadow_bouncegridtexture && cl.csqc_vidvars.drawworld)
+               if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
                {
                        permutation |= SHADERPERMUTATION_BOUNCEGRID;
-                       if (r_shadow_bouncegriddirectional)
+                       if (r_shadow_bouncegrid_state.directional)
                                permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
                }
-               GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
-               blendfuncflags = R_BlendFuncFlags(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
+               GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
+               blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
                // when using alphatocoverage, we don't need alphakill
                if (vid.allowalphatocoverage)
                {
                        if (r_transparent_alphatocoverage.integer)
                        {
-                               GL_AlphaToCoverage((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
+                               GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
                                permutation &= ~SHADERPERMUTATION_ALPHAKILL;
                        }
                        else
@@ -2446,9 +2402,9 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        }
        else
        {
-               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f))
+               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
                {
-                       switch(rsurface.texture->offsetmapping)
+                       switch(t->offsetmapping)
                        {
                        case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
                        case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
@@ -2456,16 +2412,16 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        case OFFSETMAPPING_OFF: break;
                        }
                }
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
+               if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
+               if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
                        permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
                // lightmapped wall
-               if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
+               if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
                        permutation |= SHADERPERMUTATION_GLOW;
                if (r_refdef.fogenabled)
                        permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
-               if (rsurface.texture->colormapping)
+               if (t->colormapping)
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
                if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
                {
@@ -2475,18 +2431,18 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        if (r_shadow_shadowmap2ddepthbuffer)
                                permutation |= SHADERPERMUTATION_DEPTHRGB;
                }
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
+               if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
-               if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
+               if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
                        permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
-               if (rsurface.texture->reflectmasktexture)
+               if (t->reflectmasktexture)
                        permutation |= SHADERPERMUTATION_REFLECTCUBE;
                if (FAKELIGHT_ENABLED)
                {
                        // fake lightmapping (q1bsp, q3bsp, fullbright map)
                        mode = SHADERMODE_FAKELIGHT;
                        permutation |= SHADERPERMUTATION_DIFFUSE;
-                       if (specularscale > 0)
+                       if (VectorLength2(t->render_lightmap_specular) > 0)
                                permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
                }
                else if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
@@ -2497,7 +2453,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        else
                                mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
                        permutation |= SHADERPERMUTATION_DIFFUSE;
-                       if (specularscale > 0)
+                       if (VectorLength2(t->render_lightmap_specular) > 0)
                                permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
                }
                else if (r_glsl_deluxemapping.integer >= 2)
@@ -2508,7 +2464,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        else
                                mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
                        permutation |= SHADERPERMUTATION_DIFFUSE;
-                       if (specularscale > 0)
+                       if (VectorLength2(t->render_lightmap_specular) > 0)
                                permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
                }
                else if (rsurface.uselightmaptexture)
@@ -2521,28 +2477,26 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        // ordinary vertex coloring (q3bsp)
                        mode = SHADERMODE_VERTEXCOLOR;
                }
-               if (r_shadow_bouncegridtexture && cl.csqc_vidvars.drawworld)
+               if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
                {
                        permutation |= SHADERPERMUTATION_BOUNCEGRID;
-                       if (r_shadow_bouncegriddirectional)
+                       if (r_shadow_bouncegrid_state.directional)
                                permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
                }
-               GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
-               blendfuncflags = R_BlendFuncFlags(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
+               GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
+               blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
                // when using alphatocoverage, we don't need alphakill
                if (vid.allowalphatocoverage)
                {
                        if (r_transparent_alphatocoverage.integer)
                        {
-                               GL_AlphaToCoverage((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
+                               GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
                                permutation &= ~SHADERPERMUTATION_ALPHAKILL;
                        }
                        else
                                GL_AlphaToCoverage(false);
                }
        }
-       if(!(blendfuncflags & BLENDFUNC_ALLOWS_COLORMOD))
-               colormod = dummy_colormod;
        if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
                permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
        if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA)
@@ -2564,11 +2518,11 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                {
                        if (mode == SHADERMODE_LIGHTDIRECTION)
                        {
-                               hlslVSSetParameter3f(D3DVSREGISTER_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
+                               hlslVSSetParameter3f(D3DVSREGISTER_LightDir, t->render_modellight_lightdir[0], t->render_modellight_lightdir[1], t->render_modellight_lightdir[2]);
                        }
                }
-               Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);hlslVSSetParameter16f(D3DVSREGISTER_TexMatrix, m16f);
-               Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);hlslVSSetParameter16f(D3DVSREGISTER_BackgroundTexMatrix, m16f);
+               Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);hlslVSSetParameter16f(D3DVSREGISTER_TexMatrix, m16f);
+               Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);hlslVSSetParameter16f(D3DVSREGISTER_BackgroundTexMatrix, m16f);
                Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);hlslVSSetParameter16f(D3DVSREGISTER_ShadowMapMatrix, m16f);
                hlslVSSetParameter3f(D3DVSREGISTER_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
                hlslVSSetParameter4f(D3DVSREGISTER_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
@@ -2576,66 +2530,72 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                if (mode == SHADERMODE_LIGHTSOURCE)
                {
                        hlslPSSetParameter3f(D3DPSREGISTER_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
-                       hlslPSSetParameter3f(D3DPSREGISTER_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);
-                       hlslPSSetParameter3f(D3DPSREGISTER_Color_Ambient, colormod[0] * ambientscale, colormod[1] * ambientscale, colormod[2] * ambientscale);
-                       hlslPSSetParameter3f(D3DPSREGISTER_Color_Diffuse, colormod[0] * diffusescale, colormod[1] * diffusescale, colormod[2] * diffusescale);
-                       hlslPSSetParameter3f(D3DPSREGISTER_Color_Specular, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale);
+                       hlslPSSetParameter3f(D3DPSREGISTER_LightColor, 1, 1, 1); // DEPRECATED
+                       hlslPSSetParameter3f(D3DPSREGISTER_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
+                       hlslPSSetParameter3f(D3DPSREGISTER_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
+                       hlslPSSetParameter3f(D3DPSREGISTER_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
 
                        // additive passes are only darkened by fog, not tinted
                        hlslPSSetParameter3f(D3DPSREGISTER_FogColor, 0, 0, 0);
-                       hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
+                       hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
                }
                else
                {
+                       hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
+                       hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
                        if (mode == SHADERMODE_FLATCOLOR)
                        {
-                               hlslPSSetParameter3f(D3DPSREGISTER_Color_Ambient, colormod[0], colormod[1], colormod[2]);
+                               hlslPSSetParameter3f(D3DPSREGISTER_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
                        }
                        else if (mode == SHADERMODE_LIGHTDIRECTION)
                        {
-                               hlslPSSetParameter3f(D3DPSREGISTER_Color_Ambient, (r_refdef.scene.ambient + rsurface.modellight_ambient[0] * r_refdef.lightmapintensity) * colormod[0], (r_refdef.scene.ambient + rsurface.modellight_ambient[1] * r_refdef.lightmapintensity) * colormod[1], (r_refdef.scene.ambient + rsurface.modellight_ambient[2] * r_refdef.lightmapintensity) * colormod[2]);
-                               hlslPSSetParameter3f(D3DPSREGISTER_Color_Diffuse, r_refdef.lightmapintensity * colormod[0], r_refdef.lightmapintensity * colormod[1], r_refdef.lightmapintensity * colormod[2]);
-                               hlslPSSetParameter3f(D3DPSREGISTER_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale);
-                               hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Diffuse, colormod[0], colormod[1], colormod[2]);
-                               hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Specular, specularscale, specularscale, specularscale);
-                               hlslPSSetParameter3f(D3DPSREGISTER_LightColor, rsurface.modellight_diffuse[0], rsurface.modellight_diffuse[1], rsurface.modellight_diffuse[2]);
-                               hlslPSSetParameter3f(D3DPSREGISTER_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
+                               hlslPSSetParameter3f(D3DPSREGISTER_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
+                               hlslPSSetParameter3f(D3DPSREGISTER_Color_Diffuse, t->render_modellight_diffuse[0], t->render_modellight_diffuse[1], t->render_modellight_diffuse[2]);
+                               hlslPSSetParameter3f(D3DPSREGISTER_Color_Specular, t->render_modellight_specular[0], t->render_modellight_specular[1], t->render_modellight_specular[2]);
+                               hlslPSSetParameter3f(D3DPSREGISTER_LightColor, 1, 1, 1); // DEPRECATED
+                               hlslPSSetParameter3f(D3DPSREGISTER_LightDir, t->render_modellight_lightdir[0], t->render_modellight_lightdir[1], t->render_modellight_lightdir[2]);
                        }
                        else
                        {
-                               hlslPSSetParameter3f(D3DPSREGISTER_Color_Ambient, r_refdef.scene.ambient * colormod[0], r_refdef.scene.ambient * colormod[1], r_refdef.scene.ambient * colormod[2]);
-                               hlslPSSetParameter3f(D3DPSREGISTER_Color_Diffuse, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2]);
-                               hlslPSSetParameter3f(D3DPSREGISTER_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale);
-                               hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Diffuse, colormod[0] * diffusescale, colormod[1] * diffusescale, colormod[2] * diffusescale);
-                               hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Specular, specularscale, specularscale, specularscale);
+                               hlslPSSetParameter3f(D3DPSREGISTER_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
+                               hlslPSSetParameter3f(D3DPSREGISTER_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
+                               hlslPSSetParameter3f(D3DPSREGISTER_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
                        }
                        // additive passes are only darkened by fog, not tinted
                        if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
                                hlslPSSetParameter3f(D3DPSREGISTER_FogColor, 0, 0, 0);
                        else
                                hlslPSSetParameter3f(D3DPSREGISTER_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
-                       hlslPSSetParameter4f(D3DPSREGISTER_DistortScaleRefractReflect, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor);
+                       hlslPSSetParameter4f(D3DPSREGISTER_DistortScaleRefractReflect, r_water_refractdistort.value * t->refractfactor, r_water_refractdistort.value * t->refractfactor, r_water_reflectdistort.value * t->reflectfactor, r_water_reflectdistort.value * t->reflectfactor);
                        hlslPSSetParameter4f(D3DPSREGISTER_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]);
                        hlslPSSetParameter4f(D3DPSREGISTER_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]);
-                       hlslPSSetParameter4f(D3DPSREGISTER_RefractColor, rsurface.texture->refractcolor4f[0], rsurface.texture->refractcolor4f[1], rsurface.texture->refractcolor4f[2], rsurface.texture->refractcolor4f[3] * rsurface.texture->lightmapcolor[3]);
-                       hlslPSSetParameter4f(D3DPSREGISTER_ReflectColor, rsurface.texture->reflectcolor4f[0], rsurface.texture->reflectcolor4f[1], rsurface.texture->reflectcolor4f[2], rsurface.texture->reflectcolor4f[3] * rsurface.texture->lightmapcolor[3]);
-                       hlslPSSetParameter1f(D3DPSREGISTER_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin);
-                       hlslPSSetParameter1f(D3DPSREGISTER_ReflectOffset, rsurface.texture->reflectmin);
-                       hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, (rsurface.texture->specularpower - 1.0f) * (r_shadow_glossexact.integer ? 0.25f : 1.0f));
+                       hlslPSSetParameter4f(D3DPSREGISTER_RefractColor, t->refractcolor4f[0], t->refractcolor4f[1], t->refractcolor4f[2], t->refractcolor4f[3] * t->currentalpha);
+                       hlslPSSetParameter4f(D3DPSREGISTER_ReflectColor, t->reflectcolor4f[0], t->reflectcolor4f[1], t->reflectcolor4f[2], t->reflectcolor4f[3] * t->currentalpha);
+                       hlslPSSetParameter1f(D3DPSREGISTER_ReflectFactor, t->reflectmax - t->reflectmin);
+                       hlslPSSetParameter1f(D3DPSREGISTER_ReflectOffset, t->reflectmin);
+                       hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, (t->specularpower - 1.0f) * (r_shadow_glossexact.integer ? 0.25f : 1.0f));
                        if (mode == SHADERMODE_WATER)
-                               hlslPSSetParameter2f(D3DPSREGISTER_NormalmapScrollBlend, rsurface.texture->r_water_waterscroll[0], rsurface.texture->r_water_waterscroll[1]);
+                               hlslPSSetParameter2f(D3DPSREGISTER_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
+               }
+               if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
+               {
+                       hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
+                       hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
+               }
+               else
+               {
+                       hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+                       hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
                }
-               hlslPSSetParameter2f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
-               hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
-               hlslPSSetParameter3f(D3DPSREGISTER_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]);
-               hlslPSSetParameter1f(D3DPSREGISTER_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1));
+               hlslPSSetParameter3f(D3DPSREGISTER_Color_Glow, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2]);
+               hlslPSSetParameter1f(D3DPSREGISTER_Alpha, t->currentalpha * ((t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? t->r_water_wateralpha : 1));
                hlslPSSetParameter3f(D3DPSREGISTER_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
-               if (rsurface.texture->pantstexture)
-                       hlslPSSetParameter3f(D3DPSREGISTER_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
+               if (t->pantstexture)
+                       hlslPSSetParameter3f(D3DPSREGISTER_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
                else
                        hlslPSSetParameter3f(D3DPSREGISTER_Color_Pants, 0, 0, 0);
-               if (rsurface.texture->shirttexture)
-                       hlslPSSetParameter3f(D3DPSREGISTER_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]);
+               if (t->shirttexture)
+                       hlslPSSetParameter3f(D3DPSREGISTER_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
                else
                        hlslPSSetParameter3f(D3DPSREGISTER_Color_Shirt, 0, 0, 0);
                hlslPSSetParameter4f(D3DPSREGISTER_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
@@ -2643,28 +2603,28 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                hlslPSSetParameter1f(D3DPSREGISTER_FogRangeRecip, rsurface.fograngerecip);
                hlslPSSetParameter1f(D3DPSREGISTER_FogHeightFade, rsurface.fogheightfade);
                hlslPSSetParameter4f(D3DPSREGISTER_OffsetMapping_ScaleSteps,
-                               r_glsl_offsetmapping_scale.value*rsurface.texture->offsetscale,
+                               r_glsl_offsetmapping_scale.value*t->offsetscale,
                                max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
                                1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
                                max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
                        );
                hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
-               hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_Bias, rsurface.texture->offsetbias);
+               hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_Bias, t->offsetbias);
                hlslPSSetParameter2f(D3DPSREGISTER_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
                hlslPSSetParameter2f(D3DPSREGISTER_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height);
 
-               R_Mesh_TexBind(GL20TU_NORMAL            , rsurface.texture->nmaptexture                       );
-               R_Mesh_TexBind(GL20TU_COLOR             , rsurface.texture->basetexture                       );
-               R_Mesh_TexBind(GL20TU_GLOSS             , rsurface.texture->glosstexture                      );
-               R_Mesh_TexBind(GL20TU_GLOW              , rsurface.texture->glowtexture                       );
-               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL  , rsurface.texture->backgroundnmaptexture             );
-               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_COLOR   , rsurface.texture->backgroundbasetexture             );
-               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS   , rsurface.texture->backgroundglosstexture            );
-               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_GLOW    , rsurface.texture->backgroundglowtexture             );
-               if (permutation & SHADERPERMUTATION_COLORMAPPING) R_Mesh_TexBind(GL20TU_PANTS             , rsurface.texture->pantstexture                      );
-               if (permutation & SHADERPERMUTATION_COLORMAPPING) R_Mesh_TexBind(GL20TU_SHIRT             , rsurface.texture->shirttexture                      );
-               if (permutation & SHADERPERMUTATION_REFLECTCUBE) R_Mesh_TexBind(GL20TU_REFLECTMASK       , rsurface.texture->reflectmasktexture                );
-               if (permutation & SHADERPERMUTATION_REFLECTCUBE) R_Mesh_TexBind(GL20TU_REFLECTCUBE       , rsurface.texture->reflectcubetexture ? rsurface.texture->reflectcubetexture : r_texture_whitecube);
+               R_Mesh_TexBind(GL20TU_NORMAL            , t->nmaptexture                       );
+               R_Mesh_TexBind(GL20TU_COLOR             , t->basetexture                       );
+               R_Mesh_TexBind(GL20TU_GLOSS             , t->glosstexture                      );
+               R_Mesh_TexBind(GL20TU_GLOW              , t->glowtexture                       );
+               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL  , t->backgroundnmaptexture             );
+               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_COLOR   , t->backgroundbasetexture             );
+               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS   , t->backgroundglosstexture            );
+               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_GLOW    , t->backgroundglowtexture             );
+               if (permutation & SHADERPERMUTATION_COLORMAPPING) R_Mesh_TexBind(GL20TU_PANTS             , t->pantstexture                      );
+               if (permutation & SHADERPERMUTATION_COLORMAPPING) R_Mesh_TexBind(GL20TU_SHIRT             , t->shirttexture                      );
+               if (permutation & SHADERPERMUTATION_REFLECTCUBE) R_Mesh_TexBind(GL20TU_REFLECTMASK       , t->reflectmasktexture                );
+               if (permutation & SHADERPERMUTATION_REFLECTCUBE) R_Mesh_TexBind(GL20TU_REFLECTCUBE       , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
                if (permutation & SHADERPERMUTATION_FOGHEIGHTTEXTURE) R_Mesh_TexBind(GL20TU_FOGHEIGHTTEXTURE  , r_texture_fogheighttexture                          );
                if (permutation & (SHADERPERMUTATION_FOGINSIDE | SHADERPERMUTATION_FOGOUTSIDE)) R_Mesh_TexBind(GL20TU_FOGMASK           , r_texture_fogattenuation                            );
                R_Mesh_TexBind(GL20TU_LIGHTMAP          , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
@@ -2725,45 +2685,47 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                if (rsurface.batchskeletaltransform3x4buffer)
                        permutation |= SHADERPERMUTATION_SKELETAL;
                R_SetupShader_SetPermutationGLSL(mode, permutation);
+#ifndef USE_GLES2 /* FIXME: GLES3 only */
                if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
+#endif
                if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
                if (mode == SHADERMODE_LIGHTSOURCE)
                {
                        if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
                        if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
-                       if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);
-                       if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, colormod[0] * ambientscale, colormod[1] * ambientscale, colormod[2] * ambientscale);
-                       if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, colormod[0] * diffusescale, colormod[1] * diffusescale, colormod[2] * diffusescale);
-                       if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale);
+                       if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
+                       if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
+                       if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
+                       if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
        
                        // additive passes are only darkened by fog, not tinted
                        if (r_glsl_permutation->loc_FogColor >= 0)
                                qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
-                       if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
+                       if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
                }
                else
                {
                        if (mode == SHADERMODE_FLATCOLOR)
                        {
-                               if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, colormod[0], colormod[1], colormod[2]);
+                               if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
                        }
                        else if (mode == SHADERMODE_LIGHTDIRECTION)
                        {
-                               if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, (r_refdef.scene.ambient + rsurface.modellight_ambient[0] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[0], (r_refdef.scene.ambient + rsurface.modellight_ambient[1] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[1], (r_refdef.scene.ambient + rsurface.modellight_ambient[2] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[2]);
-                               if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, r_refdef.lightmapintensity * colormod[0], r_refdef.lightmapintensity * colormod[1], r_refdef.lightmapintensity * colormod[2]);
-                               if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale);
-                               if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, colormod[0], colormod[1], colormod[2]);
-                               if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, specularscale, specularscale, specularscale);
-                               if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, rsurface.modellight_diffuse[0] * r_refdef.scene.rtlightstylevalue[0], rsurface.modellight_diffuse[1] * r_refdef.scene.rtlightstylevalue[0], rsurface.modellight_diffuse[2] * r_refdef.scene.rtlightstylevalue[0]);
-                               if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
+                               if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
+                               if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_modellight_diffuse[0], t->render_modellight_diffuse[1], t->render_modellight_diffuse[2]);
+                               if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_modellight_specular[0], t->render_modellight_specular[1], t->render_modellight_specular[2]);
+                               if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
+                               if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
+                               if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
+                               if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir[0], t->render_modellight_lightdir[1], t->render_modellight_lightdir[2]);
                        }
                        else
                        {
-                               if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, r_refdef.scene.ambient * colormod[0], r_refdef.scene.ambient * colormod[1], r_refdef.scene.ambient * colormod[2]);
-                               if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2]);
-                               if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale);
-                               if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, colormod[0] * diffusescale, colormod[1] * diffusescale, colormod[2] * diffusescale);
-                               if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, specularscale, specularscale, specularscale);
+                               if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
+                               if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
+                               if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
+                               if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
+                               if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
                        }
                        // additive passes are only darkened by fog, not tinted
                        if (r_glsl_permutation->loc_FogColor >= 0)
@@ -2773,36 +2735,44 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                else
                                        qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
                        }
-                       if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor);
+                       if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * t->refractfactor, r_water_refractdistort.value * t->refractfactor, r_water_reflectdistort.value * t->reflectfactor, r_water_reflectdistort.value * t->reflectfactor);
                        if (r_glsl_permutation->loc_ScreenScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]);
                        if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]);
-                       if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4f(r_glsl_permutation->loc_RefractColor, rsurface.texture->refractcolor4f[0], rsurface.texture->refractcolor4f[1], rsurface.texture->refractcolor4f[2], rsurface.texture->refractcolor4f[3] * rsurface.texture->lightmapcolor[3]);
-                       if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4f(r_glsl_permutation->loc_ReflectColor, rsurface.texture->reflectcolor4f[0], rsurface.texture->reflectcolor4f[1], rsurface.texture->reflectcolor4f[2], rsurface.texture->reflectcolor4f[3] * rsurface.texture->lightmapcolor[3]);
-                       if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin);
-                       if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, rsurface.texture->reflectmin);
-                       if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
-                       if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, rsurface.texture->r_water_waterscroll[0], rsurface.texture->r_water_waterscroll[1]);
-               }
-               if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
-               if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
+                       if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4f(r_glsl_permutation->loc_RefractColor, t->refractcolor4f[0], t->refractcolor4f[1], t->refractcolor4f[2], t->refractcolor4f[3] * t->currentalpha);
+                       if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4f(r_glsl_permutation->loc_ReflectColor, t->reflectcolor4f[0], t->reflectcolor4f[1], t->reflectcolor4f[2], t->reflectcolor4f[3] * t->currentalpha);
+                       if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
+                       if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
+                       if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
+                       if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
+               }
+               if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
+               if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
                if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
-               if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
-               if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+               if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
+               {
+                       if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
+                       if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
+               }
+               else
+               {
+                       if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+                       if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
+               }
 
-               if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]);
-               if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1));
+               if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2]);
+               if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, t->currentalpha * ((t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? t->r_water_wateralpha : 1));
                if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
                if (r_glsl_permutation->loc_Color_Pants >= 0)
                {
-                       if (rsurface.texture->pantstexture)
-                               qglUniform3f(r_glsl_permutation->loc_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
+                       if (t->pantstexture)
+                               qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
                        else
                                qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
                }
                if (r_glsl_permutation->loc_Color_Shirt >= 0)
                {
-                       if (rsurface.texture->shirttexture)
-                               qglUniform3f(r_glsl_permutation->loc_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]);
+                       if (t->shirttexture)
+                               qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
                        else
                                qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
                }
@@ -2811,33 +2781,33 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
                if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
                if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
-                               r_glsl_offsetmapping_scale.value*rsurface.texture->offsetscale,
+                               r_glsl_offsetmapping_scale.value*t->offsetscale,
                                max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
                                1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
                                max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
                        );
                if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
-               if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, rsurface.texture->offsetbias);
+               if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
                if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
                if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
-               if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegridmatrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
-               if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegridintensity*r_refdef.view.colorscale);
+               if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegrid_state.matrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
+               if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
 
                if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
                if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
                if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
-               if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , rsurface.texture->nmaptexture                       );
-               if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , rsurface.texture->basetexture                       );
-               if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , rsurface.texture->glosstexture                      );
-               if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , rsurface.texture->glowtexture                       );
-               if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , rsurface.texture->backgroundnmaptexture             );
-               if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , rsurface.texture->backgroundbasetexture             );
-               if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , rsurface.texture->backgroundglosstexture            );
-               if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , rsurface.texture->backgroundglowtexture             );
-               if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , rsurface.texture->pantstexture                      );
-               if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , rsurface.texture->shirttexture                      );
-               if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , rsurface.texture->reflectmasktexture                );
-               if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , rsurface.texture->reflectcubetexture ? rsurface.texture->reflectcubetexture : r_texture_whitecube);
+               if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
+               if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
+               if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
+               if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
+               if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
+               if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
+               if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
+               if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
+               if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
+               if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
+               if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
+               if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
                if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
                if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
                if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
@@ -2865,7 +2835,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
                        }
                }
-               if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegridtexture);
+               if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
                CHECKGLERROR
                break;
        case RENDERPATH_GL11:
@@ -2881,74 +2851,80 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                {
                        {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ModelToLightM1, 1, false, m16f);}
                        DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
-                       DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);
-                       DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Ambient, colormod[0] * ambientscale, colormod[1] * ambientscale, colormod[2] * ambientscale);
-                       DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Diffuse, colormod[0] * diffusescale, colormod[1] * diffusescale, colormod[2] * diffusescale);
-                       DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Specular, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale);
+                       DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_LightColor, 1, 1, 1); // DEPRECATED
+                       DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
+                       DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
+                       DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
        
                        // additive passes are only darkened by fog, not tinted
                        DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_FogColor, 0, 0, 0);
-                       DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
+                       DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
                }
                else
                {
                        if (mode == SHADERMODE_FLATCOLOR)
                        {
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Ambient, colormod[0], colormod[1], colormod[2]);
+                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
                        }
                        else if (mode == SHADERMODE_LIGHTDIRECTION)
                        {
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Ambient, (r_refdef.scene.ambient + rsurface.modellight_ambient[0] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[0], (r_refdef.scene.ambient + rsurface.modellight_ambient[1] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[1], (r_refdef.scene.ambient + rsurface.modellight_ambient[2] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[2]);
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Diffuse, r_refdef.lightmapintensity * colormod[0], r_refdef.lightmapintensity * colormod[1], r_refdef.lightmapintensity * colormod[2]);
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale);
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Diffuse, colormod[0], colormod[1], colormod[2]);
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Specular, specularscale, specularscale, specularscale);
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_LightColor, rsurface.modellight_diffuse[0] * r_refdef.scene.rtlightstylevalue[0], rsurface.modellight_diffuse[1] * r_refdef.scene.rtlightstylevalue[0], rsurface.modellight_diffuse[2] * r_refdef.scene.rtlightstylevalue[0]);
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
+                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
+                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Diffuse, t->render_modellight_diffuse[0], t->render_modellight_diffuse[1], t->render_modellight_diffuse[2]);
+                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Specular, t->render_modellight_specular[0], t->render_modellight_specular[1], t->render_modellight_specular[2]);
+                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_LightColor, 1, 1, 1); // DEPRECATED
+                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_LightDir, t->render_modellight_lightdir[0], t->render_modellight_lightdir[1], t->render_modellight_lightdir[2]);
                        }
                        else
                        {
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Ambient, r_refdef.scene.ambient * colormod[0], r_refdef.scene.ambient * colormod[1], r_refdef.scene.ambient * colormod[2]);
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Diffuse, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2]);
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale);
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Diffuse, colormod[0] * diffusescale, colormod[1] * diffusescale, colormod[2] * diffusescale);
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Specular, specularscale, specularscale, specularscale);
+                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
+                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
+                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
                        }
+                       DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
+                       DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
                        // additive passes are only darkened by fog, not tinted
                        if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
                                DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_FogColor, 0, 0, 0);
                        else
                                DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
-                       DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_DistortScaleRefractReflect, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor);
+                       DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_DistortScaleRefractReflect, r_water_refractdistort.value * t->refractfactor, r_water_refractdistort.value * t->refractfactor, r_water_reflectdistort.value * t->reflectfactor, r_water_reflectdistort.value * t->reflectfactor);
                        DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]);
                        DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]);
-                       DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_RefractColor, rsurface.texture->refractcolor4f[0], rsurface.texture->refractcolor4f[1], rsurface.texture->refractcolor4f[2], rsurface.texture->refractcolor4f[3] * rsurface.texture->lightmapcolor[3]);
-                       DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ReflectColor, rsurface.texture->reflectcolor4f[0], rsurface.texture->reflectcolor4f[1], rsurface.texture->reflectcolor4f[2], rsurface.texture->reflectcolor4f[3] * rsurface.texture->lightmapcolor[3]);
-                       DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin);
-                       DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_ReflectOffset, rsurface.texture->reflectmin);
-                       DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
-                       DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_NormalmapScrollBlend, rsurface.texture->r_water_waterscroll[0], rsurface.texture->r_water_waterscroll[1]);
-               }
-               {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_TexMatrixM1, 1, false, m16f);}
-               {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_BackgroundTexMatrixM1, 1, false, m16f);}
+                       DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_RefractColor, t->refractcolor4f[0], t->refractcolor4f[1], t->refractcolor4f[2], t->refractcolor4f[3] * t->currentalpha);
+                       DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ReflectColor, t->reflectcolor4f[0], t->reflectcolor4f[1], t->reflectcolor4f[2], t->reflectcolor4f[3] * t->currentalpha);
+                       DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_ReflectFactor, t->reflectmax - t->reflectmin);
+                       DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_ReflectOffset, t->reflectmin);
+                       DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
+                       DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
+               }
+               {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_TexMatrixM1, 1, false, m16f);}
+               {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_BackgroundTexMatrixM1, 1, false, m16f);}
                {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ShadowMapMatrixM1, 1, false, m16f);}
-               DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
-               DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+               if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
+               {
+                       DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
+                       DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
+               }
+               else
+               {
+                       DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+                       DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
+               }
 
-               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]);
-               DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1));
+               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Glow, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2]);
+               DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_Alpha, t->currentalpha * ((t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? t->r_water_wateralpha : 1));
                DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
                if (DPSOFTRAST_UNIFORM_Color_Pants >= 0)
                {
-                       if (rsurface.texture->pantstexture)
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
+                       if (t->pantstexture)
+                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
                        else
                                DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Pants, 0, 0, 0);
                }
                if (DPSOFTRAST_UNIFORM_Color_Shirt >= 0)
                {
-                       if (rsurface.texture->shirttexture)
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]);
+                       if (t->shirttexture)
+                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
                        else
                                DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Shirt, 0, 0, 0);
                }
@@ -2957,28 +2933,28 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_FogRangeRecip, rsurface.fograngerecip);
                DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_FogHeightFade, rsurface.fogheightfade);
                DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_OffsetMapping_ScaleSteps,
-                               r_glsl_offsetmapping_scale.value*rsurface.texture->offsetscale,
+                               r_glsl_offsetmapping_scale.value*t->offsetscale,
                                max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
                                1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
                                max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
                        );
                DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
-               DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_OffsetMapping_Bias, rsurface.texture->offsetbias);
+               DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_OffsetMapping_Bias, t->offsetbias);
                DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
                DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
 
-               R_Mesh_TexBind(GL20TU_NORMAL            , rsurface.texture->nmaptexture                       );
-               R_Mesh_TexBind(GL20TU_COLOR             , rsurface.texture->basetexture                       );
-               R_Mesh_TexBind(GL20TU_GLOSS             , rsurface.texture->glosstexture                      );
-               R_Mesh_TexBind(GL20TU_GLOW              , rsurface.texture->glowtexture                       );
-               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL  , rsurface.texture->backgroundnmaptexture             );
-               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_COLOR   , rsurface.texture->backgroundbasetexture             );
-               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS   , rsurface.texture->backgroundglosstexture            );
-               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_GLOW    , rsurface.texture->backgroundglowtexture             );
-               if (permutation & SHADERPERMUTATION_COLORMAPPING) R_Mesh_TexBind(GL20TU_PANTS             , rsurface.texture->pantstexture                      );
-               if (permutation & SHADERPERMUTATION_COLORMAPPING) R_Mesh_TexBind(GL20TU_SHIRT             , rsurface.texture->shirttexture                      );
-               if (permutation & SHADERPERMUTATION_REFLECTCUBE) R_Mesh_TexBind(GL20TU_REFLECTMASK       , rsurface.texture->reflectmasktexture                );
-               if (permutation & SHADERPERMUTATION_REFLECTCUBE) R_Mesh_TexBind(GL20TU_REFLECTCUBE       , rsurface.texture->reflectcubetexture ? rsurface.texture->reflectcubetexture : r_texture_whitecube);
+               R_Mesh_TexBind(GL20TU_NORMAL            , t->nmaptexture                       );
+               R_Mesh_TexBind(GL20TU_COLOR             , t->basetexture                       );
+               R_Mesh_TexBind(GL20TU_GLOSS             , t->glosstexture                      );
+               R_Mesh_TexBind(GL20TU_GLOW              , t->glowtexture                       );
+               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL  , t->backgroundnmaptexture             );
+               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_COLOR   , t->backgroundbasetexture             );
+               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS   , t->backgroundglosstexture            );
+               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_GLOW    , t->backgroundglowtexture             );
+               if (permutation & SHADERPERMUTATION_COLORMAPPING) R_Mesh_TexBind(GL20TU_PANTS             , t->pantstexture                      );
+               if (permutation & SHADERPERMUTATION_COLORMAPPING) R_Mesh_TexBind(GL20TU_SHIRT             , t->shirttexture                      );
+               if (permutation & SHADERPERMUTATION_REFLECTCUBE) R_Mesh_TexBind(GL20TU_REFLECTMASK       , t->reflectmasktexture                );
+               if (permutation & SHADERPERMUTATION_REFLECTCUBE) R_Mesh_TexBind(GL20TU_REFLECTCUBE       , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
                if (permutation & SHADERPERMUTATION_FOGHEIGHTTEXTURE) R_Mesh_TexBind(GL20TU_FOGHEIGHTTEXTURE  , r_texture_fogheighttexture                          );
                if (permutation & (SHADERPERMUTATION_FOGINSIDE | SHADERPERMUTATION_FOGOUTSIDE)) R_Mesh_TexBind(GL20TU_FOGMASK           , r_texture_fogattenuation                            );
                R_Mesh_TexBind(GL20TU_LIGHTMAP          , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
@@ -3016,7 +2992,7 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
        // combination of texture, entity, light source, and fogging, only use the
        // minimum features necessary to avoid wasting rendering time in the
        // fragment shader on features that are not being used
-       unsigned int permutation = 0;
+       dpuint64 permutation = 0;
        unsigned int mode = 0;
        const float *lightcolorbase = rtlight->currentcolor;
        float ambientscale = rtlight->ambientscale;
@@ -3049,7 +3025,7 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
                GL_AlphaToCoverage(false);
        Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
        Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
-       Matrix4x4_Invert_Simple(&viewtolight, &lighttoview);
+       Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
        Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
        switch(vid.renderpath)
        {
@@ -3061,8 +3037,8 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
                hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
                hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
                hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Specular, lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
-               hlslPSSetParameter2f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
-               hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+               hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+               hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
                hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
                hlslPSSetParameter2f(D3DPSREGISTER_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
                hlslPSSetParameter2f(D3DPSREGISTER_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height);
@@ -3088,8 +3064,8 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
                if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
                if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
                if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
-               if (r_glsl_permutation->loc_ShadowMap_TextureScale    >= 0) qglUniform2f(       r_glsl_permutation->loc_ShadowMap_TextureScale   , r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
-               if (r_glsl_permutation->loc_ShadowMap_Parameters      >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_Parameters     , r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+               if (r_glsl_permutation->loc_ShadowMap_TextureScale    >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_TextureScale   , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+               if (r_glsl_permutation->loc_ShadowMap_Parameters      >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_Parameters     , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
                if (r_glsl_permutation->loc_SpecularPower             >= 0) qglUniform1f(       r_glsl_permutation->loc_SpecularPower            , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
                if (r_glsl_permutation->loc_ScreenToDepth             >= 0) qglUniform2f(       r_glsl_permutation->loc_ScreenToDepth            , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
                if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/vid.width, 1.0f/vid.height);
@@ -3111,8 +3087,8 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
                DPSOFTRAST_Uniform3f(       DPSOFTRAST_UNIFORM_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
                DPSOFTRAST_Uniform3f(       DPSOFTRAST_UNIFORM_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
                DPSOFTRAST_Uniform3f(       DPSOFTRAST_UNIFORM_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
-               DPSOFTRAST_Uniform2f(       DPSOFTRAST_UNIFORM_ShadowMap_TextureScale   , r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
-               DPSOFTRAST_Uniform4f(       DPSOFTRAST_UNIFORM_ShadowMap_Parameters     , r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+               DPSOFTRAST_Uniform4f(       DPSOFTRAST_UNIFORM_ShadowMap_TextureScale   , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+               DPSOFTRAST_Uniform4f(       DPSOFTRAST_UNIFORM_ShadowMap_Parameters     , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
                DPSOFTRAST_Uniform1f(       DPSOFTRAST_UNIFORM_SpecularPower            , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
                DPSOFTRAST_Uniform2f(       DPSOFTRAST_UNIFORM_ScreenToDepth            , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
                DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
@@ -3130,7 +3106,7 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
 
 typedef struct
 {
-       int loadsequence; // incremented each level change
+       unsigned int loadsequence; // incremented each level change
        memexpandablearray_t array;
        skinframe_t *hash[SKINFRAME_HASH];
 }
@@ -3364,6 +3340,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        skinframe->fog = NULL;
        skinframe->reflect = NULL;
        skinframe->hasalpha = false;
+       // we could store the q2animname here too
 
        if (ddsbase)
        {
@@ -3529,7 +3506,6 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB)
 {
        int i;
-       unsigned char *temp1, *temp2;
        skinframe_t *skinframe;
        char vabuf[1024];
 
@@ -3563,11 +3539,11 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co
 
        if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
        {
-               temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
-               temp2 = temp1 + width * height * 4;
-               Image_HeightmapToNormalmap_BGRA(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
-               skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
-               Mem_Free(temp1);
+               unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
+               unsigned char *b = a + width * height * 4;
+               Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
+               skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
+               Mem_Free(a);
        }
        skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
        if (textureflags & TEXF_ALPHA)
@@ -3642,6 +3618,9 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i
                featuresmask |= palette_featureflags[skindata[i]];
 
        skinframe->hasalpha = false;
+       // fence textures
+       if (name[0] == '{')
+               skinframe->hasalpha = true;
        skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
        skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
        skinframe->qgeneratemerged = true;
@@ -3684,21 +3663,24 @@ static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboo
 
        if (skinframe->qgeneratenmap)
        {
-               unsigned char *temp1, *temp2;
+               unsigned char *a, *b;
                skinframe->qgeneratenmap = false;
-               temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
-               temp2 = temp1 + width * height * 4;
+               a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
+               b = a + width * height * 4;
                // use either a custom palette or the quake palette
-               Image_Copy8bitBGRA(skindata, temp1, width * height, palette_bgra_complete);
-               Image_HeightmapToNormalmap_BGRA(temp1, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
-               skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
-               Mem_Free(temp1);
+               Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
+               Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
+               skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
+               Mem_Free(a);
        }
 
        if (skinframe->qgenerateglow)
        {
                skinframe->qgenerateglow = false;
-               skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
+               if (skinframe->hasalpha) // fence textures
+                       skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, palette_bgra_onlyfullbrights_transparent); // glow
+               else
+                       skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
        }
 
        if (colormapped)
@@ -3711,7 +3693,10 @@ static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboo
        else
        {
                skinframe->qgeneratemerged = false;
-               skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
+               if (skinframe->hasalpha) // fence textures
+                       skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, skinframe->glow ? palette_bgra_nofullbrights_transparent : palette_bgra_transparent);
+               else
+                       skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
        }
 
        if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
@@ -4007,9 +3992,11 @@ static void gl_main_start(void)
                r_loadnormalmap = true;
                r_loadgloss = true;
                r_loadfog = false;
+#ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
                if (vid.support.arb_uniform_buffer_object)
                        qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
-               break;
+#endif
+                       break;
        case RENDERPATH_GL13:
        case RENDERPATH_GLES1:
                Cvar_SetValueQuick(&r_textureunits, vid.texunits);
@@ -4064,19 +4051,38 @@ static void gl_main_start(void)
        r_glsl_permutation = NULL;
        memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
        Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
-       glslshaderstring = NULL;
 #ifdef SUPPORTD3D
        r_hlsl_permutation = NULL;
        memset(r_hlsl_permutationhash, 0, sizeof(r_hlsl_permutationhash));
        Mem_ExpandableArray_NewArray(&r_hlsl_permutationarray, r_main_mempool, sizeof(r_hlsl_permutation_t), 256);
 #endif
-       hlslshaderstring = NULL;
        memset(&r_svbsp, 0, sizeof (r_svbsp));
 
        memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
        r_texture_numcubemaps = 0;
 
        r_refdef.fogmasktable_density = 0;
+
+#ifdef __ANDROID__
+       // For Steelstorm Android
+       // FIXME CACHE the program and reload
+       // FIXME see possible combinations for SS:BR android
+       Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
+       R_SetupShader_SetPermutationGLSL(0, 12);
+       R_SetupShader_SetPermutationGLSL(0, 13);
+       R_SetupShader_SetPermutationGLSL(0, 8388621);
+       R_SetupShader_SetPermutationGLSL(3, 0);
+       R_SetupShader_SetPermutationGLSL(3, 2048);
+       R_SetupShader_SetPermutationGLSL(5, 0);
+       R_SetupShader_SetPermutationGLSL(5, 2);
+       R_SetupShader_SetPermutationGLSL(5, 2048);
+       R_SetupShader_SetPermutationGLSL(5, 8388608);
+       R_SetupShader_SetPermutationGLSL(11, 1);
+       R_SetupShader_SetPermutationGLSL(11, 2049);
+       R_SetupShader_SetPermutationGLSL(11, 8193);
+       R_SetupShader_SetPermutationGLSL(11, 10241);
+       Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
+#endif
 }
 
 static void gl_main_shutdown(void)
@@ -4094,7 +4100,7 @@ static void gl_main_shutdown(void)
        case RENDERPATH_GL20:
        case RENDERPATH_GLES1:
        case RENDERPATH_GLES2:
-#ifdef GL_SAMPLES_PASSED_ARB
+#if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
                if (r_maxqueries)
                        qglDeleteQueriesARB(r_maxqueries, r_queries);
 #endif
@@ -4145,13 +4151,11 @@ static void gl_main_shutdown(void)
        r_glsl_permutation = NULL;
        memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
        Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
-       glslshaderstring = NULL;
 #ifdef SUPPORTD3D
        r_hlsl_permutation = NULL;
        memset(r_hlsl_permutationhash, 0, sizeof(r_hlsl_permutationhash));
        Mem_ExpandableArray_FreeArray(&r_hlsl_permutationarray);
 #endif
-       hlslshaderstring = NULL;
 }
 
 static void gl_main_newmap(void)
@@ -4184,6 +4188,7 @@ void GL_Main_Init(void)
 {
        int i;
        r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
+       R_InitShaderModeInfo();
 
        Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
        Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
@@ -4227,6 +4232,7 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_transparent_useplanardistance);
        Cvar_RegisterVariable(&r_showoverdraw);
        Cvar_RegisterVariable(&r_showbboxes);
+       Cvar_RegisterVariable(&r_showbboxes_client);
        Cvar_RegisterVariable(&r_showsurfaces);
        Cvar_RegisterVariable(&r_showtris);
        Cvar_RegisterVariable(&r_shownormals);
@@ -4241,10 +4247,12 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_draw2d);
        Cvar_RegisterVariable(&r_drawworld);
        Cvar_RegisterVariable(&r_cullentities_trace);
+       Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
        Cvar_RegisterVariable(&r_cullentities_trace_samples);
        Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
        Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
        Cvar_RegisterVariable(&r_cullentities_trace_delay);
+       Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
        Cvar_RegisterVariable(&r_sortentities);
        Cvar_RegisterVariable(&r_drawviewmodel);
        Cvar_RegisterVariable(&r_drawexteriormodel);
@@ -4254,6 +4262,11 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_dynamic);
        Cvar_RegisterVariable(&r_fakelight);
        Cvar_RegisterVariable(&r_fakelight_intensity);
+       Cvar_RegisterVariable(&r_fullbright_directed);
+       Cvar_RegisterVariable(&r_fullbright_directed_ambient);
+       Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
+       Cvar_RegisterVariable(&r_fullbright_directed_pitch);
+       Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
        Cvar_RegisterVariable(&r_fullbright);
        Cvar_RegisterVariable(&r_shadows);
        Cvar_RegisterVariable(&r_shadows_darken);
@@ -4312,6 +4325,7 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_celoutlines);
 
        Cvar_RegisterVariable(&r_water);
+       Cvar_RegisterVariable(&r_water_cameraentitiesonly);
        Cvar_RegisterVariable(&r_water_resolutionmultiplier);
        Cvar_RegisterVariable(&r_water_clippingplanebias);
        Cvar_RegisterVariable(&r_water_refractdistort);
@@ -4356,10 +4370,17 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
        Cvar_RegisterVariable(&r_framedatasize);
        for (i = 0;i < R_BUFFERDATA_COUNT;i++)
-               Cvar_RegisterVariable(&r_bufferdatasize[i]);
+               Cvar_RegisterVariable(&r_buffermegs[i]);
        Cvar_RegisterVariable(&r_batch_dynamicbuffer);
        if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
                Cvar_SetValue("r_fullbrights", 0);
+#ifdef DP_MOBILETOUCH
+       // GLES devices have terrible depth precision in general, so...
+       Cvar_SetValueQuick(&r_nearclip, 4);
+       Cvar_SetValueQuick(&r_farclip_base, 4096);
+       Cvar_SetValueQuick(&r_farclip_world, 0);
+       Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
+#endif
        R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
 }
 
@@ -4408,7 +4429,11 @@ void GL_Init (void)
        VID_CheckExtensions();
 
        // LordHavoc: report supported extensions
+#ifdef CONFIG_MENU
        Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
+#else
+       Con_DPrintf("\nQuakeC extensions for server and client: %s\n", vm_sv_extensions );
+#endif
 
        // clear to black (loading plaque will be seen over this)
        GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
@@ -4423,9 +4448,6 @@ int R_CullBox(const vec3_t mins, const vec3_t maxs)
                return false;
        for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
        {
-               // skip nearclip plane, it often culls portals when you are very close, and is almost never useful
-               if (i == 4)
-                       continue;
                p = r_refdef.view.frustum + i;
                switch(p->signbits)
                {
@@ -4591,7 +4613,13 @@ void *R_FrameData_Alloc(size_t size)
        while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
        {
                // emergency - we ran out of space, allocate more memory
-               newvalue = bound(0.25f, r_framedatasize.value * 2.0f, 256.0f);
+               // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
+               newvalue = r_framedatasize.value * 2.0f;
+               // upper bound based on architecture - if we try to allocate more than this we could overflow, better to loop until we error out on allocation failure
+               if (sizeof(size_t) >= 8)
+                       newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
+               else
+                       newvalue = bound(0.25f, newvalue, (float)(1 << 10));
                // this might not be a growing it, but we'll allocate another buffer every time
                Cvar_SetValueQuick(&r_framedatasize, newvalue);
                R_FrameData_Resize(true);
@@ -4631,8 +4659,8 @@ void R_FrameData_ReturnToMark(void)
 
 //==================================================================================
 
-// avoid reusing the same buffer objects on consecutive buffers
-#define R_BUFFERDATA_CYCLE 2
+// avoid reusing the same buffer objects on consecutive frames
+#define R_BUFFERDATA_CYCLE 3
 
 typedef struct r_bufferdata_buffer_s
 {
@@ -4656,7 +4684,7 @@ void R_BufferData_Reset(void)
                for (type = 0;type < R_BUFFERDATA_COUNT;type++)
                {
                        // free all buffers
-                       p = &r_bufferdata_buffer[r_bufferdata_cycle][type];
+                       p = &r_bufferdata_buffer[cycle][type];
                        while (*p)
                        {
                                mem = *p;
@@ -4670,12 +4698,30 @@ void R_BufferData_Reset(void)
 }
 
 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
-static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow)
+static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
 {
        r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
        size_t size;
-       size = (size_t)(r_bufferdatasize[type].value * 1024*1024);
-       size = bound(65536, size, 512*1024*1024);
+       float newvalue = r_buffermegs[type].value;
+
+       // increase the cvar if we have to (but only if we already have a mem)
+       if (mustgrow && mem)
+               newvalue *= 2.0f;
+       newvalue = bound(0.25f, newvalue, 256.0f);
+       while (newvalue * 1024*1024 < minsize)
+               newvalue *= 2.0f;
+
+       // clamp the cvar to valid range
+       newvalue = bound(0.25f, newvalue, 256.0f);
+       if (r_buffermegs[type].value != newvalue)
+               Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
+
+       // calculate size in bytes
+       size = (size_t)(newvalue * 1024*1024);
+       size = bound(131072, size, 256*1024*1024);
+
+       // allocate a new buffer if the size is different (purge old one later)
+       // or if we were told we must grow the buffer
        if (!mem || mem->size != size || mustgrow)
        {
                mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
@@ -4705,7 +4751,7 @@ void R_BufferData_NewFrame(void)
        {
                if (r_bufferdata_buffer[r_bufferdata_cycle][type])
                {
-                       R_BufferData_Resize((r_bufferdata_type_t)type, false);
+                       R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
                        // free all but the head buffer, this is how we recycle obsolete
                        // buffers after they are no longer in use
                        p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
@@ -4723,12 +4769,11 @@ void R_BufferData_NewFrame(void)
        }
 }
 
-r_meshbuffer_t *R_BufferData_Store(size_t datasize, void *data, r_bufferdata_type_t type, int *returnbufferoffset, qboolean allowfail)
+r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
 {
        r_bufferdata_buffer_t *mem;
        int offset = 0;
        int padsize;
-       float newvalue;
 
        *returnbufferoffset = 0;
 
@@ -4739,19 +4784,16 @@ r_meshbuffer_t *R_BufferData_Store(size_t datasize, void *data, r_bufferdata_typ
        else
                padsize = (datasize + 15) & ~15;
 
-       while (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
-       {
-               // emergency - we ran out of space, allocate more memory
-               newvalue = bound(0.25f, r_bufferdatasize[type].value * 2.0f, 256.0f);
-               // if we're already at the limit, just fail (if allowfail is false we might run out of video ram)
-               if (newvalue == r_bufferdatasize[type].value && allowfail)
-                       return NULL;
-               Cvar_SetValueQuick(&r_bufferdatasize[type], newvalue);
-               R_BufferData_Resize(type, true);
-       }
+       // if we ran out of space in this buffer we must allocate a new one
+       if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
+               R_BufferData_Resize(type, true, padsize);
+
+       // if the resize did not give us enough memory, fail
+       if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
+               Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
 
        mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
-       offset = mem->current;
+       offset = (int)mem->current;
        mem->current += padsize;
 
        // upload the data to the buffer at the chosen offset
@@ -4880,7 +4922,7 @@ qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qbool
                Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
                // note: this can fail if the buffer is at the grow limit
                ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
-               ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset, true);
+               ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
        }
        else if (ent->animcache_vertex3f)
        {
@@ -4966,155 +5008,88 @@ void R_AnimCache_CacheVisibleEntities(void)
 
 //==================================================================================
 
-extern cvar_t r_overheadsprites_pushback;
-
-static void R_View_UpdateEntityLighting (void)
-{
-       int i;
-       entity_render_t *ent;
-       vec3_t tempdiffusenormal, avg;
-       vec_t f, fa, fd, fdd;
-       qboolean skipunseen = r_shadows.integer != 1; //|| R_Shadow_ShadowMappingEnabled();
-
-       for (i = 0;i < r_refdef.scene.numentities;i++)
-       {
-               ent = r_refdef.scene.entities[i];
-
-               // skip unseen models
-               if ((!r_refdef.viewcache.entityvisible[i] && skipunseen))
-                       continue;
-
-               // skip bsp models
-               if (ent->model && ent->model == cl.worldmodel)
-               {
-                       // TODO: use modellight for r_ambient settings on world?
-                       VectorSet(ent->modellight_ambient, 0, 0, 0);
-                       VectorSet(ent->modellight_diffuse, 0, 0, 0);
-                       VectorSet(ent->modellight_lightdir, 0, 0, 1);
-                       continue;
-               }
-               
-               if (ent->flags & RENDER_CUSTOMIZEDMODELLIGHT)
-               {
-                       // aleady updated by CSQC
-                       // TODO: force modellight on BSP models in this case?
-                       VectorCopy(ent->modellight_lightdir, tempdiffusenormal); 
-               }
-               else
-               {
-                       // fetch the lighting from the worldmodel data
-                       VectorClear(ent->modellight_ambient);
-                       VectorClear(ent->modellight_diffuse);
-                       VectorClear(tempdiffusenormal);
-                       if (ent->flags & RENDER_LIGHT)
-                       {
-                               vec3_t org;
-                               Matrix4x4_OriginFromMatrix(&ent->matrix, org);
-
-                               // complete lightning for lit sprites
-                               // todo: make a EF_ field so small ents could be lit purely by modellight and skipping real rtlight pass (like EF_NORTLIGHT)?
-                               if (ent->model->type == mod_sprite && !(ent->model->data_textures[0].basematerialflags & MATERIALFLAG_FULLBRIGHT))
-                               {
-                                       if (ent->model->sprite.sprnum_type == SPR_OVERHEAD) // apply offset for overhead sprites
-                                               org[2] = org[2] + r_overheadsprites_pushback.value;
-                                       R_LightPoint(ent->modellight_ambient, org, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT);
-                               }
-                               else
-                                       R_CompleteLightPoint(ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal, org, LP_LIGHTMAP);
-
-                               if(ent->flags & RENDER_EQUALIZE)
-                               {
-                                       // first fix up ambient lighting...
-                                       if(r_equalize_entities_minambient.value > 0)
-                                       {
-                                               fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2];
-                                               if(fd > 0)
-                                               {
-                                                       fa = (0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2]);
-                                                       if(fa < r_equalize_entities_minambient.value * fd)
-                                                       {
-                                                               // solve:
-                                                               //   fa'/fd' = minambient
-                                                               //   fa'+0.25*fd' = fa+0.25*fd
-                                                               //   ...
-                                                               //   fa' = fd' * minambient
-                                                               //   fd'*(0.25+minambient) = fa+0.25*fd
-                                                               //   ...
-                                                               //   fd' = (fa+0.25*fd) * 1 / (0.25+minambient)
-                                                               //   fa' = (fa+0.25*fd) * minambient / (0.25+minambient)
-                                                               //   ...
-                                                               fdd = (fa + 0.25f * fd) / (0.25f + r_equalize_entities_minambient.value);
-                                                               f = fdd / fd; // f>0 because all this is additive; f<1 because fdd<fd because this follows from fa < r_equalize_entities_minambient.value * fd
-                                                               VectorMA(ent->modellight_ambient, (1-f)*0.25f, ent->modellight_diffuse, ent->modellight_ambient);
-                                                               VectorScale(ent->modellight_diffuse, f, ent->modellight_diffuse);
-                                                       }
-                                               }
-                                       }
-
-                                       if(r_equalize_entities_to.value > 0 && r_equalize_entities_by.value != 0)
-                                       {
-                                               fa = 0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2];
-                                               fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2];
-                                               f = fa + 0.25 * fd;
-                                               if(f > 0)
-                                               {
-                                                       // adjust brightness and saturation to target
-                                                       avg[0] = avg[1] = avg[2] = fa / f;
-                                                       VectorLerp(ent->modellight_ambient, r_equalize_entities_by.value, avg, ent->modellight_ambient);
-                                                       avg[0] = avg[1] = avg[2] = fd / f;
-                                                       VectorLerp(ent->modellight_diffuse, r_equalize_entities_by.value, avg, ent->modellight_diffuse);
-                                               }
-                                       }
-                               }
-                       }
-                       else // highly rare
-                               VectorSet(ent->modellight_ambient, 1, 1, 1);
-               }
-
-               // move the light direction into modelspace coordinates for lighting code
-               Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir);
-               if(VectorLength2(ent->modellight_lightdir) == 0)
-                       VectorSet(ent->modellight_lightdir, 0, 0, 1); // have to set SOME valid vector here
-               VectorNormalize(ent->modellight_lightdir);
-       }
-}
-
-#define MAX_LINEOFSIGHTTRACES 64
-
-static qboolean R_CanSeeBox(int numsamples, vec_t enlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
+qboolean R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
 {
        int i;
+       vec3_t eyemins, eyemaxs;
        vec3_t boxmins, boxmaxs;
        vec3_t start;
        vec3_t end;
        dp_model_t *model = r_refdef.scene.worldmodel;
+       static vec3_t positions[] = {
+               { 0.5f, 0.5f, 0.5f },
+               { 0.0f, 0.0f, 0.0f },
+               { 0.0f, 0.0f, 1.0f },
+               { 0.0f, 1.0f, 0.0f },
+               { 0.0f, 1.0f, 1.0f },
+               { 1.0f, 0.0f, 0.0f },
+               { 1.0f, 0.0f, 1.0f },
+               { 1.0f, 1.0f, 0.0f },
+               { 1.0f, 1.0f, 1.0f },
+       };
+
+       // sample count can be set to -1 to skip this logic, for flicker-prone objects
+       if (numsamples < 0)
+               return true;
 
-       if (!model || !model->brush.TraceLineOfSight)
+       // view origin is not used for culling in portal/reflection/refraction renders or isometric views
+       if (r_refdef.view.useclipplane || !r_refdef.view.useperspective || r_trippy.integer)
                return true;
 
+       if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
+               return true;
+
+       // expand the eye box a little
+       eyemins[0] = eye[0] - eyejitter;
+       eyemaxs[0] = eye[0] + eyejitter;
+       eyemins[1] = eye[1] - eyejitter;
+       eyemaxs[1] = eye[1] + eyejitter;
+       eyemins[2] = eye[2] - eyejitter;
+       eyemaxs[2] = eye[2] + eyejitter;
        // expand the box a little
-       boxmins[0] = (enlarge+1) * entboxmins[0] - enlarge * entboxmaxs[0];
-       boxmaxs[0] = (enlarge+1) * entboxmaxs[0] - enlarge * entboxmins[0];
-       boxmins[1] = (enlarge+1) * entboxmins[1] - enlarge * entboxmaxs[1];
-       boxmaxs[1] = (enlarge+1) * entboxmaxs[1] - enlarge * entboxmins[1];
-       boxmins[2] = (enlarge+1) * entboxmins[2] - enlarge * entboxmaxs[2];
-       boxmaxs[2] = (enlarge+1) * entboxmaxs[2] - enlarge * entboxmins[2];
-
-       // return true if eye is inside enlarged box
-       if (BoxesOverlap(boxmins, boxmaxs, eye, eye))
+       boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0];
+       boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0];
+       boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1];
+       boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1];
+       boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2];
+       boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2];
+
+       // return true if eye overlaps enlarged box
+       if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
                return true;
 
-       // try center
-       VectorCopy(eye, start);
-       VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, end);
-       if (model->brush.TraceLineOfSight(model, start, end))
+       // try specific positions in the box first - note that these can be cached
+       if (r_cullentities_trace_entityocclusion.integer)
+       {
+               for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
+               {
+                       VectorCopy(eye, start);
+                       end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
+                       end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
+                       end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
+                       //trace_t trace = CL_TraceLine(start, end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, 0.0f, true, false, NULL, true, true);
+                       trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
+                       // not picky - if the trace ended anywhere in the box we're good
+                       if (BoxesOverlap(trace.endpos, trace.endpos, boxmins, boxmaxs))
+                               return true;
+               }
+       }
+       else if (model->brush.TraceLineOfSight(model, start, end, boxmins, boxmaxs))
                return true;
 
        // try various random positions
-       for (i = 0;i < numsamples;i++)
+       for (i = 0; i < numsamples; i++)
        {
+               VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
                VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
-               if (model->brush.TraceLineOfSight(model, start, end))
+               if (r_cullentities_trace_entityocclusion.integer)
+               {
+                       trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
+                       // not picky - if the trace ended anywhere in the box we're good
+                       if (BoxesOverlap(trace.endpos, trace.endpos, boxmins, boxmaxs))
+                               return true;
+               }
+               else if (model->brush.TraceLineOfSight(model, start, end, boxmins, boxmaxs))
                        return true;
        }
 
@@ -5129,18 +5104,20 @@ static void R_View_UpdateEntityVisible (void)
        int samples;
        entity_render_t *ent;
 
-       renderimask = r_refdef.envmap                                    ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL)
-               : r_fb.water.hideplayer                                      ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL)
-               : (chase_active.integer || r_fb.water.renderingscene)  ? RENDER_VIEWMODEL
-               :                                                          RENDER_EXTERIORMODEL;
+       if (r_refdef.envmap || r_fb.water.hideplayer)
+               renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
+       else if (chase_active.integer || r_fb.water.renderingscene)
+               renderimask = RENDER_VIEWMODEL;
+       else
+               renderimask = RENDER_EXTERIORMODEL;
        if (!r_drawviewmodel.integer)
                renderimask |= RENDER_VIEWMODEL;
        if (!r_drawexteriormodel.integer)
                renderimask |= RENDER_EXTERIORMODEL;
+       memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
        if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
        {
                // worldmodel can check visibility
-               memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
                for (i = 0;i < r_refdef.scene.numentities;i++)
                {
                        ent = r_refdef.scene.entities[i];
@@ -5156,25 +5133,24 @@ static void R_View_UpdateEntityVisible (void)
                for (i = 0;i < r_refdef.scene.numentities;i++)
                {
                        ent = r_refdef.scene.entities[i];
-                       r_refdef.viewcache.entityvisible[i] = !(ent->flags & renderimask) && ((ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)) || !R_CullBox(ent->mins, ent->maxs));
+                       if (!(ent->flags & renderimask))
+                       if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
+                               r_refdef.viewcache.entityvisible[i] = true;
                }
        }
-       if(r_cullentities_trace.integer && r_refdef.scene.worldmodel->brush.TraceLineOfSight && !r_refdef.view.useclipplane && !r_trippy.integer)
-               // sorry, this check doesn't work for portal/reflection/refraction renders as the view origin is not useful for culling
+       if (r_cullentities_trace.integer)
        {
                for (i = 0;i < r_refdef.scene.numentities;i++)
                {
                        if (!r_refdef.viewcache.entityvisible[i])
                                continue;
                        ent = r_refdef.scene.entities[i];
-                       if(!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
+                       if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
                        {
-                               samples = ent->entitynumber ? r_cullentities_trace_samples.integer : r_cullentities_trace_tempentitysamples.integer;
-                               if (samples < 0)
-                                       continue; // temp entities do pvs only
-                               if(R_CanSeeBox(samples, r_cullentities_trace_enlarge.value, r_refdef.view.origin, ent->mins, ent->maxs))
+                               samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
+                               if (R_CanSeeBox(samples, r_cullentities_trace_eyejitter.value, r_cullentities_trace_enlarge.value, r_refdef.view.origin, ent->mins, ent->maxs))
                                        ent->last_trace_visibility = realtime;
-                               if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
+                               if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
                                        r_refdef.viewcache.entityvisible[i] = 0;
                        }
                }
@@ -5298,7 +5274,7 @@ void R_HDR_UpdateIrisAdaptation(const vec3_t point)
                        p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
                        p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
                        p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
-                       R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT);
+                       R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
                        d = DotProduct(forward, diffusenormal);
                        brightness += VectorLength(ambient);
                        if (d > 0)
@@ -5529,7 +5505,6 @@ static void R_View_UpdateWithScissor(const int *myscissor)
        R_View_SetFrustum(myscissor);
        R_View_WorldVisibility(r_refdef.view.useclipplane);
        R_View_UpdateEntityVisible();
-       R_View_UpdateEntityLighting();
 }
 
 static void R_View_Update(void)
@@ -5538,7 +5513,6 @@ static void R_View_Update(void)
        R_View_SetFrustum(NULL);
        R_View_WorldVisibility(r_refdef.view.useclipplane);
        R_View_UpdateEntityVisible();
-       R_View_UpdateEntityLighting();
 }
 
 float viewscalefpsadjusted = 1.0f;
@@ -5622,7 +5596,9 @@ void R_EntityMatrix(const matrix4x4_t *matrix)
                case RENDERPATH_GL11:
                case RENDERPATH_GL13:
                case RENDERPATH_GLES1:
+#ifndef USE_GLES2
                        qglLoadMatrixf(gl_modelview16f);CHECKGLERROR
+#endif
                        break;
                case RENDERPATH_SOFT:
                        DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1, 1, false, gl_modelviewprojection16f);
@@ -5736,7 +5712,7 @@ void R_RenderView_UpdateViewVectors(void)
        Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
        VectorNegate(r_refdef.view.left, r_refdef.view.right);
        // make an inverted copy of the view matrix for tracking sprites
-       Matrix4x4_Invert_Simple(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
+       Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
 }
 
 void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
@@ -5784,10 +5760,10 @@ static void R_Water_StartFrame(void)
        }
        else
        {
-               for (texturewidth   = 1;texturewidth   < waterwidth ;texturewidth   *= 2);
-               for (textureheight  = 1;textureheight  < waterheight;textureheight  *= 2);
-               for (camerawidth    = 1;camerawidth   <= waterwidth; camerawidth    *= 2); camerawidth  /= 2;
-               for (cameraheight   = 1;cameraheight  <= waterheight;cameraheight   *= 2); cameraheight /= 2;
+               for (texturewidth   = 1;texturewidth     <  waterwidth ;texturewidth   *= 2);
+               for (textureheight  = 1;textureheight    <  waterheight;textureheight  *= 2);
+               for (camerawidth    = 1;camerawidth  * 2 <= waterwidth ;camerawidth    *= 2);
+               for (cameraheight   = 1;cameraheight * 2 <= waterheight;cameraheight   *= 2);
        }
 
        // allocate textures as needed
@@ -5910,25 +5886,33 @@ void R_Water_AddWaterPlane(msurface_t *surface, int entno)
                }
        }
        planeindex = bestplaneindex;
-       p = r_fb.water.waterplanes + planeindex;
 
        // if this surface does not fit any known plane rendered this frame, add one
-       if ((planeindex < 0 || bestplanescore > 0.001f) && r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
+       if (planeindex < 0 || bestplanescore > 0.001f)
        {
-               // store the new plane
-               planeindex = r_fb.water.numwaterplanes++;
-               p = r_fb.water.waterplanes + planeindex;
-               p->plane = plane;
-               // clear materialflags and pvs
-               p->materialflags = 0;
-               p->pvsvalid = false;
-               p->camera_entity = t->camera_entity;
-               VectorCopy(mins, p->mins);
-               VectorCopy(maxs, p->maxs);
+               if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
+               {
+                       // store the new plane
+                       planeindex = r_fb.water.numwaterplanes++;
+                       p = r_fb.water.waterplanes + planeindex;
+                       p->plane = plane;
+                       // clear materialflags and pvs
+                       p->materialflags = 0;
+                       p->pvsvalid = false;
+                       p->camera_entity = t->camera_entity;
+                       VectorCopy(mins, p->mins);
+                       VectorCopy(maxs, p->maxs);
+               }
+               else
+               {
+                       // We're totally screwed.
+                       return;
+               }
        }
        else
        {
                // merge mins/maxs when we're adding this surface to the plane
+               p = r_fb.water.waterplanes + planeindex;
                p->mins[0] = min(p->mins[0], mins[0]);
                p->mins[1] = min(p->mins[1], mins[1]);
                p->mins[2] = min(p->mins[2], mins[2]);
@@ -5941,7 +5925,7 @@ void R_Water_AddWaterPlane(msurface_t *surface, int entno)
        if(!(p->materialflags & MATERIALFLAG_CAMERA))
        {
                // merge this surface's PVS into the waterplane
-               if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
+               if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
                 && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
                {
                        r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
@@ -5993,6 +5977,8 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
        // make sure enough textures are allocated
        for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
        {
+               if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
+                       continue;
                if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
                {
                        if (!p->texture_refraction)
@@ -6048,6 +6034,8 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
        r_fb.water.renderingscene = true;
        for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
        {
+               if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
+                       continue;
                if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
                {
                        r_refdef.view = myview;
@@ -6075,7 +6063,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
                                        memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
                        }
 
-                       r_fb.water.hideplayer = r_water_hideplayer.integer >= 2;
+                       r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
                        R_ResetViewRendering3D(p->fbo_reflection, r_fb.water.depthtexture, p->texture_reflection);
                        R_ClearScreen(r_refdef.fogenabled);
                        if(r_water_scissormode.integer & 2)
@@ -6104,7 +6092,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
                                        continue; // FIXME the plane then still may get rendered but with broken texture, but it sure won't be visible
                        }
 
-                       r_fb.water.hideplayer = r_water_hideplayer.integer >= 1;
+                       r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
 
                        r_refdef.view.clipplane = p->plane;
                        VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
@@ -6325,7 +6313,7 @@ static void R_Bloom_StartFrame(void)
                Cvar_SetValueQuick(&r_damageblur, 0);
        }
 
-       if (!(r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial))
+       if (!((r_glsl_postprocess.integer || r_fxaa.integer) || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial))
         && !r_bloom.integer
         && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0))
         && !useviewfbo
@@ -6489,6 +6477,7 @@ static void R_Bloom_MakeTexture(void)
        r_fb.bloomindex = 0;
        R_Mesh_SetRenderTargets(r_fb.bloomfbo[r_fb.bloomindex], NULL, r_fb.bloomtexture[r_fb.bloomindex], NULL, NULL, NULL);
        R_SetViewport(&r_fb.bloomviewport);
+       GL_CullFace(GL_NONE);
        GL_DepthTest(false);
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_Color(colorscale, colorscale, colorscale, 1);
@@ -6612,7 +6601,7 @@ static void R_Bloom_MakeTexture(void)
 
 static void R_BlendView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
-       unsigned int permutation;
+       dpuint64 permutation;
        float uservecs[4][4];
 
        R_EntityMatrix(&identitymatrix);
@@ -6931,7 +6920,7 @@ void R_UpdateVariables(void)
 {
        R_Textures_Frame();
 
-       r_refdef.scene.ambient = r_ambient.value * (1.0f / 64.0f);
+       r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
 
        r_refdef.farclip = r_farclip_base.value;
        if (r_refdef.scene.worldmodel)
@@ -6949,14 +6938,14 @@ void R_UpdateVariables(void)
        r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
        r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
        r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
-       r_refdef.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
+       r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
        if (FAKELIGHT_ENABLED)
        {
-               r_refdef.lightmapintensity *= r_fakelight_intensity.value;
+               r_refdef.scene.lightmapintensity *= r_fakelight_intensity.value;
        }
        else if (r_refdef.scene.worldmodel)
        {
-               r_refdef.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
+               r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
        }
        if (r_showsurfaces.integer)
        {
@@ -6964,7 +6953,7 @@ void R_UpdateVariables(void)
                r_refdef.scene.rtworldshadows = false;
                r_refdef.scene.rtdlight = false;
                r_refdef.scene.rtdlightshadows = false;
-               r_refdef.lightmapintensity = 0;
+               r_refdef.scene.lightmapintensity = 0;
        }
 
        r_gpuskeletal = false;
@@ -7101,7 +7090,7 @@ void R_RenderView(void)
        if (r_timereport_active)
                R_TimeReport("start");
        r_textureframe++; // used only by R_GetCurrentTexture
-       rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
+       rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
 
        if(R_CompileShader_CheckStaticParms())
                R_GLSL_Restart_f();
@@ -7112,8 +7101,6 @@ void R_RenderView(void)
                R_SortEntities();
 
        R_AnimCache_ClearCache();
-       R_FrameData_NewFrame();
-       R_BufferData_NewFrame();
 
        /* adjust for stereo display */
        if(R_Stereo_Active())
@@ -7246,10 +7233,11 @@ void R_RenderWaterPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortex
 
 extern cvar_t cl_locs_show;
 static void R_DrawLocs(void);
-static void R_DrawEntityBBoxes(void);
+static void R_DrawEntityBBoxes(prvm_prog_t *prog);
 static void R_DrawModelDecals(void);
 extern cvar_t cl_decals_newsystem;
 extern qboolean r_shadow_usingdeferredprepass;
+extern int r_shadow_shadowmapatlas_modelshadows_size;
 void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
        qboolean shadowmapping = false;
@@ -7301,18 +7289,25 @@ void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
                }
        }
 
+       R_Shadow_PrepareModelShadows();
        R_Shadow_PrepareLights(fbo, depthtexture, colortexture);
-       if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
-               R_Shadow_PrepareModelShadows();
        if (r_timereport_active)
                R_TimeReport("preparelights");
 
-       if (R_Shadow_ShadowMappingEnabled())
-               shadowmapping = true;
+       // render all the shadowmaps that will be used for this view
+       shadowmapping = R_Shadow_ShadowMappingEnabled();
+       if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
+       {
+               R_Shadow_DrawShadowMaps();
+               if (r_timereport_active)
+                       R_TimeReport("shadowmaps");
+       }
 
+       // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
        if (r_shadow_usingdeferredprepass)
                R_Shadow_DrawPrepass();
 
+       // now we begin the forward pass of the view render
        if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
        {
                r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
@@ -7326,16 +7321,6 @@ void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
                        R_TimeReport("modeldepth");
        }
 
-       if (r_shadows.integer >= 2 && shadowmapping && r_refdef.lightmapintensity > 0)
-       {
-               R_ResetViewRendering3D(fbo, depthtexture, colortexture);
-               R_DrawModelShadowMaps(fbo, depthtexture, colortexture);
-               R_ResetViewRendering3D(fbo, depthtexture, colortexture);
-               // don't let sound skip if going slow
-               if (r_refdef.scene.extraupdate)
-                       S_ExtraUpdate ();
-       }
-
        if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
        {
                r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
@@ -7355,10 +7340,10 @@ void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
        if (r_refdef.scene.extraupdate)
                S_ExtraUpdate ();
 
-       if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && !r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
+       if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && !r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
        {
                R_ResetViewRendering3D(fbo, depthtexture, colortexture);
-               R_DrawModelShadows(fbo, depthtexture, colortexture);
+               R_Shadow_DrawModelShadows();
                R_ResetViewRendering3D(fbo, depthtexture, colortexture);
                // don't let sound skip if going slow
                if (r_refdef.scene.extraupdate)
@@ -7376,10 +7361,10 @@ void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
        if (r_refdef.scene.extraupdate)
                S_ExtraUpdate ();
 
-       if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
+       if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
        {
                R_ResetViewRendering3D(fbo, depthtexture, colortexture);
-               R_DrawModelShadows(fbo, depthtexture, colortexture);
+               R_Shadow_DrawModelShadows();
                R_ResetViewRendering3D(fbo, depthtexture, colortexture);
                // don't let sound skip if going slow
                if (r_refdef.scene.extraupdate)
@@ -7408,10 +7393,6 @@ void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
                R_DrawExplosions();
                if (r_timereport_active)
                        R_TimeReport("explosions");
-
-               R_DrawLightningBeams();
-               if (r_timereport_active)
-                       R_TimeReport("lightning");
        }
 
        if (cl.csqc_loaded)
@@ -7433,11 +7414,17 @@ void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
                                R_TimeReport("portals");
                }
 
+               if (r_showbboxes_client.value > 0)
+               {
+                       R_DrawEntityBBoxes(CLVM_prog);
+                       if (r_timereport_active)
+                               R_TimeReport("clbboxes");
+               }
                if (r_showbboxes.value > 0)
                {
-                       R_DrawEntityBBoxes();
+                       R_DrawEntityBBoxes(SVVM_prog);
                        if (r_timereport_active)
-                               R_TimeReport("bboxes");
+                               R_TimeReport("svbboxes");
                }
        }
 
@@ -7501,31 +7488,66 @@ static const unsigned short bboxelements[36] =
        1, 0, 2, 1, 2, 3,
 };
 
+#define BBOXEDGES 13
+static const float bboxedges[BBOXEDGES][6] = 
+{
+       // whole box
+       { 0, 0, 0, 1, 1, 1 },
+       // bottom edges
+       { 0, 0, 0, 0, 1, 0 },
+       { 0, 0, 0, 1, 0, 0 },
+       { 0, 1, 0, 1, 1, 0 },
+       { 1, 0, 0, 1, 1, 0 },
+       // top edges
+       { 0, 0, 1, 0, 1, 1 },
+       { 0, 0, 1, 1, 0, 1 },
+       { 0, 1, 1, 1, 1, 1 },
+       { 1, 0, 1, 1, 1, 1 },
+       // vertical edges
+       { 0, 0, 0, 0, 0, 1 },
+       { 1, 0, 0, 1, 0, 1 },
+       { 0, 1, 0, 0, 1, 1 },
+       { 1, 1, 0, 1, 1, 1 },
+};
+
 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
 {
-       int i;
-       float *v, *c, f1, f2, vertex3f[8*3], color4f[8*4];
+       int numvertices = BBOXEDGES * 8;
+       float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
+       int numtriangles = BBOXEDGES * 12;
+       unsigned short elements[BBOXEDGES * 36];
+       int i, edge;
+       float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
 
-       RSurf_ActiveWorldEntity();
+       RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
 
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        GL_DepthMask(false);
        GL_DepthRange(0, 1);
        GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
-//     R_Mesh_ResetTextureState();
 
-       vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2]; //
-       vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
-       vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
-       vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
-       vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
-       vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
-       vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
-       vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
-       R_FillColors(color4f, 8, cr, cg, cb, ca);
-       if (r_refdef.fogenabled)
+       for (edge = 0; edge < BBOXEDGES; edge++)
        {
-               for (i = 0, v = vertex3f, c = color4f;i < 8;i++, v += 3, c += 4)
+               for (i = 0; i < 3; i++)
+               {
+                       edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
+                       edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
+               }
+               vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
+               vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
+               vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
+               vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
+               vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
+               vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
+               vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
+               vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
+               for (i = 0; i < 36; i++)
+                       elements[edge * 36 + i] = edge * 8 + bboxelements[i];
+       }
+       R_FillColors(color4f, numvertices, cr, cg, cb, ca);
+       if (r_refdef.fogenabled)
+       {
+               for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
                {
                        f1 = RSurf_FogVertex(v);
                        f2 = 1 - f1;
@@ -7534,23 +7556,20 @@ static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float c
                        c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
                }
        }
-       R_Mesh_PrepareVertices_Generic_Arrays(8, vertex3f, color4f, NULL);
+       R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
        R_Mesh_ResetTextureState();
        R_SetupShader_Generic_NoTexture(false, false);
-       R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
+       R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
 }
 
 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
 {
-       prvm_prog_t *prog = SVVM_prog;
+       // hacky overloading of the parameters
+       prvm_prog_t *prog = (prvm_prog_t *)rtlight;
        int i;
        float color[4];
        prvm_edict_t *edict;
 
-       // this function draws bounding boxes of server entities
-       if (!sv.active)
-               return;
-
        GL_CullFace(GL_NONE);
        R_SetupShader_Generic_NoTexture(false, false);
 
@@ -7567,37 +7586,37 @@ static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtligh
                        case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
                        default:             Vector4Set(color, 0, 0, 0, 0.50);break;
                }
-               color[3] *= r_showbboxes.value;
+               if (prog == CLVM_prog)
+                       color[3] *= r_showbboxes_client.value;
+               else
+                       color[3] *= r_showbboxes.value;
                color[3] = bound(0, color[3], 1);
                GL_DepthTest(!r_showdisabledepthtest.integer);
-               GL_CullFace(r_refdef.view.cullface_front);
                R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
        }
 }
 
-static void R_DrawEntityBBoxes(void)
+static void R_DrawEntityBBoxes(prvm_prog_t *prog)
 {
        int i;
        prvm_edict_t *edict;
        vec3_t center;
-       prvm_prog_t *prog = SVVM_prog;
 
-       // this function draws bounding boxes of server entities
-       if (!sv.active)
+       if (prog == NULL)
                return;
 
-       for (i = 0;i < prog->num_edicts;i++)
+       for (i = 0; i < prog->num_edicts; i++)
        {
                edict = PRVM_EDICT_NUM(i);
                if (edict->priv.server->free)
                        continue;
                // exclude the following for now, as they don't live in world coordinate space and can't be solid:
-               if(PRVM_serveredictedict(edict, tag_entity) != 0)
+               if (PRVM_serveredictedict(edict, tag_entity) != 0)
                        continue;
-               if(PRVM_serveredictedict(edict, viewmodelforclient) != 0)
+               if (PRVM_serveredictedict(edict, viewmodelforclient) != 0)
                        continue;
                VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
-               R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL);
+               R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
        }
 }
 
@@ -7661,7 +7680,7 @@ static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const
                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
                GL_DepthMask(false);
        }
-       else if (rsurface.colormod[3] < 1)
+       else if (ent->alpha < 1)
        {
                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                GL_DepthMask(false);
@@ -7678,10 +7697,10 @@ static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const
        memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
        for (i = 0, c = color4f;i < 6;i++, c += 4)
        {
-               c[0] *= rsurface.colormod[0];
-               c[1] *= rsurface.colormod[1];
-               c[2] *= rsurface.colormod[2];
-               c[3] *= rsurface.colormod[3];
+               c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
+               c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
+               c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
+               c[3] *= ent->alpha;
        }
        if (r_refdef.fogenabled)
        {
@@ -7921,10 +7940,22 @@ static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
 {
        int w, h, idx;
-       double f;
-       double offsetd[2];
+       float shadertime;
+       float f;
+       float offsetd[2];
        float tcmat[12];
        matrix4x4_t matrix, temp;
+       // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
+       // it's better to have one huge fixup every 9 hours than gradual
+       // degradation over time which looks consistently bad after many hours.
+       //
+       // tcmod scroll in particular suffers from this degradation which can't be
+       // effectively worked around even with floor() tricks because we don't
+       // know if tcmod scroll is the last tcmod being applied, and for clampmap
+       // a workaround involving floor() would be incorrect anyway...
+       shadertime = rsurface.shadertime;
+       if (shadertime >= 32768.0f)
+               shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
        switch(tcmod->tcmod)
        {
                case Q3TCMOD_COUNT:
@@ -7940,16 +7971,17 @@ static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcm
                        Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
                        break;
                case Q3TCMOD_ROTATE:
-                       f = tcmod->parms[0] * rsurface.shadertime;
                        Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
-                       Matrix4x4_ConcatRotate(&matrix, (f / 360 - floor(f / 360)) * 360, 0, 0, 1);
+                       Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
                        Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
                        break;
                case Q3TCMOD_SCALE:
                        Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
                        break;
                case Q3TCMOD_SCROLL:
-                       // extra care is needed because of precision breakdown with large values of time
+                       // this particular tcmod is a "bug for bug" compatible one with regards to
+                       // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
+                       // specifically did the wrapping and so we must mimic that...
                        offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
                        offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
                        Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
@@ -8011,10 +8043,11 @@ static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
 
 texture_t *R_GetCurrentTexture(texture_t *t)
 {
-       int i;
+       int i, q;
        const entity_render_t *ent = rsurface.entity;
        dp_model_t *model = ent->model; // when calling this, ent must not be NULL
        q3shaderinfo_layer_tcmod_t *tcmod;
+       float specularscale = 0.0f;
 
        if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
                return t->currentframe;
@@ -8045,7 +8078,9 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                {
                        // use an alternate animation if the entity's frame is not 0,
                        // and only if the texture has an alternate animation
-                       if (rsurface.ent_alttextures && t->anim_total[1])
+                       if (t->animated == 2) // q2bsp
+                               t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
+                       else if (rsurface.ent_alttextures && t->anim_total[1])
                                t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
                        else
                                t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
@@ -8067,36 +8102,124 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
                        R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
                t->currentskinframe = r_qwskincache[i].skinframe;
-               if (t->currentskinframe == NULL)
-                       t->currentskinframe = t->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->skinframerate, t->numskinframes)];
+               if (t->materialshaderpass && t->currentskinframe == NULL)
+                       t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
        }
-       else if (t->numskinframes >= 2)
-               t->currentskinframe = t->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->skinframerate, t->numskinframes)];
-       if (t->backgroundnumskinframes >= 2)
-               t->backgroundcurrentskinframe = t->backgroundskinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundskinframerate, t->backgroundnumskinframes)];
+       else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
+               t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
+       if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
+               t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
 
        t->currentmaterialflags = t->basematerialflags;
-       t->currentalpha = rsurface.colormod[3];
+       t->currentalpha = rsurface.entity->alpha * t->basealpha;
        if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer || r_trippy.integer))
                t->currentalpha *= r_wateralpha.value;
        if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
                t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
        if(!r_fb.water.enabled || r_refdef.view.isoverlay)
                t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
-       if (!(rsurface.ent_flags & RENDER_LIGHT))
-               t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
+
+       // decide on which type of lighting to use for this surface
+       if (rsurface.entity->render_modellight_forced)
+               t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
+       if (rsurface.entity->render_rtlight_disabled)
+               t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
+       if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
+       {
+               // some CUSTOMBLEND blendfuncs are too weird for anything but fullbright rendering, and even then we have to ignore colormod and view colorscale
+               t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT;
+               for (q = 0; q < 3; q++)
+               {
+                       t->render_glowmod[q] = rsurface.entity->glowmod[q];
+                       t->render_modellight_lightdir[q] = q == 2;
+                       t->render_modellight_ambient[q] = 1;
+                       t->render_modellight_diffuse[q] = 0;
+                       t->render_modellight_specular[q] = 0;
+                       t->render_lightmap_ambient[q] = 0;
+                       t->render_lightmap_diffuse[q] = 0;
+                       t->render_lightmap_specular[q] = 0;
+                       t->render_rtlight_diffuse[q] = 0;
+                       t->render_rtlight_specular[q] = 0;
+               }
+       }
+       else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
+       {
+               // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
+               t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
+               for (q = 0; q < 3; q++)
+               {
+                       t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
+                       t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
+                       t->render_modellight_lightdir[q] = q == 2;
+                       t->render_modellight_diffuse[q] = 0;
+                       t->render_modellight_specular[q] = 0;
+                       t->render_lightmap_ambient[q] = 0;
+                       t->render_lightmap_diffuse[q] = 0;
+                       t->render_lightmap_specular[q] = 0;
+                       t->render_rtlight_diffuse[q] = 0;
+                       t->render_rtlight_specular[q] = 0;
+               }
+       }
        else if (FAKELIGHT_ENABLED)
        {
                // no modellight if using fakelight for the map
+               t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT) & ~(MATERIALFLAG_MODELLIGHT);
+               for (q = 0; q < 3; q++)
+               {
+                       t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
+                       t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
+                       t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
+                       t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
+                       t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
+                       t->render_lightmap_ambient[q] = 0;
+                       t->render_lightmap_diffuse[q] = 0;
+                       t->render_lightmap_specular[q] = 0;
+                       t->render_rtlight_diffuse[q] = 0;
+                       t->render_rtlight_specular[q] = 0;
+               }
+       }
+       else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
+       {
+               // ambient + single direction light (modellight)
+               t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
+               for (q = 0; q < 3; q++)
+               {
+                       t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
+                       t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
+                       t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
+                       t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
+                       t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
+                       t->render_lightmap_ambient[q] = 0;
+                       t->render_lightmap_diffuse[q] = 0;
+                       t->render_lightmap_specular[q] = 0;
+                       t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
+                       t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
+               }
        }
-       else if ((rsurface.modeltexcoordlightmap2f == NULL || (rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT))) && !(t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
+       else
        {
-               // pick a model lighting mode
-               if (VectorLength2(rsurface.modellight_diffuse) >= (1.0f / 256.0f))
-                       t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT | MATERIALFLAG_MODELLIGHT_DIRECTIONAL;
-               else
-                       t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
+               // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
+               for (q = 0; q < 3; q++)
+               {
+                       t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
+                       t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q] * r_refdef.view.colorscale;
+                       t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
+                       t->render_modellight_diffuse[q] = 0;
+                       t->render_modellight_specular[q] = 0;
+                       t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
+                       t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
+                       t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
+                       t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
+                       t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
+               }
        }
+
+       for (q = 0; q < 3; q++)
+       {
+               t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
+               t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
+       }
+
        if (rsurface.ent_flags & RENDER_ADDITIVE)
                t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
        else if (t->currentalpha < 1)
@@ -8108,7 +8231,7 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
        if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
                t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
-       if (t->backgroundnumskinframes)
+       if (t->backgroundshaderpass)
                t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
        if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
        {
@@ -8137,12 +8260,11 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
        }
 
-       for (i = 0, tcmod = t->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
-               R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
-       for (i = 0, tcmod = t->backgroundtcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
-               R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
+       if (t->materialshaderpass)
+               for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
+                       R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
 
-       t->colormapping = VectorLength2(rsurface.colormap_pantscolor) + VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
+       t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
        if (t->currentskinframe->qpixels)
                R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
        t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
@@ -8157,8 +8279,10 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        t->glowtexture = t->currentskinframe->glow;
        t->fogtexture = t->currentskinframe->fog;
        t->reflectmasktexture = t->currentskinframe->reflect;
-       if (t->backgroundnumskinframes)
+       if (t->backgroundshaderpass)
        {
+               for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
+                       R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
                t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
                t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
                t->backgroundglosstexture = r_texture_black;
@@ -8180,7 +8304,6 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        }
        t->specularpower = r_shadow_glossexponent.value;
        // TODO: store reference values for these in the texture?
-       t->specularscale = 0;
        if (r_shadow_gloss.integer > 0)
        {
                if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
@@ -8189,20 +8312,19 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                        {
                                t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
                                t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
-                               t->specularscale = r_shadow_glossintensity.value;
+                               specularscale = r_shadow_glossintensity.value;
                        }
                }
                else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
                {
                        t->glosstexture = r_texture_white;
                        t->backgroundglosstexture = r_texture_white;
-                       t->specularscale = r_shadow_gloss2intensity.value;
+                       specularscale = r_shadow_gloss2intensity.value;
                        t->specularpower = r_shadow_gloss2exponent.value;
                }
        }
-       t->specularscale *= t->specularscalemod;
+       specularscale *= t->specularscalemod;
        t->specularpower *= t->specularpowermod;
-       t->rtlightambient = 0;
 
        // lightmaps mode looks bad with dlights using actual texturing, so turn
        // off the colormap and glossmap, but leave the normalmap on as it still
@@ -8223,12 +8345,20 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                        t->backgroundnmaptexture = r_texture_blanknormalmap;
                t->backgroundglosstexture = r_texture_black;
                t->backgroundglowtexture = NULL;
-               t->specularscale = 0;
-               t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_MODELLIGHT_DIRECTIONAL | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
+               specularscale = 0;
+               t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
+       }
+
+       if (specularscale != 1.0f)
+       {
+               for (q = 0; q < 3; q++)
+               {
+                       t->render_modellight_specular[q] *= specularscale;
+                       t->render_lightmap_specular[q] *= specularscale;
+                       t->render_rtlight_specular[q] *= specularscale;
+               }
        }
 
-       Vector4Set(t->lightmapcolor, rsurface.colormod[0], rsurface.colormod[1], rsurface.colormod[2], t->currentalpha);
-       VectorClear(t->dlightcolor);
        t->currentnumlayers = 0;
        if (t->currentmaterialflags & MATERIALFLAG_WALL)
        {
@@ -8254,54 +8384,38 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                        blendfunc1 = GL_ONE;
                        blendfunc2 = GL_ZERO;
                }
-               // don't colormod evilblend textures
-               if(!(R_BlendFuncFlags(blendfunc1, blendfunc2) & BLENDFUNC_ALLOWS_COLORMOD))
-                       VectorSet(t->lightmapcolor, 1, 1, 1);
                depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
-               if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
+               if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
                {
-                       // fullbright is not affected by r_refdef.lightmapintensity
-                       R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, t->lightmapcolor[0], t->lightmapcolor[1], t->lightmapcolor[2], t->lightmapcolor[3]);
-                       if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->pantstexture)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->pantstexture, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * t->lightmapcolor[0], rsurface.colormap_pantscolor[1] * t->lightmapcolor[1], rsurface.colormap_pantscolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
-                       if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->shirttexture)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->shirttexture, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * t->lightmapcolor[0], rsurface.colormap_shirtcolor[1] * t->lightmapcolor[1], rsurface.colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
+                       // basic lit geometry
+                       R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2], t->currentalpha);
+                       // add pants/shirt if needed
+                       if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
+                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->pantstexture, &t->currenttexmatrix, t->render_colormap_pants[0] * t->render_lightmap_diffuse[0], t->render_colormap_pants[1] * t->render_lightmap_diffuse[1], t->render_colormap_pants[2] * t->render_lightmap_diffuse[2], t->currentalpha);
+                       if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
+                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->shirttexture, &t->currenttexmatrix, t->render_colormap_shirt[0] * t->render_lightmap_diffuse[0], t->render_colormap_shirt[1] * t->render_lightmap_diffuse[1], t->render_colormap_shirt[2] * t->render_lightmap_diffuse[2], t->currentalpha);
                }
                else
                {
-                       vec3_t ambientcolor;
-                       float colorscale;
-                       // set the color tint used for lights affecting this surface
-                       VectorSet(t->dlightcolor, t->lightmapcolor[0] * t->lightmapcolor[3], t->lightmapcolor[1] * t->lightmapcolor[3], t->lightmapcolor[2] * t->lightmapcolor[3]);
-                       colorscale = 2;
-                       // q3bsp has no lightmap updates, so the lightstylevalue that
-                       // would normally be baked into the lightmap must be
-                       // applied to the color
-                       // FIXME: r_glsl 1 rendering doesn't support overbright lightstyles with this (the default light style is not overbright)
-                       if (model->type == mod_brushq3)
-                               colorscale *= r_refdef.scene.rtlightstylevalue[0];
-                       colorscale *= r_refdef.lightmapintensity;
-                       VectorScale(t->lightmapcolor, r_refdef.scene.ambient, ambientcolor);
-                       VectorScale(t->lightmapcolor, colorscale, t->lightmapcolor);
                        // basic lit geometry
-                       R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, t->lightmapcolor[0], t->lightmapcolor[1], t->lightmapcolor[2], t->lightmapcolor[3]);
+                       R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2], t->currentalpha);
                        // add pants/shirt if needed
-                       if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->pantstexture)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->pantstexture, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * t->lightmapcolor[0], rsurface.colormap_pantscolor[1] * t->lightmapcolor[1], rsurface.colormap_pantscolor[2]  * t->lightmapcolor[2], t->lightmapcolor[3]);
-                       if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->shirttexture)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->shirttexture, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * t->lightmapcolor[0], rsurface.colormap_shirtcolor[1] * t->lightmapcolor[1], rsurface.colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
+                       if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
+                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->pantstexture, &t->currenttexmatrix, t->render_colormap_pants[0] * t->render_lightmap_diffuse[0], t->render_colormap_pants[1] * t->render_lightmap_diffuse[1], t->render_colormap_pants[2]  * t->render_lightmap_diffuse[2], t->currentalpha);
+                       if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
+                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->shirttexture, &t->currenttexmatrix, t->render_colormap_shirt[0] * t->render_lightmap_diffuse[0], t->render_colormap_shirt[1] * t->render_lightmap_diffuse[1], t->render_colormap_shirt[2] * t->render_lightmap_diffuse[2], t->currentalpha);
                        // now add ambient passes if needed
-                       if (VectorLength2(ambientcolor) >= (1.0f/1048576.0f))
+                       if (VectorLength2(t->render_lightmap_ambient) >= (1.0f/1048576.0f))
                        {
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, ambientcolor[0], ambientcolor[1], ambientcolor[2], t->lightmapcolor[3]);
-                               if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->pantstexture)
-                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->pantstexture, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * ambientcolor[0], rsurface.colormap_pantscolor[1] * ambientcolor[1], rsurface.colormap_pantscolor[2] * ambientcolor[2], t->lightmapcolor[3]);
-                               if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->shirttexture)
-                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->shirttexture, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * ambientcolor[0], rsurface.colormap_shirtcolor[1] * ambientcolor[1], rsurface.colormap_shirtcolor[2] * ambientcolor[2], t->lightmapcolor[3]);
+                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2], t->currentalpha);
+                               if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
+                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->pantstexture, &t->currenttexmatrix, t->render_colormap_pants[0] * t->render_lightmap_ambient[0], t->render_colormap_pants[1] * t->render_lightmap_ambient[1], t->render_colormap_pants[2] * t->render_lightmap_ambient[2], t->currentalpha);
+                               if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
+                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->shirttexture, &t->currenttexmatrix, t->render_colormap_shirt[0] * t->render_lightmap_ambient[0], t->render_colormap_shirt[1] * t->render_lightmap_ambient[1], t->render_colormap_shirt[2] * t->render_lightmap_ambient[2], t->currentalpha);
                        }
                }
                if (t->glowtexture != NULL && !gl_lightmaps.integer)
-                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->glowtexture, &t->currenttexmatrix, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2], t->lightmapcolor[3]);
+                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->glowtexture, &t->currenttexmatrix, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2], t->currentalpha);
                if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
                {
                        // if this is opaque use alpha blend which will darken the earlier
@@ -8315,144 +8429,15 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                        // were darkened by fog already, and we should not add fog color
                        // (because the background was not darkened, there is no fog color
                        // that was lost behind it).
-                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_BLENDED) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->fogtexture, &t->currenttexmatrix, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], t->lightmapcolor[3]);
+                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_BLENDED) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->fogtexture, &t->currenttexmatrix, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], t->currentalpha);
                }
        }
 
-       return t->currentframe;
+       return t;
 }
 
 rsurfacestate_t rsurface;
 
-void RSurf_ActiveWorldEntity(void)
-{
-       dp_model_t *model = r_refdef.scene.worldmodel;
-       //if (rsurface.entity == r_refdef.scene.worldentity)
-       //      return;
-       rsurface.entity = r_refdef.scene.worldentity;
-       rsurface.skeleton = NULL;
-       memset(rsurface.userwavefunc_param, 0, sizeof(rsurface.userwavefunc_param));
-       rsurface.ent_skinnum = 0;
-       rsurface.ent_qwskin = -1;
-       rsurface.ent_flags = r_refdef.scene.worldentity->flags;
-       rsurface.shadertime = r_refdef.scene.time;
-       rsurface.matrix = identitymatrix;
-       rsurface.inversematrix = identitymatrix;
-       rsurface.matrixscale = 1;
-       rsurface.inversematrixscale = 1;
-       R_EntityMatrix(&identitymatrix);
-       VectorCopy(r_refdef.view.origin, rsurface.localvieworigin);
-       Vector4Copy(r_refdef.fogplane, rsurface.fogplane);
-       rsurface.fograngerecip = r_refdef.fograngerecip;
-       rsurface.fogheightfade = r_refdef.fogheightfade;
-       rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist;
-       rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
-       VectorSet(rsurface.modellight_ambient, 0, 0, 0);
-       VectorSet(rsurface.modellight_diffuse, 0, 0, 0);
-       VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
-       VectorSet(rsurface.colormap_pantscolor, 0, 0, 0);
-       VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0);
-       VectorSet(rsurface.colormod, r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale);
-       rsurface.colormod[3] = 1;
-       VectorSet(rsurface.glowmod, r_refdef.view.colorscale * r_hdr_glowintensity.value, r_refdef.view.colorscale * r_hdr_glowintensity.value, r_refdef.view.colorscale * r_hdr_glowintensity.value);
-       memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
-       rsurface.frameblend[0].lerp = 1;
-       rsurface.ent_alttextures = false;
-       rsurface.basepolygonfactor = r_refdef.polygonfactor;
-       rsurface.basepolygonoffset = r_refdef.polygonoffset;
-       rsurface.entityskeletaltransform3x4 = NULL;
-       rsurface.entityskeletaltransform3x4buffer = NULL;
-       rsurface.entityskeletaltransform3x4offset = 0;
-       rsurface.entityskeletaltransform3x4size = 0;;
-       rsurface.entityskeletalnumtransforms = 0;
-       rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
-       rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
-       rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
-       rsurface.modelsvector3f = model->surfmesh.data_svector3f;
-       rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
-       rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
-       rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
-       rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
-       rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
-       rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
-       rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
-       rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
-       rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
-       rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
-       rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
-       rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
-       rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
-       rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
-       rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
-       rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
-       rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
-       rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
-       rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
-       rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub;
-       rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
-       rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
-       rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub;
-       rsurface.modelelement3i = model->surfmesh.data_element3i;
-       rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
-       rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
-       rsurface.modelelement3s = model->surfmesh.data_element3s;
-       rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
-       rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
-       rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
-       rsurface.modelnumvertices = model->surfmesh.num_vertices;
-       rsurface.modelnumtriangles = model->surfmesh.num_triangles;
-       rsurface.modelsurfaces = model->data_surfaces;
-       rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh;
-       rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
-       rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f;
-       rsurface.modelgeneratedvertex = false;
-       rsurface.batchgeneratedvertex = false;
-       rsurface.batchfirstvertex = 0;
-       rsurface.batchnumvertices = 0;
-       rsurface.batchfirsttriangle = 0;
-       rsurface.batchnumtriangles = 0;
-       rsurface.batchvertex3f  = NULL;
-       rsurface.batchvertex3f_vertexbuffer = NULL;
-       rsurface.batchvertex3f_bufferoffset = 0;
-       rsurface.batchsvector3f = NULL;
-       rsurface.batchsvector3f_vertexbuffer = NULL;
-       rsurface.batchsvector3f_bufferoffset = 0;
-       rsurface.batchtvector3f = NULL;
-       rsurface.batchtvector3f_vertexbuffer = NULL;
-       rsurface.batchtvector3f_bufferoffset = 0;
-       rsurface.batchnormal3f  = NULL;
-       rsurface.batchnormal3f_vertexbuffer = NULL;
-       rsurface.batchnormal3f_bufferoffset = 0;
-       rsurface.batchlightmapcolor4f = NULL;
-       rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
-       rsurface.batchlightmapcolor4f_bufferoffset = 0;
-       rsurface.batchtexcoordtexture2f = NULL;
-       rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-       rsurface.batchtexcoordtexture2f_bufferoffset = 0;
-       rsurface.batchtexcoordlightmap2f = NULL;
-       rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
-       rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
-       rsurface.batchskeletalindex4ub = NULL;
-       rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
-       rsurface.batchskeletalindex4ub_bufferoffset = 0;
-       rsurface.batchskeletalweight4ub = NULL;
-       rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
-       rsurface.batchskeletalweight4ub_bufferoffset = 0;
-       rsurface.batchvertexmesh = NULL;
-       rsurface.batchvertexmesh_vertexbuffer = NULL;
-       rsurface.batchvertexmesh_bufferoffset = 0;
-       rsurface.batchelement3i = NULL;
-       rsurface.batchelement3i_indexbuffer = NULL;
-       rsurface.batchelement3i_bufferoffset = 0;
-       rsurface.batchelement3s = NULL;
-       rsurface.batchelement3s_indexbuffer = NULL;
-       rsurface.batchelement3s_bufferoffset = 0;
-       rsurface.passcolor4f = NULL;
-       rsurface.passcolor4f_vertexbuffer = NULL;
-       rsurface.passcolor4f_bufferoffset = 0;
-       rsurface.forcecurrenttextureupdate = false;
-}
-
 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
 {
        dp_model_t *model = ent->model;
@@ -8464,6 +8449,8 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        rsurface.ent_skinnum = ent->skinnum;
        rsurface.ent_qwskin = (ent->entitynumber <= cl.maxclients && ent->entitynumber >= 1 && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[ent->entitynumber - 1].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl")) ? (ent->entitynumber - 1) : -1;
        rsurface.ent_flags = ent->flags;
+       if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
+               rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
        rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
        rsurface.matrix = ent->matrix;
        rsurface.inversematrix = ent->inversematrix;
@@ -8472,18 +8459,10 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        R_EntityMatrix(&rsurface.matrix);
        Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
        Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
-       rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
+       rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
        rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
        rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
        rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
-       VectorCopy(ent->modellight_ambient, rsurface.modellight_ambient);
-       VectorCopy(ent->modellight_diffuse, rsurface.modellight_diffuse);
-       VectorCopy(ent->modellight_lightdir, rsurface.modellight_lightdir);
-       VectorCopy(ent->colormap_pantscolor, rsurface.colormap_pantscolor);
-       VectorCopy(ent->colormap_shirtcolor, rsurface.colormap_shirtcolor);
-       VectorScale(ent->colormod, r_refdef.view.colorscale, rsurface.colormod);
-       rsurface.colormod[3] = ent->alpha;
-       VectorScale(ent->glowmod, r_refdef.view.colorscale * r_hdr_glowintensity.value, rsurface.glowmod);
        memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
        rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
        rsurface.basepolygonfactor = r_refdef.polygonfactor;
@@ -8726,13 +8705,6 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve
        rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
        rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
        rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
-       VectorSet(rsurface.modellight_ambient, 0, 0, 0);
-       VectorSet(rsurface.modellight_diffuse, 0, 0, 0);
-       VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
-       VectorSet(rsurface.colormap_pantscolor, 0, 0, 0);
-       VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0);
-       Vector4Set(rsurface.colormod, r * r_refdef.view.colorscale, g * r_refdef.view.colorscale, b * r_refdef.view.colorscale, a);
-       VectorSet(rsurface.glowmod, r_refdef.view.colorscale * r_hdr_glowintensity.value, r_refdef.view.colorscale * r_hdr_glowintensity.value, r_refdef.view.colorscale * r_hdr_glowintensity.value);
        memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
        rsurface.frameblend[0].lerp = 1;
        rsurface.ent_alttextures = false;
@@ -8928,7 +8900,6 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
        qboolean dynamicvertex;
        float amplitude;
        float animpos;
-       float scale;
        float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
        float waveparms[4];
        unsigned char *ub;
@@ -9102,60 +9073,63 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                        break;
                }
        }
-       switch(rsurface.texture->tcgen.tcgen)
+       if (rsurface.texture->materialshaderpass)
        {
-       default:
-       case Q3TCGEN_TEXTURE:
-               break;
-       case Q3TCGEN_LIGHTMAP:
-               if (!dynamicvertex)
-               {
-                       r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
-                       r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
-                       r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
-                       r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
-               }
-               dynamicvertex = true;
-               batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
-               needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
-               break;
-       case Q3TCGEN_VECTOR:
-               if (!dynamicvertex)
+               switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
                {
-                       r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
-                       r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
-                       r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
-                       r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
-               }
-               dynamicvertex = true;
-               batchneed |= BATCHNEED_ARRAY_VERTEX;
-               needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
-               break;
-       case Q3TCGEN_ENVIRONMENT:
-               if (!dynamicvertex)
-               {
-                       r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
-                       r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
-                       r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
-                       r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
+               default:
+               case Q3TCGEN_TEXTURE:
+                       break;
+               case Q3TCGEN_LIGHTMAP:
+                       if (!dynamicvertex)
+                       {
+                               r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
+                               r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
+                               r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
+                               r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
+                       }
+                       dynamicvertex = true;
+                       batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
+                       needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
+                       break;
+               case Q3TCGEN_VECTOR:
+                       if (!dynamicvertex)
+                       {
+                               r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
+                               r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
+                               r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
+                               r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
+                       }
+                       dynamicvertex = true;
+                       batchneed |= BATCHNEED_ARRAY_VERTEX;
+                       needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
+                       break;
+               case Q3TCGEN_ENVIRONMENT:
+                       if (!dynamicvertex)
+                       {
+                               r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
+                               r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
+                               r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
+                               r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
+                       }
+                       dynamicvertex = true;
+                       batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
+                       needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
+                       break;
                }
-               dynamicvertex = true;
-               batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
-               needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
-               break;
-       }
-       if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
-       {
-               if (!dynamicvertex)
+               if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
                {
-                       r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
-                       r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
-                       r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
-                       r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
+                       if (!dynamicvertex)
+                       {
+                               r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
+                               r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
+                               r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
+                               r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
+                       }
+                       dynamicvertex = true;
+                       batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
+                       needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
                }
-               dynamicvertex = true;
-               batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
-               needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
        }
 
        if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
@@ -9336,12 +9310,12 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                                        rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
                        }
                        // upload buffer data for the copytriangles batch
-                       if (vid.forcevbo || (r_batch_dynamicbuffer.integer && vid.support.arb_vertex_buffer_object))
+                       if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
                        {
                                if (rsurface.batchelement3s)
-                                       rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset, !vid.forcevbo);
+                                       rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
                                else if (rsurface.batchelement3i)
-                                       rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset, !vid.forcevbo);
+                                       rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
                        }
                }
                else
@@ -9726,6 +9700,7 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
        // in place
        for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
        {
+               float scale;
                switch (deform->deform)
                {
                default:
@@ -9997,77 +9972,80 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                }
        }
 
-       // generate texcoords based on the chosen texcoord source
-       switch(rsurface.texture->tcgen.tcgen)
+       if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
        {
-       default:
-       case Q3TCGEN_TEXTURE:
-               break;
-       case Q3TCGEN_LIGHTMAP:
-//             rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
-//             rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-//             rsurface.batchtexcoordtexture2f_bufferoffset = 0;
-               if (rsurface.batchtexcoordlightmap2f)
-                       memcpy(rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordtexture2f, batchnumvertices * sizeof(float[2]));
-               break;
-       case Q3TCGEN_VECTOR:
-//             rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
-//             rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-//             rsurface.batchtexcoordtexture2f_bufferoffset = 0;
-               for (j = 0;j < batchnumvertices;j++)
-               {
-                       rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms);
-                       rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms + 3);
-               }
-               break;
-       case Q3TCGEN_ENVIRONMENT:
-               // make environment reflections using a spheremap
-               rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
-               rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-               rsurface.batchtexcoordtexture2f_bufferoffset = 0;
-               for (j = 0;j < batchnumvertices;j++)
+       // generate texcoords based on the chosen texcoord source
+               switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
                {
-                       // identical to Q3A's method, but executed in worldspace so
-                       // carried models can be shiny too
+               default:
+               case Q3TCGEN_TEXTURE:
+                       break;
+               case Q3TCGEN_LIGHTMAP:
+       //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
+       //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
+       //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+                       if (rsurface.batchtexcoordlightmap2f)
+                               memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
+                       break;
+               case Q3TCGEN_VECTOR:
+       //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
+       //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
+       //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+                       for (j = 0;j < batchnumvertices;j++)
+                       {
+                               rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
+                               rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
+                       }
+                       break;
+               case Q3TCGEN_ENVIRONMENT:
+                       // make environment reflections using a spheremap
+                       rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
+                       rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
+                       rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+                       for (j = 0;j < batchnumvertices;j++)
+                       {
+                               // identical to Q3A's method, but executed in worldspace so
+                               // carried models can be shiny too
 
-                       float viewer[3], d, reflected[3], worldreflected[3];
+                               float viewer[3], d, reflected[3], worldreflected[3];
 
-                       VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
-                       // VectorNormalize(viewer);
+                               VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
+                               // VectorNormalize(viewer);
 
-                       d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
+                               d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
 
-                       reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
-                       reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
-                       reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
-                       // note: this is proportinal to viewer, so we can normalize later
+                               reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
+                               reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
+                               reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
+                               // note: this is proportinal to viewer, so we can normalize later
 
-                       Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
-                       VectorNormalize(worldreflected);
+                               Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
+                               VectorNormalize(worldreflected);
 
-                       // note: this sphere map only uses world x and z!
-                       // so positive and negative y will LOOK THE SAME.
-                       rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
-                       rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
+                               // note: this sphere map only uses world x and z!
+                               // so positive and negative y will LOOK THE SAME.
+                               rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
+                               rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
+                       }
+                       break;
                }
-               break;
-       }
-       // the only tcmod that needs software vertex processing is turbulent, so
-       // check for it here and apply the changes if needed
-       // and we only support that as the first one
-       // (handling a mixture of turbulent and other tcmods would be problematic
-       //  without punting it entirely to a software path)
-       if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
-       {
-               amplitude = rsurface.texture->tcmods[0].parms[1];
-               animpos = rsurface.texture->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->tcmods[0].parms[3];
-//             rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
-//             rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-//             rsurface.batchtexcoordtexture2f_bufferoffset = 0;
-               for (j = 0;j < batchnumvertices;j++)
-               {
-                       rsurface.batchtexcoordtexture2f[j*2+0] += amplitude * sin(((rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
-                       rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
+               // the only tcmod that needs software vertex processing is turbulent, so
+               // check for it here and apply the changes if needed
+               // and we only support that as the first one
+               // (handling a mixture of turbulent and other tcmods would be problematic
+               //  without punting it entirely to a software path)
+               if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
+               {
+                       amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
+                       animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
+       //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
+       //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
+       //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+                       for (j = 0;j < batchnumvertices;j++)
+                       {
+                               rsurface.batchtexcoordtexture2f[j*2+0] += amplitude * sin(((rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
+                               rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
+                       }
                }
        }
 
@@ -10111,35 +10089,35 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
        }
 
        // upload buffer data for the dynamic batch
-       if (vid.forcevbo || (r_batch_dynamicbuffer.integer && vid.support.arb_vertex_buffer_object))
+       if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicvertex.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
        {
                if (rsurface.batchvertexmesh)
-                       rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset, !vid.forcevbo);
+                       rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset);
                else
                {
                        if (rsurface.batchvertex3f)
-                               rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset, !vid.forcevbo);
+                               rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
                        if (rsurface.batchsvector3f)
-                               rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset, !vid.forcevbo);
+                               rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
                        if (rsurface.batchtvector3f)
-                               rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset, !vid.forcevbo);
+                               rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
                        if (rsurface.batchnormal3f)
-                               rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset, !vid.forcevbo);
-                       if (rsurface.batchlightmapcolor4f && r_batch_dynamicbuffer.integer && vid.support.arb_vertex_buffer_object)
-                               rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset, !vid.forcevbo);
-                       if (rsurface.batchtexcoordtexture2f && r_batch_dynamicbuffer.integer && vid.support.arb_vertex_buffer_object)
-                               rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset, !vid.forcevbo);
-                       if (rsurface.batchtexcoordlightmap2f && r_batch_dynamicbuffer.integer && vid.support.arb_vertex_buffer_object)
-                               rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset, !vid.forcevbo);
+                               rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
+                       if (rsurface.batchlightmapcolor4f)
+                               rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
+                       if (rsurface.batchtexcoordtexture2f)
+                               rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
+                       if (rsurface.batchtexcoordlightmap2f)
+                               rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
                        if (rsurface.batchskeletalindex4ub)
-                               rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset, !vid.forcevbo);
+                               rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
                        if (rsurface.batchskeletalweight4ub)
-                               rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset, !vid.forcevbo);
+                               rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
                }
                if (rsurface.batchelement3s)
-                       rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset, !vid.forcevbo);
+                       rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
                else if (rsurface.batchelement3i)
-                       rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset, !vid.forcevbo);
+                       rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
        }
 }
 
@@ -10347,9 +10325,9 @@ static void RSurf_DrawBatch_GL11_ApplyAmbient(void)
        rsurface.passcolor4f_bufferoffset = 0;
        for (i = 0, c2 = rsurface.passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, c += 4, c2 += 4)
        {
-               c2[0] = c[0] + r_refdef.scene.ambient;
-               c2[1] = c[1] + r_refdef.scene.ambient;
-               c2[2] = c[2] + r_refdef.scene.ambient;
+               c2[0] = c[0] + rsurface.texture->render_lightmap_ambient[0];
+               c2[1] = c[1] + rsurface.texture->render_lightmap_ambient[1];
+               c2[2] = c[2] + rsurface.texture->render_lightmap_ambient[2];
                c2[3] = c[3];
        }
 }
@@ -10413,7 +10391,7 @@ static void RSurf_DrawBatch_GL11_ClampColor(void)
        }
 }
 
-static void RSurf_DrawBatch_GL11_ApplyFakeLight(void)
+static void RSurf_DrawBatch_GL11_ApplyFakeLight(float fakelightintensity)
 {
        int i;
        float f;
@@ -10431,14 +10409,14 @@ static void RSurf_DrawBatch_GL11_ApplyFakeLight(void)
                f = -DotProduct(r_refdef.view.forward, n);
                f = max(0, f);
                f = f * 0.85 + 0.15; // work around so stuff won't get black
-               f *= r_refdef.lightmapintensity;
+               f *= fakelightintensity;
                Vector4Set(c, f, f, f, 1);
        }
 }
 
 static void RSurf_DrawBatch_GL11_FakeLight(float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
 {
-       RSurf_DrawBatch_GL11_ApplyFakeLight();
+       RSurf_DrawBatch_GL11_ApplyFakeLight(r_refdef.scene.lightmapintensity * r_fakelight_intensity.value);
        if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog();
        if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(r, g, b, a);
        R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset);
@@ -10446,7 +10424,7 @@ static void RSurf_DrawBatch_GL11_FakeLight(float r, float g, float b, float a, q
        RSurf_DrawBatch();
 }
 
-static void RSurf_DrawBatch_GL11_ApplyVertexShade(float *r, float *g, float *b, float *a, qboolean *applycolor)
+static void RSurf_DrawBatch_GL11_ApplyVertexShade(float *r, float *g, float *b, float *a, float lightmapintensity, qboolean *applycolor)
 {
        int i;
        float f;
@@ -10459,14 +10437,14 @@ static void RSurf_DrawBatch_GL11_ApplyVertexShade(float *r, float *g, float *b,
        vec3_t lightdir;
        // TODO: optimize
        // model lighting
-       VectorCopy(rsurface.modellight_lightdir, lightdir);
-       f = 0.5f * r_refdef.lightmapintensity;
-       ambientcolor[0] = rsurface.modellight_ambient[0] * *r * f;
-       ambientcolor[1] = rsurface.modellight_ambient[1] * *g * f;
-       ambientcolor[2] = rsurface.modellight_ambient[2] * *b * f;
-       diffusecolor[0] = rsurface.modellight_diffuse[0] * *r * f;
-       diffusecolor[1] = rsurface.modellight_diffuse[1] * *g * f;
-       diffusecolor[2] = rsurface.modellight_diffuse[2] * *b * f;
+       VectorCopy(rsurface.texture->render_modellight_lightdir, lightdir);
+       f = 0.5f * lightmapintensity;
+       ambientcolor[0] = rsurface.texture->render_modellight_ambient[0] * *r * f;
+       ambientcolor[1] = rsurface.texture->render_modellight_ambient[1] * *g * f;
+       ambientcolor[2] = rsurface.texture->render_modellight_ambient[2] * *b * f;
+       diffusecolor[0] = rsurface.texture->render_modellight_diffuse[0] * *r * f;
+       diffusecolor[1] = rsurface.texture->render_modellight_diffuse[1] * *g * f;
+       diffusecolor[2] = rsurface.texture->render_modellight_diffuse[2] * *b * f;
        alpha = *a;
        if (VectorLength2(diffusecolor) > 0)
        {
@@ -10501,7 +10479,7 @@ static void RSurf_DrawBatch_GL11_ApplyVertexShade(float *r, float *g, float *b,
 
 static void RSurf_DrawBatch_GL11_VertexShade(float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
 {
-       RSurf_DrawBatch_GL11_ApplyVertexShade(&r, &g, &b, &a, &applycolor);
+       RSurf_DrawBatch_GL11_ApplyVertexShade(&r, &g, &b, &a, r_refdef.scene.lightmapintensity, &applycolor);
        if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog();
        if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(r, g, b, a);
        R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset);
@@ -10557,7 +10535,7 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_
        // in Quake3 maps as it causes problems with q3map2 sky tricks,
        // and skymasking also looks very bad when noclipping outside the
        // level, so don't use it then either.
-       if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_refdef.viewcache.world_novis && !r_trippy.integer)
+       if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.skymasking && r_q1bsp_skymasking.integer && !r_refdef.viewcache.world_novis && !r_trippy.integer)
        {
                R_Mesh_ResetTextureState();
                if (skyrendermasked)
@@ -10598,7 +10576,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface
        {
                // render screenspace normalmap to texture
                GL_DepthMask(true);
-               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
+               R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
                RSurf_DrawBatch();
                return;
        }
@@ -10626,18 +10604,18 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface
                        {
                                // render water or distortion background
                                GL_DepthMask(true);
-                               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
+                               R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
                                RSurf_DrawBatch();
                                // blend surface on top
                                GL_DepthMask(false);
-                               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
+                               R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
                                RSurf_DrawBatch();
                        }
                        else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
                        {
                                // render surface with reflection texture as input
                                GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
-                               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
+                               R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
                                RSurf_DrawBatch();
                        }
                }
@@ -10646,7 +10624,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface
 
        // render surface batch normally
        GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
-       R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0);
+       R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0);
        RSurf_DrawBatch();
 }
 
@@ -10657,7 +10635,7 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface
        qboolean applyfog;
        int layerindex;
        const texturelayer_t *layer;
-       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | ((!rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.modeltexcoordlightmap2f ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
+       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | ((!rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)) ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.modeltexcoordlightmap2f ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
        R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
 
        for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
@@ -10764,7 +10742,7 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
        qboolean applyfog;
        int layerindex;
        const texturelayer_t *layer;
-       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | ((!rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.modeltexcoordlightmap2f ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
+       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | ((!rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)) ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.modeltexcoordlightmap2f ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
        R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
 
        for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
@@ -10869,14 +10847,15 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const
        int j;
        r_vertexgeneric_t *batchvertex;
        float c[4];
+       texture_t *t = rsurface.texture;
 
 //     R_Mesh_ResetTextureState();
        R_SetupShader_Generic_NoTexture(false, false);
 
-       if(rsurface.texture && rsurface.texture->currentskinframe)
+       if(t && t->currentskinframe)
        {
-               memcpy(c, rsurface.texture->currentskinframe->avgcolor, sizeof(c));
-               c[3] *= rsurface.texture->currentalpha;
+               memcpy(c, t->currentskinframe->avgcolor, sizeof(c));
+               c[3] *= t->currentalpha;
        }
        else
        {
@@ -10886,11 +10865,11 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const
                c[3] = 1;
        }
 
-       if (rsurface.texture->pantstexture || rsurface.texture->shirttexture)
+       if (t->pantstexture || t->shirttexture)
        {
-               c[0] = 0.5 * (rsurface.colormap_pantscolor[0] * 0.3 + rsurface.colormap_shirtcolor[0] * 0.7);
-               c[1] = 0.5 * (rsurface.colormap_pantscolor[1] * 0.3 + rsurface.colormap_shirtcolor[1] * 0.7);
-               c[2] = 0.5 * (rsurface.colormap_pantscolor[2] * 0.3 + rsurface.colormap_shirtcolor[2] * 0.7);
+               c[0] = 0.5 * (t->render_colormap_pants[0] * 0.3 + t->render_colormap_shirt[0] * 0.7);
+               c[1] = 0.5 * (t->render_colormap_pants[1] * 0.3 + t->render_colormap_shirt[1] * 0.7);
+               c[2] = 0.5 * (t->render_colormap_pants[2] * 0.3 + t->render_colormap_shirt[2] * 0.7);
        }
 
        // brighten it up (as texture value 127 means "unlit")
@@ -10898,27 +10877,27 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const
        c[1] *= 2 * r_refdef.view.colorscale;
        c[2] *= 2 * r_refdef.view.colorscale;
 
-       if(rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERALPHA)
+       if(t->currentmaterialflags & MATERIALFLAG_WATERALPHA)
                c[3] *= r_wateralpha.value;
 
-       if(rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHA && c[3] != 1)
+       if(t->currentmaterialflags & MATERIALFLAG_ALPHA && c[3] != 1)
        {
                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                GL_DepthMask(false);
        }
-       else if(rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD)
+       else if(t->currentmaterialflags & MATERIALFLAG_ADD)
        {
                GL_BlendFunc(GL_ONE, GL_ONE);
                GL_DepthMask(false);
        }
-       else if(rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
+       else if(t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
        {
                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // can't do alpha test without texture, so let's blend instead
                GL_DepthMask(false);
        }
-       else if(rsurface.texture->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
+       else if(t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
        {
-               GL_BlendFunc(rsurface.texture->customblendfunc[0], rsurface.texture->customblendfunc[1]);
+               GL_BlendFunc(t->customblendfunc[0], t->customblendfunc[1]);
                GL_DepthMask(false);
        }
        else
@@ -10931,32 +10910,20 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const
        {
                rsurface.passcolor4f = NULL;
 
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
-               {
-                       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
-
-                       rsurface.passcolor4f = NULL;
-                       rsurface.passcolor4f_vertexbuffer = 0;
-                       rsurface.passcolor4f_bufferoffset = 0;
-               }
-               else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
+               if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
                {
                        qboolean applycolor = true;
                        float one = 1.0;
 
                        RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
 
-                       r_refdef.lightmapintensity = 1;
-                       RSurf_DrawBatch_GL11_ApplyVertexShade(&one, &one, &one, &one, &applycolor);
-                       r_refdef.lightmapintensity = 0; // we're in showsurfaces, after all
+                       RSurf_DrawBatch_GL11_ApplyVertexShade(&one, &one, &one, &one, 1.0f, &applycolor);
                }
                else if (FAKELIGHT_ENABLED)
                {
                        RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
 
-                       r_refdef.lightmapintensity = r_fakelight_intensity.value;
-                       RSurf_DrawBatch_GL11_ApplyFakeLight();
-                       r_refdef.lightmapintensity = 0; // we're in showsurfaces, after all
+                       RSurf_DrawBatch_GL11_ApplyFakeLight(r_fakelight_intensity.value);
                }
                else
                {
@@ -10965,12 +10932,12 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const
                        rsurface.passcolor4f = rsurface.batchlightmapcolor4f;
                        rsurface.passcolor4f_vertexbuffer = rsurface.batchlightmapcolor4f_vertexbuffer;
                        rsurface.passcolor4f_bufferoffset = rsurface.batchlightmapcolor4f_bufferoffset;
+                       RSurf_DrawBatch_GL11_ApplyAmbient();
                }
 
                if(!rsurface.passcolor4f)
                        RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray();
 
-               RSurf_DrawBatch_GL11_ApplyAmbient();
                RSurf_DrawBatch_GL11_ApplyColor(c[0], c[1], c[2], c[3]);
                if(r_refdef.fogenabled)
                        RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors();
@@ -10998,9 +10965,9 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const
                batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
                for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
                {
-                       unsigned char c = (vi << 3) * (1.0f / 256.0f);
+                       unsigned char d = (vi << 3) * (1.0f / 256.0f);
                        VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
-                       Vector4Set(batchvertex[vi].color4f, c, c, c, 1);
+                       Vector4Set(batchvertex[vi].color4f, d, d, d, 1);
                }
                R_Mesh_PrepareVertices_Generic_Unlock();
                RSurf_DrawBatch();
@@ -11012,13 +10979,13 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const
                batchvertex = R_Mesh_PrepareVertices_Generic_Lock(3*rsurface.batchnumtriangles);
                for (j = 0, e = rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle;j < rsurface.batchnumtriangles;j++, e += 3)
                {
-                       unsigned char c = ((j + rsurface.batchfirsttriangle) << 3) * (1.0f / 256.0f);
+                       unsigned char d = ((j + rsurface.batchfirsttriangle) << 3) * (1.0f / 256.0f);
                        VectorCopy(rsurface.batchvertex3f + 3*e[0], batchvertex[j*3+0].vertex3f);
                        VectorCopy(rsurface.batchvertex3f + 3*e[1], batchvertex[j*3+1].vertex3f);
                        VectorCopy(rsurface.batchvertex3f + 3*e[2], batchvertex[j*3+2].vertex3f);
-                       Vector4Set(batchvertex[j*3+0].color4f, c, c, c, 1);
-                       Vector4Set(batchvertex[j*3+1].color4f, c, c, c, 1);
-                       Vector4Set(batchvertex[j*3+2].color4f, c, c, c, 1);
+                       Vector4Set(batchvertex[j*3+0].color4f, d, d, d, 1);
+                       Vector4Set(batchvertex[j*3+1].color4f, d, d, d, 1);
+                       Vector4Set(batchvertex[j*3+2].color4f, d, d, d, 1);
                }
                R_Mesh_PrepareVertices_Generic_Unlock();
                R_Mesh_Draw(0, rsurface.batchnumtriangles*3, 0, rsurface.batchnumtriangles, NULL, NULL, 0, NULL, NULL, 0);
@@ -11049,36 +11016,6 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const
        }
 }
 
-static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
-{
-       CHECKGLERROR
-       RSurf_SetupDepthAndCulling();
-       if (r_showsurfaces.integer)
-       {
-               R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
-               return;
-       }
-       switch (vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_D3D9:
-       case RENDERPATH_D3D10:
-       case RENDERPATH_D3D11:
-       case RENDERPATH_SOFT:
-       case RENDERPATH_GLES2:
-               R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
-               break;
-       case RENDERPATH_GL13:
-       case RENDERPATH_GLES1:
-               R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist, writedepth);
-               break;
-       case RENDERPATH_GL11:
-               R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist, writedepth);
-               break;
-       }
-       CHECKGLERROR
-}
-
 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
 {
        CHECKGLERROR
@@ -11117,12 +11054,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
        const msurface_t *surface;
        const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
 
-       // if the model is static it doesn't matter what value we give for
-       // wantnormals and wanttangents, so this logic uses only rules applicable
-       // to a model, knowing that they are meaningless otherwise
-       if (ent == r_refdef.scene.worldentity)
-               RSurf_ActiveWorldEntity();
-       else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
+       if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
                RSurf_ActiveModelEntity(ent, false, false, false);
        else
        {
@@ -11227,12 +11159,9 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
                        }
                }
                // render the range of surfaces
-               if (ent == r_refdef.scene.worldentity)
-                       R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
-               else
-                       R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
+               R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
        }
-       rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
+       rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
 }
 
 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
@@ -11280,84 +11209,6 @@ static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msu
        RSurf_DrawBatch();
 }
 
-static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
-{
-       CHECKGLERROR
-       if (depthonly)
-               R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
-       else if (prepass)
-       {
-               if (!rsurface.texture->currentnumlayers)
-                       return;
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
-                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
-               else
-                       R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
-       }
-       else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
-               R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
-       else if (!rsurface.texture->currentnumlayers)
-               return;
-       else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
-       {
-               // in the deferred case, transparent surfaces were queued during prepass
-               if (!r_shadow_usingdeferredprepass)
-                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
-       }
-       else
-       {
-               // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
-               R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
-       }
-       CHECKGLERROR
-}
-
-static void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
-{
-       int i, j;
-       texture_t *texture;
-       R_FrameData_SetMark();
-       // break the surface list down into batches by texture and use of lightmapping
-       for (i = 0;i < numsurfaces;i = j)
-       {
-               j = i + 1;
-               // texture is the base texture pointer, rsurface.texture is the
-               // current frame/skin the texture is directing us to use (for example
-               // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
-               // use skin 1 instead)
-               texture = surfacelist[i]->texture;
-               rsurface.texture = R_GetCurrentTexture(texture);
-               if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
-               {
-                       // if this texture is not the kind we want, skip ahead to the next one
-                       for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
-                               ;
-                       continue;
-               }
-               if(FAKELIGHT_ENABLED || depthonly || prepass)
-               {
-                       rsurface.lightmaptexture = NULL;
-                       rsurface.deluxemaptexture = NULL;
-                       rsurface.uselightmaptexture = false;
-                       // simply scan ahead until we find a different texture or lightmap state
-                       for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
-                               ;
-               }
-               else
-               {
-                       rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
-                       rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
-                       rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
-                       // simply scan ahead until we find a different texture or lightmap state
-                       for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
-                               ;
-               }
-               // render the range of surfaces
-               R_ProcessWorldTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
-       }
-       R_FrameData_ReturnToMark();
-}
-
 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
 {
        CHECKGLERROR
@@ -11519,7 +11370,7 @@ void R_DecalSystem_Reset(decalsystem_t *decalsystem)
        memset(decalsystem, 0, sizeof(*decalsystem));
 }
 
-static void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, const float *v1, const float *v2, const float *t0, const float *t1, const float *t2, const float *c0, const float *c1, const float *c2, int triangleindex, int surfaceindex, int decalsequence)
+static void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, const float *v1, const float *v2, const float *t0, const float *t1, const float *t2, const float *c0, const float *c1, const float *c2, int triangleindex, int surfaceindex, unsigned int decalsequence)
 {
        tridecal_t *decal;
        tridecal_t *decals;
@@ -11599,7 +11450,7 @@ extern cvar_t cl_decals_bias;
 extern cvar_t cl_decals_models;
 extern cvar_t cl_decals_newsystem_intensitymultiplier;
 // baseparms, parms, temps
-static void R_DecalSystem_SplatTriangle(decalsystem_t *decalsystem, float r, float g, float b, float a, float s1, float t1, float s2, float t2, int decalsequence, qboolean dynamic, float (*planes)[4], matrix4x4_t *projection, int triangleindex, int surfaceindex)
+static void R_DecalSystem_SplatTriangle(decalsystem_t *decalsystem, float r, float g, float b, float a, float s1, float t1, float s2, float t2, unsigned int decalsequence, qboolean dynamic, float (*planes)[4], matrix4x4_t *projection, int triangleindex, int surfaceindex)
 {
        int cornerindex;
        int index;
@@ -11692,7 +11543,7 @@ static void R_DecalSystem_SplatTriangle(decalsystem_t *decalsystem, float r, flo
                for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
                        R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[cornerindex+1], v[cornerindex+2], tc[0], tc[cornerindex+1], tc[cornerindex+2], c[0], c[cornerindex+1], c[cornerindex+2], -1, surfaceindex, decalsequence);
 }
-static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, int decalsequence)
+static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, unsigned int decalsequence)
 {
        matrix4x4_t projection;
        decalsystem_t *decalsystem;
@@ -11853,7 +11704,7 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor
 }
 
 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
-static void R_DecalSystem_ApplySplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, int decalsequence)
+static void R_DecalSystem_ApplySplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, unsigned int decalsequence)
 {
        int renderentityindex;
        float worldmins[3];
@@ -11889,7 +11740,7 @@ typedef struct r_decalsystem_splatqueue_s
        float color[4];
        float tcrange[4];
        float worldsize;
-       int decalsequence;
+       unsigned int decalsequence;
 }
 r_decalsystem_splatqueue_t;
 
@@ -11928,7 +11779,7 @@ static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
        int i;
        decalsystem_t *decalsystem = &ent->decalsystem;
        int numdecals;
-       int killsequence;
+       unsigned int killsequence;
        tridecal_t *decal;
        float frametime;
        float lifetime;
@@ -11945,7 +11796,7 @@ static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
                return;
        }
 
-       killsequence = cl.decalsequence - max(1, cl_decals_max.integer);
+       killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
        lifetime = cl_decals_time.value + cl_decals_fadetime.value;
 
        if (decalsystem->lastupdatetime)
@@ -11960,7 +11811,7 @@ static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
                if (decal->color4f[0][3])
                {
                        decal->lived += frametime;
-                       if (killsequence - decal->decalsequence > 0 || decal->lived >= lifetime)
+                       if (killsequence > decal->decalsequence || decal->lived >= lifetime)
                        {
                                memset(decal, 0, sizeof(*decal));
                                if (decalsystem->freedecal > i)
@@ -12023,10 +11874,7 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
        // if the model is static it doesn't matter what value we give for
        // wantnormals and wanttangents, so this logic uses only rules applicable
        // to a model, knowing that they are meaningless otherwise
-       if (ent == r_refdef.scene.worldentity)
-               RSurf_ActiveWorldEntity();
-       else
-               RSurf_ActiveModelEntity(ent, false, false, false);
+       RSurf_ActiveModelEntity(ent, false, false, false);
 
        decalsystem->lastupdatetime = r_refdef.scene.time;
 
@@ -12165,10 +12013,9 @@ extern cvar_t mod_collision_bih;
 static void R_DrawDebugModel(void)
 {
        entity_render_t *ent = rsurface.entity;
-       int i, j, k, l, flagsmask;
+       int i, j, flagsmask;
        const msurface_t *surface;
        dp_model_t *model = ent->model;
-       vec3_t v;
 
        if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
                return;
@@ -12300,6 +12147,8 @@ static void R_DrawDebugModel(void)
 
        if (r_shownormals.value != 0 && qglBegin)
        {
+               int l, k;
+               vec3_t v;
                if (r_showdisabledepthtest.integer)
                {
                        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -12378,101 +12227,6 @@ static void R_DrawDebugModel(void)
 
 int r_maxsurfacelist = 0;
 const msurface_t **r_surfacelist = NULL;
-void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
-{
-       int i, j, endj, flagsmask;
-       dp_model_t *model = r_refdef.scene.worldmodel;
-       msurface_t *surfaces;
-       unsigned char *update;
-       int numsurfacelist = 0;
-       if (model == NULL)
-               return;
-
-       if (r_maxsurfacelist < model->num_surfaces)
-       {
-               r_maxsurfacelist = model->num_surfaces;
-               if (r_surfacelist)
-                       Mem_Free((msurface_t**)r_surfacelist);
-               r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
-       }
-
-       RSurf_ActiveWorldEntity();
-
-       surfaces = model->data_surfaces;
-       update = model->brushq1.lightmapupdateflags;
-
-       // update light styles on this submodel
-       if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0)
-       {
-               model_brush_lightstyleinfo_t *style;
-               for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
-               {
-                       if (style->value != r_refdef.scene.lightstylevalue[style->style])
-                       {
-                               int *list = style->surfacelist;
-                               style->value = r_refdef.scene.lightstylevalue[style->style];
-                               for (j = 0;j < style->numsurfaces;j++)
-                                       update[list[j]] = true;
-                       }
-               }
-       }
-
-       flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
-
-       if (debug)
-       {
-               R_DrawDebugModel();
-               rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
-               return;
-       }
-
-       rsurface.lightmaptexture = NULL;
-       rsurface.deluxemaptexture = NULL;
-       rsurface.uselightmaptexture = false;
-       rsurface.texture = NULL;
-       rsurface.rtlight = NULL;
-       numsurfacelist = 0;
-       // add visible surfaces to draw list
-       for (i = 0;i < model->nummodelsurfaces;i++)
-       {
-               j = model->sortedmodelsurfaces[i];
-               if (r_refdef.viewcache.world_surfacevisible[j])
-                       r_surfacelist[numsurfacelist++] = surfaces + j;
-       }
-       // update lightmaps if needed
-       if (model->brushq1.firstrender)
-       {
-               model->brushq1.firstrender = false;
-               for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
-                       if (update[j])
-                               R_BuildLightMap(r_refdef.scene.worldentity, surfaces + j);
-       }
-       else if (update)
-       {
-               for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
-                       if (r_refdef.viewcache.world_surfacevisible[j])
-                               if (update[j])
-                                       R_BuildLightMap(r_refdef.scene.worldentity, surfaces + j);
-       }
-       // don't do anything if there were no surfaces
-       if (!numsurfacelist)
-       {
-               rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
-               return;
-       }
-       R_QueueWorldSurfaceList(numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
-
-       // add to stats if desired
-       if (r_speeds.integer && !skysurfaces && !depthonly)
-       {
-               r_refdef.stats[r_stat_world_surfaces] += numsurfacelist;
-               for (j = 0;j < numsurfacelist;j++)
-                       r_refdef.stats[r_stat_world_triangles] += r_surfacelist[j]->num_triangles;
-       }
-
-       rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
-}
-
 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
 {
        int i, j, endj, flagsmask;
@@ -12491,12 +12245,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
                r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
        }
 
-       // if the model is static it doesn't matter what value we give for
-       // wantnormals and wanttangents, so this logic uses only rules applicable
-       // to a model, knowing that they are meaningless otherwise
-       if (ent == r_refdef.scene.worldentity)
-               RSurf_ActiveWorldEntity();
-       else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
+       if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
                RSurf_ActiveModelEntity(ent, false, false, false);
        else if (prepass)
                RSurf_ActiveModelEntity(ent, true, true, true);
@@ -12543,7 +12292,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
        update = model->brushq1.lightmapupdateflags;
 
        // update light styles
-       if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0)
+       if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
        {
                model_brush_lightstyleinfo_t *style;
                for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
@@ -12563,7 +12312,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
        if (debug)
        {
                R_DrawDebugModel();
-               rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
+               rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
                return;
        }
 
@@ -12574,12 +12323,26 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
        rsurface.rtlight = NULL;
        numsurfacelist = 0;
        // add visible surfaces to draw list
-       for (i = 0;i < model->nummodelsurfaces;i++)
-               r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
+       if (ent == r_refdef.scene.worldentity)
+       {
+               // for the world entity, check surfacevisible
+               for (i = 0;i < model->nummodelsurfaces;i++)
+               {
+                       j = model->sortedmodelsurfaces[i];
+                       if (r_refdef.viewcache.world_surfacevisible[j])
+                               r_surfacelist[numsurfacelist++] = surfaces + j;
+               }
+       }
+       else
+       {
+               // add all surfaces
+               for (i = 0; i < model->nummodelsurfaces; i++)
+                       r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
+       }
        // don't do anything if there were no surfaces
        if (!numsurfacelist)
        {
-               rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
+               rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
                return;
        }
        // update lightmaps if needed
@@ -12606,11 +12369,12 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
                        r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
        }
 
-       rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
+       rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
 }
 
 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
 {
+       int q;
        static texture_t texture;
        static msurface_t surface;
        const msurface_t *surfacelist = &surface;
@@ -12619,6 +12383,7 @@ void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, i
 
        texture.update_lastrenderframe = -1; // regenerate this texture
        texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
+       texture.basealpha = 1.0f;
        texture.currentskinframe = skinframe;
        texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
        texture.offsetmapping = OFFSETMAPPING_OFF;
@@ -12629,6 +12394,21 @@ void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, i
        // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
        // JUST GREP FOR "specularscalemod = 1".
 
+       for (q = 0; q < 3; q++)
+       {
+               texture.render_glowmod[q] = r_refdef.view.colorscale * r_hdr_glowintensity.value;
+               texture.render_modellight_lightdir[q] = q == 2;
+               texture.render_modellight_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
+               texture.render_modellight_diffuse[q] = r_refdef.view.colorscale;
+               texture.render_modellight_specular[q] = r_refdef.view.colorscale;
+               texture.render_lightmap_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
+               texture.render_lightmap_diffuse[q] = r_refdef.view.colorscale * r_refdef.scene.lightmapintensity;
+               texture.render_lightmap_specular[q] = r_refdef.view.colorscale;
+               texture.render_rtlight_diffuse[q] = r_refdef.view.colorscale;
+               texture.render_rtlight_specular[q] = r_refdef.view.colorscale;
+       }
+       texture.currentalpha = 1.0f;
+
        surface.texture = &texture;
        surface.num_triangles = numtriangles;
        surface.num_firsttriangle = firsttriangle;