]> 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 8353ecec6b177bffcbf6223020492cc1b0487485..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
@@ -88,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"};
@@ -95,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)"};
@@ -105,6 +111,15 @@ 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"};
@@ -125,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"};
@@ -155,6 +170,9 @@ 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)"};
@@ -201,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;
@@ -225,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;
@@ -283,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)
@@ -326,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)
@@ -342,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++)
@@ -386,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)
@@ -413,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);
        }
 
@@ -447,30 +477,86 @@ 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"
+"#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"
+"#if defined(USESHADOWMAPRECT) || defined(MODE_DEFERREDLIGHTSOURCE) || defined(USEDEFERREDLIGHTMAP)\n"
+"# extension GL_ARB_texture_rectangle : enable\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAP2D\n"
+"# ifdef GL_EXT_gpu_shader4\n"
+"#   extension GL_EXT_gpu_shader4 : enable\n"
+"# endif\n"
+"# ifdef GL_ARB_texture_gather\n"
+"#   extension GL_ARB_texture_gather : enable\n"
+"# else\n"
+"#   ifdef GL_AMD_texture_texture4\n"
+"#     extension GL_AMD_texture_texture4 : enable\n"
+"#   endif\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"# extension GL_EXT_gpu_shader4 : enable\n"
+"#endif\n"
+"\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 myhalf3 half3\n"
+"//# define myhalf4 half4\n"
+"//#else\n"
+"# define myhalf float\n"
+"# define myhalf2 vec2\n"
+"# define myhalf3 vec3\n"
+"# define myhalf4 vec4\n"
+"//#endif\n"
 "\n"
-"// enable various extensions depending on permutation:\n"
+"#ifdef VERTEX_SHADER\n"
+"uniform mat4 ModelViewProjectionMatrix;\n"
+"#endif\n"
 "\n"
 "#ifdef MODE_DEPTH_OR_SHADOW\n"
 "#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
-"      gl_Position = ftransform();\n"
+"      gl_Position = 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(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"
@@ -482,14 +568,21 @@ static const char *builtinshaderstring =
 "}\n"
 "#endif\n"
 "#else // !MODE_SHOWDEPTH\n"
+"\n"
+"\n"
+"\n"
+"\n"
 "#ifdef MODE_POSTPROCESS\n"
+"varying vec2 TexCoord1;\n"
+"varying vec2 TexCoord2;\n"
+"\n"
 "#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\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"
@@ -517,9 +610,9 @@ 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, ViewTintColor, ViewTintColor.a);\n"
@@ -528,11 +621,11 @@ static const char *builtinshaderstring =
 "#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"
@@ -551,18 +644,28 @@ static const char *builtinshaderstring =
 "}\n"
 "#endif\n"
 "#else // !MODE_POSTPROCESS\n"
+"\n"
+"\n"
+"\n"
+"\n"
 "#ifdef MODE_GENERIC\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"
+"      TexCoord1 = gl_MultiTexCoord0.xy;\n"
 "#endif\n"
 "#ifdef USESPECULAR\n"
-"      gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;\n"
+"      TexCoord2 = gl_MultiTexCoord1.xy;\n"
 "#endif\n"
-"      gl_Position = ftransform();\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
 "}\n"
 "#endif\n"
 "\n"
@@ -578,31 +681,36 @@ static const char *builtinshaderstring =
 "{\n"
 "      gl_FragColor = gl_Color;\n"
 "#ifdef USEDIFFUSE\n"
-"      gl_FragColor *= texture2D(Texture_First, gl_TexCoord[0].xy);\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"
+"      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"
 "#endif\n"
 "}\n"
 "#endif\n"
 "#else // !MODE_GENERIC\n"
+"\n"
+"\n"
+"\n"
+"\n"
 "#ifdef MODE_BLOOMBLUR\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"
 "\n"
@@ -613,7 +721,7 @@ static const char *builtinshaderstring =
 "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"
@@ -628,12 +736,13 @@ static const char *builtinshaderstring =
 "#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(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
-"      gl_Position = ftransform();\n"
+"      TexCoord = vec2(TexMatrix * gl_MultiTexCoord0);\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
 "      ModelViewProjectionPosition = gl_Position;\n"
 "}\n"
 "#endif\n"
@@ -671,21 +780,26 @@ static const char *builtinshaderstring =
 "}\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(gl_TextureMatrix[0] * gl_MultiTexCoord0);\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 = ftransform();\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
 "      ModelViewProjectionPosition = gl_Position;\n"
 "}\n"
 "#endif\n"
@@ -708,6 +822,7 @@ static const char *builtinshaderstring =
 "      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"
@@ -730,55 +845,16 @@ static const char *builtinshaderstring =
 "#endif\n"
 "#else // !MODE_WATER\n"
 "\n"
-"#if defined(USESHADOWMAPRECT) || defined(MODE_DEFERREDLIGHTSOURCE) || defined(USEDEFERREDLIGHTMAP)\n"
-"# extension GL_ARB_texture_rectangle : enable\n"
-"#endif\n"
-"\n"
-"#ifdef USESHADOWMAP2D\n"
-"# ifdef GL_EXT_gpu_shader4\n"
-"#   extension GL_EXT_gpu_shader4 : enable\n"
-"# endif\n"
-"# ifdef GL_ARB_texture_gather\n"
-"#   extension GL_ARB_texture_gather : enable\n"
-"# else\n"
-"#   ifdef GL_AMD_texture_texture4\n"
-"#     extension GL_AMD_texture_texture4 : enable\n"
-"#   endif\n"
-"# endif\n"
-"#endif\n"
 "\n"
-"#ifdef USESHADOWMAPCUBE\n"
-"# 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"
 "\n"
-"//#ifdef __GLSL_CG_DATA_TYPES\n"
-"//# define myhalf half\n"
-"//# define myhalf2 half2\n"
-"//# define myhalf3half3\n"
-"//# define myhalf4 half4\n"
-"//#else\n"
-"# define myhalf float\n"
-"# define myhalf2 vec2\n"
-"# define myhalf3 vec3\n"
-"# define myhalf4 vec4\n"
-"//#endif\n"
-"\n"
-"#if defined(USEFOGINSIDE) || defined(USEFOGOUTSIDE)\n"
-"# define USEFOG\n"
-"#endif\n"
-"\n"
 "varying vec2 TexCoord;\n"
 "#ifdef USEVERTEXTEXTUREBLEND\n"
 "varying vec2 TexCoord2;\n"
 "#endif\n"
