]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
Made RENDERPATH_GL20 require fbo support and always use it.
[xonotic/darkplaces.git] / gl_rmain.c
index 39aa73a7bdb30cb79e6e6cceb77f73e5999c365d..fa55fd47fe2507b0b770dcc0df541c30536c297b 100644 (file)
@@ -20,7 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // r_main.c
 
 #include "quakedef.h"
-#include "cl_dyntexture.h"
 #include "r_shadow.h"
 #include "polygon.h"
 #include "image.h"
@@ -77,10 +76,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"};
@@ -121,10 +120,16 @@ cvar_t r_sortentities = {0, "r_sortentities", "0", "sort entities before drawing
 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)"};
@@ -135,7 +140,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"};
@@ -170,6 +175,7 @@ static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the Ope
 
 cvar_t r_usedepthtextures = {CVAR_SAVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
 cvar_t r_viewfbo = {CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
+cvar_t r_rendertarget_debug = {0, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
 cvar_t r_viewscale = {CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
 cvar_t r_viewscale_fpsscaling = {CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
 cvar_t r_viewscale_fpsscaling_min = {CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
@@ -207,7 +213,6 @@ cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "h
 cvar_t r_water_scissormode = {0, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
 cvar_t r_water_lowquality = {0, "r_water_lowquality", "0", "special option to accelerate water rendering, 1 disables shadows and particles, 2 disables all dynamic lights"};
 cvar_t r_water_hideplayer = {CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
-cvar_t r_water_fbo = {CVAR_SAVE, "r_water_fbo", "1", "enables use of render to texture for water effects, otherwise copy to texture is used (slower)"};
 
 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
@@ -262,7 +267,6 @@ cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
        {CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
 };
 
-extern cvar_t v_glslgamma;
 extern cvar_t v_glslgamma_2d;
 
 extern qboolean v_flipped_state;
@@ -315,7 +319,6 @@ static int r_qwskincache_size;
 
 /// vertex coordinates for a quad that covers the screen exactly
 extern const float r_screenvertex3f[12];
-extern const float r_d3dscreenvertex3f[12];
 const float r_screenvertex3f[12] =
 {
        0, 0, 0,
@@ -323,13 +326,6 @@ const float r_screenvertex3f[12] =
        1, 1, 0,
        0, 1, 0
 };
-const float r_d3dscreenvertex3f[12] =
-{
-       0, 1, 0,
-       1, 1, 0,
-       1, 0, 0,
-       0, 0, 0
-};
 
 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
 {
@@ -751,7 +747,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;
@@ -962,7 +958,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;
 
@@ -990,7 +986,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);
@@ -1074,7 +1070,7 @@ static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean p
        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;
@@ -1156,7 +1152,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;
@@ -1389,7 +1385,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)
@@ -1409,7 +1405,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;
@@ -1451,7 +1447,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;
@@ -1538,7 +1534,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);
@@ -1715,7 +1711,7 @@ 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 = &shadermodeinfo[SHADERLANGUAGE_HLSL][mode];
@@ -1771,7 +1767,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;
@@ -1861,7 +1857,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)
@@ -1878,7 +1874,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;
@@ -1905,7 +1901,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);
@@ -2014,7 +2010,7 @@ static void R_GLSL_DumpShader_f(void)
 
 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;
@@ -2028,7 +2024,7 @@ void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemod
                permutation |= SHADERPERMUTATION_GLOW;
        else if (texturemode == GL_DECAL)
                permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
-       if (usegamma && v_glslgamma.integer && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
+       if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
                permutation |= SHADERPERMUTATION_GAMMARAMPS;
        if (suppresstexalpha)
                permutation |= SHADERPERMUTATION_REFLECTCUBE;
@@ -2044,7 +2040,7 @@ void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemod
                R_Mesh_TexBind(GL20TU_FIRST , first );
                R_Mesh_TexBind(GL20TU_SECOND, second);
                if (permutation & SHADERPERMUTATION_GAMMARAMPS)
-                       R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
+                       R_Mesh_TexBind(GL20TU_GAMMARAMPS, r_texture_gammaramps);
 #endif
                break;
        case RENDERPATH_D3D10:
@@ -2095,7 +2091,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)
@@ -2139,28 +2135,6 @@ void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean
        }
 }
 
-extern qboolean r_shadow_usingdeferredprepass;
-extern rtexture_t *r_shadow_attenuationgradienttexture;
-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_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_prepass_width;
-extern int r_shadow_prepass_height;
-extern rtexture_t *r_shadow_prepassgeometrydepthbuffer;
-extern rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
-extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
-extern rtexture_t *r_shadow_prepasslightingspeculartexture;
-
 #define BLENDFUNC_ALLOWS_COLORMOD      1
 #define BLENDFUNC_ALLOWS_FOG           2
 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
@@ -2207,37 +2181,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->currentmaterialflags & MATERIALFLAG_OCCLUDE)
+       if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
                permutation |= SHADERPERMUTATION_OCCLUDE;
-       if (rsurface.texture->r_water_waterscroll[0] && rsurface.texture->r_water_waterscroll[1])
+       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);
@@ -2250,10 +2223,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);
@@ -2270,9 +2243,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;
@@ -2280,7 +2253,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;
@@ -2291,9 +2264,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;
@@ -2301,21 +2274,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)
                {
@@ -2326,69 +2299,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;
@@ -2396,78 +2318,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_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
-               {
-                       permutation |= SHADERPERMUTATION_BOUNCEGRID;
-                       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);
-               // 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))
                {
@@ -2477,11 +2342,11 @@ 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_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
                {
@@ -2489,14 +2354,14 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        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
@@ -2505,9 +2370,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;
@@ -2515,16 +2380,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))
                {
@@ -2534,18 +2399,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)
@@ -2556,7 +2421,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)
@@ -2567,7 +2432,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)
@@ -2586,22 +2451,20 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        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)
@@ -2623,11 +2486,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]);
@@ -2635,54 +2498,52 @@ 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)
                {
@@ -2694,15 +2555,15 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        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]);
                }
-               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]);
@@ -2710,28 +2571,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);
@@ -2739,13 +2600,13 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                if (rsurface.rtlight                                  ) R_Mesh_TexBind(GL20TU_ATTENUATION       , r_shadow_attenuationgradienttexture                 );
                if (rsurfacepass == RSURFPASS_BACKGROUND)
                {
-                       R_Mesh_TexBind(GL20TU_REFRACTION        , waterplane->texture_refraction ? waterplane->texture_refraction : r_texture_black);
-                       if(mode == SHADERMODE_GENERIC) R_Mesh_TexBind(GL20TU_FIRST             , waterplane->texture_camera ? waterplane->texture_camera : r_texture_black);
-                       R_Mesh_TexBind(GL20TU_REFLECTION        , waterplane->texture_reflection ? waterplane->texture_reflection : r_texture_black);
+                       R_Mesh_TexBind(GL20TU_REFRACTION        , waterplane->rt_refraction ? waterplane->rt_refraction->colortexture[0] : r_texture_black);
+                       if(mode == SHADERMODE_GENERIC) R_Mesh_TexBind(GL20TU_FIRST             , waterplane->rt_camera ? waterplane->rt_camera->colortexture[0] : r_texture_black);
+                       R_Mesh_TexBind(GL20TU_REFLECTION        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
                }
                else
                {
-                       if (permutation & SHADERPERMUTATION_REFLECTION        ) R_Mesh_TexBind(GL20TU_REFLECTION        , waterplane->texture_reflection ? waterplane->texture_reflection : r_texture_black);
+                       if (permutation & SHADERPERMUTATION_REFLECTION        ) R_Mesh_TexBind(GL20TU_REFLECTION        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
                }
 //             if (rsurfacepass == RSURFPASS_DEFERREDLIGHT           ) R_Mesh_TexBind(GL20TU_SCREENNORMALMAP   , r_shadow_prepassgeometrynormalmaptexture            );
                if (permutation & SHADERPERMUTATION_DEFERREDLIGHTMAP  ) R_Mesh_TexBind(GL20TU_SCREENDIFFUSE     , r_shadow_prepasslightingdiffusetexture              );
@@ -2800,39 +2661,39 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                {
                        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)
@@ -2842,18 +2703,18 @@ 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 (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
                {
@@ -2866,20 +2727,20 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        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);
                }
@@ -2888,13 +2749,13 @@ 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_bouncegrid_state.matrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
@@ -2903,18 +2764,18 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                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);
@@ -2922,13 +2783,13 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
                if (rsurfacepass == RSURFPASS_BACKGROUND)
                {
-                       if (r_glsl_permutation->tex_Texture_Refraction  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Refraction        , waterplane->texture_refraction ? waterplane->texture_refraction : r_texture_black);
-                       if (r_glsl_permutation->tex_Texture_First       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First             , waterplane->texture_camera ? waterplane->texture_camera : r_texture_black);
-                       if (r_glsl_permutation->tex_Texture_Reflection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->texture_reflection ? waterplane->texture_reflection : r_texture_black);
+                       if (r_glsl_permutation->tex_Texture_Refraction  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Refraction        , waterplane->rt_refraction ? waterplane->rt_refraction->colortexture[0] : r_texture_black);
+                       if (r_glsl_permutation->tex_Texture_First       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First             , waterplane->rt_camera ? waterplane->rt_camera->colortexture[0] : r_texture_black);
+                       if (r_glsl_permutation->tex_Texture_Reflection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
                }
                else
                {
-                       if (r_glsl_permutation->tex_Texture_Reflection >= 0 && waterplane) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->texture_reflection ? waterplane->texture_reflection : r_texture_black);
+                       if (r_glsl_permutation->tex_Texture_Reflection >= 0 && waterplane) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
                }
                if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
                if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
@@ -2958,56 +2819,54 @@ 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);}
                if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
                {
@@ -3020,20 +2879,20 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        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);
                }
