]> 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 bf55c9f70ebd9caf59a55348fb14c1fad58d0398..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"
@@ -176,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"};
@@ -213,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"};
@@ -268,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;
@@ -321,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,
@@ -329,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)
 {
@@ -2034,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;
@@ -2050,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:
@@ -2145,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
@@ -2213,7 +2181,7 @@ 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
@@ -2222,28 +2190,27 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        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);
@@ -2256,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);
@@ -2276,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;
@@ -2286,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;
@@ -2297,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;
@@ -2307,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)
                {
@@ -2332,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;
@@ -2402,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))
                {
@@ -2483,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)
                {
@@ -2495,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
@@ -2511,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;
@@ -2521,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))
                {
@@ -2540,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)
@@ -2562,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)
@@ -2573,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)
@@ -2592,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)
@@ -2629,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]);
@@ -2641,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)
                {
@@ -2700,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]);
@@ -2716,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);
@@ -2745,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              );
@@ -2806,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)
@@ -2848,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)
                {
@@ -2872,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);
                }
@@ -2894,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);}
@@ -2909,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);
@@ -2928,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              );
@@ -2964,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)
                {
@@ -3026,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);
                }
@@ -3048,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);
@@ -3077,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              );
@@ -3244,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;
@@ -3253,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);
                }
        }
 }
@@ -3309,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;
@@ -3328,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);
@@ -3397,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;
@@ -3431,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;
        }
@@ -3856,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++)
                {
@@ -3904,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
 {
@@ -4163,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);
@@ -4202,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();
@@ -4410,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);
@@ -4448,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);
@@ -5123,171 +5023,6 @@ void R_AnimCache_CacheVisibleEntities(void)
 
 //==================================================================================
 
-extern cvar_t r_overheadsprites_pushback;
-
-static void R_GetDirectedFullbright(vec3_t ambient, vec3_t diffuse, vec3_t worldspacenormal)
-{
-       vec3_t angles;
-
-       VectorSet(ambient, r_fullbright_directed_ambient.value, r_fullbright_directed_ambient.value, r_fullbright_directed_ambient.value);
-       VectorSet(diffuse, r_fullbright_directed_diffuse.value, r_fullbright_directed_diffuse.value, r_fullbright_directed_diffuse.value);
-
-       // Use cl.viewangles and not r_refdef.view.forward here so it is the
-       // same for all stereo views, and to better handle pitches outside
-       // [-90, 90] (in_pitch_* cvars allow that).
-       VectorCopy(cl.viewangles, angles);
-       if (r_fullbright_directed_pitch_relative.integer) {
-               angles[PITCH] += r_fullbright_directed_pitch.value;
-       } else {
-               angles[PITCH] = r_fullbright_directed_pitch.value;
-       }
-       AngleVectors(angles, worldspacenormal, NULL, NULL);
-       VectorNegate(worldspacenormal, worldspacenormal);
-}
-
-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?
-                       // The logic here currently matches RSurf_ActiveWorldEntity.
-                       if (r_fullbright_directed.integer && (r_fullbright.integer || !ent->model || !ent->model->lit))
-                       {
-                               R_GetDirectedFullbright(ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
-                               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);
-                       }
-                       else
-                       {
-                               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 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
-                               {
-                                       R_CompleteLightPoint(ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal, org, LP_LIGHTMAP);
-                               }
-                               else if (r_fullbright_directed.integer)
-                               {
-                                       R_GetDirectedFullbright(ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
-                               }
-                               else
-                               {
-                                       VectorSet(ent->modellight_ambient, 1, 1, 1);
-                               }
-
-                               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
-                       {
-                               // EF_FULLBRIGHT entity.
-                               if (r_fullbright_directed.integer)
-                               {
-                                       R_GetDirectedFullbright(ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
-                               }
-                               else
-                               {
-                                       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;
@@ -5554,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)
@@ -5785,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)
@@ -5794,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;
@@ -5807,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)
@@ -5826,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)
        {
@@ -5895,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);
@@ -5938,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);
@@ -5997,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;
@@ -6027,80 +5849,29 @@ 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);
-       }
+               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;
 
-       // 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;
-       }
-
-       r_fb.water.maxwaterplanes = MAX_WATERPLANES;
-       r_fb.water.numwaterplanes = 0;
-}
+       r_fb.water.maxwaterplanes = MAX_WATERPLANES;
+       r_fb.water.numwaterplanes = 0;
+}
 
 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
 {
@@ -6219,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;
@@ -6227,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;
 
@@ -6256,54 +6026,11 @@ 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++)
+       for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
        {
-               if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
-                       continue;
-               if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
-               {
-                       if (!p->texture_refraction)
-                               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)
-                               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_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);
-                       }
-               }
+               p->rt_reflection = NULL;
+               p->rt_refraction = NULL;
+               p->rt_camera = NULL;
        }
 
        // render views