-"#if defined(MODE_LIGHTMAP) || defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
-"#define USELIGHTMAP\n"
+"#ifdef USELIGHTMAP\n"
 "varying vec2 TexCoordLightmap;\n"
 "#endif\n"
 "\n"
@@ -786,24 +862,18 @@ static const char *builtinshaderstring =
 "varying vec3 CubeVector;\n"
 "#endif\n"
 "\n"
-"#ifdef MODE_LIGHTSOURCE\n"
-"varying vec3 LightVector;\n"
-"#endif\n"
-"#if defined(MODE_LIGHTDIRECTION)\n"
+"#if (defined(MODE_LIGHTSOURCE) || defined(MODE_LIGHTDIRECTION)) && defined(USEDIFFUSE)\n"
 "varying vec3 LightVector;\n"
 "#endif\n"
 "\n"
-"#if defined(USEOFFSETMAPPING) || defined(USESPECULAR)\n"
-"//#if defined(USEOFFSETMAPPING) || defined(USESPECULAR) || defined(MODE_LIGHTDIRECTION) || defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
-"#define USEEYEVECTOR\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)\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"
@@ -826,144 +896,29 @@ static const char *builtinshaderstring =
 "#endif\n"
 "uniform vec4 FogPlane;\n"
 "\n"
-"\n"
-"\n"
-"\n"
-"\n"
-"// vertex shader specific:\n"
-"#ifdef VERTEX_SHADER\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"
-"#ifdef MODE_DEFERREDGEOMETRY\n"
-"void main(void)\n"
-"{\n"
-"      TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
-"#ifdef USEVERTEXTEXTUREBLEND\n"
-"      gl_FrontColor = gl_Color;\n"
-"      TexCoord2 = vec2(gl_TextureMatrix[1] * gl_MultiTexCoord0);\n"
-"#endif\n"
-"\n"
-"      // transform unnormalized eye direction into tangent space\n"
-"#ifdef USEOFFSETMAPPING\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"
-"      VectorS = normalize(gl_NormalMatrix * gl_MultiTexCoord1.xyz).xyz;\n"
-"      VectorT = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz).xyz;\n"
-"      VectorR = normalize(gl_NormalMatrix * gl_MultiTexCoord3.xyz).xyz;\n"
-"      gl_Position = ftransform();\n"
-"}\n"
-"#else // !MODE_DEFERREDGEOMETRY\n"
-"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
-"void main(void)\n"
-"{\n"
-"      ModelViewPosition = gl_ModelViewMatrix * gl_Vertex;\n"
-"      gl_Position = ftransform();\n"
-"}\n"
-"#else // !MODE_DEFERREDLIGHTSOURCE\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(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
-"#ifdef USEVERTEXTEXTUREBLEND\n"
-"      TexCoord2 = vec2(gl_TextureMatrix[1] * 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(gl_TextureMatrix[3] * 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"
-"      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"
-"#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"
-"#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"
-"#endif\n"
-"\n"
-"#ifdef USEFOG\n"
-"#ifndef USEEYEVECTOR\n"
-"      EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
-"#endif\n"
-"      FogPlaneVertexDist = dot(FogPlane, gl_Vertex);\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"varying vec3 ShadowMapTC;\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(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 USEREFLECTION\n"
-"      ModelViewProjectionPosition = gl_Position;\n"
-"#endif\n"
-"}\n"
-"#endif // !MODE_DEFERREDLIGHTSOURCE\n"
-"#endif // !MODE_DEFERREDGEOMETRY\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"
 "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"
@@ -986,12 +941,12 @@ static const char *builtinshaderstring =
 "#endif\n"
 "\n"
 "#ifdef MODE_DEFERREDLIGHTSOURCE\n"
-"uniform sampler2DRect Texture_ScreenDepth;\n"
-"uniform sampler2DRect Texture_ScreenNormalMap;\n"
+"uniform sampler2D Texture_ScreenDepth;\n"
+"uniform sampler2D Texture_ScreenNormalMap;\n"
 "#endif\n"
 "#ifdef USEDEFERREDLIGHTMAP\n"
-"uniform sampler2DRect Texture_ScreenDiffuse;\n"
-"uniform sampler2DRect Texture_ScreenSpecular;\n"
+"uniform sampler2D Texture_ScreenDiffuse;\n"
+"uniform sampler2D Texture_ScreenSpecular;\n"
 "#endif\n"
 "\n"
 "uniform myhalf3 Color_Pants;\n"
@@ -1002,15 +957,17 @@ static const char *builtinshaderstring =
 "uniform float FogRangeRecip;\n"
 "uniform float FogPlaneViewDist;\n"
 "uniform float FogHeightFade;\n"
-"myhalf FogVertex(void)\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 myhalf(texture2D(Texture_FogMask, myhalf2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)));\n"
+"      return float(texture2D(Texture_FogMask, myhalf2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)));\n"
 "}\n"
 "#endif\n"
 "\n"
@@ -1063,6 +1020,9 @@ static const char *builtinshaderstring =
 "#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"
@@ -1098,64 +1058,37 @@ static const char *builtinshaderstring =
 "#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"
-"      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"
-"      return stc;\n"
-"# endif\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"
+"# endif\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"
@@ -1168,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"
@@ -1178,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"
@@ -1241,48 +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"
-"}\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 // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE)\n"
+"#endif // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE) && !defined(USESHADOWMAPORTHO)\n"
+"#endif // FRAGMENT_SHADER\n"
+"\n"
+"\n"
+"\n"
 "\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"
+"      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"
+"      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"
+"#ifdef FRAGMENT_SHADER\n"
 "void main(void)\n"
 "{\n"
 "#ifdef USEOFFSETMAPPING\n"
@@ -1305,14 +1280,31 @@ static const char *builtinshaderstring =
 "\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), 1);\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"
+"\n"
+"\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"
@@ -1322,14 +1314,16 @@ static const char *builtinshaderstring =
 "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 / (texture2DRect(Texture_ScreenDepth, gl_FragCoord.xy).r + ScreenToDepth.x);\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 = texture2DRect(Texture_ScreenNormalMap, gl_FragCoord.xy);\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"
@@ -1346,10 +1340,10 @@ static const char *builtinshaderstring =
 "      // calculate directional shading\n"
 "      vec3 eyevector = position * -1.0;\n"
 "#  ifdef USEEXACTSPECULARMATH\n"
-"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(eyevector)))*-1.0, 0.0)), SpecularPower);\n"
+"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(eyevector)))*-1.0, 0.0)), SpecularPower * normalmap.a);\n"
 "#  else\n"
 "      myhalf3 specularnormal = normalize(lightnormal + myhalf3(normalize(eyevector)));\n"
-"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
+"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * normalmap.a);\n"
 "#  endif\n"
 "#endif\n"
 "\n"
@@ -1370,12 +1364,101 @@ static const char *builtinshaderstring =
 "\n"
 "# ifdef USECUBEFILTER\n"
 "      vec3 cubecolor = textureCube(Texture_Cube, CubeVector).rgb;\n"
-"      gl_FragData[0] *= cubecolor;\n"
-"      gl_FragData[1] *= cubecolor;\n"
+"      gl_FragData[0].rgb *= cubecolor;\n"
+"      gl_FragData[1].rgb *= cubecolor;\n"
 "# endif\n"
 "}\n"
+"#endif // FRAGMENT_SHADER\n"
 "#else // !MODE_DEFERREDLIGHTSOURCE\n"
+"\n"
+"\n"
+"\n"
+"\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"
+"      // 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"
+"#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"
@@ -1393,6 +1476,11 @@ static const char *builtinshaderstring =
 "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"
@@ -1437,28 +1525,39 @@ static const char *builtinshaderstring =
 "      myhalf3 diffusetex = color.rgb;\n"
 "#if defined(USESPECULAR) || defined(USEDEFERREDLIGHTMAP)\n"
 "# ifdef USEVERTEXTEXTUREBLEND\n"
-"      myhalf3 glosstex = mix(myhalf3(texture2D(Texture_SecondaryGloss, TexCoord2)), myhalf3(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n"
+"      myhalf4 glosstex = mix(myhalf4(texture2D(Texture_SecondaryGloss, TexCoord2)), myhalf4(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n"
 "# else\n"
-"      myhalf3 glosstex = myhalf3(texture2D(Texture_Gloss, TexCoord));\n"
+"      myhalf4 glosstex = myhalf4(texture2D(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 = 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);\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);\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"
-"      color.rgb += glosstex * (specular * Color_Specular);\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"
@@ -1475,7 +1574,9 @@ static const char *builtinshaderstring =
 "\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"
@@ -1497,7 +1598,7 @@ 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"
-"      lightcolor *= recip(max(0.25, lightnormal.z));\n"
+"      lightcolor *= 1.0 / max(0.25, lightnormal.z);\n"
 "#endif // MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
 "#ifdef MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
 "#define SHADING\n"
@@ -1527,12 +1628,12 @@ static const char *builtinshaderstring =
 "      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);\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);\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 * Color_Specular * specular) * lightcolor;\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"
@@ -1541,9 +1642,14 @@ static const char *builtinshaderstring =
 "# endif\n"
 "#endif\n"
 "\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"      color.rgb *= ShadowMapCompare(ShadowMapTC);\n"
+"#endif\n"
+"\n"
 "#ifdef USEDEFERREDLIGHTMAP\n"
-"      color.rgb += diffusetex * myhalf3(texture2DRect(Texture_ScreenDiffuse, gl_FragCoord.xy)) * DeferredMod_Diffuse;\n"
-"      color.rgb += glosstex * myhalf3(texture2DRect(Texture_ScreenSpecular, gl_FragCoord.xy)) * DeferredMod_Specular;\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"
@@ -1555,8 +1661,12 @@ static const char *builtinshaderstring =
 "#endif\n"
 "\n"
 "#ifdef USEFOG\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"      color.rgb *= myhalf(FogVertex());\n"
+"#else\n"
 "      color.rgb = mix(FogColor, color.rgb, FogVertex());\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"
@@ -1579,11 +1689,10 @@ static const char *builtinshaderstring =
 "\n"
 "      gl_FragColor = vec4(color);\n"
 "}\n"
-"#endif // !MODE_DEFERREDLIGHTSOURCE\n"
-"#endif // !MODE_DEFERREDGEOMETRY\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"
@@ -1593,132 +1702,1625 @@ static const char *builtinshaderstring =
 "#endif // !MODE_DEPTH_OR_SHADOW\n"
 ;
 
-typedef struct shaderpermutationinfo_s
-{
-       const char *pretext;
-       const char *name;
-}
-shaderpermutationinfo_t;
+/*
+=========================================================================================================================================================
 
-typedef struct shadermodeinfo_s
-{
-       const char *vertexfilename;
-       const char *geometryfilename;
-       const char *fragmentfilename;
-       const char *pretext;
-       const char *name;
-}
-shadermodeinfo_t;
 
-typedef enum shaderpermutation_e
-{
-       SHADERPERMUTATION_DIFFUSE = 1<<0, ///< (lightsource) whether to use directional shading
-       SHADERPERMUTATION_VERTEXTEXTUREBLEND = 1<<1, ///< indicates this is a two-layer material blend based on vertex alpha (q3bsp)
-       SHADERPERMUTATION_VIEWTINT = 1<<2, ///< view tint (postprocessing only)
-       SHADERPERMUTATION_COLORMAPPING = 1<<3, ///< indicates this is a colormapped skin
-       SHADERPERMUTATION_SATURATION = 1<<4, ///< saturation (postprocessing only)
-       SHADERPERMUTATION_FOGINSIDE = 1<<5, ///< tint the color by fog color or black if using additive blend mode
-       SHADERPERMUTATION_FOGOUTSIDE = 1<<6, ///< tint the color by fog color or black if using additive blend mode
-       SHADERPERMUTATION_GAMMARAMPS = 1<<7, ///< gamma (postprocessing only)
-       SHADERPERMUTATION_CUBEFILTER = 1<<8, ///< (lightsource) use cubemap light filter
-       SHADERPERMUTATION_GLOW = 1<<9, ///< (lightmap) blend in an additive glow texture
-       SHADERPERMUTATION_BLOOM = 1<<10, ///< bloom (postprocessing only)
-       SHADERPERMUTATION_SPECULAR = 1<<11, ///< (lightsource or deluxemapping) render specular effects
-       SHADERPERMUTATION_POSTPROCESSING = 1<<12, ///< user defined postprocessing (postprocessing only)
-       SHADERPERMUTATION_EXACTSPECULARMATH = 1<<13, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
-       SHADERPERMUTATION_REFLECTION = 1<<14, ///< normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
-       SHADERPERMUTATION_OFFSETMAPPING = 1<<15, ///< adjust texcoords to roughly simulate a displacement mapped surface
-       SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<16, ///< adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
-       SHADERPERMUTATION_SHADOWMAPRECT = 1<<17, ///< (lightsource) use shadowmap rectangle texture as light filter
-       SHADERPERMUTATION_SHADOWMAPCUBE = 1<<18, ///< (lightsource) use shadowmap cubemap texture as light filter
-       SHADERPERMUTATION_SHADOWMAP2D = 1<<19, ///< (lightsource) use shadowmap rectangle texture as light filter
-       SHADERPERMUTATION_SHADOWMAPPCF = 1<<20, ///< (lightsource) use percentage closer filtering on shadowmap test results
-       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_DEFERREDLIGHTMAP = 1<<24, ///< (lightmap) read Texture_ScreenDiffuse/Specular textures and add them on top of lightmapping
-       SHADERPERMUTATION_ALPHAKILL = 1<<25, ///< (deferredgeometry) discard pixel if diffuse texture alpha below 0.5
-       SHADERPERMUTATION_LIMIT = 1<<26, ///< size of permutations array
-       SHADERPERMUTATION_COUNT = 27 ///< size of shaderpermutationinfo array
-}
-shaderpermutation_t;
 
-// NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
-shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
-{
-       {"#define USEDIFFUSE\n", " diffuse"},
-       {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
-       {"#define USEVIEWTINT\n", " viewtint"},
-       {"#define USECOLORMAPPING\n", " colormapping"},
-       {"#define USESATURATION\n", " saturation"},
-       {"#define USEFOGINSIDE\n", " foginside"},
-       {"#define USEFOGOUTSIDE\n", " fogoutside"},
-       {"#define USEGAMMARAMPS\n", " gammaramps"},
-       {"#define USECUBEFILTER\n", " cubefilter"},
-       {"#define USEGLOW\n", " glow"},
-       {"#define USEBLOOM\n", " bloom"},
-       {"#define USESPECULAR\n", " specular"},
-       {"#define USEPOSTPROCESSING\n", " postprocessing"},
-       {"#define USEEXACTSPECULARMATH\n", " exactspecularmath"},
-       {"#define USEREFLECTION\n", " reflection"},
-       {"#define USEOFFSETMAPPING\n", " offsetmapping"},
-       {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
-       {"#define USESHADOWMAPRECT\n", " shadowmaprect"},
-       {"#define USESHADOWMAPCUBE\n", " shadowmapcube"},
-       {"#define USESHADOWMAP2D\n", " shadowmap2d"},
-       {"#define USESHADOWMAPPCF 1\n", " shadowmappcf"},
-       {"#define USESHADOWMAPPCF 2\n", " shadowmappcf2"},
-       {"#define USESHADOWSAMPLER\n", " shadowsampler"},
-       {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"},
-       {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
-       {"#define USEALPHAKILL\n", " alphakill"},
-};
+=========================================================================================================================================================
 
-/// this enum is multiplied by SHADERPERMUTATION_MODEBASE
-typedef enum shadermode_e
-{
-       SHADERMODE_GENERIC, ///< (particles/HUD/etc) vertex color, optionally multiplied by one texture
-       SHADERMODE_POSTPROCESS, ///< postprocessing shader (r_glsl_postprocess)
-       SHADERMODE_DEPTH_OR_SHADOW, ///< (depthfirst/shadows) vertex shader only
-       SHADERMODE_FLATCOLOR, ///< (lightmap) modulate texture by uniform color (q1bsp, q3bsp)
-       SHADERMODE_VERTEXCOLOR, ///< (lightmap) modulate texture by vertex colors (q3bsp)
-       SHADERMODE_LIGHTMAP, ///< (lightmap) modulate texture by lightmap texture (q1bsp, q3bsp)
-       SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE, ///< (lightmap) use directional pixel shading from texture containing modelspace light directions (q3bsp deluxemap)
-       SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE, ///< (lightmap) use directional pixel shading from texture containing tangentspace light directions (q1bsp deluxemap)
-       SHADERMODE_LIGHTDIRECTION, ///< (lightmap) use directional pixel shading from fixed light direction (q3bsp)
-       SHADERMODE_LIGHTSOURCE, ///< (lightsource) use directional pixel shading from light source (rtlight)
-       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] =
-{
-       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_GENERIC\n", " generic"},
-       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_POSTPROCESS\n", " postprocess"},
-       {"glsl/default.glsl", NULL, NULL               , "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
-       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_FLATCOLOR\n", " flatcolor"},
-       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
-       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTMAP\n", " lightmap"},
-       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
-       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
-       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
-       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTSOURCE\n", " lightsource"},
-       {"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"},
-};
 
-struct r_glsl_permutation_s;
-typedef struct r_glsl_permutation_s
-{
+=========================================================================================================================================================
+
+
+
+=========================================================================================================================================================
+
+
+
+=========================================================================================================================================================
+
+
+
+=========================================================================================================================================================
+
+
+
+=========================================================================================================================================================
+*/
+
+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"
+"#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"
+"\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"
+"      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"
+"      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"
+"#endif // !MODE_SHOWDEPTH\n"
+"#endif // !MODE_DEPTH_OR_SHADOW\n"
+;
+
+char *glslshaderstring = NULL;
+char *cgshaderstring = NULL;
+
+//=======================================================================================================================================================
+
+typedef struct shaderpermutationinfo_s
+{
+       const char *pretext;
+       const char *name;
+}
+shaderpermutationinfo_t;
+
+typedef struct shadermodeinfo_s
+{
+       const char *vertexfilename;
+       const char *geometryfilename;
+       const char *fragmentfilename;
+       const char *pretext;
+       const char *name;
+}
+shadermodeinfo_t;
+
+typedef enum shaderpermutation_e
+{
+       SHADERPERMUTATION_DIFFUSE = 1<<0, ///< (lightsource) whether to use directional shading
+       SHADERPERMUTATION_VERTEXTEXTUREBLEND = 1<<1, ///< indicates this is a two-layer material blend based on vertex alpha (q3bsp)
+       SHADERPERMUTATION_VIEWTINT = 1<<2, ///< view tint (postprocessing only)
+       SHADERPERMUTATION_COLORMAPPING = 1<<3, ///< indicates this is a colormapped skin
+       SHADERPERMUTATION_SATURATION = 1<<4, ///< saturation (postprocessing only)
+       SHADERPERMUTATION_FOGINSIDE = 1<<5, ///< tint the color by fog color or black if using additive blend mode
+       SHADERPERMUTATION_FOGOUTSIDE = 1<<6, ///< tint the color by fog color or black if using additive blend mode
+       SHADERPERMUTATION_GAMMARAMPS = 1<<7, ///< gamma (postprocessing only)
+       SHADERPERMUTATION_CUBEFILTER = 1<<8, ///< (lightsource) use cubemap light filter
+       SHADERPERMUTATION_GLOW = 1<<9, ///< (lightmap) blend in an additive glow texture
+       SHADERPERMUTATION_BLOOM = 1<<10, ///< bloom (postprocessing only)
+       SHADERPERMUTATION_SPECULAR = 1<<11, ///< (lightsource or deluxemapping) render specular effects
+       SHADERPERMUTATION_POSTPROCESSING = 1<<12, ///< user defined postprocessing (postprocessing only)
+       SHADERPERMUTATION_EXACTSPECULARMATH = 1<<13, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
+       SHADERPERMUTATION_REFLECTION = 1<<14, ///< normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
+       SHADERPERMUTATION_OFFSETMAPPING = 1<<15, ///< adjust texcoords to roughly simulate a displacement mapped surface
+       SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<16, ///< adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
+       SHADERPERMUTATION_SHADOWMAPRECT = 1<<17, ///< (lightsource) use shadowmap rectangle texture as light filter
+       SHADERPERMUTATION_SHADOWMAPCUBE = 1<<18, ///< (lightsource) use shadowmap cubemap texture as light filter
+       SHADERPERMUTATION_SHADOWMAP2D = 1<<19, ///< (lightsource) use shadowmap rectangle texture as light filter
+       SHADERPERMUTATION_SHADOWMAPPCF = 1<<20, ///< (lightsource) use percentage closer filtering on shadowmap test results
+       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_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;
+
+// NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
+shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
+{
+       {"#define USEDIFFUSE\n", " diffuse"},
+       {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
+       {"#define USEVIEWTINT\n", " viewtint"},
+       {"#define USECOLORMAPPING\n", " colormapping"},
+       {"#define USESATURATION\n", " saturation"},
+       {"#define USEFOGINSIDE\n", " foginside"},
+       {"#define USEFOGOUTSIDE\n", " fogoutside"},
+       {"#define USEGAMMARAMPS\n", " gammaramps"},
+       {"#define USECUBEFILTER\n", " cubefilter"},
+       {"#define USEGLOW\n", " glow"},
+       {"#define USEBLOOM\n", " bloom"},
+       {"#define USESPECULAR\n", " specular"},
+       {"#define USEPOSTPROCESSING\n", " postprocessing"},
+       {"#define USEEXACTSPECULARMATH\n", " exactspecularmath"},
+       {"#define USEREFLECTION\n", " reflection"},
+       {"#define USEOFFSETMAPPING\n", " offsetmapping"},
+       {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
+       {"#define USESHADOWMAPRECT\n", " shadowmaprect"},
+       {"#define USESHADOWMAPCUBE\n", " shadowmapcube"},
+       {"#define USESHADOWMAP2D\n", " shadowmap2d"},
+       {"#define USESHADOWMAPPCF 1\n", " shadowmappcf"},
+       {"#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
+typedef enum shadermode_e
+{
+       SHADERMODE_GENERIC, ///< (particles/HUD/etc) vertex color, optionally multiplied by one texture
+       SHADERMODE_POSTPROCESS, ///< postprocessing shader (r_glsl_postprocess)
+       SHADERMODE_DEPTH_OR_SHADOW, ///< (depthfirst/shadows) vertex shader only
+       SHADERMODE_FLATCOLOR, ///< (lightmap) modulate texture by uniform color (q1bsp, q3bsp)
+       SHADERMODE_VERTEXCOLOR, ///< (lightmap) modulate texture by vertex colors (q3bsp)
+       SHADERMODE_LIGHTMAP, ///< (lightmap) modulate texture by lightmap texture (q1bsp, q3bsp)
+       SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE, ///< (lightmap) use directional pixel shading from texture containing modelspace light directions (q3bsp deluxemap)
+       SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE, ///< (lightmap) use directional pixel shading from texture containing tangentspace light directions (q1bsp deluxemap)
+       SHADERMODE_LIGHTDIRECTION, ///< (lightmap) use directional pixel shading from fixed light direction (q3bsp)
+       SHADERMODE_LIGHTSOURCE, ///< (lightsource) use directional pixel shading from light source (rtlight)
+       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 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"},
+       {"glsl/default.glsl", NULL, NULL               , "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_FLATCOLOR\n", " flatcolor"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTMAP\n", " lightmap"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTSOURCE\n", " lightsource"},
+       {"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
+{
        /// hash lookup data
        struct r_glsl_permutation_s *hashnext;
        unsigned int mode;
@@ -1757,6 +3359,8 @@ typedef struct r_glsl_permutation_s
        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;
@@ -1800,6 +3404,14 @@ typedef struct r_glsl_permutation_s
        int loc_UserVec4;
        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;
 
@@ -1842,6 +3454,20 @@ 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)
        {
@@ -1849,18 +3475,13 @@ static char *R_GLSL_GetText(const char *filename, qboolean printfromdisknotice)
                        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;
@@ -1880,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)
@@ -1889,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
@@ -1964,6 +3585,8 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                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");
@@ -2007,6 +3630,14 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                p->loc_UserVec4                   = qglGetUniformLocationARB(p->program, "UserVec4");
                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);
@@ -2028,17 +3659,18 @@ 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
-               if (developer.integer)
-                       Con_Printf("^5GLSL shader %s compiled.\n", permutationname);
+               Con_DPrintf("^5GLSL shader %s compiled.\n", permutationname);
        }
        else
                Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
@@ -2052,57 +3684,486 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                Mem_Free(fragmentstring);
 }
 
-void R_GLSL_Restart_f(void)
+void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int permutation)
 {
-       unsigned int i, limit;
-       r_glsl_permutation_t *p;
-       limit = Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
-       for (i = 0;i < limit;i++)
+       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
+               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 = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
+               if (p->mode == mode && p->permutation == permutation)
                {
-                       GL_Backend_FreeProgram(p->program);
-                       Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
+                       //if (hashdepth > 10)
+                       //      Con_Printf("R_CG_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
+                       return p;
                }
+               //hashdepth++;
        }
-       memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
+       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;
 }
 
-void R_GLSL_DumpShader_f(void)
+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;
 
-       qfile_t *file = FS_OpenRealFile("glsl/default.glsl", "w", false);
-       if(!file)
-       {
-               Con_Printf("failed to write to glsl/default.glsl\n");
+       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";
+               }
        }
 
-       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);
+       // 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("^1CG shader %s failed!  some features may not work properly.\n", permutationname);
 
-       Con_Printf("glsl/default.glsl written\n");
+       // 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)
+               Mem_Free(geometrystring);
+       if (fragmentstring)
+               Mem_Free(fragmentstring);
 }
 