@@ -3042,28 +2901,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);
@@ -3071,13 +2930,13 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                if (rsurface.rtlight                                  ) R_Mesh_TexBind(GL20TU_ATTENUATION       , r_shadow_attenuationgradienttexture                 );
                if (rsurfacepass == RSURFPASS_BACKGROUND)
                {
-                       R_Mesh_TexBind(GL20TU_REFRACTION        , waterplane->texture_refraction ? waterplane->texture_refraction : r_texture_black);
-                       if(mode == SHADERMODE_GENERIC) R_Mesh_TexBind(GL20TU_FIRST             , waterplane->texture_camera ? waterplane->texture_camera : r_texture_black);
-                       R_Mesh_TexBind(GL20TU_REFLECTION        , waterplane->texture_reflection ? waterplane->texture_reflection : r_texture_black);
+                       R_Mesh_TexBind(GL20TU_REFRACTION        , waterplane->rt_refraction ? waterplane->rt_refraction->colortexture[0] : r_texture_black);
+                       if(mode == SHADERMODE_GENERIC) R_Mesh_TexBind(GL20TU_FIRST             , waterplane->rt_camera ? waterplane->rt_camera->colortexture[0] : r_texture_black);
+                       R_Mesh_TexBind(GL20TU_REFLECTION        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
                }
                else
                {
-                       if (permutation & SHADERPERMUTATION_REFLECTION        ) R_Mesh_TexBind(GL20TU_REFLECTION        , waterplane->texture_reflection ? waterplane->texture_reflection : r_texture_black);
+                       if (permutation & SHADERPERMUTATION_REFLECTION        ) R_Mesh_TexBind(GL20TU_REFLECTION        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
                }
 //             if (rsurfacepass == RSURFPASS_DEFERREDLIGHT           ) R_Mesh_TexBind(GL20TU_SCREENNORMALMAP   , r_shadow_prepassgeometrynormalmaptexture            );
                if (permutation & SHADERPERMUTATION_DEFERREDLIGHTMAP  ) R_Mesh_TexBind(GL20TU_SCREENDIFFUSE     , r_shadow_prepasslightingdiffusetexture              );
@@ -3101,7 +2960,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;
@@ -3238,6 +3097,23 @@ void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
        skinframe->loadsequence = r_skinframe.loadsequence;
 }
 
+void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
+{
+       if (s->merged == s->base)
+               s->merged = NULL;
+       R_PurgeTexture(s->stain); s->stain = NULL;
+       R_PurgeTexture(s->merged); s->merged = NULL;
+       R_PurgeTexture(s->base); s->base = NULL;
+       R_PurgeTexture(s->pants); s->pants = NULL;
+       R_PurgeTexture(s->shirt); s->shirt = NULL;
+       R_PurgeTexture(s->nmap); s->nmap = NULL;
+       R_PurgeTexture(s->gloss); s->gloss = NULL;
+       R_PurgeTexture(s->glow); s->glow = NULL;
+       R_PurgeTexture(s->fog); s->fog = NULL;
+       R_PurgeTexture(s->reflect); s->reflect = NULL;
+       s->loadsequence = 0;
+}
+
 void R_SkinFrame_Purge(void)
 {
        int i;
@@ -3247,22 +3123,7 @@ void R_SkinFrame_Purge(void)
                for (s = r_skinframe.hash[i];s;s = s->next)
                {
                        if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
-                       {
-                               if (s->merged == s->base)
-                                       s->merged = NULL;
-                               // FIXME: maybe pass a pointer to the pointer to R_PurgeTexture and reset it to NULL inside? [11/29/2007 Black]
-                               R_PurgeTexture(s->stain );s->stain  = NULL;
-                               R_PurgeTexture(s->merged);s->merged = NULL;
-                               R_PurgeTexture(s->base  );s->base   = NULL;
-                               R_PurgeTexture(s->pants );s->pants  = NULL;
-                               R_PurgeTexture(s->shirt );s->shirt  = NULL;
-                               R_PurgeTexture(s->nmap  );s->nmap   = NULL;
-                               R_PurgeTexture(s->gloss );s->gloss  = NULL;
-                               R_PurgeTexture(s->glow  );s->glow   = NULL;
-                               R_PurgeTexture(s->fog   );s->fog    = NULL;
-                               R_PurgeTexture(s->reflect);s->reflect = NULL;
-                               s->loadsequence = 0;
-                       }
+                               R_SkinFrame_PurgeSkinFrame(s);
                }
        }
 }
@@ -3303,16 +3164,13 @@ skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewid
                if (!strcmp(item->basename, basename) && (comparecrc < 0 || (item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)))
                        break;
 
-       if (!item) {
-               rtexture_t *dyntexture;
-               // check whether its a dynamic texture
-               dyntexture = CL_GetDynTexture( basename );
-               if (!add && !dyntexture)
+       if (!item)
+       {
+               if (!add)
                        return NULL;
                item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
                memset(item, 0, sizeof(*item));
                strlcpy(item->basename, basename, sizeof(item->basename));
-               item->base = dyntexture; // either NULL or dyntexture handle
                item->textureflags = textureflags & ~TEXF_FORCE_RELOAD;
                item->comparewidth = comparewidth;
                item->compareheight = compareheight;
@@ -3322,33 +3180,9 @@ skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewid
        }
        else if (textureflags & TEXF_FORCE_RELOAD)
        {
-               rtexture_t *dyntexture;
-               // check whether its a dynamic texture
-               dyntexture = CL_GetDynTexture( basename );
-               if (!add && !dyntexture)
+               if (!add)
                        return NULL;
-               if (item->merged == item->base)
-                       item->merged = NULL;
-               // FIXME: maybe pass a pointer to the pointer to R_PurgeTexture and reset it to NULL inside? [11/29/2007 Black]
-               R_PurgeTexture(item->stain );item->stain  = NULL;
-               R_PurgeTexture(item->merged);item->merged = NULL;
-               R_PurgeTexture(item->base  );item->base   = NULL;
-               R_PurgeTexture(item->pants );item->pants  = NULL;
-               R_PurgeTexture(item->shirt );item->shirt  = NULL;
-               R_PurgeTexture(item->nmap  );item->nmap   = NULL;
-               R_PurgeTexture(item->gloss );item->gloss  = NULL;
-               R_PurgeTexture(item->glow  );item->glow   = NULL;
-               R_PurgeTexture(item->fog   );item->fog    = NULL;
-       R_PurgeTexture(item->reflect);item->reflect = NULL;
-               item->loadsequence = 0;
-       }
-       else if( item->base == NULL )
-       {
-               rtexture_t *dyntexture;
-               // check whether its a dynamic texture
-               // this only needs to be done because Purge doesnt delete skinframes - only sets the texture pointers to NULL and we need to restore it before returing.. [11/29/2007 Black]
-               dyntexture = CL_GetDynTexture( basename );
-               item->base = dyntexture; // either NULL or dyntexture handle
+               R_SkinFrame_PurgeSkinFrame(item);
        }
 
        R_SkinFrame_MarkUsed(item);
@@ -3391,7 +3225,7 @@ skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewid
        }
 
 extern cvar_t gl_picmip;
-skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain)
+skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
 {
        int j;
        unsigned char *pixels;
@@ -3425,6 +3259,8 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
        {
                basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
+               if (basepixels == NULL && fallbacknotexture)
+                       basepixels = Image_GenerateNoTexture();
                if (basepixels == NULL)
                        return NULL;
        }
@@ -3850,7 +3686,7 @@ skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, co
                Con_Printf("loading embedded 8bit image \"%s\"\n", name);
 
        skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
-       if (textureflags & TEXF_ALPHA)
+       if ((textureflags & TEXF_ALPHA) && alphapalette)
        {
                for (i = 0;i < width * height;i++)
                {
@@ -3898,6 +3734,73 @@ skinframe_t *R_SkinFrame_LoadMissing(void)
        return skinframe;
 }
 
+skinframe_t *R_SkinFrame_LoadNoTexture(void)
+{
+       int x, y;
+       static unsigned char pix[16][16][4];
+
+       if (cls.state == ca_dedicated)
+               return NULL;
+
+       // this makes a light grey/dark grey checkerboard texture
+       if (!pix[0][0][3])
+       {
+               for (y = 0; y < 16; y++)
+               {
+                       for (x = 0; x < 16; x++)
+                       {
+                               if ((y < 8) ^ (x < 8))
+                               {
+                                       pix[y][x][0] = 128;
+                                       pix[y][x][1] = 128;
+                                       pix[y][x][2] = 128;
+                                       pix[y][x][3] = 255;
+                               }
+                               else
+                               {
+                                       pix[y][x][0] = 64;
+                                       pix[y][x][1] = 64;
+                                       pix[y][x][2] = 64;
+                                       pix[y][x][3] = 255;
+                               }
+                       }
+               }
+       }
+
+       return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, false);
+}
+
+skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
+{
+       skinframe_t *skinframe;
+       if (cls.state == ca_dedicated)
+               return NULL;
+       // if already loaded just return it, otherwise make a new skinframe
+       skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : 0, true);
+       if (skinframe->base)
+               return skinframe;
+       textureflags &= ~TEXF_FORCE_RELOAD;
+       skinframe->stain = NULL;
+       skinframe->merged = NULL;
+       skinframe->base = NULL;
+       skinframe->pants = NULL;
+       skinframe->shirt = NULL;
+       skinframe->nmap = NULL;
+       skinframe->gloss = NULL;
+       skinframe->glow = NULL;
+       skinframe->fog = NULL;
+       skinframe->reflect = NULL;
+       skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
+       // if no data was provided, then clearly the caller wanted to get a blank skinframe
+       if (!tex)
+               return NULL;
+       if (developer_loading.integer)
+               Con_Printf("loading 32bit skin \"%s\"\n", name);
+       skinframe->base = skinframe->merged = tex;
+       Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
+       return skinframe;
+}
+
 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
 typedef struct suffixinfo_s
 {
@@ -4157,6 +4060,7 @@ static void gl_main_start(void)
        r_texture_gammaramps = NULL;
        //r_texture_fogintensity = NULL;
        memset(&r_fb, 0, sizeof(r_fb));
+       Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
        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);
@@ -4196,6 +4100,8 @@ static void gl_main_start(void)
 
 static void gl_main_shutdown(void)
 {
+       R_RenderTarget_FreeUnused(true);
+       Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
        R_AnimCache_Free();
        R_FrameData_Reset();
        R_BufferData_Reset();
@@ -4371,6 +4277,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);
@@ -4399,6 +4310,7 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&gl_combine);
        Cvar_RegisterVariable(&r_usedepthtextures);
        Cvar_RegisterVariable(&r_viewfbo);
+       Cvar_RegisterVariable(&r_rendertarget_debug);
        Cvar_RegisterVariable(&r_viewscale);
        Cvar_RegisterVariable(&r_viewscale_fpsscaling);
        Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
@@ -4437,7 +4349,6 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_water_scissormode);
        Cvar_RegisterVariable(&r_water_lowquality);
        Cvar_RegisterVariable(&r_water_hideplayer);
-       Cvar_RegisterVariable(&r_water_fbo);
 
        Cvar_RegisterVariable(&r_lerpsprites);
        Cvar_RegisterVariable(&r_lerpmodels);