@@ -6318,20 +6045,27 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
        {
                if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
                        continue;
+
                if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
                {
+                       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;
+                       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)
                        {
-                               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;
@@ -6346,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
@@ -6355,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);
@@ -6395,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
@@ -6404,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;
@@ -6453,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;
@@ -6500,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:
@@ -6549,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);
@@ -6573,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))
        {
@@ -6595,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)
@@ -6651,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) 
+       if (r_bloom.integer)
        {
-               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)
-       {
-       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;
@@ -6834,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)
@@ -6864,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)
 {
        dpuint64 permutation;
        float uservecs[4][4];
+       rtexture_t *viewtexture;
+       rtexture_t *bloomtexture;
 
        R_EntityMatrix(&identitymatrix);
 
@@ -6897,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)
+               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)
                        {
-                               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))
-                       {
-                               // 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();
@@ -7022,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);
@@ -7047,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);
@@ -7071,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);
@@ -7098,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);
@@ -7202,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)
@@ -7220,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)
        {
@@ -7235,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;
@@ -7248,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)
                        {
@@ -7360,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();
@@ -7403,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;
 
@@ -7428,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;
@@ -7471,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)
        {
@@ -7507,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");
        }
@@ -7520,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;
 
@@ -7563,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");
 
@@ -7622,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 ();
@@ -7643,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 ();
@@ -7677,9 +7250,6 @@ void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
                        R_TimeReport("explosions");
        }
 
-       if (cl.csqc_loaded)
-               VM_CL_AddPolygonsToMeshQueue(CLVM_prog);
-
        if (r_refdef.view.showdebug)
        {
                if (cl_locs_show.integer)
@@ -7801,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);
@@ -7962,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);
@@ -7979,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)
        {
@@ -8325,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;
@@ -8392,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)
@@ -8457,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;
@@ -8497,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))
@@ -8506,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
@@ -8540,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)
        {
@@ -8571,213 +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)
+               if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
                {
-                       // fullbright is not affected by r_refdef.lightmapintensity
-                       R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, t->lightmapcolor[0], t->lightmapcolor[1], t->lightmapcolor[2], t->lightmapcolor[3]);
-                       if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->pantstexture)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->pantstexture, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * t->lightmapcolor[0], rsurface.colormap_pantscolor[1] * t->lightmapcolor[1], rsurface.colormap_pantscolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
-                       if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->shirttexture)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->shirttexture, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * t->lightmapcolor[0], rsurface.colormap_shirtcolor[1] * t->lightmapcolor[1], rsurface.colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
-               }
-               else
-               {
-                       vec3_t ambientcolor;
-                       float colorscale;
-                       // set the color tint used for lights affecting this surface
-                       VectorSet(t->dlightcolor, t->lightmapcolor[0] * t->lightmapcolor[3], t->lightmapcolor[1] * t->lightmapcolor[3], t->lightmapcolor[2] * t->lightmapcolor[3]);
-                       colorscale = 2;
-                       // q3bsp has no lightmap updates, so the lightstylevalue that
-                       // would normally be baked into the lightmap must be
-                       // applied to the color
-                       // FIXME: r_glsl 1 rendering doesn't support overbright lightstyles with this (the default light style is not overbright)
-                       if (model->type == mod_brushq3)
-                               colorscale *= r_refdef.scene.rtlightstylevalue[0];
-                       colorscale *= r_refdef.lightmapintensity;
-                       VectorScale(t->lightmapcolor, r_refdef.scene.ambient, ambientcolor);
-                       VectorScale(t->lightmapcolor, colorscale, t->lightmapcolor);
                        // basic lit geometry
-                       R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, t->lightmapcolor[0], t->lightmapcolor[1], t->lightmapcolor[2], t->lightmapcolor[3]);
+                       R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2], t->currentalpha);
                        // add pants/shirt if needed
-                       if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->pantstexture)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->pantstexture, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * t->lightmapcolor[0], rsurface.colormap_pantscolor[1] * t->lightmapcolor[1], rsurface.colormap_pantscolor[2]  * t->lightmapcolor[2], t->lightmapcolor[3]);
-                       if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->shirttexture)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->shirttexture, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * t->lightmapcolor[0], rsurface.colormap_shirtcolor[1] * t->lightmapcolor[1], rsurface.colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
-                       // 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 (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);
                }
-               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]);
-               }
-       }
-
-       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;
-       if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
-       {
-               R_GetDirectedFullbright(rsurface.modellight_ambient, rsurface.modellight_diffuse, rsurface.modellight_lightdir);
-               rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
-       }
-       else
-       {
-               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;
@@ -8790,9 +8326,7 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        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;
@@ -8805,14 +8339,6 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        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;
@@ -9055,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;
@@ -10682,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];
        }
 }
@@ -10748,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;
@@ -10766,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);
@@ -10781,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;
@@ -10794,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)
        {
@@ -10836,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);
@@ -10879,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;
@@ -10886,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);
@@ -10933,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;
        }
@@ -10961,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();
                        }
                }
@@ -10981,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();
 }
 
@@ -10992,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++)
@@ -11099,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++)
@@ -11204,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
        {
@@ -11221,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")
@@ -11233,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
@@ -11266,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
                {
@@ -11300,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();
@@ -11384,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
@@ -11452,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
        {
@@ -11562,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)
@@ -11615,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
@@ -12358,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;
 
@@ -12714,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;
@@ -12827,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);
@@ -12879,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++)
@@ -12899,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;
        }
 
@@ -12910,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
@@ -12942,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;
@@ -12966,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;