-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;
@@ -2113,73 +4174,223 @@ 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 R_SetupGenericShader(qboolean usetexture)
+void CG_BindTexture(CGparameter param, rtexture_t *tex)
 {
+       cgGLSetTextureParameter(param, R_GetTexture(tex));
+       cgGLEnableTextureParameter(param);
+}
+#endif
+
+void R_GLSL_Restart_f(void)
+{
+       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)
        {
        case RENDERPATH_GL20:
-               R_SetupShader_SetPermutation(SHADERMODE_GENERIC, usetexture ? SHADERPERMUTATION_DIFFUSE : 0);
+               {
+                       r_glsl_permutation_t *p;
+                       r_glsl_permutation = NULL;
+                       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_SetupGenericTwoTextureShader(int texturemode)
+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_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale)
 {
+       if (!second)
+               texturemode = GL_MODULATE;
        switch (vid.renderpath)
        {
        case RENDERPATH_GL20:
-               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))));
+               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_TexCombine(1, GL_DECAL, GL_DECAL, 1, 1);
+               R_Mesh_TexBind(0, first );
                break;
        }
 }
 
-void R_SetupDepthOrShadowShader(void)
+void R_SetupShader_DepthOrShadow(void)
 {
        switch (vid.renderpath)
        {
        case RENDERPATH_GL20:
-               R_SetupShader_SetPermutation(SHADERMODE_DEPTH_OR_SHADOW, 0);
+               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)
 {
        switch (vid.renderpath)
        {
        case RENDERPATH_GL20:
-               R_SetupShader_SetPermutation(SHADERMODE_SHOWDEPTH, 0);
+               R_SetupShader_SetPermutationGLSL(SHADERMODE_SHOWDEPTH, 0);
+               break;
+       case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+               R_SetupShader_SetPermutationCG(SHADERMODE_SHOWDEPTH, 0);
+#endif
                break;
        case RENDERPATH_GL13:
                break;
@@ -2196,12 +4407,25 @@ 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
@@ -2209,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
@@ -2223,22 +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;
                }
-       }
-       else if (rsurfacepass == RSURFPASS_RTLIGHT)
-       {
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
+                       permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
                // light source
                mode = SHADERMODE_LIGHTSOURCE;
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
@@ -2248,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)
@@ -2271,69 +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)
        {
+               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;
                // unshaded geometry (fullbright or ambient model lighting)
                mode = SHADERMODE_FLATCOLOR;
                ambientscale = diffusescale = specularscale = 0;
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
-                       permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
-               if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
+               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)
        {
-               // 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)
+               // 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 (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;
                // 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;
+               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)
@@ -2343,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)
                {
@@ -2351,120 +4791,334 @@ 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 (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
-                       permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
+               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);
+               }
+               GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
+               GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
        }