@@ -5112,119 +5023,6 @@ 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);
-       }
-}
-
 qboolean R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
 {
        int i;
@@ -5491,7 +5289,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)
@@ -5722,7 +5520,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)
@@ -5731,7 +5528,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;
@@ -5744,14 +5540,14 @@ static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outhe
        *outheight = (int)ceil(height * scale);
 }
 
-void R_SetupView(qboolean allowwaterclippingplane, int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
+void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
 {
        const float *customclipplane = NULL;
        float plane[4];
-       int /*rtwidth,*/ rtheight, scaledwidth, scaledheight;
+       int /*rtwidth,*/ rtheight;
        if (r_refdef.view.useclipplane && allowwaterclippingplane)
        {
-               // LordHavoc: couldn't figure out how to make this approach the
+               // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
                vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
                vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
                if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
@@ -5763,17 +5559,16 @@ void R_SetupView(qboolean allowwaterclippingplane, int fbo, rtexture_t *depthtex
                if(vid.renderpath != RENDERPATH_SOFT) customclipplane = plane;
        }
 
-       //rtwidth = fbo ? R_TextureWidth(depthtexture ? depthtexture : colortexture) : vid.width;
-       rtheight = fbo ? R_TextureHeight(depthtexture ? depthtexture : colortexture) : vid.height;
+       //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
+       rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
 
-       R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &scaledwidth, &scaledheight);
        if (!r_refdef.view.useperspective)
-               R_Viewport_InitOrtho(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, rtheight - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, -r_refdef.view.ortho_x, -r_refdef.view.ortho_y, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
+               R_Viewport_InitOrtho(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, -r_refdef.view.ortho_x, -r_refdef.view.ortho_y, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
        else if (vid.stencil && r_useinfinitefarclip.integer)
-               R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, rtheight - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
+               R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
        else
-               R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, rtheight - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
-       R_Mesh_SetRenderTargets(fbo, depthtexture, colortexture, NULL, NULL, NULL);
+               R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
+       R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
        R_SetViewport(&r_refdef.view.viewport);
        if (r_refdef.view.useclipplane && allowwaterclippingplane && vid.renderpath == RENDERPATH_SOFT)
        {
@@ -5832,15 +5627,15 @@ void R_EntityMatrix(const matrix4x4_t *matrix)
        }
 }
 
-void R_ResetViewRendering2D_Common(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, float x2, float y2)
+void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
 {
        r_viewport_t viewport;
 
        CHECKGLERROR
 
        // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
-       R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, 0, 0, x2, y2, -10, 100, NULL);
-       R_Mesh_SetRenderTargets(fbo, depthtexture, colortexture, NULL, NULL, NULL);
+       R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
+       R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
        R_SetViewport(&viewport);
        GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
        GL_Color(1, 1, 1, 1);
@@ -5875,18 +5670,18 @@ void R_ResetViewRendering2D_Common(int fbo, rtexture_t *depthtexture, rtexture_t
        CHECKGLERROR
 }
 
-void R_ResetViewRendering2D(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
+void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
 {
        DrawQ_Finish();
 
-       R_ResetViewRendering2D_Common(fbo, depthtexture, colortexture, 1, 1);
+       R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
 }
 
-void R_ResetViewRendering3D(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
+void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
 {
        DrawQ_Finish();
 
-       R_SetupView(true, fbo, depthtexture, colortexture);
+       R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
        GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
        GL_Color(1, 1, 1, 1);
        GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
@@ -5934,15 +5729,105 @@ void R_RenderView_UpdateViewVectors(void)
        Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
 }
 
-void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
-void R_RenderWaterPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
+void R_RenderTarget_FreeUnused(qboolean force)
+{
+       int i, j, end;
+       end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
+       for (i = 0; i < end; i++)
+       {
+               r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
+               // free resources for rendertargets that have not been used for a while
+               // (note: this check is run after the frame render, so any targets used
+               // this frame will not be affected even at low framerates)
+               if (r && (realtime - r->lastusetime > 0.2 || force))
+               {
+                       if (r->fbo)
+                               R_Mesh_DestroyFramebufferObject(r->fbo);
+                       for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
+                               if (r->colortexture[j])
+                                       R_FreeTexture(r->colortexture[j]);
+                       if (r->depthtexture)
+                               R_FreeTexture(r->depthtexture);
+                       Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
+               }
+       }
+}
+
+static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
+{
+       float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
+       switch (vid.renderpath)
+       {
+       case RENDERPATH_D3D9:
+               x1 = (x + 0.5f) * iw;
+               x2 = (x + 0.5f + w) * iw;
+               y1 = (y + 0.5f) * ih;
+               y2 = (y + 0.5f + h) * ih;
+               break;
+       default:
+               x1 = x * iw;
+               x2 = (x + w) * iw;
+               y1 = (th - y) * ih;
+               y2 = (th - y - h) * ih;
+               break;
+       }
+       texcoord2f[0] = x1;
+       texcoord2f[2] = x2;
+       texcoord2f[4] = x2;
+       texcoord2f[6] = x1;
+       texcoord2f[1] = y1;
+       texcoord2f[3] = y1;
+       texcoord2f[5] = y2;
+       texcoord2f[7] = y2;
+}
+
+r_rendertarget_t *R_RenderTarget_Get(int texturewidth, int textureheight, textype_t depthtextype, qboolean depthisrenderbuffer, textype_t colortextype0, textype_t colortextype1, textype_t colortextype2, textype_t colortextype3)
+{
+       int i, j, end;
+       r_rendertarget_t *r = NULL;
+       char vabuf[256];
+       // first try to reuse an existing slot if possible
+       end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
+       for (i = 0; i < end; i++)
+       {
+               r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
+               if (r && r->lastusetime != realtime && r->texturewidth == texturewidth && r->textureheight == textureheight && r->depthtextype == depthtextype && r->colortextype[0] == colortextype0 && r->colortextype[1] == colortextype1 && r->colortextype[2] == colortextype2 && r->colortextype[3] == colortextype3)
+                       break;
+       }
+       if (i == end)
+       {
+               // no unused exact match found, so we have to make one in the first unused slot
+               r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
+               r->texturewidth = texturewidth;
+               r->textureheight = textureheight;
+               r->colortextype[0] = colortextype0;
+               r->colortextype[1] = colortextype1;
+               r->colortextype[2] = colortextype2;
+               r->colortextype[3] = colortextype3;
+               r->depthtextype = depthtextype;
+               r->depthisrenderbuffer = depthisrenderbuffer;
+               for (j = 0; j < 4; j++)
+                       if (r->colortextype[j])
+                               r->colortexture[j] = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_%i_type%i", i, j, (int)r->colortextype[j]), r->texturewidth, r->textureheight, NULL, r->colortextype[j], TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
+               if (r->depthtextype)
+               {
+                       if (r->depthisrenderbuffer)
+                               r->depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, va(vabuf, sizeof(vabuf), "renderbuffer%i_depth_type%i", i, (int)r->depthtextype), r->texturewidth, r->textureheight, r->depthtextype);
+                       else
+                               r->depthtexture = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_depth_type%i", i, j, (int)r->depthtextype), r->texturewidth, r->textureheight, NULL, r->depthtextype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
+               }
+               r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
+       }
+       r_refdef.stats[r_stat_rendertargets_used]++;
+       r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
+       r->lastusetime = realtime;
+       R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
+       return r;
+}
 
 static void R_Water_StartFrame(void)
 {
-       int i;
-       int waterwidth, waterheight, texturewidth, textureheight, camerawidth, cameraheight;
-       r_waterstate_waterplane_t *p;
-       qboolean usewaterfbo = (r_viewfbo.integer >= 1 || r_water_fbo.integer >= 1) && vid.support.ext_framebuffer_object && vid.support.arb_texture_non_power_of_two && vid.samples < 2;
+       int waterwidth, waterheight;
 
        if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
                return;
@@ -5964,76 +5849,25 @@ static void R_Water_StartFrame(void)
 
        // set waterwidth and waterheight to the water resolution that will be
        // used (often less than the screen resolution for faster rendering)
-       R_GetScaledViewSize(bound(1, vid.width * r_water_resolutionmultiplier.value, vid.width), bound(1, vid.height * r_water_resolutionmultiplier.value, vid.height), &waterwidth, &waterheight);
+       waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
+       waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
+       R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
 
-       // calculate desired texture sizes
-       // can't use water if the card does not support the texture size
        if (!r_water.integer || r_showsurfaces.integer)
-               texturewidth = textureheight = waterwidth = waterheight = camerawidth = cameraheight = 0;
-       else if (vid.support.arb_texture_non_power_of_two)
-       {
-               texturewidth = waterwidth;
-               textureheight = waterheight;
-               camerawidth = waterwidth;
-               cameraheight = waterheight;
-       }
-       else
-       {
-               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
-       if (r_fb.water.texturewidth != texturewidth || r_fb.water.textureheight != textureheight || r_fb.water.camerawidth != camerawidth || r_fb.water.cameraheight != cameraheight || (r_fb.depthtexture && !usewaterfbo))
-       {
-               r_fb.water.maxwaterplanes = MAX_WATERPLANES;
-               for (i = 0, p = r_fb.water.waterplanes;i < r_fb.water.maxwaterplanes;i++, p++)
-               {
-                       if (p->texture_refraction)
-                               R_FreeTexture(p->texture_refraction);
-                       p->texture_refraction = NULL;
-                       if (p->fbo_refraction)
-                               R_Mesh_DestroyFramebufferObject(p->fbo_refraction);
-                       p->fbo_refraction = 0;
-                       if (p->texture_reflection)
-                               R_FreeTexture(p->texture_reflection);
-                       p->texture_reflection = NULL;
-                       if (p->fbo_reflection)
-                               R_Mesh_DestroyFramebufferObject(p->fbo_reflection);
-                       p->fbo_reflection = 0;
-                       if (p->texture_camera)
-                               R_FreeTexture(p->texture_camera);
-                       p->texture_camera = NULL;
-                       if (p->fbo_camera)
-                               R_Mesh_DestroyFramebufferObject(p->fbo_camera);
-                       p->fbo_camera = 0;
-               }
-               memset(&r_fb.water, 0, sizeof(r_fb.water));
-               r_fb.water.texturewidth = texturewidth;
-               r_fb.water.textureheight = textureheight;
-               r_fb.water.camerawidth = camerawidth;
-               r_fb.water.cameraheight = cameraheight;
-       }
-
-       if (r_fb.water.texturewidth)
-       {
-               int scaledwidth, scaledheight;
-
-               r_fb.water.enabled = true;
-
-               // water resolution is usually reduced
-               r_fb.water.waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
-               r_fb.water.waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
-               R_GetScaledViewSize(r_fb.water.waterwidth, r_fb.water.waterheight, &scaledwidth, &scaledheight);
-
-               // set up variables that will be used in shader setup
-               r_fb.water.screenscale[0] = 0.5f * (float)scaledwidth / (float)r_fb.water.texturewidth;
-               r_fb.water.screenscale[1] = 0.5f * (float)scaledheight / (float)r_fb.water.textureheight;
-               r_fb.water.screencenter[0] = 0.5f * (float)scaledwidth / (float)r_fb.water.texturewidth;
-               r_fb.water.screencenter[1] = 0.5f * (float)scaledheight / (float)r_fb.water.textureheight;
-       }
+               waterwidth = waterheight = 0;
+
+       // set up variables that will be used in shader setup
+       r_fb.water.waterwidth = waterwidth;
+       r_fb.water.waterheight = waterheight;
+       r_fb.water.texturewidth = waterwidth;
+       r_fb.water.textureheight = waterheight;
+       r_fb.water.camerawidth = waterwidth;
+       r_fb.water.cameraheight = waterheight;
+       r_fb.water.screenscale[0] = 0.5f;
+       r_fb.water.screenscale[1] = 0.5f;
+       r_fb.water.screencenter[0] = 0.5f;
+       r_fb.water.screencenter[1] = 0.5f;
+       r_fb.water.enabled = waterwidth != 0;
 
        r_fb.water.maxwaterplanes = MAX_WATERPLANES;
        r_fb.water.numwaterplanes = 0;
@@ -6156,7 +5990,7 @@ void R_Water_AddWaterPlane(msurface_t *surface, int entno)
 extern cvar_t r_drawparticles;
 extern cvar_t r_drawdecals;
 
-static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
+static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
 {
        int myscissor[4];
        r_refdef_view_t originalview;
@@ -6164,8 +5998,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
        int planeindex, qualityreduction = 0, old_r_dynamic = 0, old_r_shadows = 0, old_r_worldrtlight = 0, old_r_dlight = 0, old_r_particles = 0, old_r_decals = 0;
        r_waterstate_waterplane_t *p;
        vec3_t visorigin;
-       qboolean usewaterfbo = (r_viewfbo.integer >= 1 || r_water_fbo.integer >= 1) && vid.support.ext_framebuffer_object && vid.support.arb_texture_non_power_of_two && vid.samples < 2;
-       char vabuf[1024];
+       r_rendertarget_t *rt;
 
        originalview = r_refdef.view;
 
@@ -6193,82 +6026,46 @@ 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++)
+       {
+               p->rt_reflection = NULL;
+               p->rt_refraction = NULL;
+               p->rt_camera = NULL;
+       }
+
+       // render views
+       r_refdef.view = originalview;
+       r_refdef.view.showdebug = false;
+       r_refdef.view.width = r_fb.water.waterwidth;
+       r_refdef.view.height = r_fb.water.waterheight;
+       r_refdef.view.useclipplane = true;
+       myview = r_refdef.view;
+       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_REFRACTION))
+
+               if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
                {
-                       if (!p->texture_refraction)
-                               p->texture_refraction = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "waterplane%i_refraction", planeindex), r_fb.water.texturewidth, r_fb.water.textureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
-                       if (!p->texture_refraction)
+                       rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
+                       if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
                                goto error;
-                       if (usewaterfbo)
+                       r_refdef.view = myview;
+                       Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
+                       Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
+                       if(r_water_scissormode.integer)
                        {
-                               if (r_fb.water.depthtexture == NULL)
-                                       r_fb.water.depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, "waterviewdepth", r_fb.water.texturewidth, r_fb.water.textureheight, TEXTYPE_DEPTHBUFFER24STENCIL8);
-                               if (p->fbo_refraction == 0)
-                                       p->fbo_refraction = R_Mesh_CreateFramebufferObject(r_fb.water.depthtexture, p->texture_refraction, NULL, NULL, NULL);
-                       }
-               }
-               else if (p->materialflags & MATERIALFLAG_CAMERA)
-               {
-                       if (!p->texture_camera)
-                               p->texture_camera = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "waterplane%i_camera", planeindex), r_fb.water.camerawidth, r_fb.water.cameraheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR, -1, NULL);
-                       if (!p->texture_camera)
-                               goto error;
-                       if (usewaterfbo)
-                       {
-                               if (r_fb.water.depthtexture == NULL)
-                                       r_fb.water.depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, "waterviewdepth", r_fb.water.texturewidth, r_fb.water.textureheight, TEXTYPE_DEPTHBUFFER24STENCIL8);
-                               if (p->fbo_camera == 0)
-                                       p->fbo_camera = R_Mesh_CreateFramebufferObject(r_fb.water.depthtexture, p->texture_camera, NULL, NULL, NULL);
-                       }
-               }
-
-               if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
-               {
-                       if (!p->texture_reflection)
-                               p->texture_reflection = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "waterplane%i_reflection", planeindex), r_fb.water.texturewidth, r_fb.water.textureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
-                       if (!p->texture_reflection)
-                               goto error;
-                       if (usewaterfbo)
-                       {
-                               if (r_fb.water.depthtexture == NULL)
-                                       r_fb.water.depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, "waterviewdepth", r_fb.water.texturewidth, r_fb.water.textureheight, TEXTYPE_DEPTHBUFFER24STENCIL8);
-                               if (p->fbo_reflection == 0)
-                                       p->fbo_reflection = R_Mesh_CreateFramebufferObject(r_fb.water.depthtexture, p->texture_reflection, NULL, NULL, NULL);
-                       }
-               }
-       }
-
-       // render views
-       r_refdef.view = originalview;
-       r_refdef.view.showdebug = false;
-       r_refdef.view.width = r_fb.water.waterwidth;
-       r_refdef.view.height = r_fb.water.waterheight;
-       r_refdef.view.useclipplane = true;
-       myview = r_refdef.view;
-       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;
-                       if(r_water_scissormode.integer)
-                       {
-                               R_SetupView(true, p->fbo_reflection, r_fb.water.depthtexture, p->texture_reflection);
-                               if(R_ScissorForBBox(p->mins, p->maxs, myscissor))
-                                       continue; // FIXME the plane then still may get rendered but with broken texture, but it sure won't be visible
+                               R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
+                               if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
+                               {
+                                       p->rt_reflection = NULL;
+                                       p->rt_refraction = NULL;
+                                       p->rt_camera = NULL;
+                                       continue;
+                               }
                        }
 
