]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
implemented and debugged BIH (Bounding Interval Hierarchy) code, more
[xonotic/darkplaces.git] / gl_rmain.c
index 17128079c105021cd20ec2a1a3f1d8f68cd88a43..a3b5b241cb601e7abf563de941d0f0a9b4a62d34 100644 (file)
@@ -24,15 +24,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "r_shadow.h"
 #include "polygon.h"
 #include "image.h"
+#include "ft2.h"
 
 mempool_t *r_main_mempool;
 rtexturepool_t *r_main_texturepool;
 
-static int r_frame = 0; ///< used only by R_GetCurrentTexture
+static int r_textureframe = 0; ///< used only by R_GetCurrentTexture
 
-qboolean r_loadnormalmap;
-qboolean r_loadgloss;
+static qboolean r_loadnormalmap;
+static qboolean r_loadgloss;
 qboolean r_loadfog;
+static qboolean r_loaddds;
+static qboolean r_savedds;
 
 //
 // screen size info
@@ -54,8 +57,6 @@ cvar_t r_equalize_entities_minambient = {CVAR_SAVE, "r_equalize_entities_minambi
 cvar_t r_equalize_entities_by = {CVAR_SAVE, "r_equalize_entities_by", "0.7", "light equalizing: exponent of dynamics compression (0 = no compression, 1 = full compression)"};
 cvar_t r_equalize_entities_to = {CVAR_SAVE, "r_equalize_entities_to", "0.8", "light equalizing: target light level"};
 
-cvar_t r_animcache = {CVAR_SAVE, "r_animcache", "1", "cache animation frames to save CPU usage, primarily optimizes shadows and reflections"};
-
 cvar_t r_depthfirst = {CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
 cvar_t r_useinfinitefarclip = {CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
 cvar_t r_farclip_base = {0, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
@@ -90,6 +91,8 @@ cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "
 cvar_t r_shadows_throwdirection = {CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
 cvar_t r_shadows_drawafterrtlighting = {CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
 cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
+cvar_t r_shadows_focus = {CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
+cvar_t r_shadows_shadowmapscale = {CVAR_SAVE, "r_shadows_shadowmapscale", "1", "increases shadowmap quality (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
 cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
 cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
 cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
@@ -97,6 +100,7 @@ cvar_t r_polygonoffset_decals_factor = {0, "r_polygonoffset_decals_factor", "0",
 cvar_t r_polygonoffset_decals_offset = {0, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
 cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
 cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
+cvar_t r_transparentdepthmasking = {CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
 
 cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
@@ -107,6 +111,19 @@ cvar_t gl_fogstart = {0, "gl_fogstart", "0", "nehahra fog start distance (for Ne
 cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
 cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
 
+cvar_t r_texture_dds_load = {CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
+cvar_t r_texture_dds_save = {CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
+
+cvar_t r_texture_convertsRGB_2d = {0, "r_texture_convertsRGB_2d", "0", "load textures as sRGB and convert to linear for proper shading"};
+cvar_t r_texture_convertsRGB_skin = {0, "r_texture_convertsRGB_skin", "0", "load textures as sRGB and convert to linear for proper shading"};
+cvar_t r_texture_convertsRGB_cubemap = {0, "r_texture_convertsRGB_cubemap", "0", "load textures as sRGB and convert to linear for proper shading"};
+cvar_t r_texture_convertsRGB_skybox = {0, "r_texture_convertsRGB_skybox", "0", "load textures as sRGB and convert to linear for proper shading"};
+cvar_t r_texture_convertsRGB_particles = {0, "r_texture_convertsRGB_particles", "0", "load textures as sRGB and convert to linear for proper shading"};
+
+cvar_t r_textureunits = {0, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
+static cvar_t gl_combine = {CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
+static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
+
 cvar_t r_glsl_deluxemapping = {CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
 cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
@@ -123,7 +140,7 @@ cvar_t r_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier"
 cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
 cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
 
-cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites"};
+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"};
 cvar_t r_lerplightstyles = {CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
@@ -153,8 +170,13 @@ cvar_t r_track_sprites = {CVAR_SAVE, "r_track_sprites", "1", "track SPR_LABEL* s
 cvar_t r_track_sprites_flags = {CVAR_SAVE, "r_track_sprites_flags", "1", "1: Rotate sprites accodringly, 2: Make it a continuous rotation"};
 cvar_t r_track_sprites_scalew = {CVAR_SAVE, "r_track_sprites_scalew", "1", "width scaling of tracked sprites"};
 cvar_t r_track_sprites_scaleh = {CVAR_SAVE, "r_track_sprites_scaleh", "1", "height scaling of tracked sprites"};
+cvar_t r_overheadsprites_perspective = {CVAR_SAVE, "r_overheadsprites_perspective", "0.15", "fake perspective effect for SPR_OVERHEAD sprites"};
+cvar_t r_overheadsprites_pushback = {CVAR_SAVE, "r_overheadsprites_pushback", "16", "how far to pull the SPR_OVERHEAD sprites toward the eye (used to avoid intersections with 3D models)"};
+
 cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
 
+cvar_t r_framedatasize = {CVAR_SAVE, "r_framedatasize", "1", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
+
 extern cvar_t v_glslgamma;
 
 extern qboolean v_flipped_state;
@@ -197,6 +219,18 @@ rtexture_t *r_texture_fogattenuation;
 rtexture_t *r_texture_gammaramps;
 unsigned int r_texture_gammaramps_serial;
 //rtexture_t *r_texture_fogintensity;
+rtexture_t *r_texture_reflectcube;
+
+// TODO: hash lookups?
+typedef struct cubemapinfo_s
+{
+       char basename[64];
+       rtexture_t *texture;
+}
+cubemapinfo_t;
+
+int r_texture_numcubemaps;
+cubemapinfo_t r_texture_cubemaps[MAX_CUBEMAPS];
 
 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
 unsigned int r_numqueries;
@@ -221,8 +255,6 @@ const float r_screenvertex3f[12] =
        0, 1, 0
 };
 
-extern void R_DrawModelShadows(void);
-
 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
 {
        int i;
@@ -279,22 +311,22 @@ static void R_BuildBlankTextures(void)
        data[1] = 128; // normal Y
        data[0] = 255; // normal Z
        data[3] = 128; // height
-       r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_PERSISTENT, NULL);
+       r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, NULL);
        data[0] = 255;
        data[1] = 255;
        data[2] = 255;
        data[3] = 255;
-       r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_PERSISTENT, NULL);
+       r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, NULL);
        data[0] = 128;
        data[1] = 128;
        data[2] = 128;
        data[3] = 255;
-       r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_PERSISTENT, NULL);
+       r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, NULL);
        data[0] = 0;
        data[1] = 0;
        data[2] = 0;
        data[3] = 255;
-       r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_PERSISTENT, NULL);
+       r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, NULL);
 }
 
 static void R_BuildNoTexture(void)
@@ -322,14 +354,14 @@ static void R_BuildNoTexture(void)
                        }
                }
        }
-       r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_MIPMAP | TEXF_PERSISTENT, NULL);
+       r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, NULL);
 }
 
 static void R_BuildWhiteCube(void)
 {
        unsigned char data[6*1*1*4];
        memset(data, 255, sizeof(data));
-       r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
+       r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, NULL);
 }
 
 static void R_BuildNormalizationCube(void)
@@ -338,7 +370,8 @@ static void R_BuildNormalizationCube(void)
        vec3_t v;
        vec_t s, t, intensity;
 #define NORMSIZE 64
-       unsigned char data[6][NORMSIZE][NORMSIZE][4];
+       unsigned char *data;
+       data = Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
        for (side = 0;side < 6;side++)
        {
                for (y = 0;y < NORMSIZE;y++)
@@ -382,14 +415,15 @@ static void R_BuildNormalizationCube(void)
                                        break;
                                }
                                intensity = 127.0f / sqrt(DotProduct(v, v));
-                               data[side][y][x][2] = (unsigned char)(128.0f + intensity * v[0]);
-                               data[side][y][x][1] = (unsigned char)(128.0f + intensity * v[1]);
-                               data[side][y][x][0] = (unsigned char)(128.0f + intensity * v[2]);
-                               data[side][y][x][3] = 255;
+                               data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
+                               data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
+                               data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
+                               data[((side*64+y)*64+x)*4+3] = 255;
                        }
                }
        }
-       r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, &data[0][0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
+       r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, NULL);
+       Mem_Free(data);
 }
 
 static void R_BuildFogTexture(void)
@@ -409,18 +443,18 @@ static void R_BuildFogTexture(void)
        for (x = 0;x < FOGMASKTABLEWIDTH;x++)
        {
                d = (x * r - r_refdef.fogmasktable_start);
-               if(developer.integer >= 100)
-                       Con_Printf("%f ", d);
+               if(developer_extra.integer)
+                       Con_DPrintf("%f ", d);
                d = max(0, d);
                if (r_fog_exp2.integer)
                        alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
                else
                        alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
-               if(developer.integer >= 100)
-                       Con_Printf(" : %f ", alpha);
+               if(developer_extra.integer)
+                       Con_DPrintf(" : %f ", alpha);
                alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
-               if(developer.integer >= 100)
-                       Con_Printf(" = %f\n", alpha);
+               if(developer_extra.integer)
+                       Con_DPrintf(" = %f\n", alpha);
                r_refdef.fogmasktable[x] = bound(0, alpha, 1);
        }
 
@@ -443,18 +477,29 @@ static void R_BuildFogTexture(void)
        }
        else
        {
-               r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
-               //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
+               r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT | TEXF_ALLOWUPDATES, NULL);
+               //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALLOWUPDATES, NULL);
        }
 }
 
+//=======================================================================================================================================================
+
 static const char *builtinshaderstring =
 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
 "// written by Forest 'LordHavoc' Hale\n"
+"// shadowmapping enhancements by Lee 'eihrul' Salzman\n"
 "\n"
-"// enable various extensions depending on permutation:\n"
+"#if defined(USEFOGINSIDE) || defined(USEFOGOUTSIDE)\n"
+"# define USEFOG\n"
+"#endif\n"
+"#if defined(MODE_LIGHTMAP) || defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
+"#define USELIGHTMAP\n"
+"#endif\n"
+"#if defined(USESPECULAR) || defined(USEOFFSETMAPPING) || defined(USEREFLECTCUBE)\n"
+"#define USEEYEVECTOR\n"
+"#endif\n"
 "\n"
-"#ifdef USESHADOWMAPRECT\n"
+"#if defined(USESHADOWMAPRECT) || defined(MODE_DEFERREDLIGHTSOURCE) || defined(USEDEFERREDLIGHTMAP)\n"
 "# extension GL_ARB_texture_rectangle : enable\n"
 "#endif\n"
 "\n"
@@ -475,16 +520,14 @@ static const char *builtinshaderstring =
 "# extension GL_EXT_gpu_shader4 : enable\n"
 "#endif\n"
 "\n"
-"#ifdef USESHADOWSAMPLER\n"
-"# extension GL_ARB_shadow : enable\n"
-"#endif\n"
-"\n"
-"// common definitions between vertex shader and fragment shader:\n"
+"//#ifdef USESHADOWSAMPLER\n"
+"//# extension GL_ARB_shadow : enable\n"
+"//#endif\n"
 "\n"
 "//#ifdef __GLSL_CG_DATA_TYPES\n"
 "//# define myhalf half\n"
 "//# define myhalf2 half2\n"
-"//# define myhalf3half3\n"
+"//# define myhalf3 half3\n"
 "//# define myhalf4 half4\n"
 "//#else\n"
 "# define myhalf float\n"
@@ -493,55 +536,58 @@ static const char *builtinshaderstring =
 "# define myhalf4 vec4\n"
 "//#endif\n"
 "\n"
-"#ifdef USEFOGINSIDE\n"
-"# define USEFOG\n"
-"#else\n"
-"# ifdef USEFOGOUTSIDE\n"
-"#  define USEFOG\n"
-"# endif\n"
+"#ifdef VERTEX_SHADER\n"
+"uniform mat4 ModelViewProjectionMatrix;\n"
 "#endif\n"
 "\n"
 "#ifdef MODE_DEPTH_OR_SHADOW\n"
-"\n"
-"# ifdef VERTEX_SHADER\n"
+"#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
-"      gl_Position = ftransform();\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
 "}\n"
-"# endif\n"
+"#endif\n"
+"#else // !MODE_DEPTH_ORSHADOW\n"
+"\n"
+"\n"
+"\n"
 "\n"
-"#else\n"
 "#ifdef MODE_SHOWDEPTH\n"
-"# ifdef VERTEX_SHADER\n"
+"#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
-"      gl_Position = ftransform();\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
 "      gl_FrontColor = vec4(gl_Position.z, gl_Position.z, gl_Position.z, 1.0);\n"
 "}\n"
-"# endif\n"
-"# ifdef FRAGMENT_SHADER\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
 "void main(void)\n"
 "{\n"
 "      gl_FragColor = gl_Color;\n"
 "}\n"
-"# endif\n"
-"\n"
+"#endif\n"
 "#else // !MODE_SHOWDEPTH\n"
 "\n"
+"\n"
+"\n"
+"\n"
 "#ifdef MODE_POSTPROCESS\n"
-"# ifdef VERTEX_SHADER\n"
+"varying vec2 TexCoord1;\n"
+"varying vec2 TexCoord2;\n"
+"\n"
+"#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
-"      gl_FrontColor = gl_Color;\n"
-"      gl_Position = ftransform();\n"
-"      gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
+"      TexCoord1 = gl_MultiTexCoord0.xy;\n"
 "#ifdef USEBLOOM\n"
-"      gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;\n"
+"      TexCoord2 = gl_MultiTexCoord1.xy;\n"
 "#endif\n"
 "}\n"
-"# endif\n"
-"# ifdef FRAGMENT_SHADER\n"
+"#endif\n"
 "\n"
+"#ifdef FRAGMENT_SHADER\n"
 "uniform sampler2D Texture_First;\n"
 "#ifdef USEBLOOM\n"
 "uniform sampler2D Texture_Second;\n"
@@ -553,7 +599,7 @@ static const char *builtinshaderstring =
 "uniform float Saturation;\n"
 "#endif\n"
 "#ifdef USEVIEWTINT\n"
-"uniform vec4 TintColor;\n"
+"uniform vec4 ViewTintColor;\n"
 "#endif\n"
 "//uncomment these if you want to use them:\n"
 "uniform vec4 UserVec1;\n"
@@ -564,28 +610,28 @@ static const char *builtinshaderstring =
 "uniform vec2 PixelSize;\n"
 "void main(void)\n"
 "{\n"
-"      gl_FragColor = texture2D(Texture_First, gl_TexCoord[0].xy);\n"
+"      gl_FragColor = texture2D(Texture_First, TexCoord1);\n"
 "#ifdef USEBLOOM\n"
-"      gl_FragColor += texture2D(Texture_Second, gl_TexCoord[1].xy);\n"
+"      gl_FragColor += texture2D(Texture_Second, TexCoord2);\n"
 "#endif\n"
 "#ifdef USEVIEWTINT\n"
-"      gl_FragColor = mix(gl_FragColor, TintColor, TintColor.a);\n"
+"      gl_FragColor = mix(gl_FragColor, ViewTintColor, ViewTintColor.a);\n"
 "#endif\n"
 "\n"
 "#ifdef USEPOSTPROCESSING\n"
 "// do r_glsl_dumpshader, edit glsl/default.glsl, and replace this by your own postprocessing if you want\n"
 "// this code does a blur with the radius specified in the first component of r_glsl_postprocess_uservec1 and blends it using the second component\n"
-"      gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.987688, -0.156434)) * UserVec1.y;\n"
-"      gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.156434, -0.891007)) * UserVec1.y;\n"
-"      gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2( 0.891007, -0.453990)) * UserVec1.y;\n"
-"      gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2( 0.707107,  0.707107)) * UserVec1.y;\n"
-"      gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.453990,  0.891007)) * UserVec1.y;\n"
+"      gl_FragColor += texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2(-0.987688, -0.156434)) * UserVec1.y;\n"
+"      gl_FragColor += texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2(-0.156434, -0.891007)) * UserVec1.y;\n"
+"      gl_FragColor += texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2( 0.891007, -0.453990)) * UserVec1.y;\n"
+"      gl_FragColor += texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2( 0.707107,  0.707107)) * UserVec1.y;\n"
+"      gl_FragColor += texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2(-0.453990,  0.891007)) * UserVec1.y;\n"
 "      gl_FragColor /= (1 + 5 * UserVec1.y);\n"
 "#endif\n"
 "\n"
 "#ifdef USESATURATION\n"
 "      //apply saturation BEFORE gamma ramps, so v_glslgamma value does not matter\n"
-"      myhalf y = dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114));\n"
+"      float y = dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114));\n"
 "      //gl_FragColor = vec3(y) + (gl_FragColor.rgb - vec3(y)) * Saturation;\n"
 "      gl_FragColor.rgb = mix(vec3(y), gl_FragColor.rgb, Saturation);\n"
 "#endif\n"
@@ -596,74 +642,86 @@ static const char *builtinshaderstring =
 "      gl_FragColor.b = texture2D(Texture_GammaRamps, vec2(gl_FragColor.b, 0)).b;\n"
 "#endif\n"
 "}\n"
-"# endif\n"
+"#endif\n"
+"#else // !MODE_POSTPROCESS\n"
+"\n"
+"\n"
 "\n"
 "\n"
-"#else\n"
 "#ifdef MODE_GENERIC\n"
-"# ifdef VERTEX_SHADER\n"
+"#ifdef USEDIFFUSE\n"
+"varying vec2 TexCoord1;\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
+"varying vec2 TexCoord2;\n"
+"#endif\n"
+"#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
 "      gl_FrontColor = gl_Color;\n"
-"#  ifdef USEDIFFUSE\n"
-"      gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
-"#  endif\n"
-"#  ifdef USESPECULAR\n"
-"      gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;\n"
-"#  endif\n"
-"      gl_Position = ftransform();\n"
+"#ifdef USEDIFFUSE\n"
+"      TexCoord1 = gl_MultiTexCoord0.xy;\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
+"      TexCoord2 = gl_MultiTexCoord1.xy;\n"
+"#endif\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
 "}\n"
-"# endif\n"
-"# ifdef FRAGMENT_SHADER\n"
+"#endif\n"
 "\n"
-"#  ifdef USEDIFFUSE\n"
+"#ifdef FRAGMENT_SHADER\n"
+"#ifdef USEDIFFUSE\n"
 "uniform sampler2D Texture_First;\n"
-"#  endif\n"
-"#  ifdef USESPECULAR\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
 "uniform sampler2D Texture_Second;\n"
-"#  endif\n"
+"#endif\n"
 "\n"
 "void main(void)\n"
 "{\n"
 "      gl_FragColor = gl_Color;\n"
-"#  ifdef USEDIFFUSE\n"
-"      gl_FragColor *= texture2D(Texture_First, gl_TexCoord[0].xy);\n"
-"#  endif\n"
+"#ifdef USEDIFFUSE\n"
+"      gl_FragColor *= texture2D(Texture_First, TexCoord1);\n"
+"#endif\n"
 "\n"
-"#  ifdef USESPECULAR\n"
-"      vec4 tex2 = texture2D(Texture_Second, gl_TexCoord[1].xy);\n"
-"#  endif\n"
-"#  ifdef USECOLORMAPPING\n"
+"#ifdef USESPECULAR\n"
+"      vec4 tex2 = texture2D(Texture_Second, TexCoord2);\n"
+"# ifdef USECOLORMAPPING\n"
 "      gl_FragColor *= tex2;\n"
-"#  endif\n"
-"#  ifdef USEGLOW\n"
+"# endif\n"
+"# ifdef USEGLOW\n"
 "      gl_FragColor += tex2;\n"
-"#  endif\n"
-"#  ifdef USEVERTEXTEXTUREBLEND\n"
+"# endif\n"
+"# ifdef USEVERTEXTEXTUREBLEND\n"
 "      gl_FragColor = mix(gl_FragColor, tex2, tex2.a);\n"
-"#  endif\n"
-"}\n"
 "# endif\n"
-"\n"
+"#endif\n"
+"}\n"
+"#endif\n"
 "#else // !MODE_GENERIC\n"
+"\n"
+"\n"
+"\n"
+"\n"
 "#ifdef MODE_BLOOMBLUR\n"
-"# ifdef VERTEX_SHADER\n"
+"varying TexCoord;\n"
+"#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
 "      gl_FrontColor = gl_Color;\n"
-"      gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
-"      gl_Position = ftransform();\n"
+"      TexCoord = gl_MultiTexCoord0.xy;\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
 "}\n"
-"# endif\n"
-"# ifdef FRAGMENT_SHADER\n"
+"#endif\n"
 "\n"
+"#ifdef FRAGMENT_SHADER\n"
 "uniform sampler2D Texture_First;\n"
 "uniform vec4 BloomBlur_Parameters;\n"
 "\n"
 "void main(void)\n"
 "{\n"
 "      int i;\n"
-"      vec2 tc = gl_TexCoord[0].xy;\n"
+"      vec2 tc = TexCoord;\n"
 "      vec3 color = texture2D(Texture_First, tc).rgb;\n"
 "      tc += BloomBlur_Parameters.xy;\n"
 "      for (i = 1;i < SAMPLES;i++)\n"
@@ -673,245 +731,248 @@ static const char *builtinshaderstring =
 "      }\n"
 "      gl_FragColor = vec4(color * BloomBlur_Parameters.z + vec3(BloomBlur_Parameters.w), 1);\n"
 "}\n"
-"# endif\n"
-"\n"
+"#endif\n"
 "#else // !MODE_BLOOMBLUR\n"
+"#ifdef MODE_REFRACTION\n"
+"varying vec2 TexCoord;\n"
+"varying vec4 ModelViewProjectionPosition;\n"
+"uniform mat4 TexMatrix;\n"
+"#ifdef VERTEX_SHADER\n"
+"\n"
+"void main(void)\n"
+"{\n"
+"      TexCoord = vec2(TexMatrix * gl_MultiTexCoord0);\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
+"      ModelViewProjectionPosition = gl_Position;\n"
+"}\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"uniform sampler2D Texture_Normal;\n"
+"uniform sampler2D Texture_Refraction;\n"
+"uniform sampler2D Texture_Reflection;\n"
+"\n"
+"uniform vec4 DistortScaleRefractReflect;\n"
+"uniform vec4 ScreenScaleRefractReflect;\n"
+"uniform vec4 ScreenCenterRefractReflect;\n"
+"uniform vec4 RefractColor;\n"
+"uniform vec4 ReflectColor;\n"
+"uniform float ReflectFactor;\n"
+"uniform float ReflectOffset;\n"
+"\n"
+"void main(void)\n"
+"{\n"
+"      vec2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n"
+"      //vec2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
+"      vec2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
+"      vec2 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5))).xy * DistortScaleRefractReflect.xy;\n"
+"      // FIXME temporary hack to detect the case that the reflection\n"
+"      // gets blackened at edges due to leaving the area that contains actual\n"
+"      // content.\n"
+"      // Remove this 'ack once we have a better way to stop this thing from\n"
+"      // 'appening.\n"
+"      float f = min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, -0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
+"      ScreenTexCoord = mix(SafeScreenTexCoord, ScreenTexCoord, f);\n"
+"      gl_FragColor = texture2D(Texture_Refraction, ScreenTexCoord) * RefractColor;\n"
+"}\n"
+"#endif\n"
+"#else // !MODE_REFRACTION\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef MODE_WATER\n"
+"varying vec2 TexCoord;\n"
+"varying vec3 EyeVector;\n"
+"varying vec4 ModelViewProjectionPosition;\n"
+"#ifdef VERTEX_SHADER\n"
+"uniform vec3 EyePosition;\n"
+"uniform mat4 TexMatrix;\n"
+"\n"
+"void main(void)\n"
+"{\n"
+"      TexCoord = vec2(TexMatrix * gl_MultiTexCoord0);\n"
+"      vec3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
+"      EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
+"      EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
+"      EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
+"      ModelViewProjectionPosition = gl_Position;\n"
+"}\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"uniform sampler2D Texture_Normal;\n"
+"uniform sampler2D Texture_Refraction;\n"
+"uniform sampler2D Texture_Reflection;\n"
+"\n"
+"uniform vec4 DistortScaleRefractReflect;\n"
+"uniform vec4 ScreenScaleRefractReflect;\n"
+"uniform vec4 ScreenCenterRefractReflect;\n"
+"uniform vec4 RefractColor;\n"
+"uniform vec4 ReflectColor;\n"
+"uniform float ReflectFactor;\n"
+"uniform float ReflectOffset;\n"
+"\n"
+"void main(void)\n"
+"{\n"
+"      vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
+"      //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
+"      vec4 SafeScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
+"      //SafeScreenTexCoord = gl_FragCoord.xyxy * vec4(1.0 / 1920.0, 1.0 / 1200.0, 1.0 / 1920.0, 1.0 / 1200.0);\n"
+"      vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5))).xyxy * DistortScaleRefractReflect;\n"
+"      // FIXME temporary hack to detect the case that the reflection\n"
+"      // gets blackened at edges due to leaving the area that contains actual\n"
+"      // content.\n"
+"      // Remove this 'ack once we have a better way to stop this thing from\n"
+"      // 'appening.\n"
+"      float f = min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.01, -0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
+"      ScreenTexCoord.xy = mix(SafeScreenTexCoord.xy, ScreenTexCoord.xy, f);\n"
+"      f       = min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.01, -0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
+"      ScreenTexCoord.zw = mix(SafeScreenTexCoord.zw, ScreenTexCoord.zw, f);\n"
+"      float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * ReflectFactor + ReflectOffset;\n"
+"      gl_FragColor = mix(texture2D(Texture_Refraction, ScreenTexCoord.xy) * RefractColor, texture2D(Texture_Reflection, ScreenTexCoord.zw) * ReflectColor, Fresnel);\n"
+"}\n"
+"#endif\n"
+"#else // !MODE_WATER\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"// common definitions between vertex shader and fragment shader:\n"
 "\n"
 "varying vec2 TexCoord;\n"
 "#ifdef USEVERTEXTEXTUREBLEND\n"
 "varying vec2 TexCoord2;\n"
 "#endif\n"
+"#ifdef USELIGHTMAP\n"
 "varying vec2 TexCoordLightmap;\n"
+"#endif\n"
 "\n"
 "#ifdef MODE_LIGHTSOURCE\n"
 "varying vec3 CubeVector;\n"
 "#endif\n"
 "\n"
-"#ifdef MODE_LIGHTSOURCE\n"
-"varying vec3 LightVector;\n"
-"#endif\n"
-"#ifdef MODE_LIGHTDIRECTION\n"
+"#if (defined(MODE_LIGHTSOURCE) || defined(MODE_LIGHTDIRECTION)) && defined(USEDIFFUSE)\n"
 "varying vec3 LightVector;\n"
 "#endif\n"
 "\n"
+"#ifdef USEEYEVECTOR\n"
 "varying vec3 EyeVector;\n"
+"#endif\n"
 "#ifdef USEFOG\n"
-"varying vec3 EyeVectorModelSpace;\n"
-"varying float FogPlaneVertexDist;\n"
+"varying vec4 EyeVectorModelSpaceFogPlaneVertexDist;\n"
 "#endif\n"
 "\n"
+"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_DEFERREDGEOMETRY) || defined(USEREFLECTCUBE)\n"
 "varying vec3 VectorS; // direction of S texcoord (sometimes crudely called tangent)\n"
 "varying vec3 VectorT; // direction of T texcoord (sometimes crudely called binormal)\n"
 "varying vec3 VectorR; // direction of R texcoord (surface normal)\n"
-"\n"
-"#ifdef MODE_WATER\n"
-"varying vec4 ModelViewProjectionPosition;\n"
-"#endif\n"
-"#ifdef MODE_REFRACTION\n"
-"varying vec4 ModelViewProjectionPosition;\n"
 "#endif\n"
+"\n"
 "#ifdef USEREFLECTION\n"
 "varying vec4 ModelViewProjectionPosition;\n"
 "#endif\n"
+"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
+"uniform vec3 LightPosition;\n"
+"varying vec4 ModelViewPosition;\n"
+"#endif\n"
 "\n"
-"\n"
-"\n"
-"\n"
-"\n"
-"// vertex shader specific:\n"
-"#ifdef VERTEX_SHADER\n"
-"\n"
+"#ifdef MODE_LIGHTSOURCE\n"
 "uniform vec3 LightPosition;\n"
+"#endif\n"
 "uniform vec3 EyePosition;\n"
+"#ifdef MODE_LIGHTDIRECTION\n"
 "uniform vec3 LightDir;\n"
+"#endif\n"
 "uniform vec4 FogPlane;\n"
 "\n"
-"// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3), this would require sending a 4 component texcoord1 with W as 1 or -1 according to which side the texcoord2 should be on\n"
-"\n"
-"void main(void)\n"
-"{\n"
-"      gl_FrontColor = gl_Color;\n"
-"      // copy the surface texcoord\n"
-"      TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
-"#ifdef USEVERTEXTEXTUREBLEND\n"
-"      TexCoord2 = vec2(gl_TextureMatrix[1] * gl_MultiTexCoord0);\n"
-"#endif\n"
-"#ifndef MODE_LIGHTSOURCE\n"
-"# ifndef MODE_LIGHTDIRECTION\n"
-"      TexCoordLightmap = vec2(gl_MultiTexCoord4);\n"
-"# endif\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"varying vec3 ShadowMapTC;\n"
 "#endif\n"
 "\n"
-"#ifdef MODE_LIGHTSOURCE\n"
-"      // transform vertex position into light attenuation/cubemap space\n"
-"      // (-1 to +1 across the light box)\n"
-"      CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
 "\n"
-"      // transform unnormalized light direction into tangent space\n"
-"      // (we use unnormalized to ensure that it interpolates correctly and then\n"
-"      //  normalize it per pixel)\n"
-"      vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
-"      LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
-"      LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
-"      LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
-"#endif\n"
-"\n"
-"#ifdef MODE_LIGHTDIRECTION\n"
-"      LightVector.x = dot(LightDir, gl_MultiTexCoord1.xyz);\n"
-"      LightVector.y = dot(LightDir, gl_MultiTexCoord2.xyz);\n"
-"      LightVector.z = dot(LightDir, gl_MultiTexCoord3.xyz);\n"
-"#endif\n"
-"\n"
-"      // transform unnormalized eye direction into tangent space\n"
-"#ifndef USEFOG\n"
-"      vec3 EyeVectorModelSpace;\n"
-"#endif\n"
-"      EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
-"      EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
-"      EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
-"      EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
-"\n"
-"#ifdef USEFOG\n"
-"      FogPlaneVertexDist = dot(FogPlane, gl_Vertex);\n"
-"#endif\n"
-"\n"
-"#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
-"      VectorS = gl_MultiTexCoord1.xyz;\n"
-"      VectorT = gl_MultiTexCoord2.xyz;\n"
-"      VectorR = gl_MultiTexCoord3.xyz;\n"
-"#endif\n"
-"\n"
-"//#if defined(MODE_WATER) || defined(MODE_REFRACTION) || defined(USEREFLECTION)\n"
-"//    ModelViewProjectionPosition = gl_Vertex * gl_ModelViewProjectionMatrix;\n"
-"//    //ModelViewProjectionPosition_svector = (gl_Vertex + vec4(gl_MultiTexCoord1.xyz, 0)) * gl_ModelViewProjectionMatrix - ModelViewProjectionPosition;\n"
-"//    //ModelViewProjectionPosition_tvector = (gl_Vertex + vec4(gl_MultiTexCoord2.xyz, 0)) * gl_ModelViewProjectionMatrix - ModelViewProjectionPosition;\n"
-"//#endif\n"
-"\n"
-"// transform vertex to camera space, using ftransform to match non-VS\n"
-"      // rendering\n"
-"      gl_Position = ftransform();\n"
-"\n"
-"#ifdef MODE_WATER\n"
-"      ModelViewProjectionPosition = gl_Position;\n"
-"#endif\n"
-"#ifdef MODE_REFRACTION\n"
-"      ModelViewProjectionPosition = gl_Position;\n"
-"#endif\n"
-"#ifdef USEREFLECTION\n"
-"      ModelViewProjectionPosition = gl_Position;\n"
-"#endif\n"
-"}\n"
-"\n"
-"#endif // VERTEX_SHADER\n"
 "\n"
 "\n"
 "\n"
+"// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3), this would require sending a 4 component texcoord1 with W as 1 or -1 according to which side the texcoord2 should be on\n"
 "\n"
 "// fragment shader specific:\n"
 "#ifdef FRAGMENT_SHADER\n"
 "\n"
-"// 13 textures, we can only use up to 16 on DX9-class hardware\n"
 "uniform sampler2D Texture_Normal;\n"
 "uniform sampler2D Texture_Color;\n"
 "uniform sampler2D Texture_Gloss;\n"
+"#ifdef USEGLOW\n"
 "uniform sampler2D Texture_Glow;\n"
+"#endif\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
 "uniform sampler2D Texture_SecondaryNormal;\n"
 "uniform sampler2D Texture_SecondaryColor;\n"
 "uniform sampler2D Texture_SecondaryGloss;\n"
+"#ifdef USEGLOW\n"
 "uniform sampler2D Texture_SecondaryGlow;\n"
+"#endif\n"
+"#endif\n"
+"#ifdef USECOLORMAPPING\n"
 "uniform sampler2D Texture_Pants;\n"
 "uniform sampler2D Texture_Shirt;\n"
+"#endif\n"
+"#ifdef USEFOG\n"
 "uniform sampler2D Texture_FogMask;\n"
+"#endif\n"
+"#ifdef USELIGHTMAP\n"
 "uniform sampler2D Texture_Lightmap;\n"
+"#endif\n"
+"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
 "uniform sampler2D Texture_Deluxemap;\n"
-"uniform sampler2D Texture_Refraction;\n"
-"uniform sampler2D Texture_Reflection;\n"
-"uniform sampler2D Texture_Attenuation;\n"
-"uniform samplerCube Texture_Cube;\n"
-"\n"
-"#define showshadowmap 0\n"
-"\n"
-"#ifdef USESHADOWMAPRECT\n"
-"# ifdef USESHADOWSAMPLER\n"
-"uniform sampler2DRectShadow Texture_ShadowMapRect;\n"
-"# else\n"
-"uniform sampler2DRect Texture_ShadowMapRect;\n"
-"# endif\n"
 "#endif\n"
-"\n"
-"#ifdef USESHADOWMAP2D\n"
-"# ifdef USESHADOWSAMPLER\n"
-"uniform sampler2DShadow Texture_ShadowMap2D;\n"
-"# else\n"
-"uniform sampler2D Texture_ShadowMap2D;\n"
-"# endif\n"
+"#ifdef USEREFLECTION\n"
+"uniform sampler2D Texture_Reflection;\n"
 "#endif\n"
 "\n"
-"#ifdef USESHADOWMAPVSDCT\n"
-"uniform samplerCube Texture_CubeProjection;\n"
+"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
+"uniform sampler2D Texture_ScreenDepth;\n"
+"uniform sampler2D Texture_ScreenNormalMap;\n"
 "#endif\n"
-"\n"
-"#ifdef USESHADOWMAPCUBE\n"
-"# ifdef USESHADOWSAMPLER\n"
-"uniform samplerCubeShadow Texture_ShadowMapCube;\n"
-"# else\n"
-"uniform samplerCube Texture_ShadowMapCube;\n"
-"# endif\n"
+"#ifdef USEDEFERREDLIGHTMAP\n"
+"uniform sampler2D Texture_ScreenDiffuse;\n"
+"uniform sampler2D Texture_ScreenSpecular;\n"
 "#endif\n"
 "\n"
-"uniform myhalf3 LightColor;\n"
-"uniform myhalf3 AmbientColor;\n"
-"uniform myhalf3 DiffuseColor;\n"
-"uniform myhalf3 SpecularColor;\n"
 "uniform myhalf3 Color_Pants;\n"
 "uniform myhalf3 Color_Shirt;\n"
 "uniform myhalf3 FogColor;\n"
 "\n"
-"uniform myhalf4 TintColor;\n"
-"\n"
-"\n"
-"//#ifdef MODE_WATER\n"
-"uniform vec4 DistortScaleRefractReflect;\n"
-"uniform vec4 ScreenScaleRefractReflect;\n"
-"uniform vec4 ScreenCenterRefractReflect;\n"
-"uniform myhalf4 RefractColor;\n"
-"uniform myhalf4 ReflectColor;\n"
-"uniform myhalf ReflectFactor;\n"
-"uniform myhalf ReflectOffset;\n"
-"//#else\n"
-"//# ifdef MODE_REFRACTION\n"
-"//uniform vec4 DistortScaleRefractReflect;\n"
-"//uniform vec4 ScreenScaleRefractReflect;\n"
-"//uniform vec4 ScreenCenterRefractReflect;\n"
-"//uniform myhalf4 RefractColor;\n"
-"//#  ifdef USEREFLECTION\n"
-"//uniform myhalf4 ReflectColor;\n"
-"//#  endif\n"
-"//# else\n"
-"//#  ifdef USEREFLECTION\n"
-"//uniform vec4 DistortScaleRefractReflect;\n"
-"//uniform vec4 ScreenScaleRefractReflect;\n"
-"//uniform vec4 ScreenCenterRefractReflect;\n"
-"//uniform myhalf4 ReflectColor;\n"
-"//#  endif\n"
-"//# endif\n"
-"//#endif\n"
-"\n"
-"uniform myhalf3 GlowColor;\n"
-"uniform myhalf SceneBrightness;\n"
-"\n"
-"uniform float OffsetMapping_Scale;\n"
-"uniform float OffsetMapping_Bias;\n"
+"#ifdef USEFOG\n"
 "uniform float FogRangeRecip;\n"
 "uniform float FogPlaneViewDist;\n"
 "uniform float FogHeightFade;\n"
-"\n"
-"uniform myhalf AmbientScale;\n"
-"uniform myhalf DiffuseScale;\n"
-"uniform myhalf SpecularScale;\n"
-"uniform myhalf SpecularPower;\n"
+"float FogVertex(void)\n"
+"{\n"
+"      vec3 EyeVectorModelSpace = EyeVectorModelSpaceFogPlaneVertexDist.xyz;\n"
+"      float FogPlaneVertexDist = EyeVectorModelSpaceFogPlaneVertexDist.w;\n"
+"      float fogfrac;\n"
+"#ifdef USEFOGOUTSIDE\n"
+"      fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0, min(0.0, FogPlaneVertexDist) * FogHeightFade);\n"
+"#else\n"
+"      fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist)) * min(1.0, (min(0.0, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);\n"
+"#endif\n"
+"      return float(texture2D(Texture_FogMask, myhalf2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)));\n"
+"}\n"
+"#endif\n"
 "\n"
 "#ifdef USEOFFSETMAPPING\n"
+"uniform float OffsetMapping_Scale;\n"
 "vec2 OffsetMapping(vec2 TexCoord)\n"
 "{\n"
 "#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n"
@@ -956,80 +1017,81 @@ static const char *builtinshaderstring =
 "}\n"
 "#endif // USEOFFSETMAPPING\n"
 "\n"
+"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE)\n"
+"uniform sampler2D Texture_Attenuation;\n"
+"uniform samplerCube Texture_Cube;\n"
+"#endif\n"
+"\n"
+"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE) || defined(USESHADOWMAPORTHO)\n"
+"\n"
+"#ifdef USESHADOWMAPRECT\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform sampler2DRectShadow Texture_ShadowMapRect;\n"
+"# else\n"
+"uniform sampler2DRect Texture_ShadowMapRect;\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAP2D\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform sampler2DShadow Texture_ShadowMap2D;\n"
+"# else\n"
+"uniform sampler2D Texture_ShadowMap2D;\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAPVSDCT\n"
+"uniform samplerCube Texture_CubeProjection;\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform samplerCubeShadow Texture_ShadowMapCube;\n"
+"# else\n"
+"uniform samplerCube Texture_ShadowMapCube;\n"
+"# endif\n"
+"#endif\n"
+"\n"
 "#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D) || defined(USESHADOWMAPCUBE)\n"
 "uniform vec2 ShadowMap_TextureScale;\n"
 "uniform vec4 ShadowMap_Parameters;\n"
 "#endif\n"
 "\n"
 "#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
+"# ifdef USESHADOWMAPORTHO\n"
+"#  define GetShadowMapTC2D(dir) (min(dir, ShadowMap_Parameters.xyz))\n"
+"# else\n"
+"#  ifdef USESHADOWMAPVSDCT\n"
 "vec3 GetShadowMapTC2D(vec3 dir)\n"
 "{\n"
 "      vec3 adir = abs(dir);\n"
-"# ifndef USESHADOWMAPVSDCT\n"
-"      vec2 tc;\n"
-"      vec2 offset;\n"
-"      float ma;\n"
-"      if (adir.x > adir.y)\n"
-"      {\n"
-"              if (adir.x > adir.z) // X\n"
-"              {\n"
-"                      ma = adir.x;\n"
-"                      tc = dir.zy;\n"
-"                      offset = vec2(mix(0.5, 1.5, dir.x < 0.0), 0.5);\n"
-"              }\n"
-"              else // Z\n"
-"              {\n"
-"                      ma = adir.z;\n"
-"                      tc = dir.xy;\n"
-"                      offset = vec2(mix(0.5, 1.5, dir.z < 0.0), 2.5);\n"
-"              }\n"
-"      }\n"
-"      else\n"
-"      {\n"
-"              if (adir.y > adir.z) // Y\n"
-"              {\n"
-"                      ma = adir.y;\n"
-"                      tc = dir.xz;\n"
-"                      offset = vec2(mix(0.5, 1.5, dir.y < 0.0), 1.5);\n"
-"              }\n"
-"              else // Z\n"
-"              {\n"
-"                      ma = adir.z;\n"
-"                      tc = dir.xy;\n"
-"                      offset = vec2(mix(0.5, 1.5, dir.z < 0.0), 2.5);\n"
-"              }\n"
-"      }\n"
-"\n"
-"      vec3 stc = vec3(tc * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
-"      stc.xy += offset * ShadowMap_Parameters.y;\n"
-"      stc.z += ShadowMap_Parameters.z;\n"
-"#  if showshadowmap\n"
-"      stc.xy *= ShadowMap_TextureScale;\n"
-"#  endif\n"
-"      return stc;\n"
-"# else\n"
+"      vec2 aparams = ShadowMap_Parameters.xy / max(max(adir.x, adir.y), adir.z);\n"
 "      vec4 proj = textureCube(Texture_CubeProjection, dir);\n"
-"      float ma = max(max(adir.x, adir.y), adir.z);\n"
-"      vec3 stc = vec3(mix(dir.xy, dir.zz, proj.xy) * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
-"      stc.xy += proj.zw * ShadowMap_Parameters.y;\n"
-"      stc.z += ShadowMap_Parameters.z;\n"
-"#  if showshadowmap\n"
-"      stc.xy *= ShadowMap_TextureScale;\n"
+"      return vec3(mix(dir.xy, dir.zz, proj.xy) * aparams.x + proj.zw * ShadowMap_Parameters.z, aparams.y + ShadowMap_Parameters.w);\n"
+"}\n"
+"#  else\n"
+"vec3 GetShadowMapTC2D(vec3 dir)\n"
+"{\n"
+"      vec3 adir = abs(dir);\n"
+"      float ma = adir.z;\n"
+"      vec4 proj = vec4(dir, 2.5);\n"
+"      if (adir.x > ma) { ma = adir.x; proj = vec4(dir.zyx, 0.5); }\n"
+"      if (adir.y > ma) { ma = adir.y; proj = vec4(dir.xzy, 1.5); }\n"
+"      vec2 aparams = ShadowMap_Parameters.xy / ma;\n"
+"      return vec3(proj.xy * aparams.x + vec2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.z, aparams.y + ShadowMap_Parameters.w);\n"
+"}\n"
 "#  endif\n"
-"      return stc;\n"
 "# endif\n"
-"}\n"
 "#endif // defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
 "\n"
 "#ifdef USESHADOWMAPCUBE\n"
 "vec4 GetShadowMapTCCube(vec3 dir)\n"
 "{\n"
-"    vec3 adir = abs(dir);\n"
-"    return vec4(dir, ShadowMap_Parameters.z + ShadowMap_Parameters.w / max(max(adir.x, adir.y), adir.z));\n"
+"      vec3 adir = abs(dir);\n"
+"      return vec4(dir, ShadowMap_Parameters.z + ShadowMap_Parameters.w / max(max(adir.x, adir.y), adir.z));\n"
 "}\n"
 "#endif\n"
 "\n"
-"#if !showshadowmap\n"
 "# ifdef USESHADOWMAPRECT\n"
 "float ShadowMapCompare(vec3 dir)\n"
 "{\n"
@@ -1039,9 +1101,9 @@ static const char *builtinshaderstring =
 "\n"
 "#    ifdef USESHADOWMAPPCF\n"
 "#      define texval(x, y) shadow2DRect(Texture_ShadowMapRect, shadowmaptc + vec3(x, y, 0.0)).r\n"
-"    f = dot(vec4(0.25), vec4(texval(-0.4, 1.0), texval(-1.0, -0.4), texval(0.4, -1.0), texval(1.0, 0.4)));\n"
+"      f = dot(vec4(0.25), vec4(texval(-0.4, 1.0), texval(-1.0, -0.4), texval(0.4, -1.0), texval(1.0, 0.4)));\n"
 "#    else\n"
-"    f = shadow2DRect(Texture_ShadowMapRect, shadowmaptc).r;\n"
+"      f = shadow2DRect(Texture_ShadowMapRect, shadowmaptc).r;\n"
 "#    endif\n"
 "\n"
 "#  else\n"
@@ -1049,62 +1111,66 @@ static const char *builtinshaderstring =
 "#    ifdef USESHADOWMAPPCF\n"
 "#      if USESHADOWMAPPCF > 1\n"
 "#        define texval(x, y) texture2DRect(Texture_ShadowMapRect, center + vec2(x, y)).r\n"
-"    vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n"
-"    vec4 row1 = step(shadowmaptc.z, vec4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n"
-"    vec4 row2 = step(shadowmaptc.z, vec4(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0), texval( 2.0,  0.0)));\n"
-"    vec4 row3 = step(shadowmaptc.z, vec4(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0), texval( 2.0,  1.0)));\n"
-"    vec4 row4 = step(shadowmaptc.z, vec4(texval(-1.0,  2.0), texval( 0.0,  2.0), texval( 1.0,  2.0), texval( 2.0,  2.0)));\n"
-"    vec4 cols = row2 + row3 + mix(row1, row4, offset.y);\n"
-"    f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
+"      vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n"
+"      vec4 row1 = step(shadowmaptc.z, vec4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n"
+"      vec4 row2 = step(shadowmaptc.z, vec4(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0), texval( 2.0,  0.0)));\n"
+"      vec4 row3 = step(shadowmaptc.z, vec4(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0), texval( 2.0,  1.0)));\n"
+"      vec4 row4 = step(shadowmaptc.z, vec4(texval(-1.0,  2.0), texval( 0.0,  2.0), texval( 1.0,  2.0), texval( 2.0,  2.0)));\n"
+"      vec4 cols = row2 + row3 + mix(row1, row4, offset.y);\n"
+"      f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
 "#      else\n"
 "#        define texval(x, y) texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2(x, y)).r\n"
-"    vec2 offset = fract(shadowmaptc.xy);\n"
-"    vec3 row1 = step(shadowmaptc.z, vec3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n"
-"    vec3 row2 = step(shadowmaptc.z, vec3(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0)));\n"
-"    vec3 row3 = step(shadowmaptc.z, vec3(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0)));\n"
-"    vec3 cols = row2 + mix(row1, row3, offset.y);\n"
-"    f = dot(mix(cols.xy, cols.yz, offset.x), vec2(0.25));\n"
+"      vec2 offset = fract(shadowmaptc.xy);\n"
+"      vec3 row1 = step(shadowmaptc.z, vec3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n"
+"      vec3 row2 = step(shadowmaptc.z, vec3(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0)));\n"
+"      vec3 row3 = step(shadowmaptc.z, vec3(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0)));\n"
+"      vec3 cols = row2 + mix(row1, row3, offset.y);\n"
+"      f = dot(mix(cols.xy, cols.yz, offset.x), vec2(0.25));\n"
 "#      endif\n"
 "#    else\n"
-"    f = step(shadowmaptc.z, texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy).r);\n"
+"      f = step(shadowmaptc.z, texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy).r);\n"
 "#    endif\n"
 "\n"
 "#  endif\n"
+"#  ifdef USESHADOWMAPORTHO\n"
+"      return mix(ShadowMap_Parameters.w, 1.0, f);\n"
+"#  else\n"
 "      return f;\n"
+"#  endif\n"
 "}\n"
 "# endif\n"
 "\n"
 "# ifdef USESHADOWMAP2D\n"
 "float ShadowMapCompare(vec3 dir)\n"
 "{\n"
-"    vec3 shadowmaptc = GetShadowMapTC2D(dir);\n"
-"    float f;\n"
+"      vec3 shadowmaptc = GetShadowMapTC2D(dir);\n"
+"      float f;\n"
 "\n"
 "#  ifdef USESHADOWSAMPLER\n"
 "#    ifdef USESHADOWMAPPCF\n"
 "#      define texval(x, y) shadow2D(Texture_ShadowMap2D, vec3(center + vec2(x, y)*ShadowMap_TextureScale, shadowmaptc.z)).r  \n"
-"    vec2 center = shadowmaptc.xy*ShadowMap_TextureScale;\n"
-"    f = dot(vec4(0.25), vec4(texval(-0.4, 1.0), texval(-1.0, -0.4), texval(0.4, -1.0), texval(1.0, 0.4)));\n"
+"      vec2 center = shadowmaptc.xy*ShadowMap_TextureScale;\n"
+"      f = dot(vec4(0.25), vec4(texval(-0.4, 1.0), texval(-1.0, -0.4), texval(0.4, -1.0), texval(1.0, 0.4)));\n"
 "#    else\n"
-"    f = shadow2D(Texture_ShadowMap2D, vec3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z)).r;\n"
+"      f = shadow2D(Texture_ShadowMap2D, vec3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z)).r;\n"
 "#    endif\n"
 "#  else\n"
 "#    ifdef USESHADOWMAPPCF\n"
 "#     if defined(GL_ARB_texture_gather) || defined(GL_AMD_texture_texture4)\n"
 "#      ifdef GL_ARB_texture_gather\n"
-"#        define texval(x, y) textureGatherOffset(Texture_ShadowMap2D, center, ivec(x, y))\n"
+"#        define texval(x, y) textureGatherOffset(Texture_ShadowMap2D, center, ivec2(x, y))\n"
 "#      else\n"
-"#        define texval(x, y) texture4(Texture_ShadowMap2D, center + vec2(x,y)*ShadowMap_TextureScale)\n"
+"#        define texval(x, y) texture4(Texture_ShadowMap2D, center + vec2(x, y)*ShadowMap_TextureScale)\n"
 "#      endif\n"
-"    vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n"
-"    center *= ShadowMap_TextureScale;\n"
-"    vec4 group1 = step(shadowmaptc.z, texval(-1.0, -1.0));\n"
-"    vec4 group2 = step(shadowmaptc.z, texval( 1.0, -1.0));\n"
-"    vec4 group3 = step(shadowmaptc.z, texval(-1.0,  1.0));\n"
-"    vec4 group4 = step(shadowmaptc.z, texval( 1.0,  1.0));\n"
-"    vec4 cols = vec4(group1.rg, group2.rg) + vec4(group3.ab, group4.ab) +\n"
-"                mix(vec4(group1.ab, group2.ab), vec4(group3.rg, group4.rg), offset.y);\n"
-"    f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
+"      vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n"
+"      center *= ShadowMap_TextureScale;\n"
+"      vec4 group1 = step(shadowmaptc.z, texval(-1.0, -1.0));\n"
+"      vec4 group2 = step(shadowmaptc.z, texval( 1.0, -1.0));\n"
+"      vec4 group3 = step(shadowmaptc.z, texval(-1.0,  1.0));\n"
+"      vec4 group4 = step(shadowmaptc.z, texval( 1.0,  1.0));\n"
+"      vec4 cols = vec4(group1.rg, group2.rg) + vec4(group3.ab, group4.ab) +\n"
+"                              mix(vec4(group1.ab, group2.ab), vec4(group3.rg, group4.rg), offset.y);\n"
+"      f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
 "#     else\n"
 "#      ifdef GL_EXT_gpu_shader4\n"
 "#        define texval(x, y) texture2DOffset(Texture_ShadowMap2D, center, ivec2(x, y)).r\n"
@@ -1112,111 +1178,86 @@ static const char *builtinshaderstring =
 "#        define texval(x, y) texture2D(Texture_ShadowMap2D, center + vec2(x, y)*ShadowMap_TextureScale).r  \n"
 "#      endif\n"
 "#      if USESHADOWMAPPCF > 1\n"
-"    vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n"
-"    center *= ShadowMap_TextureScale;\n"
-"    vec4 row1 = step(shadowmaptc.z, vec4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n"
-"    vec4 row2 = step(shadowmaptc.z, vec4(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0), texval( 2.0,  0.0)));\n"
-"    vec4 row3 = step(shadowmaptc.z, vec4(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0), texval( 2.0,  1.0)));\n"
-"    vec4 row4 = step(shadowmaptc.z, vec4(texval(-1.0,  2.0), texval( 0.0,  2.0), texval( 1.0,  2.0), texval( 2.0,  2.0)));\n"
-"    vec4 cols = row2 + row3 + mix(row1, row4, offset.y);\n"
-"    f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
+"      vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n"
+"      center *= ShadowMap_TextureScale;\n"
+"      vec4 row1 = step(shadowmaptc.z, vec4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n"
+"      vec4 row2 = step(shadowmaptc.z, vec4(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0), texval( 2.0,  0.0)));\n"
+"      vec4 row3 = step(shadowmaptc.z, vec4(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0), texval( 2.0,  1.0)));\n"
+"      vec4 row4 = step(shadowmaptc.z, vec4(texval(-1.0,  2.0), texval( 0.0,  2.0), texval( 1.0,  2.0), texval( 2.0,  2.0)));\n"
+"      vec4 cols = row2 + row3 + mix(row1, row4, offset.y);\n"
+"      f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
 "#      else\n"
-"    vec2 center = shadowmaptc.xy*ShadowMap_TextureScale, offset = fract(shadowmaptc.xy);\n"
-"    vec3 row1 = step(shadowmaptc.z, vec3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n"
-"    vec3 row2 = step(shadowmaptc.z, vec3(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0)));\n"
-"    vec3 row3 = step(shadowmaptc.z, vec3(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0)));\n"
-"    vec3 cols = row2 + mix(row1, row3, offset.y);\n"
-"    f = dot(mix(cols.xy, cols.yz, offset.x), vec2(0.25));\n"
+"      vec2 center = shadowmaptc.xy*ShadowMap_TextureScale, offset = fract(shadowmaptc.xy);\n"
+"      vec3 row1 = step(shadowmaptc.z, vec3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n"
+"      vec3 row2 = step(shadowmaptc.z, vec3(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0)));\n"
+"      vec3 row3 = step(shadowmaptc.z, vec3(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0)));\n"
+"      vec3 cols = row2 + mix(row1, row3, offset.y);\n"
+"      f = dot(mix(cols.xy, cols.yz, offset.x), vec2(0.25));\n"
 "#      endif\n"
 "#     endif\n"
 "#    else\n"
-"    f = step(shadowmaptc.z, texture2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale).r);\n"
+"      f = step(shadowmaptc.z, texture2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale).r);\n"
 "#    endif\n"
 "#  endif\n"
-"    return f;\n"
+"#  ifdef USESHADOWMAPORTHO\n"
+"      return mix(ShadowMap_Parameters.w, 1.0, f);\n"
+"#  else\n"
+"      return f;\n"
+"#  endif\n"
 "}\n"
 "# endif\n"
 "\n"
 "# ifdef USESHADOWMAPCUBE\n"
 "float ShadowMapCompare(vec3 dir)\n"
 "{\n"
-"    // apply depth texture cubemap as light filter\n"
-"    vec4 shadowmaptc = GetShadowMapTCCube(dir);\n"
-"    float f;\n"
+"      // apply depth texture cubemap as light filter\n"
+"      vec4 shadowmaptc = GetShadowMapTCCube(dir);\n"
+"      float f;\n"
 "#  ifdef USESHADOWSAMPLER\n"
-"    f = shadowCube(Texture_ShadowMapCube, shadowmaptc).r;\n"
+"      f = shadowCube(Texture_ShadowMapCube, shadowmaptc).r;\n"
 "#  else\n"
-"    f = step(shadowmaptc.w, textureCube(Texture_ShadowMapCube, shadowmaptc.xyz).r);\n"
+"      f = step(shadowmaptc.w, textureCube(Texture_ShadowMapCube, shadowmaptc.xyz).r);\n"
 "#  endif\n"
-"    return f;\n"
+"      return f;\n"
 "}\n"
 "# endif\n"
-"#endif\n"
-"\n"
-"#ifdef MODE_WATER\n"
+"#endif // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE) && !defined(USESHADOWMAPORTHO)\n"
+"#endif // FRAGMENT_SHADER\n"
 "\n"
-"// water pass\n"
-"void main(void)\n"
-"{\n"
-"#ifdef USEOFFSETMAPPING\n"
-"      // apply offsetmapping\n"
-"      vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
-"#define TexCoord TexCoordOffset\n"
-"#endif\n"
 "\n"
-"      vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
-"      //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
-"      vec4 SafeScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
-"      vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5))).xyxy * DistortScaleRefractReflect;\n"
-"      // FIXME temporary hack to detect the case that the reflection\n"
-"      // gets blackened at edges due to leaving the area that contains actual\n"
-"      // content.\n"
-"      // Remove this 'ack once we have a better way to stop this thing from\n"
-"      // 'appening.\n"
-"      float f = min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.01, 0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.01, -0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
-"      ScreenTexCoord.xy = mix(SafeScreenTexCoord.xy, ScreenTexCoord.xy, f);\n"
-"      f       = min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.01, 0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.01, -0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
-"      ScreenTexCoord.zw = mix(SafeScreenTexCoord.zw, ScreenTexCoord.zw, f);\n"
-"      float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * ReflectFactor + ReflectOffset;\n"
-"      gl_FragColor = mix(texture2D(Texture_Refraction, ScreenTexCoord.xy) * RefractColor, texture2D(Texture_Reflection, ScreenTexCoord.zw) * ReflectColor, Fresnel);\n"
-"}\n"
 "\n"
-"#else // !MODE_WATER\n"
-"#ifdef MODE_REFRACTION\n"
 "\n"
-"// refraction pass\n"
+"#ifdef MODE_DEFERREDGEOMETRY\n"
+"#ifdef VERTEX_SHADER\n"
+"uniform mat4 TexMatrix;\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"uniform mat4 BackgroundTexMatrix;\n"
+"#endif\n"
+"uniform mat4 ModelViewMatrix;\n"
 "void main(void)\n"
 "{\n"
+"      TexCoord = vec2(TexMatrix * gl_MultiTexCoord0);\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"      gl_FrontColor = gl_Color;\n"
+"      TexCoord2 = vec2(BackgroundTexMatrix * gl_MultiTexCoord0);\n"
+"#endif\n"
+"\n"
+"      // transform unnormalized eye direction into tangent space\n"
 "#ifdef USEOFFSETMAPPING\n"
-"      // apply offsetmapping\n"
-"      vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
-"#define TexCoord TexCoordOffset\n"
+"      vec3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
+"      EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
+"      EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
+"      EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
 "#endif\n"
 "\n"
-"      vec2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n"
-"      //vec2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
-"      vec2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
-"      vec2 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5))).xy * DistortScaleRefractReflect.xy;\n"
-"      // FIXME temporary hack to detect the case that the reflection\n"
-"      // gets blackened at edges due to leaving the area that contains actual\n"
-"      // content.\n"
-"      // Remove this 'ack once we have a better way to stop this thing from\n"
-"      // 'appening.\n"
-"      float f = min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, 0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, -0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
-"      ScreenTexCoord = mix(SafeScreenTexCoord, ScreenTexCoord, f);\n"
-"      gl_FragColor = texture2D(Texture_Refraction, ScreenTexCoord) * RefractColor;\n"
+"      VectorS = (ModelViewMatrix * vec4(gl_MultiTexCoord1.xyz, 0)).xyz;\n"
+"      VectorT = (ModelViewMatrix * vec4(gl_MultiTexCoord2.xyz, 0)).xyz;\n"
+"      VectorR = (ModelViewMatrix * vec4(gl_MultiTexCoord3.xyz, 0)).xyz;\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
 "}\n"
+"#endif // VERTEX_SHADER\n"
 "\n"
-"#else // !MODE_REFRACTION\n"
+"#ifdef FRAGMENT_SHADER\n"
 "void main(void)\n"
 "{\n"
 "#ifdef USEOFFSETMAPPING\n"
@@ -1225,123 +1266,329 @@ static const char *builtinshaderstring =
 "#define TexCoord TexCoordOffset\n"
 "#endif\n"
 "\n"
-"      // combine the diffuse textures (base, pants, shirt)\n"
-"      myhalf4 color = myhalf4(texture2D(Texture_Color, TexCoord));\n"
-"#ifdef USECOLORMAPPING\n"
-"      color.rgb += myhalf3(texture2D(Texture_Pants, TexCoord)) * Color_Pants + myhalf3(texture2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
+"#ifdef USEALPHAKILL\n"
+"      if (texture2D(Texture_Color, TexCoord).a < 0.5)\n"
+"              discard;\n"
 "#endif\n"
+"\n"
 "#ifdef USEVERTEXTEXTUREBLEND\n"
-"      myhalf terrainblend = clamp(myhalf(gl_Color.a) * color.a * 2.0 - 0.5, myhalf(0.0), myhalf(1.0));\n"
-"      //myhalf terrainblend = min(myhalf(gl_Color.a) * color.a * 2.0, myhalf(1.0));\n"
-"      //myhalf terrainblend = myhalf(gl_Color.a) * color.a > 0.5;\n"
-"      color.rgb = mix(myhalf3(texture2D(Texture_SecondaryColor, TexCoord2)), color.rgb, terrainblend);\n"
-"      color.a = 1.0;\n"
-"      //color = mix(myhalf4(1, 0, 0, 1), color, terrainblend);\n"
+"      float alpha = texture2D(Texture_Color, TexCoord).a;\n"
+"      float terrainblend = clamp(float(gl_Color.a) * alpha * 2.0 - 0.5, float(0.0), float(1.0));\n"
+"      //float terrainblend = min(float(gl_Color.a) * alpha * 2.0, float(1.0));\n"
+"      //float terrainblend = float(gl_Color.a) * alpha > 0.5;\n"
 "#endif\n"
 "\n"
-"#ifdef USEDIFFUSE\n"
-"      // get the surface normal and the gloss color\n"
-"# ifdef USEVERTEXTEXTUREBLEND\n"
-"      myhalf3 surfacenormal = normalize(mix(myhalf3(texture2D(Texture_SecondaryNormal, TexCoord2)), myhalf3(texture2D(Texture_Normal, TexCoord)), terrainblend) - myhalf3(0.5, 0.5, 0.5));\n"
-"#  ifdef USESPECULAR\n"
-"      myhalf3 glosscolor = mix(myhalf3(texture2D(Texture_SecondaryGloss, TexCoord2)), myhalf3(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n"
-"#  endif\n"
-"# else\n"
-"      myhalf3 surfacenormal = normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5, 0.5, 0.5));\n"
-"#  ifdef USESPECULAR\n"
-"      myhalf3 glosscolor = myhalf3(texture2D(Texture_Gloss, TexCoord));\n"
-"#  endif\n"
-"# endif\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"      vec3 surfacenormal = mix(vec3(texture2D(Texture_SecondaryNormal, TexCoord2)), vec3(texture2D(Texture_Normal, TexCoord)), terrainblend) - vec3(0.5, 0.5, 0.5);\n"
+"      float a = mix(texture2D(Texture_SecondaryGloss, TexCoord2).a, texture2D(Texture_Gloss, TexCoord).a, terrainblend);\n"
+"#else\n"
+"      vec3 surfacenormal = vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5, 0.5, 0.5);\n"
+"      float a = texture2D(Texture_Gloss, TexCoord).a;\n"
 "#endif\n"
 "\n"
+"      gl_FragColor = vec4(normalize(surfacenormal.x * VectorS + surfacenormal.y * VectorT + surfacenormal.z * VectorR) * 0.5 + vec3(0.5, 0.5, 0.5), a);\n"
+"}\n"
+"#endif // FRAGMENT_SHADER\n"
+"#else // !MODE_DEFERREDGEOMETRY\n"
 "\n"
 "\n"
-"#ifdef MODE_LIGHTSOURCE\n"
-"      // light source\n"
 "\n"
-"      // calculate surface normal, light normal, and specular normal\n"
-"      // compute color intensity for the two textures (colormap and glossmap)\n"
-"      // scale by light color and attenuation as efficiently as possible\n"
-"      // (do as much scalar math as possible rather than vector math)\n"
-"# ifdef USEDIFFUSE\n"
-"      // get the light normal\n"
-"      myhalf3 diffusenormal = myhalf3(normalize(LightVector));\n"
-"# endif\n"
-"# ifdef USESPECULAR\n"
-"#  ifndef USEEXACTSPECULARMATH\n"
-"      myhalf3 specularnormal = normalize(diffusenormal + myhalf3(normalize(EyeVector)));\n"
 "\n"
-"#  endif\n"
+"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
+"#ifdef VERTEX_SHADER\n"
+"uniform mat4 ModelViewMatrix;\n"
+"void main(void)\n"
+"{\n"
+"      ModelViewPosition = ModelViewMatrix * gl_Vertex;\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
+"}\n"
+"#endif // VERTEX_SHADER\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"uniform mat4 ViewToLight;\n"
+"// ScreenToDepth = vec2(Far / (Far - Near), Far * Near / (Near - Far));\n"
+"uniform vec2 ScreenToDepth;\n"
+"uniform myhalf3 DeferredColor_Ambient;\n"
+"uniform myhalf3 DeferredColor_Diffuse;\n"
+"#ifdef USESPECULAR\n"
+"uniform myhalf3 DeferredColor_Specular;\n"
+"uniform myhalf SpecularPower;\n"
+"#endif\n"
+"uniform myhalf2 PixelToScreenTexCoord;\n"
+"void main(void)\n"
+"{\n"
+"      // calculate viewspace pixel position\n"
+"      vec2 ScreenTexCoord = gl_FragCoord.xy * PixelToScreenTexCoord;\n"
+"      vec3 position;\n"
+"      position.z = ScreenToDepth.y / (texture2D(Texture_ScreenDepth, ScreenTexCoord).r + ScreenToDepth.x);\n"
+"      position.xy = ModelViewPosition.xy * (position.z / ModelViewPosition.z);\n"
+"      // decode viewspace pixel normal\n"
+"      myhalf4 normalmap = texture2D(Texture_ScreenNormalMap, ScreenTexCoord);\n"
+"      myhalf3 surfacenormal = normalize(normalmap.rgb - myhalf3(0.5,0.5,0.5));\n"
+"      // surfacenormal = pixel normal in viewspace\n"
+"      // LightVector = pixel to light in viewspace\n"
+"      // CubeVector = position in lightspace\n"
+"      // eyevector = pixel to view in viewspace\n"
+"      vec3 CubeVector = vec3(ViewToLight * vec4(position,1));\n"
+"      myhalf fade = myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
+"#ifdef USEDIFFUSE\n"
+"      // calculate diffuse shading\n"
+"      myhalf3 lightnormal = myhalf3(normalize(LightPosition - position));\n"
+"      myhalf diffuse = myhalf(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
 "      // calculate directional shading\n"
+"      vec3 eyevector = position * -1.0;\n"
 "#  ifdef USEEXACTSPECULARMATH\n"
-"      color.rgb = myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (color.rgb * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))) + (SpecularScale * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower)) * glosscolor);\n"
-"#  else\n"
-"      color.rgb = myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (color.rgb * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))) + (SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower)) * glosscolor);\n"
-"#  endif\n"
-"# else\n"
-"#  ifdef USEDIFFUSE\n"
-"      // calculate directional shading\n"
-"      color.rgb = color.rgb * (myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))));\n"
+"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(eyevector)))*-1.0, 0.0)), SpecularPower * normalmap.a);\n"
 "#  else\n"
-"      // calculate directionless shading\n"
-"      color.rgb = color.rgb * myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
+"      myhalf3 specularnormal = normalize(lightnormal + myhalf3(normalize(eyevector)));\n"
+"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * normalmap.a);\n"
 "#  endif\n"
-"# endif\n"
+"#endif\n"
 "\n"
 "#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAPCUBE) || defined(USESHADOWMAP2D)\n"
-"#if !showshadowmap\n"
-"    color.rgb *= ShadowMapCompare(CubeVector);\n"
+"      fade *= ShadowMapCompare(CubeVector);\n"
+"#endif\n"
+"\n"
+"#ifdef USEDIFFUSE\n"
+"      gl_FragData[0] = vec4((DeferredColor_Ambient + DeferredColor_Diffuse * diffuse) * fade, 1.0);\n"
+"#else\n"
+"      gl_FragData[0] = vec4(DeferredColor_Ambient * fade, 1.0);\n"
 "#endif\n"
+"#ifdef USESPECULAR\n"
+"      gl_FragData[1] = vec4(DeferredColor_Specular * (specular * fade), 1.0);\n"
+"#else\n"
+"      gl_FragData[1] = vec4(0.0, 0.0, 0.0, 1.0);\n"
 "#endif\n"
 "\n"
 "# ifdef USECUBEFILTER\n"
-"      // apply light cubemap filter\n"
-"      //color.rgb *= normalize(CubeVector) * 0.5 + 0.5;//vec3(textureCube(Texture_Cube, CubeVector));\n"
-"      color.rgb *= myhalf3(textureCube(Texture_Cube, CubeVector));\n"
+"      vec3 cubecolor = textureCube(Texture_Cube, CubeVector).rgb;\n"
+"      gl_FragData[0].rgb *= cubecolor;\n"
+"      gl_FragData[1].rgb *= cubecolor;\n"
 "# endif\n"
-"#endif // MODE_LIGHTSOURCE\n"
+"}\n"
+"#endif // FRAGMENT_SHADER\n"
+"#else // !MODE_DEFERREDLIGHTSOURCE\n"
 "\n"
 "\n"
 "\n"
 "\n"
-"#ifdef MODE_LIGHTDIRECTION\n"
-"      // directional model lighting\n"
+"#ifdef VERTEX_SHADER\n"
+"uniform mat4 TexMatrix;\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"uniform mat4 BackgroundTexMatrix;\n"
+"#endif\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"uniform mat4 ModelToLight;\n"
+"#endif\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"uniform mat4 ShadowMapMatrix;\n"
+"#endif\n"
+"void main(void)\n"
+"{\n"
+"#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND)\n"
+"      gl_FrontColor = gl_Color;\n"
+"#endif\n"
+"      // copy the surface texcoord\n"
+"      TexCoord = vec2(TexMatrix * gl_MultiTexCoord0);\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"      TexCoord2 = vec2(BackgroundTexMatrix * gl_MultiTexCoord0);\n"
+"#endif\n"
+"#ifdef USELIGHTMAP\n"
+"      TexCoordLightmap = vec2(gl_MultiTexCoord4);\n"
+"#endif\n"
+"\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"      // transform vertex position into light attenuation/cubemap space\n"
+"      // (-1 to +1 across the light box)\n"
+"      CubeVector = vec3(ModelToLight * gl_Vertex);\n"
+"\n"
 "# ifdef USEDIFFUSE\n"
-"      // get the light normal\n"
-"      myhalf3 diffusenormal = myhalf3(normalize(LightVector));\n"
+"      // transform unnormalized light direction into tangent space\n"
+"      // (we use unnormalized to ensure that it interpolates correctly and then\n"
+"      //  normalize it per pixel)\n"
+"      vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
+"      LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
+"      LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
+"      LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
 "# endif\n"
-"# ifdef USESPECULAR\n"
-"      // calculate directional shading\n"
-"      color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
-"#  ifdef USEEXACTSPECULARMATH\n"
-"      color.rgb += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
-"#  else\n"
-"      myhalf3 specularnormal = normalize(diffusenormal + myhalf3(normalize(EyeVector)));\n"
-"      color.rgb += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
-"#  endif\n"
+"#endif\n"
+"\n"
+"#if defined(MODE_LIGHTDIRECTION) && defined(USEDIFFUSE)\n"
+"      LightVector.x = dot(LightDir, gl_MultiTexCoord1.xyz);\n"
+"      LightVector.y = dot(LightDir, gl_MultiTexCoord2.xyz);\n"
+"      LightVector.z = dot(LightDir, gl_MultiTexCoord3.xyz);\n"
+"#endif\n"
+"\n"
+"      // transform unnormalized eye direction into tangent space\n"
+"#ifdef USEEYEVECTOR\n"
+"      vec3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
+"      EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
+"      EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
+"      EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
+"#endif\n"
+"\n"
+"#ifdef USEFOG\n"
+"      EyeVectorModelSpaceFogPlaneVertexDist.xyz = EyePosition - gl_Vertex.xyz;\n"
+"      EyeVectorModelSpaceFogPlaneVertexDist.w = dot(FogPlane, gl_Vertex);\n"
+"#endif\n"
+"\n"
+"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(USEREFLECTCUBE)\n"
+"      VectorS = gl_MultiTexCoord1.xyz;\n"
+"      VectorT = gl_MultiTexCoord2.xyz;\n"
+"      VectorR = gl_MultiTexCoord3.xyz;\n"
+"#endif\n"
+"\n"
+"      // transform vertex to camera space, using ftransform to match non-VS rendering\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
+"\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"      ShadowMapTC = vec3(ShadowMapMatrix * gl_Position);\n"
+"#endif\n"
+"\n"
+"#ifdef USEREFLECTION\n"
+"      ModelViewProjectionPosition = gl_Position;\n"
+"#endif\n"
+"}\n"
+"#endif // VERTEX_SHADER\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"#ifdef USEDEFERREDLIGHTMAP\n"
+"uniform myhalf2 PixelToScreenTexCoord;\n"
+"uniform myhalf3 DeferredMod_Diffuse;\n"
+"uniform myhalf3 DeferredMod_Specular;\n"
+"#endif\n"
+"uniform myhalf3 Color_Ambient;\n"
+"uniform myhalf3 Color_Diffuse;\n"
+"uniform myhalf3 Color_Specular;\n"
+"uniform myhalf SpecularPower;\n"
+"#ifdef USEGLOW\n"
+"uniform myhalf3 Color_Glow;\n"
+"#endif\n"
+"uniform myhalf Alpha;\n"
+"#ifdef USEREFLECTION\n"
+"uniform vec4 DistortScaleRefractReflect;\n"
+"uniform vec4 ScreenScaleRefractReflect;\n"
+"uniform vec4 ScreenCenterRefractReflect;\n"
+"uniform myhalf4 ReflectColor;\n"
+"#endif\n"
+"#ifdef USEREFLECTCUBE\n"
+"uniform mat4 ModelToReflectCube;\n"
+"uniform sampler2D Texture_ReflectMask;\n"
+"uniform samplerCube Texture_ReflectCube;\n"
+"#endif\n"
+"#ifdef MODE_LIGHTDIRECTION\n"
+"uniform myhalf3 LightColor;\n"
+"#endif\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"uniform myhalf3 LightColor;\n"
+"#endif\n"
+"void main(void)\n"
+"{\n"
+"#ifdef USEOFFSETMAPPING\n"
+"      // apply offsetmapping\n"
+"      vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
+"#define TexCoord TexCoordOffset\n"
+"#endif\n"
+"\n"
+"      // combine the diffuse textures (base, pants, shirt)\n"
+"      myhalf4 color = myhalf4(texture2D(Texture_Color, TexCoord));\n"
+"#ifdef USEALPHAKILL\n"
+"      if (color.a < 0.5)\n"
+"              discard;\n"
+"#endif\n"
+"      color.a *= Alpha;\n"
+"#ifdef USECOLORMAPPING\n"
+"      color.rgb += myhalf3(texture2D(Texture_Pants, TexCoord)) * Color_Pants + myhalf3(texture2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
+"#endif\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"      myhalf terrainblend = clamp(myhalf(gl_Color.a) * color.a * 2.0 - 0.5, myhalf(0.0), myhalf(1.0));\n"
+"      //myhalf terrainblend = min(myhalf(gl_Color.a) * color.a * 2.0, myhalf(1.0));\n"
+"      //myhalf terrainblend = myhalf(gl_Color.a) * color.a > 0.5;\n"
+"      color.rgb = mix(myhalf3(texture2D(Texture_SecondaryColor, TexCoord2)), color.rgb, terrainblend);\n"
+"      color.a = 1.0;\n"
+"      //color = mix(myhalf4(1, 0, 0, 1), color, terrainblend);\n"
+"#endif\n"
+"\n"
+"      // get the surface normal\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"      myhalf3 surfacenormal = normalize(mix(myhalf3(texture2D(Texture_SecondaryNormal, TexCoord2)), myhalf3(texture2D(Texture_Normal, TexCoord)), terrainblend) - myhalf3(0.5, 0.5, 0.5));\n"
+"#else\n"
+"      myhalf3 surfacenormal = normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5, 0.5, 0.5));\n"
+"#endif\n"
+"\n"
+"      // get the material colors\n"
+"      myhalf3 diffusetex = color.rgb;\n"
+"#if defined(USESPECULAR) || defined(USEDEFERREDLIGHTMAP)\n"
+"# ifdef USEVERTEXTEXTUREBLEND\n"
+"      myhalf4 glosstex = mix(myhalf4(texture2D(Texture_SecondaryGloss, TexCoord2)), myhalf4(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n"
 "# else\n"
-"#  ifdef USEDIFFUSE\n"
+"      myhalf4 glosstex = myhalf4(texture2D(Texture_Gloss, TexCoord));\n"
+"# endif\n"
+"#endif\n"
 "\n"
-"      // calculate directional shading\n"
-"      color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
-"#  else\n"
-"      color.rgb *= AmbientColor;\n"
-"#  endif\n"
+"#ifdef USEREFLECTCUBE\n"
+"      vec3 TangentReflectVector = reflect(-EyeVector, surfacenormal);\n"
+"      vec3 ModelReflectVector = TangentReflectVector.x * VectorS + TangentReflectVector.y * VectorT + TangentReflectVector.z * VectorR;\n"
+"      vec3 ReflectCubeTexCoord = vec3(ModelToReflectCube * vec4(ModelReflectVector, 0));\n"
+"      diffusetex += myhalf3(texture2D(Texture_ReflectMask, TexCoord)) * myhalf3(textureCube(Texture_ReflectCube, ReflectCubeTexCoord));\n"
+"#endif\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"      // light source\n"
+"#ifdef USEDIFFUSE\n"
+"      myhalf3 lightnormal = myhalf3(normalize(LightVector));\n"
+"      myhalf diffuse = myhalf(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
+"      color.rgb = diffusetex * (Color_Ambient + diffuse * Color_Diffuse);\n"
+"#ifdef USESPECULAR\n"
+"#ifdef USEEXACTSPECULARMATH\n"
+"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower * glosstex.a);\n"
+"#else\n"
+"      myhalf3 specularnormal = normalize(lightnormal + myhalf3(normalize(EyeVector)));\n"
+"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * glosstex.a);\n"
+"#endif\n"
+"      color.rgb += glosstex.rgb * (specular * Color_Specular);\n"
+"#endif\n"
+"#else\n"
+"      color.rgb = diffusetex * Color_Ambient;\n"
+"#endif\n"
+"      color.rgb *= LightColor;\n"
+"      color.rgb *= myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAPCUBE) || defined(USESHADOWMAP2D)\n"
+"      color.rgb *= ShadowMapCompare(CubeVector);\n"
+"#endif\n"
+"# ifdef USECUBEFILTER\n"
+"      color.rgb *= myhalf3(textureCube(Texture_Cube, CubeVector));\n"
 "# endif\n"
-"#endif // MODE_LIGHTDIRECTION\n"
+"#endif // MODE_LIGHTSOURCE\n"
 "\n"
 "\n"
 "\n"
 "\n"
+"#ifdef MODE_LIGHTDIRECTION\n"
+"#define SHADING\n"
+"#ifdef USEDIFFUSE\n"
+"      myhalf3 lightnormal = myhalf3(normalize(LightVector));\n"
+"#endif\n"
+"#define lightcolor LightColor\n"
+"#endif // MODE_LIGHTDIRECTION\n"
 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
-"      // deluxemap lightmapping using light vectors in modelspace (evil q3map2)\n"
-"\n"
-"      // get the light normal\n"
-"      myhalf3 diffusenormal_modelspace = myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n"
-"      myhalf3 diffusenormal;\n"
-"      diffusenormal.x = dot(diffusenormal_modelspace, myhalf3(VectorS));\n"
-"      diffusenormal.y = dot(diffusenormal_modelspace, myhalf3(VectorT));\n"
-"      diffusenormal.z = dot(diffusenormal_modelspace, myhalf3(VectorR));\n"
+"#define SHADING\n"
+"      // deluxemap lightmapping using light vectors in modelspace (q3map2 -light -deluxe)\n"
+"      myhalf3 lightnormal_modelspace = myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n"
+"      myhalf3 lightcolor = myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap));\n"
+"      // convert modelspace light vector to tangentspace\n"
+"      myhalf3 lightnormal;\n"
+"      lightnormal.x = dot(lightnormal_modelspace, myhalf3(VectorS));\n"
+"      lightnormal.y = dot(lightnormal_modelspace, myhalf3(VectorT));\n"
+"      lightnormal.z = dot(lightnormal_modelspace, myhalf3(VectorR));\n"
 "      // calculate directional shading (and undoing the existing angle attenuation on the lightmap by the division)\n"
 "      // note that q3map2 is too stupid to calculate proper surface normals when q3map_nonplanar\n"
 "      // is used (the lightmap and deluxemap coords correspond to virtually random coordinates\n"
@@ -1351,119 +1598,74 @@ static const char *builtinshaderstring =
 "      // are added up. To prevent divisions by zero or strong exaggerations, a max()\n"
 "      // nudge is done here at expense of some additional fps. This is ONLY needed for\n"
 "      // deluxemaps, tangentspace deluxemap avoid this problem by design.\n"
-"      myhalf3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal) / max(0.25, diffusenormal.z)), 0.0)));\n"
-"              // 0.25 supports up to 75.5 degrees normal/deluxe angle\n"
-"# ifdef USESPECULAR\n"
-"#  ifdef USEEXACTSPECULARMATH\n"
-"      tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(reflect(normalize(diffusenormal), surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
-"#  else\n"
-"      myhalf3 specularnormal = myhalf3(normalize(diffusenormal + myhalf3(normalize(EyeVector))));\n"
-"      tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
-"#  endif\n"
-"# endif\n"
-"\n"
-"      // apply lightmap color\n"
-"      color.rgb = color.rgb * AmbientScale + tempcolor * myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap));\n"
+"      lightcolor *= 1.0 / max(0.25, lightnormal.z);\n"
 "#endif // MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
-"\n"
-"\n"
-"\n"
-"\n"
 "#ifdef MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
+"#define SHADING\n"
 "      // deluxemap lightmapping using light vectors in tangentspace (hmap2 -light)\n"
-"\n"
-"      // get the light normal\n"
-"      myhalf3 diffusenormal = myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n"
-"      // calculate directional shading (and undoing the existing angle attenuation on the lightmap by the division)\n"
-"      myhalf3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal) / diffusenormal.z), 0.0)));\n"
-"# ifdef USESPECULAR\n"
-"#  ifdef USEEXACTSPECULARMATH\n"
-"      tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
-"#  else\n"
-"      myhalf3 specularnormal = myhalf3(normalize(diffusenormal + myhalf3(normalize(EyeVector))));\n"
-"      tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
-"#  endif\n"
-"# endif\n"
-"\n"
-"      // apply lightmap color\n"
-"      color.rgb = color.rgb * AmbientScale + tempcolor * myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap));\n"
-"#endif // MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
+"      myhalf3 lightnormal = myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n"
+"      myhalf3 lightcolor = myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap));\n"
+"#endif\n"
 "\n"
 "\n"
 "\n"
 "\n"
 "#ifdef MODE_LIGHTMAP\n"
-"      // apply lightmap color\n"
-"      color.rgb = color.rgb * myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap)) * DiffuseScale + color.rgb * AmbientScale;\n"
+"      color.rgb = diffusetex * (Color_Ambient + myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap)) * Color_Diffuse);\n"
 "#endif // MODE_LIGHTMAP\n"
-"\n"
-"\n"
-"\n"
-"\n"
 "#ifdef MODE_VERTEXCOLOR\n"
-"      // apply lightmap color\n"
-"      color.rgb = color.rgb * myhalf3(gl_Color.rgb) * DiffuseScale + color.rgb * AmbientScale;\n"
+"      color.rgb = diffusetex * (Color_Ambient + myhalf3(gl_Color.rgb) * Color_Diffuse);\n"
 "#endif // MODE_VERTEXCOLOR\n"
-"\n"
-"\n"
-"\n"
-"\n"
 "#ifdef MODE_FLATCOLOR\n"
+"      color.rgb = diffusetex * Color_Ambient;\n"
 "#endif // MODE_FLATCOLOR\n"
 "\n"
 "\n"
 "\n"
 "\n"
+"#ifdef SHADING\n"
+"# ifdef USEDIFFUSE\n"
+"      myhalf diffuse = myhalf(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
+"#  ifdef USESPECULAR\n"
+"#   ifdef USEEXACTSPECULARMATH\n"
+"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower * glosstex.a);\n"
+"#   else\n"
+"      myhalf3 specularnormal = normalize(lightnormal + myhalf3(normalize(EyeVector)));\n"
+"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * glosstex.a);\n"
+"#   endif\n"
+"      color.rgb = diffusetex * Color_Ambient + (diffusetex * Color_Diffuse * diffuse + glosstex.rgb * Color_Specular * specular) * lightcolor;\n"
+"#  else\n"
+"      color.rgb = diffusetex * (Color_Ambient + Color_Diffuse * diffuse * lightcolor);\n"
+"#  endif\n"
+"# else\n"
+"      color.rgb = diffusetex * Color_Ambient;\n"
+"# endif\n"
+"#endif\n"
 "\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"      color.rgb *= ShadowMapCompare(ShadowMapTC);\n"
+"#endif\n"
 "\n"
-"\n"
-"      color *= TintColor;\n"
+"#ifdef USEDEFERREDLIGHTMAP\n"
+"      vec2 ScreenTexCoord = gl_FragCoord.xy * PixelToScreenTexCoord;\n"
+"      color.rgb += diffusetex * myhalf3(texture2D(Texture_ScreenDiffuse, ScreenTexCoord)) * DeferredMod_Diffuse;\n"
+"      color.rgb += glosstex.rgb * myhalf3(texture2D(Texture_ScreenSpecular, ScreenTexCoord)) * DeferredMod_Specular;\n"
+"#endif\n"
 "\n"
 "#ifdef USEGLOW\n"
 "#ifdef USEVERTEXTEXTUREBLEND\n"
-"      color.rgb += mix(myhalf3(texture2D(Texture_SecondaryGlow, TexCoord2)), myhalf3(texture2D(Texture_Glow, TexCoord)), terrainblend);\n"
+"      color.rgb += mix(myhalf3(texture2D(Texture_SecondaryGlow, TexCoord2)), myhalf3(texture2D(Texture_Glow, TexCoord)), terrainblend) * Color_Glow;\n"
 "#else\n"
-"      color.rgb += myhalf3(texture2D(Texture_Glow, TexCoord)) * GlowColor;\n"
+"      color.rgb += myhalf3(texture2D(Texture_Glow, TexCoord)) * Color_Glow;\n"
 "#endif\n"
 "#endif\n"
 "\n"
-"      color.rgb *= SceneBrightness;\n"
-"\n"
-"      // apply fog after Contrastboost/SceneBrightness because its color is already modified appropriately\n"
 "#ifdef USEFOG\n"
-"      float fogfrac;\n"
-"#ifdef USEFOGOUTSIDE\n"
-"      fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0, min(0.0, FogPlaneVertexDist) * FogHeightFade);\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"      color.rgb *= myhalf(FogVertex());\n"
 "#else\n"
-"      fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist)) * min(1.0, (min(0.0, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);\n"
+"      color.rgb = mix(FogColor, color.rgb, FogVertex());\n"
 "#endif\n"
-"//    float FogHeightFade1 = -0.5/1024.0;\n"
-"//    if (FogPlaneViewDist >= 0.0)\n"
-"//            fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0, min(0.0, FogPlaneVertexDist) * FogHeightFade1);\n"
-"//    else\n"
-"//            fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist)) * min(1.0, (min(0.0, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade1);\n"
-"//# ifdef USEFOGABOVE\n"
-"//    if (FogPlaneViewDist >= 0.0)\n"
-"//            fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist);\n"
-"//    else\n"
-"//            fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist));\n"
-"//    fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist))*FogHeightFade1);\n"
-"//    fogfrac *= min(1.0, (max(0.0, fade*FogPlaneVertexDist) + max(0.0, fade*FogPlaneViewDist)));\n"
-"//    fogfrac *= min(1.0, (max(0.0, FogHeightFade1*FogPlaneVertexDist) + max(0.0, FogHeightFade1*FogPlaneViewDist)));\n"
-"//    fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist))*FogHeightFade1);\n"
-"\n"
-"      //fogfrac *= min(1.0, max(0.0, (max(-2048, min(0, FogPlaneVertexDist)) + max(-2048, min(0, FogPlaneViewDist)))/-2048.0));\n"
-"      //float fade = -0.5/128.0;\n"
-"      //fogfrac *= max(0.0, min(1.0, fade*FogPlaneVertexDist)) + max(0.0, min(1.0, fade*FogPlaneViewDist));\n"
-"      //fogfrac *= max(0.0, min(1.0, FogHeightFade1*FogPlaneVertexDist)) + max(0.0, min(1.0, FogHeightFade1*FogPlaneViewDist));\n"
-"      //fogfrac *= min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist)) + min(1.0, max(0.0, FogHeightFade1*FogPlaneViewDist));\n"
-"      //fogfrac *= min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist) + max(0.0, FogHeightFade1*FogPlaneViewDist));\n"
-"      //fogfrac *= min(1.0, min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist)) + min(1.0, max(0.0, FogHeightFade1*FogPlaneViewDist)));\n"
-"      //fogfrac *= min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist) + max(0.0, FogHeightFade1*FogPlaneViewDist));\n"
-"      //fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist)) * FogHeightFade1);\n"
-"      //fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist)) * FogHeightFade1);\n"
-"//# endif\n"
-"      color.rgb = mix(FogColor, color.rgb, myhalf(texture2D(Texture_FogMask, myhalf2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0))));\n"
 "#endif\n"
 "\n"
 "      // reflection must come last because it already contains exactly the correct fog (the reflection render preserves camera distance from the plane, it only flips the side) and ContrastBoost/SceneBrightness\n"
@@ -1486,37 +1688,1476 @@ static const char *builtinshaderstring =
 "#endif\n"
 "\n"
 "      gl_FragColor = vec4(color);\n"
+"}\n"
+"#endif // FRAGMENT_SHADER\n"
 "\n"
-"#if showshadowmap\n"
-"# ifdef USESHADOWMAPRECT\n"
-"#  ifdef USESHADOWSAMPLER\n"
-"      gl_FragColor = shadow2DRect(Texture_ShadowMapRect, GetShadowMapTC2D(CubeVector).xyz);\n"
-"#  else\n"
-"      gl_FragColor = texture2DRect(Texture_ShadowMapRect, GetShadowMapTC2D(CubeVector).xy);\n"
-"#  endif\n"
-"# endif\n"
-"# ifdef USESHADOWMAP2D\n"
-"#  ifdef USESHADOWSAMPLER\n"
-"    gl_FragColor = shadow2D(Texture_ShadowMap2D, GetShadowMapTC2D(CubeVector).xyz);\n"
-"#  else\n"
-"    gl_FragColor = texture2D(Texture_ShadowMap2D, GetShadowMapTC2D(CubeVector).xy);\n"
-"#  endif\n"
-"# endif\n"
+"#endif // !MODE_DEFERREDLIGHTSOURCE\n"
+"#endif // !MODE_DEFERREDGEOMETRY\n"
+"#endif // !MODE_WATER\n"
+"#endif // !MODE_REFRACTION\n"
+"#endif // !MODE_BLOOMBLUR\n"
+"#endif // !MODE_GENERIC\n"
+"#endif // !MODE_POSTPROCESS\n"
+"#endif // !MODE_SHOWDEPTH\n"
+"#endif // !MODE_DEPTH_OR_SHADOW\n"
+;
+
+/*
+=========================================================================================================================================================
+
+
+
+=========================================================================================================================================================
+
+
+
+=========================================================================================================================================================
+
+
+
+=========================================================================================================================================================
+
+
+
+=========================================================================================================================================================
+
+
+
+=========================================================================================================================================================
+
+
+
+=========================================================================================================================================================
+*/
+
+const char *builtincgshaderstring =
+"// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
+"// written by Forest 'LordHavoc' Hale\n"
+"// shadowmapping enhancements by Lee 'eihrul' Salzman\n"
 "\n"
-"# ifdef USESHADOWMAPCUBE\n"
+"#if defined(USEFOGINSIDE) || defined(USEFOGOUTSIDE)\n"
+"# define USEFOG\n"
+"#endif\n"
+"#if defined(MODE_LIGHTMAP) || defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
+"#define USELIGHTMAP\n"
+"#endif\n"
+"#if defined(USESPECULAR) || defined(USEOFFSETMAPPING) || defined(USEREFLECTCUBE)\n"
+"#define USEEYEVECTOR\n"
+"#endif\n"
+"\n"
+"#ifdef MODE_DEPTH_OR_SHADOW\n"
+"#ifdef VERTEX_SHADER\n"
+"void main\n"
+"(\n"
+"float4 gl_Vertex : POSITION,\n"
+"uniform float4x4 ModelViewProjectionMatrix,\n"
+"out float4 gl_Position : POSITION\n"
+")\n"
+"{\n"
+"      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
+"}\n"
+"#endif\n"
+"#else // !MODE_DEPTH_ORSHADOW\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef MODE_SHOWDEPTH\n"
+"#ifdef VERTEX_SHADER\n"
+"void main\n"
+"(\n"
+"float4 gl_Vertex : POSITION,\n"
+"uniform float4x4 ModelViewProjectionMatrix,\n"
+"out float4 gl_Position : POSITION,\n"
+"out float4 gl_FrontColor : COLOR0\n"
+")\n"
+"{\n"
+"      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
+"      gl_FrontColor = float4(gl_Position.z, gl_Position.z, gl_Position.z, 1.0);\n"
+"}\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"void main\n"
+"(\n"
+"float4 gl_FrontColor : COLOR0,\n"
+"out float4 gl_FragColor : COLOR\n"
+")\n"
+"{\n"
+"      gl_FragColor = gl_FrontColor;\n"
+"}\n"
+"#endif\n"
+"#else // !MODE_SHOWDEPTH\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef MODE_POSTPROCESS\n"
+"\n"
+"#ifdef VERTEX_SHADER\n"
+"void main\n"
+"(\n"
+"float4 gl_Vertex : POSITION,\n"
+"uniform float4x4 ModelViewProjectionMatrix,\n"
+"float4 gl_MultiTexCoord0 : TEXCOORD0,\n"
+"float4 gl_MultiTexCoord1 : TEXCOORD1,\n"
+"out float4 gl_Position : POSITION,\n"
+"out float2 TexCoord1 : TEXCOORD0,\n"
+"out float2 TexCoord2 : TEXCOORD1\n"
+")\n"
+"{\n"
+"      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
+"      TexCoord1 = gl_MultiTexCoord0.xy;\n"
+"#ifdef USEBLOOM\n"
+"      TexCoord2 = gl_MultiTexCoord1.xy;\n"
+"#endif\n"
+"}\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"void main\n"
+"(\n"
+"float2 TexCoord1 : TEXCOORD0,\n"
+"float2 TexCoord2 : TEXCOORD1,\n"
+"uniform sampler2D Texture_First,\n"
+"#ifdef USEBLOOM\n"
+"uniform sampler2D Texture_Second,\n"
+"#endif\n"
+"#ifdef USEGAMMARAMPS\n"
+"uniform sampler2D Texture_GammaRamps,\n"
+"#endif\n"
+"#ifdef USESATURATION\n"
+"uniform float Saturation,\n"
+"#endif\n"
+"#ifdef USEVIEWTINT\n"
+"uniform float4 ViewTintColor,\n"
+"#endif\n"
+"uniform float4 UserVec1,\n"
+"uniform float4 UserVec2,\n"
+"uniform float4 UserVec3,\n"
+"uniform float4 UserVec4,\n"
+"uniform float ClientTime,\n"
+"uniform float2 PixelSize,\n"
+"out float4 gl_FragColor : COLOR\n"
+")\n"
+"{\n"
+"      gl_FragColor = tex2D(Texture_First, TexCoord1);\n"
+"#ifdef USEBLOOM\n"
+"      gl_FragColor += tex2D(Texture_Second, TexCoord2);\n"
+"#endif\n"
+"#ifdef USEVIEWTINT\n"
+"      gl_FragColor = lerp(gl_FragColor, ViewTintColor, ViewTintColor.a);\n"
+"#endif\n"
+"\n"
+"#ifdef USEPOSTPROCESSING\n"
+"// do r_glsl_dumpshader, edit glsl/default.glsl, and replace this by your own postprocessing if you want\n"
+"// this code does a blur with the radius specified in the first component of r_glsl_postprocess_uservec1 and blends it using the second component\n"
+"      gl_FragColor += tex2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*float2(-0.987688, -0.156434)) * UserVec1.y;\n"
+"      gl_FragColor += tex2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*float2(-0.156434, -0.891007)) * UserVec1.y;\n"
+"      gl_FragColor += tex2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*float2( 0.891007, -0.453990)) * UserVec1.y;\n"
+"      gl_FragColor += tex2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*float2( 0.707107,  0.707107)) * UserVec1.y;\n"
+"      gl_FragColor += tex2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*float2(-0.453990,  0.891007)) * UserVec1.y;\n"
+"      gl_FragColor /= (1 + 5 * UserVec1.y);\n"
+"#endif\n"
+"\n"
+"#ifdef USESATURATION\n"
+"      //apply saturation BEFORE gamma ramps, so v_glslgamma value does not matter\n"
+"      float y = dot(gl_FragColor.rgb, float3(0.299, 0.587, 0.114));\n"
+"      //gl_FragColor = float3(y) + (gl_FragColor.rgb - float3(y)) * Saturation;\n"
+"      gl_FragColor.rgb = lerp(float3(y), gl_FragColor.rgb, Saturation);\n"
+"#endif\n"
+"\n"
+"#ifdef USEGAMMARAMPS\n"
+"      gl_FragColor.r = tex2D(Texture_GammaRamps, float2(gl_FragColor.r, 0)).r;\n"
+"      gl_FragColor.g = tex2D(Texture_GammaRamps, float2(gl_FragColor.g, 0)).g;\n"
+"      gl_FragColor.b = tex2D(Texture_GammaRamps, float2(gl_FragColor.b, 0)).b;\n"
+"#endif\n"
+"}\n"
+"#endif\n"
+"#else // !MODE_POSTPROCESS\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef MODE_GENERIC\n"
+"#ifdef VERTEX_SHADER\n"
+"void main\n"
+"(\n"
+"float4 gl_Vertex : POSITION,\n"
+"uniform float4x4 ModelViewProjectionMatrix,\n"
+"float4 gl_Color : COLOR0,\n"
+"float4 gl_MultiTexCoord0 : TEXCOORD0,\n"
+"float4 gl_MultiTexCoord1 : TEXCOORD1,\n"
+"out float4 gl_Position : POSITION,\n"
+"out float4 gl_FrontColor : COLOR,\n"
+"out float2 TexCoord1 : TEXCOORD0,\n"
+"out float2 TexCoord2 : TEXCOORD1\n"
+")\n"
+"{\n"
+"      gl_FrontColor = gl_Color;\n"
+"#ifdef USEDIFFUSE\n"
+"      TexCoord1 = gl_MultiTexCoord0.xy;\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
+"      TexCoord2 = gl_MultiTexCoord1.xy;\n"
+"#endif\n"
+"      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
+"}\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"\n"
+"void main\n"
+"(\n"
+"float4 gl_FrontColor : COLOR,\n"
+"float2 TexCoord1 : TEXCOORD0,\n"
+"float2 TexCoord2 : TEXCOORD1,\n"
+"#ifdef USEDIFFUSE\n"
+"uniform sampler2D Texture_First,\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
+"uniform sampler2D Texture_Second,\n"
+"#endif\n"
+"out float4 gl_FragColor : COLOR\n"
+")\n"
+"{\n"
+"      gl_FragColor = gl_FrontColor;\n"
+"#ifdef USEDIFFUSE\n"
+"      gl_FragColor *= tex2D(Texture_First, TexCoord1);\n"
+"#endif\n"
+"\n"
+"#ifdef USESPECULAR\n"
+"      float4 tex2 = tex2D(Texture_Second, TexCoord2);\n"
+"# ifdef USECOLORMAPPING\n"
+"      gl_FragColor *= tex2;\n"
+"# endif\n"
+"# ifdef USEGLOW\n"
+"      gl_FragColor += tex2;\n"
+"# endif\n"
+"# ifdef USEVERTEXTEXTUREBLEND\n"
+"      gl_FragColor = lerp(gl_FragColor, tex2, tex2.a);\n"
+"# endif\n"
+"#endif\n"
+"}\n"
+"#endif\n"
+"#else // !MODE_GENERIC\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef MODE_BLOOMBLUR\n"
+"#ifdef VERTEX_SHADER\n"
+"void main\n"
+"(\n"
+"float4 gl_Vertex : POSITION,\n"
+"uniform float4x4 ModelViewProjectionMatrix,\n"
+"float4 gl_MultiTexCoord0 : TEXCOORD0,\n"
+"out float4 gl_Position : POSITION,\n"
+"out float2 TexCoord : TEXCOORD0\n"
+")\n"
+"{\n"
+"      TexCoord = gl_MultiTexCoord0.xy;\n"
+"      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
+"}\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"\n"
+"void main\n"
+"(\n"
+"float2 TexCoord : TEXCOORD0,\n"
+"uniform sampler2D Texture_First,\n"
+"uniform float4 BloomBlur_Parameters,\n"
+"out float4 gl_FragColor : COLOR\n"
+")\n"
+"{\n"
+"      int i;\n"
+"      float2 tc = TexCoord;\n"
+"      float3 color = tex2D(Texture_First, tc).rgb;\n"
+"      tc += BloomBlur_Parameters.xy;\n"
+"      for (i = 1;i < SAMPLES;i++)\n"
+"      {\n"
+"              color += tex2D(Texture_First, tc).rgb;\n"
+"              tc += BloomBlur_Parameters.xy;\n"
+"      }\n"
+"      gl_FragColor = float4(color * BloomBlur_Parameters.z + float3(BloomBlur_Parameters.w), 1);\n"
+"}\n"
+"#endif\n"
+"#else // !MODE_BLOOMBLUR\n"
+"#ifdef MODE_REFRACTION\n"
+"#ifdef VERTEX_SHADER\n"
+"void main\n"
+"(\n"
+"float4 gl_Vertex : POSITION,\n"
+"uniform float4x4 ModelViewProjectionMatrix,\n"
+"float4 gl_MultiTexCoord0 : TEXCOORD0,\n"
+"uniform float4x4 TexMatrix,\n"
+"uniform float3 EyePosition,\n"
+"out float4 gl_Position : POSITION,\n"
+"out float2 TexCoord : TEXCOORD0,\n"
+"out float3 EyeVector : TEXCOORD1,\n"
+"out float4 ModelViewProjectionPosition : TEXCOORD2\n"
+")\n"
+"{\n"
+"      TexCoord = float2(mul(TexMatrix, gl_MultiTexCoord0));\n"
+"      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
+"      ModelViewProjectionPosition = gl_Position;\n"
+"}\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"void main\n"
+"(\n"
+"float2 TexCoord : TEXCOORD0,\n"
+"float3 EyeVector : TEXCOORD1,\n"
+"float4 ModelViewProjectionPosition : TEXCOORD2,\n"
+"uniform sampler2D Texture_Normal,\n"
+"uniform sampler2D Texture_Refraction,\n"
+"uniform sampler2D Texture_Reflection,\n"
+"uniform float4 DistortScaleRefractReflect,\n"
+"uniform float4 ScreenScaleRefractReflect,\n"
+"uniform float4 ScreenCenterRefractReflect,\n"
+"uniform float4 RefractColor,\n"
+"out float4 gl_FragColor : COLOR\n"
+")\n"
+"{\n"
+"      float2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n"
+"      //float2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(float3(tex2D(Texture_Normal, TexCoord)) - float3(0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
+"      float2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
+"      float2 ScreenTexCoord = SafeScreenTexCoord + float2(normalize(float3(tex2D(Texture_Normal, TexCoord)) - float3(0.5))).xy * DistortScaleRefractReflect.xy;\n"
+"      // FIXME temporary hack to detect the case that the reflection\n"
+"      // gets blackened at edges due to leaving the area that contains actual\n"
+"      // content.\n"
+"      // Remove this 'ack once we have a better way to stop this thing from\n"
+"      // 'appening.\n"
+"      float f = min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord + float2(0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord + float2(0.01, -0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord + float2(-0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord + float2(-0.01, -0.01)).rgb) / 0.05);\n"
+"      ScreenTexCoord = lerp(SafeScreenTexCoord, ScreenTexCoord, f);\n"
+"      gl_FragColor = tex2D(Texture_Refraction, ScreenTexCoord) * RefractColor;\n"
+"}\n"
+"#endif\n"
+"#else // !MODE_REFRACTION\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef MODE_WATER\n"
+"#ifdef VERTEX_SHADER\n"
+"\n"
+"void main\n"
+"(\n"
+"float4 gl_Vertex : POSITION,\n"
+"uniform float4x4 ModelViewProjectionMatrix,\n"
+"float4 gl_MultiTexCoord0 : TEXCOORD0,\n"
+"uniform float4x4 TexMatrix,\n"
+"uniform float3 EyePosition,\n"
+"out float4 gl_Position : POSITION,\n"
+"out float2 TexCoord : TEXCOORD0,\n"
+"out float3 EyeVector : TEXCOORD1,\n"
+"out float4 ModelViewProjectionPosition : TEXCOORD2\n"
+")\n"
+"{\n"
+"      TexCoord = float2(mul(TexMatrix, gl_MultiTexCoord0));\n"
+"      float3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
+"      EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
+"      EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
+"      EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
+"      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
+"      ModelViewProjectionPosition = gl_Position;\n"
+"}\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"void main\n"
+"(\n"
+"float2 TexCoord : TEXCOORD0,\n"
+"float3 EyeVector : TEXCOORD1,\n"
+"float4 ModelViewProjectionPosition : TEXCOORD2,\n"
+"uniform sampler2D Texture_Normal,\n"
+"uniform sampler2D Texture_Refraction,\n"
+"uniform sampler2D Texture_Reflection,\n"
+"uniform float4 DistortScaleRefractReflect,\n"
+"uniform float4 ScreenScaleRefractReflect,\n"
+"uniform float4 ScreenCenterRefractReflect,\n"
+"uniform float4 RefractColor,\n"
+"uniform float4 ReflectColor,\n"
+"uniform float ReflectFactor,\n"
+"uniform float ReflectOffset,\n"
+"out float4 gl_FragColor : COLOR\n"
+")\n"
+"{\n"
+"      float4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
+"      //float4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(float3(tex2D(Texture_Normal, TexCoord)) - float3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
+"      float4 SafeScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
+"      float4 ScreenTexCoord = SafeScreenTexCoord + float2(normalize(float3(tex2D(Texture_Normal, TexCoord)) - float3(0.5))).xyxy * DistortScaleRefractReflect;\n"
+"      // FIXME temporary hack to detect the case that the reflection\n"
+"      // gets blackened at edges due to leaving the area that contains actual\n"
+"      // content.\n"
+"      // Remove this 'ack once we have a better way to stop this thing from\n"
+"      // 'appening.\n"
+"      float f = min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord.xy + float2(0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord.xy + float2(0.01, -0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord.xy + float2(-0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord.xy + float2(-0.01, -0.01)).rgb) / 0.05);\n"
+"      ScreenTexCoord.xy = lerp(SafeScreenTexCoord.xy, ScreenTexCoord.xy, f);\n"
+"      f       = min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord.zw + float2(0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord.zw + float2(0.01, -0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord.zw + float2(-0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord.zw + float2(-0.01, -0.01)).rgb) / 0.05);\n"
+"      ScreenTexCoord.zw = lerp(SafeScreenTexCoord.zw, ScreenTexCoord.zw, f);\n"
+"      float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * ReflectFactor + ReflectOffset;\n"
+"      gl_FragColor = lerp(tex2D(Texture_Refraction, ScreenTexCoord.xy) * RefractColor, tex2D(Texture_Reflection, ScreenTexCoord.zw) * ReflectColor, Fresnel);\n"
+"}\n"
+"#endif\n"
+"#else // !MODE_WATER\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3), this would require sending a 4 component texcoord1 with W as 1 or -1 according to which side the texcoord2 should be on\n"
+"\n"
+"// fragment shader specific:\n"
+"#ifdef FRAGMENT_SHADER\n"
+"\n"
+"#ifdef USEFOG\n"
+"float FogVertex(float3 EyeVectorModelSpace, float FogPlaneVertexDist, float FogRangeRecip, float FogPlaneViewDist, float FogHeightFade, sampler2D Texture_FogMask)\n"
+"{\n"
+"      float fogfrac;\n"
+"#ifdef USEFOGOUTSIDE\n"
+"      fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0, min(0.0, FogPlaneVertexDist) * FogHeightFade);\n"
+"#else\n"
+"      fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist)) * min(1.0, (min(0.0, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);\n"
+"#endif\n"
+"      return float(tex2D(Texture_FogMask, half2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)));\n"
+"}\n"
+"#endif\n"
+"\n"
+"#ifdef USEOFFSETMAPPING\n"
+"float2 OffsetMapping(float2 TexCoord, float OffsetMapping_Scale, float3 EyeVector, sampler2D Texture_Normal)\n"
+"{\n"
+"#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n"
+"      // 14 sample relief mapping: linear search and then binary search\n"
+"      // this basically steps forward a small amount repeatedly until it finds\n"
+"      // itself inside solid, then jitters forward and back using decreasing\n"
+"      // amounts to find the impact\n"
+"      //float3 OffsetVector = float3(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * float2(-1, 1), -1);\n"
+"      //float3 OffsetVector = float3(normalize(EyeVector.xy) * OffsetMapping_Scale * float2(-1, 1), -1);\n"
+"      float3 OffsetVector = float3(normalize(EyeVector).xy * OffsetMapping_Scale * float2(-1, 1), -1);\n"
+"      float3 RT = float3(TexCoord, 1);\n"
+"      OffsetVector *= 0.1;\n"
+"      RT += OffsetVector *  step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
+"      RT += OffsetVector *  step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
+"      RT += OffsetVector *  step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
+"      RT += OffsetVector *  step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
+"      RT += OffsetVector *  step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
+"      RT += OffsetVector *  step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
+"      RT += OffsetVector *  step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
+"      RT += OffsetVector *  step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
+"      RT += OffsetVector *  step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
+"      RT += OffsetVector * (step(tex2D(Texture_Normal, RT.xy).a, RT.z)          - 0.5);\n"
+"      RT += OffsetVector * (step(tex2D(Texture_Normal, RT.xy).a, RT.z) * 0.5    - 0.25);\n"
+"      RT += OffsetVector * (step(tex2D(Texture_Normal, RT.xy).a, RT.z) * 0.25   - 0.125);\n"
+"      RT += OffsetVector * (step(tex2D(Texture_Normal, RT.xy).a, RT.z) * 0.125  - 0.0625);\n"
+"      RT += OffsetVector * (step(tex2D(Texture_Normal, RT.xy).a, RT.z) * 0.0625 - 0.03125);\n"
+"      return RT.xy;\n"
+"#else\n"
+"      // 3 sample offset mapping (only 3 samples because of ATI Radeon 9500-9800/X300 limits)\n"
+"      // this basically moves forward the full distance, and then backs up based\n"
+"      // on height of samples\n"
+"      //float2 OffsetVector = float2(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * float2(-1, 1));\n"
+"      //float2 OffsetVector = float2(normalize(EyeVector.xy) * OffsetMapping_Scale * float2(-1, 1));\n"
+"      float2 OffsetVector = float2(normalize(EyeVector).xy * OffsetMapping_Scale * float2(-1, 1));\n"
+"      TexCoord += OffsetVector;\n"
+"      OffsetVector *= 0.333;\n"
+"      TexCoord -= OffsetVector * tex2D(Texture_Normal, TexCoord).a;\n"
+"      TexCoord -= OffsetVector * tex2D(Texture_Normal, TexCoord).a;\n"
+"      TexCoord -= OffsetVector * tex2D(Texture_Normal, TexCoord).a;\n"
+"      return TexCoord;\n"
+"#endif\n"
+"}\n"
+"#endif // USEOFFSETMAPPING\n"
+"\n"
+"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE) || defined(USESHADOWMAPORTHO)\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
+"# ifdef USESHADOWMAPORTHO\n"
+"#  define GetShadowMapTC2D(dir, ShadowMap_Parameters) (min(dir, ShadowMap_Parameters.xyz))\n"
+"# else\n"
+"#  ifdef USESHADOWMAPVSDCT\n"
+"float3 GetShadowMapTC2D(float3 dir, float4 ShadowMap_Parameters, samplerCUBE Texture_CubeProjection)\n"
+"{\n"
+"      float3 adir = abs(dir);\n"
+"      float2 aparams = ShadowMap_Parameters.xy / max(max(adir.x, adir.y), adir.z);\n"
+"      float4 proj = texCUBEe(Texture_CubeProjection, dir);\n"
+"      return float3(mix(dir.xy, dir.zz, proj.xy) * aparams.x + proj.zw * ShadowMap_Parameters.z, aparams.y + ShadowMap_Parameters.w);\n"
+"}\n"
+"#  else\n"
+"float3 GetShadowMapTC2D(float3 dir, float4 ShadowMap_Parameters)\n"
+"{\n"
+"      float3 adir = abs(dir);\n"
+"      float ma = adir.z;\n"
+"      float4 proj = float4(dir, 2.5);\n"
+"      if (adir.x > ma) { ma = adir.x; proj = float4(dir.zyx, 0.5); }\n"
+"      if (adir.y > ma) { ma = adir.y; proj = float4(dir.xzy, 1.5); }\n"
+"      float2 aparams = ShadowMap_Parameters.xy / ma;\n"
+"      return float3(proj.xy * aparams.x + float2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.z, aparams.y + ShadowMap_Parameters.w);\n"
+"}\n"
+"#  endif\n"
+"# endif\n"
+"#endif // defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D) || defined(USESHADOWMAPORTHO)\n"
+"\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"float4 GetShadowMapTCCube(float3 dir, float4 ShadowMap_Parameters)\n"
+"{\n"
+"    float3 adir = abs(dir);\n"
+"    return float4(dir, ShadowMap_Parameters.z + ShadowMap_Parameters.w / max(max(adir.x, adir.y), adir.z));\n"
+"}\n"
+"#endif\n"
+"\n"
+"# ifdef USESHADOWMAPRECT\n"
+"#ifdef USESHADOWMAPVSDCT\n"
+"float ShadowMapCompare(float3 dir, samplerRECT Texture_ShadowMapRect, float4 ShadowMap_Parameters, samplerCUBE Texture_CubeProjection)\n"
+"#else\n"
+"float ShadowMapCompare(float3 dir, samplerRECT Texture_ShadowMapRect, float4 ShadowMap_Parameters)\n"
+"#endif\n"
+"{\n"
+"#ifdef USESHADOWMAPVSDCT\n"
+"      float3 shadowmaptc = GetShadowMapTC2D(dir, ShadowMap_Parameters, Texture_CubeProjection);\n"
+"#else\n"
+"      float3 shadowmaptc = GetShadowMapTC2D(dir, ShadowMap_Parameters);\n"
+"#endif\n"
+"      float f;\n"
 "#  ifdef USESHADOWSAMPLER\n"
-"    gl_FragColor = shadowCube(Texture_ShadowMapCube, GetShadowMapTCCube(CubeVector));\n"
+"\n"
+"#    ifdef USESHADOWMAPPCF\n"
+"#      define texval(x, y) shadow2DRect(Texture_ShadowMapRect, shadowmaptc + float3(x, y, 0.0)).r\n"
+"    f = dot(float4(0.25), float4(texval(-0.4, 1.0), texval(-1.0, -0.4), texval(0.4, -1.0), texval(1.0, 0.4)));\n"
+"#    else\n"
+"    f = shadow2DRect(Texture_ShadowMapRect, shadowmaptc).r;\n"
+"#    endif\n"
+"\n"
+"#  else\n"
+"\n"
+"#    ifdef USESHADOWMAPPCF\n"
+"#      if USESHADOWMAPPCF > 1\n"
+"#        define texval(x, y) texRECT(Texture_ShadowMapRect, center + float2(x, y)).r\n"
+"    float2 center = shadowmaptc.xy - 0.5, offset = frac(center);\n"
+"    float4 row1 = step(shadowmaptc.z, float4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n"
+"    float4 row2 = step(shadowmaptc.z, float4(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0), texval( 2.0,  0.0)));\n"
+"    float4 row3 = step(shadowmaptc.z, float4(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0), texval( 2.0,  1.0)));\n"
+"    float4 row4 = step(shadowmaptc.z, float4(texval(-1.0,  2.0), texval( 0.0,  2.0), texval( 1.0,  2.0), texval( 2.0,  2.0)));\n"
+"    float4 cols = row2 + row3 + lerp(row1, row4, offset.y);\n"
+"    f = dot(lerp(cols.xyz, cols.yzw, offset.x), float3(1.0/9.0));\n"
+"#      else\n"
+"#        define texval(x, y) texRECT(Texture_ShadowMapRect, shadowmaptc.xy + float2(x, y)).r\n"
+"    float2 offset = frac(shadowmaptc.xy);\n"
+"    float3 row1 = step(shadowmaptc.z, float3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n"
+"    float3 row2 = step(shadowmaptc.z, float3(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0)));\n"
+"    float3 row3 = step(shadowmaptc.z, float3(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0)));\n"
+"    float3 cols = row2 + lerp(row1, row3, offset.y);\n"
+"    f = dot(lerp(cols.xy, cols.yz, offset.x), float2(0.25));\n"
+"#      endif\n"
+"#    else\n"
+"    f = step(shadowmaptc.z, texRECT(Texture_ShadowMapRect, shadowmaptc.xy).r);\n"
+"#    endif\n"
+"\n"
+"#  endif\n"
+"#  ifdef USESHADOWMAPORTHO\n"
+"      return lerp(ShadowMap_Parameters.w, 1.0, f);\n"
 "#  else\n"
-"    gl_FragColor = textureCube(Texture_ShadowMapCube, GetShadowMapTCCube(CubeVector).xyz);\n"
+"      return f;\n"
 "#  endif\n"
+"}\n"
 "# endif\n"
+"\n"
+"# ifdef USESHADOWMAP2D\n"
+"#ifdef USESHADOWMAPVSDCT\n"
+"float ShadowMapCompare(float3 dir, sampler2D Texture_ShadowMap2D, float4 ShadowMap_Parameters, float2 ShadowMap_TextureScale, samplerCUBE Texture_CubeProjection)\n"
+"#else\n"
+"float ShadowMapCompare(float3 dir, sampler2D Texture_ShadowMap2D, float4 ShadowMap_Parameters, float2 ShadowMap_TextureScale)\n"
+"#endif\n"
+"{\n"
+"#ifdef USESHADOWMAPVSDCT\n"
+"      float3 shadowmaptc = GetShadowMapTC2D(dir, ShadowMap_Parameters, Texture_CubeProjection);\n"
+"#else\n"
+"      float3 shadowmaptc = GetShadowMapTC2D(dir, ShadowMap_Parameters);\n"
+"#endif\n"
+"    float f;\n"
+"\n"
+"#  ifdef USESHADOWSAMPLER\n"
+"#    ifdef USESHADOWMAPPCF\n"
+"#      define texval(x, y) shadow2D(Texture_ShadowMap2D, float3(center + float2(x, y)*ShadowMap_TextureScale, shadowmaptc.z)).r  \n"
+"    float2 center = shadowmaptc.xy*ShadowMap_TextureScale;\n"
+"    f = dot(float4(0.25), float4(texval(-0.4, 1.0), texval(-1.0, -0.4), texval(0.4, -1.0), texval(1.0, 0.4)));\n"
+"#    else\n"
+"    f = shadow2D(Texture_ShadowMap2D, float3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z)).r;\n"
+"#    endif\n"
+"#  else\n"
+"#    ifdef USESHADOWMAPPCF\n"
+"#     if defined(GL_ARB_texture_gather) || defined(GL_AMD_texture_texture4)\n"
+"#      ifdef GL_ARB_texture_gather\n"
+"#        define texval(x, y) textureGatherOffset(Texture_ShadowMap2D, center, ivec(x, y))\n"
+"#      else\n"
+"#        define texval(x, y) texture4(Texture_ShadowMap2D, center + float2(x,y)*ShadowMap_TextureScale)\n"
+"#      endif\n"
+"    float2 center = shadowmaptc.xy - 0.5, offset = frac(center);\n"
+"    center *= ShadowMap_TextureScale;\n"
+"    float4 group1 = step(shadowmaptc.z, texval(-1.0, -1.0));\n"
+"    float4 group2 = step(shadowmaptc.z, texval( 1.0, -1.0));\n"
+"    float4 group3 = step(shadowmaptc.z, texval(-1.0,  1.0));\n"
+"    float4 group4 = step(shadowmaptc.z, texval( 1.0,  1.0));\n"
+"    float4 cols = float4(group1.rg, group2.rg) + float4(group3.ab, group4.ab) +\n"
+"                lerp(float4(group1.ab, group2.ab), float4(group3.rg, group4.rg), offset.y);\n"
+"    f = dot(lerp(cols.xyz, cols.yzw, offset.x), float3(1.0/9.0));\n"
+"#     else\n"
+"#        define texval(x, y) texDepth2D(Texture_ShadowMap2D, center + float2(x, y)*ShadowMap_TextureScale)  \n"
+"#      if USESHADOWMAPPCF > 1\n"
+"    float2 center = shadowmaptc.xy - 0.5, offset = frac(center);\n"
+"    center *= ShadowMap_TextureScale;\n"
+"    float4 row1 = step(shadowmaptc.z, float4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n"
+"    float4 row2 = step(shadowmaptc.z, float4(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0), texval( 2.0,  0.0)));\n"
+"    float4 row3 = step(shadowmaptc.z, float4(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0), texval( 2.0,  1.0)));\n"
+"    float4 row4 = step(shadowmaptc.z, float4(texval(-1.0,  2.0), texval( 0.0,  2.0), texval( 1.0,  2.0), texval( 2.0,  2.0)));\n"
+"    float4 cols = row2 + row3 + lerp(row1, row4, offset.y);\n"
+"    f = dot(lerp(cols.xyz, cols.yzw, offset.x), float3(1.0/9.0));\n"
+"#      else\n"
+"    float2 center = shadowmaptc.xy*ShadowMap_TextureScale, offset = frac(shadowmaptc.xy);\n"
+"    float3 row1 = step(shadowmaptc.z, float3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n"
+"    float3 row2 = step(shadowmaptc.z, float3(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0)));\n"
+"    float3 row3 = step(shadowmaptc.z, float3(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0)));\n"
+"    float3 cols = row2 + lerp(row1, row3, offset.y);\n"
+"    f = dot(lerp(cols.xy, cols.yz, offset.x), float2(0.25));\n"
+"#      endif\n"
+"#     endif\n"
+"#    else\n"
+"    f = step(shadowmaptc.z, tex2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale).r);\n"
+"#    endif\n"
+"#  endif\n"
+"#  ifdef USESHADOWMAPORTHO\n"
+"      return lerp(ShadowMap_Parameters.w, 1.0, f);\n"
+"#  else\n"
+"      return f;\n"
+"#  endif\n"
+"}\n"
+"# endif\n"
+"\n"
+"# ifdef USESHADOWMAPCUBE\n"
+"float ShadowMapCompare(float3 dir, samplerCUBE Texture_ShadowMapCube, float4 ShadowMap_Parameters)\n"
+"{\n"
+"    // apply depth texture cubemap as light filter\n"
+"    float4 shadowmaptc = GetShadowMapTCCube(dir, ShadowMap_Parameters);\n"
+"    float f;\n"
+"#  ifdef USESHADOWSAMPLER\n"
+"    f = shadowCube(Texture_ShadowMapCube, shadowmaptc).r;\n"
+"#  else\n"
+"    f = step(shadowmaptc.w, texCUBE(Texture_ShadowMapCube, shadowmaptc.xyz).r);\n"
+"#  endif\n"
+"    return f;\n"
+"}\n"
+"# endif\n"
+"#endif // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE)\n"
+"#endif // FRAGMENT_SHADER\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef MODE_DEFERREDGEOMETRY\n"
+"#ifdef VERTEX_SHADER\n"
+"void main\n"
+"(\n"
+"float4 gl_Vertex : POSITION,\n"
+"uniform float4x4 ModelViewProjectionMatrix,\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"float4 gl_Color : COLOR0,\n"
+"#endif\n"
+"float4 gl_MultiTexCoord0 : TEXCOORD0,\n"
+"float4 gl_MultiTexCoord1 : TEXCOORD1,\n"
+"float4 gl_MultiTexCoord2 : TEXCOORD2,\n"
+"float4 gl_MultiTexCoord3 : TEXCOORD3,\n"
+"uniform float4x4 TexMatrix,\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"uniform float4x4 BackgroundTexMatrix,\n"
+"#endif\n"
+"uniform float4x4 ModelViewMatrix,\n"
+"#ifdef USEOFFSETMAPPING\n"
+"uniform float3 EyePosition,\n"
+"#endif\n"
+"out float4 gl_Position : POSITION,\n"
+"out float4 gl_FrontColor : COLOR,\n"
+"out float4 TexCoordBoth : TEXCOORD0,\n"
+"#ifdef USEOFFSETMAPPING\n"
+"out float3 EyeVector : TEXCOORD2,\n"
+"#endif\n"
+"out float3 VectorS : TEXCOORD5, // direction of S texcoord (sometimes crudely called tangent)\n"
+"out float3 VectorT : TEXCOORD6, // direction of T texcoord (sometimes crudely called binormal)\n"
+"out float3 VectorR : TEXCOORD7 // direction of R texcoord (surface normal)\n"
+")\n"
+"{\n"
+"      TexCoordBoth = mul(TexMatrix, gl_MultiTexCoord0);\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"      gl_FrontColor = gl_Color;\n"
+"      TexCoordBoth.zw = float2(Backgroundmul(TexMatrix, gl_MultiTexCoord0));\n"
+"#endif\n"
+"\n"
+"      // transform unnormalized eye direction into tangent space\n"
+"#ifdef USEOFFSETMAPPING\n"
+"      float3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
+"      EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
+"      EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
+"      EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
+"#endif\n"
+"\n"
+"      VectorS = mul(ModelViewMatrix, float4(gl_MultiTexCoord1.xyz, 0)).xyz;\n"
+"      VectorT = mul(ModelViewMatrix, float4(gl_MultiTexCoord2.xyz, 0)).xyz;\n"
+"      VectorR = mul(ModelViewMatrix, float4(gl_MultiTexCoord3.xyz, 0)).xyz;\n"
+"      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
+"}\n"
+"#endif // VERTEX_SHADER\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"void main\n"
+"(\n"
+"float4 TexCoordBoth : TEXCOORD0,\n"
+"float3 EyeVector : TEXCOORD2,\n"
+"float3 VectorS : TEXCOORD5, // direction of S texcoord (sometimes crudely called tangent)\n"
+"float3 VectorT : TEXCOORD6, // direction of T texcoord (sometimes crudely called binormal)\n"
+"float3 VectorR : TEXCOORD7, // direction of R texcoord (surface normal)\n"
+"uniform sampler2D Texture_Normal,\n"
+"#ifdef USEALPHAKILL\n"
+"uniform sampler2D Texture_Color,\n"
+"#endif\n"
+"uniform sampler2D Texture_Gloss,\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"uniform sampler2D Texture_SecondaryNormal,\n"
+"uniform sampler2D Texture_SecondaryGloss,\n"
+"#endif\n"
+"#ifdef USEOFFSETMAPPING\n"
+"uniform float OffsetMapping_Scale,\n"
+"#endif\n"
+"uniform half SpecularPower,\n"
+"out float4 gl_FragColor : COLOR\n"
+")\n"
+"{\n"
+"      float2 TexCoord = TexCoordBoth.xy;\n"
+"#ifdef USEOFFSETMAPPING\n"
+"      // apply offsetmapping\n"
+"      float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_Scale, EyeVector, Texture_Normal);\n"
+"#define TexCoord TexCoordOffset\n"
+"#endif\n"
+"\n"
+"#ifdef USEALPHAKILL\n"
+"      if (tex2D(Texture_Color, TexCoord).a < 0.5)\n"
+"              discard;\n"
+"#endif\n"
+"\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"      float alpha = tex2D(Texture_Color, TexCoord).a;\n"
+"      float terrainblend = clamp(float(gl_FrontColor.a) * alpha * 2.0 - 0.5, float(0.0), float(1.0));\n"
+"      //float terrainblend = min(float(gl_FrontColor.a) * alpha * 2.0, float(1.0));\n"
+"      //float terrainblend = float(gl_FrontColor.a) * alpha > 0.5;\n"
+"#endif\n"
+"\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"      float3 surfacenormal = lerp(float3(tex2D(Texture_SecondaryNormal, TexCoord2)), float3(tex2D(Texture_Normal, TexCoord)), terrainblend) - float3(0.5, 0.5, 0.5);\n"
+"      float a = lerp(tex2D(Texture_SecondaryGloss, TexCoord2), tex2D(Texture_Gloss, TexCoord).a, terrainblend);\n"
+"#else\n"
+"      float3 surfacenormal = float3(tex2D(Texture_Normal, TexCoord)) - float3(0.5, 0.5, 0.5);\n"
+"      float a = tex2D(Texture_Gloss, TexCoord).a;\n"
+"#endif\n"
+"\n"
+"      gl_FragColor = float4(normalize(surfacenormal.x * VectorS + surfacenormal.y * VectorT + surfacenormal.z * VectorR) * 0.5 + float3(0.5, 0.5, 0.5), 1);\n"
+"}\n"
+"#endif // FRAGMENT_SHADER\n"
+"#else // !MODE_DEFERREDGEOMETRY\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
+"#ifdef VERTEX_SHADER\n"
+"void main\n"
+"(\n"
+"float4 gl_Vertex : POSITION,\n"
+"uniform float4x4 ModelViewProjectionMatrix,\n"
+"uniform float4x4 ModelViewMatrix,\n"
+"out float4 gl_Position : POSITION,\n"
+"out float4 ModelViewPosition : TEXCOORD0\n"
+")\n"
+"{\n"
+"      ModelViewPosition = mul(ModelViewMatrix, gl_Vertex);\n"
+"      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
+"}\n"
+"#endif // VERTEX_SHADER\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"void main\n"
+"(\n"
+"float2 Pixel : WPOS,\n"
+"float4 ModelViewPosition : TEXCOORD0,\n"
+"uniform float4x4 ViewToLight,\n"
+"uniform float2 ScreenToDepth, // ScreenToDepth = float2(Far / (Far - Near), Far * Near / (Near - Far));\n"
+"uniform float3 LightPosition,\n"
+"uniform half2 PixelToScreenTexCoord,\n"
+"uniform half3 DeferredColor_Ambient,\n"
+"uniform half3 DeferredColor_Diffuse,\n"
+"#ifdef USESPECULAR\n"
+"uniform half3 DeferredColor_Specular,\n"
+"uniform half SpecularPower,\n"
+"#endif\n"
+"uniform sampler2D Texture_Attenuation,\n"
+"uniform sampler2D Texture_ScreenDepth,\n"
+"uniform sampler2D Texture_ScreenNormalMap,\n"
+"\n"
+"#ifdef USESHADOWMAPRECT\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform samplerRECTShadow Texture_ShadowMapRect,\n"
+"# else\n"
+"uniform samplerRECT Texture_ShadowMapRect,\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAP2D\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform sampler2DShadow Texture_ShadowMap2D,\n"
+"# else\n"
+"uniform sampler2D Texture_ShadowMap2D,\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAPVSDCT\n"
+"uniform samplerCUBE Texture_CubeProjection,\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform samplerCUBEShadow Texture_ShadowMapCube,\n"
+"# else\n"
+"uniform samplerCUBE Texture_ShadowMapCube,\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D) || defined(USESHADOWMAPCUBE)\n"
+"uniform float2 ShadowMap_TextureScale,\n"
+"uniform float4 ShadowMap_Parameters,\n"
+"#endif\n"
+"\n"
+"out float4 gl_FragData0 : COLOR0,\n"
+"out float4 gl_FragData1 : COLOR1\n"
+")\n"
+"{\n"
+"      // calculate viewspace pixel position\n"
+"      float2 ScreenTexCoord = Pixel * PixelToScreenTexCoord;\n"
+"      ScreenTexCoord.y = ScreenTexCoord.y * -1 + 1; // Cg is opposite?\n"
+"      float3 position;\n"
+"      position.z = ScreenToDepth.y / (texDepth2D(Texture_ScreenDepth, ScreenTexCoord) + ScreenToDepth.x);\n"
+"      position.xy = ModelViewPosition.xy * (position.z / ModelViewPosition.z);\n"
+"      // decode viewspace pixel normal\n"
+"      half4 normalmap = tex2D(Texture_ScreenNormalMap, ScreenTexCoord);\n"
+"      half3 surfacenormal = normalize(normalmap.rgb - half3(0.5,0.5,0.5));\n"
+"      // surfacenormal = pixel normal in viewspace\n"
+"      // LightVector = pixel to light in viewspace\n"
+"      // CubeVector = position in lightspace\n"
+"      // eyevector = pixel to view in viewspace\n"
+"      float3 CubeVector = float3(mul(ViewToLight, float4(position,1)));\n"
+"      half fade = half(tex2D(Texture_Attenuation, float2(length(CubeVector), 0.0)));\n"
+"#ifdef USEDIFFUSE\n"
+"      // calculate diffuse shading\n"
+"      half3 lightnormal = half3(normalize(LightPosition - position));\n"
+"      half diffuse = half(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
+"      // calculate directional shading\n"
+"      float3 eyevector = position * -1.0;\n"
+"#  ifdef USEEXACTSPECULARMATH\n"
+"      half specular = pow(half(max(float(dot(reflect(lightnormal, surfacenormal), normalize(eyevector)))*-1.0, 0.0)), SpecularPower * normalmap.a);\n"
+"#  else\n"
+"      half3 specularnormal = normalize(lightnormal + half3(normalize(eyevector)));\n"
+"      half specular = pow(half(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * normalmap.a);\n"
+"#  endif\n"
+"#endif\n"
+"\n"
+"#if defined(USESHADOWMAP2D) || defined(USESHADOWMAPRECT) || defined(USESHADOWMAPCUBE)\n"
+"      fade *= ShadowMapCompare(CubeVector,\n"
+"# if defined(USESHADOWMAP2D)\n"
+"Texture_ShadowMap2D, ShadowMap_Parameters, ShadowMap_TextureScale\n"
+"# endif\n"
+"# if defined(USESHADOWMAPRECT)\n"
+"Texture_ShadowMapRect, ShadowMap_Parameters\n"
+"# endif\n"
+"# if defined(USESHADOWMAPCUBE)\n"
+"Texture_ShadowMapCube, ShadowMap_Parameters\n"
+"# endif\n"
+"\n"
+"#ifdef USESHADOWMAPVSDCT\n"
+", Texture_CubeProjection\n"
+"#endif\n"
+"      );\n"
+"#endif\n"
+"\n"
+"#ifdef USEDIFFUSE\n"
+"      gl_FragData0 = float4((DeferredColor_Ambient + DeferredColor_Diffuse * diffuse) * fade, 1.0);\n"
+"#else\n"
+"      gl_FragData0 = float4(DeferredColor_Ambient * fade, 1.0);\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
+"      gl_FragData1 = float4(DeferredColor_Specular * (specular * fade), 1.0);\n"
+"#else\n"
+"      gl_FragData1 = float4(0.0, 0.0, 0.0, 1.0);\n"
+"#endif\n"
+"\n"
+"# ifdef USECUBEFILTER\n"
+"      float3 cubecolor = texCUBE(Texture_Cube, CubeVector).rgb;\n"
+"      gl_FragData0.rgb *= cubecolor;\n"
+"      gl_FragData1.rgb *= cubecolor;\n"
+"# endif\n"
+"}\n"
+"#endif // FRAGMENT_SHADER\n"
+"#else // !MODE_DEFERREDLIGHTSOURCE\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef VERTEX_SHADER\n"
+"void main\n"
+"(\n"
+"float4 gl_Vertex : POSITION,\n"
+"uniform float4x4 ModelViewProjectionMatrix,\n"
+"#if defined(USEVERTEXTEXTUREBLEND) || defined(MODE_VERTEXCOLOR)\n"
+"float4 gl_Color : COLOR0,\n"
+"#endif\n"
+"float4 gl_MultiTexCoord0 : TEXCOORD0,\n"
+"float4 gl_MultiTexCoord1 : TEXCOORD1,\n"
+"float4 gl_MultiTexCoord2 : TEXCOORD2,\n"
+"float4 gl_MultiTexCoord3 : TEXCOORD3,\n"
+"float4 gl_MultiTexCoord4 : TEXCOORD4,\n"
+"\n"
+"uniform float3 EyePosition,\n"
+"uniform float4x4 TexMatrix,\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"uniform float4x4 BackgroundTexMatrix,\n"
+"#endif\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"uniform float4x4 ModelToLight,\n"
+"#endif\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"uniform float3 LightPosition,\n"
+"#endif\n"
+"#ifdef MODE_LIGHTDIRECTION\n"
+"uniform float3 LightDir,\n"
+"#endif\n"
+"uniform float4 FogPlane,\n"
+"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
+"uniform float3 LightPosition,\n"
+"#endif\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"uniform float4x4 ShadowMapMatrix,\n"
+"#endif\n"
+"\n"
+"out float4 gl_FrontColor : COLOR,\n"
+"out float4 TexCoordBoth : TEXCOORD0,\n"
+"#ifdef USELIGHTMAP\n"
+"out float2 TexCoordLightmap : TEXCOORD1,\n"
+"#endif\n"
+"#ifdef USEEYEVECTOR\n"
+"out float3 EyeVector : TEXCOORD2,\n"
+"#endif\n"
+"#ifdef USEREFLECTION\n"
+"out float4 ModelViewProjectionPosition : TEXCOORD3,\n"
+"#endif\n"
+"#ifdef USEFOG\n"
+"out float4 EyeVectorModelSpaceFogPlaneVertexDist : TEXCOORD4,\n"
+"#endif\n"
+"#if defined(MODE_LIGHTSOURCE) || defined(MODE_LIGHTDIRECTION)\n"
+"out float3 LightVector : TEXCOORD5,\n"
+"#endif\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"out float3 CubeVector : TEXCOORD3,\n"
+"#endif\n"
+"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_DEFERREDGEOMETRY) || defined(USEREFLECTCUBE)\n"
+"out float3 VectorS : TEXCOORD5, // direction of S texcoord (sometimes crudely called tangent)\n"
+"out float3 VectorT : TEXCOORD6, // direction of T texcoord (sometimes crudely called binormal)\n"
+"out float3 VectorR : TEXCOORD7, // direction of R texcoord (surface normal)\n"
+"#endif\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"out float3 ShadowMapTC : TEXCOORD8,\n"
+"#endif\n"
+"out float4 gl_Position : POSITION\n"
+")\n"
+"{\n"
+"#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND)\n"
+"      gl_FrontColor = gl_Color;\n"
+"#endif\n"
+"      // copy the surface texcoord\n"
+"      TexCoordBoth = mul(TexMatrix, gl_MultiTexCoord0);\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"      TexCoordBoth.zw = mul(BackgroundTexMatrix, gl_MultiTexCoord0).xy;\n"
+"#endif\n"
+"#ifdef USELIGHTMAP\n"
+"      TexCoordLightmap = float2(gl_MultiTexCoord4);\n"
+"#endif\n"
+"\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"      // transform vertex position into light attenuation/cubemap space\n"
+"      // (-1 to +1 across the light box)\n"
+"      CubeVector = float3(mul(ModelToLight, gl_Vertex));\n"
+"\n"
+"# ifdef USEDIFFUSE\n"
+"      // transform unnormalized light direction into tangent space\n"
+"      // (we use unnormalized to ensure that it interpolates correctly and then\n"
+"      //  normalize it per pixel)\n"
+"      float3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
+"      LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
+"      LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
+"      LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#if defined(MODE_LIGHTDIRECTION) && defined(USEDIFFUSE)\n"
+"      LightVector.x = dot(LightDir, gl_MultiTexCoord1.xyz);\n"
+"      LightVector.y = dot(LightDir, gl_MultiTexCoord2.xyz);\n"
+"      LightVector.z = dot(LightDir, gl_MultiTexCoord3.xyz);\n"
+"#endif\n"
+"\n"
+"      // transform unnormalized eye direction into tangent space\n"
+"#ifdef USEEYEVECTOR\n"
+"      float3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
+"      EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
+"      EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
+"      EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
+"#endif\n"
+"\n"
+"#ifdef USEFOG\n"
+"      EyeVectorModelSpaceFogPlaneVertexDist.xyz = EyePosition - gl_Vertex.xyz;\n"
+"      EyeVectorModelSpaceFogPlaneVertexDist.w = dot(FogPlane, gl_Vertex);\n"
+"#endif\n"
+"\n"
+"#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
+"      VectorS = gl_MultiTexCoord1.xyz;\n"
+"      VectorT = gl_MultiTexCoord2.xyz;\n"
+"      VectorR = gl_MultiTexCoord3.xyz;\n"
+"#endif\n"
+"\n"
+"      // transform vertex to camera space, using ftransform to match non-VS rendering\n"
+"      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
+"\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"      ShadowMapTC = float3(mul(ShadowMapMatrix, gl_Position));\n"
+"#endif\n"
+"\n"
+"#ifdef USEREFLECTION\n"
+"      ModelViewProjectionPosition = gl_Position;\n"
+"#endif\n"
+"}\n"
+"#endif // VERTEX_SHADER\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"void main\n"
+"(\n"
+"#ifdef USEDEFERREDLIGHTMAP\n"
+"float2 Pixel : WPOS,\n"
+"#endif\n"
+"float4 gl_FrontColor : COLOR,\n"
+"float4 TexCoordBoth : TEXCOORD0,\n"
+"#ifdef USELIGHTMAP\n"
+"float2 TexCoordLightmap : TEXCOORD1,\n"
+"#endif\n"
+"#ifdef USEEYEVECTOR\n"
+"float3 EyeVector : TEXCOORD2,\n"
+"#endif\n"
+"#ifdef USEREFLECTION\n"
+"float4 ModelViewProjectionPosition : TEXCOORD3,\n"
+"#endif\n"
+"#ifdef USEFOG\n"
+"float4 EyeVectorModelSpaceFogPlaneVertexDist : TEXCOORD4,\n"
+"#endif\n"
+"#if defined(MODE_LIGHTSOURCE) || defined(MODE_LIGHTDIRECTION)\n"
+"float3 LightVector : TEXCOORD5,\n"
+"#endif\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"float3 CubeVector : TEXCOORD3,\n"
+"#endif\n"
+"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
+"float4 ModelViewPosition : TEXCOORD0,\n"
+"#endif\n"
+"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_DEFERREDGEOMETRY) || defined(USEREFLECTCUBE)\n"
+"float3 VectorS : TEXCOORD5, // direction of S texcoord (sometimes crudely called tangent)\n"
+"float3 VectorT : TEXCOORD6, // direction of T texcoord (sometimes crudely called binormal)\n"
+"float3 VectorR : TEXCOORD7, // direction of R texcoord (surface normal)\n"
+"#endif\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"float3 ShadowMapTC : TEXCOORD8\n"
+"#endif\n"
+"\n"
+"uniform sampler2D Texture_Normal,\n"
+"uniform sampler2D Texture_Color,\n"
+"#if defined(USESPECULAR) || defined(USEDEFERREDLIGHTMAP)\n"
+"uniform sampler2D Texture_Gloss,\n"
+"#endif\n"
+"#ifdef USEGLOW\n"
+"uniform sampler2D Texture_Glow,\n"
+"#endif\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"uniform sampler2D Texture_SecondaryNormal,\n"
+"uniform sampler2D Texture_SecondaryColor,\n"
+"#if defined(USESPECULAR) || defined(USEDEFERREDLIGHTMAP)\n"
+"uniform sampler2D Texture_SecondaryGloss,\n"
+"#endif\n"
+"#ifdef USEGLOW\n"
+"uniform sampler2D Texture_SecondaryGlow,\n"
+"#endif\n"
+"#endif\n"
+"#ifdef USECOLORMAPPING\n"
+"uniform sampler2D Texture_Pants,\n"
+"uniform sampler2D Texture_Shirt,\n"
+"#endif\n"
+"#ifdef USEFOG\n"
+"uniform sampler2D Texture_FogMask,\n"
+"#endif\n"
+"#ifdef USELIGHTMAP\n"
+"uniform sampler2D Texture_Lightmap,\n"
+"#endif\n"
+"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
+"uniform sampler2D Texture_Deluxemap,\n"
+"#endif\n"
+"#ifdef USEREFLECTION\n"
+"uniform sampler2D Texture_Reflection,\n"
+"#endif\n"
+"\n"
+"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
+"uniform sampler2D Texture_ScreenDepth,\n"
+"uniform sampler2D Texture_ScreenNormalMap,\n"
+"#endif\n"
+"#ifdef USEDEFERREDLIGHTMAP\n"
+"uniform sampler2D Texture_ScreenDiffuse,\n"
+"uniform sampler2D Texture_ScreenSpecular,\n"
+"#endif\n"
+"\n"
+"#ifdef USECOLORMAPPING\n"
+"uniform half3 Color_Pants,\n"
+"uniform half3 Color_Shirt,\n"
+"#endif\n"
+"#ifdef USEFOG\n"
+"uniform float3 FogColor,\n"
+"uniform float FogRangeRecip,\n"
+"uniform float FogPlaneViewDist,\n"
+"uniform float FogHeightFade,\n"
+"#endif\n"
+"\n"
+"#ifdef USEOFFSETMAPPING\n"
+"uniform float OffsetMapping_Scale,\n"
+"#endif\n"
+"\n"
+"#ifdef USEDEFERREDLIGHTMAP\n"
+"uniform half2 PixelToScreenTexCoord,\n"
+"uniform half3 DeferredMod_Diffuse,\n"
+"uniform half3 DeferredMod_Specular,\n"
+"#endif\n"
+"uniform half3 Color_Ambient,\n"
+"uniform half3 Color_Diffuse,\n"
+"uniform half3 Color_Specular,\n"
+"uniform half SpecularPower,\n"
+"#ifdef USEGLOW\n"
+"uniform half3 Color_Glow,\n"
+"#endif\n"
+"uniform half Alpha,\n"
+"#ifdef USEREFLECTION\n"
+"uniform float4 DistortScaleRefractReflect,\n"
+"uniform float4 ScreenScaleRefractReflect,\n"
+"uniform float4 ScreenCenterRefractReflect,\n"
+"uniform half4 ReflectColor,\n"
+"#endif\n"
+"#ifdef USEREFLECTCUBE\n"
+"uniform float4x4 ModelToReflectCube,\n"
+"uniform sampler2D Texture_ReflectMask,\n"
+"uniform samplerCUBE Texture_ReflectCube,\n"
+"#endif\n"
+"#ifdef MODE_LIGHTDIRECTION\n"
+"uniform half3 LightColor,\n"
+"#endif\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"uniform half3 LightColor,\n"
+"#endif\n"
+"\n"
+"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE)\n"
+"uniform sampler2D Texture_Attenuation,\n"
+"uniform samplerCUBE Texture_Cube,\n"
+"#endif\n"
+"\n"
+"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE) || defined(USESHADOWMAPORTHO)\n"
+"\n"
+"#ifdef USESHADOWMAPRECT\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform samplerRECTShadow Texture_ShadowMapRect,\n"
+"# else\n"
+"uniform samplerRECT Texture_ShadowMapRect,\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAP2D\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform sampler2DShadow Texture_ShadowMap2D,\n"
+"# else\n"
+"uniform sampler2D Texture_ShadowMap2D,\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAPVSDCT\n"
+"uniform samplerCUBE Texture_CubeProjection,\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform samplerCUBEShadow Texture_ShadowMapCube,\n"
+"# else\n"
+"uniform samplerCUBE Texture_ShadowMapCube,\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D) || defined(USESHADOWMAPCUBE)\n"
+"uniform float2 ShadowMap_TextureScale,\n"
+"uniform float4 ShadowMap_Parameters,\n"
+"#endif\n"
+"#endif // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE) && !defined(USESHADOWMAPORTHO)\n"
+"\n"
+"out float4 gl_FragColor : COLOR\n"
+")\n"
+"{\n"
+"      float2 TexCoord = TexCoordBoth.xy;\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"      float2 TexCoord2 = TexCoordBoth.zw;\n"
+"#endif\n"
+"#ifdef USEOFFSETMAPPING\n"
+"      // apply offsetmapping\n"
+"      float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_Scale, EyeVector, Texture_Normal);\n"
+"#define TexCoord TexCoordOffset\n"
+"#endif\n"
+"\n"
+"      // combine the diffuse textures (base, pants, shirt)\n"
+"      half4 color = half4(tex2D(Texture_Color, TexCoord));\n"
+"#ifdef USEALPHAKILL\n"
+"      if (color.a < 0.5)\n"
+"              discard;\n"
+"#endif\n"
+"      color.a *= Alpha;\n"
+"#ifdef USECOLORMAPPING\n"
+"      color.rgb += half3(tex2D(Texture_Pants, TexCoord)) * Color_Pants + half3(tex2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
+"#endif\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"      float terrainblend = clamp(half(gl_FrontColor.a) * color.a * 2.0 - 0.5, half(0.0), half(1.0));\n"
+"      //half terrainblend = min(half(gl_FrontColor.a) * color.a * 2.0, half(1.0));\n"
+"      //half terrainblend = half(gl_FrontColor.a) * color.a > 0.5;\n"
+"      color.rgb = half3(lerp(float3(tex2D(Texture_SecondaryColor, TexCoord2)), float3(color.rgb), terrainblend));\n"
+"      color.a = 1.0;\n"
+"      //color = lerp(half4(1, 0, 0, 1), color, terrainblend);\n"
+"#endif\n"
+"\n"
+"      // get the surface normal\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"      half3 surfacenormal = normalize(half3(lerp(float3(tex2D(Texture_SecondaryNormal, TexCoord2)), float3(tex2D(Texture_Normal, TexCoord)), terrainblend)) - half3(0.5, 0.5, 0.5));\n"
+"#else\n"
+"      half3 surfacenormal = normalize(half3(tex2D(Texture_Normal, TexCoord)) - half3(0.5, 0.5, 0.5));\n"
+"#endif\n"
+"\n"
+"      // get the material colors\n"
+"      half3 diffusetex = color.rgb;\n"
+"#if defined(USESPECULAR) || defined(USEDEFERREDLIGHTMAP)\n"
+"# ifdef USEVERTEXTEXTUREBLEND\n"
+"      half4 glosstex = half4(lerp(float4(tex2D(Texture_SecondaryGloss, TexCoord2)), float4(tex2D(Texture_Gloss, TexCoord)), terrainblend));\n"
+"# else\n"
+"      half4 glosstex = half4(tex2D(Texture_Gloss, TexCoord));\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USEREFLECTCUBE\n"
+"      vec3 TangentReflectVector = reflect(-EyeVector, surfacenormal);\n"
+"      vec3 ModelReflectVector = TangentReflectVector.x * VectorS + TangentReflectVector.y * VectorT + TangentReflectVector.z * VectorR;\n"
+"      vec3 ReflectCubeTexCoord = float3(mul(ModelToReflectCube, float4(ModelReflectVector, 0)));\n"
+"      diffusetex += half3(tex2D(Texture_ReflectMask, TexCoord)) * half3(texCUBE(Texture_ReflectCube, ReflectCubeTexCoord));\n"
+"#endif\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"      // light source\n"
+"#ifdef USEDIFFUSE\n"
+"      half3 lightnormal = half3(normalize(LightVector));\n"
+"      half diffuse = half(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
+"      color.rgb = diffusetex * (Color_Ambient + diffuse * Color_Diffuse);\n"
+"#ifdef USESPECULAR\n"
+"#ifdef USEEXACTSPECULARMATH\n"
+"      half specular = pow(half(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower * glosstex.a);\n"
+"#else\n"
+"      half3 specularnormal = normalize(lightnormal + half3(normalize(EyeVector)));\n"
+"      half specular = pow(half(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * glosstex.a);\n"
+"#endif\n"
+"      color.rgb += glosstex.rgb * (specular * Color_Specular);\n"
+"#endif\n"
+"#else\n"
+"      color.rgb = diffusetex * Color_Ambient;\n"
+"#endif\n"
+"      color.rgb *= LightColor;\n"
+"      color.rgb *= half(tex2D(Texture_Attenuation, float2(length(CubeVector), 0.0)));\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAPCUBE) || defined(USESHADOWMAP2D)\n"
+"      color.rgb *= ShadowMapCompare(CubeVector,\n"
+"# if defined(USESHADOWMAP2D)\n"
+"Texture_ShadowMap2D, ShadowMap_Parameters, ShadowMap_TextureScale\n"
+"# endif\n"
+"# if defined(USESHADOWMAPRECT)\n"
+"Texture_ShadowMapRect, ShadowMap_Parameters\n"
+"# endif\n"
+"# if defined(USESHADOWMAPCUBE)\n"
+"Texture_ShadowMapCube, ShadowMap_Parameters\n"
+"# endif\n"
+"\n"
+"#ifdef USESHADOWMAPVSDCT\n"
+", Texture_CubeProjection\n"
+"#endif\n"
+"      );\n"
+"\n"
+"#endif\n"
+"# ifdef USECUBEFILTER\n"
+"      color.rgb *= half3(texCUBE(Texture_Cube, CubeVector));\n"
+"# endif\n"
+"#endif // MODE_LIGHTSOURCE\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef MODE_LIGHTDIRECTION\n"
+"#define SHADING\n"
+"#ifdef USEDIFFUSE\n"
+"      half3 lightnormal = half3(normalize(LightVector));\n"
+"#endif\n"
+"#define lightcolor LightColor\n"
+"#endif // MODE_LIGHTDIRECTION\n"
+"#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
+"#define SHADING\n"
+"      // deluxemap lightmapping using light vectors in modelspace (q3map2 -light -deluxe)\n"
+"      half3 lightnormal_modelspace = half3(tex2D(Texture_Deluxemap, TexCoordLightmap)) * 2.0 + half3(-1.0, -1.0, -1.0);\n"
+"      half3 lightcolor = half3(tex2D(Texture_Lightmap, TexCoordLightmap));\n"
+"      // convert modelspace light vector to tangentspace\n"
+"      half3 lightnormal;\n"
+"      lightnormal.x = dot(lightnormal_modelspace, half3(VectorS));\n"
+"      lightnormal.y = dot(lightnormal_modelspace, half3(VectorT));\n"
+"      lightnormal.z = dot(lightnormal_modelspace, half3(VectorR));\n"
+"      // calculate directional shading (and undoing the existing angle attenuation on the lightmap by the division)\n"
+"      // note that q3map2 is too stupid to calculate proper surface normals when q3map_nonplanar\n"
+"      // is used (the lightmap and deluxemap coords correspond to virtually random coordinates\n"
+"      // on that luxel, and NOT to its center, because recursive triangle subdivision is used\n"
+"      // to map the luxels to coordinates on the draw surfaces), which also causes\n"
+"      // deluxemaps to be wrong because light contributions from the wrong side of the surface\n"
+"      // are added up. To prevent divisions by zero or strong exaggerations, a max()\n"
+"      // nudge is done here at expense of some additional fps. This is ONLY needed for\n"
+"      // deluxemaps, tangentspace deluxemap avoid this problem by design.\n"
+"      lightcolor *= 1.0 / max(0.25, lightnormal.z);\n"
+"#endif // MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
+"#ifdef MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
+"#define SHADING\n"
+"      // deluxemap lightmapping using light vectors in tangentspace (hmap2 -light)\n"
+"      half3 lightnormal = half3(tex2D(Texture_Deluxemap, TexCoordLightmap)) * 2.0 + half3(-1.0, -1.0, -1.0);\n"
+"      half3 lightcolor = half3(tex2D(Texture_Lightmap, TexCoordLightmap));\n"
+"#endif\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef MODE_LIGHTMAP\n"
+"      color.rgb = diffusetex * (Color_Ambient + half3(tex2D(Texture_Lightmap, TexCoordLightmap)) * Color_Diffuse);\n"
+"#endif // MODE_LIGHTMAP\n"
+"#ifdef MODE_VERTEXCOLOR\n"
+"      color.rgb = diffusetex * (Color_Ambient + half3(gl_FrontColor.rgb) * Color_Diffuse);\n"
+"#endif // MODE_VERTEXCOLOR\n"
+"#ifdef MODE_FLATCOLOR\n"
+"      color.rgb = diffusetex * Color_Ambient;\n"
+"#endif // MODE_FLATCOLOR\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#ifdef SHADING\n"
+"# ifdef USEDIFFUSE\n"
+"      half diffuse = half(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
+"#  ifdef USESPECULAR\n"
+"#   ifdef USEEXACTSPECULARMATH\n"
+"      half specular = pow(half(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower * glosstex.a);\n"
+"#   else\n"
+"      half3 specularnormal = normalize(lightnormal + half3(normalize(EyeVector)));\n"
+"      half specular = pow(half(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * glosstex.a);\n"
+"#   endif\n"
+"      color.rgb = diffusetex * Color_Ambient + (diffusetex * Color_Diffuse * diffuse + glosstex.rgb * Color_Specular * specular) * lightcolor;\n"
+"#  else\n"
+"      color.rgb = diffusetex * (Color_Ambient + Color_Diffuse * diffuse * lightcolor);\n"
+"#  endif\n"
+"# else\n"
+"      color.rgb = diffusetex * Color_Ambient;\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"      color.rgb *= ShadowMapCompare(ShadowMapTC,\n"
+"# if defined(USESHADOWMAP2D)\n"
+"Texture_ShadowMap2D, ShadowMap_Parameters, ShadowMap_TextureScale\n"
+"# endif\n"
+"# if defined(USESHADOWMAPRECT)\n"
+"Texture_ShadowMapRect, ShadowMap_Parameters\n"
+"# endif\n"
+"      );\n"
+"#endif\n"
+"\n"
+"#ifdef USEDEFERREDLIGHTMAP\n"
+"      float2 ScreenTexCoord = Pixel * PixelToScreenTexCoord;\n"
+"      color.rgb += diffusetex * half3(tex2D(Texture_ScreenDiffuse, ScreenTexCoord)) * DeferredMod_Diffuse;\n"
+"      color.rgb += glosstex.rgb * half3(tex2D(Texture_ScreenSpecular, ScreenTexCoord)) * DeferredMod_Specular;\n"
+"#endif\n"
+"\n"
+"#ifdef USEGLOW\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"      color.rgb += lerp(half3(tex2D(Texture_SecondaryGlow, TexCoord2)), half3(tex2D(Texture_Glow, TexCoord)), terrainblend) * Color_Glow;\n"
+"#else\n"
+"      color.rgb += half3(tex2D(Texture_Glow, TexCoord)) * Color_Glow;\n"
+"#endif\n"
+"#endif\n"
+"\n"
+"#ifdef USEFOG\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"      color.rgb *= half(FogVertex(EyeVectorModelSpaceFogPlaneVertexDist.xyz, EyeVectorModelSpaceFogPlaneVertexDist.w, FogRangeRecip, FogPlaneViewDist, FogHeightFade, Texture_FogMask));\n"
+"#else\n"
+"      color.rgb = lerp(FogColor, float3(color.rgb), FogVertex(EyeVectorModelSpaceFogPlaneVertexDist.xyz, EyeVectorModelSpaceFogPlaneVertexDist.w, FogRangeRecip, FogPlaneViewDist, FogHeightFade, Texture_FogMask));\n"
+"#endif\n"
+"#endif\n"
+"\n"
+"      // reflection must come last because it already contains exactly the correct fog (the reflection render preserves camera distance from the plane, it only flips the side) and ContrastBoost/SceneBrightness\n"
+"#ifdef USEREFLECTION\n"
+"      float4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
+"      //float4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(half3(tex2D(Texture_Normal, TexCoord)) - half3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
+"      float2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW.zw + ScreenCenterRefractReflect.zw;\n"
+"      float2 ScreenTexCoord = SafeScreenTexCoord + float3(normalize(half3(tex2D(Texture_Normal, TexCoord)) - half3(0.5))).xy * DistortScaleRefractReflect.zw;\n"
+"      // FIXME temporary hack to detect the case that the reflection\n"
+"      // gets blackened at edges due to leaving the area that contains actual\n"
+"      // content.\n"
+"      // Remove this 'ack once we have a better way to stop this thing from\n"
+"      // 'appening.\n"
+"      float f = min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord + float2(0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord + float2(0.01, -0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord + float2(-0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord + float2(-0.01, -0.01)).rgb) / 0.05);\n"
+"      ScreenTexCoord = lerp(SafeScreenTexCoord, ScreenTexCoord, f);\n"
+"      color.rgb = lerp(color.rgb, half3(tex2D(Texture_Reflection, ScreenTexCoord)) * ReflectColor.rgb, ReflectColor.a);\n"
 "#endif\n"
-"}\n"
-"#endif // !MODE_REFRACTION\n"
-"#endif // !MODE_WATER\n"
 "\n"
+"      gl_FragColor = float4(color);\n"
+"}\n"
 "#endif // FRAGMENT_SHADER\n"
 "\n"
+"#endif // !MODE_DEFERREDLIGHTSOURCE\n"
+"#endif // !MODE_DEFERREDGEOMETRY\n"
+"#endif // !MODE_WATER\n"
+"#endif // !MODE_REFRACTION\n"
 "#endif // !MODE_BLOOMBLUR\n"
 "#endif // !MODE_GENERIC\n"
 "#endif // !MODE_POSTPROCESS\n"
@@ -1524,6 +3165,11 @@ static const char *builtinshaderstring =
 "#endif // !MODE_DEPTH_OR_SHADOW\n"
 ;
 
+char *glslshaderstring = NULL;
+char *cgshaderstring = NULL;
+
+//=======================================================================================================================================================
+
 typedef struct shaderpermutationinfo_s
 {
        const char *pretext;
@@ -1567,8 +3213,12 @@ typedef enum shaderpermutation_e
        SHADERPERMUTATION_SHADOWMAPPCF2 = 1<<21, ///< (lightsource) use higher quality percentage closer filtering on shadowmap test results
        SHADERPERMUTATION_SHADOWSAMPLER = 1<<22, ///< (lightsource) use hardware shadowmap test
        SHADERPERMUTATION_SHADOWMAPVSDCT = 1<<23, ///< (lightsource) use virtual shadow depth cube texture for shadowmap indexing
-       SHADERPERMUTATION_LIMIT = 1<<24, ///< size of permutations array
-       SHADERPERMUTATION_COUNT = 24 ///< size of shaderpermutationinfo array
+       SHADERPERMUTATION_SHADOWMAPORTHO = 1<<24, //< (lightsource) use orthographic shadowmap projection
+       SHADERPERMUTATION_DEFERREDLIGHTMAP = 1<<25, ///< (lightmap) read Texture_ScreenDiffuse/Specular textures and add them on top of lightmapping
+       SHADERPERMUTATION_ALPHAKILL = 1<<26, ///< (deferredgeometry) discard pixel if diffuse texture alpha below 0.5
+       SHADERPERMUTATION_REFLECTCUBE = 1<<27, ///< fake reflections using global cubemap (not HDRI light probe)
+       SHADERPERMUTATION_LIMIT = 1<<28, ///< size of permutations array
+       SHADERPERMUTATION_COUNT = 28 ///< size of shaderpermutationinfo array
 }
 shaderpermutation_t;
 
@@ -1599,6 +3249,10 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
        {"#define USESHADOWMAPPCF 2\n", " shadowmappcf2"},
        {"#define USESHADOWSAMPLER\n", " shadowsampler"},
        {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"},
+       {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
+       {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
+       {"#define USEALPHAKILL\n", " alphakill"},
+       {"#define USEREFLECTCUBE\n", " reflectcube"},
 };
 
 /// this enum is multiplied by SHADERPERMUTATION_MODEBASE
@@ -1617,12 +3271,14 @@ typedef enum shadermode_e
        SHADERMODE_REFRACTION, ///< refract background (the material is rendered normally after this pass)
        SHADERMODE_WATER, ///< refract background and reflection (the material is rendered normally after this pass)
        SHADERMODE_SHOWDEPTH, ///< (debugging) renders depth as color
+       SHADERMODE_DEFERREDGEOMETRY, ///< (deferred) render material properties to screenspace geometry buffers
+       SHADERMODE_DEFERREDLIGHTSOURCE, ///< (deferred) use directional pixel shading from light source (rtlight) on screenspace geometry buffers
        SHADERMODE_COUNT
 }
 shadermode_t;
 
 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
-shadermodeinfo_t shadermodeinfo[SHADERMODE_COUNT] =
+shadermodeinfo_t glslshadermodeinfo[SHADERMODE_COUNT] =
 {
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_GENERIC\n", " generic"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_POSTPROCESS\n", " postprocess"},
@@ -1637,7 +3293,30 @@ shadermodeinfo_t shadermodeinfo[SHADERMODE_COUNT] =
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_REFRACTION\n", " refraction"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_WATER\n", " water"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_SHOWDEPTH\n", " showdepth"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
+};
+
+#ifdef SUPPORTCG
+shadermodeinfo_t cgshadermodeinfo[SHADERMODE_COUNT] =
+{
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_GENERIC\n", " generic"},
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_POSTPROCESS\n", " postprocess"},
+       {"cg/default.cg", NULL, NULL           , "#define MODE_DEPTH_OR_SHADOW\n", " depth"},
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_FLATCOLOR\n", " flatcolor"},
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_LIGHTMAP\n", " lightmap"},
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_LIGHTSOURCE\n", " lightsource"},
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_REFRACTION\n", " refraction"},
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_WATER\n", " water"},
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_SHOWDEPTH\n", " showdepth"},
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
 };
+#endif
 
 struct r_glsl_permutation_s;
 typedef struct r_glsl_permutation_s
@@ -1676,45 +3355,63 @@ typedef struct r_glsl_permutation_s
        int loc_Texture_ShadowMapCube;
        int loc_Texture_ShadowMap2D;
        int loc_Texture_CubeProjection;
-       int loc_FogColor;
-       int loc_LightPosition;
-       int loc_EyePosition;
+       int loc_Texture_ScreenDepth;
+       int loc_Texture_ScreenNormalMap;
+       int loc_Texture_ScreenDiffuse;
+       int loc_Texture_ScreenSpecular;
+       int loc_Texture_ReflectMask;
+       int loc_Texture_ReflectCube;
+       int loc_Alpha;
+       int loc_BloomBlur_Parameters;
+       int loc_ClientTime;
+       int loc_Color_Ambient;
+       int loc_Color_Diffuse;
+       int loc_Color_Specular;
+       int loc_Color_Glow;
        int loc_Color_Pants;
        int loc_Color_Shirt;
+       int loc_DeferredColor_Ambient;
+       int loc_DeferredColor_Diffuse;
+       int loc_DeferredColor_Specular;
+       int loc_DeferredMod_Diffuse;
+       int loc_DeferredMod_Specular;
+       int loc_DistortScaleRefractReflect;
+       int loc_EyePosition;
+       int loc_FogColor;
+       int loc_FogHeightFade;
        int loc_FogPlane;
        int loc_FogPlaneViewDist;
        int loc_FogRangeRecip;
-       int loc_FogHeightFade;
-       int loc_AmbientScale;
-       int loc_DiffuseScale;
-       int loc_SpecularScale;
-       int loc_SpecularPower;
-       int loc_GlowColor;
-       int loc_SceneBrightness; // or: Scenebrightness * ContrastBoost
-       int loc_OffsetMapping_Scale;
-       int loc_TintColor;
-       int loc_AmbientColor;
-       int loc_DiffuseColor;
-       int loc_SpecularColor;
+       int loc_LightColor;
        int loc_LightDir;
-       int loc_ContrastBoostCoeff; ///< 1 - 1/ContrastBoost
-       int loc_GammaCoeff; ///< 1 / gamma
-       int loc_DistortScaleRefractReflect;
-       int loc_ScreenScaleRefractReflect;
-       int loc_ScreenCenterRefractReflect;
-       int loc_RefractColor;
+       int loc_LightPosition;
+       int loc_OffsetMapping_Scale;
+       int loc_PixelSize;
        int loc_ReflectColor;
        int loc_ReflectFactor;
        int loc_ReflectOffset;
+       int loc_RefractColor;
+       int loc_Saturation;
+       int loc_ScreenCenterRefractReflect;
+       int loc_ScreenScaleRefractReflect;
+       int loc_ScreenToDepth;
+       int loc_ShadowMap_Parameters;
+       int loc_ShadowMap_TextureScale;
+       int loc_SpecularPower;
        int loc_UserVec1;
        int loc_UserVec2;
        int loc_UserVec3;
        int loc_UserVec4;
-       int loc_ClientTime;
-       int loc_PixelSize;
-       int loc_Saturation;
-       int loc_ShadowMap_TextureScale;
-       int loc_ShadowMap_Parameters;
+       int loc_ViewTintColor;
+       int loc_ViewToLight;
+       int loc_ModelToLight;
+       int loc_TexMatrix;
+       int loc_BackgroundTexMatrix;
+       int loc_ModelViewProjectionMatrix;
+       int loc_ModelViewMatrix;
+       int loc_PixelToScreenTexCoord;
+       int loc_ModelToReflectCube;
+       int loc_ShadowMapMatrix;        
 }
 r_glsl_permutation_t;
 
@@ -1757,25 +3454,34 @@ static char *R_GLSL_GetText(const char *filename, qboolean printfromdisknotice)
        char *shaderstring;
        if (!filename || !filename[0])
                return NULL;
+       if (!strcmp(filename, "glsl/default.glsl"))
+       {
+               if (!glslshaderstring)
+               {
+                       glslshaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
+                       if (glslshaderstring)
+                               Con_DPrintf("Loading shaders from file %s...\n", filename);
+                       else
+                               glslshaderstring = (char *)builtinshaderstring;
+               }
+               shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(glslshaderstring) + 1);
+               memcpy(shaderstring, glslshaderstring, strlen(glslshaderstring) + 1);
+               return shaderstring;
+       }
        shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
        if (shaderstring)
        {
                if (printfromdisknotice)
-                       Con_DPrint("from disk... ");
+                       Con_DPrintf("from disk %s... ", filename);
                return shaderstring;
        }
-       else if (!strcmp(filename, "glsl/default.glsl"))
-       {
-               shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(builtinshaderstring) + 1);
-               memcpy(shaderstring, builtinshaderstring, strlen(builtinshaderstring) + 1);
-       }
        return shaderstring;
 }
 
 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, unsigned int permutation)
 {
        int i;
-       shadermodeinfo_t *modeinfo = shadermodeinfo + mode;
+       shadermodeinfo_t *modeinfo = glslshadermodeinfo + mode;
        int vertstrings_count = 0;
        int geomstrings_count = 0;
        int fragstrings_count = 0;
@@ -1795,7 +3501,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
        geometrystring = R_GLSL_GetText(modeinfo->geometryfilename, false);
        fragmentstring = R_GLSL_GetText(modeinfo->fragmentfilename, false);
 
-       strlcat(permutationname, shadermodeinfo[mode].vertexfilename, sizeof(permutationname));
+       strlcat(permutationname, modeinfo->vertexfilename, sizeof(permutationname));
 
        // the first pretext is which type of shader to compile as
        // (later these will all be bound together as a program object)
@@ -1804,9 +3510,9 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
        fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
 
        // the second pretext is the mode (for example a light source)
-       vertstrings_list[vertstrings_count++] = shadermodeinfo[mode].pretext;
-       geomstrings_list[geomstrings_count++] = shadermodeinfo[mode].pretext;
-       fragstrings_list[fragstrings_count++] = shadermodeinfo[mode].pretext;
+       vertstrings_list[vertstrings_count++] = modeinfo->pretext;
+       geomstrings_list[geomstrings_count++] = modeinfo->pretext;
+       fragstrings_list[fragstrings_count++] = modeinfo->pretext;
        strlcat(permutationname, modeinfo->name, sizeof(permutationname));
 
        // now add all the permutation pretexts
@@ -1850,6 +3556,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                qglUseProgramObjectARB(p->program);CHECKGLERROR
                // look up all the uniform variable names we care about, so we don't
                // have to look them up every time we set them
+
                p->loc_Texture_First              = qglGetUniformLocationARB(p->program, "Texture_First");
                p->loc_Texture_Second             = qglGetUniformLocationARB(p->program, "Texture_Second");
                p->loc_Texture_GammaRamps         = qglGetUniformLocationARB(p->program, "Texture_GammaRamps");
@@ -1861,58 +3568,76 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                p->loc_Texture_SecondaryColor     = qglGetUniformLocationARB(p->program, "Texture_SecondaryColor");
                p->loc_Texture_SecondaryGloss     = qglGetUniformLocationARB(p->program, "Texture_SecondaryGloss");
                p->loc_Texture_SecondaryGlow      = qglGetUniformLocationARB(p->program, "Texture_SecondaryGlow");
-               p->loc_Texture_FogMask            = qglGetUniformLocationARB(p->program, "Texture_FogMask");
                p->loc_Texture_Pants              = qglGetUniformLocationARB(p->program, "Texture_Pants");
                p->loc_Texture_Shirt              = qglGetUniformLocationARB(p->program, "Texture_Shirt");
+               p->loc_Texture_FogMask            = qglGetUniformLocationARB(p->program, "Texture_FogMask");
                p->loc_Texture_Lightmap           = qglGetUniformLocationARB(p->program, "Texture_Lightmap");
                p->loc_Texture_Deluxemap          = qglGetUniformLocationARB(p->program, "Texture_Deluxemap");
-               p->loc_Texture_Refraction         = qglGetUniformLocationARB(p->program, "Texture_Refraction");
-               p->loc_Texture_Reflection         = qglGetUniformLocationARB(p->program, "Texture_Reflection");
                p->loc_Texture_Attenuation        = qglGetUniformLocationARB(p->program, "Texture_Attenuation");
                p->loc_Texture_Cube               = qglGetUniformLocationARB(p->program, "Texture_Cube");
+               p->loc_Texture_Refraction         = qglGetUniformLocationARB(p->program, "Texture_Refraction");
+               p->loc_Texture_Reflection         = qglGetUniformLocationARB(p->program, "Texture_Reflection");
                p->loc_Texture_ShadowMapRect      = qglGetUniformLocationARB(p->program, "Texture_ShadowMapRect");
                p->loc_Texture_ShadowMapCube      = qglGetUniformLocationARB(p->program, "Texture_ShadowMapCube");
                p->loc_Texture_ShadowMap2D        = qglGetUniformLocationARB(p->program, "Texture_ShadowMap2D");
                p->loc_Texture_CubeProjection     = qglGetUniformLocationARB(p->program, "Texture_CubeProjection");
-               p->loc_FogColor                   = qglGetUniformLocationARB(p->program, "FogColor");
-               p->loc_LightPosition              = qglGetUniformLocationARB(p->program, "LightPosition");
-               p->loc_EyePosition                = qglGetUniformLocationARB(p->program, "EyePosition");
+               p->loc_Texture_ScreenDepth        = qglGetUniformLocationARB(p->program, "Texture_ScreenDepth");
+               p->loc_Texture_ScreenNormalMap    = qglGetUniformLocationARB(p->program, "Texture_ScreenNormalMap");
+               p->loc_Texture_ScreenDiffuse      = qglGetUniformLocationARB(p->program, "Texture_ScreenDiffuse");
+               p->loc_Texture_ScreenSpecular     = qglGetUniformLocationARB(p->program, "Texture_ScreenSpecular");
+               p->loc_Texture_ReflectMask        = qglGetUniformLocationARB(p->program, "Texture_ReflectMask");
+               p->loc_Texture_ReflectCube        = qglGetUniformLocationARB(p->program, "Texture_ReflectCube");
+               p->loc_Alpha                      = qglGetUniformLocationARB(p->program, "Alpha");
+               p->loc_BloomBlur_Parameters       = qglGetUniformLocationARB(p->program, "BloomBlur_Parameters");
+               p->loc_ClientTime                 = qglGetUniformLocationARB(p->program, "ClientTime");
+               p->loc_Color_Ambient              = qglGetUniformLocationARB(p->program, "Color_Ambient");
+               p->loc_Color_Diffuse              = qglGetUniformLocationARB(p->program, "Color_Diffuse");
+               p->loc_Color_Specular             = qglGetUniformLocationARB(p->program, "Color_Specular");
+               p->loc_Color_Glow                 = qglGetUniformLocationARB(p->program, "Color_Glow");
                p->loc_Color_Pants                = qglGetUniformLocationARB(p->program, "Color_Pants");
                p->loc_Color_Shirt                = qglGetUniformLocationARB(p->program, "Color_Shirt");
+               p->loc_DeferredColor_Ambient      = qglGetUniformLocationARB(p->program, "DeferredColor_Ambient");
+               p->loc_DeferredColor_Diffuse      = qglGetUniformLocationARB(p->program, "DeferredColor_Diffuse");
+               p->loc_DeferredColor_Specular     = qglGetUniformLocationARB(p->program, "DeferredColor_Specular");
+               p->loc_DeferredMod_Diffuse        = qglGetUniformLocationARB(p->program, "DeferredMod_Diffuse");
+               p->loc_DeferredMod_Specular       = qglGetUniformLocationARB(p->program, "DeferredMod_Specular");
+               p->loc_DistortScaleRefractReflect = qglGetUniformLocationARB(p->program, "DistortScaleRefractReflect");
+               p->loc_EyePosition                = qglGetUniformLocationARB(p->program, "EyePosition");
+               p->loc_FogColor                   = qglGetUniformLocationARB(p->program, "FogColor");
+               p->loc_FogHeightFade              = qglGetUniformLocationARB(p->program, "FogHeightFade");
                p->loc_FogPlane                   = qglGetUniformLocationARB(p->program, "FogPlane");
                p->loc_FogPlaneViewDist           = qglGetUniformLocationARB(p->program, "FogPlaneViewDist");
                p->loc_FogRangeRecip              = qglGetUniformLocationARB(p->program, "FogRangeRecip");
-               p->loc_FogHeightFade              = qglGetUniformLocationARB(p->program, "FogHeightFade");
-               p->loc_AmbientScale               = qglGetUniformLocationARB(p->program, "AmbientScale");
-               p->loc_DiffuseScale               = qglGetUniformLocationARB(p->program, "DiffuseScale");
-               p->loc_SpecularPower              = qglGetUniformLocationARB(p->program, "SpecularPower");
-               p->loc_SpecularScale              = qglGetUniformLocationARB(p->program, "SpecularScale");
-               p->loc_GlowColor                  = qglGetUniformLocationARB(p->program, "GlowColor");
-               p->loc_SceneBrightness            = qglGetUniformLocationARB(p->program, "SceneBrightness");
-               p->loc_OffsetMapping_Scale        = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
-               p->loc_TintColor                  = qglGetUniformLocationARB(p->program, "TintColor");
-               p->loc_AmbientColor               = qglGetUniformLocationARB(p->program, "AmbientColor");
-               p->loc_DiffuseColor               = qglGetUniformLocationARB(p->program, "DiffuseColor");
-               p->loc_SpecularColor              = qglGetUniformLocationARB(p->program, "SpecularColor");
+               p->loc_LightColor                 = qglGetUniformLocationARB(p->program, "LightColor");
                p->loc_LightDir                   = qglGetUniformLocationARB(p->program, "LightDir");
-               p->loc_ContrastBoostCoeff         = qglGetUniformLocationARB(p->program, "ContrastBoostCoeff");
-               p->loc_DistortScaleRefractReflect = qglGetUniformLocationARB(p->program, "DistortScaleRefractReflect");
-               p->loc_ScreenScaleRefractReflect  = qglGetUniformLocationARB(p->program, "ScreenScaleRefractReflect");
-               p->loc_ScreenCenterRefractReflect = qglGetUniformLocationARB(p->program, "ScreenCenterRefractReflect");
-               p->loc_RefractColor               = qglGetUniformLocationARB(p->program, "RefractColor");
+               p->loc_LightPosition              = qglGetUniformLocationARB(p->program, "LightPosition");
+               p->loc_OffsetMapping_Scale        = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
+               p->loc_PixelSize                  = qglGetUniformLocationARB(p->program, "PixelSize");
                p->loc_ReflectColor               = qglGetUniformLocationARB(p->program, "ReflectColor");
                p->loc_ReflectFactor              = qglGetUniformLocationARB(p->program, "ReflectFactor");
                p->loc_ReflectOffset              = qglGetUniformLocationARB(p->program, "ReflectOffset");
-               p->loc_GammaCoeff                 = qglGetUniformLocationARB(p->program, "GammaCoeff");
+               p->loc_RefractColor               = qglGetUniformLocationARB(p->program, "RefractColor");
+               p->loc_Saturation                 = qglGetUniformLocationARB(p->program, "Saturation");
+               p->loc_ScreenCenterRefractReflect = qglGetUniformLocationARB(p->program, "ScreenCenterRefractReflect");
+               p->loc_ScreenScaleRefractReflect  = qglGetUniformLocationARB(p->program, "ScreenScaleRefractReflect");
+               p->loc_ScreenToDepth              = qglGetUniformLocationARB(p->program, "ScreenToDepth");
+               p->loc_ShadowMap_Parameters       = qglGetUniformLocationARB(p->program, "ShadowMap_Parameters");
+               p->loc_ShadowMap_TextureScale     = qglGetUniformLocationARB(p->program, "ShadowMap_TextureScale");
+               p->loc_SpecularPower              = qglGetUniformLocationARB(p->program, "SpecularPower");
                p->loc_UserVec1                   = qglGetUniformLocationARB(p->program, "UserVec1");
                p->loc_UserVec2                   = qglGetUniformLocationARB(p->program, "UserVec2");
                p->loc_UserVec3                   = qglGetUniformLocationARB(p->program, "UserVec3");
                p->loc_UserVec4                   = qglGetUniformLocationARB(p->program, "UserVec4");
-               p->loc_ClientTime                 = qglGetUniformLocationARB(p->program, "ClientTime");
-               p->loc_PixelSize                  = qglGetUniformLocationARB(p->program, "PixelSize");
-               p->loc_Saturation                 = qglGetUniformLocationARB(p->program, "Saturation");
-               p->loc_ShadowMap_TextureScale     = qglGetUniformLocationARB(p->program, "ShadowMap_TextureScale");
-               p->loc_ShadowMap_Parameters       = qglGetUniformLocationARB(p->program, "ShadowMap_Parameters");
+               p->loc_ViewTintColor              = qglGetUniformLocationARB(p->program, "ViewTintColor");
+               p->loc_ViewToLight                = qglGetUniformLocationARB(p->program, "ViewToLight");
+               p->loc_ModelToLight               = qglGetUniformLocationARB(p->program, "ModelToLight");
+               p->loc_TexMatrix                  = qglGetUniformLocationARB(p->program, "TexMatrix");
+               p->loc_BackgroundTexMatrix        = qglGetUniformLocationARB(p->program, "BackgroundTexMatrix");
+               p->loc_ModelViewMatrix            = qglGetUniformLocationARB(p->program, "ModelViewMatrix");
+               p->loc_ModelViewProjectionMatrix  = qglGetUniformLocationARB(p->program, "ModelViewProjectionMatrix");
+               p->loc_PixelToScreenTexCoord      = qglGetUniformLocationARB(p->program, "PixelToScreenTexCoord");
+               p->loc_ModelToReflectCube         = qglGetUniformLocationARB(p->program, "ModelToReflectCube");
+               p->loc_ShadowMapMatrix            = qglGetUniformLocationARB(p->program, "ShadowMapMatrix");            
                // initialize the samplers to refer to the texture units we use
                if (p->loc_Texture_First           >= 0) qglUniform1iARB(p->loc_Texture_First          , GL20TU_FIRST);
                if (p->loc_Texture_Second          >= 0) qglUniform1iARB(p->loc_Texture_Second         , GL20TU_SECOND);
@@ -1934,18 +3659,490 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                if (p->loc_Texture_Cube            >= 0) qglUniform1iARB(p->loc_Texture_Cube           , GL20TU_CUBE);
                if (p->loc_Texture_Refraction      >= 0) qglUniform1iARB(p->loc_Texture_Refraction     , GL20TU_REFRACTION);
                if (p->loc_Texture_Reflection      >= 0) qglUniform1iARB(p->loc_Texture_Reflection     , GL20TU_REFLECTION);
-               if (p->loc_Texture_ShadowMapRect   >= 0) qglUniform1iARB(p->loc_Texture_ShadowMapRect  , GL20TU_SHADOWMAPRECT);
+               if (p->loc_Texture_ShadowMapRect   >= 0) qglUniform1iARB(p->loc_Texture_ShadowMapRect  , permutation & SHADERPERMUTATION_SHADOWMAPORTHO ? GL20TU_SHADOWMAPORTHORECT : GL20TU_SHADOWMAPRECT);
                if (p->loc_Texture_ShadowMapCube   >= 0) qglUniform1iARB(p->loc_Texture_ShadowMapCube  , GL20TU_SHADOWMAPCUBE);
-               if (p->loc_Texture_ShadowMap2D     >= 0) qglUniform1iARB(p->loc_Texture_ShadowMap2D    , GL20TU_SHADOWMAP2D);
+               if (p->loc_Texture_ShadowMap2D     >= 0) qglUniform1iARB(p->loc_Texture_ShadowMap2D    , permutation & SHADERPERMUTATION_SHADOWMAPORTHO ? GL20TU_SHADOWMAPORTHO2D : GL20TU_SHADOWMAP2D);
                if (p->loc_Texture_CubeProjection  >= 0) qglUniform1iARB(p->loc_Texture_CubeProjection , GL20TU_CUBEPROJECTION);
+               if (p->loc_Texture_ScreenDepth     >= 0) qglUniform1iARB(p->loc_Texture_ScreenDepth    , GL20TU_SCREENDEPTH);
+               if (p->loc_Texture_ScreenNormalMap >= 0) qglUniform1iARB(p->loc_Texture_ScreenNormalMap, GL20TU_SCREENNORMALMAP);
+               if (p->loc_Texture_ScreenDiffuse   >= 0) qglUniform1iARB(p->loc_Texture_ScreenDiffuse  , GL20TU_SCREENDIFFUSE);
+               if (p->loc_Texture_ScreenSpecular  >= 0) qglUniform1iARB(p->loc_Texture_ScreenSpecular , GL20TU_SCREENSPECULAR);
+               if (p->loc_Texture_ReflectMask     >= 0) qglUniform1iARB(p->loc_Texture_ReflectMask    , GL20TU_REFLECTMASK);
+               if (p->loc_Texture_ReflectCube     >= 0) qglUniform1iARB(p->loc_Texture_ReflectCube    , GL20TU_REFLECTCUBE);
+               CHECKGLERROR
+               Con_DPrintf("^5GLSL shader %s compiled.\n", permutationname);
+       }
+       else
+               Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
+
+       // free the strings
+       if (vertexstring)
+               Mem_Free(vertexstring);
+       if (geometrystring)
+               Mem_Free(geometrystring);
+       if (fragmentstring)
+               Mem_Free(fragmentstring);
+}
+
+void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int permutation)
+{
+       r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
+       if (r_glsl_permutation != perm)
+       {
+               r_glsl_permutation = perm;
+               if (!r_glsl_permutation->program)
+               {
+                       if (!r_glsl_permutation->compiled)
+                               R_GLSL_CompilePermutation(perm, mode, permutation);
+                       if (!r_glsl_permutation->program)
+                       {
+                               // remove features until we find a valid permutation
+                               int i;
+                               for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
+                               {
+                                       // reduce i more quickly whenever it would not remove any bits
+                                       int j = 1<<(SHADERPERMUTATION_COUNT-1-i);
+                                       if (!(permutation & j))
+                                               continue;
+                                       permutation -= j;
+                                       r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
+                                       if (!r_glsl_permutation->compiled)
+                                               R_GLSL_CompilePermutation(perm, mode, permutation);
+                                       if (r_glsl_permutation->program)
+                                               break;
+                               }
+                               if (i >= SHADERPERMUTATION_COUNT)
+                               {
+                                       //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].vertexfilename, shadermodeinfo[mode].pretext);
+                                       r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
+                                       qglUseProgramObjectARB(0);CHECKGLERROR
+                                       return; // no bit left to clear, entire mode is broken
+                               }
+                       }
+               }
                CHECKGLERROR
-               if (developer.integer)
-                       Con_Printf("GLSL shader %s compiled.\n", permutationname);
+               qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR
+       }
+       if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fvARB(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
+       if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fvARB(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
+       if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1fARB(r_glsl_permutation->loc_ClientTime, cl.time);
+}
+
+#ifdef SUPPORTCG
+#include <Cg/cgGL.h>
+struct r_cg_permutation_s;
+typedef struct r_cg_permutation_s
+{
+       /// hash lookup data
+       struct r_cg_permutation_s *hashnext;
+       unsigned int mode;
+       unsigned int permutation;
+
+       /// indicates if we have tried compiling this permutation already
+       qboolean compiled;
+       /// 0 if compilation failed
+       CGprogram vprogram;
+       CGprogram fprogram;
+       /// locations of detected parameters in programs, or NULL if not found
+       CGparameter vp_EyePosition;
+       CGparameter vp_FogPlane;
+       CGparameter vp_LightDir;
+       CGparameter vp_LightPosition;
+       CGparameter vp_ModelToLight;
+       CGparameter vp_TexMatrix;
+       CGparameter vp_BackgroundTexMatrix;
+       CGparameter vp_ModelViewProjectionMatrix;
+       CGparameter vp_ModelViewMatrix;
+       CGparameter vp_ShadowMapMatrix;
+
+       CGparameter fp_Texture_First;
+       CGparameter fp_Texture_Second;
+       CGparameter fp_Texture_GammaRamps;
+       CGparameter fp_Texture_Normal;
+       CGparameter fp_Texture_Color;
+       CGparameter fp_Texture_Gloss;
+       CGparameter fp_Texture_Glow;
+       CGparameter fp_Texture_SecondaryNormal;
+       CGparameter fp_Texture_SecondaryColor;
+       CGparameter fp_Texture_SecondaryGloss;
+       CGparameter fp_Texture_SecondaryGlow;
+       CGparameter fp_Texture_Pants;
+       CGparameter fp_Texture_Shirt;
+       CGparameter fp_Texture_FogMask;
+       CGparameter fp_Texture_Lightmap;
+       CGparameter fp_Texture_Deluxemap;
+       CGparameter fp_Texture_Attenuation;
+       CGparameter fp_Texture_Cube;
+       CGparameter fp_Texture_Refraction;
+       CGparameter fp_Texture_Reflection;
+       CGparameter fp_Texture_ShadowMapRect;
+       CGparameter fp_Texture_ShadowMapCube;
+       CGparameter fp_Texture_ShadowMap2D;
+       CGparameter fp_Texture_CubeProjection;
+       CGparameter fp_Texture_ScreenDepth;
+       CGparameter fp_Texture_ScreenNormalMap;
+       CGparameter fp_Texture_ScreenDiffuse;
+       CGparameter fp_Texture_ScreenSpecular;
+       CGparameter fp_Texture_ReflectMask;
+       CGparameter fp_Texture_ReflectCube;
+       CGparameter fp_Alpha;
+       CGparameter fp_BloomBlur_Parameters;
+       CGparameter fp_ClientTime;
+       CGparameter fp_Color_Ambient;
+       CGparameter fp_Color_Diffuse;
+       CGparameter fp_Color_Specular;
+       CGparameter fp_Color_Glow;
+       CGparameter fp_Color_Pants;
+       CGparameter fp_Color_Shirt;
+       CGparameter fp_DeferredColor_Ambient;
+       CGparameter fp_DeferredColor_Diffuse;
+       CGparameter fp_DeferredColor_Specular;
+       CGparameter fp_DeferredMod_Diffuse;
+       CGparameter fp_DeferredMod_Specular;
+       CGparameter fp_DistortScaleRefractReflect;
+       CGparameter fp_EyePosition;
+       CGparameter fp_FogColor;
+       CGparameter fp_FogHeightFade;
+       CGparameter fp_FogPlane;
+       CGparameter fp_FogPlaneViewDist;
+       CGparameter fp_FogRangeRecip;
+       CGparameter fp_LightColor;
+       CGparameter fp_LightDir;
+       CGparameter fp_LightPosition;
+       CGparameter fp_OffsetMapping_Scale;
+       CGparameter fp_PixelSize;
+       CGparameter fp_ReflectColor;
+       CGparameter fp_ReflectFactor;
+       CGparameter fp_ReflectOffset;
+       CGparameter fp_RefractColor;
+       CGparameter fp_Saturation;
+       CGparameter fp_ScreenCenterRefractReflect;
+       CGparameter fp_ScreenScaleRefractReflect;
+       CGparameter fp_ScreenToDepth;
+       CGparameter fp_ShadowMap_Parameters;
+       CGparameter fp_ShadowMap_TextureScale;
+       CGparameter fp_SpecularPower;
+       CGparameter fp_UserVec1;
+       CGparameter fp_UserVec2;
+       CGparameter fp_UserVec3;
+       CGparameter fp_UserVec4;
+       CGparameter fp_ViewTintColor;
+       CGparameter fp_ViewToLight;
+       CGparameter fp_PixelToScreenTexCoord;
+       CGparameter fp_ModelToReflectCube;
+}
+r_cg_permutation_t;
+
+/// information about each possible shader permutation
+r_cg_permutation_t *r_cg_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
+/// currently selected permutation
+r_cg_permutation_t *r_cg_permutation;
+/// storage for permutations linked in the hash table
+memexpandablearray_t r_cg_permutationarray;
+
+#define CHECKCGERROR {CGerror err = cgGetError(), err2 = err;if (err){Con_Printf("%s:%i CG error %i: %s : %s\n", __FILE__, __LINE__, err, cgGetErrorString(err), cgGetLastErrorString(&err2));if (err == 1) Con_Printf("last listing:\n%s\n", cgGetLastListing(vid.cgcontext));}}
+
+static r_cg_permutation_t *R_CG_FindPermutation(unsigned int mode, unsigned int permutation)
+{
+       //unsigned int hashdepth = 0;
+       unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
+       r_cg_permutation_t *p;
+       for (p = r_cg_permutationhash[mode][hashindex];p;p = p->hashnext)
+       {
+               if (p->mode == mode && p->permutation == permutation)
+               {
+                       //if (hashdepth > 10)
+                       //      Con_Printf("R_CG_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
+                       return p;
+               }
+               //hashdepth++;
+       }
+       p = (r_cg_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_cg_permutationarray);
+       p->mode = mode;
+       p->permutation = permutation;
+       p->hashnext = r_cg_permutationhash[mode][hashindex];
+       r_cg_permutationhash[mode][hashindex] = p;
+       //if (hashdepth > 10)
+       //      Con_Printf("R_CG_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
+       return p;
+}
+
+static char *R_CG_GetText(const char *filename, qboolean printfromdisknotice)
+{
+       char *shaderstring;
+       if (!filename || !filename[0])
+               return NULL;
+       if (!strcmp(filename, "cg/default.cg"))
+       {
+               if (!cgshaderstring)
+               {
+                       cgshaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
+                       if (cgshaderstring)
+                               Con_DPrintf("Loading shaders from file %s...\n", filename);
+                       else
+                               cgshaderstring = (char *)builtincgshaderstring;
+               }
+               shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(cgshaderstring) + 1);
+               memcpy(shaderstring, cgshaderstring, strlen(cgshaderstring) + 1);
+               return shaderstring;
+       }
+       shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
+       if (shaderstring)
+       {
+               if (printfromdisknotice)
+                       Con_DPrintf("from disk %s... ", filename);
+               return shaderstring;
+       }
+       return shaderstring;
+}
+
+static void R_CG_CacheShader(r_cg_permutation_t *p, const char *cachename, const char *vertstring, const char *fragstring)
+{
+       // TODO: load or create .fp and .vp shader files
+}
+
+static void R_CG_CompilePermutation(r_cg_permutation_t *p, unsigned int mode, unsigned int permutation)
+{
+       int i;
+       shadermodeinfo_t *modeinfo = cgshadermodeinfo + mode;
+       int vertstrings_count = 0, vertstring_length = 0;
+       int geomstrings_count = 0, geomstring_length = 0;
+       int fragstrings_count = 0, fragstring_length = 0;
+       char *t;
+       char *vertexstring, *geometrystring, *fragmentstring;
+       char *vertstring, *geomstring, *fragstring;
+       const char *vertstrings_list[32+3];
+       const char *geomstrings_list[32+3];
+       const char *fragstrings_list[32+3];
+       char permutationname[256];
+       char cachename[256];
+       CGprofile vertexProfile;
+       CGprofile fragmentProfile;
+
+       if (p->compiled)
+               return;
+       p->compiled = true;
+       p->vprogram = NULL;
+       p->fprogram = NULL;
+
+       permutationname[0] = 0;
+       cachename[0] = 0;
+       vertexstring   = R_CG_GetText(modeinfo->vertexfilename, true);
+       geometrystring = R_CG_GetText(modeinfo->geometryfilename, false);
+       fragmentstring = R_CG_GetText(modeinfo->fragmentfilename, false);
+
+       strlcat(permutationname, modeinfo->vertexfilename, sizeof(permutationname));
+       strlcat(cachename, "cg/", sizeof(cachename));
+
+       // the first pretext is which type of shader to compile as
+       // (later these will all be bound together as a program object)
+       vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
+       geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
+       fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
+
+       // the second pretext is the mode (for example a light source)
+       vertstrings_list[vertstrings_count++] = modeinfo->pretext;
+       geomstrings_list[geomstrings_count++] = modeinfo->pretext;
+       fragstrings_list[fragstrings_count++] = modeinfo->pretext;
+       strlcat(permutationname, modeinfo->name, sizeof(permutationname));
+       strlcat(cachename, modeinfo->name, sizeof(cachename));
+
+       // now add all the permutation pretexts
+       for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
+       {
+               if (permutation & (1<<i))
+               {
+                       vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
+                       geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
+                       fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
+                       strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
+                       strlcat(cachename, shaderpermutationinfo[i].name, sizeof(cachename));
+               }
+               else
+               {
+                       // keep line numbers correct
+                       vertstrings_list[vertstrings_count++] = "\n";
+                       geomstrings_list[geomstrings_count++] = "\n";
+                       fragstrings_list[fragstrings_count++] = "\n";
+               }
        }
+
+       // replace spaces in the cachename with _ characters
+       for (i = 0;cachename[i];i++)
+               if (cachename[i] == ' ')
+                       cachename[i] = '_';
+
+       // now append the shader text itself
+       vertstrings_list[vertstrings_count++] = vertexstring;
+       geomstrings_list[geomstrings_count++] = geometrystring;
+       fragstrings_list[fragstrings_count++] = fragmentstring;
+
+       // if any sources were NULL, clear the respective list
+       if (!vertexstring)
+               vertstrings_count = 0;
+       if (!geometrystring)
+               geomstrings_count = 0;
+       if (!fragmentstring)
+               fragstrings_count = 0;
+
+       vertstring_length = 0;
+       for (i = 0;i < vertstrings_count;i++)
+               vertstring_length += strlen(vertstrings_list[i]);
+       vertstring = t = Mem_Alloc(tempmempool, vertstring_length + 1);
+       for (i = 0;i < vertstrings_count;t += strlen(vertstrings_list[i]), i++)
+               memcpy(t, vertstrings_list[i], strlen(vertstrings_list[i]));
+
+       geomstring_length = 0;
+       for (i = 0;i < geomstrings_count;i++)
+               geomstring_length += strlen(geomstrings_list[i]);
+       geomstring = t = Mem_Alloc(tempmempool, geomstring_length + 1);
+       for (i = 0;i < geomstrings_count;t += strlen(geomstrings_list[i]), i++)
+               memcpy(t, geomstrings_list[i], strlen(geomstrings_list[i]));
+
+       fragstring_length = 0;
+       for (i = 0;i < fragstrings_count;i++)
+               fragstring_length += strlen(fragstrings_list[i]);
+       fragstring = t = Mem_Alloc(tempmempool, fragstring_length + 1);
+       for (i = 0;i < fragstrings_count;t += strlen(fragstrings_list[i]), i++)
+               memcpy(t, fragstrings_list[i], strlen(fragstrings_list[i]));
+
+       CHECKGLERROR
+       CHECKCGERROR
+       //vertexProfile = CG_PROFILE_ARBVP1;
+       //fragmentProfile = CG_PROFILE_ARBFP1;
+       vertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);CHECKCGERROR
+       fragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);CHECKCGERROR
+       //cgGLSetOptimalOptions(vertexProfile);CHECKCGERROR
+       //cgGLSetOptimalOptions(fragmentProfile);CHECKCGERROR
+       //cgSetAutoCompile(vid.cgcontext, CG_COMPILE_MANUAL);CHECKCGERROR
+       CHECKGLERROR
+
+       // try to load the cached shader, or generate one
+       R_CG_CacheShader(p, cachename, vertstring, fragstring);
+
+       // if caching failed, do a dynamic compile for now
+       CHECKCGERROR
+       if (vertstring[0] && !p->vprogram)
+               p->vprogram = cgCreateProgram(vid.cgcontext, CG_SOURCE, vertstring, vertexProfile, NULL, NULL);
+       CHECKCGERROR
+       if (fragstring[0] && !p->fprogram)
+               p->fprogram = cgCreateProgram(vid.cgcontext, CG_SOURCE, fragstring, fragmentProfile, NULL, NULL);
+       CHECKCGERROR
+
+       // look up all the uniform variable names we care about, so we don't
+       // have to look them up every time we set them
+       if (p->vprogram)
+       {
+               CHECKCGERROR
+               cgGLLoadProgram(p->vprogram);CHECKCGERROR CHECKGLERROR
+               cgGLEnableProfile(vertexProfile);CHECKCGERROR CHECKGLERROR
+               p->vp_EyePosition                = cgGetNamedParameter(p->vprogram, "EyePosition");
+               p->vp_FogPlane                   = cgGetNamedParameter(p->vprogram, "FogPlane");
+               p->vp_LightDir                   = cgGetNamedParameter(p->vprogram, "LightDir");
+               p->vp_LightPosition              = cgGetNamedParameter(p->vprogram, "LightPosition");
+               p->vp_ModelToLight               = cgGetNamedParameter(p->vprogram, "ModelToLight");
+               p->vp_TexMatrix                  = cgGetNamedParameter(p->vprogram, "TexMatrix");
+               p->vp_BackgroundTexMatrix        = cgGetNamedParameter(p->vprogram, "BackgroundTexMatrix");
+               p->vp_ModelViewProjectionMatrix  = cgGetNamedParameter(p->vprogram, "ModelViewProjectionMatrix");
+               p->vp_ModelViewMatrix            = cgGetNamedParameter(p->vprogram, "ModelViewMatrix");
+               p->vp_ShadowMapMatrix            = cgGetNamedParameter(p->vprogram, "ShadowMapMatrix");
+               CHECKCGERROR
+       }
+       if (p->fprogram)
+       {
+               CHECKCGERROR
+               cgGLLoadProgram(p->fprogram);CHECKCGERROR CHECKGLERROR
+               cgGLEnableProfile(fragmentProfile);CHECKCGERROR CHECKGLERROR
+               p->fp_Texture_First              = cgGetNamedParameter(p->fprogram, "Texture_First");
+               p->fp_Texture_Second             = cgGetNamedParameter(p->fprogram, "Texture_Second");
+               p->fp_Texture_GammaRamps         = cgGetNamedParameter(p->fprogram, "Texture_GammaRamps");
+               p->fp_Texture_Normal             = cgGetNamedParameter(p->fprogram, "Texture_Normal");
+               p->fp_Texture_Color              = cgGetNamedParameter(p->fprogram, "Texture_Color");
+               p->fp_Texture_Gloss              = cgGetNamedParameter(p->fprogram, "Texture_Gloss");
+               p->fp_Texture_Glow               = cgGetNamedParameter(p->fprogram, "Texture_Glow");
+               p->fp_Texture_SecondaryNormal    = cgGetNamedParameter(p->fprogram, "Texture_SecondaryNormal");
+               p->fp_Texture_SecondaryColor     = cgGetNamedParameter(p->fprogram, "Texture_SecondaryColor");
+               p->fp_Texture_SecondaryGloss     = cgGetNamedParameter(p->fprogram, "Texture_SecondaryGloss");
+               p->fp_Texture_SecondaryGlow      = cgGetNamedParameter(p->fprogram, "Texture_SecondaryGlow");
+               p->fp_Texture_Pants              = cgGetNamedParameter(p->fprogram, "Texture_Pants");
+               p->fp_Texture_Shirt              = cgGetNamedParameter(p->fprogram, "Texture_Shirt");
+               p->fp_Texture_FogMask            = cgGetNamedParameter(p->fprogram, "Texture_FogMask");
+               p->fp_Texture_Lightmap           = cgGetNamedParameter(p->fprogram, "Texture_Lightmap");
+               p->fp_Texture_Deluxemap          = cgGetNamedParameter(p->fprogram, "Texture_Deluxemap");
+               p->fp_Texture_Attenuation        = cgGetNamedParameter(p->fprogram, "Texture_Attenuation");
+               p->fp_Texture_Cube               = cgGetNamedParameter(p->fprogram, "Texture_Cube");
+               p->fp_Texture_Refraction         = cgGetNamedParameter(p->fprogram, "Texture_Refraction");
+               p->fp_Texture_Reflection         = cgGetNamedParameter(p->fprogram, "Texture_Reflection");
+               p->fp_Texture_ShadowMapRect      = cgGetNamedParameter(p->fprogram, "Texture_ShadowMapRect");
+               p->fp_Texture_ShadowMapCube      = cgGetNamedParameter(p->fprogram, "Texture_ShadowMapCube");
+               p->fp_Texture_ShadowMap2D        = cgGetNamedParameter(p->fprogram, "Texture_ShadowMap2D");
+               p->fp_Texture_CubeProjection     = cgGetNamedParameter(p->fprogram, "Texture_CubeProjection");
+               p->fp_Texture_ScreenDepth        = cgGetNamedParameter(p->fprogram, "Texture_ScreenDepth");
+               p->fp_Texture_ScreenNormalMap    = cgGetNamedParameter(p->fprogram, "Texture_ScreenNormalMap");
+               p->fp_Texture_ScreenDiffuse      = cgGetNamedParameter(p->fprogram, "Texture_ScreenDiffuse");
+               p->fp_Texture_ScreenSpecular     = cgGetNamedParameter(p->fprogram, "Texture_ScreenSpecular");
+               p->fp_Texture_ReflectMask        = cgGetNamedParameter(p->fprogram, "Texture_ReflectMask");
+               p->fp_Texture_ReflectCube        = cgGetNamedParameter(p->fprogram, "Texture_ReflectCube");
+               p->fp_Alpha                      = cgGetNamedParameter(p->fprogram, "Alpha");
+               p->fp_BloomBlur_Parameters       = cgGetNamedParameter(p->fprogram, "BloomBlur_Parameters");
+               p->fp_ClientTime                 = cgGetNamedParameter(p->fprogram, "ClientTime");
+               p->fp_Color_Ambient              = cgGetNamedParameter(p->fprogram, "Color_Ambient");
+               p->fp_Color_Diffuse              = cgGetNamedParameter(p->fprogram, "Color_Diffuse");
+               p->fp_Color_Specular             = cgGetNamedParameter(p->fprogram, "Color_Specular");
+               p->fp_Color_Glow                 = cgGetNamedParameter(p->fprogram, "Color_Glow");
+               p->fp_Color_Pants                = cgGetNamedParameter(p->fprogram, "Color_Pants");
+               p->fp_Color_Shirt                = cgGetNamedParameter(p->fprogram, "Color_Shirt");
+               p->fp_DeferredColor_Ambient      = cgGetNamedParameter(p->fprogram, "DeferredColor_Ambient");
+               p->fp_DeferredColor_Diffuse      = cgGetNamedParameter(p->fprogram, "DeferredColor_Diffuse");
+               p->fp_DeferredColor_Specular     = cgGetNamedParameter(p->fprogram, "DeferredColor_Specular");
+               p->fp_DeferredMod_Diffuse        = cgGetNamedParameter(p->fprogram, "DeferredMod_Diffuse");
+               p->fp_DeferredMod_Specular       = cgGetNamedParameter(p->fprogram, "DeferredMod_Specular");
+               p->fp_DistortScaleRefractReflect = cgGetNamedParameter(p->fprogram, "DistortScaleRefractReflect");
+               p->fp_EyePosition                = cgGetNamedParameter(p->fprogram, "EyePosition");
+               p->fp_FogColor                   = cgGetNamedParameter(p->fprogram, "FogColor");
+               p->fp_FogHeightFade              = cgGetNamedParameter(p->fprogram, "FogHeightFade");
+               p->fp_FogPlane                   = cgGetNamedParameter(p->fprogram, "FogPlane");
+               p->fp_FogPlaneViewDist           = cgGetNamedParameter(p->fprogram, "FogPlaneViewDist");
+               p->fp_FogRangeRecip              = cgGetNamedParameter(p->fprogram, "FogRangeRecip");
+               p->fp_LightColor                 = cgGetNamedParameter(p->fprogram, "LightColor");
+               p->fp_LightDir                   = cgGetNamedParameter(p->fprogram, "LightDir");
+               p->fp_LightPosition              = cgGetNamedParameter(p->fprogram, "LightPosition");
+               p->fp_OffsetMapping_Scale        = cgGetNamedParameter(p->fprogram, "OffsetMapping_Scale");
+               p->fp_PixelSize                  = cgGetNamedParameter(p->fprogram, "PixelSize");
+               p->fp_ReflectColor               = cgGetNamedParameter(p->fprogram, "ReflectColor");
+               p->fp_ReflectFactor              = cgGetNamedParameter(p->fprogram, "ReflectFactor");
+               p->fp_ReflectOffset              = cgGetNamedParameter(p->fprogram, "ReflectOffset");
+               p->fp_RefractColor               = cgGetNamedParameter(p->fprogram, "RefractColor");
+               p->fp_Saturation                 = cgGetNamedParameter(p->fprogram, "Saturation");
+               p->fp_ScreenCenterRefractReflect = cgGetNamedParameter(p->fprogram, "ScreenCenterRefractReflect");
+               p->fp_ScreenScaleRefractReflect  = cgGetNamedParameter(p->fprogram, "ScreenScaleRefractReflect");
+               p->fp_ScreenToDepth              = cgGetNamedParameter(p->fprogram, "ScreenToDepth");
+               p->fp_ShadowMap_Parameters       = cgGetNamedParameter(p->fprogram, "ShadowMap_Parameters");
+               p->fp_ShadowMap_TextureScale     = cgGetNamedParameter(p->fprogram, "ShadowMap_TextureScale");
+               p->fp_SpecularPower              = cgGetNamedParameter(p->fprogram, "SpecularPower");
+               p->fp_UserVec1                   = cgGetNamedParameter(p->fprogram, "UserVec1");
+               p->fp_UserVec2                   = cgGetNamedParameter(p->fprogram, "UserVec2");
+               p->fp_UserVec3                   = cgGetNamedParameter(p->fprogram, "UserVec3");
+               p->fp_UserVec4                   = cgGetNamedParameter(p->fprogram, "UserVec4");
+               p->fp_ViewTintColor              = cgGetNamedParameter(p->fprogram, "ViewTintColor");
+               p->fp_ViewToLight                = cgGetNamedParameter(p->fprogram, "ViewToLight");
+               p->fp_PixelToScreenTexCoord      = cgGetNamedParameter(p->fprogram, "PixelToScreenTexCoord");
+               p->fp_ModelToReflectCube         = cgGetNamedParameter(p->fprogram, "ModelToReflectCube");
+               CHECKCGERROR
+       }
+
+       if ((p->vprogram || !vertstring[0]) && (p->fprogram || !fragstring[0]))
+               Con_DPrintf("^5CG shader %s compiled.\n", permutationname);
        else
-               Con_Printf("GLSL shader %s failed!  some features may not work properly.\n", permutationname);
+               Con_Printf("^1CG shader %s failed!  some features may not work properly.\n", permutationname);
 
        // free the strings
+       if (vertstring)
+               Mem_Free(vertstring);
+       if (geomstring)
+               Mem_Free(geomstring);
+       if (fragstring)
+               Mem_Free(fragstring);
        if (vertexstring)
                Mem_Free(vertexstring);
        if (geometrystring)
@@ -1954,57 +4151,19 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                Mem_Free(fragmentstring);
 }
 
-void R_GLSL_Restart_f(void)
-{
-       unsigned int i, limit;
-       r_glsl_permutation_t *p;
-       limit = Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
-       for (i = 0;i < limit;i++)
-       {
-               if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
-               {
-                       GL_Backend_FreeProgram(p->program);
-                       Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
-               }
-       }
-       memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
-}
-
-void R_GLSL_DumpShader_f(void)
-{
-       int i;
-
-       qfile_t *file = FS_OpenRealFile("glsl/default.glsl", "w", false);
-       if(!file)
-       {
-               Con_Printf("failed to write to glsl/default.glsl\n");
-               return;
-       }
-
-       FS_Print(file, "/* The engine may define the following macros:\n");
-       FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
-       for (i = 0;i < SHADERMODE_COUNT;i++)
-               FS_Print(file, shadermodeinfo[i].pretext);
-       for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
-               FS_Print(file, shaderpermutationinfo[i].pretext);
-       FS_Print(file, "*/\n");
-       FS_Print(file, builtinshaderstring);
-       FS_Close(file);
-
-       Con_Printf("glsl/default.glsl written\n");
-}
-
-void R_SetupShader_SetPermutation(unsigned int mode, unsigned int permutation)
+void R_SetupShader_SetPermutationCG(unsigned int mode, unsigned int permutation)
 {
-       r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
-       if (r_glsl_permutation != perm)
+       r_cg_permutation_t *perm = R_CG_FindPermutation(mode, permutation);
+       CHECKGLERROR
+       CHECKCGERROR
+       if (r_cg_permutation != perm)
        {
-               r_glsl_permutation = perm;
-               if (!r_glsl_permutation->program)
+               r_cg_permutation = perm;
+               if (!r_cg_permutation->vprogram && !r_cg_permutation->fprogram)
                {
-                       if (!r_glsl_permutation->compiled)
-                               R_GLSL_CompilePermutation(perm, mode, permutation);
-                       if (!r_glsl_permutation->program)
+                       if (!r_cg_permutation->compiled)
+                               R_CG_CompilePermutation(perm, mode, permutation);
+                       if (!r_cg_permutation->vprogram && !r_cg_permutation->fprogram)
                        {
                                // remove features until we find a valid permutation
                                int i;
@@ -2015,96 +4174,258 @@ void R_SetupShader_SetPermutation(unsigned int mode, unsigned int permutation)
                                        if (!(permutation & j))
                                                continue;
                                        permutation -= j;
-                                       r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
-                                       if (!r_glsl_permutation->compiled)
-                                               R_GLSL_CompilePermutation(perm, mode, permutation);
-                                       if (r_glsl_permutation->program)
+                                       r_cg_permutation = R_CG_FindPermutation(mode, permutation);
+                                       if (!r_cg_permutation->compiled)
+                                               R_CG_CompilePermutation(perm, mode, permutation);
+                                       if (r_cg_permutation->vprogram || r_cg_permutation->fprogram)
                                                break;
                                }
                                if (i >= SHADERPERMUTATION_COUNT)
                                {
-                                       Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].vertexfilename, shadermodeinfo[mode].pretext);
-                                       r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
-                                       qglUseProgramObjectARB(0);CHECKGLERROR
+                                       //Con_Printf("Could not find a working Cg shader for permutation %s %s\n", shadermodeinfo[mode].vertexfilename, shadermodeinfo[mode].pretext);
+                                       r_cg_permutation = R_CG_FindPermutation(mode, permutation);
                                        return; // no bit left to clear, entire mode is broken
                                }
                        }
                }
                CHECKGLERROR
-               qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR
+               CHECKCGERROR
+               if (r_cg_permutation->vprogram)
+               {
+                       cgGLLoadProgram(r_cg_permutation->vprogram);CHECKCGERROR CHECKGLERROR
+                       cgGLBindProgram(r_cg_permutation->vprogram);CHECKCGERROR CHECKGLERROR
+                       cgGLEnableProfile(cgGLGetLatestProfile(CG_GL_VERTEX));CHECKCGERROR CHECKGLERROR
+               }
+               else
+               {
+                       cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_VERTEX));CHECKCGERROR CHECKGLERROR
+                       cgGLUnbindProgram(cgGLGetLatestProfile(CG_GL_VERTEX));CHECKCGERROR CHECKGLERROR
+               }
+               if (r_cg_permutation->fprogram)
+               {
+                       cgGLLoadProgram(r_cg_permutation->fprogram);CHECKCGERROR CHECKGLERROR
+                       cgGLBindProgram(r_cg_permutation->fprogram);CHECKCGERROR CHECKGLERROR
+                       cgGLEnableProfile(cgGLGetLatestProfile(CG_GL_FRAGMENT));CHECKCGERROR CHECKGLERROR
+               }
+               else
+               {
+                       cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_FRAGMENT));CHECKCGERROR CHECKGLERROR
+                       cgGLUnbindProgram(cgGLGetLatestProfile(CG_GL_FRAGMENT));CHECKCGERROR CHECKGLERROR
+               }
        }
+       CHECKCGERROR
+       if (r_cg_permutation->vp_ModelViewProjectionMatrix) cgGLSetMatrixParameterfc(r_cg_permutation->vp_ModelViewProjectionMatrix, gl_modelviewprojection16f);CHECKCGERROR
+       if (r_cg_permutation->vp_ModelViewMatrix) cgGLSetMatrixParameterfc(r_cg_permutation->vp_ModelViewMatrix, gl_modelview16f);CHECKCGERROR
+       if (r_cg_permutation->fp_ClientTime) cgGLSetParameter1f(r_cg_permutation->fp_ClientTime, cl.time);CHECKCGERROR
+}
+
+void CG_BindTexture(CGparameter param, rtexture_t *tex)
+{
+       cgGLSetTextureParameter(param, R_GetTexture(tex));
+       cgGLEnableTextureParameter(param);
 }
+#endif
 
-void R_SetupGenericShader(qboolean usetexture)
+void R_GLSL_Restart_f(void)
 {
-       if (vid.support.arb_fragment_shader)
+       unsigned int i, limit;
+       if (glslshaderstring && glslshaderstring != builtinshaderstring)
+               Mem_Free(glslshaderstring);
+       glslshaderstring = NULL;
+       if (cgshaderstring && cgshaderstring != builtincgshaderstring)
+               Mem_Free(cgshaderstring);
+       cgshaderstring = NULL;
+       switch(vid.renderpath)
        {
-               if (r_glsl.integer)
-                       R_SetupShader_SetPermutation(SHADERMODE_GENERIC, usetexture ? SHADERPERMUTATION_DIFFUSE : 0);
-               else if (r_glsl_permutation)
+       case RENDERPATH_GL20:
                {
+                       r_glsl_permutation_t *p;
                        r_glsl_permutation = NULL;
-                       qglUseProgramObjectARB(0);CHECKGLERROR
+                       limit = Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
+                       for (i = 0;i < limit;i++)
+                       {
+                               if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
+                               {
+                                       GL_Backend_FreeProgram(p->program);
+                                       Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
+                               }
+                       }
+                       memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
+               }
+               break;
+       case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+               {
+                       r_cg_permutation_t *p;
+                       r_cg_permutation = NULL;
+                       cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_VERTEX));CHECKCGERROR CHECKGLERROR
+                       cgGLUnbindProgram(cgGLGetLatestProfile(CG_GL_VERTEX));CHECKCGERROR CHECKGLERROR
+                       cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_FRAGMENT));CHECKCGERROR CHECKGLERROR
+                       cgGLUnbindProgram(cgGLGetLatestProfile(CG_GL_FRAGMENT));CHECKCGERROR CHECKGLERROR
+                       limit = Mem_ExpandableArray_IndexRange(&r_cg_permutationarray);
+                       for (i = 0;i < limit;i++)
+                       {
+                               if ((p = (r_cg_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_cg_permutationarray, i)))
+                               {
+                                       if (p->vprogram)
+                                               cgDestroyProgram(p->vprogram);
+                                       if (p->fprogram)
+                                               cgDestroyProgram(p->fprogram);
+                                       Mem_ExpandableArray_FreeRecord(&r_cg_permutationarray, (void*)p);
+                               }
+                       }
+                       memset(r_cg_permutationhash, 0, sizeof(r_cg_permutationhash));
                }
+               break;
+#endif
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               break;
+       }
+}
+
+void R_GLSL_DumpShader_f(void)
+{
+       int i;
+       qfile_t *file;
+
+       file = FS_OpenRealFile("glsl/default.glsl", "w", false);
+       if (file)
+       {
+               FS_Print(file, "/* The engine may define the following macros:\n");
+               FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
+               for (i = 0;i < SHADERMODE_COUNT;i++)
+                       FS_Print(file, glslshadermodeinfo[i].pretext);
+               for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
+                       FS_Print(file, shaderpermutationinfo[i].pretext);
+               FS_Print(file, "*/\n");
+               FS_Print(file, builtinshaderstring);
+               FS_Close(file);
+               Con_Printf("glsl/default.glsl written\n");
+       }
+       else
+               Con_Printf("failed to write to glsl/default.glsl\n");
+
+#ifdef SUPPORTCG
+       file = FS_OpenRealFile("cg/default.cg", "w", false);
+       if (file)
+       {
+               FS_Print(file, "/* The engine may define the following macros:\n");
+               FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
+               for (i = 0;i < SHADERMODE_COUNT;i++)
+                       FS_Print(file, cgshadermodeinfo[i].pretext);
+               for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
+                       FS_Print(file, shaderpermutationinfo[i].pretext);
+               FS_Print(file, "*/\n");
+               FS_Print(file, builtincgshaderstring);
+               FS_Close(file);
+               Con_Printf("cg/default.cg written\n");
        }
+       else
+               Con_Printf("failed to write to cg/default.cg\n");
+#endif
 }
 
-void R_SetupGenericTwoTextureShader(int texturemode)
+void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale)
 {
-       if (vid.support.arb_fragment_shader)
+       if (!second)
+               texturemode = GL_MODULATE;
+       switch (vid.renderpath)
        {
-               if (r_glsl.integer)
-                       R_SetupShader_SetPermutation(SHADERMODE_GENERIC, SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | (r_shadow_glossexact.integer ? SHADERPERMUTATION_EXACTSPECULARMATH : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
-               else if (r_glsl_permutation)
-               {
-                       r_glsl_permutation = NULL;
-                       qglUseProgramObjectARB(0);CHECKGLERROR
-               }
+       case RENDERPATH_GL20:
+               R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, (first ? SHADERPERMUTATION_DIFFUSE : 0) | (second ? SHADERPERMUTATION_SPECULAR : 0) | (r_shadow_glossexact.integer ? SHADERPERMUTATION_EXACTSPECULARMATH : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
+               if (r_glsl_permutation->loc_Texture_First ) R_Mesh_TexBind(GL20TU_FIRST , first );
+               if (r_glsl_permutation->loc_Texture_Second) R_Mesh_TexBind(GL20TU_SECOND, second);
+               break;
+       case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+               CHECKCGERROR
+               R_SetupShader_SetPermutationCG(SHADERMODE_GENERIC, (first ? SHADERPERMUTATION_DIFFUSE : 0) | (second ? SHADERPERMUTATION_SPECULAR : 0) | (r_shadow_glossexact.integer ? SHADERPERMUTATION_EXACTSPECULARMATH : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
+               if (r_cg_permutation->fp_Texture_First ) CG_BindTexture(r_cg_permutation->fp_Texture_First , first );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Second) CG_BindTexture(r_cg_permutation->fp_Texture_Second, second);CHECKCGERROR
+#endif
+               break;
+       case RENDERPATH_GL13:
+               R_Mesh_TexBind(0, first );
+               R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+               R_Mesh_TexBind(1, second);
+               if (second)
+                       R_Mesh_TexCombine(1, texturemode, texturemode, rgbscale, 1);
+               break;
+       case RENDERPATH_GL11:
+               R_Mesh_TexBind(0, first );
+               break;
        }
-       if (!r_glsl_permutation)
-               R_Mesh_TexCombine(1, GL_DECAL, GL_DECAL, 1, 1);
 }
 
-void R_SetupDepthOrShadowShader(void)
+void R_SetupShader_DepthOrShadow(void)
 {
-       if (vid.support.arb_fragment_shader)
+       switch (vid.renderpath)
        {
-               if (r_glsl.integer)
-                       R_SetupShader_SetPermutation(SHADERMODE_DEPTH_OR_SHADOW, 0);
-               else if (r_glsl_permutation)
-               {
-                       r_glsl_permutation = NULL;
-                       qglUseProgramObjectARB(0);CHECKGLERROR
-               }
+       case RENDERPATH_GL20:
+               R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, 0);
+               break;
+       case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+               R_SetupShader_SetPermutationCG(SHADERMODE_DEPTH_OR_SHADOW, 0);
+#endif
+               break;
+       case RENDERPATH_GL13:
+               R_Mesh_TexBind(0, 0);
+               R_Mesh_TexBind(1, 0);
+               break;
+       case RENDERPATH_GL11:
+               R_Mesh_TexBind(0, 0);
+               break;
        }
 }
 
-void R_SetupShowDepthShader(void)
+void R_SetupShader_ShowDepth(void)
 {
-       if (vid.support.arb_fragment_shader)
+       switch (vid.renderpath)
        {
-               if (r_glsl.integer)
-                       R_SetupShader_SetPermutation(SHADERMODE_SHOWDEPTH, 0);
-               else if (r_glsl_permutation)
-               {
-                       r_glsl_permutation = NULL;
-                       qglUseProgramObjectARB(0);CHECKGLERROR
-               }
+       case RENDERPATH_GL20:
+               R_SetupShader_SetPermutationGLSL(SHADERMODE_SHOWDEPTH, 0);
+               break;
+       case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+               R_SetupShader_SetPermutationCG(SHADERMODE_SHOWDEPTH, 0);
+#endif
+               break;
+       case RENDERPATH_GL13:
+               break;
+       case RENDERPATH_GL11:
+               break;
        }
 }
 
+extern qboolean r_shadow_usingdeferredprepass;
+extern cvar_t r_shadow_deferred_8bitrange;
 extern rtexture_t *r_shadow_attenuationgradienttexture;
 extern rtexture_t *r_shadow_attenuation2dtexture;
 extern rtexture_t *r_shadow_attenuation3dtexture;
 extern qboolean r_shadow_usingshadowmaprect;
 extern qboolean r_shadow_usingshadowmapcube;
 extern qboolean r_shadow_usingshadowmap2d;
+extern qboolean r_shadow_usingshadowmaportho;
 extern float r_shadow_shadowmap_texturescale[2];
 extern float r_shadow_shadowmap_parameters[4];
 extern qboolean r_shadow_shadowmapvsdct;
 extern qboolean r_shadow_shadowmapsampler;
 extern int r_shadow_shadowmappcf;
-void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass)
+extern rtexture_t *r_shadow_shadowmaprectangletexture;
+extern rtexture_t *r_shadow_shadowmap2dtexture;
+extern rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
+extern rtexture_t *r_shadow_shadowmapvsdcttexture;
+extern matrix4x4_t r_shadow_shadowmapmatrix;
+extern int r_shadow_shadowmaplod; // changes for each light based on distance
+extern int r_shadow_prepass_width;
+extern int r_shadow_prepass_height;
+extern rtexture_t *r_shadow_prepassgeometrydepthtexture;
+extern rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
+extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
+extern rtexture_t *r_shadow_prepasslightingspeculartexture;
+void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass)
 {
        // select a permutation of the lighting shader appropriate to this
        // combination of texture, entity, light source, and fogging, only use the
@@ -2112,13 +4433,7 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
        // fragment shader on features that are not being used
        unsigned int permutation = 0;
        unsigned int mode = 0;
-       // TODO: implement geometry-shader based shadow volumes someday
-       if (r_glsl_offsetmapping.integer)
-       {
-               permutation |= SHADERPERMUTATION_OFFSETMAPPING;
-               if (r_glsl_offsetmapping_reliefmapping.integer)
-                       permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
-       }
+       float m16f[16];
        if (rsurfacepass == RSURFPASS_BACKGROUND)
        {
                // distorted background
@@ -2126,9 +4441,53 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                        mode = SHADERMODE_WATER;
                else
                        mode = SHADERMODE_REFRACTION;
+               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+               R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
+               R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
+               R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
+               R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0);
+               R_Mesh_ColorPointer(NULL, 0, 0);
+               GL_AlphaTest(false);
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+       }
+       else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
+       {
+               if (r_glsl_offsetmapping.integer)
+               {
+                       permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                       if (r_glsl_offsetmapping_reliefmapping.integer)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+               }
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
+                       permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
+                       permutation |= SHADERPERMUTATION_ALPHAKILL;
+               // normalmap (deferred prepass), may use alpha test on diffuse
+               mode = SHADERMODE_DEFERREDGEOMETRY;
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
+                       permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
+               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+               R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
+               R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
+               R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
+               R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0);
+               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND)
+                       R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
+               else
+                       R_Mesh_ColorPointer(NULL, 0, 0);
+               GL_AlphaTest(false);
+               GL_BlendFunc(GL_ONE, GL_ZERO);
        }
        else if (rsurfacepass == RSURFPASS_RTLIGHT)
        {
+               if (r_glsl_offsetmapping.integer)
+               {
+                       permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                       if (r_glsl_offsetmapping_reliefmapping.integer)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+               }
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
+                       permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
                // light source
                mode = SHADERMODE_LIGHTSOURCE;
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
@@ -2138,7 +4497,11 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                if (diffusescale > 0)
                        permutation |= SHADERPERMUTATION_DIFFUSE;
                if (specularscale > 0)
+               {
                        permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
+                       if (r_shadow_glossexact.integer)
+                               permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
+               }
                if (r_refdef.fogenabled)
                        permutation |= r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE;
                if (rsurface.texture->colormapping)
@@ -2161,64 +4524,247 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                        else if (r_shadow_shadowmappcf)
                                permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
                }
+               if (rsurface.texture->reflectmasktexture)
+                       permutation |= SHADERPERMUTATION_REFLECTCUBE;
+               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+               if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING))
+               {
+                       R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
+               }
+               else
+               {
+                       R_Mesh_TexCoordPointer(1, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(2, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(3, 0, NULL, 0, 0);
+               }
+               //R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0);
+               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND)
+                       R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
+               else
+                       R_Mesh_ColorPointer(NULL, 0, 0);
+               GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
        }
        else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
        {
-               // unshaded geometry (fullbright or ambient model lighting)
-               mode = SHADERMODE_FLATCOLOR;
+               if (r_glsl_offsetmapping.integer)
+               {
+                       permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                       if (r_glsl_offsetmapping_reliefmapping.integer)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+               }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
-               if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
+               // unshaded geometry (fullbright or ambient model lighting)
+               mode = SHADERMODE_FLATCOLOR;
+               ambientscale = diffusescale = specularscale = 0;
+               if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
                        permutation |= SHADERPERMUTATION_GLOW;
                if (r_refdef.fogenabled)
                        permutation |= r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE;
                if (rsurface.texture->colormapping)
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
-               if (r_glsl_offsetmapping.integer)
+               if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
                {
-                       permutation |= SHADERPERMUTATION_OFFSETMAPPING;
-                       if (r_glsl_offsetmapping_reliefmapping.integer)
-                               permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
+                       if (r_shadow_usingshadowmaprect)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
+                       if (r_shadow_usingshadowmap2d)
+                               permutation |= SHADERPERMUTATION_SHADOWMAP2D;
+
+                       if (r_shadow_shadowmapsampler)
+                               permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
+                       if (r_shadow_shadowmappcf > 1)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
+                       else if (r_shadow_shadowmappcf)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
+               if (rsurface.texture->reflectmasktexture)
+                       permutation |= SHADERPERMUTATION_REFLECTCUBE;
+               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+               if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING))
+               {
+                       R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
+               }
+               else
+               {
+                       R_Mesh_TexCoordPointer(1, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(2, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(3, 0, NULL, 0, 0);
+               }
+               R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0);
+               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND)
+                       R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
+               else
+                       R_Mesh_ColorPointer(NULL, 0, 0);
+               GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
+               GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
        }
        else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT_DIRECTIONAL)
        {
-               // directional model lighting
-               mode = SHADERMODE_LIGHTDIRECTION;
+               if (r_glsl_offsetmapping.integer)
+               {
+                       permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                       if (r_glsl_offsetmapping_reliefmapping.integer)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+               }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
-               if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
+               // directional model lighting
+               mode = SHADERMODE_LIGHTDIRECTION;
+               if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
                        permutation |= SHADERPERMUTATION_GLOW;
                permutation |= SHADERPERMUTATION_DIFFUSE;
                if (specularscale > 0)
+               {
                        permutation |= SHADERPERMUTATION_SPECULAR;
+                       if (r_shadow_glossexact.integer)
+                               permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
+               }
+               if (r_refdef.fogenabled)
+                       permutation |= 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;
+                       if (r_shadow_usingshadowmaprect)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
+                       if (r_shadow_usingshadowmap2d)
+                               permutation |= SHADERPERMUTATION_SHADOWMAP2D;
+
+                       if (r_shadow_shadowmapsampler)
+                               permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
+                       if (r_shadow_shadowmappcf > 1)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
+                       else if (r_shadow_shadowmappcf)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+               }
+               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;
+               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+               if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING))
+               {
+                       R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
+               }
+               else
+               {
+                       R_Mesh_TexCoordPointer(1, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(2, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(3, 0, NULL, 0, 0);
+               }
+               R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0);
+               R_Mesh_ColorPointer(NULL, 0, 0);
+               GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
+               GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
+       }
+       else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
+       {
+               if (r_glsl_offsetmapping.integer)
+               {
+                       permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                       if (r_glsl_offsetmapping_reliefmapping.integer)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+               }
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
+                       permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
+               // ambient model lighting
+               mode = SHADERMODE_LIGHTDIRECTION;
+               if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
+                       permutation |= SHADERPERMUTATION_GLOW;
                if (r_refdef.fogenabled)
                        permutation |= 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;
+                       if (r_shadow_usingshadowmaprect)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
+                       if (r_shadow_usingshadowmap2d)
+                               permutation |= SHADERPERMUTATION_SHADOWMAP2D;
+
+                       if (r_shadow_shadowmapsampler)
+                               permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
+                       if (r_shadow_shadowmappcf > 1)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
+                       else if (r_shadow_shadowmappcf)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+               }
                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;
+               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+               if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING))
+               {
+                       R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
+               }
+               else
+               {
+                       R_Mesh_TexCoordPointer(1, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(2, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(3, 0, NULL, 0, 0);
+               }
+               R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0);
+               R_Mesh_ColorPointer(NULL, 0, 0);
+               GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
+               GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
        }
-       else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
+       else
        {
-               // ambient model lighting
-               mode = SHADERMODE_LIGHTDIRECTION;
+               if (r_glsl_offsetmapping.integer)
+               {
+                       permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                       if (r_glsl_offsetmapping_reliefmapping.integer)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+               }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
-               if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
+               // lightmapped wall
+               if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
                        permutation |= SHADERPERMUTATION_GLOW;
                if (r_refdef.fogenabled)
                        permutation |= 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;
+                       if (r_shadow_usingshadowmaprect)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
+                       if (r_shadow_usingshadowmap2d)
+                               permutation |= SHADERPERMUTATION_SHADOWMAP2D;
+
+                       if (r_shadow_shadowmapsampler)
+                               permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
+                       if (r_shadow_shadowmappcf > 1)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
+                       else if (r_shadow_shadowmappcf)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+               }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
-       }
-       else
-       {
-               // lightmapped wall
+               if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
+                       permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
+               if (rsurface.texture->reflectmasktexture)
+                       permutation |= SHADERPERMUTATION_REFLECTCUBE;
                if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
                {
                        // deluxemapping (light direction texture)
@@ -2228,7 +4774,16 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                                mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
                        permutation |= SHADERPERMUTATION_DIFFUSE;
                        if (specularscale > 0)
+                       {
                                permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
+                               if (r_shadow_glossexact.integer)
+                                       permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
+                       }
+                       R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
+                       if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND)
+                               R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
+                       else
+                               R_Mesh_ColorPointer(NULL, 0, 0);
                }
                else if (r_glsl_deluxemapping.integer >= 2)
                {
@@ -2236,120 +4791,440 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                        mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
                        permutation |= SHADERPERMUTATION_DIFFUSE;
                        if (specularscale > 0)
+                       {
                                permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
+                               if (r_shadow_glossexact.integer)
+                                       permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
+                       }
+                       R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
+                       if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND)
+                               R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
+                       else
+                               R_Mesh_ColorPointer(NULL, 0, 0);
                }
                else if (rsurface.uselightmaptexture)
                {
                        // ordinary lightmapping (q1bsp, q3bsp)
                        mode = SHADERMODE_LIGHTMAP;
+                       R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
+                       if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND)
+                               R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
+                       else
+                               R_Mesh_ColorPointer(NULL, 0, 0);
                }
                else
                {
                        // ordinary vertex coloring (q3bsp)
                        mode = SHADERMODE_VERTEXCOLOR;
+                       R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0);
+                       R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
                }
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
-                       permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
-               if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
-                       permutation |= SHADERPERMUTATION_GLOW;
-               if (r_refdef.fogenabled)
-                       permutation |= r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE;
-               if (rsurface.texture->colormapping)
-                       permutation |= SHADERPERMUTATION_COLORMAPPING;
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
-                       permutation |= SHADERPERMUTATION_REFLECTION;
-       }
-       if(permutation & SHADERPERMUTATION_SPECULAR)
-               if(r_shadow_glossexact.integer)
-                       permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
-       R_SetupShader_SetPermutation(mode, permutation);
-       if (mode == SHADERMODE_LIGHTSOURCE)
-       {
-               if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
-               if (permutation & SHADERPERMUTATION_DIFFUSE)
+               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+               if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING))
                {
-                       if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2], rsurface.texture->lightmapcolor[3]);
-                       if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, ambientscale);
-                       if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, diffusescale);
-                       if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, specularscale);
+                       R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
                }
                else
                {
-                       // ambient only is simpler
-                       if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, lightcolorbase[0] * ambientscale, lightcolorbase[1] * ambientscale, lightcolorbase[2] * ambientscale, rsurface.texture->lightmapcolor[3]);
-                       if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, 1);
-                       if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, 0);
-                       if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, 0);
+                       R_Mesh_TexCoordPointer(1, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(2, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(3, 0, NULL, 0, 0);
                }
-               // additive passes are only darkened by fog, not tinted
-               if (r_glsl_permutation->loc_FogColor >= 0)
-                       qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
-               if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2fARB(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
-               if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4fARB(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+               GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
+               GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
        }
-       else
-       {
-               if (mode == SHADERMODE_LIGHTDIRECTION)
-               {
-                       if (r_glsl_permutation->loc_AmbientColor  >= 0) qglUniform3fARB(r_glsl_permutation->loc_AmbientColor , rsurface.modellight_ambient[0] * ambientscale  * 0.5f, rsurface.modellight_ambient[1] * ambientscale  * 0.5f, rsurface.modellight_ambient[2] * ambientscale  * 0.5f);
-                       if (r_glsl_permutation->loc_DiffuseColor  >= 0) qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor , rsurface.modellight_diffuse[0] * diffusescale  * 0.5f, rsurface.modellight_diffuse[1] * diffusescale  * 0.5f, rsurface.modellight_diffuse[2] * diffusescale  * 0.5f);
-                       if (r_glsl_permutation->loc_SpecularColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, rsurface.modellight_diffuse[0] * specularscale * 0.5f, rsurface.modellight_diffuse[1] * specularscale * 0.5f, rsurface.modellight_diffuse[2] * specularscale * 0.5f);
-                       if (r_glsl_permutation->loc_LightDir      >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
+       switch(vid.renderpath)
+       {
+       case RENDERPATH_GL20:
+               R_SetupShader_SetPermutationGLSL(mode, permutation);
+               if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
+               if (mode == SHADERMODE_LIGHTSOURCE)
+               {
+                       if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
+                       if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
+                       if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);
+                       if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Ambient, rsurface.colormod[0] * ambientscale, rsurface.colormod[1] * ambientscale, rsurface.colormod[2] * ambientscale);
+                       if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Diffuse, rsurface.colormod[0] * diffusescale, rsurface.colormod[1] * diffusescale, rsurface.colormod[2] * diffusescale);
+                       if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Specular, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale);
+       
+                       // additive passes are only darkened by fog, not tinted
+                       if (r_glsl_permutation->loc_FogColor >= 0)
+                               qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
+                       if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));
                }
                else
                {
-                       if (r_glsl_permutation->loc_AmbientScale  >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, r_refdef.scene.ambient * 1.0f / 128.0f);
-                       if (r_glsl_permutation->loc_DiffuseScale  >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_refdef.lightmapintensity);
-                       if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale);
+                       if (mode == SHADERMODE_FLATCOLOR)
+                       {
+                               if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Ambient, rsurface.colormod[0], rsurface.colormod[1], rsurface.colormod[2]);
+                       }
+                       else if (mode == SHADERMODE_LIGHTDIRECTION)
+                       {
+                               if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Ambient, (r_refdef.scene.ambient + rsurface.modellight_ambient[0] * r_refdef.lightmapintensity) * rsurface.colormod[0], (r_refdef.scene.ambient + rsurface.modellight_ambient[1] * r_refdef.lightmapintensity) * rsurface.colormod[1], (r_refdef.scene.ambient + rsurface.modellight_ambient[2] * r_refdef.lightmapintensity) * rsurface.colormod[2]);
+                               if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Diffuse, r_refdef.lightmapintensity * rsurface.colormod[0], r_refdef.lightmapintensity * rsurface.colormod[1], r_refdef.lightmapintensity * rsurface.colormod[2]);
+                               if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3fARB(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) qglUniform3fARB(r_glsl_permutation->loc_DeferredMod_Diffuse, rsurface.colormod[0] * r_shadow_deferred_8bitrange.value, rsurface.colormod[1] * r_shadow_deferred_8bitrange.value, rsurface.colormod[2] * r_shadow_deferred_8bitrange.value);
+                               if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3fARB(r_glsl_permutation->loc_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value);
+                               if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, rsurface.modellight_diffuse[0], rsurface.modellight_diffuse[1], rsurface.modellight_diffuse[2]);
+                               if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
+                       }
+                       else
+                       {
+                               if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Ambient, r_refdef.scene.ambient * rsurface.colormod[0], r_refdef.scene.ambient * rsurface.colormod[1], r_refdef.scene.ambient * rsurface.colormod[2]);
+                               if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3fARB(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) qglUniform3fARB(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) qglUniform3fARB(r_glsl_permutation->loc_DeferredMod_Diffuse, rsurface.colormod[0] * diffusescale * r_shadow_deferred_8bitrange.value, rsurface.colormod[1] * diffusescale * r_shadow_deferred_8bitrange.value, rsurface.colormod[2] * diffusescale * r_shadow_deferred_8bitrange.value);
+                               if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3fARB(r_glsl_permutation->loc_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value);
+                       }
+                       // additive passes are only darkened by fog, not tinted
+                       if (r_glsl_permutation->loc_FogColor >= 0)
+                       {
+                               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD)
+                                       qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
+                               else
+                                       qglUniform3fARB(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
+                       }
+                       if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4fARB(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_ScreenScaleRefractReflect >= 0) qglUniform4fARB(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_waterstate.screenscale[0], r_waterstate.screenscale[1], r_waterstate.screenscale[0], r_waterstate.screenscale[1]);
+                       if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4fARB(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_waterstate.screencenter[0], r_waterstate.screencenter[1], r_waterstate.screencenter[0], r_waterstate.screencenter[1]);
+                       if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_RefractColor, 1, rsurface.texture->refractcolor4f);
+                       if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_ReflectColor, 1, rsurface.texture->reflectcolor4f);
+                       if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin);
+                       if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectOffset, rsurface.texture->reflectmin);
+                       if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));
+               }
+               if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
+               if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
+               if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
+               if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2fARB(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
+               if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4fARB(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+
+               if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]);
+               if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1fARB(r_glsl_permutation->loc_Alpha, rsurface.texture->lightmapcolor[3]);
+               if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(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)
+                               qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
+                       else
+                               qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
                }
-               if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2], rsurface.texture->lightmapcolor[3]);
-               if (r_glsl_permutation->loc_GlowColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_GlowColor, rsurface.glowmod[0] * r_hdr_glowintensity.value, rsurface.glowmod[1] * r_hdr_glowintensity.value, rsurface.glowmod[2] * r_hdr_glowintensity.value);
-               // additive passes are only darkened by fog, not tinted
-               if (r_glsl_permutation->loc_FogColor >= 0)
+               if (r_glsl_permutation->loc_Color_Shirt >= 0)
                {
-                       if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD)
-                               qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
+                       if (rsurface.texture->shirttexture)
+                               qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]);
                        else
-                               qglUniform3fARB(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
-               }
-               if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4fARB(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_ScreenScaleRefractReflect >= 0) qglUniform4fARB(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_waterstate.screenscale[0], r_waterstate.screenscale[1], r_waterstate.screenscale[0], r_waterstate.screenscale[1]);
-               if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4fARB(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_waterstate.screencenter[0], r_waterstate.screencenter[1], r_waterstate.screencenter[0], r_waterstate.screencenter[1]);
-               if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_RefractColor, 1, rsurface.texture->refractcolor4f);
-               if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_ReflectColor, 1, rsurface.texture->reflectcolor4f);
-               if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin);
-               if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectOffset, rsurface.texture->reflectmin);
-       }
-       if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_refdef.view.colorscale);
-       if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(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->currentskinframe->pants)
-                       qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
+                               qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
+               }
+               if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4fARB(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
+               if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
+               if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
+               if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
+               if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
+               if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2fARB(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
+               if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2fARB(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
+
+       //      if (r_glsl_permutation->loc_Texture_First           >= 0) R_Mesh_TexBind(GL20TU_FIRST             , r_texture_white                                     );
+       //      if (r_glsl_permutation->loc_Texture_Second          >= 0) R_Mesh_TexBind(GL20TU_SECOND            , r_texture_white                                     );
+       //      if (r_glsl_permutation->loc_Texture_GammaRamps      >= 0) R_Mesh_TexBind(GL20TU_GAMMARAMPS        , r_texture_gammaramps                                );
+               if (r_glsl_permutation->loc_Texture_Normal          >= 0) R_Mesh_TexBind(GL20TU_NORMAL            , rsurface.texture->nmaptexture                       );
+               if (r_glsl_permutation->loc_Texture_Color           >= 0) R_Mesh_TexBind(GL20TU_COLOR             , rsurface.texture->basetexture                       );
+               if (r_glsl_permutation->loc_Texture_Gloss           >= 0) R_Mesh_TexBind(GL20TU_GLOSS             , rsurface.texture->glosstexture                      );
+               if (r_glsl_permutation->loc_Texture_Glow            >= 0) R_Mesh_TexBind(GL20TU_GLOW              , rsurface.texture->glowtexture                       );
+               if (r_glsl_permutation->loc_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL  , rsurface.texture->backgroundnmaptexture             );
+               if (r_glsl_permutation->loc_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(GL20TU_SECONDARY_COLOR   , rsurface.texture->backgroundbasetexture             );
+               if (r_glsl_permutation->loc_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS   , rsurface.texture->backgroundglosstexture            );
+               if (r_glsl_permutation->loc_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(GL20TU_SECONDARY_GLOW    , rsurface.texture->backgroundglowtexture             );
+               if (r_glsl_permutation->loc_Texture_Pants           >= 0) R_Mesh_TexBind(GL20TU_PANTS             , rsurface.texture->pantstexture                      );
+               if (r_glsl_permutation->loc_Texture_Shirt           >= 0) R_Mesh_TexBind(GL20TU_SHIRT             , rsurface.texture->shirttexture                      );
+               if (r_glsl_permutation->loc_Texture_ReflectMask     >= 0) R_Mesh_TexBind(GL20TU_REFLECTMASK       , rsurface.texture->reflectmasktexture                );
+               if (r_glsl_permutation->loc_Texture_ReflectCube     >= 0) R_Mesh_TexBind(GL20TU_REFLECTCUBE       , rsurface.texture->reflectcubetexture ? rsurface.texture->reflectcubetexture : r_texture_whitecube);
+               if (r_glsl_permutation->loc_Texture_FogMask         >= 0) R_Mesh_TexBind(GL20TU_FOGMASK           , r_texture_fogattenuation                            );
+               if (r_glsl_permutation->loc_Texture_Lightmap        >= 0) R_Mesh_TexBind(GL20TU_LIGHTMAP          , r_texture_white                                     );
+               if (r_glsl_permutation->loc_Texture_Deluxemap       >= 0) R_Mesh_TexBind(GL20TU_LIGHTMAP          , r_texture_blanknormalmap                            );
+               if (r_glsl_permutation->loc_Texture_Attenuation     >= 0) R_Mesh_TexBind(GL20TU_ATTENUATION       , r_shadow_attenuationgradienttexture                 );
+               if (r_glsl_permutation->loc_Texture_Refraction      >= 0) R_Mesh_TexBind(GL20TU_REFRACTION        , r_texture_white                                     );
+               if (r_glsl_permutation->loc_Texture_Reflection      >= 0) R_Mesh_TexBind(GL20TU_REFLECTION        , r_texture_white                                     );
+               if (r_glsl_permutation->loc_Texture_ScreenDepth     >= 0) R_Mesh_TexBind(GL20TU_SCREENDEPTH       , r_shadow_prepassgeometrydepthtexture                );
+               if (r_glsl_permutation->loc_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(GL20TU_SCREENNORMALMAP   , r_shadow_prepassgeometrynormalmaptexture            );
+               if (r_glsl_permutation->loc_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(GL20TU_SCREENDIFFUSE     , r_shadow_prepasslightingdiffusetexture              );
+               if (r_glsl_permutation->loc_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(GL20TU_SCREENSPECULAR    , r_shadow_prepasslightingspeculartexture             );
+               if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
+               {
+                       if (r_glsl_permutation->loc_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_shadow_usingshadowmaportho ? GL20TU_SHADOWMAPORTHO2D : GL20TU_SHADOWMAP2D, r_shadow_shadowmap2dtexture                         );
+                       if (r_glsl_permutation->loc_Texture_ShadowMapRect   >= 0) R_Mesh_TexBind(r_shadow_usingshadowmaportho ? GL20TU_SHADOWMAPORTHORECT : GL20TU_SHADOWMAPRECT, r_shadow_shadowmaprectangletexture                  );
+                       if (rsurface.rtlight)
+                       {
+                               if (r_glsl_permutation->loc_Texture_Cube            >= 0) R_Mesh_TexBind(GL20TU_CUBE              , rsurface.rtlight->currentcubemap                    );
+                               if (r_shadow_usingshadowmapcube)
+                                       if (r_glsl_permutation->loc_Texture_ShadowMapCube   >= 0) R_Mesh_TexBind(GL20TU_SHADOWMAPCUBE     , r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
+                               if (r_glsl_permutation->loc_Texture_CubeProjection  >= 0) R_Mesh_TexBind(GL20TU_CUBEPROJECTION    , r_shadow_shadowmapvsdcttexture                      );
+                       }
+               }
+               CHECKGLERROR
+               break;
+       case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+               R_SetupShader_SetPermutationCG(mode, permutation);
+               if (r_cg_permutation->fp_ModelToReflectCube) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);cgGLSetMatrixParameterfc(r_cg_permutation->fp_ModelToReflectCube, m16f);}CHECKCGERROR
+               if (mode == SHADERMODE_LIGHTSOURCE)
+               {
+                       if (r_cg_permutation->vp_ModelToLight) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);cgGLSetMatrixParameterfc(r_cg_permutation->vp_ModelToLight, m16f);}CHECKCGERROR
+                       if (r_cg_permutation->vp_LightPosition) cgGLSetParameter3f(r_cg_permutation->vp_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);CHECKCGERROR
+               }
                else
-                       qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
-       }
-       if (r_glsl_permutation->loc_Color_Shirt >= 0)
-       {
-               if (rsurface.texture->currentskinframe->shirt)
-                       qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]);
+               {
+                       if (mode == SHADERMODE_LIGHTDIRECTION)
+                       {
+                               if (r_cg_permutation->vp_LightDir) cgGLSetParameter3f(r_cg_permutation->vp_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);CHECKCGERROR
+                       }
+               }
+               if (r_cg_permutation->vp_TexMatrix) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);cgGLSetMatrixParameterfc(r_cg_permutation->vp_TexMatrix, m16f);}CHECKCGERROR
+               if (r_cg_permutation->vp_BackgroundTexMatrix) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);cgGLSetMatrixParameterfc(r_cg_permutation->vp_BackgroundTexMatrix, m16f);}CHECKCGERROR
+               if (r_cg_permutation->vp_ShadowMapMatrix) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);cgGLSetMatrixParameterfc(r_cg_permutation->vp_ShadowMapMatrix, m16f);}CHECKGLERROR
+               if (r_cg_permutation->vp_EyePosition) cgGLSetParameter3f(r_cg_permutation->vp_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);CHECKCGERROR
+               if (r_cg_permutation->vp_FogPlane) cgGLSetParameter4f(r_cg_permutation->vp_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);CHECKCGERROR
+               CHECKGLERROR
+
+               if (mode == SHADERMODE_LIGHTSOURCE)
+               {
+                       if (r_cg_permutation->fp_LightPosition) cgGLSetParameter3f(r_cg_permutation->fp_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);CHECKCGERROR
+                       if (r_cg_permutation->fp_LightColor) cgGLSetParameter3f(r_cg_permutation->fp_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKCGERROR
+                       if (r_cg_permutation->fp_Color_Ambient) cgGLSetParameter3f(r_cg_permutation->fp_Color_Ambient, rsurface.colormod[0] * ambientscale, rsurface.colormod[1] * ambientscale, rsurface.colormod[2] * ambientscale);CHECKCGERROR
+                       if (r_cg_permutation->fp_Color_Diffuse) cgGLSetParameter3f(r_cg_permutation->fp_Color_Diffuse, rsurface.colormod[0] * diffusescale, rsurface.colormod[1] * diffusescale, rsurface.colormod[2] * diffusescale);CHECKCGERROR
+                       if (r_cg_permutation->fp_Color_Specular) cgGLSetParameter3f(r_cg_permutation->fp_Color_Specular, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale);CHECKCGERROR
+
+                       // additive passes are only darkened by fog, not tinted
+                       if (r_cg_permutation->fp_FogColor) cgGLSetParameter3f(r_cg_permutation->fp_FogColor, 0, 0, 0);CHECKCGERROR
+                       if (r_cg_permutation->fp_SpecularPower) cgGLSetParameter1f(r_cg_permutation->fp_SpecularPower, rsurface.texture->specularpower * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));CHECKCGERROR
+               }
                else
-                       qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
+               {
+                       if (mode == SHADERMODE_FLATCOLOR)
+                       {
+                               if (r_cg_permutation->fp_Color_Ambient) cgGLSetParameter3f(r_cg_permutation->fp_Color_Ambient, rsurface.colormod[0], rsurface.colormod[1], rsurface.colormod[2]);CHECKCGERROR
+                       }
+                       else if (mode == SHADERMODE_LIGHTDIRECTION)
+                       {
+                               if (r_cg_permutation->fp_Color_Ambient) cgGLSetParameter3f(r_cg_permutation->fp_Color_Ambient, (r_refdef.scene.ambient + rsurface.modellight_ambient[0] * r_refdef.lightmapintensity) * rsurface.colormod[0], (r_refdef.scene.ambient + rsurface.modellight_ambient[1] * r_refdef.lightmapintensity) * rsurface.colormod[1], (r_refdef.scene.ambient + rsurface.modellight_ambient[2] * r_refdef.lightmapintensity) * rsurface.colormod[2]);CHECKCGERROR
+                               if (r_cg_permutation->fp_Color_Diffuse) cgGLSetParameter3f(r_cg_permutation->fp_Color_Diffuse, r_refdef.lightmapintensity * rsurface.colormod[0], r_refdef.lightmapintensity * rsurface.colormod[1], r_refdef.lightmapintensity * rsurface.colormod[2]);CHECKCGERROR
+                               if (r_cg_permutation->fp_Color_Specular) cgGLSetParameter3f(r_cg_permutation->fp_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);CHECKCGERROR
+                               if (r_cg_permutation->fp_DeferredMod_Diffuse) cgGLSetParameter3f(r_cg_permutation->fp_DeferredMod_Diffuse, rsurface.colormod[0] * r_shadow_deferred_8bitrange.value, rsurface.colormod[1] * r_shadow_deferred_8bitrange.value, rsurface.colormod[2] * r_shadow_deferred_8bitrange.value);CHECKCGERROR
+                               if (r_cg_permutation->fp_DeferredMod_Specular) cgGLSetParameter3f(r_cg_permutation->fp_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value);CHECKCGERROR
+                               if (r_cg_permutation->fp_LightColor) cgGLSetParameter3f(r_cg_permutation->fp_LightColor, rsurface.modellight_diffuse[0], rsurface.modellight_diffuse[1], rsurface.modellight_diffuse[2]);CHECKCGERROR
+                               if (r_cg_permutation->fp_LightDir) cgGLSetParameter3f(r_cg_permutation->fp_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);CHECKCGERROR
+                       }
+                       else
+                       {
+                               if (r_cg_permutation->fp_Color_Ambient) cgGLSetParameter3f(r_cg_permutation->fp_Color_Ambient, r_refdef.scene.ambient * rsurface.colormod[0], r_refdef.scene.ambient * rsurface.colormod[1], r_refdef.scene.ambient * rsurface.colormod[2]);CHECKCGERROR
+                               if (r_cg_permutation->fp_Color_Diffuse) cgGLSetParameter3f(r_cg_permutation->fp_Color_Diffuse, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2]);CHECKCGERROR
+                               if (r_cg_permutation->fp_Color_Specular) cgGLSetParameter3f(r_cg_permutation->fp_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);CHECKCGERROR
+                               if (r_cg_permutation->fp_DeferredMod_Diffuse) cgGLSetParameter3f(r_cg_permutation->fp_DeferredMod_Diffuse, rsurface.colormod[0] * diffusescale * r_shadow_deferred_8bitrange.value, rsurface.colormod[1] * diffusescale * r_shadow_deferred_8bitrange.value, rsurface.colormod[2] * diffusescale * r_shadow_deferred_8bitrange.value);CHECKCGERROR
+                               if (r_cg_permutation->fp_DeferredMod_Specular) cgGLSetParameter3f(r_cg_permutation->fp_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value);CHECKCGERROR
+                       }
+                       // additive passes are only darkened by fog, not tinted
+                       if (r_cg_permutation->fp_FogColor)
+                       {
+                               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD)
+                                       cgGLSetParameter3f(r_cg_permutation->fp_FogColor, 0, 0, 0);
+                               else
+                                       cgGLSetParameter3f(r_cg_permutation->fp_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
+                               CHECKCGERROR
+                       }
+                       if (r_cg_permutation->fp_DistortScaleRefractReflect) cgGLSetParameter4f(r_cg_permutation->fp_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);CHECKCGERROR
+                       if (r_cg_permutation->fp_ScreenScaleRefractReflect) cgGLSetParameter4f(r_cg_permutation->fp_ScreenScaleRefractReflect, r_waterstate.screenscale[0], r_waterstate.screenscale[1], r_waterstate.screenscale[0], r_waterstate.screenscale[1]);CHECKCGERROR
+                       if (r_cg_permutation->fp_ScreenCenterRefractReflect) cgGLSetParameter4f(r_cg_permutation->fp_ScreenCenterRefractReflect, r_waterstate.screencenter[0], r_waterstate.screencenter[1], r_waterstate.screencenter[0], r_waterstate.screencenter[1]);CHECKCGERROR
+                       if (r_cg_permutation->fp_RefractColor) cgGLSetParameter4fv(r_cg_permutation->fp_RefractColor, rsurface.texture->refractcolor4f);CHECKCGERROR
+                       if (r_cg_permutation->fp_ReflectColor) cgGLSetParameter4fv(r_cg_permutation->fp_ReflectColor, rsurface.texture->reflectcolor4f);CHECKCGERROR
+                       if (r_cg_permutation->fp_ReflectFactor) cgGLSetParameter1f(r_cg_permutation->fp_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin);CHECKCGERROR
+                       if (r_cg_permutation->fp_ReflectOffset) cgGLSetParameter1f(r_cg_permutation->fp_ReflectOffset, rsurface.texture->reflectmin);CHECKCGERROR
+                       if (r_cg_permutation->fp_SpecularPower) cgGLSetParameter1f(r_cg_permutation->fp_SpecularPower, rsurface.texture->specularpower * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));CHECKCGERROR
+               }
+               if (r_cg_permutation->fp_ShadowMap_TextureScale) cgGLSetParameter2f(r_cg_permutation->fp_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);CHECKCGERROR
+               if (r_cg_permutation->fp_ShadowMap_Parameters) cgGLSetParameter4f(r_cg_permutation->fp_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);CHECKCGERROR
+               if (r_cg_permutation->fp_Color_Glow) cgGLSetParameter3f(r_cg_permutation->fp_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]);CHECKCGERROR
+               if (r_cg_permutation->fp_Alpha) cgGLSetParameter1f(r_cg_permutation->fp_Alpha, rsurface.texture->lightmapcolor[3]);CHECKCGERROR
+               if (r_cg_permutation->fp_EyePosition) cgGLSetParameter3f(r_cg_permutation->fp_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);CHECKCGERROR
+               if (r_cg_permutation->fp_Color_Pants)
+               {
+                       if (rsurface.texture->pantstexture)
+                               cgGLSetParameter3f(r_cg_permutation->fp_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
+                       else
+                               cgGLSetParameter3f(r_cg_permutation->fp_Color_Pants, 0, 0, 0);
+                       CHECKCGERROR
+               }
+               if (r_cg_permutation->fp_Color_Shirt)
+               {
+                       if (rsurface.texture->shirttexture)
+                               cgGLSetParameter3f(r_cg_permutation->fp_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]);
+                       else
+                               cgGLSetParameter3f(r_cg_permutation->fp_Color_Shirt, 0, 0, 0);
+                       CHECKCGERROR
+               }
+               if (r_cg_permutation->fp_FogPlane) cgGLSetParameter4f(r_cg_permutation->fp_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);CHECKCGERROR
+               if (r_cg_permutation->fp_FogPlaneViewDist) cgGLSetParameter1f(r_cg_permutation->fp_FogPlaneViewDist, rsurface.fogplaneviewdist);CHECKCGERROR
+               if (r_cg_permutation->fp_FogRangeRecip) cgGLSetParameter1f(r_cg_permutation->fp_FogRangeRecip, rsurface.fograngerecip);CHECKCGERROR
+               if (r_cg_permutation->fp_FogHeightFade) cgGLSetParameter1f(r_cg_permutation->fp_FogHeightFade, rsurface.fogheightfade);CHECKCGERROR
+               if (r_cg_permutation->fp_OffsetMapping_Scale) cgGLSetParameter1f(r_cg_permutation->fp_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);CHECKCGERROR
+               if (r_cg_permutation->fp_ScreenToDepth) cgGLSetParameter2f(r_cg_permutation->fp_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);CHECKCGERROR
+               if (r_cg_permutation->fp_PixelToScreenTexCoord) cgGLSetParameter2f(r_cg_permutation->fp_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height);CHECKCGERROR
+
+       //      if (r_cg_permutation->fp_Texture_First          ) CG_BindTexture(r_cg_permutation->fp_Texture_First          , r_texture_white                                     );CHECKCGERROR
+       //      if (r_cg_permutation->fp_Texture_Second         ) CG_BindTexture(r_cg_permutation->fp_Texture_Second         , r_texture_white                                     );CHECKCGERROR
+       //      if (r_cg_permutation->fp_Texture_GammaRamps     ) CG_BindTexture(r_cg_permutation->fp_Texture_GammaRamps     , r_texture_gammaramps                                );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Normal         ) CG_BindTexture(r_cg_permutation->fp_Texture_Normal         , rsurface.texture->nmaptexture                       );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Color          ) CG_BindTexture(r_cg_permutation->fp_Texture_Color          , rsurface.texture->basetexture                       );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Gloss          ) CG_BindTexture(r_cg_permutation->fp_Texture_Gloss          , rsurface.texture->glosstexture                      );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Glow           ) CG_BindTexture(r_cg_permutation->fp_Texture_Glow           , rsurface.texture->glowtexture                       );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_SecondaryNormal) CG_BindTexture(r_cg_permutation->fp_Texture_SecondaryNormal, rsurface.texture->backgroundnmaptexture             );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_SecondaryColor ) CG_BindTexture(r_cg_permutation->fp_Texture_SecondaryColor , rsurface.texture->backgroundbasetexture             );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_SecondaryGloss ) CG_BindTexture(r_cg_permutation->fp_Texture_SecondaryGloss , rsurface.texture->backgroundglosstexture            );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_SecondaryGlow  ) CG_BindTexture(r_cg_permutation->fp_Texture_SecondaryGlow  , rsurface.texture->backgroundglowtexture             );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Pants          ) CG_BindTexture(r_cg_permutation->fp_Texture_Pants          , rsurface.texture->pantstexture                      );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Shirt          ) CG_BindTexture(r_cg_permutation->fp_Texture_Shirt          , rsurface.texture->shirttexture                      );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ReflectMask    ) CG_BindTexture(r_cg_permutation->fp_Texture_ReflectMask    , rsurface.texture->reflectmasktexture                );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ReflectCube    ) CG_BindTexture(r_cg_permutation->fp_Texture_ReflectCube    , rsurface.texture->reflectcubetexture ? rsurface.texture->reflectcubetexture : r_texture_whitecube);CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_FogMask        ) CG_BindTexture(r_cg_permutation->fp_Texture_FogMask        , r_texture_fogattenuation                            );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Lightmap       ) CG_BindTexture(r_cg_permutation->fp_Texture_Lightmap       , r_texture_white                                     );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Deluxemap      ) CG_BindTexture(r_cg_permutation->fp_Texture_Deluxemap      , r_texture_blanknormalmap                            );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Attenuation    ) CG_BindTexture(r_cg_permutation->fp_Texture_Attenuation    , r_shadow_attenuationgradienttexture                 );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Refraction     ) CG_BindTexture(r_cg_permutation->fp_Texture_Refraction     , r_texture_white                                     );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Reflection     ) CG_BindTexture(r_cg_permutation->fp_Texture_Reflection     , r_texture_white                                     );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ScreenDepth    ) CG_BindTexture(r_cg_permutation->fp_Texture_ScreenDepth    , r_shadow_prepassgeometrydepthtexture                );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ScreenNormalMap) CG_BindTexture(r_cg_permutation->fp_Texture_ScreenNormalMap, r_shadow_prepassgeometrynormalmaptexture            );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ScreenDiffuse  ) CG_BindTexture(r_cg_permutation->fp_Texture_ScreenDiffuse  , r_shadow_prepasslightingdiffusetexture              );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ScreenSpecular ) CG_BindTexture(r_cg_permutation->fp_Texture_ScreenSpecular , r_shadow_prepasslightingspeculartexture             );CHECKCGERROR
+               if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
+               {
+                       if (r_cg_permutation->fp_Texture_ShadowMap2D    ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMap2D    , r_shadow_shadowmap2dtexture                         );CHECKCGERROR
+                       if (r_cg_permutation->fp_Texture_ShadowMapRect  ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMapRect  , r_shadow_shadowmaprectangletexture                  );CHECKCGERROR
+                       if (rsurface.rtlight)
+                       {
+                               if (r_cg_permutation->fp_Texture_Cube           ) CG_BindTexture(r_cg_permutation->fp_Texture_Cube           , rsurface.rtlight->currentcubemap                    );CHECKCGERROR
+                               if (r_shadow_usingshadowmapcube)
+                                       if (r_cg_permutation->fp_Texture_ShadowMapCube  ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMapCube  , r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);CHECKCGERROR
+                               if (r_cg_permutation->fp_Texture_CubeProjection ) CG_BindTexture(r_cg_permutation->fp_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture                      );CHECKCGERROR
+                       }
+               }
+
+               CHECKGLERROR
+#endif
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               break;
        }
-       if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4fARB(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
-       if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
-       if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
-       if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
-       if(permutation & SHADERPERMUTATION_EXACTSPECULARMATH)
+}
+
+void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
+{
+       // select a permutation of the lighting shader appropriate to this
+       // combination of texture, entity, light source, and fogging, only use the
+       // minimum features necessary to avoid wasting rendering time in the
+       // fragment shader on features that are not being used
+       unsigned int permutation = 0;
+       unsigned int mode = 0;
+       const float *lightcolorbase = rtlight->currentcolor;
+       float ambientscale = rtlight->ambientscale;
+       float diffusescale = rtlight->diffusescale;
+       float specularscale = rtlight->specularscale;
+       // this is the location of the light in view space
+       vec3_t viewlightorigin;
+       // this transforms from view space (camera) to light space (cubemap)
+       matrix4x4_t viewtolight;
+       matrix4x4_t lighttoview;
+       float viewtolight16f[16];
+       float range = 1.0f / r_shadow_deferred_8bitrange.value;
+       // light source
+       mode = SHADERMODE_DEFERREDLIGHTSOURCE;
+       if (rtlight->currentcubemap != r_texture_whitecube)
+               permutation |= SHADERPERMUTATION_CUBEFILTER;
+       if (diffusescale > 0)
+               permutation |= SHADERPERMUTATION_DIFFUSE;
+       if (specularscale > 0)
        {
-               if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * 0.25);
+               permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
+               if (r_shadow_glossexact.integer)
+                       permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
        }
-       else
-       {
-               if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower);
+       if (r_shadow_usingshadowmaprect || r_shadow_usingshadowmap2d || r_shadow_usingshadowmapcube)
+       {
+               if (r_shadow_usingshadowmaprect)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
+               if (r_shadow_usingshadowmap2d)
+                       permutation |= SHADERPERMUTATION_SHADOWMAP2D;
+               if (r_shadow_usingshadowmapcube)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPCUBE;
+               else if(r_shadow_shadowmapvsdct)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
+
+               if (r_shadow_shadowmapsampler)
+                       permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
+               if (r_shadow_shadowmappcf > 1)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
+               else if (r_shadow_shadowmappcf)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+       }
+       Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
+       Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
+       Matrix4x4_Invert_Simple(&viewtolight, &lighttoview);
+       Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
+       switch(vid.renderpath)
+       {
+       case RENDERPATH_GL20:
+               R_SetupShader_SetPermutationGLSL(mode, permutation);
+               if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3fARB(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
+               if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fvARB(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
+               if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3fARB(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale  * range, lightcolorbase[1] * ambientscale  * range, lightcolorbase[2] * ambientscale  * range);
+               if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3fARB(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale  * range, lightcolorbase[1] * diffusescale  * range, lightcolorbase[2] * diffusescale  * range);
+               if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3fARB(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale * range, lightcolorbase[1] * specularscale * range, lightcolorbase[2] * specularscale * range);
+               if (r_glsl_permutation->loc_ShadowMap_TextureScale    >= 0) qglUniform2fARB(       r_glsl_permutation->loc_ShadowMap_TextureScale   , r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
+               if (r_glsl_permutation->loc_ShadowMap_Parameters      >= 0) qglUniform4fARB(       r_glsl_permutation->loc_ShadowMap_Parameters     , r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+               if (r_glsl_permutation->loc_SpecularPower             >= 0) qglUniform1fARB(       r_glsl_permutation->loc_SpecularPower            , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));
+               if (r_glsl_permutation->loc_ScreenToDepth             >= 0) qglUniform2fARB(       r_glsl_permutation->loc_ScreenToDepth            , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
+               if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2fARB(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
+
+               if (r_glsl_permutation->loc_Texture_Attenuation       >= 0) R_Mesh_TexBind(GL20TU_ATTENUATION        , r_shadow_attenuationgradienttexture                 );
+               if (r_glsl_permutation->loc_Texture_ScreenDepth       >= 0) R_Mesh_TexBind(GL20TU_SCREENDEPTH        , r_shadow_prepassgeometrydepthtexture                );
+               if (r_glsl_permutation->loc_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(GL20TU_SCREENNORMALMAP    , r_shadow_prepassgeometrynormalmaptexture            );
+               if (r_glsl_permutation->loc_Texture_Cube              >= 0) R_Mesh_TexBind(GL20TU_CUBE               , rsurface.rtlight->currentcubemap                    );
+               if (r_glsl_permutation->loc_Texture_ShadowMapRect     >= 0) R_Mesh_TexBind(GL20TU_SHADOWMAPRECT      , r_shadow_shadowmaprectangletexture                  );
+               if (r_shadow_usingshadowmapcube)
+                       if (r_glsl_permutation->loc_Texture_ShadowMapCube     >= 0) R_Mesh_TexBind(GL20TU_SHADOWMAPCUBE      , r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
+               if (r_glsl_permutation->loc_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(GL20TU_SHADOWMAP2D        , r_shadow_shadowmap2dtexture                         );
+               if (r_glsl_permutation->loc_Texture_CubeProjection    >= 0) R_Mesh_TexBind(GL20TU_CUBEPROJECTION     , r_shadow_shadowmapvsdcttexture                      );
+               break;
+       case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+               R_SetupShader_SetPermutationCG(mode, permutation);
+               if (r_cg_permutation->fp_LightPosition            ) cgGLSetParameter3f(r_cg_permutation->fp_LightPosition, viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);CHECKCGERROR
+               if (r_cg_permutation->fp_ViewToLight              ) cgGLSetMatrixParameterfc(r_cg_permutation->fp_ViewToLight, viewtolight16f);CHECKCGERROR
+               if (r_cg_permutation->fp_DeferredColor_Ambient    ) cgGLSetParameter3f(r_cg_permutation->fp_DeferredColor_Ambient , lightcolorbase[0] * ambientscale  * range, lightcolorbase[1] * ambientscale  * range, lightcolorbase[2] * ambientscale  * range);CHECKCGERROR
+               if (r_cg_permutation->fp_DeferredColor_Diffuse    ) cgGLSetParameter3f(r_cg_permutation->fp_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale  * range, lightcolorbase[1] * diffusescale  * range, lightcolorbase[2] * diffusescale  * range);CHECKCGERROR
+               if (r_cg_permutation->fp_DeferredColor_Specular   ) cgGLSetParameter3f(r_cg_permutation->fp_DeferredColor_Specular, lightcolorbase[0] * specularscale * range, lightcolorbase[1] * specularscale * range, lightcolorbase[2] * specularscale * range);CHECKCGERROR
+               if (r_cg_permutation->fp_ShadowMap_TextureScale   ) cgGLSetParameter2f(r_cg_permutation->fp_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);CHECKCGERROR
+               if (r_cg_permutation->fp_ShadowMap_Parameters     ) cgGLSetParameter4f(r_cg_permutation->fp_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);CHECKCGERROR
+               if (r_cg_permutation->fp_SpecularPower            ) cgGLSetParameter1f(r_cg_permutation->fp_SpecularPower, (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));CHECKCGERROR
+               if (r_cg_permutation->fp_ScreenToDepth            ) cgGLSetParameter2f(r_cg_permutation->fp_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);CHECKCGERROR
+               if (r_cg_permutation->fp_PixelToScreenTexCoord    ) cgGLSetParameter2f(r_cg_permutation->fp_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height);CHECKCGERROR
+
+               if (r_cg_permutation->fp_Texture_Attenuation      ) CG_BindTexture(r_cg_permutation->fp_Texture_Attenuation    , r_shadow_attenuationgradienttexture                 );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ScreenDepth      ) CG_BindTexture(r_cg_permutation->fp_Texture_ScreenDepth    , r_shadow_prepassgeometrydepthtexture                );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ScreenNormalMap  ) CG_BindTexture(r_cg_permutation->fp_Texture_ScreenNormalMap, r_shadow_prepassgeometrynormalmaptexture            );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Cube             ) CG_BindTexture(r_cg_permutation->fp_Texture_Cube           , rsurface.rtlight->currentcubemap                    );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ShadowMapRect    ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMapRect  , r_shadow_shadowmaprectangletexture                  );CHECKCGERROR
+               if (r_shadow_usingshadowmapcube)
+                       if (r_cg_permutation->fp_Texture_ShadowMapCube    ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMapCube  , r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ShadowMap2D      ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMap2D    , r_shadow_shadowmap2dtexture                         );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_CubeProjection   ) CG_BindTexture(r_cg_permutation->fp_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture                      );CHECKCGERROR
+#endif
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               break;
        }
-       if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
-       CHECKGLERROR
 }
 
 #define SKINFRAME_HASH 1024
@@ -2401,6 +5276,7 @@ void R_SkinFrame_Purge(void)
                                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;
                        }
                }
@@ -2514,9 +5390,13 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        unsigned char *pixels;
        unsigned char *bumppixels;
        unsigned char *basepixels = NULL;
-       int basepixels_width;
-       int basepixels_height;
+       int basepixels_width = 0;
+       int basepixels_height = 0;
        skinframe_t *skinframe;
+       rtexture_t *ddsbase = NULL;
+       qboolean ddshasalpha = false;
+       float ddsavgcolor[4];
+       char basename[MAX_QPATH];
 
        if (cls.state == ca_dedicated)
                return NULL;
@@ -2528,9 +5408,15 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        if (skinframe && skinframe->base)
                return skinframe;
 
-       basepixels = loadimagepixelsbgra(name, complain, true);
-       if (basepixels == NULL)
-               return NULL;
+       Image_StripImageExtension(name, basename, sizeof(basename));
+
+       // check for DDS texture file first
+       if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s.dds", basename), textureflags, &ddshasalpha, ddsavgcolor)))
+       {
+               basepixels = loadimagepixelsbgra(name, complain, true, r_texture_convertsRGB_skin.integer);
+               if (basepixels == NULL)
+                       return NULL;
+       }
 
        if (developer_loading.integer)
                Con_Printf("loading skin \"%s\"\n", name);
@@ -2540,58 +5426,85 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
        skinframe->stain = NULL;
        skinframe->merged = NULL;
-       skinframe->base = r_texture_notexture;
+       skinframe->base = NULL;
        skinframe->pants = NULL;
        skinframe->shirt = NULL;
-       skinframe->nmap = r_texture_blanknormalmap;
+       skinframe->nmap = NULL;
        skinframe->gloss = NULL;
        skinframe->glow = NULL;
        skinframe->fog = NULL;
+       skinframe->reflect = NULL;
        skinframe->hasalpha = false;
 
-       basepixels_width = image_width;
-       basepixels_height = image_height;
-       skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);
-
-       if (textureflags & TEXF_ALPHA)
+       if (ddsbase)
+       {
+               skinframe->base = ddsbase;
+               skinframe->hasalpha = ddshasalpha;
+               VectorCopy(ddsavgcolor, skinframe->avgcolor);
+               if (r_loadfog && skinframe->hasalpha)
+                       skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_mask.dds", skinframe->basename), textureflags | TEXF_ALPHA, NULL, NULL);
+               //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
+       }
+       else
        {
-               for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
+               basepixels_width = image_width;
+               basepixels_height = image_height;
+               skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);
+               if (textureflags & TEXF_ALPHA)
                {
-                       if (basepixels[j] < 255)
+                       for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
                        {
-                               skinframe->hasalpha = true;
-                               break;
+                               if (basepixels[j] < 255)
+                               {
+                                       skinframe->hasalpha = true;
+                                       break;
+                               }
                        }
-               }
-               if (r_loadfog && skinframe->hasalpha)
-               {
-                       // has transparent pixels
-                       pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
-                       for (j = 0;j < image_width * image_height * 4;j += 4)
+                       if (r_loadfog && skinframe->hasalpha)
                        {
-                               pixels[j+0] = 255;
-                               pixels[j+1] = 255;
-                               pixels[j+2] = 255;
-                               pixels[j+3] = basepixels[j+3];
+                               // has transparent pixels
+                               pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
+                               for (j = 0;j < image_width * image_height * 4;j += 4)
+                               {
+                                       pixels[j+0] = 255;
+                                       pixels[j+1] = 255;
+                                       pixels[j+2] = 255;
+                                       pixels[j+3] = basepixels[j+3];
+                               }
+                               skinframe->fog = R_LoadTexture2D (r_main_texturepool, va("%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);
+                               Mem_Free(pixels);
                        }
-                       skinframe->fog = R_LoadTexture2D (r_main_texturepool, va("%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);
-                       Mem_Free(pixels);
                }
+               R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
+               //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
+               if (r_savedds && qglGetCompressedTexImageARB && skinframe->base)
+                       R_SaveTextureDDSFile(skinframe->base, va("dds/%s.dds", skinframe->basename), true);
+               if (r_savedds && qglGetCompressedTexImageARB && skinframe->fog)
+                       R_SaveTextureDDSFile(skinframe->fog, va("dds/%s_mask.dds", skinframe->basename), true);
        }
 
-       R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
-       //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
+       if (r_loaddds)
+       {
+               if (r_loadnormalmap)
+                       skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_norm.dds", skinframe->basename), textureflags | TEXF_ALPHA, NULL, NULL);
+               skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_glow.dds", skinframe->basename), textureflags, NULL, NULL);
+               if (r_loadgloss)
+                       skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_gloss.dds", skinframe->basename), textureflags, NULL, NULL);
+               skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_pants.dds", skinframe->basename), textureflags, NULL, NULL);
+               skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_shirt.dds", skinframe->basename), textureflags, NULL, NULL);
+               skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_reflect.dds", skinframe->basename), textureflags, NULL, NULL);
+       }
 
        // _norm is the name used by tenebrae and has been adopted as standard
-       if (r_loadnormalmap)
+       if (r_loadnormalmap && skinframe->nmap == NULL)
        {
-               if ((pixels = loadimagepixelsbgra(va("%s_norm", skinframe->basename), false, false)) != NULL)
+               if ((pixels = loadimagepixelsbgra(va("%s_norm", skinframe->basename), false, false, false)) != NULL)
                {
                        skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | skinframe->textureflags) & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL);
                        Mem_Free(pixels);
                        pixels = NULL;
                }
-               else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va("%s_bump", skinframe->basename), false, false)) != NULL)
+               else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va("%s_bump", skinframe->basename), false, false, false)) != NULL)
                {
                        pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
                        Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
@@ -2606,14 +5519,55 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                        skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | skinframe->textureflags) & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL);
                        Mem_Free(pixels);
                }
+               if (r_savedds && qglGetCompressedTexImageARB && skinframe->nmap)
+                       R_SaveTextureDDSFile(skinframe->nmap, va("dds/%s_norm.dds", skinframe->basename), true);
        }
-       // _luma is supported for tenebrae compatibility
-       // (I think it's a very stupid name, but oh well)
+
+       // _luma is supported only for tenebrae compatibility
        // _glow is the preferred name
-       if ((pixels = loadimagepixelsbgra(va("%s_glow",  skinframe->basename), false, false)) || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false))) {skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_glow.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
-       if (r_loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false))) {skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_gloss.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
-       if ((pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false))) {skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
-       if ((pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false))) {skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
+       if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va("%s_glow",  skinframe->basename), false, false, r_texture_convertsRGB_skin.integer)) || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer))))
+       {
+               skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_glow.integer ? ~0 : ~TEXF_COMPRESS), NULL);
+               if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow)
+                       R_SaveTextureDDSFile(skinframe->glow, va("dds/%s_glow.dds", skinframe->basename), true);
+               Mem_Free(pixels);pixels = NULL;
+       }
+
+       if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer)))
+       {
+               skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_gloss.integer ? ~0 : ~TEXF_COMPRESS), NULL);
+               if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss)
+                       R_SaveTextureDDSFile(skinframe->gloss, va("dds/%s_gloss.dds", skinframe->basename), true);
+               Mem_Free(pixels);
+               pixels = NULL;
+       }
+
+       if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer)))
+       {
+               skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);
+               if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants)
+                       R_SaveTextureDDSFile(skinframe->pants, va("dds/%s_pants.dds", skinframe->basename), true);
+               Mem_Free(pixels);
+               pixels = NULL;
+       }
+
+       if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer)))
+       {
+               skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);
+               if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt)
+                       R_SaveTextureDDSFile(skinframe->shirt, va("dds/%s_shirt.dds", skinframe->basename), true);
+               Mem_Free(pixels);
+               pixels = NULL;
+       }
+
+       if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va("%s_reflect", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer)))
+       {
+               skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va("%s_reflect", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_reflectmask.integer ? ~0 : ~TEXF_COMPRESS), NULL);
+               if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect)
+                       R_SaveTextureDDSFile(skinframe->reflect, va("dds/%s_reflect.dds", skinframe->basename), true);
+               Mem_Free(pixels);
+               pixels = NULL;
+       }
 
        if (basepixels)
                Mem_Free(basepixels);
@@ -2638,13 +5592,14 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co
 
        skinframe->stain = NULL;
        skinframe->merged = NULL;
-       skinframe->base = r_texture_notexture;
+       skinframe->base = NULL;
        skinframe->pants = NULL;
        skinframe->shirt = NULL;
-       skinframe->nmap = r_texture_blanknormalmap;
+       skinframe->nmap = NULL;
        skinframe->gloss = NULL;
        skinframe->glow = NULL;
        skinframe->fog = NULL;
+       skinframe->reflect = NULL;
        skinframe->hasalpha = false;
 
        // if no data was provided, then clearly the caller wanted to get a blank skinframe
@@ -2706,13 +5661,14 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i
 
        skinframe->stain = NULL;
        skinframe->merged = NULL;
-       skinframe->base = r_texture_notexture;
+       skinframe->base = NULL;
        skinframe->pants = NULL;
        skinframe->shirt = NULL;
-       skinframe->nmap = r_texture_blanknormalmap;
+       skinframe->nmap = NULL;
        skinframe->gloss = NULL;
        skinframe->glow = NULL;
        skinframe->fog = NULL;
+       skinframe->reflect = NULL;
        skinframe->hasalpha = false;
 
        // if no data was provided, then clearly the caller wanted to get a blank skinframe
@@ -2826,13 +5782,14 @@ skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, co
 
        skinframe->stain = NULL;
        skinframe->merged = NULL;
-       skinframe->base = r_texture_notexture;
+       skinframe->base = NULL;
        skinframe->pants = NULL;
        skinframe->shirt = NULL;
-       skinframe->nmap = r_texture_blanknormalmap;
+       skinframe->nmap = NULL;
        skinframe->gloss = NULL;
        skinframe->glow = NULL;
        skinframe->fog = NULL;
+       skinframe->reflect = NULL;
        skinframe->hasalpha = false;
 
        // if no data was provided, then clearly the caller wanted to get a blank skinframe
@@ -2870,16 +5827,17 @@ skinframe_t *R_SkinFrame_LoadMissing(void)
        if (cls.state == ca_dedicated)
                return NULL;
 
-       skinframe = R_SkinFrame_Find("missing", TEXF_PRECACHE | TEXF_FORCENEAREST, 0, 0, 0, true);
+       skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
        skinframe->stain = NULL;
        skinframe->merged = NULL;
-       skinframe->base = r_texture_notexture;
+       skinframe->base = NULL;
        skinframe->pants = NULL;
        skinframe->shirt = NULL;
-       skinframe->nmap = r_texture_blanknormalmap;
+       skinframe->nmap = NULL;
        skinframe->gloss = NULL;
        skinframe->glow = NULL;
        skinframe->fog = NULL;
+       skinframe->reflect = NULL;
        skinframe->hasalpha = false;
 
        skinframe->avgcolor[0] = rand() / RAND_MAX;
@@ -2890,6 +5848,136 @@ skinframe_t *R_SkinFrame_LoadMissing(void)
        return skinframe;
 }
 
+//static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
+typedef struct suffixinfo_s
+{
+       char *suffix;
+       qboolean flipx, flipy, flipdiagonal;
+}
+suffixinfo_t;
+static suffixinfo_t suffix[3][6] =
+{
+       {
+               {"px",   false, false, false},
+               {"nx",   false, false, false},
+               {"py",   false, false, false},
+               {"ny",   false, false, false},
+               {"pz",   false, false, false},
+               {"nz",   false, false, false}
+       },
+       {
+               {"posx", false, false, false},
+               {"negx", false, false, false},
+               {"posy", false, false, false},
+               {"negy", false, false, false},
+               {"posz", false, false, false},
+               {"negz", false, false, false}
+       },
+       {
+               {"rt",    true, false,  true},
+               {"lf",   false,  true,  true},
+               {"ft",    true,  true, false},
+               {"bk",   false, false, false},
+               {"up",    true, false,  true},
+               {"dn",    true, false,  true}
+       }
+};
+
+static int componentorder[4] = {0, 1, 2, 3};
+
+rtexture_t *R_LoadCubemap(const char *basename)
+{
+       int i, j, cubemapsize;
+       unsigned char *cubemappixels, *image_buffer;
+       rtexture_t *cubemaptexture;
+       char name[256];
+       // must start 0 so the first loadimagepixels has no requested width/height
+       cubemapsize = 0;
+       cubemappixels = NULL;
+       cubemaptexture = NULL;
+       // keep trying different suffix groups (posx, px, rt) until one loads
+       for (j = 0;j < 3 && !cubemappixels;j++)
+       {
+               // load the 6 images in the suffix group
+               for (i = 0;i < 6;i++)
+               {
+                       // generate an image name based on the base and and suffix
+                       dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
+                       // load it
+                       if ((image_buffer = loadimagepixelsbgra(name, false, false, r_texture_convertsRGB_cubemap.integer)))
+                       {
+                               // an image loaded, make sure width and height are equal
+                               if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
+                               {
+                                       // if this is the first image to load successfully, allocate the cubemap memory
+                                       if (!cubemappixels && image_width >= 1)
+                                       {
+                                               cubemapsize = image_width;
+                                               // note this clears to black, so unavailable sides are black
+                                               cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
+                                       }
+                                       // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
+                                       if (cubemappixels)
+                                               Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
+                               }
+                               else
+                                       Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
+                               // free the image
+                               Mem_Free(image_buffer);
+                       }
+               }
+       }
+       // if a cubemap loaded, upload it
+       if (cubemappixels)
+       {
+               if (developer_loading.integer)
+                       Con_Printf("loading cubemap \"%s\"\n", basename);
+
+               cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
+               Mem_Free(cubemappixels);
+       }
+       else
+       {
+               Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
+               if (developer_loading.integer)
+               {
+                       Con_Printf("(tried tried images ");
+                       for (j = 0;j < 3;j++)
+                               for (i = 0;i < 6;i++)
+                                       Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
+                       Con_Print(" and was unable to find any of them).\n");
+               }
+       }
+       return cubemaptexture;
+}
+
+rtexture_t *R_GetCubemap(const char *basename)
+{
+       int i;
+       for (i = 0;i < r_texture_numcubemaps;i++)
+               if (!strcasecmp(r_texture_cubemaps[i].basename, basename))
+                       return r_texture_cubemaps[i].texture ? r_texture_cubemaps[i].texture : r_texture_whitecube;
+       if (i >= MAX_CUBEMAPS)
+               return r_texture_whitecube;
+       r_texture_numcubemaps++;
+       strlcpy(r_texture_cubemaps[i].basename, basename, sizeof(r_texture_cubemaps[i].basename));
+       r_texture_cubemaps[i].texture = R_LoadCubemap(r_texture_cubemaps[i].basename);
+       return r_texture_cubemaps[i].texture;
+}
+
+void R_FreeCubemaps(void)
+{
+       int i;
+       for (i = 0;i < r_texture_numcubemaps;i++)
+       {
+               if (developer_loading.integer)
+                       Con_DPrintf("unloading cubemap \"%s\"\n", r_texture_cubemaps[i].basename);
+               if (r_texture_cubemaps[i].texture)
+                       R_FreeTexture(r_texture_cubemaps[i].texture);
+       }
+       r_texture_numcubemaps = 0;
+}
+
 void R_Main_FreeViewCache(void)
 {
        if (r_refdef.viewcache.entityvisible)
@@ -2939,12 +6027,56 @@ void R_Main_ResizeViewCache(void)
                        Mem_Free(r_refdef.viewcache.world_surfacevisible);
                r_refdef.viewcache.world_surfacevisible = Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
        }
-}
+}
+
+extern rtexture_t *loadingscreentexture;
+void gl_main_start(void)
+{
+       loadingscreentexture = NULL;
+       r_texture_blanknormalmap = NULL;
+       r_texture_white = NULL;
+       r_texture_grey128 = NULL;
+       r_texture_black = NULL;
+       r_texture_whitecube = NULL;
+       r_texture_normalizationcube = NULL;
+       r_texture_fogattenuation = NULL;
+       r_texture_gammaramps = NULL;
+       r_texture_numcubemaps = 0;
+
+       r_loaddds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_load.integer;
+       r_savedds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
+
+       switch(vid.renderpath)
+       {
+       case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
+               Cvar_SetValueQuick(&r_textureunits, vid.texunits);
+               Cvar_SetValueQuick(&gl_combine, 1);
+               Cvar_SetValueQuick(&r_glsl, 1);
+               r_loadnormalmap = true;
+               r_loadgloss = true;
+               r_loadfog = false;
+               break;
+       case RENDERPATH_GL13:
+               Cvar_SetValueQuick(&r_textureunits, vid.texunits);
+               Cvar_SetValueQuick(&gl_combine, 1);
+               Cvar_SetValueQuick(&r_glsl, 0);
+               r_loadnormalmap = false;
+               r_loadgloss = false;
+               r_loadfog = true;
+               break;
+       case RENDERPATH_GL11:
+               Cvar_SetValueQuick(&r_textureunits, vid.texunits);
+               Cvar_SetValueQuick(&gl_combine, 0);
+               Cvar_SetValueQuick(&r_glsl, 0);
+               r_loadnormalmap = false;
+               r_loadgloss = false;
+               r_loadfog = true;
+               break;
+       }
 
-void gl_main_start(void)
-{
-       r_loadnormalmap = r_loadgloss = vid.support.arb_texture_env_dot3 || vid.support.arb_fragment_shader;
-       r_loadfog = true;
+       R_AnimCache_Free();
+       R_FrameData_Reset();
 
        r_numqueries = 0;
        r_maxqueries = 0;
@@ -2973,14 +6105,22 @@ void gl_main_start(void)
        memset(&r_waterstate, 0, sizeof(r_waterstate));
        memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
        Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
+       glslshaderstring = NULL;
+#ifdef SUPPORTCG
+       memset(r_cg_permutationhash, 0, sizeof(r_cg_permutationhash));
+       Mem_ExpandableArray_NewArray(&r_cg_permutationarray, r_main_mempool, sizeof(r_cg_permutation_t), 256);
+       cgshaderstring = NULL;
+#endif
        memset(&r_svbsp, 0, sizeof (r_svbsp));
 
        r_refdef.fogmasktable_density = 0;
 }
 
-extern rtexture_t *loadingscreentexture;
 void gl_main_shutdown(void)
 {
+       R_AnimCache_Free();
+       R_FrameData_Reset();
+
        R_Main_FreeViewCache();
 
        if (r_maxqueries)
@@ -3010,6 +6150,7 @@ void gl_main_shutdown(void)
        r_texture_normalizationcube = NULL;
        r_texture_fogattenuation = NULL;
        r_texture_gammaramps = NULL;
+       r_texture_numcubemaps = 0;
        //r_texture_fogintensity = NULL;
        memset(&r_bloomstate, 0, sizeof(r_bloomstate));
        memset(&r_waterstate, 0, sizeof(r_waterstate));
@@ -3044,6 +6185,8 @@ void gl_main_newmap(void)
                        CL_ParseEntityLump(cl.worldmodel->brush.entities);
        }
        R_Main_FreeViewCache();
+
+       R_FrameData_Reset();
 }
 
 void GL_Main_Init(void)
@@ -3076,7 +6219,6 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_equalize_entities_minambient);
        Cvar_RegisterVariable(&r_equalize_entities_by);
        Cvar_RegisterVariable(&r_equalize_entities_to);
-       Cvar_RegisterVariable(&r_animcache);
        Cvar_RegisterVariable(&r_depthfirst);
        Cvar_RegisterVariable(&r_useinfinitefarclip);
        Cvar_RegisterVariable(&r_farclip_base);
@@ -3111,6 +6253,8 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_shadows_castfrombmodels);
        Cvar_RegisterVariable(&r_shadows_throwdistance);
        Cvar_RegisterVariable(&r_shadows_throwdirection);
+       Cvar_RegisterVariable(&r_shadows_focus);
+       Cvar_RegisterVariable(&r_shadows_shadowmapscale);
        Cvar_RegisterVariable(&r_q1bsp_skymasking);
        Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
        Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
@@ -3118,6 +6262,17 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
        Cvar_RegisterVariable(&r_fog_exp2);
        Cvar_RegisterVariable(&r_drawfog);
+       Cvar_RegisterVariable(&r_transparentdepthmasking);
+       Cvar_RegisterVariable(&r_texture_dds_load);
+       Cvar_RegisterVariable(&r_texture_dds_save);
+       Cvar_RegisterVariable(&r_texture_convertsRGB_2d);
+       Cvar_RegisterVariable(&r_texture_convertsRGB_skin);
+       Cvar_RegisterVariable(&r_texture_convertsRGB_cubemap);
+       Cvar_RegisterVariable(&r_texture_convertsRGB_skybox);
+       Cvar_RegisterVariable(&r_texture_convertsRGB_particles);
+       Cvar_RegisterVariable(&r_textureunits);
+       Cvar_RegisterVariable(&gl_combine);
+       Cvar_RegisterVariable(&r_glsl);
        Cvar_RegisterVariable(&r_glsl_deluxemapping);
        Cvar_RegisterVariable(&r_glsl_offsetmapping);
        Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
@@ -3153,6 +6308,7 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_test);
        Cvar_RegisterVariable(&r_batchmode);
        Cvar_RegisterVariable(&r_glsl_saturation);
+       Cvar_RegisterVariable(&r_framedatasize);
        if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
                Cvar_SetValue("r_fullbrights", 0);
        R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
@@ -3161,6 +6317,8 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_track_sprites_flags);
        Cvar_RegisterVariable(&r_track_sprites_scalew);
        Cvar_RegisterVariable(&r_track_sprites_scaleh);
+       Cvar_RegisterVariable(&r_overheadsprites_perspective);
+       Cvar_RegisterVariable(&r_overheadsprites_pushback);
 }
 
 extern void R_Textures_Init(void);
@@ -3175,12 +6333,14 @@ extern void gl_backend_init(void);
 extern void Sbar_Init(void);
 extern void R_LightningBeams_Init(void);
 extern void Mod_RenderInit(void);
+extern void Font_Init(void);
 
 void Render_Init(void)
 {
        gl_backend_init();
        R_Textures_Init();
        GL_Main_Init();
+       Font_Init();
        GL_Draw_Init();
        R_Shadow_Init();
        R_Sky_Init();
@@ -3326,148 +6486,170 @@ int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, c
 
 //==================================================================================
 
-// LordHavoc: animcache written by Echon, refactored and reformatted by me
-
-/**
- * Animation cache helps save re-animating a player mesh if it's re-rendered again in a given frame
- * (reflections, lighting, etc). All animation cache becomes invalid on the next frame and is flushed
- * (well, over-wrote). The memory for each cache is kept around to save on allocation thrashing.
- */
+// LordHavoc: this stores temporary data used within the same frame
 
-typedef struct r_animcache_entity_s
-{
-       float *vertex3f;
-       float *normal3f;
-       float *svector3f;
-       float *tvector3f;
-       int maxvertices;
-       qboolean wantnormals;
-       qboolean wanttangents;
-}
-r_animcache_entity_t;
+qboolean r_framedata_failed;
+static size_t r_framedata_size;
+static size_t r_framedata_current;
+static void *r_framedata_base;
 
-typedef struct r_animcache_s
+void R_FrameData_Reset(void)
 {
-       r_animcache_entity_t entity[MAX_EDICTS];
-       int maxindex;
-       int currentindex;
+       if (r_framedata_base)
+               Mem_Free(r_framedata_base);
+       r_framedata_base = NULL;
+       r_framedata_size = 0;
+       r_framedata_current = 0;
+       r_framedata_failed = false;
 }
-r_animcache_t;
-
-static r_animcache_t r_animcachestate;
 
-void R_AnimCache_Free(void)
+void R_FrameData_NewFrame(void)
 {
-       int idx;
-       for (idx=0 ; idx<r_animcachestate.maxindex ; idx++)
+       size_t wantedsize;
+       if (r_framedata_failed)
+               Cvar_SetValueQuick(&r_framedatasize, r_framedatasize.value + 1.0f);
+       wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
+       wantedsize = bound(65536, wantedsize, 128*1024*1024);
+       if (r_framedata_size != wantedsize)
        {
-               r_animcachestate.entity[idx].maxvertices = 0;
-               Mem_Free(r_animcachestate.entity[idx].vertex3f);
-               r_animcachestate.entity[idx].vertex3f = NULL;
-               r_animcachestate.entity[idx].normal3f = NULL;
-               r_animcachestate.entity[idx].svector3f = NULL;
-               r_animcachestate.entity[idx].tvector3f = NULL;
+               r_framedata_size = wantedsize;
+               if (r_framedata_base)
+                       Mem_Free(r_framedata_base);
+               r_framedata_base = Mem_Alloc(r_main_mempool, r_framedata_size);
        }
-       r_animcachestate.currentindex = 0;
-       r_animcachestate.maxindex = 0;
+       r_framedata_current = 0;
+       r_framedata_failed = false;
 }
 
-void R_AnimCache_ResizeEntityCache(const int cacheIdx, const int numvertices)
+void *R_FrameData_Alloc(size_t size)
 {
-       int arraySize;
-       float *base;
-       r_animcache_entity_t *cache = &r_animcachestate.entity[cacheIdx];
+       void *data;
 
-       if (cache->maxvertices >= numvertices)
-               return;
-
-       // Release existing memory
-       if (cache->vertex3f)
-               Mem_Free(cache->vertex3f);
+       // align to 16 byte boundary
+       size = (size + 15) & ~15;
+       data = (void *)((unsigned char*)r_framedata_base + r_framedata_current);
+       r_framedata_current += size;
 
-       // Pad by 1024 verts
-       cache->maxvertices = (numvertices + 1023) & ~1023;
-       arraySize = cache->maxvertices * 3;
+       // check overflow
+       if (r_framedata_current > r_framedata_size)
+               r_framedata_failed = true;
 
-       // Allocate, even if we don't need this memory in this instance it will get ignored and potentially used later
-       base = (float *)Mem_Alloc(r_main_mempool, arraySize * sizeof(float) * 4);
-       r_animcachestate.entity[cacheIdx].vertex3f = base;
-       r_animcachestate.entity[cacheIdx].normal3f = base + arraySize;
-       r_animcachestate.entity[cacheIdx].svector3f = base + arraySize*2;
-       r_animcachestate.entity[cacheIdx].tvector3f = base + arraySize*3;
+       // return NULL on everything after a failure
+       if (r_framedata_failed)
+               return NULL;
 
-//     Con_Printf("allocated cache for %i (%f KB)\n", cacheIdx, (arraySize*sizeof(float)*4)/1024.0f);
+       return data;
 }
 
-void R_AnimCache_NewFrame(void)
+void *R_FrameData_Store(size_t size, void *data)
 {
-       int i;
+       void *d = R_FrameData_Alloc(size);
+       if (d)
+               memcpy(d, data, size);
+       return d;
+}
+
+//==================================================================================
+
+// LordHavoc: animcache originally written by Echon, rewritten since then
 
-       if (r_animcache.integer && r_drawentities.integer)
-               r_animcachestate.maxindex = sizeof(r_animcachestate.entity) / sizeof(r_animcachestate.entity[0]);
-       else if (r_animcachestate.maxindex)
-               R_AnimCache_Free();
+/**
+ * Animation cache prevents re-generating mesh data for an animated model
+ * multiple times in one frame for lighting, shadowing, reflections, etc.
+ */
+
+void R_AnimCache_Free(void)
+{
+}
 
-       r_animcachestate.currentindex = 0;
+void R_AnimCache_ClearCache(void)
+{
+       int i;
+       entity_render_t *ent;
 
        for (i = 0;i < r_refdef.scene.numentities;i++)
-               r_refdef.scene.entities[i]->animcacheindex = -1;
+       {
+               ent = r_refdef.scene.entities[i];
+               ent->animcache_vertex3f = NULL;
+               ent->animcache_normal3f = NULL;
+               ent->animcache_svector3f = NULL;
+               ent->animcache_tvector3f = NULL;
+       }
 }
 
 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
 {
        dp_model_t *model = ent->model;
-       r_animcache_entity_t *c;
+       int numvertices;
        // see if it's already cached this frame
-       if (ent->animcacheindex >= 0)
+       if (ent->animcache_vertex3f)
        {
                // add normals/tangents if needed
-               c = r_animcachestate.entity + ent->animcacheindex;
-               if (c->wantnormals)
-                       wantnormals = false;
-               if (c->wanttangents)
-                       wanttangents = false;
                if (wantnormals || wanttangents)
-                       model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL);
+               {
+                       if (ent->animcache_normal3f)
+                               wantnormals = false;
+                       if (ent->animcache_svector3f)
+                               wanttangents = false;
+                       if (wantnormals || wanttangents)
+                       {
+                               numvertices = model->surfmesh.num_vertices;
+                               if (wantnormals)
+                                       ent->animcache_normal3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+                               if (wanttangents)
+                               {
+                                       ent->animcache_svector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+                                       ent->animcache_tvector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+                               }
+                               if (!r_framedata_failed)
+                                       model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
+                       }
+               }
        }
        else
        {
                // see if this ent is worth caching
-               if (r_animcachestate.maxindex <= r_animcachestate.currentindex)
-                       return false;
-               if (!model || !model->Draw || !model->surfmesh.isanimated || !model->AnimateVertices || (ent->frameblend[0].lerp == 1 && ent->frameblend[0].subframe == 0))
+               if (!model || !model->Draw || !model->surfmesh.isanimated || !model->AnimateVertices || (ent->frameblend[0].lerp == 1 && ent->frameblend[0].subframe == 0 && !ent->skeleton))
                        return false;
-               // assign it a cache entry and make sure the arrays are big enough
-               R_AnimCache_ResizeEntityCache(r_animcachestate.currentindex, model->surfmesh.num_vertices);
-               ent->animcacheindex = r_animcachestate.currentindex++;
-               c = r_animcachestate.entity + ent->animcacheindex;
-               c->wantnormals = wantnormals;
-               c->wanttangents = wanttangents;
-               model->AnimateVertices(model, ent->frameblend, ent->skeleton, c->vertex3f, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL);
+               // get some memory for this entity and generate mesh data
+               numvertices = model->surfmesh.num_vertices;
+               ent->animcache_vertex3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+               if (wantnormals)
+                       ent->animcache_normal3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+               if (wanttangents)
+               {
+                       ent->animcache_svector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+                       ent->animcache_tvector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+               }
+               if (!r_framedata_failed)
+                       model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
        }
-       return true;
+       return !r_framedata_failed;
 }
 
 void R_AnimCache_CacheVisibleEntities(void)
 {
        int i;
-       qboolean wantnormals;
-       qboolean wanttangents;
-
-       if (!r_animcachestate.maxindex)
-               return;
+       qboolean wantnormals = !r_showsurfaces.integer;
+       qboolean wanttangents = !r_showsurfaces.integer;
 
-       wantnormals = !r_showsurfaces.integer;
-       wanttangents = !r_showsurfaces.integer && (r_glsl.integer || r_refdef.scene.rtworld || r_refdef.scene.rtdlight);
+       switch(vid.renderpath)
+       {
+       case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               wanttangents = false;
+               break;
+       }
 
-       // TODO: thread this?
+       // TODO: thread this
+       // NOTE: R_PrepareRTLights() also caches entities
 
        for (i = 0;i < r_refdef.scene.numentities;i++)
-       {
-               if (!r_refdef.viewcache.entityvisible[i])
-                       continue;
-               R_AnimCache_GetEntity(r_refdef.scene.entities[i], wantnormals, wanttangents);
-       }
+               if (r_refdef.viewcache.entityvisible[i])
+                       R_AnimCache_GetEntity(r_refdef.scene.entities[i], wantnormals, wanttangents);
 }
 
 //==================================================================================
@@ -3478,13 +6660,14 @@ static void R_View_UpdateEntityLighting (void)
        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] && r_shadows.integer != 1)
+               if (!r_refdef.viewcache.entityvisible[i] && skipunseen)
                        continue;
 
                // skip bsp models
@@ -3498,7 +6681,7 @@ static void R_View_UpdateEntityLighting (void)
                }
 
                // fetch the lighting from the worldmodel data
-               VectorSet(ent->modellight_ambient, r_refdef.scene.ambient * (2.0f / 128.0f), r_refdef.scene.ambient * (2.0f / 128.0f), r_refdef.scene.ambient * (2.0f / 128.0f));
+               VectorClear(ent->modellight_ambient);
                VectorClear(ent->modellight_diffuse);
                VectorClear(tempdiffusenormal);
                if ((ent->flags & RENDER_LIGHT) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
@@ -3580,6 +6763,10 @@ static qboolean R_CanSeeBox(int numsamples, vec_t enlarge, vec3_t eye, vec3_t en
        boxmins[2] = (enlarge+1) * entboxmins[2] - enlarge * entboxmaxs[2];
        boxmaxs[2] = (enlarge+1) * entboxmaxs[2] - enlarge * entboxmins[2];
 
+       // return true if eye is inside enlarged box
+       if (BoxesOverlap(boxmins, boxmaxs, eye, eye))
+               return true;
+
        // try center
        VectorCopy(eye, start);
        VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, end);
@@ -3605,10 +6792,12 @@ static void R_View_UpdateEntityVisible (void)
        int samples;
        entity_render_t *ent;
 
-       if (!r_drawentities.integer)
-               return;
-
-       renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : ((chase_active.integer || r_waterstate.renderingscene) ? RENDER_VIEWMODEL : RENDER_EXTERIORMODEL);
+       renderimask = r_refdef.envmap                                    ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL)
+               : r_waterstate.renderingrefraction                       ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL)
+               : (chase_active.integer || r_waterstate.renderingscene)  ? RENDER_VIEWMODEL
+               :                                                          RENDER_EXTERIORMODEL;
+       if (!r_drawviewmodel.integer)
+               renderimask |= RENDER_VIEWMODEL;
        if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
        {
                // worldmodel can check visibility
@@ -3656,9 +6845,6 @@ int R_DrawBrushModelsSky (void)
        int i, sky;
        entity_render_t *ent;
 
-       if (!r_drawentities.integer)
-               return false;
-
        sky = false;
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
@@ -3679,9 +6865,6 @@ static void R_DrawModels(void)
        int i;
        entity_render_t *ent;
 
-       if (!r_drawentities.integer)
-               return;
-
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
                if (!r_refdef.viewcache.entityvisible[i])
@@ -3700,9 +6883,6 @@ static void R_DrawModelsDepth(void)
        int i;
        entity_render_t *ent;
 
-       if (!r_drawentities.integer)
-               return;
-
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
                if (!r_refdef.viewcache.entityvisible[i])
@@ -3718,9 +6898,6 @@ static void R_DrawModelsDebug(void)
        int i;
        entity_render_t *ent;
 
-       if (!r_drawentities.integer)
-               return;
-
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
                if (!r_refdef.viewcache.entityvisible[i])
@@ -3736,9 +6913,6 @@ static void R_DrawModelsAddWaterPlanes(void)
        int i;
        entity_render_t *ent;
 
-       if (!r_drawentities.integer)
-               return;
-
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
                if (!r_refdef.viewcache.entityvisible[i])
@@ -3915,8 +7089,8 @@ void R_View_Update(void)
 
 void R_SetupView(qboolean allowwaterclippingplane)
 {
-       const double *customclipplane = NULL;
-       double plane[4];
+       const float *customclipplane = NULL;
+       float plane[4];
        if (r_refdef.view.useclipplane && allowwaterclippingplane)
        {
                // LordHavoc: couldn't figure out how to make this approach the
@@ -3940,6 +7114,40 @@ void R_SetupView(qboolean allowwaterclippingplane)
        R_SetViewport(&r_refdef.view.viewport);
 }
 
+void R_EntityMatrix(const matrix4x4_t *matrix)
+{
+       if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
+       {
+               gl_modelmatrixchanged = false;
+               gl_modelmatrix = *matrix;
+               Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
+               Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
+               Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
+               Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
+               CHECKGLERROR
+               switch(vid.renderpath)
+               {
+               case RENDERPATH_GL20:
+                       if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fvARB(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
+                       if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fvARB(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
+                       qglLoadMatrixf(gl_modelview16f);CHECKGLERROR
+                       break;
+               case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+                       CHECKCGERROR
+                       if (r_cg_permutation && r_cg_permutation->vp_ModelViewProjectionMatrix) cgGLSetMatrixParameterfc(r_cg_permutation->vp_ModelViewProjectionMatrix, gl_modelviewprojection16f);CHECKCGERROR
+                       if (r_cg_permutation && r_cg_permutation->vp_ModelViewMatrix) cgGLSetMatrixParameterfc(r_cg_permutation->vp_ModelViewMatrix, gl_modelview16f);CHECKCGERROR
+                       qglLoadMatrixf(gl_modelview16f);CHECKGLERROR
+#endif
+                       break;
+               case RENDERPATH_GL13:
+               case RENDERPATH_GL11:
+                       qglLoadMatrixf(gl_modelview16f);CHECKGLERROR
+                       break;
+               }
+       }
+}
+
 void R_ResetViewRendering2D(void)
 {
        r_viewport_t viewport;
@@ -3957,7 +7165,7 @@ void R_ResetViewRendering2D(void)
        GL_DepthMask(false);
        GL_DepthRange(0, 1);
        GL_DepthTest(false);
-       R_Mesh_Matrix(&identitymatrix);
+       R_EntityMatrix(&identitymatrix);
        R_Mesh_ResetTextureState();
        GL_PolygonOffset(0, 0);
        qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
@@ -3967,7 +7175,6 @@ void R_ResetViewRendering2D(void)
        qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
        GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
-       R_SetupGenericShader(true);
 }
 
 void R_ResetViewRendering3D(void)
@@ -3984,7 +7191,7 @@ void R_ResetViewRendering3D(void)
        GL_DepthMask(true);
        GL_DepthRange(0, 1);
        GL_DepthTest(true);
-       R_Mesh_Matrix(&identitymatrix);
+       R_EntityMatrix(&identitymatrix);
        R_Mesh_ResetTextureState();
        GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
        qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
@@ -3994,7 +7201,6 @@ void R_ResetViewRendering3D(void)
        qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
        GL_CullFace(r_refdef.view.cullface_back);
-       R_SetupGenericShader(true);
 }
 
 void R_RenderScene(void);
@@ -4006,6 +7212,19 @@ static void R_Water_StartFrame(void)
        int waterwidth, waterheight, texturewidth, textureheight;
        r_waterstate_waterplane_t *p;
 
+       if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
+               return;
+
+       switch(vid.renderpath)
+       {
+       case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               return;
+       }
+
        // set waterwidth and waterheight to the water resolution that will be
        // used (often less than the screen resolution for faster rendering)
        waterwidth = (int)bound(1, vid.width * r_water_resolutionmultiplier.value, vid.width);
@@ -4013,7 +7232,7 @@ static void R_Water_StartFrame(void)
 
        // calculate desired texture sizes
        // can't use water if the card does not support the texture size
-       if (!r_water.integer || !r_glsl.integer || !vid.support.arb_fragment_shader || waterwidth > (int)vid.maxtexturesize_2d || waterheight > (int)vid.maxtexturesize_2d || r_showsurfaces.integer)
+       if (!r_water.integer || r_showsurfaces.integer)
                texturewidth = textureheight = waterwidth = waterheight = 0;
        else if (vid.support.arb_texture_non_power_of_two)
        {
@@ -4144,7 +7363,7 @@ static void R_Water_ProcessPlanes(void)
                if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
                {
                        if (!p->texture_refraction)
-                               p->texture_refraction = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_refraction", planeindex), r_waterstate.texturewidth, r_waterstate.textureheight, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+                               p->texture_refraction = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_refraction", planeindex), r_waterstate.texturewidth, r_waterstate.textureheight, NULL, TEXTYPE_COLORBUFFER, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
                        if (!p->texture_refraction)
                                goto error;
                }
@@ -4152,7 +7371,7 @@ static void R_Water_ProcessPlanes(void)
                if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
                {
                        if (!p->texture_reflection)
-                               p->texture_reflection = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_reflection", planeindex), r_waterstate.texturewidth, r_waterstate.textureheight, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+                               p->texture_reflection = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_reflection", planeindex), r_waterstate.texturewidth, r_waterstate.textureheight, NULL, TEXTYPE_COLORBUFFER, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
                        if (!p->texture_reflection)
                                goto error;
                }
@@ -4168,28 +7387,6 @@ static void R_Water_ProcessPlanes(void)
        r_waterstate.renderingscene = true;
        for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
        {
-               // 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))
-               {
-                       r_refdef.view = myview;
-                       r_refdef.view.clipplane = p->plane;
-                       VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
-                       r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
-                       PlaneClassify(&r_refdef.view.clipplane);
-
-                       R_ResetViewRendering3D();
-                       R_ClearScreen(r_refdef.fogenabled);
-                       R_View_Update();
-                       R_RenderScene();
-
-                       // copy view into the screen texture
-                       R_Mesh_TexBind(0, R_GetTexture(p->texture_refraction));
-                       GL_ActiveTexture(0);
-                       CHECKGLERROR
-                       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);CHECKGLERROR
-               }
-
                if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
                {
                        r_refdef.view = myview;
@@ -4215,11 +7412,29 @@ static void R_Water_ProcessPlanes(void)
                        R_View_Update();
                        R_RenderScene();
 
-                       R_Mesh_TexBind(0, R_GetTexture(p->texture_reflection));
-                       GL_ActiveTexture(0);
-                       CHECKGLERROR
-                       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);CHECKGLERROR
+                       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);
+               }
+
+               // 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))
+               {
+                       r_waterstate.renderingrefraction = true;
+                       r_refdef.view = myview;
+                       r_refdef.view.clipplane = p->plane;
+                       VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
+                       r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
+                       PlaneClassify(&r_refdef.view.clipplane);
+
+                       R_ResetViewRendering3D();
+                       R_ClearScreen(r_refdef.fogenabled);
+                       R_View_Update();
+                       R_RenderScene();
+
+                       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_waterstate.renderingrefraction = false;
                }
+
        }
        r_waterstate.renderingscene = false;
        r_refdef.view = originalview;
@@ -4239,6 +7454,16 @@ void R_Bloom_StartFrame(void)
 {
        int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
 
+       switch(vid.renderpath)
+       {
+       case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               return;
+       }
+
        // set bloomwidth and bloomheight to the bloom resolution that will be
        // used (often less than the screen resolution for faster rendering)
        r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, vid.height);
@@ -4271,7 +7496,7 @@ void R_Bloom_StartFrame(void)
                Cvar_SetValueQuick(&r_damageblur, 0);
        }
 
-       if (!(r_glsl.integer && (r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial))) && !r_bloom.integer && !r_hdr.integer && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0)))
+       if (!(r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial)) && !r_bloom.integer && !r_hdr.integer && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0)))
                screentexturewidth = screentextureheight = 0;
        if (!r_hdr.integer && !r_bloom.integer)
                bloomtexturewidth = bloomtextureheight = 0;
@@ -4285,7 +7510,7 @@ void R_Bloom_StartFrame(void)
                r_bloomstate.screentexturewidth = screentexturewidth;
                r_bloomstate.screentextureheight = screentextureheight;
                if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight)
-                       r_bloomstate.texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, NULL, TEXTYPE_BGRA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+                       r_bloomstate.texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, NULL, TEXTYPE_COLORBUFFER, TEXF_FORCENEAREST | TEXF_CLAMP, NULL);
        }
        if (r_bloomstate.bloomtexturewidth != bloomtexturewidth || r_bloomstate.bloomtextureheight != bloomtextureheight)
        {
@@ -4295,7 +7520,7 @@ void R_Bloom_StartFrame(void)
                r_bloomstate.bloomtexturewidth = bloomtexturewidth;
                r_bloomstate.bloomtextureheight = bloomtextureheight;
                if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight)
-                       r_bloomstate.texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", r_bloomstate.bloomtexturewidth, r_bloomstate.bloomtextureheight, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+                       r_bloomstate.texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", r_bloomstate.bloomtexturewidth, r_bloomstate.bloomtextureheight, NULL, TEXTYPE_COLORBUFFER, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
        }
 
        // when doing a reduced render (HDR) we want to use a smaller area
@@ -4346,27 +7571,20 @@ void R_Bloom_CopyBloomTexture(float colorscale)
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_Color(colorscale, colorscale, colorscale, 1);
        // TODO: optimize with multitexture or GLSL
-       R_SetupGenericShader(true);
        R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
-       R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
+       R_SetupShader_Generic(r_bloomstate.texture_screen, NULL, GL_MODULATE, 1);
        R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
        r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
 
        // we now have a bloom image in the framebuffer
        // copy it into the bloom image texture for later processing
-       R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
-       GL_ActiveTexture(0);
-       CHECKGLERROR
-       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height);CHECKGLERROR
+       R_Mesh_CopyToTexture(r_bloomstate.texture_bloom, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height);
        r_refdef.stats.bloom_copypixels += r_bloomstate.viewport.width * r_bloomstate.viewport.height;
 }
 
 void R_Bloom_CopyHDRTexture(void)
 {
-       R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
-       GL_ActiveTexture(0);
-       CHECKGLERROR
-       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);CHECKGLERROR
+       R_Mesh_CopyToTexture(r_bloomstate.texture_bloom, 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.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
 }
 
@@ -4380,7 +7598,6 @@ void R_Bloom_MakeTexture(void)
        R_ResetViewRendering2D();
        R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
        R_Mesh_ColorPointer(NULL, 0, 0);
-       R_SetupGenericShader(true);
 
        // we have a bloom image in the framebuffer
        CHECKGLERROR
@@ -4392,15 +7609,13 @@ void R_Bloom_MakeTexture(void)
                r = bound(0, r_bloom_colorexponent.value / x, 1);
                GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
                GL_Color(r, r, r, 1);
-               R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+               R_SetupShader_Generic(r_bloomstate.texture_bloom, NULL, GL_MODULATE, 1);
                R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
                R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
                r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
 
                // copy the vertically blurred bloom view to a texture
-               GL_ActiveTexture(0);
-               CHECKGLERROR
-               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height);CHECKGLERROR
+               R_Mesh_CopyToTexture(r_bloomstate.texture_bloom, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height);
                r_refdef.stats.bloom_copypixels += r_bloomstate.viewport.width * r_bloomstate.viewport.height;
        }
 
@@ -4411,7 +7626,7 @@ void R_Bloom_MakeTexture(void)
        brighten = sqrt(brighten);
        if(range >= 1)
                brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
-       R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+       R_SetupShader_Generic(r_bloomstate.texture_bloom, NULL, GL_MODULATE, 1);
        R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f, 0, 0);
 
        for (dir = 0;dir < 2;dir++)
@@ -4450,9 +7665,7 @@ void R_Bloom_MakeTexture(void)
                }
 
                // copy the vertically blurred bloom view to a texture
-               GL_ActiveTexture(0);
-               CHECKGLERROR
-               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height);CHECKGLERROR
+               R_Mesh_CopyToTexture(r_bloomstate.texture_bloom, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height);
                r_refdef.stats.bloom_copypixels += r_bloomstate.viewport.width * r_bloomstate.viewport.height;
        }
 
@@ -4461,7 +7674,7 @@ void R_Bloom_MakeTexture(void)
        if (r_bloom_colorsubtract.value > 0 && vid.support.ext_blend_subtract)
        {
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+               R_SetupShader_Generic(r_bloomstate.texture_bloom, NULL, GL_MODULATE, 1);
                R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
                GL_Color(1, 1, 1, 1);
                R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
@@ -4469,7 +7682,7 @@ void R_Bloom_MakeTexture(void)
 
                GL_BlendFunc(GL_ONE, GL_ONE);
                qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
-               R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
                R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
                GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1);
                R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
@@ -4477,10 +7690,7 @@ void R_Bloom_MakeTexture(void)
                qglBlendEquationEXT(GL_FUNC_ADD_EXT);
 
                // copy the darkened bloom view to a texture
-               R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
-               GL_ActiveTexture(0);
-               CHECKGLERROR
-               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height);CHECKGLERROR
+               R_Mesh_CopyToTexture(r_bloomstate.texture_bloom, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height);
                r_refdef.stats.bloom_copypixels += r_bloomstate.viewport.width * r_bloomstate.viewport.height;
        }
 }
@@ -4541,72 +7751,90 @@ void R_HDR_RenderBloomTexture(void)
 
 static void R_BlendView(void)
 {
-       if (r_bloomstate.texture_screen)
-       {
-               // make sure the buffer is available
-               if (r_bloom_blur.value < 1) { Cvar_SetValueQuick(&r_bloom_blur, 1); }
-
-               R_ResetViewRendering2D();
-               R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
-               R_Mesh_ColorPointer(NULL, 0, 0);
-               R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
-               GL_ActiveTexture(0);CHECKGLERROR
-
-               if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))
-               {  
-                       // declare variables
-                       float speed;
-                       static float avgspeed;
-
-                       speed = VectorLength(cl.movement_velocity);
-
-                       cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_vcoeff.value), 1);
-                       avgspeed = avgspeed * (1 - cl.motionbluralpha) + speed * cl.motionbluralpha;
-
-                       speed = (avgspeed - r_motionblur_vmin.value) / max(1, r_motionblur_vmax.value - r_motionblur_vmin.value);
-                       speed = bound(0, speed, 1);
-                       speed = speed * (1 - r_motionblur_bmin.value) + r_motionblur_bmin.value;
-
-                       // calculate values into a standard alpha
-                       cl.motionbluralpha = 1 - exp(-
-                                       (
-                                        (r_motionblur.value * speed / 80)
-                                        +
-                                        (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
-                                       )
-                                       /
-                                       max(0.0001, cl.time - cl.oldtime) // fps independent
-                                  );
-
-                       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
-                       if (cl.motionbluralpha > 0)
-                       {
-                               R_SetupGenericShader(true);
-                               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-                               GL_Color(1, 1, 1, cl.motionbluralpha);
-                               R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
-                               R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
-                               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
-                               r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
-                       }
-               }
-
-               // copy view into the screen texture
-               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);CHECKGLERROR
-               r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
-       }
+       unsigned int permutation;
+       float uservecs[4][4];
 
-       if (r_glsl.integer && vid.support.arb_fragment_shader && (r_bloomstate.texture_screen || r_bloomstate.texture_bloom))
+       switch (vid.renderpath)
        {
-               unsigned int permutation =
+       case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
+               permutation =
                          (r_bloomstate.texture_bloom ? SHADERPERMUTATION_BLOOM : 0)
                        | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
                        | ((v_glslgamma.value && !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_bloomstate.texture_screen)
+               {
+                       // make sure the buffer is available
+                       if (r_bloom_blur.value < 1) { Cvar_SetValueQuick(&r_bloom_blur, 1); }
+
+                       R_ResetViewRendering2D();
+                       R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
+                       R_Mesh_ColorPointer(NULL, 0, 0);
+
+                       if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))
+                       {
+                               // declare variables
+                               float speed;
+                               static float avgspeed;
+
+                               speed = VectorLength(cl.movement_velocity);
+
+                               cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_vcoeff.value), 1);
+                               avgspeed = avgspeed * (1 - cl.motionbluralpha) + speed * cl.motionbluralpha;
+
+                               speed = (avgspeed - r_motionblur_vmin.value) / max(1, r_motionblur_vmax.value - r_motionblur_vmin.value);
+                               speed = bound(0, speed, 1);
+                               speed = speed * (1 - r_motionblur_bmin.value) + r_motionblur_bmin.value;
+
+                               // calculate values into a standard alpha
+                               cl.motionbluralpha = 1 - exp(-
+                                               (
+                                                (r_motionblur.value * speed / 80)
+                                                +
+                                                (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
+                                               )
+                                               /
+                                               max(0.0001, cl.time - cl.oldtime) // fps independent
+                                          );
+
+                               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
+                               if (cl.motionbluralpha > 0)
+                               {
+                                       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+                                       GL_Color(1, 1, 1, cl.motionbluralpha);
+                                       R_SetupShader_Generic(r_bloomstate.texture_screen, NULL, GL_MODULATE, 1);
+                                       R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
+                                       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
+                                       r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
+                               }
+                       }
+
+                       // copy view into the screen texture
+                       R_Mesh_CopyToTexture(r_bloomstate.texture_screen, 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.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
+               }
+               else if (!r_bloomstate.texture_bloom)
+               {
+                       // 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();
+                               R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
+                               R_Mesh_ColorPointer(NULL, 0, 0);
+                               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+                               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+                               GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
+                               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
+                       }
+                       break; // no screen processing, no bloom, skip it
+               }
+
                if (r_bloomstate.texture_bloom && !r_bloomstate.hdr)
                {
                        // render simple bloom effect
@@ -4616,122 +7844,75 @@ static void R_BlendView(void)
                        R_Bloom_MakeTexture();
                }
 
+#if _MSC_VER >= 1400
+#define sscanf sscanf_s
+#endif
+               memset(uservecs, 0, sizeof(uservecs));
+               sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
+               sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
+               sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
+               sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
+
                R_ResetViewRendering2D();
                R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
                R_Mesh_ColorPointer(NULL, 0, 0);
                GL_Color(1, 1, 1, 1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_SetupShader_SetPermutation(SHADERMODE_POSTPROCESS, permutation);
-               R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
                R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
-               R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_bloom));
                R_Mesh_TexCoordPointer(1, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
-               if (r_glsl_permutation->loc_Texture_GammaRamps >= 0)
-                       R_Mesh_TexBind(GL20TU_GAMMARAMPS, R_GetTexture(r_texture_gammaramps));
-               if (r_glsl_permutation->loc_TintColor >= 0)
-                       qglUniform4fARB(r_glsl_permutation->loc_TintColor, r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
-               if (r_glsl_permutation->loc_ClientTime >= 0)
-                       qglUniform1fARB(r_glsl_permutation->loc_ClientTime, cl.time);
-               if (r_glsl_permutation->loc_PixelSize >= 0)
-                       qglUniform2fARB(r_glsl_permutation->loc_PixelSize, 1.0/r_bloomstate.screentexturewidth, 1.0/r_bloomstate.screentextureheight);
-               if (r_glsl_permutation->loc_UserVec1 >= 0)
-               {
-                       float a=0, b=0, c=0, d=0;
-#if _MSC_VER >= 1400
-#define sscanf sscanf_s
+
+               switch(vid.renderpath)
+               {
+               case RENDERPATH_GL20:
+                       R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
+                       if (r_glsl_permutation->loc_Texture_First      >= 0) R_Mesh_TexBind(GL20TU_FIRST     , r_bloomstate.texture_screen);
+                       if (r_glsl_permutation->loc_Texture_Second     >= 0) R_Mesh_TexBind(GL20TU_SECOND    , r_bloomstate.texture_bloom );
+                       if (r_glsl_permutation->loc_Texture_GammaRamps >= 0) R_Mesh_TexBind(GL20TU_GAMMARAMPS, r_texture_gammaramps       );
+                       if (r_glsl_permutation->loc_ViewTintColor      >= 0) qglUniform4fARB(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) qglUniform2fARB(r_glsl_permutation->loc_PixelSize         , 1.0/r_bloomstate.screentexturewidth, 1.0/r_bloomstate.screentextureheight);
+                       if (r_glsl_permutation->loc_UserVec1           >= 0) qglUniform4fARB(r_glsl_permutation->loc_UserVec1          , uservecs[0][0], uservecs[0][1], uservecs[0][2], uservecs[0][3]);
+                       if (r_glsl_permutation->loc_UserVec2           >= 0) qglUniform4fARB(r_glsl_permutation->loc_UserVec2          , uservecs[1][0], uservecs[1][1], uservecs[1][2], uservecs[1][3]);
+                       if (r_glsl_permutation->loc_UserVec3           >= 0) qglUniform4fARB(r_glsl_permutation->loc_UserVec3          , uservecs[2][0], uservecs[2][1], uservecs[2][2], uservecs[2][3]);
+                       if (r_glsl_permutation->loc_UserVec4           >= 0) qglUniform4fARB(r_glsl_permutation->loc_UserVec4          , uservecs[3][0], uservecs[3][1], uservecs[3][2], uservecs[3][3]);
+                       if (r_glsl_permutation->loc_Saturation         >= 0) qglUniform1fARB(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
+                       if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2fARB(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
+                       break;
+               case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+                       R_SetupShader_SetPermutationCG(SHADERMODE_POSTPROCESS, permutation);
+                       if (r_cg_permutation->fp_Texture_First     ) CG_BindTexture(r_cg_permutation->fp_Texture_First     , r_bloomstate.texture_screen);CHECKCGERROR
+                       if (r_cg_permutation->fp_Texture_Second    ) CG_BindTexture(r_cg_permutation->fp_Texture_Second    , r_bloomstate.texture_bloom );CHECKCGERROR
+                       if (r_cg_permutation->fp_Texture_GammaRamps) CG_BindTexture(r_cg_permutation->fp_Texture_GammaRamps, r_texture_gammaramps       );CHECKCGERROR
+                       if (r_cg_permutation->fp_ViewTintColor     ) cgGLSetParameter4f(     r_cg_permutation->fp_ViewTintColor     , r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);CHECKCGERROR
+                       if (r_cg_permutation->fp_PixelSize         ) cgGLSetParameter2f(     r_cg_permutation->fp_PixelSize         , 1.0/r_bloomstate.screentexturewidth, 1.0/r_bloomstate.screentextureheight);CHECKCGERROR
+                       if (r_cg_permutation->fp_UserVec1          ) cgGLSetParameter4f(     r_cg_permutation->fp_UserVec1          , uservecs[0][0], uservecs[0][1], uservecs[0][2], uservecs[0][3]);CHECKCGERROR
+                       if (r_cg_permutation->fp_UserVec2          ) cgGLSetParameter4f(     r_cg_permutation->fp_UserVec2          , uservecs[1][0], uservecs[1][1], uservecs[1][2], uservecs[1][3]);CHECKCGERROR
+                       if (r_cg_permutation->fp_UserVec3          ) cgGLSetParameter4f(     r_cg_permutation->fp_UserVec3          , uservecs[2][0], uservecs[2][1], uservecs[2][2], uservecs[2][3]);CHECKCGERROR
+                       if (r_cg_permutation->fp_UserVec4          ) cgGLSetParameter4f(     r_cg_permutation->fp_UserVec4          , uservecs[3][0], uservecs[3][1], uservecs[3][2], uservecs[3][3]);CHECKCGERROR
+                       if (r_cg_permutation->fp_Saturation        ) cgGLSetParameter1f(     r_cg_permutation->fp_Saturation        , r_glsl_saturation.value);CHECKCGERROR
+                       if (r_cg_permutation->fp_PixelToScreenTexCoord) cgGLSetParameter2f(r_cg_permutation->fp_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height);CHECKCGERROR
 #endif
-                       sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &a, &b, &c, &d);
-                       qglUniform4fARB(r_glsl_permutation->loc_UserVec1, a, b, c, d);
-               }
-               if (r_glsl_permutation->loc_UserVec2 >= 0)
-               {
-                       float a=0, b=0, c=0, d=0;
-                       sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &a, &b, &c, &d);
-                       qglUniform4fARB(r_glsl_permutation->loc_UserVec2, a, b, c, d);
-               }
-               if (r_glsl_permutation->loc_UserVec3 >= 0)
-               {
-                       float a=0, b=0, c=0, d=0;
-                       sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &a, &b, &c, &d);
-                       qglUniform4fARB(r_glsl_permutation->loc_UserVec3, a, b, c, d);
-               }
-               if (r_glsl_permutation->loc_UserVec4 >= 0)
-               {
-                       float a=0, b=0, c=0, d=0;
-                       sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &a, &b, &c, &d);
-                       qglUniform4fARB(r_glsl_permutation->loc_UserVec4, a, b, c, d);
+                       break;
+               default:
+                       break;
                }
-               if (r_glsl_permutation->loc_Saturation >= 0)
-                       qglUniform1fARB(r_glsl_permutation->loc_Saturation, r_glsl_saturation.value);
-               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
-               r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
-               return;
-       }
-
-
-
-       if (r_bloomstate.texture_bloom && r_bloomstate.hdr)
-       {
-               // render high dynamic range bloom effect
-               // the bloom texture was made earlier this render, so we just need to
-               // blend it onto the screen...
-               R_ResetViewRendering2D();
-               R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
-               R_Mesh_ColorPointer(NULL, 0, 0);
-               R_SetupGenericShader(true);
-               GL_Color(1, 1, 1, 1);
-               GL_BlendFunc(GL_ONE, GL_ONE);
-               R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
-               R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
                R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
                r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
-       }
-       else if (r_bloomstate.texture_bloom)
-       {
-               // render simple bloom effect
-               // copy the screen and shrink it and darken it for the bloom process
-               R_Bloom_CopyBloomTexture(r_bloom_colorscale.value);
-               // make the bloom texture
-               R_Bloom_MakeTexture();
-               // put the original screen image back in place and blend the bloom
-               // texture on it
-               R_ResetViewRendering2D();
-               R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
-               R_Mesh_ColorPointer(NULL, 0, 0);
-               GL_Color(1, 1, 1, 1);
-               GL_BlendFunc(GL_ONE, GL_ZERO);
-               // do both in one pass if possible
-               R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
-               R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
-               if (r_textureunits.integer >= 2 && gl_combine.integer)
-               {
-                       R_SetupGenericTwoTextureShader(GL_ADD);
-                       R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_screen));
-                       R_Mesh_TexCoordPointer(1, 2, r_bloomstate.screentexcoord2f, 0, 0);
-               }
-               else
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
                {
-                       R_SetupGenericShader(true);
+                       // apply a color tint to the whole view
+                       R_ResetViewRendering2D();
+                       R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
+                       R_Mesh_ColorPointer(NULL, 0, 0);
+                       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+                       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+                       GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
                        R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
-                       r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
-                       // now blend on the bloom texture
-                       GL_BlendFunc(GL_ONE, GL_ONE);
-                       R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
-                       R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
                }
-               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
-               r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
-       }
-       if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
-       {
-               // apply a color tint to the whole view
-               R_ResetViewRendering2D();
-               R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
-               R_Mesh_ColorPointer(NULL, 0, 0);
-               R_SetupGenericShader(false);
-               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-               GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
-               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
+               break;
        }
 }
 
@@ -4766,7 +7947,7 @@ void R_UpdateVariables(void)
 {
        R_Textures_Frame();
 
-       r_refdef.scene.ambient = r_ambient.value;
+       r_refdef.scene.ambient = r_ambient.value * (1.0f / 64.0f);
 
        r_refdef.farclip = r_farclip_base.value;
        if (r_refdef.scene.worldmodel)
@@ -4851,39 +8032,48 @@ void R_UpdateVariables(void)
        else
                r_refdef.fogenabled = false;
 
-       if(r_glsl.integer && v_glslgamma.integer && !vid_gammatables_trivial)
+       switch(vid.renderpath)
        {
-               if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
+       case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
+               if(v_glslgamma.integer && !vid_gammatables_trivial)
                {
-                       // build GLSL gamma texture
+                       if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
+                       {
+                               // build GLSL gamma texture
 #define RAMPWIDTH 256
-                       unsigned short ramp[RAMPWIDTH * 3];
-                       unsigned char rampbgr[RAMPWIDTH][4];
-                       int i;
+                               unsigned short ramp[RAMPWIDTH * 3];
+                               unsigned char rampbgr[RAMPWIDTH][4];
+                               int i;
 
-                       r_texture_gammaramps_serial = vid_gammatables_serial;
+                               r_texture_gammaramps_serial = vid_gammatables_serial;
 
-                       VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
-                       for(i = 0; i < RAMPWIDTH; ++i)
-                       {
-                               rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
-                               rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
-                               rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
-                               rampbgr[i][3] = 0;
-                       }
-                       if (r_texture_gammaramps)
-                       {
-                               R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, RAMPWIDTH, 1);
-                       }
-                       else
-                       {
-                               r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
+                               VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
+                               for(i = 0; i < RAMPWIDTH; ++i)
+                               {
+                                       rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
+                                       rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
+                                       rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
+                                       rampbgr[i][3] = 0;
+                               }
+                               if (r_texture_gammaramps)
+                               {
+                                       R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, RAMPWIDTH, 1);
+                               }
+                               else
+                               {
+                                       r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT | TEXF_ALLOWUPDATES, NULL);
+                               }
                        }
                }
-       }
-       else
-       {
-               // remove GLSL gamma texture
+               else
+               {
+                       // remove GLSL gamma texture
+               }
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               break;
        }
 }
 
@@ -4928,10 +8118,14 @@ void R_RenderView(void)
 {
        if (r_timereport_active)
                R_TimeReport("start");
-       r_frame++; // used only by R_GetCurrentTexture
+       r_textureframe++; // used only by R_GetCurrentTexture
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 
-       R_AnimCache_NewFrame();
+       if (!r_drawentities.integer)
+               r_refdef.scene.numentities = 0;
+
+       R_AnimCache_ClearCache();
+       R_FrameData_NewFrame();
 
        if (r_refdef.view.isoverlay)
        {
@@ -4984,7 +8178,11 @@ void R_RenderView(void)
 
        // this produces a bloom texture to be used in R_BlendView() later
        if (r_hdr.integer && r_bloomstate.bloomwidth)
+       {
                R_HDR_RenderBloomTexture();
+               // we have to bump the texture frame again because r_refdef.view.colorscale is cached in the textures
+               r_textureframe++; // used only by R_GetCurrentTexture
+       }
 
        r_refdef.view.showdebug = true;
 
@@ -5040,9 +8238,14 @@ extern cvar_t cl_locs_show;
 static void R_DrawLocs(void);
 static void R_DrawEntityBBoxes(void);
 static void R_DrawModelDecals(void);
+extern void R_DrawModelShadows(void);
+extern void R_DrawModelShadowMaps(void);
 extern cvar_t cl_decals_newsystem;
+extern qboolean r_shadow_usingdeferredprepass;
 void R_RenderScene(void)
 {
+       qboolean shadowmapping = false;
+
        r_refdef.stats.renders++;
 
        R_UpdateFogColor();
@@ -5079,10 +8282,26 @@ void R_RenderScene(void)
                        R_SetupView(false);
                        R_Sky();
                        R_SetupView(true);
+                       if (r_timereport_active)
+                               R_TimeReport("sky");
                }
        }
 
        R_AnimCache_CacheVisibleEntities();
+       if (r_timereport_active)
+               R_TimeReport("animation");
+
+       R_Shadow_PrepareLights();
+       if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
+               R_Shadow_PrepareModelShadows();
+       if (r_timereport_active)
+               R_TimeReport("preparelights");
+
+       if (R_Shadow_ShadowMappingEnabled())
+               shadowmapping = true;
+
+       if (r_shadow_usingdeferredprepass)
+               R_Shadow_DrawPrepass();
 
        if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
        {
@@ -5097,6 +8316,15 @@ void R_RenderScene(void)
                        R_TimeReport("modeldepth");
        }
 
+       if (r_shadows.integer > 0 && shadowmapping && r_refdef.lightmapintensity > 0)
+       {
+               R_DrawModelShadowMaps();
+               R_ResetViewRendering3D();
+               // don't let sound skip if going slow
+               if (r_refdef.scene.extraupdate)
+                       S_ExtraUpdate ();
+       }
+
        if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
        {
                r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
@@ -5116,7 +8344,7 @@ void R_RenderScene(void)
        if (r_refdef.scene.extraupdate)
                S_ExtraUpdate ();
 
-       if (r_shadows.integer > 0 && !r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
+       if (r_shadows.integer > 0 && !shadowmapping && !r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
        {
                R_DrawModelShadows();
                R_ResetViewRendering3D();
@@ -5125,15 +8353,18 @@ void R_RenderScene(void)
                        S_ExtraUpdate ();
        }
 
-       R_ShadowVolumeLighting(false);
-       if (r_timereport_active)
-               R_TimeReport("rtlights");
+       if (!r_shadow_usingdeferredprepass)
+       {
+               R_Shadow_DrawLights();
+               if (r_timereport_active)
+                       R_TimeReport("rtlights");
+       }
 
        // don't let sound skip if going slow
        if (r_refdef.scene.extraupdate)
                S_ExtraUpdate ();
 
-       if (r_shadows.integer > 0 && r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
+       if (r_shadows.integer > 0 && !shadowmapping && r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
        {
                R_DrawModelShadows();
                R_ResetViewRendering3D();
@@ -5170,7 +8401,6 @@ void R_RenderScene(void)
                        R_TimeReport("lightning");
        }
 
-       R_SetupGenericShader(true);
        VM_CL_AddPolygonsToMeshQueue();
 
        if (r_refdef.view.showdebug)
@@ -5197,13 +8427,10 @@ void R_RenderScene(void)
                }
        }
 
-       R_SetupGenericShader(true);
        R_MeshQueue_RenderTransparent();
        if (r_timereport_active)
                R_TimeReport("drawtrans");
 
-       R_SetupGenericShader(true);
-
        if (r_refdef.view.showdebug && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDebug && (r_showtris.value > 0 || r_shownormals.value != 0 || r_showcollisionbrushes.value > 0))
        {
                r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
@@ -5214,11 +8441,9 @@ void R_RenderScene(void)
                        R_TimeReport("modeldebug");
        }
 
-       R_SetupGenericShader(true);
-
        if (cl.csqc_vidvars.drawworld)
        {
-               R_DrawCoronas();
+               R_Shadow_DrawCoronas();
                if (r_timereport_active)
                        R_TimeReport("coronas");
        }
@@ -5276,7 +8501,7 @@ void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, floa
        R_Mesh_VertexPointer(vertex3f, 0, 0);
        R_Mesh_ColorPointer(color4f, 0, 0);
        R_Mesh_ResetTextureState();
-       R_SetupGenericShader(false);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
        R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
 }
 
@@ -5292,7 +8517,7 @@ static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtligh
                return;
 
        GL_CullFace(GL_NONE);
-       R_SetupGenericShader(false);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
 
        prog = 0;
        SV_VM_Begin();
@@ -5408,7 +8633,7 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight
                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
                GL_DepthMask(false);
        }
-       else if (rsurface.ent_color[3] < 1)
+       else if (rsurface.colormod[3] < 1)
        {
                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                GL_DepthMask(false);
@@ -5422,16 +8647,16 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight
        GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
        GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
        GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
-       R_SetupGenericShader(false);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
        R_Mesh_VertexPointer(rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
        memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
        R_Mesh_ColorPointer(color4f, 0, 0);
        for (i = 0, c = color4f;i < 6;i++, c += 4)
        {
-               c[0] *= rsurface.ent_color[0];
-               c[1] *= rsurface.ent_color[1];
-               c[2] *= rsurface.ent_color[2];
-               c[3] *= rsurface.ent_color[3];
+               c[0] *= rsurface.colormod[0];
+               c[1] *= rsurface.colormod[1];
+               c[2] *= rsurface.colormod[2];
+               c[3] *= rsurface.colormod[3];
        }
        if (r_refdef.fogenabled)
        {
@@ -5612,9 +8837,9 @@ static void R_Texture_AddLayer(texture_t *t, qboolean depthmask, int blendfunc1,
        layer->blendfunc2 = blendfunc2;
        layer->texture = texture;
        layer->texmatrix = *matrix;
-       layer->color[0] = r * r_refdef.view.colorscale;
-       layer->color[1] = g * r_refdef.view.colorscale;
-       layer->color[2] = b * r_refdef.view.colorscale;
+       layer->color[0] = r;
+       layer->color[1] = g;
+       layer->color[2] = b;
        layer->color[3] = a;
 }
 
@@ -5712,7 +8937,7 @@ void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *t
 
 void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
 {
-       int textureflags = TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP | TEXF_COMPRESS;
+       int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP | TEXF_COMPRESS;
        char name[MAX_QPATH];
        skinframe_t *skinframe;
        unsigned char pixels[296*194];
@@ -5729,7 +8954,7 @@ void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
                f = FS_LoadFile(name, tempmempool, true, &filesize);
                if (f)
                {
-                       if (LoadPCX_QWSkin(f, filesize, pixels, 296, 194))
+                       if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
                                skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
                        Mem_Free(f);
                }
@@ -5744,9 +8969,9 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        dp_model_t *model = ent->model;
        q3shaderinfo_layer_tcmod_t *tcmod;
 
-       if (t->update_lastrenderframe == r_frame && t->update_lastrenderentity == (void *)ent)
+       if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent)
                return t->currentframe;
-       t->update_lastrenderframe = r_frame;
+       t->update_lastrenderframe = r_textureframe;
        t->update_lastrenderentity = (void *)ent;
 
        // switch to an alternate material if this is a q1bsp animated material
@@ -5799,7 +9024,7 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                t->backgroundcurrentskinframe = t->backgroundskinframes[(int)(t->backgroundskinframerate * (cl.time - rsurface.ent_shadertime)) % t->backgroundnumskinframes];
 
        t->currentmaterialflags = t->basematerialflags;
-       t->currentalpha = rsurface.ent_color[3];
+       t->currentalpha = rsurface.colormod[3];
        if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer))
                t->currentalpha *= r_wateralpha.value;
        if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_waterstate.enabled && !r_refdef.view.isoverlay)
@@ -5808,7 +9033,7 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION);
        if (!(rsurface.ent_flags & RENDER_LIGHT))
                t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
-       else if (rsurface.modeltexcoordlightmap2f == NULL)
+       else if (rsurface.modeltexcoordlightmap2f == NULL && !(t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
        {
                // pick a model lighting mode
                if (VectorLength2(rsurface.modellight_diffuse) >= (1.0f / 256.0f))
@@ -5833,6 +9058,8 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        }
        else
                t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER);
+       if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
+               t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
 
        // there is no tcmod
        if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
@@ -5855,9 +9082,33 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        if (t->currentskinframe->qpixels)
                R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
        t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
+       if (!t->basetexture)
+               t->basetexture = r_texture_notexture;
+       t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
+       t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
+       t->nmaptexture = t->currentskinframe->nmap;
+       if (!t->nmaptexture)
+               t->nmaptexture = r_texture_blanknormalmap;
        t->glosstexture = r_texture_black;
-       t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white;
-       t->backgroundglosstexture = r_texture_black;
+       t->glowtexture = t->currentskinframe->glow;
+       t->fogtexture = t->currentskinframe->fog;
+       t->reflectmasktexture = t->currentskinframe->reflect;
+       if (t->backgroundnumskinframes)
+       {
+               t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
+               t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
+               t->backgroundglosstexture = r_texture_black;
+               t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
+               if (!t->backgroundnmaptexture)
+                       t->backgroundnmaptexture = r_texture_blanknormalmap;
+       }
+       else
+       {
+               t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white;
+               t->backgroundnmaptexture = r_texture_blanknormalmap;
+               t->backgroundglosstexture = r_texture_black;
+               t->backgroundglowtexture = NULL;
+       }
        t->specularpower = r_shadow_glossexponent.value;
        // TODO: store reference values for these in the texture?
        t->specularscale = 0;
@@ -5889,17 +9140,26 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        if (gl_lightmaps.integer)
        {
                t->basetexture = r_texture_grey128;
+               t->pantstexture = r_texture_black;
+               t->shirttexture = r_texture_black;
+               t->nmaptexture = r_texture_blanknormalmap;
+               t->glosstexture = r_texture_black;
+               t->glowtexture = NULL;
+               t->fogtexture = NULL;
+               t->reflectmasktexture = NULL;
                t->backgroundbasetexture = NULL;
+               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));
        }
 
-       Vector4Set(t->lightmapcolor, rsurface.ent_color[0], rsurface.ent_color[1], rsurface.ent_color[2], t->currentalpha);
+       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)
        {
-               int layerflags = 0;
                int blendfunc1, blendfunc2;
                qboolean depthmask;
                if (t->currentmaterialflags & MATERIALFLAG_ADD)
@@ -5923,23 +9183,21 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                        blendfunc2 = GL_ZERO;
                }
                depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
-               if (r_refdef.fogenabled && (t->currentmaterialflags & MATERIALFLAG_BLENDED))
-                       layerflags |= TEXTURELAYERFLAG_FOGDARKEN;
                if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
                {
                        // fullbright is not affected by r_refdef.lightmapintensity
                        R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, t->lightmapcolor[0], t->lightmapcolor[1], t->lightmapcolor[2], t->lightmapcolor[3]);
-                       if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &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->currentskinframe->shirt)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * t->lightmapcolor[0], rsurface.colormap_shirtcolor[1] * t->lightmapcolor[1], rsurface.colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
+                       if (VectorLength2(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, rsurface.ent_color[0] * t->lightmapcolor[3], rsurface.ent_color[1] * t->lightmapcolor[3], rsurface.ent_color[2] * t->lightmapcolor[3]);
+                       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
@@ -5948,27 +9206,27 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                        if (model->type == mod_brushq3)
                                colorscale *= r_refdef.scene.rtlightstylevalue[0];
                        colorscale *= r_refdef.lightmapintensity;
-                       VectorScale(t->lightmapcolor, r_refdef.scene.ambient * (1.0f / 64.0f), ambientcolor);
+                       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]);
                        // add pants/shirt if needed
-                       if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->pants, &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->currentskinframe->shirt)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * t->lightmapcolor[0], rsurface.colormap_shirtcolor[1] * t->lightmapcolor[1], rsurface.colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
+                       if (VectorLength2(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->currentskinframe->pants)
-                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &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->currentskinframe->shirt)
-                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &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(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->pantstexture)
+                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->pantstexture, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * ambientcolor[0], rsurface.colormap_pantscolor[1] * ambientcolor[1], rsurface.colormap_pantscolor[2] * ambientcolor[2], t->lightmapcolor[3]);
+                               if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->shirttexture)
+                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->shirttexture, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * ambientcolor[0], rsurface.colormap_shirtcolor[1] * ambientcolor[1], rsurface.colormap_shirtcolor[2] * ambientcolor[2], t->lightmapcolor[3]);
                        }
                }
-               if (t->currentskinframe->glow != NULL && !gl_lightmaps.integer)
-                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->glow, &t->currenttexmatrix, r_hdr_glowintensity.value, r_hdr_glowintensity.value, r_hdr_glowintensity.value, t->lightmapcolor[3]);
+               if (t->glowtexture != NULL && !gl_lightmaps.integer)
+                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->glowtexture, &t->currenttexmatrix, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2], t->lightmapcolor[3]);
                if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
                {
                        // if this is opaque use alpha blend which will darken the earlier
@@ -5982,7 +9240,7 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                        // were darkened by fog already, and we should not add fog color
                        // (because the background was not darkened, there is no fog color
                        // that was lost behind it).
-                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_BLENDED) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->currentskinframe->fog, &identitymatrix, r_refdef.fogcolor[0] / r_refdef.view.colorscale, r_refdef.fogcolor[1] / r_refdef.view.colorscale, r_refdef.fogcolor[2] / r_refdef.view.colorscale, t->lightmapcolor[3]);
+                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_BLENDED) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->fogtexture, &t->currenttexmatrix, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], t->lightmapcolor[3]);
                }
        }
 
@@ -6023,7 +9281,6 @@ void RSurf_ActiveWorldEntity(void)
        rsurface.ent_skinnum = 0;
        rsurface.ent_qwskin = -1;
        rsurface.ent_shadertime = 0;
-       Vector4Set(rsurface.ent_color, 1, 1, 1, 1);
        rsurface.ent_flags = r_refdef.scene.worldentity->flags;
        if (rsurface.array_size < model->surfmesh.num_vertices)
                R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
@@ -6031,7 +9288,7 @@ void RSurf_ActiveWorldEntity(void)
        rsurface.inversematrix = identitymatrix;
        rsurface.matrixscale = 1;
        rsurface.inversematrixscale = 1;
-       R_Mesh_Matrix(&identitymatrix);
+       R_EntityMatrix(&identitymatrix);
        VectorCopy(r_refdef.view.origin, rsurface.localvieworigin);
        Vector4Copy(r_refdef.fogplane, rsurface.fogplane);
        rsurface.fograngerecip = r_refdef.fograngerecip;
@@ -6043,7 +9300,9 @@ void RSurf_ActiveWorldEntity(void)
        VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
        VectorSet(rsurface.colormap_pantscolor, 0, 0, 0);
        VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0);
-       VectorSet(rsurface.glowmod, 1, 1, 1);
+       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;
@@ -6094,7 +9353,7 @@ void RSurf_ActiveWorldEntity(void)
        rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
 }
 
-void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
+void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
 {
        dp_model_t *model = ent->model;
        //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
@@ -6104,7 +9363,6 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        rsurface.ent_skinnum = ent->skinnum;
        rsurface.ent_qwskin = (ent->entitynumber <= cl.maxclients && ent->entitynumber >= 1 && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[ent->entitynumber - 1].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl")) ? (ent->entitynumber - 1) : -1;
        rsurface.ent_shadertime = ent->shadertime;
-       Vector4Set(rsurface.ent_color, ent->colormod[0], ent->colormod[1], ent->colormod[2], ent->alpha);
        rsurface.ent_flags = ent->flags;
        if (rsurface.array_size < model->surfmesh.num_vertices)
                R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
@@ -6112,7 +9370,7 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        rsurface.inversematrix = ent->inversematrix;
        rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
        rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
-       R_Mesh_Matrix(&rsurface.matrix);
+       R_EntityMatrix(&rsurface.matrix);
        Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
        Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
        rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
@@ -6124,24 +9382,26 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        VectorCopy(ent->modellight_lightdir, rsurface.modellight_lightdir);
        VectorCopy(ent->colormap_pantscolor, rsurface.colormap_pantscolor);
        VectorCopy(ent->colormap_shirtcolor, rsurface.colormap_shirtcolor);
-       VectorCopy(ent->glowmod, rsurface.glowmod);
+       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;
        rsurface.basepolygonoffset = r_refdef.polygonoffset;
-       if (ent->model->brush.submodel)
+       if (ent->model->brush.submodel && !prepass)
        {
                rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
                rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
        }
        if (model->surfmesh.isanimated && model->AnimateVertices && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].subframe != 0))
        {
-               if (R_AnimCache_GetEntity((entity_render_t *)ent, wantnormals, wanttangents))
+               if (ent->animcache_vertex3f && !r_framedata_failed)
                {
-                       rsurface.modelvertex3f = r_animcachestate.entity[ent->animcacheindex].vertex3f;
-                       rsurface.modelsvector3f = wanttangents ? r_animcachestate.entity[ent->animcacheindex].svector3f : NULL;
-                       rsurface.modeltvector3f = wanttangents ? r_animcachestate.entity[ent->animcacheindex].tvector3f : NULL;
-                       rsurface.modelnormal3f = wantnormals ? r_animcachestate.entity[ent->animcacheindex].normal3f : NULL;
+                       rsurface.modelvertex3f = ent->animcache_vertex3f;
+                       rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
+                       rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
+                       rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
                }
                else if (wanttangents)
                {
@@ -6232,7 +9492,6 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve
        rsurface.ent_skinnum = 0;
        rsurface.ent_qwskin = -1;
        rsurface.ent_shadertime = shadertime;
-       Vector4Set(rsurface.ent_color, r, g, b, a);
        rsurface.ent_flags = entflags;
        rsurface.modelnum_vertices = numvertices;
        rsurface.modelnum_triangles = numtriangles;
@@ -6242,7 +9501,7 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve
        rsurface.inversematrix = *inversematrix;
        rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
        rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
-       R_Mesh_Matrix(&rsurface.matrix);
+       R_EntityMatrix(&rsurface.matrix);
        Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
        Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
        rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
@@ -6254,7 +9513,8 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve
        VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
        VectorSet(rsurface.colormap_pantscolor, 0, 0, 0);
        VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0);
-       VectorSet(rsurface.glowmod, 1, 1, 1);
+       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;
@@ -6808,15 +10068,12 @@ void RSurf_DrawBatch_Simple(int texturenumsurfaces, const msurface_t **texturesu
        int numtriangles;
        // TODO: lock all array ranges before render, rather than on each surface
        if (texturenumsurfaces == 1)
-       {
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
                R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
-       }
        else if (r_batchmode.integer == 2)
        {
                #define MAXBATCHTRIANGLES 4096
                int batchtriangles = 0;
-               int batchelements[MAXBATCHTRIANGLES*3];
+               static int batchelements[MAXBATCHTRIANGLES*3];
                for (i = 0;i < texturenumsurfaces;i = j)
                {
                        surface = texturesurfacelist[i];
@@ -6856,7 +10113,6 @@ void RSurf_DrawBatch_Simple(int texturenumsurfaces, const msurface_t **texturesu
                        surface2 = texturesurfacelist[j-1];
                        numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
                        numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
-                       GL_LockArrays(surface->num_firstvertex, numvertices);
                        R_Mesh_Draw(surface->num_firstvertex, numvertices, surface->num_firsttriangle, numtriangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
                }
        }
@@ -6865,66 +10121,90 @@ void RSurf_DrawBatch_Simple(int texturenumsurfaces, const msurface_t **texturesu
                for (i = 0;i < texturenumsurfaces;i++)
                {
                        surface = texturesurfacelist[i];
-                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
                        R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
                }
        }
 }
 
-static void RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(int texturenumsurfaces, const msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit, int refractiontexunit, int reflectiontexunit)
+static void RSurf_BindLightmapForSurface(const msurface_t *surface)
+{
+       switch(vid.renderpath)
+       {
+       case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+               if (r_cg_permutation->fp_Texture_Lightmap ) CG_BindTexture(r_cg_permutation->fp_Texture_Lightmap , surface->lightmaptexture );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Deluxemap) CG_BindTexture(r_cg_permutation->fp_Texture_Deluxemap, surface->deluxemaptexture);CHECKCGERROR
+#endif
+               break;
+       case RENDERPATH_GL20:
+               if (r_glsl_permutation->loc_Texture_Lightmap  >= 0) R_Mesh_TexBind(GL20TU_LIGHTMAP , surface->lightmaptexture );
+               if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) R_Mesh_TexBind(GL20TU_DELUXEMAP, surface->deluxemaptexture);
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               R_Mesh_TexBind(0, surface->lightmaptexture);
+               break;
+       }
+}
+
+static void RSurf_BindReflectionForSurface(const msurface_t *surface)
 {
-       int i, planeindex, vertexindex;
+       // pick the closest matching water plane and bind textures
+       int planeindex, vertexindex;
        float d, bestd;
        vec3_t vert;
        const float *v;
        r_waterstate_waterplane_t *p, *bestp;
+       bestd = 0;
+       bestp = NULL;
+       for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
+       {
+               d = 0;
+               for (vertexindex = 0, v = rsurface.modelvertex3f + surface->num_firstvertex * 3;vertexindex < surface->num_vertices;vertexindex++, v += 3)
+               {
+                       Matrix4x4_Transform(&rsurface.matrix, v, vert);
+                       d += fabs(PlaneDiff(vert, &p->plane));
+               }
+               if (bestd > d || !bestp)
+               {
+                       bestd = d;
+                       bestp = p;
+               }
+       }
+       switch(vid.renderpath)
+       {
+       case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+               if (r_cg_permutation->fp_Texture_Refraction) CG_BindTexture(r_cg_permutation->fp_Texture_Refraction, bestp ? bestp->texture_refraction : r_texture_black);CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Reflection) CG_BindTexture(r_cg_permutation->fp_Texture_Reflection, bestp ? bestp->texture_reflection : r_texture_black);CHECKCGERROR
+#endif
+               break;
+       case RENDERPATH_GL20:
+               if (r_glsl_permutation->loc_Texture_Refraction >= 0) R_Mesh_TexBind(GL20TU_REFRACTION, bestp ? bestp->texture_refraction : r_texture_black);
+               if (r_glsl_permutation->loc_Texture_Reflection >= 0) R_Mesh_TexBind(GL20TU_REFLECTION, bestp ? bestp->texture_reflection : r_texture_black);
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               break;
+       }
+}
+
+static void RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(int texturenumsurfaces, const msurface_t **texturesurfacelist)
+{
+       int i;
        const msurface_t *surface;
        if (r_waterstate.renderingscene)
                return;
        for (i = 0;i < texturenumsurfaces;i++)
        {
                surface = texturesurfacelist[i];
-               if (lightmaptexunit >= 0)
-                       R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
-               if (deluxemaptexunit >= 0)
-                       R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
-               // pick the closest matching water plane
-               bestd = 0;
-               bestp = NULL;
-               for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
-               {
-                       d = 0;
-                       for (vertexindex = 0, v = rsurface.modelvertex3f + surface->num_firstvertex * 3;vertexindex < surface->num_vertices;vertexindex++, v += 3)
-                       {
-                               Matrix4x4_Transform(&rsurface.matrix, v, vert);
-                               d += fabs(PlaneDiff(vert, &p->plane));
-                       }
-                       if (bestd > d || !bestp)
-                       {
-                               bestd = d;
-                               bestp = p;
-                       }
-               }
-               if (bestp)
-               {
-                       if (refractiontexunit >= 0)
-                               R_Mesh_TexBind(refractiontexunit, R_GetTexture(bestp->texture_refraction));
-                       if (reflectiontexunit >= 0)
-                               R_Mesh_TexBind(reflectiontexunit, R_GetTexture(bestp->texture_reflection));
-               }
-               else
-               {
-                       if (refractiontexunit >= 0)
-                               R_Mesh_TexBind(refractiontexunit, R_GetTexture(r_texture_black));
-                       if (reflectiontexunit >= 0)
-                               R_Mesh_TexBind(reflectiontexunit, R_GetTexture(r_texture_black));
-               }
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               RSurf_BindLightmapForSurface(surface);
+               RSurf_BindReflectionForSurface(surface);
                R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
        }
 }
 
-static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, const msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit)
+static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, const msurface_t **texturesurfacelist)
 {
        int i;
        int j;
@@ -6934,26 +10214,20 @@ static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, const
        int endvertex;
        int numvertices;
        int numtriangles;
-       // TODO: lock all array ranges before render, rather than on each surface
        if (texturenumsurfaces == 1)
        {
-               R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
-               if (deluxemaptexunit >= 0)
-                       R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               RSurf_BindLightmapForSurface(surface);
                R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
        }
        else if (r_batchmode.integer == 2)
        {
-               #define MAXBATCHTRIANGLES 4096
+#define MAXBATCHTRIANGLES 4096
                int batchtriangles = 0;
-               int batchelements[MAXBATCHTRIANGLES*3];
+               static int batchelements[MAXBATCHTRIANGLES*3];
                for (i = 0;i < texturenumsurfaces;i = j)
                {
                        surface = texturesurfacelist[i];
-                       R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
-                       if (deluxemaptexunit >= 0)
-                               R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
+                       RSurf_BindLightmapForSurface(surface);
                        j = i + 1;
                        if (surface->num_triangles > MAXBATCHTRIANGLES)
                        {
@@ -6997,9 +10271,7 @@ static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, const
                for (i = 0;i < texturenumsurfaces;i = j)
                {
                        surface = texturesurfacelist[i];
-                       R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
-                       if (deluxemaptexunit >= 0)
-                               R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
+                       RSurf_BindLightmapForSurface(surface);
                        for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
                                if (texturesurfacelist[j] != surface2 || texturesurfacelist[j]->lightmaptexture != surface->lightmaptexture)
                                        break;
@@ -7009,7 +10281,6 @@ static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, const
                        surface2 = texturesurfacelist[j-1];
                        numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
                        numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
-                       GL_LockArrays(surface->num_firstvertex, numvertices);
                        R_Mesh_Draw(surface->num_firstvertex, numvertices, surface->num_firsttriangle, numtriangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
                }
 #if 0
@@ -7021,10 +10292,7 @@ static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, const
                for (i = 0;i < texturenumsurfaces;i++)
                {
                        surface = texturesurfacelist[i];
-                       R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
-                       if (deluxemaptexunit >= 0)
-                               R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
-                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+                       RSurf_BindLightmapForSurface(surface);
                        R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
                }
        }
@@ -7054,7 +10322,6 @@ static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, const msurface_
                        const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
                        int k = (int)(((size_t)surface) / sizeof(msurface_t));
                        GL_Color((k & 15) * (1.0f / 16.0f) * r_refdef.view.colorscale, ((k >> 4) & 15) * (1.0f / 16.0f) * r_refdef.view.colorscale, ((k >> 8) & 15) * (1.0f / 16.0f) * r_refdef.view.colorscale, 1);
-                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
                        R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
                }
        }
@@ -7191,9 +10458,9 @@ static void RSurf_DrawBatch_GL11_ApplyAmbient(int texturenumsurfaces, const msur
                const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
                for (i = 0, c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4)
                {
-                       c2[0] = c[0] + r_refdef.scene.ambient / 128.0;
-                       c2[1] = c[1] + r_refdef.scene.ambient / 128.0;
-                       c2[2] = c[2] + r_refdef.scene.ambient / 128.0;
+                       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[3] = c[3];
                }
        }
@@ -7212,7 +10479,7 @@ static void RSurf_DrawBatch_GL11_Lightmap(int texturenumsurfaces, const msurface
        if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
        R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
        GL_Color(r, g, b, a);
-       RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 0, -1);
+       RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist);
 }
 
 static void RSurf_DrawBatch_GL11_Unlit(int texturenumsurfaces, const msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
@@ -7379,7 +10646,7 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_
        // transparent sky would be ridiculous
        if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
                return;
-       R_SetupGenericShader(false);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
        skyrenderlater = true;
        RSurf_SetupDepthAndCulling();
        GL_DepthMask(true);
@@ -7396,7 +10663,7 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_
                R_Mesh_ResetTextureState();
                if (skyrendermasked)
                {
-                       R_SetupDepthOrShadowShader();
+                       R_SetupShader_DepthOrShadow();
                        // depth-only (masking)
                        GL_ColorMask(0,0,0,0);
                        // just to make sure that braindead drivers don't draw
@@ -7405,7 +10672,7 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_
                }
                else
                {
-                       R_SetupGenericShader(false);
+                       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
                        // fog sky
                        GL_BlendFunc(GL_ONE, GL_ZERO);
                }
@@ -7418,107 +10685,45 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_
        GL_Color(1, 1, 1, 1);
 }
 
-static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
+extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
+extern rtexture_t *r_shadow_prepasslightingspeculartexture;
+static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
 {
        if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)))
                return;
-
-       R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
-       R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
-       R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
-       R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
-       R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
-       R_Mesh_TexBind(GL20TU_GLOW, R_GetTexture(rsurface.texture->currentskinframe->glow));
-       if (rsurface.texture->backgroundcurrentskinframe)
-       {
-               R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
-               R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
-               R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
-               R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
-       }
-       if(rsurface.texture->colormapping)
+       RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist);
+       if (prepass)
        {
-               R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
-               R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
+               // 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);
+               RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
        }
-       R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
-       if ((rsurface.uselightmaptexture || (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
-               R_Mesh_ColorPointer(NULL, 0, 0);
-       else
-               R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
-
-       if (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
+       else if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)) && !r_waterstate.renderingscene)
        {
-               // render background
-               GL_BlendFunc(GL_ONE, GL_ZERO);
+               // render water or distortion background, then blend surface on top
                GL_DepthMask(true);
-               GL_AlphaTest(false);
-
-               GL_Color(1, 1, 1, 1);
-               R_Mesh_ColorPointer(NULL, 0, 0);
-
-               R_SetupSurfaceShader(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND);
-               if (r_glsl_permutation)
-               {
-                       RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist);
-                       R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
-                       R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
-                       R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
-                       R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
-                       R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
-                       RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, -1, -1, r_glsl_permutation->loc_Texture_Refraction >= 0 ? GL20TU_REFRACTION : -1, r_glsl_permutation->loc_Texture_Reflection >= 0 ? GL20TU_REFLECTION : -1);
-               }
-               GL_LockArrays(0, 0);
-
-               GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
+               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND);
+               RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist);
                GL_DepthMask(false);
-               if ((rsurface.uselightmaptexture || (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
-                       R_Mesh_ColorPointer(NULL, 0, 0);
+               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE);
+               if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
+                       RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist);
                else
-                       R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
-               R_Mesh_TexBind(GL20TU_REFRACTION, R_GetTexture(r_texture_white)); // changed per surface
-               R_Mesh_TexBind(GL20TU_REFLECTION, R_GetTexture(r_texture_white)); // changed per surface
-       }
-
-       R_SetupSurfaceShader(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE);
-       if (!r_glsl_permutation)
-               return;
-
-       RSurf_PrepareVerticesForBatch(r_glsl_permutation->loc_Texture_Normal >= 0 || r_glsl_permutation->loc_LightDir >= 0, r_glsl_permutation->loc_Texture_Normal >= 0, texturenumsurfaces, texturesurfacelist);
-       R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
-       R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
-       R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
-       R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
-       R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
-
-       if (r_glsl_permutation->loc_Texture_Refraction >= 0)
-       {
-               GL_BlendFunc(GL_ONE, GL_ZERO);
-               GL_DepthMask(true);
-               GL_AlphaTest(false);
+                       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
        }
        else
        {
-               GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
+               // render surface normally
                GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
-               GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
-       }
-
-       if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
-       {
-               if (r_glsl_permutation->loc_Texture_Refraction >= 0 || r_glsl_permutation->loc_Texture_Reflection >= 0)
-                       RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, GL20TU_LIGHTMAP, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? GL20TU_DELUXEMAP : -1, r_glsl_permutation->loc_Texture_Refraction >= 0 ? GL20TU_REFRACTION : -1, r_glsl_permutation->loc_Texture_Reflection >= 0 ? GL20TU_REFLECTION : -1);
-               else
-                       RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, GL20TU_LIGHTMAP, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? GL20TU_DELUXEMAP : -1);
-       }
-       else
-       {
-               if (r_glsl_permutation->loc_Texture_Refraction >= 0 || r_glsl_permutation->loc_Texture_Reflection >= 0)
-                       RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, -1, -1, r_glsl_permutation->loc_Texture_Refraction >= 0 ? GL20TU_REFRACTION : -1, r_glsl_permutation->loc_Texture_Reflection >= 0 ? GL20TU_REFLECTION : -1);
+               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE);
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
+                       RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist);
+               else if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
+                       RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist);
                else
                        RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
        }
-       GL_LockArrays(0, 0);
 }
 
 static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
@@ -7527,7 +10732,6 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface
        int texturesurfaceindex;
        qboolean applycolor;
        qboolean applyfog;
-       rmeshstate_t m;
        int layerindex;
        const texturelayer_t *layer;
        RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
@@ -7566,22 +10770,19 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface
                layercolor[3] = layer->color[3];
                applycolor = layercolor[0] != 1 || layercolor[1] != 1 || layercolor[2] != 1 || layercolor[3] != 1;
                R_Mesh_ColorPointer(NULL, 0, 0);
-               applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
+               applyfog = r_refdef.fogenabled && (rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED);
                switch (layer->type)
                {
                case TEXTURELAYERTYPE_LITTEXTURE:
-                       memset(&m, 0, sizeof(m));
-                       m.tex[0] = R_GetTexture(r_texture_white);
-                       m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
-                       m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
-                       m.tex[1] = R_GetTexture(layer->texture);
-                       m.texmatrix[1] = layer->texmatrix;
-                       m.texrgbscale[1] = layertexrgbscale;
-                       m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
-                       m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
-                       R_Mesh_TextureState(&m);
+                       // single-pass lightmapped texture with 2x rgbscale
+                       R_Mesh_TexBind(0, r_texture_white);
+                       R_Mesh_TexMatrix(0, NULL);
+                       R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+                       R_Mesh_TexCoordPointer(0, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
+                       R_Mesh_TexBind(1, layer->texture);
+                       R_Mesh_TexMatrix(1, &layer->texmatrix);
+                       R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1);
+                       R_Mesh_TexCoordPointer(1, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                        if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
                                RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
                        else if (rsurface.uselightmaptexture)
@@ -7590,28 +10791,31 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface
                                RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
                        break;
                case TEXTURELAYERTYPE_TEXTURE:
-                       memset(&m, 0, sizeof(m));
-                       m.tex[0] = R_GetTexture(layer->texture);
-                       m.texmatrix[0] = layer->texmatrix;
-                       m.texrgbscale[0] = layertexrgbscale;
-                       m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-                       m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-                       R_Mesh_TextureState(&m);
+                       // singletexture unlit texture with transparency support
+                       R_Mesh_TexBind(0, layer->texture);
+                       R_Mesh_TexMatrix(0, &layer->texmatrix);
+                       R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1);
+                       R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+                       R_Mesh_TexBind(1, 0);
+                       R_Mesh_TexCoordPointer(1, 2, NULL, 0, 0);
                        RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
                        break;
                case TEXTURELAYERTYPE_FOG:
-                       memset(&m, 0, sizeof(m));
-                       m.texrgbscale[0] = layertexrgbscale;
+                       // singletexture fogging
                        if (layer->texture)
                        {
-                               m.tex[0] = R_GetTexture(layer->texture);
-                               m.texmatrix[0] = layer->texmatrix;
-                               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-                               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-                               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
+                               R_Mesh_TexBind(0, layer->texture);
+                               R_Mesh_TexMatrix(0, &layer->texmatrix);
+                               R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+                       }
+                       else
+                       {
+                               R_Mesh_TexBind(0, 0);
+                               R_Mesh_TexCoordPointer(0, 2, NULL, 0, 0);
                        }
-                       R_Mesh_TextureState(&m);
+                       R_Mesh_TexBind(1, 0);
+                       R_Mesh_TexCoordPointer(1, 2, NULL, 0, 0);
                        // generate a color array for the fog pass
                        R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
                        for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
@@ -7635,7 +10839,6 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface
                default:
                        Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
                }
-               GL_LockArrays(0, 0);
        }
        CHECKGLERROR
        if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
@@ -7650,7 +10853,6 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
        // OpenGL 1.1 - crusty old voodoo path
        int texturesurfaceindex;
        qboolean applyfog;
-       rmeshstate_t m;
        int layerindex;
        const texturelayer_t *layer;
        RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
@@ -7670,7 +10872,7 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
                GL_DepthMask(layer->depthmask && writedepth);
                GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
                R_Mesh_ColorPointer(NULL, 0, 0);
-               applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
+               applyfog = r_refdef.fogenabled && (rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED);
                switch (layer->type)
                {
                case TEXTURELAYERTYPE_LITTEXTURE:
@@ -7678,40 +10880,31 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
                        {
                                // two-pass lit texture with 2x rgbscale
                                // first the lightmap pass
-                               memset(&m, 0, sizeof(m));
-                               m.tex[0] = R_GetTexture(r_texture_white);
-                               m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
-                               m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
-                               m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
-                               R_Mesh_TextureState(&m);
+                               R_Mesh_TexBind(0, r_texture_white);
+                               R_Mesh_TexMatrix(0, NULL);
+                               R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
                                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
                                        RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
                                else if (rsurface.uselightmaptexture)
                                        RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
                                else
                                        RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
-                               GL_LockArrays(0, 0);
                                // then apply the texture to it
                                GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
-                               memset(&m, 0, sizeof(m));
-                               m.tex[0] = R_GetTexture(layer->texture);
-                               m.texmatrix[0] = layer->texmatrix;
-                               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-                               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-                               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-                               R_Mesh_TextureState(&m);
+                               R_Mesh_TexBind(0, layer->texture);
+                               R_Mesh_TexMatrix(0, &layer->texmatrix);
+                               R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                                RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layer->color[0] * 0.5f, layer->color[1] * 0.5f, layer->color[2] * 0.5f, layer->color[3], layer->color[0] != 2 || layer->color[1] != 2 || layer->color[2] != 2 || layer->color[3] != 1, false);
                        }
                        else
                        {
                                // single pass vertex-lighting-only texture with 1x rgbscale and transparency support
-                               memset(&m, 0, sizeof(m));
-                               m.tex[0] = R_GetTexture(layer->texture);
-                               m.texmatrix[0] = layer->texmatrix;
-                               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-                               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-                               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-                               R_Mesh_TextureState(&m);
+                               R_Mesh_TexBind(0, layer->texture);
+                               R_Mesh_TexMatrix(0, &layer->texmatrix);
+                               R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
                                        RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
                                else
@@ -7720,31 +10913,28 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
                        break;
                case TEXTURELAYERTYPE_TEXTURE:
                        // singletexture unlit texture with transparency support
-                       memset(&m, 0, sizeof(m));
-                       m.tex[0] = R_GetTexture(layer->texture);
-                       m.texmatrix[0] = layer->texmatrix;
-                       m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-                       m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-                       R_Mesh_TextureState(&m);
+                       R_Mesh_TexBind(0, layer->texture);
+                       R_Mesh_TexMatrix(0, &layer->texmatrix);
+                       R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+                       R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                        RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
                        break;
                case TEXTURELAYERTYPE_FOG:
                        // singletexture fogging
-                       R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
                        if (layer->texture)
                        {
-                               memset(&m, 0, sizeof(m));
-                               m.tex[0] = R_GetTexture(layer->texture);
-                               m.texmatrix[0] = layer->texmatrix;
-                               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-                               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-                               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-                               R_Mesh_TextureState(&m);
+                               R_Mesh_TexBind(0, layer->texture);
+                               R_Mesh_TexMatrix(0, &layer->texmatrix);
+                               R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                        }
                        else
-                               R_Mesh_ResetTextureState();
+                       {
+                               R_Mesh_TexBind(0, 0);
+                               R_Mesh_TexCoordPointer(0, 2, NULL, 0, 0);
+                       }
                        // generate a color array for the fog pass
+                       R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
                        for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                        {
                                int i;
@@ -7766,7 +10956,6 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
                default:
                        Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
                }
-               GL_LockArrays(0, 0);
        }
        CHECKGLERROR
        if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
@@ -7783,7 +10972,7 @@ static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, const
        GL_AlphaTest(false);
        R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
-       R_SetupGenericShader(false);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
 
        if(rsurface.texture && rsurface.texture->currentskinframe)
        {
@@ -7798,7 +10987,7 @@ static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, const
                c[3] = 1;
        }
 
-       if (rsurface.texture->currentskinframe->pants || rsurface.texture->currentskinframe->shirt)
+       if (rsurface.texture->pantstexture || rsurface.texture->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);
@@ -7881,33 +11070,53 @@ static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, const
        RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
 }
 
-static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
+static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
 {
        CHECKGLERROR
        RSurf_SetupDepthAndCulling();
-       if (r_showsurfaces.integer == 3)
+       if (r_showsurfaces.integer == 3 && !prepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY))
+       {
                R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth);
-       else if (r_glsl.integer && vid.support.arb_fragment_shader)
-               R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth);
-       else if (gl_combine.integer && r_textureunits.integer >= 2)
+               return;
+       }
+       switch (vid.renderpath)
+       {
+       case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
+               R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
+               break;
+       case RENDERPATH_GL13:
                R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist, writedepth);
-       else
+               break;
+       case RENDERPATH_GL11:
                R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist, writedepth);
+               break;
+       }
        CHECKGLERROR
 }
 
-static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
+static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
 {
        CHECKGLERROR
        RSurf_SetupDepthAndCulling();
-       if (r_showsurfaces.integer == 3)
+       if (r_showsurfaces.integer == 3 && !prepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY))
+       {
                R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth);
-       else if (r_glsl.integer && vid.support.arb_fragment_shader)
-               R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth);
-       else if (gl_combine.integer && r_textureunits.integer >= 2)
+               return;
+       }
+       switch (vid.renderpath)
+       {
+       case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
+               R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
+               break;
+       case RENDERPATH_GL13:
                R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist, writedepth);
-       else
+               break;
+       case RENDERPATH_GL11:
                R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist, writedepth);
+               break;
+       }
        CHECKGLERROR
 }
 
@@ -7917,7 +11126,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
        int texturenumsurfaces, endsurface;
        texture_t *texture;
        const msurface_t *surface;
-       const msurface_t *texturesurfacelist[1024];
+       const msurface_t *texturesurfacelist[256];
 
        // if the model is static it doesn't matter what value we give for
        // wantnormals and wanttangents, so this logic uses only rules applicable
@@ -7925,9 +11134,66 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
        if (ent == r_refdef.scene.worldentity)
                RSurf_ActiveWorldEntity();
        else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
-               RSurf_ActiveModelEntity(ent, false, false);
+               RSurf_ActiveModelEntity(ent, false, false, false);
        else
-               RSurf_ActiveModelEntity(ent, true, r_glsl.integer && vid.support.arb_fragment_shader);
+       {
+               switch (vid.renderpath)
+               {
+               case RENDERPATH_GL20:
+               case RENDERPATH_CGGL:
+                       RSurf_ActiveModelEntity(ent, true, true, false);
+                       break;
+               case RENDERPATH_GL13:
+               case RENDERPATH_GL11:
+                       RSurf_ActiveModelEntity(ent, true, false, false);
+                       break;
+               }
+       }
+
+       if (r_transparentdepthmasking.integer)
+       {
+               qboolean setup = false;
+               for (i = 0;i < numsurfaces;i = j)
+               {
+                       j = i + 1;
+                       surface = rsurface.modelsurfaces + surfacelist[i];
+                       texture = surface->texture;
+                       rsurface.texture = R_GetCurrentTexture(texture);
+                       rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
+                       // scan ahead until we find a different texture
+                       endsurface = min(i + 1024, numsurfaces);
+                       texturenumsurfaces = 0;
+                       texturesurfacelist[texturenumsurfaces++] = surface;
+                       for (;j < endsurface;j++)
+                       {
+                               surface = rsurface.modelsurfaces + surfacelist[j];
+                               if (texture != surface->texture || rsurface.uselightmaptexture != (surface->lightmaptexture != NULL))
+                                       break;
+                               texturesurfacelist[texturenumsurfaces++] = surface;
+                       }
+                       if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
+                               continue;
+                       // render the range of surfaces as depth
+                       if (!setup)
+                       {
+                               setup = true;
+                               GL_ColorMask(0,0,0,0);
+                               GL_Color(1,1,1,1);
+                               GL_DepthTest(true);
+                               GL_BlendFunc(GL_ONE, GL_ZERO);
+                               GL_DepthMask(true);
+                               GL_AlphaTest(false);
+                               R_Mesh_ColorPointer(NULL, 0, 0);
+                               R_Mesh_ResetTextureState();
+                               R_SetupShader_DepthOrShadow();
+                       }
+                       RSurf_SetupDepthAndCulling();
+                       RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+                       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+               }
+               if (setup)
+                       GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
+       }
 
        for (i = 0;i < numsurfaces;i = j)
        {
@@ -7949,15 +11215,38 @@ 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);
+                       R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
                else
-                       R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false);
+                       R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
        }
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
        GL_AlphaTest(false);
 }
 
-static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly)
+static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, const entity_render_t *queueentity)
+{
+       // transparent surfaces get pushed off into the transparent queue
+       int surfacelistindex;
+       const msurface_t *surface;
+       vec3_t tempcenter, center;
+       for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
+       {
+               surface = texturesurfacelist[surfacelistindex];
+               tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
+               tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
+               tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
+               Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
+               if (queueentity->transparent_offset) // transparent offset
+               {
+                       center[0] += r_refdef.view.forward[0]*queueentity->transparent_offset;
+                       center[1] += r_refdef.view.forward[1]*queueentity->transparent_offset;
+                       center[2] += r_refdef.view.forward[2]*queueentity->transparent_offset;
+               }
+               R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight);
+       }
+}
+
+static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
 {
        const entity_render_t *queueentity = r_refdef.scene.worldentity;
        CHECKGLERROR
@@ -7971,13 +11260,22 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf
                RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
                RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
        }
-       else if (r_showsurfaces.integer && !r_refdef.view.showdebug)
+       else if (prepass)
+       {
+               if (!rsurface.texture->currentnumlayers)
+                       return;
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity);
+               else
+                       R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
+       }
+       else if (r_showsurfaces.integer && !r_refdef.view.showdebug && !prepass)
        {
                RSurf_SetupDepthAndCulling();
                GL_AlphaTest(false);
                R_Mesh_ColorPointer(NULL, 0, 0);
                R_Mesh_ResetTextureState();
-               R_SetupGenericShader(false);
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
                RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
                GL_DepthMask(true);
                GL_BlendFunc(GL_ONE, GL_ZERO);
@@ -7985,13 +11283,13 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf
                GL_DepthTest(writedepth);
                RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
        }
-       else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
+       else if (r_showsurfaces.integer && r_showsurfaces.integer != 3 && !prepass)
        {
                RSurf_SetupDepthAndCulling();
                GL_AlphaTest(false);
                R_Mesh_ColorPointer(NULL, 0, 0);
                R_Mesh_ResetTextureState();
-               R_SetupGenericShader(false);
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
                RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
                GL_DepthMask(true);
                GL_BlendFunc(GL_ONE, GL_ZERO);
@@ -8004,29 +11302,19 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf
                return;
        else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))) && queueentity)
        {
-               // transparent surfaces get pushed off into the transparent queue
-               int surfacelistindex;
-               const msurface_t *surface;
-               vec3_t tempcenter, center;
-               for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
-               {
-                       surface = texturesurfacelist[surfacelistindex];
-                       tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
-                       tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
-                       tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
-                       Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
-                       R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight);
-               }
+               // in the deferred case, transparent surfaces were queued during prepass
+               if (!r_shadow_usingdeferredprepass)
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity);
        }
        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));
+               R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
        }
        CHECKGLERROR
 }
 
-void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly)
+void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
 {
        int i, j;
        texture_t *texture;
@@ -8040,7 +11328,7 @@ void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, in
                // use skin 1 instead)
                texture = surfacelist[i]->texture;
                rsurface.texture = R_GetCurrentTexture(texture);
-               rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
+               rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL && !depthonly && !prepass;
                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
@@ -8052,11 +11340,11 @@ void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, in
                for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
                        ;
                // render the range of surfaces
-               R_ProcessWorldTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly);
+               R_ProcessWorldTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
        }
 }
 
-static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity)
+static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity, qboolean prepass)
 {
        CHECKGLERROR
        if (depthonly)
@@ -8069,13 +11357,22 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf
                RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
                RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
        }
+       else if (prepass)
+       {
+               if (!rsurface.texture->currentnumlayers)
+                       return;
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity);
+               else
+                       R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
+       }
        else if (r_showsurfaces.integer && !r_refdef.view.showdebug)
        {
                RSurf_SetupDepthAndCulling();
                GL_AlphaTest(false);
                R_Mesh_ColorPointer(NULL, 0, 0);
                R_Mesh_ResetTextureState();
-               R_SetupGenericShader(false);
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
                RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
                GL_DepthMask(true);
                GL_BlendFunc(GL_ONE, GL_ZERO);
@@ -8089,7 +11386,7 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf
                GL_AlphaTest(false);
                R_Mesh_ColorPointer(NULL, 0, 0);
                R_Mesh_ResetTextureState();
-               R_SetupGenericShader(false);
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
                RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
                GL_DepthMask(true);
                GL_BlendFunc(GL_ONE, GL_ZERO);
@@ -8102,35 +11399,19 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf
                return;
        else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))) && queueentity)
        {
-               // transparent surfaces get pushed off into the transparent queue
-               int surfacelistindex;
-               const msurface_t *surface;
-               vec3_t tempcenter, center;
-               for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
-               {
-                       surface = texturesurfacelist[surfacelistindex];
-                       tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
-                       tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
-                       tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
-                       Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
-                       if (queueentity->transparent_offset) // transparent offset
-                       {
-                               center[0] += r_refdef.view.forward[0]*queueentity->transparent_offset;
-                               center[1] += r_refdef.view.forward[1]*queueentity->transparent_offset;
-                               center[2] += r_refdef.view.forward[2]*queueentity->transparent_offset;
-                       }
-                       R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight);
-               }
+               // in the deferred case, transparent surfaces were queued during prepass
+               if (!r_shadow_usingdeferredprepass)
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity);
        }
        else
        {
                // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
-               R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST));
+               R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
        }
        CHECKGLERROR
 }
 
-void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly)
+void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
 {
        int i, j;
        texture_t *texture;
@@ -8144,7 +11425,7 @@ void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurfa
                // use skin 1 instead)
                texture = surfacelist[i]->texture;
                rsurface.texture = R_GetCurrentTexture(texture);
-               rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
+               rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL && !depthonly && !prepass;
                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
@@ -8156,7 +11437,7 @@ void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurfa
                for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
                        ;
                // render the range of surfaces
-               R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent);
+               R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent, prepass);
        }
 }
 
@@ -8193,12 +11474,12 @@ void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, in
        GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
        GL_DepthTest(true);
        GL_CullFace(GL_NONE);
-       R_Mesh_Matrix(&identitymatrix);
+       R_EntityMatrix(&identitymatrix);
 
        R_Mesh_VertexPointer(vertex3f, 0, 0);
        R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
-       R_SetupGenericShader(false);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
 
        i = surfacelist[0];
        GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
@@ -8249,7 +11530,6 @@ static void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float
        tridecal_t *decal;
        tridecal_t *decals;
        int i;
-       int maxdecals;
 
        // expand or initialize the system
        if (decalsystem->maxdecals <= decalsystem->numdecals)
@@ -8276,7 +11556,6 @@ static void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float
        }
 
        // grab a decal and search for another free slot for the next one
-       maxdecals = decalsystem->maxdecals;
        decals = decalsystem->decals;
        decal = decalsystem->decals + (i = decalsystem->freedecal++);
        for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4ub[0][3];i++)
@@ -8333,13 +11612,11 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor
        const msurface_t *surfaces;
        const int *surfacelist;
        const texture_t *texture;
-       int numvertices;
        int numtriangles;
        int numsurfacelist;
        int surfacelistindex;
        int surfaceindex;
        int triangleindex;
-       int decalsurfaceindex;
        int cornerindex;
        int index;
        int numpoints;
@@ -8349,7 +11626,6 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor
        float localmins[3];
        float localmaxs[3];
        float localsize;
-       float ilocalsize;
        float v[9][3];
        float tc[9][2];
        float c[9][4];
@@ -8379,13 +11655,12 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor
                R_DecalSystem_Reset(decalsystem);
        decalsystem->model = model;
 
-       RSurf_ActiveModelEntity(ent, false, false);
+       RSurf_ActiveModelEntity(ent, false, false, false);
 
        Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
        Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
        VectorNormalize(localnormal);
        localsize = worldsize*rsurface.inversematrixscale;
-       ilocalsize = 1.0f / localsize;
        localmins[0] = localorigin[0] - localsize;
        localmins[1] = localorigin[1] - localsize;
        localmins[2] = localorigin[2] - localsize;
@@ -8446,16 +11721,15 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor
        {
                surfaceindex = surfacelist[surfacelistindex];
                surface = surfaces + surfaceindex;
+               // check cull box first because it rejects more than any other check
+               if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
+                       continue;
                // skip transparent surfaces
                texture = surface->texture;
                if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
                        continue;
                if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
                        continue;
-               if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
-                       continue;
-               decalsurfaceindex = ent == r_refdef.scene.worldentity ? surfaceindex : -1;
-               numvertices = surface->num_vertices;
                numtriangles = surface->num_triangles;
                for (triangleindex = 0, e = model->surfmesh.data_element3i + 3*surface->num_firsttriangle;triangleindex < numtriangles;triangleindex++, e += 3)
                {
@@ -8565,7 +11839,6 @@ typedef struct r_decalsystem_splatqueue_s
 r_decalsystem_splatqueue_t;
 
 int r_decalsystem_numqueued = 0;
-#define MAX_DECALSYSTEM_QUEUE 1024
 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
 
 void R_DecalSystem_SplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize)
@@ -8671,14 +11944,13 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
        decalsystem_t *decalsystem = &ent->decalsystem;
        int numdecals;
        tridecal_t *decal;
-       float fadedelay;
        float faderate;
        float alpha;
        float *v3f;
        float *c4f;
        float *t2f;
        const int *e;
-       const unsigned char *surfacevisible = r_refdef.viewcache.world_surfacevisible;
+       const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
        int numtris = 0;
 
        numdecals = decalsystem->numdecals;
@@ -8700,12 +11972,11 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
        if (ent == r_refdef.scene.worldentity)
                RSurf_ActiveWorldEntity();
        else
-               RSurf_ActiveModelEntity(ent, false, false);
+               RSurf_ActiveModelEntity(ent, false, false, false);
 
        decalsystem->lastupdatetime = cl.time;
        decal = decalsystem->decals;
 
-       fadedelay = cl_decals_time.value;
        faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
 
        // update vertex positions for animated models
@@ -8717,7 +11988,7 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
                if (!decal->color4ub[0][3])
                        continue;
 
-               if (decal->surfaceindex >= 0 && !surfacevisible[decal->surfaceindex])
+               if (surfacevisible && !surfacevisible[decal->surfaceindex])
                        continue;
 
                // update color values for fading decals
@@ -8764,6 +12035,16 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
                        VectorCopy(decal->vertex3f[2], v3f + 6);
                }
 
+               if (r_refdef.fogenabled)
+               {
+                       alpha = RSurf_FogVertex(v3f);
+                       VectorScale(c4f, alpha, c4f);
+                       alpha = RSurf_FogVertex(v3f + 3);
+                       VectorScale(c4f + 4, alpha, c4f + 4);
+                       alpha = RSurf_FogVertex(v3f + 6);
+                       VectorScale(c4f + 8, alpha, c4f + 8);
+               }
+
                v3f += 9;
                c4f += 12;
                t2f += 6;
@@ -8773,6 +12054,7 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
        if (numtris > 0)
        {
                r_refdef.stats.drawndecals += numtris;
+
                // now render the decals all at once
                // (this assumes they all use one particle font texture!)
                RSurf_ActiveCustomEntity(&rsurface.matrix, &rsurface.inversematrix, rsurface.ent_flags, rsurface.ent_shadertime, 1, 1, 1, 1, numdecals*3, decalsystem->vertex3f, decalsystem->texcoord2f, NULL, NULL, NULL, decalsystem->color4f, numtris, decalsystem->element3i, decalsystem->element3s, false, false);
@@ -8780,18 +12062,14 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
                R_Mesh_VertexPointer(decalsystem->vertex3f, 0, 0);
                R_Mesh_TexCoordPointer(0, 2, decalsystem->texcoord2f, 0, 0);
                R_Mesh_ColorPointer(decalsystem->color4f, 0, 0);
-               R_SetupGenericShader(true);
                GL_DepthMask(false);
                GL_DepthRange(0, 1);
                GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
                GL_DepthTest(true);
                GL_CullFace(GL_NONE);
                GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
-               R_Mesh_TexBind(0, R_GetTexture(decalskinframe->base));
-               //R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
-               GL_LockArrays(0, numtris * 3);
+               R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1);
                R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, decalsystem->element3s, 0, 0);
-               GL_LockArrays(0, 0);
        }
 }
 
@@ -8822,9 +12100,6 @@ static void R_DrawModelDecals(void)
 
        R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
 
-       if (!r_drawentities.integer)
-               return;
-
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
                if (!r_refdef.viewcache.entityvisible[i])
@@ -8834,12 +12109,11 @@ static void R_DrawModelDecals(void)
        }
 }
 
+extern cvar_t mod_collision_bih;
 void R_DrawDebugModel(void)
 {
        entity_render_t *ent = rsurface.entity;
        int i, j, k, l, flagsmask;
-       const int *elements;
-       q3mbrush_t *brush;
        const msurface_t *surface;
        dp_model_t *model = ent->model;
        vec3_t v;
@@ -8848,31 +12122,51 @@ void R_DrawDebugModel(void)
 
        R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
-       R_SetupGenericShader(false);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
        GL_DepthRange(0, 1);
        GL_DepthTest(!r_showdisabledepthtest.integer);
        GL_DepthMask(false);
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
-       if (r_showcollisionbrushes.value > 0 && model->brush.num_brushes)
+       if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs && mod_collision_bih.integer)
        {
+               int triangleindex;
+               int bihleafindex;
+               qboolean cullbox = ent == r_refdef.scene.worldentity;
+               const q3mbrush_t *brush;
+               const bih_t *bih = &model->collision_bih;
+               const bih_leaf_t *bihleaf;
+               float vertex3f[3][3];
                GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
-               for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
-               {
-                       if (brush->colbrushf && brush->colbrushf->numtriangles)
-                       {
-                               R_Mesh_VertexPointer(brush->colbrushf->points->v, 0, 0);
-                               GL_Color((i & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((i >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((i >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
-                               R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, 0);
-                       }
-               }
-               for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
+               cullbox = false;
+               for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
                {
-                       if (surface->num_collisiontriangles)
+                       if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
+                               continue;
+                       switch (bihleaf->type)
                        {
-                               R_Mesh_VertexPointer(surface->data_collisionvertex3f, 0, 0);
-                               GL_Color((i & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((i >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((i >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
-                               R_Mesh_Draw(0, surface->num_collisionvertices, 0, surface->num_collisiontriangles, surface->data_collisionelement3i, NULL, 0, 0);
+                       case BIH_LEAF:
+                               // brush
+                               brush = model->brush.data_brushes + bihleaf->itemindex;
+                               if (brush->colbrushf && brush->colbrushf->numtriangles)
+                               {
+                                       R_Mesh_VertexPointer(brush->colbrushf->points->v, 0, 0);
+                                       GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
+                                       R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, 0);
+                               }
+                               break;
+                       case BIH_LEAF + 1:
+                               // triangle
+                               triangleindex = bihleaf->itemindex;
+                               VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
+                               VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
+                               VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
+                               R_Mesh_VertexPointer(vertex3f[0], 0, 0);
+                               GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
+                               R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);
+                               break;
+                       default:
+                               break;
                        }
                }
        }
@@ -8907,7 +12201,6 @@ void R_DrawDebugModel(void)
                                                GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
                                        else
                                                GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
-                                       elements = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
                                        R_Mesh_VertexPointer(rsurface.vertex3f, 0, 0);
                                        R_Mesh_ColorPointer(NULL, 0, 0);
                                        R_Mesh_TexCoordPointer(0, 0, NULL, 0, 0);
@@ -8980,10 +12273,9 @@ void R_DrawDebugModel(void)
 extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
 int r_maxsurfacelist = 0;
 const msurface_t **r_surfacelist = NULL;
-void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug)
+void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
 {
-       int i, j, endj, f, flagsmask;
-       texture_t *t;
+       int i, j, endj, flagsmask;
        dp_model_t *model = r_refdef.scene.worldmodel;
        msurface_t *surfaces;
        unsigned char *update;
@@ -9005,7 +12297,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep
        update = model->brushq1.lightmapupdateflags;
 
        // update light styles on this submodel
-       if (!skysurfaces && !depthonly && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0)
+       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++)
@@ -9029,8 +12321,6 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep
                return;
        }
 
-       f = 0;
-       t = NULL;
        rsurface.uselightmaptexture = false;
        rsurface.texture = NULL;
        rsurface.rtlight = NULL;
@@ -9043,18 +12333,27 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep
                        r_surfacelist[numsurfacelist++] = surfaces + j;
        }
        // update lightmaps if needed
-       if (update)
+       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);
+       R_QueueWorldSurfaceList(numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
        GL_AlphaTest(false);
 
        // add to stats if desired
@@ -9068,10 +12367,9 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep
        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)
+void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
 {
-       int i, j, endj, f, flagsmask;
-       texture_t *t;
+       int i, j, endj, flagsmask;
        dp_model_t *model = ent->model;
        msurface_t *surfaces;
        unsigned char *update;
@@ -9093,17 +12391,43 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
        if (ent == r_refdef.scene.worldentity)
                RSurf_ActiveWorldEntity();
        else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
-               RSurf_ActiveModelEntity(ent, false, false);
+               RSurf_ActiveModelEntity(ent, false, false, false);
+       else if (prepass)
+               RSurf_ActiveModelEntity(ent, true, true, true);
        else if (depthonly)
-               RSurf_ActiveModelEntity(ent, false, false);
+       {
+               switch (vid.renderpath)
+               {
+               case RENDERPATH_GL20:
+               case RENDERPATH_CGGL:
+                       RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
+                       break;
+               case RENDERPATH_GL13:
+               case RENDERPATH_GL11:
+                       RSurf_ActiveModelEntity(ent, model->wantnormals, false, false);
+                       break;
+               }
+       }
        else
-               RSurf_ActiveModelEntity(ent, true, r_glsl.integer && vid.support.arb_fragment_shader);
+       {
+               switch (vid.renderpath)
+               {
+               case RENDERPATH_GL20:
+               case RENDERPATH_CGGL:
+                       RSurf_ActiveModelEntity(ent, true, true, false);
+                       break;
+               case RENDERPATH_GL13:
+               case RENDERPATH_GL11:
+                       RSurf_ActiveModelEntity(ent, true, false, false);
+                       break;
+               }
+       }
 
        surfaces = model->data_surfaces;
        update = model->brushq1.lightmapupdateflags;
 
        // update light styles
-       if (!skysurfaces && !depthonly && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0)
+       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++)
@@ -9127,8 +12451,6 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
                return;
        }
 
-       f = 0;
-       t = NULL;
        rsurface.uselightmaptexture = false;
        rsurface.texture = NULL;
        rsurface.rtlight = NULL;
@@ -9143,11 +12465,23 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
                return;
        }
        // update lightmaps if needed
+       if (update)
+       {
+               int updated = 0;
+               for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
+               {
+                       if (update[j])
+                       {
+                               updated++;
+                               R_BuildLightMap(ent, surfaces + j);
+                       }
+               }
+       }
        if (update)
                for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
                        if (update[j])
                                R_BuildLightMap(ent, surfaces + j);
-       R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly);
+       R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
        GL_AlphaTest(false);
 
        // add to stats if desired
@@ -9161,7 +12495,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
-void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth)
+void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
 {
        static texture_t texture;
        static msurface_t surface;
@@ -9185,5 +12519,24 @@ void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, i
        // now render it
        rsurface.texture = R_GetCurrentTexture(surface.texture);
        rsurface.uselightmaptexture = false;
-       R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth);
+       R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
+}
+
+void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
+{
+       static msurface_t surface;
+       const msurface_t *surfacelist = &surface;
+
+       // fake enough texture and surface state to render this geometry
+
+       surface.texture = texture;
+       surface.num_triangles = numtriangles;
+       surface.num_firsttriangle = firsttriangle;
+       surface.num_vertices = numvertices;
+       surface.num_firstvertex = firstvertex;
+
+       // now render it
+       rsurface.texture = R_GetCurrentTexture(surface.texture);
+       rsurface.uselightmaptexture = false;
+       R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
 }