-       if(permutation & SHADERPERMUTATION_SPECULAR)
-               if(r_shadow_glossexact.integer)
-                       permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
-       if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) && r_shadow_usingdeferredprepass)
-               permutation |= SHADERPERMUTATION_ALPHAKILL;
-       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 (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, specularscale, specularscale, 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);
+       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 (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_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));
-       }
-       else
-       {
-               if (mode == SHADERMODE_FLATCOLOR)
+
+               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_Color_Shirt >= 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_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
                {
-                       if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Ambient, rsurface.colormod[0], rsurface.colormod[1], rsurface.colormod[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
+                       }
                }
-               else if (mode == SHADERMODE_LIGHTDIRECTION)
+               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_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, r_refdef.lightmapintensity, r_refdef.lightmapintensity);
-                       if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Specular, r_refdef.lightmapintensity * specularscale, r_refdef.lightmapintensity * specularscale, r_refdef.lightmapintensity * 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]);
+                       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
                {
-                       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 * specularscale, r_refdef.lightmapintensity * specularscale, r_refdef.lightmapintensity * 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);
+                       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
                }
-               // additive passes are only darkened by fog, not tinted
-               if (r_glsl_permutation->loc_FogColor >= 0)
+               if (r_cg_permutation->fp_Color_Shirt)
                {
-                       if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD)
-                               qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
+                       if (rsurface.texture->shirttexture)
+                               cgGLSetParameter3f(r_cg_permutation->fp_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_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));
-       }
-       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->currentskinframe->pants)
-                       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);
+                               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_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]);
-               else
-                       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]);
-       CHECKGLERROR
 }
 