-                       // render reflected scene and copy into texture
-                       Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
-                       // update the r_refdef.view.origin because otherwise the sky renders at the wrong location (amongst other problems)
-                       Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
                        r_refdef.view.clipplane = p->plane;
                        // reverse the cullface settings for this render
                        r_refdef.view.cullface_front = GL_FRONT;
@@ -6283,8 +6080,10 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
                        }
 
                        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_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
+                       GL_ScissorTest(false);
                        R_ClearScreen(r_refdef.fogenabled);
+                       GL_ScissorTest(true);
                        if(r_water_scissormode.integer & 2)
                                R_View_UpdateWithScissor(myscissor);
                        else
@@ -6292,23 +6091,30 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
                        R_AnimCache_CacheVisibleEntities();
                        if(r_water_scissormode.integer & 1)
                                GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
-                       R_RenderScene(p->fbo_reflection, r_fb.water.depthtexture, p->texture_reflection);
+                       R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
 
-                       if (!p->fbo_reflection)
-                               R_Mesh_CopyToTexture(p->texture_reflection, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
                        r_fb.water.hideplayer = false;
+                       p->rt_reflection = rt;
                }
 
                // render the normal view scene and copy into texture
                // (except that a clipping plane should be used to hide everything on one side of the water, and the viewer's weapon model should be omitted)
                if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
                {
+                       rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
+                       if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
+                               goto error;
                        r_refdef.view = myview;
                        if(r_water_scissormode.integer)
                        {
-                               R_SetupView(true, p->fbo_refraction, r_fb.water.depthtexture, p->texture_refraction);
-                               if(R_ScissorForBBox(p->mins, p->maxs, myscissor))
-                                       continue; // FIXME the plane then still may get rendered but with broken texture, but it sure won't be visible
+                               R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
+                               if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
+                               {
+                                       p->rt_reflection = NULL;
+                                       p->rt_refraction = NULL;
+                                       p->rt_camera = NULL;
+                                       continue;
+                               }
                        }
 
                        r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
@@ -6332,8 +6138,10 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
 
                        PlaneClassify(&r_refdef.view.clipplane);
 
-                       R_ResetViewRendering3D(p->fbo_refraction, r_fb.water.depthtexture, p->texture_refraction);
+                       R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
+                       GL_ScissorTest(false);
                        R_ClearScreen(r_refdef.fogenabled);
+                       GL_ScissorTest(true);
                        if(r_water_scissormode.integer & 2)
                                R_View_UpdateWithScissor(myscissor);
                        else
@@ -6341,14 +6149,16 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
                        R_AnimCache_CacheVisibleEntities();
                        if(r_water_scissormode.integer & 1)
                                GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
-                       R_RenderScene(p->fbo_refraction, r_fb.water.depthtexture, p->texture_refraction);
+                       R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
 
-                       if (!p->fbo_refraction)
-                               R_Mesh_CopyToTexture(p->texture_refraction, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
                        r_fb.water.hideplayer = false;
+                       p->rt_refraction = rt;
                }
                else if (p->materialflags & MATERIALFLAG_CAMERA)
                {
+                       rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
+                       if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
+                               goto error;
                        r_refdef.view = myview;
 
                        r_refdef.view.clipplane = p->plane;
@@ -6390,24 +6200,23 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
 
                        r_fb.water.hideplayer = false;
 
-                       R_ResetViewRendering3D(p->fbo_camera, r_fb.water.depthtexture, p->texture_camera);
+                       R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
+                       GL_ScissorTest(false);
                        R_ClearScreen(r_refdef.fogenabled);
+                       GL_ScissorTest(true);
                        R_View_Update();
                        R_AnimCache_CacheVisibleEntities();
-                       R_RenderScene(p->fbo_camera, r_fb.water.depthtexture, p->texture_camera);
+                       R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
 
-                       if (!p->fbo_camera)
-                               R_Mesh_CopyToTexture(p->texture_camera, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
                        r_fb.water.hideplayer = false;
+                       p->rt_camera = rt;
                }
 
        }
        if(vid.renderpath==RENDERPATH_SOFT) DPSOFTRAST_ClipPlane(0, 0, 0, 1);
        r_fb.water.renderingscene = false;
        r_refdef.view = originalview;
-       R_ResetViewRendering3D(fbo, depthtexture, colortexture);
-       if (!r_fb.water.depthtexture)
-               R_ClearScreen(r_refdef.fogenabled);
+       R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
        R_View_Update();
        R_AnimCache_CacheVisibleEntities();
        goto finish;
@@ -6437,25 +6246,28 @@ finish:
 
 static void R_Bloom_StartFrame(void)
 {
-       int i;
        int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
        int viewwidth, viewheight;
-       qboolean useviewfbo = r_viewfbo.integer >= 1 && vid.support.ext_framebuffer_object && vid.support.arb_texture_non_power_of_two && vid.samples < 2;
        textype_t textype = TEXTYPE_COLORBUFFER;
 
+       // clear the pointers to rendertargets from last frame as they're stale
+       r_fb.rt_screen = NULL;
+       r_fb.rt_bloom = NULL;
+
        switch (vid.renderpath)
        {
        case RENDERPATH_GL20:
                r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
-               if (vid.support.ext_framebuffer_object && vid.support.arb_texture_non_power_of_two)
-               {
-                       if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
-                       if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
-               }
+               if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
+               if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
+               // for simplicity, bloom requires FBO render to texture, which basically all video drivers support now
+               if (!vid.support.ext_framebuffer_object)
+                       return;
                break;
        case RENDERPATH_GL11:
        case RENDERPATH_GL13:
        case RENDERPATH_GLES1:
+               return; // don't bother
        case RENDERPATH_GLES2:
        case RENDERPATH_D3D9:
        case RENDERPATH_D3D10:
@@ -6486,21 +6298,6 @@ static void R_Bloom_StartFrame(void)
 
        R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
 
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_D3D9:
-       case RENDERPATH_D3D10:
-       case RENDERPATH_D3D11:
-       case RENDERPATH_SOFT:
-       case RENDERPATH_GLES2:
-               break;
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GLES1:
-               return;
-       }
-
        // set bloomwidth and bloomheight to the bloom resolution that will be
        // used (often less than the screen resolution for faster rendering)
        r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
@@ -6510,20 +6307,10 @@ static void R_Bloom_StartFrame(void)
        r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
 
        // calculate desired texture sizes
-       if (vid.support.arb_texture_non_power_of_two)
-       {
-               screentexturewidth = vid.width;
-               screentextureheight = vid.height;
-               bloomtexturewidth = r_fb.bloomwidth;
-               bloomtextureheight = r_fb.bloomheight;
-       }
-       else
-       {
-               for (screentexturewidth  = 1;screentexturewidth  < vid.width       ;screentexturewidth  *= 2);
-               for (screentextureheight = 1;screentextureheight < vid.height      ;screentextureheight *= 2);
-               for (bloomtexturewidth   = 1;bloomtexturewidth   < r_fb.bloomwidth ;bloomtexturewidth   *= 2);
-               for (bloomtextureheight  = 1;bloomtextureheight  < r_fb.bloomheight;bloomtextureheight  *= 2);
-       }
+       screentexturewidth = viewwidth;
+       screentextureheight = viewheight;
+       bloomtexturewidth = r_fb.bloomwidth;
+       bloomtextureheight = r_fb.bloomheight;
 
        if ((r_bloom.integer || (!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))) && ((r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512) || r_refdef.view.width > (int)vid.maxtexturesize_2d || r_refdef.view.height > (int)vid.maxtexturesize_2d))
        {
@@ -6532,55 +6319,15 @@ static void R_Bloom_StartFrame(void)
                Cvar_SetValueQuick(&r_damageblur, 0);
        }
 
-       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
-        && r_viewscale.value == 1.0f
-        && !r_viewscale_fpsscaling.integer)
-               screentexturewidth = screentextureheight = 0;
-       if (!r_bloom.integer)
-               bloomtexturewidth = bloomtextureheight = 0;
-
-       // allocate textures as needed
-       if (r_fb.screentexturewidth != screentexturewidth
-        || r_fb.screentextureheight != screentextureheight
-        || r_fb.bloomtexturewidth != bloomtexturewidth
-        || r_fb.bloomtextureheight != bloomtextureheight
-        || r_fb.textype != textype
-        || useviewfbo != (r_fb.fbo != 0))
+       // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
+       if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
        {
-               for (i = 0;i < (int)(sizeof(r_fb.bloomtexture)/sizeof(r_fb.bloomtexture[i]));i++)
-               {
-                       if (r_fb.bloomtexture[i])
-                               R_FreeTexture(r_fb.bloomtexture[i]);
-                       r_fb.bloomtexture[i] = NULL;
-
-                       if (r_fb.bloomfbo[i])
-                               R_Mesh_DestroyFramebufferObject(r_fb.bloomfbo[i]);
-                       r_fb.bloomfbo[i] = 0;
-               }
-
-               if (r_fb.fbo)
-                       R_Mesh_DestroyFramebufferObject(r_fb.fbo);
-               r_fb.fbo = 0;
-
-               if (r_fb.colortexture)
-                       R_FreeTexture(r_fb.colortexture);
-               r_fb.colortexture = NULL;
-
-               if (r_fb.depthtexture)
-                       R_FreeTexture(r_fb.depthtexture);
-               r_fb.depthtexture = NULL;
-
                if (r_fb.ghosttexture)
                        R_FreeTexture(r_fb.ghosttexture);
                r_fb.ghosttexture = NULL;
 
                r_fb.screentexturewidth = screentexturewidth;
                r_fb.screentextureheight = screentextureheight;
-               r_fb.bloomtexturewidth = bloomtexturewidth;
-               r_fb.bloomtextureheight = bloomtextureheight;
                r_fb.textype = textype;
 
                if (r_fb.screentexturewidth && r_fb.screentextureheight)
@@ -6588,179 +6335,71 @@ static void R_Bloom_StartFrame(void)
                        if (r_motionblur.value > 0 || r_damageblur.value > 0)
                                r_fb.ghosttexture = R_LoadTexture2D(r_main_texturepool, "framebuffermotionblur", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
                        r_fb.ghosttexture_valid = false;
-                       r_fb.colortexture = R_LoadTexture2D(r_main_texturepool, "framebuffercolor", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
-                       if (useviewfbo)
-                       {
-                               r_fb.depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, "framebufferdepth", r_fb.screentexturewidth, r_fb.screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8);
-                               r_fb.fbo = R_Mesh_CreateFramebufferObject(r_fb.depthtexture, r_fb.colortexture, NULL, NULL, NULL);
-                               R_Mesh_SetRenderTargets(r_fb.fbo, r_fb.depthtexture, r_fb.colortexture, NULL, NULL, NULL);
-                       }
-               }
-
-               if (r_fb.bloomtexturewidth && r_fb.bloomtextureheight)
-               {
-                       for (i = 0;i < (int)(sizeof(r_fb.bloomtexture)/sizeof(r_fb.bloomtexture[i]));i++)
-                       {
-                               r_fb.bloomtexture[i] = R_LoadTexture2D(r_main_texturepool, "framebufferbloom", r_fb.bloomtexturewidth, r_fb.bloomtextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
-                               if (useviewfbo)
-                                       r_fb.bloomfbo[i] = R_Mesh_CreateFramebufferObject(NULL, r_fb.bloomtexture[i], NULL, NULL, NULL);
-                       }
-               }
-       }
-
-       // bloom texture is a different resolution
-       r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
-       r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
-       r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
-       r_fb.bloomwidth = bound(1, r_fb.bloomwidth, r_fb.bloomtexturewidth);
-       r_fb.bloomheight = bound(1, r_fb.bloomheight, r_fb.bloomtextureheight);
-
-       // set up a texcoord array for the full resolution screen image
-       // (we have to keep this around to copy back during final render)
-       r_fb.screentexcoord2f[0] = 0;
-       r_fb.screentexcoord2f[1] = (float)viewheight    / (float)r_fb.screentextureheight;
-       r_fb.screentexcoord2f[2] = (float)viewwidth     / (float)r_fb.screentexturewidth;
-       r_fb.screentexcoord2f[3] = (float)viewheight    / (float)r_fb.screentextureheight;
-       r_fb.screentexcoord2f[4] = (float)viewwidth     / (float)r_fb.screentexturewidth;
-       r_fb.screentexcoord2f[5] = 0;
-       r_fb.screentexcoord2f[6] = 0;
-       r_fb.screentexcoord2f[7] = 0;
-
-       if(r_fb.fbo) 
-       {
-               for (i = 1;i < 8;i += 2)
-               {
-                       r_fb.screentexcoord2f[i] += 1 - (float)(viewheight + r_refdef.view.y) / (float)r_fb.screentextureheight;
                }
        }
 
-       // set up a texcoord array for the reduced resolution bloom image
-       // (which will be additive blended over the screen image)
-       r_fb.bloomtexcoord2f[0] = 0;
-       r_fb.bloomtexcoord2f[1] = (float)r_fb.bloomheight / (float)r_fb.bloomtextureheight;
-       r_fb.bloomtexcoord2f[2] = (float)r_fb.bloomwidth  / (float)r_fb.bloomtexturewidth;
-       r_fb.bloomtexcoord2f[3] = (float)r_fb.bloomheight / (float)r_fb.bloomtextureheight;
-       r_fb.bloomtexcoord2f[4] = (float)r_fb.bloomwidth  / (float)r_fb.bloomtexturewidth;
-       r_fb.bloomtexcoord2f[5] = 0;
-       r_fb.bloomtexcoord2f[6] = 0;
-       r_fb.bloomtexcoord2f[7] = 0;
-
-       switch(vid.renderpath)
+       if (r_bloom.integer)
        {
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL20:
-       case RENDERPATH_SOFT:
-       case RENDERPATH_GLES1:
-       case RENDERPATH_GLES2:
-               break;
-       case RENDERPATH_D3D9:
-       case RENDERPATH_D3D10:
-       case RENDERPATH_D3D11:
-               for (i = 0;i < 4;i++)
-               {
-                       r_fb.screentexcoord2f[i*2+0] += 0.5f / (float)r_fb.screentexturewidth;
-                       r_fb.screentexcoord2f[i*2+1] += 0.5f / (float)r_fb.screentextureheight;
-                       r_fb.bloomtexcoord2f[i*2+0] += 0.5f / (float)r_fb.bloomtexturewidth;
-                       r_fb.bloomtexcoord2f[i*2+1] += 0.5f / (float)r_fb.bloomtextureheight;
-               }
-               break;
+               // bloom texture is a different resolution
+               r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
+               r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
+               r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
        }
+       else
+               r_fb.bloomwidth = r_fb.bloomheight = 0;
 
-       R_Viewport_InitOrtho(&r_fb.bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
+       r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
 
-       if (r_fb.fbo)
-               r_refdef.view.clear = true;
+       r_refdef.view.clear = true;
 }
 
 static void R_Bloom_MakeTexture(void)
 {
        int x, range, dir;
        float xoffset, yoffset, r, brighten;
-       rtexture_t *intex;
        float colorscale = r_bloom_colorscale.value;
+       r_viewport_t bloomviewport;
+       r_rendertarget_t *prev, *cur;
+       textype_t textype = r_fb.rt_screen->colortextype[0];
 
        r_refdef.stats[r_stat_bloom]++;
-    
-#if 0
-    // this copy is unnecessary since it happens in R_BlendView already
-       if (!r_fb.fbo)
-       {
-               R_Mesh_CopyToTexture(r_fb.colortexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
-               r_refdef.stats[r_stat_bloom_copypixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
-       }
-#endif
+
+       R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
 
        // scale down screen texture to the bloom texture size
        CHECKGLERROR
-       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);
+       prev = r_fb.rt_screen;
+       cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
+       R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
+       R_SetViewport(&bloomviewport);
        GL_CullFace(GL_NONE);
        GL_DepthTest(false);
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_Color(colorscale, colorscale, colorscale, 1);
-       // D3D has upside down Y coords, the easiest way to flip this is to flip the screen vertices rather than the texcoords, so we just use a different array for that...
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL20:
-       case RENDERPATH_GLES1:
-       case RENDERPATH_GLES2:
-       case RENDERPATH_SOFT:
-               R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.screentexcoord2f);
-               break;
-       case RENDERPATH_D3D9:
-       case RENDERPATH_D3D10:
-       case RENDERPATH_D3D11:
-               R_Mesh_PrepareVertices_Generic_Arrays(4, r_d3dscreenvertex3f, NULL, r_fb.screentexcoord2f);
-               break;
-       }
+       R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
        // TODO: do boxfilter scale-down in shader?
-       R_SetupShader_Generic(r_fb.colortexture, NULL, GL_MODULATE, 1, false, true, true);
+       R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, true);
        R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
        r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
-
        // we now have a properly scaled bloom image
-       if (!r_fb.bloomfbo[r_fb.bloomindex])
-       {
-               // copy it into the bloom texture
-               R_Mesh_CopyToTexture(r_fb.bloomtexture[r_fb.bloomindex], 0, 0, r_fb.bloomviewport.x, r_fb.bloomviewport.y, r_fb.bloomviewport.width, r_fb.bloomviewport.height);
-               r_refdef.stats[r_stat_bloom_copypixels] += r_fb.bloomviewport.width * r_fb.bloomviewport.height;
-       }
 
-       // multiply bloom image by itself as many times as desired
+       // multiply bloom image by itself as many times as desired to darken it
+       // TODO: if people actually use this it could be done more quickly in the previous shader pass
        for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
        {
-               intex = r_fb.bloomtexture[r_fb.bloomindex];
-               r_fb.bloomindex ^= 1;
-               R_Mesh_SetRenderTargets(r_fb.bloomfbo[r_fb.bloomindex], NULL, r_fb.bloomtexture[r_fb.bloomindex], NULL, NULL, NULL);
+               prev = cur;
+               cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
+               R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
                x *= 2;
                r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
-               if (!r_fb.bloomfbo[r_fb.bloomindex])
-               {
-                       GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); // square it and multiply by two
-                       GL_Color(r,r,r,1); // apply fix factor
-               }
-               else
-               {
-                       if(x <= 2)
-                               GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
-                       GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
-                       GL_Color(1,1,1,1); // no fix factor supported here
-               }
-               R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.bloomtexcoord2f);
-               R_SetupShader_Generic(intex, NULL, GL_MODULATE, 1, false, true, false);
+               if(x <= 2)
+                       GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
+               GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
+               GL_Color(1,1,1,1); // no fix factor supported here
+               R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
+               R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
                R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
                r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