-void R_SetupDeferredLightShader(const rtlight_t *rtlight)
+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
@@ -2513,20 +5167,64 @@ void R_SetupDeferredLightShader(const rtlight_t *rtlight)
                else if (r_shadow_shadowmappcf)
                        permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
        }
-       R_SetupShader_SetPermutation(mode, permutation);
        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);
-       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]);
+       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;
+       }
 }
 
 #define SKINFRAME_HASH 1024
@@ -2578,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;
                        }
                }
@@ -2691,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;
@@ -2705,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);
@@ -2717,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);
@@ -2783,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);
@@ -2815,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
@@ -2883,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
@@ -3003,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
@@ -3047,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;
@@ -3067,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)
@@ -3130,10 +6041,15 @@ void gl_main_start(void)
        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);
@@ -3189,6 +6105,12 @@ 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;
@@ -3228,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));
@@ -3330,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);
@@ -3337,6 +6262,14 @@ 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);
@@ -3384,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);
@@ -3398,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();
@@ -3558,7 +6495,7 @@ static void *r_framedata_base;
 
 void R_FrameData_Reset(void)
 {
-       if (r_framedata_base);
+       if (r_framedata_base)
                Mem_Free(r_framedata_base);
        r_framedata_base = NULL;
        r_framedata_size = 0;
@@ -3576,7 +6513,7 @@ void R_FrameData_NewFrame(void)
        if (r_framedata_size != wantedsize)
        {
                r_framedata_size = wantedsize;
-               if (r_framedata_base);
+               if (r_framedata_base)
                        Mem_Free(r_framedata_base);
                r_framedata_base = Mem_Alloc(r_main_mempool, r_framedata_size);
        }
@@ -3699,6 +6636,7 @@ void R_AnimCache_CacheVisibleEntities(void)
        switch(vid.renderpath)
        {
        case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
                break;
        case RENDERPATH_GL13:
        case RENDERPATH_GL11:
@@ -3712,11 +6650,6 @@ void R_AnimCache_CacheVisibleEntities(void)
        for (i = 0;i < r_refdef.scene.numentities;i++)
                if (r_refdef.viewcache.entityvisible[i])
                        R_AnimCache_GetEntity(r_refdef.scene.entities[i], wantnormals, wanttangents);
-
-       if (r_shadows.integer)
-               for (i = 0;i < r_refdef.scene.numentities;i++)
-                       if (!r_refdef.viewcache.entityvisible[i])
-                               R_AnimCache_GetEntity(r_refdef.scene.entities[i], false, false);
 }
 
 //==================================================================================
@@ -3727,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
@@ -3829,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);
@@ -3854,7 +6792,12 @@ static void R_View_UpdateEntityVisible (void)
        int samples;
        entity_render_t *ent;
 