-
-               if (!r_fb.bloomfbo[r_fb.bloomindex])
-               {
-                       // copy the darkened image to a texture
-                       R_Mesh_CopyToTexture(r_fb.bloomtexture[r_fb.bloomindex], 0, 0, r_fb.bloomviewport.x, r_fb.bloomviewport.y, r_fb.bloomviewport.width, r_fb.bloomviewport.height);
-                       r_refdef.stats[r_stat_bloom_copypixels] += r_fb.bloomviewport.width * r_fb.bloomviewport.height;
-               }
        }
 
        range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
@@ -6771,29 +6410,29 @@ static void R_Bloom_MakeTexture(void)
 
        for (dir = 0;dir < 2;dir++)
        {
-               intex = r_fb.bloomtexture[r_fb.bloomindex];
-               r_fb.bloomindex ^= 1;
-               R_Mesh_SetRenderTargets(r_fb.bloomfbo[r_fb.bloomindex], NULL, r_fb.bloomtexture[r_fb.bloomindex], NULL, NULL, NULL);
+               prev = cur;
+               cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
+               R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
                // blend on at multiple vertical offsets to achieve a vertical blur
                // TODO: do offset blends using GLSL
                // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_SetupShader_Generic(intex, NULL, GL_MODULATE, 1, false, true, false);
+               R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
                for (x = -range;x <= range;x++)
                {
                        if (!dir){xoffset = 0;yoffset = x;}
                        else {xoffset = x;yoffset = 0;}
-                       xoffset /= (float)r_fb.bloomtexturewidth;
-                       yoffset /= (float)r_fb.bloomtextureheight;
+                       xoffset /= (float)prev->texturewidth;
+                       yoffset /= (float)prev->textureheight;
                        // compute a texcoord array with the specified x and y offset
-                       r_fb.offsettexcoord2f[0] = xoffset+r_fb.bloomtexcoord2f[0];
-                       r_fb.offsettexcoord2f[1] = yoffset+r_fb.bloomtexcoord2f[1];
-                       r_fb.offsettexcoord2f[2] = xoffset+r_fb.bloomtexcoord2f[2];
-                       r_fb.offsettexcoord2f[3] = yoffset+r_fb.bloomtexcoord2f[3];
-                       r_fb.offsettexcoord2f[4] = xoffset+r_fb.bloomtexcoord2f[4];
-                       r_fb.offsettexcoord2f[5] = yoffset+r_fb.bloomtexcoord2f[5];
-                       r_fb.offsettexcoord2f[6] = xoffset+r_fb.bloomtexcoord2f[6];
-                       r_fb.offsettexcoord2f[7] = yoffset+r_fb.bloomtexcoord2f[7];
+                       r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
+                       r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
+                       r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
+                       r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
+                       r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
+                       r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
+                       r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
+                       r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
                        // this r value looks like a 'dot' particle, fading sharply to
                        // black at the edges
                        // (probably not realistic but looks good enough)
@@ -6801,27 +6440,27 @@ static void R_Bloom_MakeTexture(void)
                        //r = brighten/(range*2+1);
                        r = brighten / (range * 2 + 1);
                        if(range >= 1)
-                               r *= (1 - x*x/(float)(range*range));
+                               r *= (1 - x*x/(float)((range+1)*(range+1)));
+                       if (r <= 0)
+                               continue;
                        GL_Color(r, r, r, 1);
                        R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
                        R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
                        r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
                        GL_BlendFunc(GL_ONE, GL_ONE);
                }
-
-               if (!r_fb.bloomfbo[r_fb.bloomindex])
-               {
-                       // copy the vertically or horizontally blurred bloom view to a texture
-                       R_Mesh_CopyToTexture(r_fb.bloomtexture[r_fb.bloomindex], 0, 0, r_fb.bloomviewport.x, r_fb.bloomviewport.y, r_fb.bloomviewport.width, r_fb.bloomviewport.height);
-                       r_refdef.stats[r_stat_bloom_copypixels] += r_fb.bloomviewport.width * r_fb.bloomviewport.height;
-               }
        }
+
+       // now we have the bloom image, so keep track of it
+       r_fb.rt_bloom = cur;
 }
 