-       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
@@ -4146,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
@@ -4171,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;
@@ -4188,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
@@ -4198,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)
@@ -4215,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
@@ -4225,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);
@@ -4243,6 +7218,7 @@ static void R_Water_StartFrame(void)
        switch(vid.renderpath)
        {
        case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
                break;
        case RENDERPATH_GL13:
        case RENDERPATH_GL11:
@@ -4387,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;
                }
@@ -4395,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;
                }
@@ -4411,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;
@@ -4458,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;
@@ -4485,6 +7457,7 @@ void R_Bloom_StartFrame(void)
        switch(vid.renderpath)
        {
        case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
                break;
        case RENDERPATH_GL13:
        case RENDERPATH_GL11:
@@ -4537,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)
        {
@@ -4547,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
@@ -4598,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;
 }
 
@@ -4632,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
@@ -4644,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;
        }
 
@@ -4663,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++)
@@ -4702,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;
        }
 
@@ -4713,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);
@@ -4721,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);
@@ -4729,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;
        }
 }
@@ -4794,10 +7752,12 @@ void R_HDR_RenderBloomTexture(void)
 static void R_BlendView(void)
 {
        unsigned int permutation;
+       float uservecs[4][4];
 
        switch (vid.renderpath)
        {
        case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
                permutation =
                          (r_bloomstate.texture_bloom ? SHADERPERMUTATION_BLOOM : 0)
                        | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
@@ -4813,8 +7773,6 @@ static void R_BlendView(void)
                        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))
                        {
@@ -4847,10 +7805,9 @@ static void R_BlendView(void)
                                // 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_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;
@@ -4858,7 +7815,7 @@ static void R_BlendView(void)
                        }
 
                        // 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_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)