-static void R_BlendView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
+static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
 {
-       unsigned int permutation;
+       dpuint64 permutation;
        float uservecs[4][4];
+       rtexture_t *viewtexture;
+       rtexture_t *bloomtexture;
 
        R_EntityMatrix(&identitymatrix);
 
@@ -6834,113 +6473,74 @@ static void R_BlendView(int fbo, rtexture_t *depthtexture, rtexture_t *colortext
        case RENDERPATH_SOFT:
        case RENDERPATH_GLES2:
                permutation =
-                         (r_fb.bloomtexture[r_fb.bloomindex] ? SHADERPERMUTATION_BLOOM : 0)
+                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
                        | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
-                       | ((v_glslgamma.value && !vid_gammatables_trivial) ? SHADERPERMUTATION_GAMMARAMPS : 0)
+                       | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
                        | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
                        | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
 
-               if (r_fb.colortexture)
-               {
-                       if (!r_fb.fbo)
-                       {
-                               R_Mesh_CopyToTexture(r_fb.colortexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
-                               r_refdef.stats[r_stat_bloom_copypixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
-                       }
-
-                       if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
-                       {
-                               // declare variables
-                               float blur_factor, blur_mouseaccel, blur_velocity;
-                               static float blur_average; 
-                               static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
-
-                               // set a goal for the factoring
-                               blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
-                                       / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
-                               blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
-                                       / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
-                               blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
-                                       + (blur_mouseaccel * r_motionblur_mousefactor.value));
-
-                               // from the goal, pick an averaged value between goal and last value
-                               cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
-                               blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
-
-                               // enforce minimum amount of blur 
-                               blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
-
-                               //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
-
-                               // calculate values into a standard alpha
-                               cl.motionbluralpha = 1 - exp(-
-                                               (
-                                                (r_motionblur.value * blur_factor / 80)
-                                                +
-                                                (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
-                                               )
-                                               /
-                                               max(0.0001, cl.time - cl.oldtime) // fps independent
-                                         );
-
-                               // randomization for the blur value to combat persistent ghosting
-                               cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
-                               cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
-
-                               // apply the blur
-                               R_ResetViewRendering2D(fbo, depthtexture, colortexture);
-                               if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
-                               {
-                                       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-                                       GL_Color(1, 1, 1, cl.motionbluralpha);
-                                       switch(vid.renderpath)
-                                       {
-                                       case RENDERPATH_GL11:
-                                       case RENDERPATH_GL13:
-                                       case RENDERPATH_GL20:
-                                       case RENDERPATH_GLES1:
-                                       case RENDERPATH_GLES2:
-                                       case RENDERPATH_SOFT:
-                                               R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.screentexcoord2f);
-                                               break;
-                                       case RENDERPATH_D3D9:
-                                       case RENDERPATH_D3D10:
-                                       case RENDERPATH_D3D11:
-                                               R_Mesh_PrepareVertices_Generic_Arrays(4, r_d3dscreenvertex3f, NULL, r_fb.screentexcoord2f);
-                                               break;
-                                       }
-                                       R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true);
-                                       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
-                                       r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
-                               }
-
-                               // updates old view angles for next pass
-                               VectorCopy(cl.viewangles, blur_oldangles);
-
-                               // copy view into the ghost texture
-                               R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
-                               r_refdef.stats[r_stat_bloom_copypixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
-                               r_fb.ghosttexture_valid = true;
-                       }
-               }
-               else
-               {
-                       // no r_fb.colortexture means we're rendering to the real fb
-                       // we may still have to do view tint...
-                       if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
+               if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
+               {
+                       // declare variables
+                       float blur_factor, blur_mouseaccel, blur_velocity;
+                       static float blur_average; 
+                       static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
+
+                       // set a goal for the factoring
+                       blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
+                               / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
+                       blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
+                               / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
+                       blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
+                               + (blur_mouseaccel * r_motionblur_mousefactor.value));
+
+                       // from the goal, pick an averaged value between goal and last value
+                       cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
+                       blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
+
+                       // enforce minimum amount of blur 
+                       blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
+
+                       //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
+
+                       // calculate values into a standard alpha
+                       cl.motionbluralpha = 1 - exp(-
+                                       (
+                                               (r_motionblur.value * blur_factor / 80)
+                                               +
+                                               (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
+                                       )
+                                       /
+                                       max(0.0001, cl.time - cl.oldtime) // fps independent
+                                       );
+
+                       // randomization for the blur value to combat persistent ghosting
+                       cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
+                       cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
+
+                       // apply the blur
+                       R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
+                       if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
                        {
-                               // apply a color tint to the whole view
-                               R_ResetViewRendering2D(0, NULL, NULL);
-                               GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
-                               R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
-                               R_SetupShader_Generic_NoTexture(false, true);
                                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+                               GL_Color(1, 1, 1, cl.motionbluralpha);
+                               R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
+                               R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
+                               R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true);
                                R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+                               r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
                        }
-                       break; // no screen processing, no bloom, skip it
+
+                       // updates old view angles for next pass
+                       VectorCopy(cl.viewangles, blur_oldangles);
+
+                       // copy view into the ghost texture
+                       R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
+                       r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
+                       r_fb.ghosttexture_valid = true;
                }
 
-               if (r_fb.bloomtexture[0])
+               if (r_fb.bloomwidth)
                {
                        // make the bloom texture
                        R_Bloom_MakeTexture();
@@ -6959,18 +6559,32 @@ static void R_BlendView(int fbo, rtexture_t *depthtexture, rtexture_t *colortext
                if (r_glsl_postprocess_uservec4_enable.integer)
                        sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
 
-               R_ResetViewRendering2D(0, NULL, NULL); // here we render to the real framebuffer!
+               // render to the screen fbo
+               R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
                GL_Color(1, 1, 1, 1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
 
+               viewtexture = r_fb.rt_screen->colortexture[0];
+               bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
+
+               if (r_rendertarget_debug.integer >= 0)
+               {
+                       r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
+                       if (rt && rt->colortexture[0])
+                       {
+                               viewtexture = rt->colortexture[0];
+                               bloomtexture = NULL;
+                       }
+               }
+
+               R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
                switch(vid.renderpath)
                {
                case RENDERPATH_GL20:
                case RENDERPATH_GLES2:
-                       R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.screentexcoord2f, r_fb.bloomtexcoord2f);
                        R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
-                       if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , r_fb.colortexture);
-                       if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , r_fb.bloomtexture[r_fb.bloomindex]);
+                       if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
+                       if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
                        if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
                        if (r_glsl_permutation->loc_ViewTintColor           >= 0) qglUniform4f(r_glsl_permutation->loc_ViewTintColor     , r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
                        if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
@@ -6984,11 +6598,9 @@ static void R_BlendView(int fbo, rtexture_t *depthtexture, rtexture_t *colortext
                        break;
                case RENDERPATH_D3D9:
 #ifdef SUPPORTD3D
-                       // D3D has upside down Y coords, the easiest way to flip this is to flip the screen vertices rather than the texcoords, so we just use a different array for that...
-                       R_Mesh_PrepareVertices_Mesh_Arrays(4, r_d3dscreenvertex3f, NULL, NULL, NULL, NULL, r_fb.screentexcoord2f, r_fb.bloomtexcoord2f);
                        R_SetupShader_SetPermutationHLSL(SHADERMODE_POSTPROCESS, permutation);
-                       R_Mesh_TexBind(GL20TU_FIRST     , r_fb.colortexture);
-                       R_Mesh_TexBind(GL20TU_SECOND    , r_fb.bloomtexture[r_fb.bloomindex]);
+                       R_Mesh_TexBind(GL20TU_FIRST     , viewtexture);
+                       R_Mesh_TexBind(GL20TU_SECOND    , bloomtexture);
                        R_Mesh_TexBind(GL20TU_GAMMARAMPS, r_texture_gammaramps       );
                        hlslPSSetParameter4f(D3DPSREGISTER_ViewTintColor        , r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
                        hlslPSSetParameter2f(D3DPSREGISTER_PixelSize            , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
@@ -7008,10 +6620,9 @@ static void R_BlendView(int fbo, rtexture_t *depthtexture, rtexture_t *colortext
                        Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
                        break;
                case RENDERPATH_SOFT:
-                       R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.screentexcoord2f, r_fb.bloomtexcoord2f);
                        R_SetupShader_SetPermutationSoft(SHADERMODE_POSTPROCESS, permutation);
-                       R_Mesh_TexBind(GL20TU_FIRST     , r_fb.colortexture);
-                       R_Mesh_TexBind(GL20TU_SECOND    , r_fb.bloomtexture[r_fb.bloomindex]);
+                       R_Mesh_TexBind(GL20TU_FIRST     , viewtexture);
+                       R_Mesh_TexBind(GL20TU_SECOND    , bloomtexture);
                        R_Mesh_TexBind(GL20TU_GAMMARAMPS, r_texture_gammaramps       );
                        DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ViewTintColor     , r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
                        DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
@@ -7035,7 +6646,7 @@ static void R_BlendView(int fbo, rtexture_t *depthtexture, rtexture_t *colortext
                if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
                {
                        // apply a color tint to the whole view
-                       R_ResetViewRendering2D(0, NULL, NULL);
+                       R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
                        GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
                        R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
                        R_SetupShader_Generic_NoTexture(false, true);
@@ -7139,7 +6750,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)
@@ -7157,14 +6768,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)
        {
@@ -7172,7 +6783,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;
@@ -7185,7 +6796,7 @@ void R_UpdateVariables(void)
        case RENDERPATH_D3D11:
        case RENDERPATH_SOFT:
        case RENDERPATH_GLES2:
-               if(v_glslgamma.integer && !vid_gammatables_trivial)
+               if(!vid_gammatables_trivial)
                {
                        if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
                        {
@@ -7297,19 +6908,20 @@ R_RenderView
 */
 int dpsoftrast_test;
 extern cvar_t r_shadow_bouncegrid;
-void R_RenderView(void)
+void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
 {
        matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
-       int fbo;
-       rtexture_t *depthtexture;
-       rtexture_t *colortexture;
+       int viewfbo = 0;
+       rtexture_t *viewdepthtexture = NULL;
+       rtexture_t *viewcolortexture = NULL;
+       int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
 
        dpsoftrast_test = r_test.integer;
 
        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();
@@ -7340,7 +6952,7 @@ void R_RenderView(void)
                r_fb.water.enabled = false;
                r_fb.water.numwaterplanes = 0;
 
-               R_RenderScene(0, NULL, NULL);
+               R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
 
                r_refdef.view.matrix = originalmatrix;
 
@@ -7365,31 +6977,41 @@ void R_RenderView(void)
 
        R_Shadow_UpdateWorldLightSelection();
 
+       // this will set up r_fb.rt_screen
        R_Bloom_StartFrame();
 
        // apply bloom brightness offset
-       if(r_fb.bloomtexture[0])
+       if(r_fb.rt_bloom)
                r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
 
-       R_Water_StartFrame();
+       // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
+       if (r_fb.rt_screen)
+       {
+               viewfbo = r_fb.rt_screen->fbo;
+               viewdepthtexture = r_fb.rt_screen->depthtexture;
+               viewcolortexture = r_fb.rt_screen->colortexture[0];
+               viewx = 0;
+               viewy = 0;
+               viewwidth = width;
+               viewheight = height;
+       }
 
-       // now we probably have an fbo to render into
-       fbo = r_fb.fbo;
-       depthtexture = r_fb.depthtexture;
-       colortexture = r_fb.colortexture;
+       R_Water_StartFrame();
 
        CHECKGLERROR
        if (r_timereport_active)
                R_TimeReport("viewsetup");
 
-       R_ResetViewRendering3D(fbo, depthtexture, colortexture);
+       R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
+
+       // clear the whole fbo every frame - otherwise the driver will consider
+       // it to be an inter-frame texture and stall in multi-gpu configurations
+       if (r_fb.rt_screen)
+               GL_ScissorTest(false);
+       R_ClearScreen(r_refdef.fogenabled);
+       if (r_timereport_active)
+               R_TimeReport("viewclear");
 
-       if (r_refdef.view.clear || r_refdef.fogenabled || fbo)
-       {
-               R_ClearScreen(r_refdef.fogenabled);
-               if (r_timereport_active)
-                       R_TimeReport("viewclear");
-       }
        r_refdef.view.clear = true;
 
        r_refdef.view.showdebug = true;
@@ -7408,24 +7030,29 @@ void R_RenderView(void)
 
        r_fb.water.numwaterplanes = 0;
        if (r_fb.water.enabled)
-               R_RenderWaterPlanes(fbo, depthtexture, colortexture);
-
-       R_RenderScene(fbo, depthtexture, colortexture);
+               R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
+
+       // for the actual view render we use scissoring a fair amount, so scissor
+       // test needs to be on
+       if (r_fb.rt_screen)
+               GL_ScissorTest(true);
+       GL_Scissor(viewx, viewy, viewwidth, viewheight);
+       R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
        r_fb.water.numwaterplanes = 0;
 
-       R_BlendView(fbo, depthtexture, colortexture);
+       // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
+       GL_ScissorTest(false);
+
+       R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
        if (r_timereport_active)
                R_TimeReport("blendview");
 
-       GL_Scissor(0, 0, vid.width, vid.height);
-       GL_ScissorTest(false);
-
        r_refdef.view.matrix = originalmatrix;
 
        CHECKGLERROR
 }
 
-void R_RenderWaterPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
+void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
 {
        if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
        {
@@ -7444,7 +7071,7 @@ void R_RenderWaterPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortex
 
        if (r_fb.water.numwaterplanes)
        {
-               R_Water_ProcessPlanes(fbo, depthtexture, colortexture);
+               R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
                if (r_timereport_active)
                        R_TimeReport("waterscenes");
        }
@@ -7457,7 +7084,7 @@ 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)
+void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
 {
        qboolean shadowmapping = false;
 
@@ -7500,16 +7127,25 @@ void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
                if (skyrendermasked && skyrenderlater)
                {
                        // we have to force off the water clipping plane while rendering sky
-                       R_SetupView(false, fbo, depthtexture, colortexture);
+                       R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
                        R_Sky();
-                       R_SetupView(true, fbo, depthtexture, colortexture);
+                       R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
                        if (r_timereport_active)
                                R_TimeReport("sky");
                }
        }
 
+       // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
+       r_shadow_viewfbo = viewfbo;
+       r_shadow_viewdepthtexture = viewdepthtexture;
+       r_shadow_viewcolortexture = viewcolortexture;
+       r_shadow_viewx = viewx;
+       r_shadow_viewy = viewy;
+       r_shadow_viewwidth = viewwidth;
+       r_shadow_viewheight = viewheight;
+
        R_Shadow_PrepareModelShadows();
-       R_Shadow_PrepareLights(fbo, depthtexture, colortexture);
+       R_Shadow_PrepareLights();
        if (r_timereport_active)
                R_TimeReport("preparelights");
 
@@ -7559,11 +7195,11 @@ 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_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
                R_Shadow_DrawModelShadows();
-               R_ResetViewRendering3D(fbo, depthtexture, colortexture);
+               R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
                // don't let sound skip if going slow
                if (r_refdef.scene.extraupdate)
                        S_ExtraUpdate ();
@@ -7580,11 +7216,11 @@ 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_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
                R_Shadow_DrawModelShadows();
-               R_ResetViewRendering3D(fbo, depthtexture, colortexture);
+               R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
                // don't let sound skip if going slow
                if (r_refdef.scene.extraupdate)
                        S_ExtraUpdate ();
@@ -7612,15 +7248,8 @@ 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)
-               VM_CL_AddPolygonsToMeshQueue(CLVM_prog);
-
        if (r_refdef.view.showdebug)
        {
                if (cl_locs_show.integer)
@@ -7742,7 +7371,7 @@ static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float c
        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);
@@ -7903,7 +7532,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);
@@ -7920,10 +7549,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)
        {
@@ -8266,10 +7895,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;
@@ -8333,27 +7963,139 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
 
        t->currentmaterialflags = t->basematerialflags;
-       t->currentalpha = rsurface.colormod[3] * t->basealpha;
+       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, we have to ignore colormod and view colorscale
+               t->currentmaterialflags = t->currentmaterialflags | 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] = q == 2;
+                       t->render_modellight_ambient[q] = 0;
+                       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;
+               }
        }
+
+       if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
+       {
+               // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
+               // attribute, we punt it to the lightmap path and hope for the best,
+               // but lighting doesn't work.
+               //
+               // FIXME: this is fine for effects but CSQC polygons should be subject
+               // to lighting.
+               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] = q == 2;
+                       t->render_modellight_ambient[q] = 0;
+                       t->render_modellight_diffuse[q] = 0;
+                       t->render_modellight_specular[q] = 0;
+                       t->render_lightmap_ambient[q] = 0;
+                       t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
+                       t->render_lightmap_specular[q] = 0;
+                       t->render_rtlight_diffuse[q] = 0;
+                       t->render_rtlight_specular[q] = 0;
+               }
+       }
+
+       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)
@@ -8398,7 +8140,7 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                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;
@@ -8438,7 +8180,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))
@@ -8447,20 +8188,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
@@ -8481,12 +8221,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)
        {
@@ -8512,205 +8260,60 @@ 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)
-               {
-                       // 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]);
-               }
-               else
+               if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
                {
-                       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]);
-                       // now add ambient passes if needed
-                       if (VectorLength2(ambientcolor) >= (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]);
-                       }
-               }
-               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]);
-               if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
-               {
-                       // if this is opaque use alpha blend which will darken the earlier
-                       // passes cheaply.
-                       //
-                       // if this is an alpha blended material, all the earlier passes
-                       // were darkened by fog already, so we only need to add the fog
-                       // color ontop through the fog mask texture
-                       //
-                       // if this is an additive blended material, all the earlier passes
-                       // 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]);
+                       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);
                }
-       }
-
-       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;
+               else
+               {
+                       // 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);
+                       // now add ambient passes if needed
+                       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, 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, 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
+                       // passes cheaply.
+                       //
+                       // if this is an alpha blended material, all the earlier passes
+                       // were darkened by fog already, so we only need to add the fog
+                       // color ontop through the fog mask texture
+                       //
+                       // if this is an additive blended material, all the earlier passes
+                       // 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->currentalpha);
+               }
+       }
+
+       return t;
 }
 
+rsurfacestate_t rsurface;
+
 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
 {
        dp_model_t *model = ent->model;
@@ -8722,6 +8325,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;
@@ -8730,18 +8335,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;
@@ -8984,13 +8581,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;
@@ -10611,9 +10201,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];
        }
 }
@@ -10677,7 +10267,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;
@@ -10695,14 +10285,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);
@@ -10710,7 +10300,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;
@@ -10723,14 +10313,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)
        {
@@ -10765,7 +10355,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);
@@ -10808,6 +10398,7 @@ void RSurf_SetupDepthAndCulling(void)
 
 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
 {
+       int i, j;
        // transparent sky would be ridiculous
        if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
                return;
@@ -10815,20 +10406,75 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_
        skyrenderlater = true;
        RSurf_SetupDepthAndCulling();
        GL_DepthMask(true);
-       // LordHavoc: HalfLife maps have freaky skypolys so don't use
+
+       // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
+       if (r_sky_scissor.integer)
+       {
+               RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
+               for (i = 0; i < texturenumsurfaces; i++)
+               {
+                       const msurface_t *surf = texturesurfacelist[i];
+                       const float *v;
+                       float p[3];
+                       float mins[3], maxs[3];
+                       int scissor[4];
+                       for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
+                       {
+                               Matrix4x4_Transform(&rsurface.matrix, v, p);
+                               if (j > 0)
+                               {
+                                       if (mins[0] > p[0]) mins[0] = p[0];
+                                       if (mins[1] > p[1]) mins[1] = p[1];
+                                       if (mins[2] > p[2]) mins[2] = p[2];
+                                       if (maxs[0] < p[0]) maxs[0] = p[0];
+                                       if (maxs[1] < p[1]) maxs[1] = p[1];
+                                       if (maxs[2] < p[2]) maxs[2] = p[2];
+                               }
+                               else
+                               {
+                                       VectorCopy(p, mins);
+                                       VectorCopy(p, maxs);
+                               }
+                       }
+                       if (!R_ScissorForBBox(mins, maxs, scissor))
+                       {
+                               if (skyscissor[2])
+                               {
+                                       if (skyscissor[0] > scissor[0])
+                                       {
+                                               skyscissor[2] += skyscissor[0] - scissor[0];
+                                               skyscissor[0] = scissor[0];
+                                       }
+                                       if (skyscissor[1] > scissor[1])
+                                       {
+                                               skyscissor[3] += skyscissor[1] - scissor[1];
+                                               skyscissor[1] = scissor[1];
+                                       }
+                                       if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
+                                               skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
+                                       if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
+                                               skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
+                               }
+                               else
+                                       Vector4Copy(scissor, skyscissor);
+                       }
+               }
+       }
+
+       // LadyHavoc: HalfLife maps have freaky skypolys so don't use
        // skymasking on them, and Quake3 never did sky masking (unlike
        // software Quake and software Quake2), so disable the sky masking
        // 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->brush.skymasking && r_q1bsp_skymasking.integer && !r_refdef.viewcache.world_novis && !r_trippy.integer)
+       if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.skymasking && (r_refdef.scene.worldmodel->brush.isq3bsp ? r_q3bsp_renderskydepth.integer : r_q1bsp_skymasking.integer) && !r_refdef.viewcache.world_novis && !r_trippy.integer)
        {
                R_Mesh_ResetTextureState();
                if (skyrendermasked)
                {
                        R_SetupShader_DepthOrShadow(false, false, false);
                        // depth-only (masking)
-                       GL_ColorMask(0,0,0,0);
+                       GL_ColorMask(0, 0, 0, 0);
                        // just to make sure that braindead drivers don't draw
                        // anything despite that colormask...
                        GL_BlendFunc(GL_ZERO, GL_ONE);
@@ -10862,7 +10508,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;
        }
@@ -10890,18 +10536,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();
                        }
                }
@@ -10910,7 +10556,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();
 }
 
@@ -10921,7 +10567,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++)
@@ -11028,7 +10674,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++)
@@ -11133,14 +10779,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
        {
@@ -11150,11 +10797,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")
@@ -11162,27 +10809,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
@@ -11195,32 +10842,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
                {
@@ -11229,12 +10864,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();
@@ -11313,36 +10948,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
@@ -11381,12 +10986,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
        {
@@ -11491,12 +11091,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)
@@ -11544,84 +11141,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
@@ -12287,10 +11806,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;
 
@@ -12643,101 +12159,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;
@@ -12756,12 +12177,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);
@@ -12808,7 +12224,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++)
@@ -12828,7 +12244,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;
        }
 
@@ -12839,12 +12255,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
@@ -12871,11 +12301,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;
@@ -12895,6 +12326,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;