@@ -4870,7 +7827,7 @@ static void R_BlendView(void)
                                R_ResetViewRendering2D();
                                R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
                                R_Mesh_ColorPointer(NULL, 0, 0);
-                               R_SetupGenericShader(false);
+                               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
                                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);
@@ -4887,53 +7844,58 @@ 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_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_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
-#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)
+
+               switch(vid.renderpath)
                {
-                       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);
+               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
+                       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;
                break;
@@ -4945,7 +7907,7 @@ static void R_BlendView(void)
                        R_ResetViewRendering2D();
                        R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
                        R_Mesh_ColorPointer(NULL, 0, 0);
-                       R_SetupGenericShader(false);
+                       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
                        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);
@@ -5073,6 +8035,7 @@ void R_UpdateVariables(void)
        switch(vid.renderpath)
        {
        case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
                if(v_glslgamma.integer && !vid_gammatables_trivial)
                {
                        if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
@@ -5099,7 +8062,7 @@ void R_UpdateVariables(void)
                                }
                                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);
+                                       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);
                                }
                        }
                }
@@ -5155,7 +8118,7 @@ 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
 
        if (!r_drawentities.integer)
@@ -5215,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;
 
@@ -5271,10 +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();
@@ -5321,9 +8292,14 @@ void R_RenderScene(void)
                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();
 
@@ -5340,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);
@@ -5359,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();
@@ -5379,7 +8364,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();
@@ -5416,7 +8401,6 @@ void R_RenderScene(void)
                        R_TimeReport("lightning");
        }
 
-       R_SetupGenericShader(true);
        VM_CL_AddPolygonsToMeshQueue();
 
        if (r_refdef.view.showdebug)
@@ -5443,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);
@@ -5460,8 +8441,6 @@ void R_RenderScene(void)
                        R_TimeReport("modeldebug");
        }
 
-       R_SetupGenericShader(true);
-
        if (cl.csqc_vidvars.drawworld)
        {
                R_Shadow_DrawCoronas();
@@ -5522,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);
 }
 
@@ -5538,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();
@@ -5668,7 +8647,7 @@ 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);
@@ -5958,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];
@@ -5975,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);
                }
@@ -5990,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
@@ -6054,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))
@@ -6079,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)
@@ -6101,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;
@@ -6135,7 +9140,17 @@ 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));
        }
@@ -6145,7 +9160,6 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        t->currentnumlayers = 0;
        if (t->currentmaterialflags & MATERIALFLAG_WALL)
        {
-               int layerflags = 0;
                int blendfunc1, blendfunc2;
                qboolean depthmask;
                if (t->currentmaterialflags & MATERIALFLAG_ADD)
@@ -6169,16 +9183,14 @@ 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
                {
@@ -6199,22 +9211,22 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                        // 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, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2], t->lightmapcolor[3]);
+               if (t->glowtexture != NULL && !gl_lightmaps.integer)
+                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->glowtexture, &t->currenttexmatrix, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2], t->lightmapcolor[3]);
                if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
                {
                        // if this is opaque use alpha blend which will darken the earlier
@@ -6228,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]);
                }
        }
 
@@ -6276,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;
@@ -6358,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;
@@ -6489,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;
@@ -7056,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];
@@ -7104,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);
                }
        }
@@ -7113,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;
@@ -7182,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)
                        {
@@ -7245,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;
@@ -7257,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
@@ -7269,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);
                }
        }
@@ -7302,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);
                }
        }
@@ -7460,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)
@@ -7627,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);
@@ -7644,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
@@ -7653,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);
                }
@@ -7672,109 +10691,39 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface
 {
        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)
-       {
-               R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
-               R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
-       }
-       R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
-       if (r_shadow_usingdeferredprepass)
+       RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist);
+       if (prepass)
        {
-               R_Mesh_TexBindAll(GL20TU_SCREENDIFFUSE, 0, 0, 0, R_GetTexture(r_shadow_prepasslightingdiffusetexture));
-               R_Mesh_TexBindAll(GL20TU_SCREENSPECULAR, 0, 0, 0, R_GetTexture(r_shadow_prepasslightingspeculartexture));
+               // 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);
        }
-       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)) && !prepass)
+       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, prepass ? RSURFPASS_DEFERREDGEOMETRY : 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);
-       if (!prepass)
-               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 && !r_shadow_usingdeferredprepass);
-       }
-
-       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)
@@ -7783,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);
@@ -7822,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)
@@ -7846,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);
                        }
-                       R_Mesh_TextureState(&m);
+                       else
+                       {
+                               R_Mesh_TexBind(0, 0);
+                               R_Mesh_TexCoordPointer(0, 2, NULL, 0, 0);
+                       }
+                       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++)
@@ -7891,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)
@@ -7906,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);
@@ -7926,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:
@@ -7934,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
@@ -7976,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;
@@ -8022,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)
@@ -8039,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)
        {
@@ -8054,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);
@@ -8141,7 +11074,7 @@ static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface
 {
        CHECKGLERROR
        RSurf_SetupDepthAndCulling();
-       if (r_showsurfaces.integer == 3 && !prepass)
+       if (r_showsurfaces.integer == 3 && !prepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY))
        {
                R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth);
                return;
@@ -8149,6 +11082,7 @@ static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface
        switch (vid.renderpath)
        {
        case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
                R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
                break;
        case RENDERPATH_GL13:
@@ -8165,7 +11099,7 @@ static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface
 {
        CHECKGLERROR
        RSurf_SetupDepthAndCulling();
-       if (r_showsurfaces.integer == 3 && !prepass)
+       if (r_showsurfaces.integer == 3 && !prepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY))
        {
                R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth);
                return;
@@ -8173,6 +11107,7 @@ static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface
        switch (vid.renderpath)
        {
        case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
                R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
                break;
        case RENDERPATH_GL13:
@@ -8191,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
@@ -8205,6 +11140,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
                switch (vid.renderpath)
                {
                case RENDERPATH_GL20:
+               case RENDERPATH_CGGL:
                        RSurf_ActiveModelEntity(ent, true, true, false);
                        break;
                case RENDERPATH_GL13:
@@ -8214,6 +11150,51 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
                }
        }
 
+       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)
        {
                j = i + 1;
@@ -8242,6 +11223,29 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
        GL_AlphaTest(false);
 }
 
+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;
@@ -8258,19 +11262,20 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf
        }
        else if (prepass)
        {
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
-                       return;
                if (!rsurface.texture->currentnumlayers)
                        return;
-               R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
+               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)
+       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);
@@ -8278,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);
@@ -8297,19 +11302,9 @@ 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
        {
@@ -8364,11 +11359,12 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf
        }
        else if (prepass)
        {
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
-                       return;
                if (!rsurface.texture->currentnumlayers)
                        return;
-               R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
+               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)
        {
@@ -8376,7 +11372,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);
@@ -8390,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);
@@ -8403,25 +11399,9 @@ 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
        {
@@ -8494,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,
@@ -8550,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)
@@ -8577,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++)
@@ -8634,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;
@@ -8650,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];
@@ -8686,7 +11661,6 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor
        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;
@@ -8747,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)
                {
@@ -8866,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)
@@ -8972,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;
@@ -9006,7 +11977,6 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
        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
@@ -9018,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
@@ -9065,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;
@@ -9074,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);
@@ -9081,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);
        }
 }
 
@@ -9132,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;
@@ -9146,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;
                        }
                }
        }
@@ -9205,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);
@@ -9280,8 +12275,7 @@ int r_maxsurfacelist = 0;
 const msurface_t **r_surfacelist = NULL;
 void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
 {
-       int i, j, endj, f, flagsmask;
-       texture_t *t;
+       int i, j, endj, flagsmask;
        dp_model_t *model = r_refdef.scene.worldmodel;
        msurface_t *surfaces;
        unsigned char *update;
@@ -9327,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;
@@ -9341,11 +12333,20 @@ 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)
        {
@@ -9368,8 +12369,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep
 
 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;
@@ -9395,12 +12395,25 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
        else if (prepass)
                RSurf_ActiveModelEntity(ent, true, true, true);
        else if (depthonly)
-               RSurf_ActiveModelEntity(ent, false, 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
        {
                switch (vid.renderpath)
                {
                case RENDERPATH_GL20:
+               case RENDERPATH_CGGL:
                        RSurf_ActiveModelEntity(ent, true, true, false);
                        break;
                case RENDERPATH_GL13:
@@ -9438,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;
@@ -9454,6 +12465,18 @@ 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])
@@ -9498,3 +12521,22 @@ void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, i
        rsurface.uselightmaptexture = false;
        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);
+}