]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
turn font size snapping into a float
[xonotic/darkplaces.git] / gl_rmain.c
index e9800542d5c9d9802cb219a03a3b82658e978672..bf28ab4dca0a12bb2a22c4a07d95cdb39c237083 100644 (file)
@@ -24,6 +24,7 @@ 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;
@@ -95,6 +96,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)"};
@@ -283,22 +285,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 +328,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 +344,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 +389,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)
@@ -447,8 +451,8 @@ 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);
        }
 }
 
@@ -458,94 +462,50 @@ static const char *builtinshaderstring =
 "\n"
 "// enable various extensions depending on permutation:\n"
 "\n"
-"#ifdef USESHADOWMAPRECT\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"
-"#ifdef USEFOGINSIDE\n"
-"# define USEFOG\n"
-"#else\n"
-"# ifdef USEFOGOUTSIDE\n"
-"#  define USEFOG\n"
-"# endif\n"
+"#ifdef VERTEX_SHADER\n"
+"uniform mat4 ModelViewProjectionMatrix;\n"
 "#endif\n"
 "\n"
 "#ifdef MODE_DEPTH_OR_SHADOW\n"
-"\n"
-"# ifdef VERTEX_SHADER\n"
+"#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
-"      gl_Position = ftransform();\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
 "}\n"
-"# endif\n"
-"\n"
-"#else\n"
+"#endif\n"
+"#else // !MODE_DEPTH_ORSHADOW\n"
 "#ifdef MODE_SHOWDEPTH\n"
-"# ifdef VERTEX_SHADER\n"
+"#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
-"      gl_Position = ftransform();\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
 "      gl_FrontColor = vec4(gl_Position.z, gl_Position.z, gl_Position.z, 1.0);\n"
 "}\n"
-"# endif\n"
-"# ifdef FRAGMENT_SHADER\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
 "void main(void)\n"
 "{\n"
 "      gl_FragColor = gl_Color;\n"
 "}\n"
-"# endif\n"
-"\n"
+"#endif\n"
 "#else // !MODE_SHOWDEPTH\n"
-"\n"
 "#ifdef MODE_POSTPROCESS\n"
-"# ifdef VERTEX_SHADER\n"
+"varying vec2 TexCoord1;\n"
+"varying vec2 TexCoord2;\n"
+"\n"
+"#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
-"      gl_FrontColor = gl_Color;\n"
-"      gl_Position = ftransform();\n"
-"      gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
+"      TexCoord1 = gl_MultiTexCoord0.xy;\n"
 "#ifdef USEBLOOM\n"
-"      gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;\n"
+"      TexCoord2 = gl_MultiTexCoord1.xy;\n"
 "#endif\n"
 "}\n"
-"# endif\n"
-"# ifdef FRAGMENT_SHADER\n"
+"#endif\n"
 "\n"
+"#ifdef FRAGMENT_SHADER\n"
 "uniform sampler2D Texture_First;\n"
 "#ifdef USEBLOOM\n"
 "uniform sampler2D Texture_Second;\n"
@@ -557,7 +517,7 @@ static const char *builtinshaderstring =
 "uniform float Saturation;\n"
 "#endif\n"
 "#ifdef USEVIEWTINT\n"
-"uniform vec4 TintColor;\n"
+"uniform vec4 ViewTintColor;\n"
 "#endif\n"
 "//uncomment these if you want to use them:\n"
 "uniform vec4 UserVec1;\n"
@@ -568,28 +528,28 @@ static const char *builtinshaderstring =
 "uniform vec2 PixelSize;\n"
 "void main(void)\n"
 "{\n"
-"      gl_FragColor = texture2D(Texture_First, gl_TexCoord[0].xy);\n"
+"      gl_FragColor = texture2D(Texture_First, TexCoord1);\n"
 "#ifdef USEBLOOM\n"
-"      gl_FragColor += texture2D(Texture_Second, gl_TexCoord[1].xy);\n"
+"      gl_FragColor += texture2D(Texture_Second, TexCoord2);\n"
 "#endif\n"
 "#ifdef USEVIEWTINT\n"
-"      gl_FragColor = mix(gl_FragColor, TintColor, TintColor.a);\n"
+"      gl_FragColor = mix(gl_FragColor, ViewTintColor, ViewTintColor.a);\n"
 "#endif\n"
 "\n"
 "#ifdef USEPOSTPROCESSING\n"
 "// do r_glsl_dumpshader, edit glsl/default.glsl, and replace this by your own postprocessing if you want\n"
 "// this code does a blur with the radius specified in the first component of r_glsl_postprocess_uservec1 and blends it using the second component\n"
-"      gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.987688, -0.156434)) * UserVec1.y;\n"
-"      gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.156434, -0.891007)) * UserVec1.y;\n"
-"      gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2( 0.891007, -0.453990)) * UserVec1.y;\n"
-"      gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2( 0.707107,  0.707107)) * UserVec1.y;\n"
-"      gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.453990,  0.891007)) * UserVec1.y;\n"
+"      gl_FragColor += texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2(-0.987688, -0.156434)) * UserVec1.y;\n"
+"      gl_FragColor += texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2(-0.156434, -0.891007)) * UserVec1.y;\n"
+"      gl_FragColor += texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2( 0.891007, -0.453990)) * UserVec1.y;\n"
+"      gl_FragColor += texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2( 0.707107,  0.707107)) * UserVec1.y;\n"
+"      gl_FragColor += texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2(-0.453990,  0.891007)) * UserVec1.y;\n"
 "      gl_FragColor /= (1 + 5 * UserVec1.y);\n"
 "#endif\n"
 "\n"
 "#ifdef USESATURATION\n"
 "      //apply saturation BEFORE gamma ramps, so v_glslgamma value does not matter\n"
-"      myhalf y = dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114));\n"
+"      float y = dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114));\n"
 "      //gl_FragColor = vec3(y) + (gl_FragColor.rgb - vec3(y)) * Saturation;\n"
 "      gl_FragColor.rgb = mix(vec3(y), gl_FragColor.rgb, Saturation);\n"
 "#endif\n"
@@ -600,74 +560,78 @@ static const char *builtinshaderstring =
 "      gl_FragColor.b = texture2D(Texture_GammaRamps, vec2(gl_FragColor.b, 0)).b;\n"
 "#endif\n"
 "}\n"
-"# endif\n"
-"\n"
-"\n"
-"#else\n"
+"#endif\n"
+"#else // !MODE_POSTPROCESS\n"
 "#ifdef MODE_GENERIC\n"
-"# ifdef VERTEX_SHADER\n"
+"#ifdef USEDIFFUSE\n"
+"varying vec2 TexCoord1;\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
+"varying vec2 TexCoord2;\n"
+"#endif\n"
+"#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
 "      gl_FrontColor = gl_Color;\n"
-"#  ifdef USEDIFFUSE\n"
-"      gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
-"#  endif\n"
-"#  ifdef USESPECULAR\n"
-"      gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;\n"
-"#  endif\n"
-"      gl_Position = ftransform();\n"
+"#ifdef USEDIFFUSE\n"
+"      TexCoord1 = gl_MultiTexCoord0.xy;\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
+"      TexCoord2 = gl_MultiTexCoord1.xy;\n"
+"#endif\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
 "}\n"
-"# endif\n"
-"# ifdef FRAGMENT_SHADER\n"
+"#endif\n"
 "\n"
-"#  ifdef USEDIFFUSE\n"
+"#ifdef FRAGMENT_SHADER\n"
+"#ifdef USEDIFFUSE\n"
 "uniform sampler2D Texture_First;\n"
-"#  endif\n"
-"#  ifdef USESPECULAR\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
 "uniform sampler2D Texture_Second;\n"
-"#  endif\n"
+"#endif\n"
 "\n"
 "void main(void)\n"
 "{\n"
 "      gl_FragColor = gl_Color;\n"
-"#  ifdef USEDIFFUSE\n"
-"      gl_FragColor *= texture2D(Texture_First, gl_TexCoord[0].xy);\n"
-"#  endif\n"
+"#ifdef USEDIFFUSE\n"
+"      gl_FragColor *= texture2D(Texture_First, TexCoord1);\n"
+"#endif\n"
 "\n"
-"#  ifdef USESPECULAR\n"
-"      vec4 tex2 = texture2D(Texture_Second, gl_TexCoord[1].xy);\n"
-"#  endif\n"
-"#  ifdef USECOLORMAPPING\n"
+"#ifdef USESPECULAR\n"
+"      vec4 tex2 = texture2D(Texture_Second, TexCoord2);\n"
+"# ifdef USECOLORMAPPING\n"
 "      gl_FragColor *= tex2;\n"
-"#  endif\n"
-"#  ifdef USEGLOW\n"
+"# endif\n"
+"# ifdef USEGLOW\n"
 "      gl_FragColor += tex2;\n"
-"#  endif\n"
-"#  ifdef USEVERTEXTEXTUREBLEND\n"
+"# endif\n"
+"# ifdef USEVERTEXTEXTUREBLEND\n"
 "      gl_FragColor = mix(gl_FragColor, tex2, tex2.a);\n"
-"#  endif\n"
-"}\n"
 "# endif\n"
-"\n"
+"#endif\n"
+"}\n"
+"#endif\n"
 "#else // !MODE_GENERIC\n"
 "#ifdef MODE_BLOOMBLUR\n"
-"# ifdef VERTEX_SHADER\n"
+"varying TexCoord;\n"
+"#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
 "      gl_FrontColor = gl_Color;\n"
-"      gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
-"      gl_Position = ftransform();\n"
+"      TexCoord = gl_MultiTexCoord0.xy;\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
 "}\n"
-"# endif\n"
-"# ifdef FRAGMENT_SHADER\n"
+"#endif\n"
 "\n"
+"#ifdef FRAGMENT_SHADER\n"
 "uniform sampler2D Texture_First;\n"
 "uniform vec4 BloomBlur_Parameters;\n"
 "\n"
 "void main(void)\n"
 "{\n"
 "      int i;\n"
-"      vec2 tc = gl_TexCoord[0].xy;\n"
+"      vec2 tc = TexCoord;\n"
 "      vec3 color = texture2D(Texture_First, tc).rgb;\n"
 "      tc += BloomBlur_Parameters.xy;\n"
 "      for (i = 1;i < SAMPLES;i++)\n"
@@ -677,15 +641,166 @@ static const char *builtinshaderstring =
 "      }\n"
 "      gl_FragColor = vec4(color * BloomBlur_Parameters.z + vec3(BloomBlur_Parameters.w), 1);\n"
 "}\n"
+"#endif\n"
+"#else // !MODE_BLOOMBLUR\n"
+"#ifdef MODE_REFRACTION\n"
+"varying vec2 TexCoord;\n"
+"varying vec4 ModelViewProjectionPosition;\n"
+"uniform mat4 TexMatrix;\n"
+"#ifdef VERTEX_SHADER\n"
+"\n"
+"void main(void)\n"
+"{\n"
+"      TexCoord = vec2(TexMatrix * gl_MultiTexCoord0);\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
+"      ModelViewProjectionPosition = gl_Position;\n"
+"}\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"uniform sampler2D Texture_Normal;\n"
+"uniform sampler2D Texture_Refraction;\n"
+"uniform sampler2D Texture_Reflection;\n"
+"\n"
+"uniform vec4 DistortScaleRefractReflect;\n"
+"uniform vec4 ScreenScaleRefractReflect;\n"
+"uniform vec4 ScreenCenterRefractReflect;\n"
+"uniform vec4 RefractColor;\n"
+"uniform vec4 ReflectColor;\n"
+"uniform float ReflectFactor;\n"
+"uniform float ReflectOffset;\n"
+"\n"
+"void main(void)\n"
+"{\n"
+"      vec2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n"
+"      //vec2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
+"      vec2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
+"      vec2 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5))).xy * DistortScaleRefractReflect.xy;\n"
+"      // FIXME temporary hack to detect the case that the reflection\n"
+"      // gets blackened at edges due to leaving the area that contains actual\n"
+"      // content.\n"
+"      // Remove this 'ack once we have a better way to stop this thing from\n"
+"      // 'appening.\n"
+"      float f = min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, -0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
+"      ScreenTexCoord = mix(SafeScreenTexCoord, ScreenTexCoord, f);\n"
+"      gl_FragColor = texture2D(Texture_Refraction, ScreenTexCoord) * RefractColor;\n"
+"}\n"
+"#endif\n"
+"#else // !MODE_REFRACTION\n"
+"#ifdef MODE_WATER\n"
+"varying vec2 TexCoord;\n"
+"varying vec3 EyeVector;\n"
+"varying vec4 ModelViewProjectionPosition;\n"
+"#ifdef VERTEX_SHADER\n"
+"uniform vec3 EyePosition;\n"
+"uniform mat4 TexMatrix;\n"
+"\n"
+"void main(void)\n"
+"{\n"
+"      TexCoord = vec2(TexMatrix * gl_MultiTexCoord0);\n"
+"      vec3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
+"      EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
+"      EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
+"      EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
+"      ModelViewProjectionPosition = gl_Position;\n"
+"}\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"uniform sampler2D Texture_Normal;\n"
+"uniform sampler2D Texture_Refraction;\n"
+"uniform sampler2D Texture_Reflection;\n"
+"\n"
+"uniform vec4 DistortScaleRefractReflect;\n"
+"uniform vec4 ScreenScaleRefractReflect;\n"
+"uniform vec4 ScreenCenterRefractReflect;\n"
+"uniform vec4 RefractColor;\n"
+"uniform vec4 ReflectColor;\n"
+"uniform float ReflectFactor;\n"
+"uniform float ReflectOffset;\n"
+"\n"
+"void main(void)\n"
+"{\n"
+"      vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
+"      //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
+"      vec4 SafeScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
+"      vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5))).xyxy * DistortScaleRefractReflect;\n"
+"      // FIXME temporary hack to detect the case that the reflection\n"
+"      // gets blackened at edges due to leaving the area that contains actual\n"
+"      // content.\n"
+"      // Remove this 'ack once we have a better way to stop this thing from\n"
+"      // 'appening.\n"
+"      float f = min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.01, -0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
+"      ScreenTexCoord.xy = mix(SafeScreenTexCoord.xy, ScreenTexCoord.xy, f);\n"
+"      f       = min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.01, -0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
+"      ScreenTexCoord.zw = mix(SafeScreenTexCoord.zw, ScreenTexCoord.zw, f);\n"
+"      float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * ReflectFactor + ReflectOffset;\n"
+"      gl_FragColor = mix(texture2D(Texture_Refraction, ScreenTexCoord.xy) * RefractColor, texture2D(Texture_Reflection, ScreenTexCoord.zw) * ReflectColor, Fresnel);\n"
+"}\n"
+"#endif\n"
+"#else // !MODE_WATER\n"
+"\n"
+"#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"
-"#else // !MODE_BLOOMBLUR\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"
 "varying vec2 TexCoordLightmap;\n"
+"#endif\n"
 "\n"
 "#ifdef MODE_LIGHTSOURCE\n"
 "varying vec3 CubeVector;\n"
@@ -694,63 +809,115 @@ static const char *builtinshaderstring =
 "#ifdef MODE_LIGHTSOURCE\n"
 "varying vec3 LightVector;\n"
 "#endif\n"
-"#ifdef MODE_LIGHTDIRECTION\n"
+"#if defined(MODE_LIGHTDIRECTION)\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"
 "varying vec3 EyeVector;\n"
+"#endif\n"
 "#ifdef USEFOG\n"
 "varying vec3 EyeVectorModelSpace;\n"
 "varying float FogPlaneVertexDist;\n"
 "#endif\n"
 "\n"
+"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_DEFERREDGEOMETRY)\n"
 "varying vec3 VectorS; // direction of S texcoord (sometimes crudely called tangent)\n"
 "varying vec3 VectorT; // direction of T texcoord (sometimes crudely called binormal)\n"
 "varying vec3 VectorR; // direction of R texcoord (surface normal)\n"
-"\n"
-"#ifdef MODE_WATER\n"
-"varying vec4 ModelViewProjectionPosition;\n"
-"#endif\n"
-"#ifdef MODE_REFRACTION\n"
-"varying vec4 ModelViewProjectionPosition;\n"
 "#endif\n"
+"\n"
 "#ifdef USEREFLECTION\n"
 "varying vec4 ModelViewProjectionPosition;\n"
 "#endif\n"
+"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
+"uniform vec3 LightPosition;\n"
+"varying vec4 ModelViewPosition;\n"
+"#endif\n"
 "\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"uniform vec3 LightPosition;\n"
+"#endif\n"
+"uniform vec3 EyePosition;\n"
+"#ifdef MODE_LIGHTDIRECTION\n"
+"uniform vec3 LightDir;\n"
+"#endif\n"
+"uniform vec4 FogPlane;\n"
 "\n"
 "\n"
 "\n"
 "\n"
-"// vertex shader specific:\n"
-"#ifdef VERTEX_SHADER\n"
 "\n"
-"uniform vec3 LightPosition;\n"
-"uniform vec3 EyePosition;\n"
-"uniform vec3 LightDir;\n"
-"uniform vec4 FogPlane;\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"
+"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"
+"#else // !MODE_DEFERREDGEOMETRY\n"
+"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
+"uniform mat4 ModelViewMatrix;\n"
+"void main(void)\n"
+"{\n"
+"      ModelViewPosition = ModelViewMatrix * gl_Vertex;\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
+"}\n"
+"#else // !MODE_DEFERREDLIGHTSOURCE\n"
+"uniform mat4 TexMatrix;\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"uniform mat4 BackgroundTexMatrix;\n"
+"#endif\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"uniform mat4 ModelToLight;\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(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
+"      TexCoord = vec2(TexMatrix * gl_MultiTexCoord0);\n"
 "#ifdef USEVERTEXTEXTUREBLEND\n"
-"      TexCoord2 = vec2(gl_TextureMatrix[1] * gl_MultiTexCoord0);\n"
+"      TexCoord2 = vec2(BackgroundTexMatrix * gl_MultiTexCoord0);\n"
 "#endif\n"
-"#ifndef MODE_LIGHTSOURCE\n"
-"# ifndef MODE_LIGHTDIRECTION\n"
+"#ifdef USELIGHTMAP\n"
 "      TexCoordLightmap = vec2(gl_MultiTexCoord4);\n"
-"# endif\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"
+"      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"
@@ -758,15 +925,17 @@ static const char *builtinshaderstring =
 "      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"
-"#ifdef MODE_LIGHTDIRECTION\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"
@@ -774,8 +943,12 @@ static const char *builtinshaderstring =
 "      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"
 "#endif\n"
 "\n"
@@ -785,26 +958,15 @@ static const char *builtinshaderstring =
 "      VectorR = gl_MultiTexCoord3.xyz;\n"
 "#endif\n"
 "\n"
-"//#if defined(MODE_WATER) || defined(MODE_REFRACTION) || defined(USEREFLECTION)\n"
-"//    ModelViewProjectionPosition = gl_Vertex * gl_ModelViewProjectionMatrix;\n"
-"//    //ModelViewProjectionPosition_svector = (gl_Vertex + vec4(gl_MultiTexCoord1.xyz, 0)) * gl_ModelViewProjectionMatrix - ModelViewProjectionPosition;\n"
-"//    //ModelViewProjectionPosition_tvector = (gl_Vertex + vec4(gl_MultiTexCoord2.xyz, 0)) * gl_ModelViewProjectionMatrix - ModelViewProjectionPosition;\n"
-"//#endif\n"
-"\n"
-"// transform vertex to camera space, using ftransform to match non-VS\n"
-"      // rendering\n"
-"      gl_Position = ftransform();\n"
+"      // transform vertex to camera space, using ftransform to match non-VS rendering\n"
+"      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
 "\n"
-"#ifdef MODE_WATER\n"
-"      ModelViewProjectionPosition = gl_Position;\n"
-"#endif\n"
-"#ifdef MODE_REFRACTION\n"
-"      ModelViewProjectionPosition = gl_Position;\n"
-"#endif\n"
 "#ifdef USEREFLECTION\n"
 "      ModelViewProjectionPosition = gl_Position;\n"
 "#endif\n"
 "}\n"
+"#endif // !MODE_DEFERREDLIGHTSOURCE\n"
+"#endif // !MODE_DEFERREDGEOMETRY\n"
 "\n"
 "#endif // VERTEX_SHADER\n"
 "\n"
@@ -814,108 +976,72 @@ static const char *builtinshaderstring =
 "// fragment shader specific:\n"
 "#ifdef FRAGMENT_SHADER\n"
 "\n"
-"// 13 textures, we can only use up to 16 on DX9-class hardware\n"
 "uniform sampler2D Texture_Normal;\n"
 "uniform sampler2D Texture_Color;\n"
+"//#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"
-"uniform sampler2D Texture_Refraction;\n"
-"uniform sampler2D Texture_Reflection;\n"
-"uniform sampler2D Texture_Attenuation;\n"
-"uniform samplerCube Texture_Cube;\n"
-"\n"
-"#define showshadowmap 0\n"
-"\n"
-"#ifdef USESHADOWMAPRECT\n"
-"# ifdef USESHADOWSAMPLER\n"
-"uniform sampler2DRectShadow Texture_ShadowMapRect;\n"
-"# else\n"
-"uniform sampler2DRect Texture_ShadowMapRect;\n"
-"# endif\n"
 "#endif\n"
-"\n"
-"#ifdef USESHADOWMAP2D\n"
-"# ifdef USESHADOWSAMPLER\n"
-"uniform sampler2DShadow Texture_ShadowMap2D;\n"
-"# else\n"
-"uniform sampler2D Texture_ShadowMap2D;\n"
-"# endif\n"
+"#ifdef USEREFLECTION\n"
+"uniform sampler2D Texture_Reflection;\n"
 "#endif\n"
 "\n"
-"#ifdef USESHADOWMAPVSDCT\n"
-"uniform samplerCube Texture_CubeProjection;\n"
+"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
+"uniform sampler2DRect Texture_ScreenDepth;\n"
+"uniform sampler2DRect Texture_ScreenNormalMap;\n"
 "#endif\n"
-"\n"
-"#ifdef USESHADOWMAPCUBE\n"
-"# ifdef USESHADOWSAMPLER\n"
-"uniform samplerCubeShadow Texture_ShadowMapCube;\n"
-"# else\n"
-"uniform samplerCube Texture_ShadowMapCube;\n"
-"# endif\n"
+"#ifdef USEDEFERREDLIGHTMAP\n"
+"uniform sampler2DRect Texture_ScreenDiffuse;\n"
+"uniform sampler2DRect Texture_ScreenSpecular;\n"
 "#endif\n"
 "\n"
-"uniform myhalf3 LightColor;\n"
-"uniform myhalf3 AmbientColor;\n"
-"uniform myhalf3 DiffuseColor;\n"
-"uniform myhalf3 SpecularColor;\n"
 "uniform myhalf3 Color_Pants;\n"
 "uniform myhalf3 Color_Shirt;\n"
 "uniform myhalf3 FogColor;\n"
 "\n"
-"uniform myhalf4 TintColor;\n"
-"\n"
-"\n"
-"//#ifdef MODE_WATER\n"
-"uniform vec4 DistortScaleRefractReflect;\n"
-"uniform vec4 ScreenScaleRefractReflect;\n"
-"uniform vec4 ScreenCenterRefractReflect;\n"
-"uniform myhalf4 RefractColor;\n"
-"uniform myhalf4 ReflectColor;\n"
-"uniform myhalf ReflectFactor;\n"
-"uniform myhalf ReflectOffset;\n"
-"//#else\n"
-"//# ifdef MODE_REFRACTION\n"
-"//uniform vec4 DistortScaleRefractReflect;\n"
-"//uniform vec4 ScreenScaleRefractReflect;\n"
-"//uniform vec4 ScreenCenterRefractReflect;\n"
-"//uniform myhalf4 RefractColor;\n"
-"//#  ifdef USEREFLECTION\n"
-"//uniform myhalf4 ReflectColor;\n"
-"//#  endif\n"
-"//# else\n"
-"//#  ifdef USEREFLECTION\n"
-"//uniform vec4 DistortScaleRefractReflect;\n"
-"//uniform vec4 ScreenScaleRefractReflect;\n"
-"//uniform vec4 ScreenCenterRefractReflect;\n"
-"//uniform myhalf4 ReflectColor;\n"
-"//#  endif\n"
-"//# endif\n"
-"//#endif\n"
-"\n"
-"uniform myhalf3 GlowColor;\n"
-"uniform myhalf SceneBrightness;\n"
-"\n"
-"uniform float OffsetMapping_Scale;\n"
-"uniform float OffsetMapping_Bias;\n"
+"#ifdef USEFOG\n"
 "uniform float FogRangeRecip;\n"
 "uniform float FogPlaneViewDist;\n"
 "uniform float FogHeightFade;\n"
-"\n"
-"uniform myhalf AmbientScale;\n"
-"uniform myhalf DiffuseScale;\n"
-"uniform myhalf SpecularScale;\n"
-"uniform myhalf SpecularPower;\n"
+"myhalf FogVertex(void)\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 myhalf(texture2D(Texture_FogMask, myhalf2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)));\n"
+"}\n"
+"#endif\n"
 "\n"
 "#ifdef USEOFFSETMAPPING\n"
+"uniform float OffsetMapping_Scale;\n"
 "vec2 OffsetMapping(vec2 TexCoord)\n"
 "{\n"
 "#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n"
@@ -960,6 +1086,38 @@ static const char *builtinshaderstring =
 "}\n"
 "#endif // USEOFFSETMAPPING\n"
 "\n"
+"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE)\n"
+"uniform sampler2D Texture_Attenuation;\n"
+"uniform samplerCube Texture_Cube;\n"
+"\n"
+"#ifdef USESHADOWMAPRECT\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform sampler2DRectShadow Texture_ShadowMapRect;\n"
+"# else\n"
+"uniform sampler2DRect Texture_ShadowMapRect;\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAP2D\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform sampler2DShadow Texture_ShadowMap2D;\n"
+"# else\n"
+"uniform sampler2D Texture_ShadowMap2D;\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAPVSDCT\n"
+"uniform samplerCube Texture_CubeProjection;\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform samplerCubeShadow Texture_ShadowMapCube;\n"
+"# else\n"
+"uniform samplerCube Texture_ShadowMapCube;\n"
+"# endif\n"
+"#endif\n"
+"\n"
 "#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D) || defined(USESHADOWMAPCUBE)\n"
 "uniform vec2 ShadowMap_TextureScale;\n"
 "uniform vec4 ShadowMap_Parameters;\n"
@@ -1007,9 +1165,6 @@ static const char *builtinshaderstring =
 "      vec3 stc = vec3(tc * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
 "      stc.xy += offset * ShadowMap_Parameters.y;\n"
 "      stc.z += ShadowMap_Parameters.z;\n"
-"#  if showshadowmap\n"
-"      stc.xy *= ShadowMap_TextureScale;\n"
-"#  endif\n"
 "      return stc;\n"
 "# else\n"
 "      vec4 proj = textureCube(Texture_CubeProjection, dir);\n"
@@ -1017,9 +1172,6 @@ static const char *builtinshaderstring =
 "      vec3 stc = vec3(mix(dir.xy, dir.zz, proj.xy) * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
 "      stc.xy += proj.zw * ShadowMap_Parameters.y;\n"
 "      stc.z += ShadowMap_Parameters.z;\n"
-"#  if showshadowmap\n"
-"      stc.xy *= ShadowMap_TextureScale;\n"
-"#  endif\n"
 "      return stc;\n"
 "# endif\n"
 "}\n"
@@ -1033,7 +1185,6 @@ static const char *builtinshaderstring =
 "}\n"
 "#endif\n"
 "\n"
-"#if !showshadowmap\n"
 "# ifdef USESHADOWMAPRECT\n"
 "float ShadowMapCompare(vec3 dir)\n"
 "{\n"
@@ -1155,11 +1306,9 @@ static const char *builtinshaderstring =
 "    return f;\n"
 "}\n"
 "# endif\n"
-"#endif\n"
-"\n"
-"#ifdef MODE_WATER\n"
+"#endif // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE)\n"
 "\n"
-"// water pass\n"
+"#ifdef MODE_DEFERREDGEOMETRY\n"
 "void main(void)\n"
 "{\n"
 "#ifdef USEOFFSETMAPPING\n"
@@ -1168,59 +1317,114 @@ static const char *builtinshaderstring =
 "#define TexCoord TexCoordOffset\n"
 "#endif\n"
 "\n"
-"      vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
-"      //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
-"      vec4 SafeScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
-"      vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5))).xyxy * DistortScaleRefractReflect;\n"
-"      // FIXME temporary hack to detect the case that the reflection\n"
-"      // gets blackened at edges due to leaving the area that contains actual\n"
-"      // content.\n"
-"      // Remove this 'ack once we have a better way to stop this thing from\n"
-"      // 'appening.\n"
-"      float f = min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.01, 0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.01, -0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
-"      ScreenTexCoord.xy = mix(SafeScreenTexCoord.xy, ScreenTexCoord.xy, f);\n"
-"      f       = min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.01, 0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.01, -0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
-"      ScreenTexCoord.zw = mix(SafeScreenTexCoord.zw, ScreenTexCoord.zw, f);\n"
-"      float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * ReflectFactor + ReflectOffset;\n"
-"      gl_FragColor = mix(texture2D(Texture_Refraction, ScreenTexCoord.xy) * RefractColor, texture2D(Texture_Reflection, ScreenTexCoord.zw) * ReflectColor, Fresnel);\n"
-"}\n"
+"#ifdef USEALPHAKILL\n"
+"      if (texture2D(Texture_Color, TexCoord).a < 0.5)\n"
+"              discard;\n"
+"#endif\n"
 "\n"
-"#else // !MODE_WATER\n"
-"#ifdef MODE_REFRACTION\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"      float alpha = texture2D(Texture_Color, TexCoord).a;\n"
+"      float terrainblend = clamp(float(gl_Color.a) * alpha * 2.0 - 0.5, float(0.0), float(1.0));\n"
+"      //float terrainblend = min(float(gl_Color.a) * alpha * 2.0, float(1.0));\n"
+"      //float terrainblend = float(gl_Color.a) * alpha > 0.5;\n"
+"#endif\n"
+"\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"      vec3 surfacenormal = mix(vec3(texture2D(Texture_SecondaryNormal, TexCoord2)), vec3(texture2D(Texture_Normal, TexCoord)), terrainblend) - vec3(0.5, 0.5, 0.5);\n"
+"#else\n"
+"      vec3 surfacenormal = vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5, 0.5, 0.5);\n"
+"#endif\n"
 "\n"
-"// refraction pass\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"
+"}\n"
+"#else // !MODE_DEFERREDGEOMETRY\n"
+"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
+"uniform mat4 ViewToLight;\n"
+"// ScreenToDepth = vec2(Far / (Far - Near), Far * Near / (Near - Far));\n"
+"uniform vec2 ScreenToDepth;\n"
+"uniform myhalf3 DeferredColor_Ambient;\n"
+"uniform myhalf3 DeferredColor_Diffuse;\n"
+"#ifdef USESPECULAR\n"
+"uniform myhalf3 DeferredColor_Specular;\n"
+"uniform myhalf SpecularPower;\n"
+"#endif\n"
 "void main(void)\n"
 "{\n"
-"#ifdef USEOFFSETMAPPING\n"
-"      // apply offsetmapping\n"
-"      vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
-"#define TexCoord TexCoordOffset\n"
+"      // calculate viewspace pixel position\n"
+"      vec3 position;\n"
+"      position.z = ScreenToDepth.y / (texture2DRect(Texture_ScreenDepth, gl_FragCoord.xy).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"
+"      myhalf3 surfacenormal = normalize(normalmap.rgb - myhalf3(0.5,0.5,0.5));\n"
+"      // surfacenormal = pixel normal in viewspace\n"
+"      // LightVector = pixel to light in viewspace\n"
+"      // CubeVector = position in lightspace\n"
+"      // eyevector = pixel to view in viewspace\n"
+"      vec3 CubeVector = vec3(ViewToLight * vec4(position,1));\n"
+"      myhalf fade = myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
+"#ifdef USEDIFFUSE\n"
+"      // calculate diffuse shading\n"
+"      myhalf3 lightnormal = myhalf3(normalize(LightPosition - position));\n"
+"      myhalf diffuse = myhalf(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
+"      // calculate directional shading\n"
+"      vec3 eyevector = position * -1.0;\n"
+"#  ifdef USEEXACTSPECULARMATH\n"
+"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(eyevector)))*-1.0, 0.0)), SpecularPower);\n"
+"#  else\n"
+"      myhalf3 specularnormal = normalize(lightnormal + myhalf3(normalize(eyevector)));\n"
+"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
+"#  endif\n"
 "#endif\n"
 "\n"
-"      vec2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n"
-"      //vec2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
-"      vec2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
-"      vec2 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5))).xy * DistortScaleRefractReflect.xy;\n"
-"      // FIXME temporary hack to detect the case that the reflection\n"
-"      // gets blackened at edges due to leaving the area that contains actual\n"
-"      // content.\n"
-"      // Remove this 'ack once we have a better way to stop this thing from\n"
-"      // 'appening.\n"
-"      float f = min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, 0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, -0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
-"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
-"      ScreenTexCoord = mix(SafeScreenTexCoord, ScreenTexCoord, f);\n"
-"      gl_FragColor = texture2D(Texture_Refraction, ScreenTexCoord) * RefractColor;\n"
-"}\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAPCUBE) || defined(USESHADOWMAP2D)\n"
+"      fade *= ShadowMapCompare(CubeVector);\n"
+"#endif\n"
 "\n"
-"#else // !MODE_REFRACTION\n"
+"#ifdef USEDIFFUSE\n"
+"      gl_FragData[0] = vec4((DeferredColor_Ambient + DeferredColor_Diffuse * diffuse) * fade, 1.0);\n"
+"#else\n"
+"      gl_FragData[0] = vec4(DeferredColor_Ambient * fade, 1.0);\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
+"      gl_FragData[1] = vec4(DeferredColor_Specular * (specular * fade), 1.0);\n"
+"#else\n"
+"      gl_FragData[1] = vec4(0.0, 0.0, 0.0, 1.0);\n"
+"#endif\n"
+"\n"
+"# ifdef USECUBEFILTER\n"
+"      vec3 cubecolor = textureCube(Texture_Cube, CubeVector).rgb;\n"
+"      gl_FragData[0] *= cubecolor;\n"
+"      gl_FragData[1] *= cubecolor;\n"
+"# endif\n"
+"}\n"
+"#else // !MODE_DEFERREDLIGHTSOURCE\n"
+"#ifdef USEDEFERREDLIGHTMAP\n"
+"uniform myhalf3 DeferredMod_Diffuse;\n"
+"uniform myhalf3 DeferredMod_Specular;\n"
+"#endif\n"
+"uniform myhalf3 Color_Ambient;\n"
+"uniform myhalf3 Color_Diffuse;\n"
+"uniform myhalf3 Color_Specular;\n"
+"uniform myhalf SpecularPower;\n"
+"#ifdef USEGLOW\n"
+"uniform myhalf3 Color_Glow;\n"
+"#endif\n"
+"uniform myhalf Alpha;\n"
+"#ifdef USEREFLECTION\n"
+"uniform vec4 DistortScaleRefractReflect;\n"
+"uniform vec4 ScreenScaleRefractReflect;\n"
+"uniform vec4 ScreenCenterRefractReflect;\n"
+"uniform myhalf4 ReflectColor;\n"
+"#endif\n"
+"#ifdef MODE_LIGHTDIRECTION\n"
+"uniform myhalf3 LightColor;\n"
+"#endif\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"uniform myhalf3 LightColor;\n"
+"#endif\n"
 "void main(void)\n"
 "{\n"
 "#ifdef USEOFFSETMAPPING\n"
@@ -1231,6 +1435,11 @@ static const char *builtinshaderstring =
 "\n"
 "      // combine the diffuse textures (base, pants, shirt)\n"
 "      myhalf4 color = myhalf4(texture2D(Texture_Color, TexCoord));\n"
+"#ifdef USEALPHAKILL\n"
+"      if (color.a < 0.5)\n"
+"              discard;\n"
+"#endif\n"
+"      color.a *= Alpha;\n"
 "#ifdef USECOLORMAPPING\n"
 "      color.rgb += myhalf3(texture2D(Texture_Pants, TexCoord)) * Color_Pants + myhalf3(texture2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
 "#endif\n"
@@ -1243,64 +1452,46 @@ static const char *builtinshaderstring =
 "      //color = mix(myhalf4(1, 0, 0, 1), color, terrainblend);\n"
 "#endif\n"
 "\n"
-"#ifdef USEDIFFUSE\n"
-"      // get the surface normal and the gloss color\n"
-"# ifdef USEVERTEXTEXTUREBLEND\n"
+"      // get the surface normal\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
 "      myhalf3 surfacenormal = normalize(mix(myhalf3(texture2D(Texture_SecondaryNormal, TexCoord2)), myhalf3(texture2D(Texture_Normal, TexCoord)), terrainblend) - myhalf3(0.5, 0.5, 0.5));\n"
-"#  ifdef USESPECULAR\n"
-"      myhalf3 glosscolor = mix(myhalf3(texture2D(Texture_SecondaryGloss, TexCoord2)), myhalf3(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n"
-"#  endif\n"
-"# else\n"
+"#else\n"
 "      myhalf3 surfacenormal = normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5, 0.5, 0.5));\n"
-"#  ifdef USESPECULAR\n"
-"      myhalf3 glosscolor = myhalf3(texture2D(Texture_Gloss, TexCoord));\n"
-"#  endif\n"
-"# endif\n"
-"#endif\n"
-"\n"
-"\n"
-"\n"
-"#ifdef MODE_LIGHTSOURCE\n"
-"      // light source\n"
-"\n"
-"      // calculate surface normal, light normal, and specular normal\n"
-"      // compute color intensity for the two textures (colormap and glossmap)\n"
-"      // scale by light color and attenuation as efficiently as possible\n"
-"      // (do as much scalar math as possible rather than vector math)\n"
-"# ifdef USEDIFFUSE\n"
-"      // get the light normal\n"
-"      myhalf3 diffusenormal = myhalf3(normalize(LightVector));\n"
-"# endif\n"
-"# ifdef USESPECULAR\n"
-"#  ifndef USEEXACTSPECULARMATH\n"
-"      myhalf3 specularnormal = normalize(diffusenormal + myhalf3(normalize(EyeVector)));\n"
-"\n"
-"#  endif\n"
-"      // calculate directional shading\n"
-"#  ifdef USEEXACTSPECULARMATH\n"
-"      color.rgb = myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (color.rgb * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))) + (SpecularScale * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower)) * glosscolor);\n"
-"#  else\n"
-"      color.rgb = myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (color.rgb * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))) + (SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower)) * glosscolor);\n"
-"#  endif\n"
+"#endif\n"
+"\n"
+"      // get the material colors\n"
+"      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"
 "# else\n"
-"#  ifdef USEDIFFUSE\n"
-"      // calculate directional shading\n"
-"      color.rgb = color.rgb * (myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))));\n"
-"#  else\n"
-"      // calculate directionless shading\n"
-"      color.rgb = color.rgb * myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
-"#  endif\n"
+"      myhalf3 glosstex = myhalf3(texture2D(Texture_Gloss, TexCoord));\n"
 "# endif\n"
+"#endif\n"
 "\n"
-"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAPCUBE) || defined(USESHADOWMAP2D)\n"
-"#if !showshadowmap\n"
-"    color.rgb *= ShadowMapCompare(CubeVector);\n"
+"\n"
+"\n"
+"\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"      // light source\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"
+"#else\n"
+"      myhalf3 specularnormal = normalize(lightnormal + myhalf3(normalize(EyeVector)));\n"
+"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
 "#endif\n"
+"      color.rgb += glosstex * (specular * Color_Specular);\n"
+"#endif\n"
+"      color.rgb *= LightColor;\n"
+"      color.rgb *= myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAPCUBE) || defined(USESHADOWMAP2D)\n"
+"      color.rgb *= ShadowMapCompare(CubeVector);\n"
 "#endif\n"
-"\n"
 "# ifdef USECUBEFILTER\n"
-"      // apply light cubemap filter\n"
-"      //color.rgb *= normalize(CubeVector) * 0.5 + 0.5;//vec3(textureCube(Texture_Cube, CubeVector));\n"
 "      color.rgb *= myhalf3(textureCube(Texture_Cube, CubeVector));\n"
 "# endif\n"
 "#endif // MODE_LIGHTSOURCE\n"
@@ -1309,43 +1500,20 @@ static const char *builtinshaderstring =
 "\n"
 "\n"
 "#ifdef MODE_LIGHTDIRECTION\n"
-"      // directional model lighting\n"
-"# ifdef USEDIFFUSE\n"
-"      // get the light normal\n"
-"      myhalf3 diffusenormal = myhalf3(normalize(LightVector));\n"
-"# endif\n"
-"# ifdef USESPECULAR\n"
-"      // calculate directional shading\n"
-"      color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
-"#  ifdef USEEXACTSPECULARMATH\n"
-"      color.rgb += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
-"#  else\n"
-"      myhalf3 specularnormal = normalize(diffusenormal + myhalf3(normalize(EyeVector)));\n"
-"      color.rgb += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
-"#  endif\n"
-"# else\n"
-"#  ifdef USEDIFFUSE\n"
-"\n"
-"      // calculate directional shading\n"
-"      color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
-"#  else\n"
-"      color.rgb *= AmbientColor;\n"
-"#  endif\n"
-"# endif\n"
+"#define SHADING\n"
+"      myhalf3 lightnormal = myhalf3(normalize(LightVector));\n"
+"#define lightcolor LightColor\n"
 "#endif // MODE_LIGHTDIRECTION\n"
-"\n"
-"\n"
-"\n"
-"\n"
 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
-"      // deluxemap lightmapping using light vectors in modelspace (evil q3map2)\n"
-"\n"
-"      // get the light normal\n"
-"      myhalf3 diffusenormal_modelspace = myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n"
-"      myhalf3 diffusenormal;\n"
-"      diffusenormal.x = dot(diffusenormal_modelspace, myhalf3(VectorS));\n"
-"      diffusenormal.y = dot(diffusenormal_modelspace, myhalf3(VectorT));\n"
-"      diffusenormal.z = dot(diffusenormal_modelspace, myhalf3(VectorR));\n"
+"#define SHADING\n"
+"      // deluxemap lightmapping using light vectors in modelspace (q3map2 -light -deluxe)\n"
+"      myhalf3 lightnormal_modelspace = myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n"
+"      myhalf3 lightcolor = myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap));\n"
+"      // convert modelspace light vector to tangentspace\n"
+"      myhalf3 lightnormal;\n"
+"      lightnormal.x = dot(lightnormal_modelspace, myhalf3(VectorS));\n"
+"      lightnormal.y = dot(lightnormal_modelspace, myhalf3(VectorT));\n"
+"      lightnormal.z = dot(lightnormal_modelspace, myhalf3(VectorR));\n"
 "      // calculate directional shading (and undoing the existing angle attenuation on the lightmap by the division)\n"
 "      // note that q3map2 is too stupid to calculate proper surface normals when q3map_nonplanar\n"
 "      // is used (the lightmap and deluxemap coords correspond to virtually random coordinates\n"
@@ -1355,119 +1523,65 @@ static const char *builtinshaderstring =
 "      // are added up. To prevent divisions by zero or strong exaggerations, a max()\n"
 "      // nudge is done here at expense of some additional fps. This is ONLY needed for\n"
 "      // deluxemaps, tangentspace deluxemap avoid this problem by design.\n"
-"      myhalf3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal) / max(0.25, diffusenormal.z)), 0.0)));\n"
-"              // 0.25 supports up to 75.5 degrees normal/deluxe angle\n"
-"# ifdef USESPECULAR\n"
-"#  ifdef USEEXACTSPECULARMATH\n"
-"      tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(reflect(normalize(diffusenormal), surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
-"#  else\n"
-"      myhalf3 specularnormal = myhalf3(normalize(diffusenormal + myhalf3(normalize(EyeVector))));\n"
-"      tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
-"#  endif\n"
-"# endif\n"
-"\n"
-"      // apply lightmap color\n"
-"      color.rgb = color.rgb * AmbientScale + tempcolor * myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap));\n"
+"      lightcolor *= 1.0 / max(0.25, lightnormal.z);\n"
 "#endif // MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
-"\n"
-"\n"
-"\n"
-"\n"
 "#ifdef MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
+"#define SHADING\n"
 "      // deluxemap lightmapping using light vectors in tangentspace (hmap2 -light)\n"
-"\n"
-"      // get the light normal\n"
-"      myhalf3 diffusenormal = myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n"
-"      // calculate directional shading (and undoing the existing angle attenuation on the lightmap by the division)\n"
-"      myhalf3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal) / diffusenormal.z), 0.0)));\n"
-"# ifdef USESPECULAR\n"
-"#  ifdef USEEXACTSPECULARMATH\n"
-"      tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
-"#  else\n"
-"      myhalf3 specularnormal = myhalf3(normalize(diffusenormal + myhalf3(normalize(EyeVector))));\n"
-"      tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
-"#  endif\n"
-"# endif\n"
-"\n"
-"      // apply lightmap color\n"
-"      color.rgb = color.rgb * AmbientScale + tempcolor * myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap));\n"
-"#endif // MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
+"      myhalf3 lightnormal = myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n"
+"      myhalf3 lightcolor = myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap));\n"
+"#endif\n"
 "\n"
 "\n"
 "\n"
 "\n"
 "#ifdef MODE_LIGHTMAP\n"
-"      // apply lightmap color\n"
-"      color.rgb = color.rgb * myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap)) * DiffuseScale + color.rgb * AmbientScale;\n"
+"      color.rgb = diffusetex * (Color_Ambient + myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap)) * Color_Diffuse);\n"
 "#endif // MODE_LIGHTMAP\n"
-"\n"
-"\n"
-"\n"
-"\n"
 "#ifdef MODE_VERTEXCOLOR\n"
-"      // apply lightmap color\n"
-"      color.rgb = color.rgb * myhalf3(gl_Color.rgb) * DiffuseScale + color.rgb * AmbientScale;\n"
+"      color.rgb = diffusetex * (Color_Ambient + myhalf3(gl_Color.rgb) * Color_Diffuse);\n"
 "#endif // MODE_VERTEXCOLOR\n"
-"\n"
-"\n"
-"\n"
-"\n"
 "#ifdef MODE_FLATCOLOR\n"
+"      color.rgb = diffusetex * Color_Ambient;\n"
 "#endif // MODE_FLATCOLOR\n"
 "\n"
 "\n"
 "\n"
 "\n"
+"#ifdef SHADING\n"
+"# ifdef USEDIFFUSE\n"
+"      myhalf diffuse = myhalf(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
+"#  ifdef USESPECULAR\n"
+"#   ifdef USEEXACTSPECULARMATH\n"
+"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
+"#   else\n"
+"      myhalf3 specularnormal = normalize(lightnormal + myhalf3(normalize(EyeVector)));\n"
+"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
+"#   endif\n"
+"      color.rgb = diffusetex * Color_Ambient + (diffusetex * Color_Diffuse * diffuse + glosstex * 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"
-"\n"
-"\n"
-"      color *= TintColor;\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"
+"#endif\n"
 "\n"
 "#ifdef USEGLOW\n"
 "#ifdef USEVERTEXTEXTUREBLEND\n"
-"      color.rgb += mix(myhalf3(texture2D(Texture_SecondaryGlow, TexCoord2)), myhalf3(texture2D(Texture_Glow, TexCoord)), terrainblend);\n"
+"      color.rgb += mix(myhalf3(texture2D(Texture_SecondaryGlow, TexCoord2)), myhalf3(texture2D(Texture_Glow, TexCoord)), terrainblend) * Color_Glow;\n"
 "#else\n"
-"      color.rgb += myhalf3(texture2D(Texture_Glow, TexCoord)) * GlowColor;\n"
+"      color.rgb += myhalf3(texture2D(Texture_Glow, TexCoord)) * Color_Glow;\n"
 "#endif\n"
 "#endif\n"
 "\n"
-"      color.rgb *= SceneBrightness;\n"
-"\n"
-"      // apply fog after Contrastboost/SceneBrightness because its color is already modified appropriately\n"
 "#ifdef USEFOG\n"
-"      float fogfrac;\n"
-"#ifdef USEFOGOUTSIDE\n"
-"      fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0, min(0.0, FogPlaneVertexDist) * FogHeightFade);\n"
-"#else\n"
-"      fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist)) * min(1.0, (min(0.0, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);\n"
-"#endif\n"
-"//    float FogHeightFade1 = -0.5/1024.0;\n"
-"//    if (FogPlaneViewDist >= 0.0)\n"
-"//            fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0, min(0.0, FogPlaneVertexDist) * FogHeightFade1);\n"
-"//    else\n"
-"//            fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist)) * min(1.0, (min(0.0, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade1);\n"
-"//# ifdef USEFOGABOVE\n"
-"//    if (FogPlaneViewDist >= 0.0)\n"
-"//            fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist);\n"
-"//    else\n"
-"//            fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist));\n"
-"//    fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist))*FogHeightFade1);\n"
-"//    fogfrac *= min(1.0, (max(0.0, fade*FogPlaneVertexDist) + max(0.0, fade*FogPlaneViewDist)));\n"
-"//    fogfrac *= min(1.0, (max(0.0, FogHeightFade1*FogPlaneVertexDist) + max(0.0, FogHeightFade1*FogPlaneViewDist)));\n"
-"//    fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist))*FogHeightFade1);\n"
-"\n"
-"      //fogfrac *= min(1.0, max(0.0, (max(-2048, min(0, FogPlaneVertexDist)) + max(-2048, min(0, FogPlaneViewDist)))/-2048.0));\n"
-"      //float fade = -0.5/128.0;\n"
-"      //fogfrac *= max(0.0, min(1.0, fade*FogPlaneVertexDist)) + max(0.0, min(1.0, fade*FogPlaneViewDist));\n"
-"      //fogfrac *= max(0.0, min(1.0, FogHeightFade1*FogPlaneVertexDist)) + max(0.0, min(1.0, FogHeightFade1*FogPlaneViewDist));\n"
-"      //fogfrac *= min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist)) + min(1.0, max(0.0, FogHeightFade1*FogPlaneViewDist));\n"
-"      //fogfrac *= min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist) + max(0.0, FogHeightFade1*FogPlaneViewDist));\n"
-"      //fogfrac *= min(1.0, min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist)) + min(1.0, max(0.0, FogHeightFade1*FogPlaneViewDist)));\n"
-"      //fogfrac *= min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist) + max(0.0, FogHeightFade1*FogPlaneViewDist));\n"
-"      //fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist)) * FogHeightFade1);\n"
-"      //fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist)) * FogHeightFade1);\n"
-"//# endif\n"
-"      color.rgb = mix(FogColor, color.rgb, myhalf(texture2D(Texture_FogMask, myhalf2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0))));\n"
+"      color.rgb = mix(FogColor, color.rgb, FogVertex());\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"
@@ -1490,37 +1604,14 @@ static const char *builtinshaderstring =
 "#endif\n"
 "\n"
 "      gl_FragColor = vec4(color);\n"
-"\n"
-"#if showshadowmap\n"
-"# ifdef USESHADOWMAPRECT\n"
-"#  ifdef USESHADOWSAMPLER\n"
-"      gl_FragColor = shadow2DRect(Texture_ShadowMapRect, GetShadowMapTC2D(CubeVector).xyz);\n"
-"#  else\n"
-"      gl_FragColor = texture2DRect(Texture_ShadowMapRect, GetShadowMapTC2D(CubeVector).xy);\n"
-"#  endif\n"
-"# endif\n"
-"# ifdef USESHADOWMAP2D\n"
-"#  ifdef USESHADOWSAMPLER\n"
-"    gl_FragColor = shadow2D(Texture_ShadowMap2D, GetShadowMapTC2D(CubeVector).xyz);\n"
-"#  else\n"
-"    gl_FragColor = texture2D(Texture_ShadowMap2D, GetShadowMapTC2D(CubeVector).xy);\n"
-"#  endif\n"
-"# endif\n"
-"\n"
-"# ifdef USESHADOWMAPCUBE\n"
-"#  ifdef USESHADOWSAMPLER\n"
-"    gl_FragColor = shadowCube(Texture_ShadowMapCube, GetShadowMapTCCube(CubeVector));\n"
-"#  else\n"
-"    gl_FragColor = textureCube(Texture_ShadowMapCube, GetShadowMapTCCube(CubeVector).xyz);\n"
-"#  endif\n"
-"# endif\n"
-"#endif\n"
 "}\n"
-"#endif // !MODE_REFRACTION\n"
-"#endif // !MODE_WATER\n"
+"#endif // !MODE_DEFERREDLIGHTSOURCE\n"
+"#endif // !MODE_DEFERREDGEOMETRY\n"
 "\n"
 "#endif // FRAGMENT_SHADER\n"
 "\n"
+"#endif // !MODE_WATER\n"
+"#endif // !MODE_REFRACTION\n"
 "#endif // !MODE_BLOOMBLUR\n"
 "#endif // !MODE_GENERIC\n"
 "#endif // !MODE_POSTPROCESS\n"
@@ -1528,6 +1619,8 @@ static const char *builtinshaderstring =
 "#endif // !MODE_DEPTH_OR_SHADOW\n"
 ;
 
+const char *builtincgshaderstring = "";
+
 typedef struct shaderpermutationinfo_s
 {
        const char *pretext;
@@ -1571,8 +1664,10 @@ typedef enum shaderpermutation_e
        SHADERPERMUTATION_SHADOWMAPPCF2 = 1<<21, ///< (lightsource) use higher quality percentage closer filtering on shadowmap test results
        SHADERPERMUTATION_SHADOWSAMPLER = 1<<22, ///< (lightsource) use hardware shadowmap test
        SHADERPERMUTATION_SHADOWMAPVSDCT = 1<<23, ///< (lightsource) use virtual shadow depth cube texture for shadowmap indexing
-       SHADERPERMUTATION_LIMIT = 1<<24, ///< size of permutations array
-       SHADERPERMUTATION_COUNT = 24 ///< size of shaderpermutationinfo array
+       SHADERPERMUTATION_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;
 
@@ -1603,6 +1698,8 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
        {"#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
@@ -1621,12 +1718,14 @@ typedef enum shadermode_e
        SHADERMODE_REFRACTION, ///< refract background (the material is rendered normally after this pass)
        SHADERMODE_WATER, ///< refract background and reflection (the material is rendered normally after this pass)
        SHADERMODE_SHOWDEPTH, ///< (debugging) renders depth as color
+       SHADERMODE_DEFERREDGEOMETRY, ///< (deferred) render material properties to screenspace geometry buffers
+       SHADERMODE_DEFERREDLIGHTSOURCE, ///< (deferred) use directional pixel shading from light source (rtlight) on screenspace geometry buffers
        SHADERMODE_COUNT
 }
 shadermode_t;
 
 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
-shadermodeinfo_t shadermodeinfo[SHADERMODE_COUNT] =
+shadermodeinfo_t glslshadermodeinfo[SHADERMODE_COUNT] =
 {
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_GENERIC\n", " generic"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_POSTPROCESS\n", " postprocess"},
@@ -1641,7 +1740,30 @@ shadermodeinfo_t shadermodeinfo[SHADERMODE_COUNT] =
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_REFRACTION\n", " refraction"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_WATER\n", " water"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_SHOWDEPTH\n", " showdepth"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
+};
+
+#ifdef SUPPORTCG
+shadermodeinfo_t cgshadermodeinfo[SHADERMODE_COUNT] =
+{
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_GENERIC\n", " generic"},
+       {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_POSTPROCESS\n", " postprocess"},
+       {"cg/default.cg", NULL, NULL           , "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
+       {"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
@@ -1680,45 +1802,58 @@ typedef struct r_glsl_permutation_s
        int loc_Texture_ShadowMapCube;
        int loc_Texture_ShadowMap2D;
        int loc_Texture_CubeProjection;
-       int loc_FogColor;
-       int loc_LightPosition;
-       int loc_EyePosition;
+       int loc_Texture_ScreenDepth;
+       int loc_Texture_ScreenNormalMap;
+       int loc_Texture_ScreenDiffuse;
+       int loc_Texture_ScreenSpecular;
+       int loc_Alpha;
+       int loc_BloomBlur_Parameters;
+       int loc_ClientTime;
+       int loc_Color_Ambient;
+       int loc_Color_Diffuse;
+       int loc_Color_Specular;
+       int loc_Color_Glow;
        int loc_Color_Pants;
        int loc_Color_Shirt;
+       int loc_DeferredColor_Ambient;
+       int loc_DeferredColor_Diffuse;
+       int loc_DeferredColor_Specular;
+       int loc_DeferredMod_Diffuse;
+       int loc_DeferredMod_Specular;
+       int loc_DistortScaleRefractReflect;
+       int loc_EyePosition;
+       int loc_FogColor;
+       int loc_FogHeightFade;
        int loc_FogPlane;
        int loc_FogPlaneViewDist;
        int loc_FogRangeRecip;
-       int loc_FogHeightFade;
-       int loc_AmbientScale;
-       int loc_DiffuseScale;
-       int loc_SpecularScale;
-       int loc_SpecularPower;
-       int loc_GlowColor;
-       int loc_SceneBrightness; // or: Scenebrightness * ContrastBoost
-       int loc_OffsetMapping_Scale;
-       int loc_TintColor;
-       int loc_AmbientColor;
-       int loc_DiffuseColor;
-       int loc_SpecularColor;
+       int loc_LightColor;
        int loc_LightDir;
-       int loc_ContrastBoostCoeff; ///< 1 - 1/ContrastBoost
-       int loc_GammaCoeff; ///< 1 / gamma
-       int loc_DistortScaleRefractReflect;
-       int loc_ScreenScaleRefractReflect;
-       int loc_ScreenCenterRefractReflect;
-       int loc_RefractColor;
+       int loc_LightPosition;
+       int loc_OffsetMapping_Scale;
+       int loc_PixelSize;
        int loc_ReflectColor;
        int loc_ReflectFactor;
        int loc_ReflectOffset;
+       int loc_RefractColor;
+       int loc_Saturation;
+       int loc_ScreenCenterRefractReflect;
+       int loc_ScreenScaleRefractReflect;
+       int loc_ScreenToDepth;
+       int loc_ShadowMap_Parameters;
+       int loc_ShadowMap_TextureScale;
+       int loc_SpecularPower;
        int loc_UserVec1;
        int loc_UserVec2;
        int loc_UserVec3;
        int loc_UserVec4;
-       int loc_ClientTime;
-       int loc_PixelSize;
-       int loc_Saturation;
-       int loc_ShadowMap_TextureScale;
-       int loc_ShadowMap_Parameters;
+       int loc_ViewTintColor;
+       int loc_ViewToLight;
+       int loc_ModelToLight;
+       int loc_TexMatrix;
+       int loc_BackgroundTexMatrix;
+       int loc_ModelViewProjectionMatrix;
+       int loc_ModelViewMatrix;
 }
 r_glsl_permutation_t;
 
@@ -1765,7 +1900,7 @@ static char *R_GLSL_GetText(const char *filename, qboolean printfromdisknotice)
        if (shaderstring)
        {
                if (printfromdisknotice)
-                       Con_DPrint("from disk... ");
+                       Con_DPrintf("from disk %s... ", filename);
                return shaderstring;
        }
        else if (!strcmp(filename, "glsl/default.glsl"))
@@ -1779,7 +1914,7 @@ static char *R_GLSL_GetText(const char *filename, qboolean printfromdisknotice)
 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;
@@ -1799,7 +1934,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)
@@ -1808,9 +1943,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
@@ -1854,6 +1989,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                qglUseProgramObjectARB(p->program);CHECKGLERROR
                // look up all the uniform variable names we care about, so we don't
                // have to look them up every time we set them
+
                p->loc_Texture_First              = qglGetUniformLocationARB(p->program, "Texture_First");
                p->loc_Texture_Second             = qglGetUniformLocationARB(p->program, "Texture_Second");
                p->loc_Texture_GammaRamps         = qglGetUniformLocationARB(p->program, "Texture_GammaRamps");
@@ -1865,58 +2001,71 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                p->loc_Texture_SecondaryColor     = qglGetUniformLocationARB(p->program, "Texture_SecondaryColor");
                p->loc_Texture_SecondaryGloss     = qglGetUniformLocationARB(p->program, "Texture_SecondaryGloss");
                p->loc_Texture_SecondaryGlow      = qglGetUniformLocationARB(p->program, "Texture_SecondaryGlow");
-               p->loc_Texture_FogMask            = qglGetUniformLocationARB(p->program, "Texture_FogMask");
                p->loc_Texture_Pants              = qglGetUniformLocationARB(p->program, "Texture_Pants");
                p->loc_Texture_Shirt              = qglGetUniformLocationARB(p->program, "Texture_Shirt");
+               p->loc_Texture_FogMask            = qglGetUniformLocationARB(p->program, "Texture_FogMask");
                p->loc_Texture_Lightmap           = qglGetUniformLocationARB(p->program, "Texture_Lightmap");
                p->loc_Texture_Deluxemap          = qglGetUniformLocationARB(p->program, "Texture_Deluxemap");
-               p->loc_Texture_Refraction         = qglGetUniformLocationARB(p->program, "Texture_Refraction");
-               p->loc_Texture_Reflection         = qglGetUniformLocationARB(p->program, "Texture_Reflection");
                p->loc_Texture_Attenuation        = qglGetUniformLocationARB(p->program, "Texture_Attenuation");
                p->loc_Texture_Cube               = qglGetUniformLocationARB(p->program, "Texture_Cube");
+               p->loc_Texture_Refraction         = qglGetUniformLocationARB(p->program, "Texture_Refraction");
+               p->loc_Texture_Reflection         = qglGetUniformLocationARB(p->program, "Texture_Reflection");
                p->loc_Texture_ShadowMapRect      = qglGetUniformLocationARB(p->program, "Texture_ShadowMapRect");
                p->loc_Texture_ShadowMapCube      = qglGetUniformLocationARB(p->program, "Texture_ShadowMapCube");
                p->loc_Texture_ShadowMap2D        = qglGetUniformLocationARB(p->program, "Texture_ShadowMap2D");
                p->loc_Texture_CubeProjection     = qglGetUniformLocationARB(p->program, "Texture_CubeProjection");
-               p->loc_FogColor                   = qglGetUniformLocationARB(p->program, "FogColor");
-               p->loc_LightPosition              = qglGetUniformLocationARB(p->program, "LightPosition");
-               p->loc_EyePosition                = qglGetUniformLocationARB(p->program, "EyePosition");
+               p->loc_Texture_ScreenDepth        = qglGetUniformLocationARB(p->program, "Texture_ScreenDepth");
+               p->loc_Texture_ScreenNormalMap    = qglGetUniformLocationARB(p->program, "Texture_ScreenNormalMap");
+               p->loc_Texture_ScreenDiffuse      = qglGetUniformLocationARB(p->program, "Texture_ScreenDiffuse");
+               p->loc_Texture_ScreenSpecular     = qglGetUniformLocationARB(p->program, "Texture_ScreenSpecular");
+               p->loc_Alpha                      = qglGetUniformLocationARB(p->program, "Alpha");
+               p->loc_BloomBlur_Parameters       = qglGetUniformLocationARB(p->program, "BloomBlur_Parameters");
+               p->loc_ClientTime                 = qglGetUniformLocationARB(p->program, "ClientTime");
+               p->loc_Color_Ambient              = qglGetUniformLocationARB(p->program, "Color_Ambient");
+               p->loc_Color_Diffuse              = qglGetUniformLocationARB(p->program, "Color_Diffuse");
+               p->loc_Color_Specular             = qglGetUniformLocationARB(p->program, "Color_Specular");
+               p->loc_Color_Glow                 = qglGetUniformLocationARB(p->program, "Color_Glow");
                p->loc_Color_Pants                = qglGetUniformLocationARB(p->program, "Color_Pants");
                p->loc_Color_Shirt                = qglGetUniformLocationARB(p->program, "Color_Shirt");
+               p->loc_DeferredColor_Ambient      = qglGetUniformLocationARB(p->program, "DeferredColor_Ambient");
+               p->loc_DeferredColor_Diffuse      = qglGetUniformLocationARB(p->program, "DeferredColor_Diffuse");
+               p->loc_DeferredColor_Specular     = qglGetUniformLocationARB(p->program, "DeferredColor_Specular");
+               p->loc_DeferredMod_Diffuse        = qglGetUniformLocationARB(p->program, "DeferredMod_Diffuse");
+               p->loc_DeferredMod_Specular       = qglGetUniformLocationARB(p->program, "DeferredMod_Specular");
+               p->loc_DistortScaleRefractReflect = qglGetUniformLocationARB(p->program, "DistortScaleRefractReflect");
+               p->loc_EyePosition                = qglGetUniformLocationARB(p->program, "EyePosition");
+               p->loc_FogColor                   = qglGetUniformLocationARB(p->program, "FogColor");
+               p->loc_FogHeightFade              = qglGetUniformLocationARB(p->program, "FogHeightFade");
                p->loc_FogPlane                   = qglGetUniformLocationARB(p->program, "FogPlane");
                p->loc_FogPlaneViewDist           = qglGetUniformLocationARB(p->program, "FogPlaneViewDist");
                p->loc_FogRangeRecip              = qglGetUniformLocationARB(p->program, "FogRangeRecip");
-               p->loc_FogHeightFade              = qglGetUniformLocationARB(p->program, "FogHeightFade");
-               p->loc_AmbientScale               = qglGetUniformLocationARB(p->program, "AmbientScale");
-               p->loc_DiffuseScale               = qglGetUniformLocationARB(p->program, "DiffuseScale");
-               p->loc_SpecularPower              = qglGetUniformLocationARB(p->program, "SpecularPower");
-               p->loc_SpecularScale              = qglGetUniformLocationARB(p->program, "SpecularScale");
-               p->loc_GlowColor                  = qglGetUniformLocationARB(p->program, "GlowColor");
-               p->loc_SceneBrightness            = qglGetUniformLocationARB(p->program, "SceneBrightness");
-               p->loc_OffsetMapping_Scale        = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
-               p->loc_TintColor                  = qglGetUniformLocationARB(p->program, "TintColor");
-               p->loc_AmbientColor               = qglGetUniformLocationARB(p->program, "AmbientColor");
-               p->loc_DiffuseColor               = qglGetUniformLocationARB(p->program, "DiffuseColor");
-               p->loc_SpecularColor              = qglGetUniformLocationARB(p->program, "SpecularColor");
+               p->loc_LightColor                 = qglGetUniformLocationARB(p->program, "LightColor");
                p->loc_LightDir                   = qglGetUniformLocationARB(p->program, "LightDir");
-               p->loc_ContrastBoostCoeff         = qglGetUniformLocationARB(p->program, "ContrastBoostCoeff");
-               p->loc_DistortScaleRefractReflect = qglGetUniformLocationARB(p->program, "DistortScaleRefractReflect");
-               p->loc_ScreenScaleRefractReflect  = qglGetUniformLocationARB(p->program, "ScreenScaleRefractReflect");
-               p->loc_ScreenCenterRefractReflect = qglGetUniformLocationARB(p->program, "ScreenCenterRefractReflect");
-               p->loc_RefractColor               = qglGetUniformLocationARB(p->program, "RefractColor");
+               p->loc_LightPosition              = qglGetUniformLocationARB(p->program, "LightPosition");
+               p->loc_OffsetMapping_Scale        = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
+               p->loc_PixelSize                  = qglGetUniformLocationARB(p->program, "PixelSize");
                p->loc_ReflectColor               = qglGetUniformLocationARB(p->program, "ReflectColor");
                p->loc_ReflectFactor              = qglGetUniformLocationARB(p->program, "ReflectFactor");
                p->loc_ReflectOffset              = qglGetUniformLocationARB(p->program, "ReflectOffset");
-               p->loc_GammaCoeff                 = qglGetUniformLocationARB(p->program, "GammaCoeff");
+               p->loc_RefractColor               = qglGetUniformLocationARB(p->program, "RefractColor");
+               p->loc_Saturation                 = qglGetUniformLocationARB(p->program, "Saturation");
+               p->loc_ScreenCenterRefractReflect = qglGetUniformLocationARB(p->program, "ScreenCenterRefractReflect");
+               p->loc_ScreenScaleRefractReflect  = qglGetUniformLocationARB(p->program, "ScreenScaleRefractReflect");
+               p->loc_ScreenToDepth              = qglGetUniformLocationARB(p->program, "ScreenToDepth");
+               p->loc_ShadowMap_Parameters       = qglGetUniformLocationARB(p->program, "ShadowMap_Parameters");
+               p->loc_ShadowMap_TextureScale     = qglGetUniformLocationARB(p->program, "ShadowMap_TextureScale");
+               p->loc_SpecularPower              = qglGetUniformLocationARB(p->program, "SpecularPower");
                p->loc_UserVec1                   = qglGetUniformLocationARB(p->program, "UserVec1");
                p->loc_UserVec2                   = qglGetUniformLocationARB(p->program, "UserVec2");
                p->loc_UserVec3                   = qglGetUniformLocationARB(p->program, "UserVec3");
                p->loc_UserVec4                   = qglGetUniformLocationARB(p->program, "UserVec4");
-               p->loc_ClientTime                 = qglGetUniformLocationARB(p->program, "ClientTime");
-               p->loc_PixelSize                  = qglGetUniformLocationARB(p->program, "PixelSize");
-               p->loc_Saturation                 = qglGetUniformLocationARB(p->program, "Saturation");
-               p->loc_ShadowMap_TextureScale     = qglGetUniformLocationARB(p->program, "ShadowMap_TextureScale");
-               p->loc_ShadowMap_Parameters       = qglGetUniformLocationARB(p->program, "ShadowMap_Parameters");
+               p->loc_ViewTintColor              = qglGetUniformLocationARB(p->program, "ViewTintColor");
+               p->loc_ViewToLight                = qglGetUniformLocationARB(p->program, "ViewToLight");
+               p->loc_ModelToLight               = qglGetUniformLocationARB(p->program, "ModelToLight");
+               p->loc_TexMatrix                  = qglGetUniformLocationARB(p->program, "TexMatrix");
+               p->loc_BackgroundTexMatrix        = qglGetUniformLocationARB(p->program, "BackgroundTexMatrix");
+               p->loc_ModelViewMatrix            = qglGetUniformLocationARB(p->program, "ModelViewMatrix");
+               p->loc_ModelViewProjectionMatrix  = qglGetUniformLocationARB(p->program, "ModelViewProjectionMatrix");
                // 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);
@@ -1942,12 +2091,16 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                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_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);
                CHECKGLERROR
                if (developer.integer)
-                       Con_Printf("GLSL shader %s compiled.\n", permutationname);
+                       Con_Printf("^5GLSL shader %s compiled.\n", permutationname);
        }
        else
-               Con_Printf("GLSL shader %s failed!  some features may not work properly.\n", permutationname);
+               Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
 
        // free the strings
        if (vertexstring)
@@ -1958,57 +2111,462 @@ 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)
+{
+       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);
+}
+
+#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 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_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;
+}
+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;const char *errorstring = cgGetLastErrorString(&err);if (err){Con_Printf("%s:%i CG error %i: %s\n", __FILE__, __LINE__, err, errorstring);if (err == 1) Con_Printf("last listing:\n%s\n", cgGetLastListing(vid.cgcontext));}}
+
+static r_cg_permutation_t *R_CG_FindPermutation(unsigned int mode, unsigned int permutation)
+{
+       //unsigned int hashdepth = 0;
+       unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
+       r_cg_permutation_t *p;
+       for (p = r_cg_permutationhash[mode][hashindex];p;p = p->hashnext)
+       {
+               if (p->mode == mode && p->permutation == permutation)
+               {
+                       //if (hashdepth > 10)
+                       //      Con_Printf("R_CG_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
+                       return p;
+               }
+               //hashdepth++;
+       }
+       p = (r_cg_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_cg_permutationarray);
+       p->mode = mode;
+       p->permutation = permutation;
+       p->hashnext = r_cg_permutationhash[mode][hashindex];
+       r_cg_permutationhash[mode][hashindex] = p;
+       //if (hashdepth > 10)
+       //      Con_Printf("R_CG_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
+       return p;
+}
+
+static char *R_CG_GetText(const char *filename, qboolean printfromdisknotice)
+{
+       char *shaderstring;
+       if (!filename || !filename[0])
+               return NULL;
+       shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
+       if (shaderstring)
+       {
+               if (printfromdisknotice)
+                       Con_DPrintf("from disk %s... ", filename);
+               return shaderstring;
+       }
+       else if (!strcmp(filename, "cg/default.cg"))
+       {
+               shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(builtincgshaderstring) + 1);
+               memcpy(shaderstring, builtincgshaderstring, strlen(builtincgshaderstring) + 1);
+       }
+       return shaderstring;
+}
+
+static void R_CG_CompilePermutation(r_cg_permutation_t *p, 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++)
+       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];
+       CGprofile vertexProfile;
+       CGprofile fragmentProfile;
+
+       if (p->compiled)
+               return;
+       p->compiled = true;
+       p->vprogram = NULL;
+       p->fprogram = NULL;
+
+       permutationname[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));
+
+       // 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));
+
+       // now add all the permutation pretexts
+       for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
        {
-               if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, 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));
+               }
+               else
                {
-                       GL_Backend_FreeProgram(p->program);
-                       Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
+                       // keep line numbers correct
+                       vertstrings_list[vertstrings_count++] = "\n";
+                       geomstrings_list[geomstrings_count++] = "\n";
+                       fragstrings_list[fragstrings_count++] = "\n";
                }
        }
-       memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
-}
 
-void R_GLSL_DumpShader_f(void)
-{
-       int 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
 
-       qfile_t *file = FS_OpenRealFile("glsl/default.glsl", "w", false);
-       if(!file)
+       // compile the vertex program
+       if (vertstring[0] && (p->vprogram = cgCreateProgram(vid.cgcontext, CG_SOURCE, vertstring, CG_PROFILE_ARBVP1, NULL, NULL)))
        {
-               Con_Printf("failed to write to glsl/default.glsl\n");
-               return;
+               CHECKCGERROR
+               cgCompileProgram(p->vprogram);CHECKCGERROR
+               if (!cgIsProgramCompiled(p->vprogram))
+               {
+                       CHECKCGERROR
+                       cgDestroyProgram(p->vprogram);CHECKCGERROR
+                       p->vprogram = 0;
+               }
+               else
+               {
+                       cgGLLoadProgram(p->vprogram);CHECKCGERROR CHECKGLERROR
+                       cgGLEnableProfile(vertexProfile);CHECKCGERROR CHECKGLERROR
+                       // look up all the uniform variable names we care about, so we don't
+                       // have to look them up every time we set them
+                       CHECKCGERROR
+                       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");
+                       CHECKCGERROR
+               }
        }
 
-       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);
+       // compile the fragment program
+       if (fragstring[0] && (p->fprogram = cgCreateProgram(vid.cgcontext, CG_SOURCE, fragstring, CG_PROFILE_ARBFP1, NULL, NULL)))
+       {
+               cgCompileProgram(p->fprogram);CHECKCGERROR
+               if (!cgIsProgramCompiled(p->fprogram))
+               {
+                       CHECKCGERROR
+                       cgDestroyProgram(p->fprogram);CHECKCGERROR
+                       p->fprogram = 0;
+               }
+               else
+               {
+                       cgGLLoadProgram(p->fprogram);CHECKCGERROR CHECKGLERROR
+                       cgGLEnableProfile(fragmentProfile);CHECKCGERROR CHECKGLERROR
+                       CHECKCGERROR
+                       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_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");
+                       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;
@@ -2019,73 +2577,209 @@ 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
+}
+
+void CG_BindTexture(CGparameter param, int texnum)
+{
+       cgGLSetTextureParameter(param, texnum);
+       cgGLEnableTextureParameter(param);
 }
+#endif
 
-void R_SetupGenericShader(qboolean usetexture)
+void R_GLSL_Restart_f(void)
 {
+       unsigned int i, limit;
        switch(vid.renderpath)
        {
        case RENDERPATH_GL20:
-               R_SetupShader_SetPermutation(SHADERMODE_GENERIC, usetexture ? SHADERPERMUTATION_DIFFUSE : 0);
+               {
+                       r_glsl_permutation_t *p;
+                       limit = Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
+                       for (i = 0;i < limit;i++)
+                       {
+                               if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
+                               {
+                                       GL_Backend_FreeProgram(p->program);
+                                       Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
+                               }
+                       }
+                       memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
+               }
+               break;
+       case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+               {
+                       r_cg_permutation_t *p;
+                       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 , R_GetTexture(first ));
+               if (r_glsl_permutation->loc_Texture_Second) R_Mesh_TexBind(GL20TU_SECOND, R_GetTexture(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 , R_GetTexture(first ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Second) CG_BindTexture(r_cg_permutation->fp_Texture_Second, R_GetTexture(second));CHECKCGERROR
+#endif
                break;
        case RENDERPATH_GL13:
+               R_Mesh_TexBind(0, R_GetTexture(first ));
+               R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+               R_Mesh_TexBind(1, R_GetTexture(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, R_GetTexture(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;
@@ -2094,6 +2788,8 @@ void R_SetupShowDepthShader(void)
        }
 }
 
+extern qboolean r_shadow_usingdeferredprepass;
+extern cvar_t r_shadow_deferred_8bitrange;
 extern rtexture_t *r_shadow_attenuationgradienttexture;
 extern rtexture_t *r_shadow_attenuation2dtexture;
 extern rtexture_t *r_shadow_attenuation3dtexture;
@@ -2105,7 +2801,18 @@ 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 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
@@ -2113,6 +2820,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;
+       float m16f[16];
        // TODO: implement geometry-shader based shadow volumes someday
        if (r_glsl_offsetmapping.integer)
        {
@@ -2128,6 +2836,19 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                else
                        mode = SHADERMODE_REFRACTION;
        }
+       else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
+       {
+               // normalmap (deferred prepass), may use alpha test on diffuse
+               mode = SHADERMODE_DEFERREDGEOMETRY;
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
+                       permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
+               if (r_glsl_offsetmapping.integer)
+               {
+                       permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                       if (r_glsl_offsetmapping_reliefmapping.integer)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+               }
+       }
        else if (rsurfacepass == RSURFPASS_RTLIGHT)
        {
                // light source
@@ -2167,9 +2888,10 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
        {
                // 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;
@@ -2190,7 +2912,7 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                mode = SHADERMODE_LIGHTDIRECTION;
                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;
                permutation |= SHADERPERMUTATION_DIFFUSE;
                if (specularscale > 0)
@@ -2201,6 +2923,8 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
+               if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
+                       permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
        }
        else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
        {
@@ -2208,7 +2932,7 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                mode = SHADERMODE_LIGHTDIRECTION;
                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;
@@ -2216,6 +2940,8 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
+               if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
+                       permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
        }
        else
        {
@@ -2251,7 +2977,7 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                }
                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;
@@ -2259,98 +2985,389 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
+               if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
+                       permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
        }
        if(permutation & SHADERPERMUTATION_SPECULAR)
                if(r_shadow_glossexact.integer)
                        permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
-       R_SetupShader_SetPermutation(mode, permutation);
-       if (mode == SHADERMODE_LIGHTSOURCE)
+       if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) && r_shadow_usingdeferredprepass)
+               permutation |= SHADERPERMUTATION_ALPHAKILL;
+       switch(vid.renderpath)
        {
-               if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
-               if (permutation & SHADERPERMUTATION_DIFFUSE)
+       case RENDERPATH_GL20:
+               R_SetupShader_SetPermutationGLSL(mode, permutation);
+               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, 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);
+                       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_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, 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]);
+                       }
+                       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);
+                       }
+                       // 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_ModelViewMatrix >= 0) qglUniformMatrix4fvARB(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
+               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_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_Texture_First           >= 0) R_Mesh_TexBind(GL20TU_FIRST             ,          R_GetTexture(r_texture_white                                     ));
+       //      if (r_glsl_permutation->loc_Texture_Second          >= 0) R_Mesh_TexBind(GL20TU_SECOND            ,          R_GetTexture(r_texture_white                                     ));
+       //      if (r_glsl_permutation->loc_Texture_GammaRamps      >= 0) R_Mesh_TexBind(GL20TU_GAMMARAMPS        ,          R_GetTexture(r_texture_gammaramps                                ));
+               if (r_glsl_permutation->loc_Texture_Normal          >= 0) R_Mesh_TexBind(GL20TU_NORMAL            ,          R_GetTexture(rsurface.texture->nmaptexture                       ));
+               if (r_glsl_permutation->loc_Texture_Color           >= 0) R_Mesh_TexBind(GL20TU_COLOR             ,          R_GetTexture(rsurface.texture->basetexture                       ));
+               if (r_glsl_permutation->loc_Texture_Gloss           >= 0) R_Mesh_TexBind(GL20TU_GLOSS             ,          R_GetTexture(rsurface.texture->glosstexture                      ));
+               if (r_glsl_permutation->loc_Texture_Glow            >= 0) R_Mesh_TexBind(GL20TU_GLOW              ,          R_GetTexture(rsurface.texture->glowtexture                       ));
+               if (r_glsl_permutation->loc_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL  ,          R_GetTexture(rsurface.texture->backgroundnmaptexture             ));
+               if (r_glsl_permutation->loc_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(GL20TU_SECONDARY_COLOR   ,          R_GetTexture(rsurface.texture->backgroundbasetexture             ));
+               if (r_glsl_permutation->loc_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS   ,          R_GetTexture(rsurface.texture->backgroundglosstexture            ));
+               if (r_glsl_permutation->loc_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(GL20TU_SECONDARY_GLOW    ,          R_GetTexture(rsurface.texture->backgroundglowtexture             ));
+               if (r_glsl_permutation->loc_Texture_Pants           >= 0) R_Mesh_TexBind(GL20TU_PANTS             ,          R_GetTexture(rsurface.texture->pantstexture                      ));
+               if (r_glsl_permutation->loc_Texture_Shirt           >= 0) R_Mesh_TexBind(GL20TU_SHIRT             ,          R_GetTexture(rsurface.texture->shirttexture                      ));
+               if (r_glsl_permutation->loc_Texture_FogMask         >= 0) R_Mesh_TexBind(GL20TU_FOGMASK           ,          R_GetTexture(r_texture_fogattenuation                            ));
+               if (r_glsl_permutation->loc_Texture_Lightmap        >= 0) R_Mesh_TexBind(GL20TU_LIGHTMAP          ,          R_GetTexture(r_texture_white                                     ));
+               if (r_glsl_permutation->loc_Texture_Deluxemap       >= 0) R_Mesh_TexBind(GL20TU_LIGHTMAP          ,          R_GetTexture(r_texture_blanknormalmap                            ));
+               if (r_glsl_permutation->loc_Texture_Attenuation     >= 0) R_Mesh_TexBind(GL20TU_ATTENUATION       ,          R_GetTexture(r_shadow_attenuationgradienttexture                 ));
+               if (r_glsl_permutation->loc_Texture_Refraction      >= 0) R_Mesh_TexBind(GL20TU_REFRACTION        ,          R_GetTexture(r_texture_white                                     ));
+               if (r_glsl_permutation->loc_Texture_Reflection      >= 0) R_Mesh_TexBind(GL20TU_REFLECTION        ,          R_GetTexture(r_texture_white                                     ));
+               if (r_glsl_permutation->loc_Texture_ScreenDepth     >= 0) R_Mesh_TexBindAll(GL20TU_SCREENDEPTH    , 0, 0, 0, R_GetTexture(r_shadow_prepassgeometrydepthtexture                ));
+               if (r_glsl_permutation->loc_Texture_ScreenNormalMap >= 0) R_Mesh_TexBindAll(GL20TU_SCREENNORMALMAP, 0, 0, 0, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture            ));
+               if (r_glsl_permutation->loc_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBindAll(GL20TU_SCREENDIFFUSE  , 0, 0, 0, R_GetTexture(r_shadow_prepasslightingdiffusetexture              ));
+               if (r_glsl_permutation->loc_Texture_ScreenSpecular  >= 0) R_Mesh_TexBindAll(GL20TU_SCREENSPECULAR , 0, 0, 0, R_GetTexture(r_shadow_prepasslightingspeculartexture             ));
+               if (rsurface.rtlight)
+               {
+                       if (r_glsl_permutation->loc_Texture_Cube            >= 0) R_Mesh_TexBindAll(GL20TU_CUBE           , 0, 0,    R_GetTexture(rsurface.rtlight->currentcubemap                    ), 0);
+                       if (r_glsl_permutation->loc_Texture_ShadowMapRect   >= 0) R_Mesh_TexBindAll(GL20TU_SHADOWMAPRECT  , 0, 0, 0, R_GetTexture(r_shadow_shadowmaprectangletexture                  ));
+                       if (r_shadow_usingshadowmapcube)
+                               if (r_glsl_permutation->loc_Texture_ShadowMapCube   >= 0) R_Mesh_TexBindAll(GL20TU_SHADOWMAPCUBE  , 0, 0,    R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);
+                       if (r_glsl_permutation->loc_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(GL20TU_SHADOWMAP2D       ,          R_GetTexture(r_shadow_shadowmap2dtexture                         ));
+                       if (r_glsl_permutation->loc_Texture_CubeProjection  >= 0) R_Mesh_TexBindAll(GL20TU_CUBEPROJECTION , 0, 0,    R_GetTexture(r_shadow_shadowmapvsdcttexture                      ), 0);
+               }
+               CHECKGLERROR
+               break;
+       case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+               R_SetupShader_SetPermutationCG(mode, permutation);
+               if (mode == SHADERMODE_LIGHTSOURCE)
                {
-                       if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2], rsurface.texture->lightmapcolor[3]);
-                       if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, ambientscale);
-                       if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, diffusescale);
-                       if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, specularscale);
+                       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
                {
-                       // ambient only is simpler
-                       if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, lightcolorbase[0] * ambientscale, lightcolorbase[1] * ambientscale, lightcolorbase[2] * ambientscale, rsurface.texture->lightmapcolor[3]);
-                       if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, 1);
-                       if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, 0);
-                       if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, 0);
+                       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
+                       }
                }
-               // additive passes are only darkened by fog, not tinted
-               if (r_glsl_permutation->loc_FogColor >= 0)
-                       qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
-               if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2fARB(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
-               if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4fARB(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
-       }
-       else
-       {
-               if (mode == SHADERMODE_LIGHTDIRECTION)
+               if (r_cg_permutation->vp_ModelViewMatrix) cgGLSetMatrixParameterfc(r_cg_permutation->vp_ModelViewMatrix, gl_modelviewprojection16f);CHECKCGERROR
+               if (r_cg_permutation->vp_TexMatrix) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);cgGLSetMatrixParameterfc(r_cg_permutation->vp_TexMatrix, m16f);}CHECKCGERROR
+               if (r_cg_permutation->vp_BackgroundTexMatrix) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);cgGLSetMatrixParameterfc(r_cg_permutation->vp_BackgroundTexMatrix, m16f);}CHECKCGERROR
+               if (r_cg_permutation->vp_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_AmbientColor  >= 0) qglUniform3fARB(r_glsl_permutation->loc_AmbientColor , rsurface.modellight_ambient[0] * ambientscale  * 0.5f, rsurface.modellight_ambient[1] * ambientscale  * 0.5f, rsurface.modellight_ambient[2] * ambientscale  * 0.5f);
-                       if (r_glsl_permutation->loc_DiffuseColor  >= 0) qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor , rsurface.modellight_diffuse[0] * diffusescale  * 0.5f, rsurface.modellight_diffuse[1] * diffusescale  * 0.5f, rsurface.modellight_diffuse[2] * diffusescale  * 0.5f);
-                       if (r_glsl_permutation->loc_SpecularColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, rsurface.modellight_diffuse[0] * specularscale * 0.5f, rsurface.modellight_diffuse[1] * specularscale * 0.5f, rsurface.modellight_diffuse[2] * specularscale * 0.5f);
-                       if (r_glsl_permutation->loc_LightDir      >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
+                       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, specularscale, specularscale, 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_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, rsurface.texture->specularpower * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));CHECKCGERROR
                }
                else
                {
-                       if (r_glsl_permutation->loc_AmbientScale  >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, r_refdef.scene.ambient * 1.0f / 128.0f);
-                       if (r_glsl_permutation->loc_DiffuseScale  >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_refdef.lightmapintensity);
-                       if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale);
+                       if (mode == SHADERMODE_FLATCOLOR)
+                       {
+                               if (r_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, r_refdef.lightmapintensity, r_refdef.lightmapintensity);CHECKCGERROR
+                               if (r_cg_permutation->fp_Color_Specular) cgGLSetParameter3f(r_cg_permutation->fp_Color_Specular, r_refdef.lightmapintensity * specularscale, r_refdef.lightmapintensity * specularscale, r_refdef.lightmapintensity * 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 * specularscale, r_refdef.lightmapintensity * specularscale, r_refdef.lightmapintensity * 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_Color_Glow) cgGLSetParameter3f(r_cg_permutation->fp_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]);CHECKCGERROR
+               if (r_cg_permutation->fp_Alpha) cgGLSetParameter1f(r_cg_permutation->fp_Alpha, rsurface.texture->lightmapcolor[3]);CHECKCGERROR
+               if (r_cg_permutation->fp_EyePosition) cgGLSetParameter3f(r_cg_permutation->fp_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);CHECKCGERROR
+               if (r_cg_permutation->fp_Color_Pants)
+               {
+                       if (rsurface.texture->pantstexture)
+                               cgGLSetParameter3f(r_cg_permutation->fp_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
+                       else
+                               cgGLSetParameter3f(r_cg_permutation->fp_Color_Pants, 0, 0, 0);
+                       CHECKCGERROR
                }
-               if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2], rsurface.texture->lightmapcolor[3]);
-               if (r_glsl_permutation->loc_GlowColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_GlowColor, rsurface.glowmod[0] * r_hdr_glowintensity.value, rsurface.glowmod[1] * r_hdr_glowintensity.value, rsurface.glowmod[2] * r_hdr_glowintensity.value);
-               // additive passes are only darkened by fog, not tinted
-               if (r_glsl_permutation->loc_FogColor >= 0)
+               if (r_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_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_refdef.view.colorscale);
-       if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
-       if (r_glsl_permutation->loc_Color_Pants >= 0)
-       {
-               if (rsurface.texture->currentskinframe->pants)
-                       qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
-               else
-                       qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
-       }
-       if (r_glsl_permutation->loc_Color_Shirt >= 0)
-       {
-               if (rsurface.texture->currentskinframe->shirt)
-                       qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]);
-               else
-                       qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 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_Texture_First          ) CG_BindTexture(r_cg_permutation->fp_Texture_First          , R_GetTexture(r_texture_white                                     ));CHECKCGERROR
+       //      if (r_cg_permutation->fp_Texture_Second         ) CG_BindTexture(r_cg_permutation->fp_Texture_Second         , R_GetTexture(r_texture_white                                     ));CHECKCGERROR
+       //      if (r_cg_permutation->fp_Texture_GammaRamps     ) CG_BindTexture(r_cg_permutation->fp_Texture_GammaRamps     , R_GetTexture(r_texture_gammaramps                                ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Normal         ) CG_BindTexture(r_cg_permutation->fp_Texture_Normal         , R_GetTexture(rsurface.texture->nmaptexture                       ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Color          ) CG_BindTexture(r_cg_permutation->fp_Texture_Color          , R_GetTexture(rsurface.texture->basetexture                       ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Gloss          ) CG_BindTexture(r_cg_permutation->fp_Texture_Gloss          , R_GetTexture(rsurface.texture->glosstexture                      ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Glow           ) CG_BindTexture(r_cg_permutation->fp_Texture_Glow           , R_GetTexture(rsurface.texture->glowtexture                       ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_SecondaryNormal) CG_BindTexture(r_cg_permutation->fp_Texture_SecondaryNormal, R_GetTexture(rsurface.texture->backgroundnmaptexture             ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_SecondaryColor ) CG_BindTexture(r_cg_permutation->fp_Texture_SecondaryColor , R_GetTexture(rsurface.texture->backgroundbasetexture             ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_SecondaryGloss ) CG_BindTexture(r_cg_permutation->fp_Texture_SecondaryGloss , R_GetTexture(rsurface.texture->backgroundglosstexture            ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_SecondaryGlow  ) CG_BindTexture(r_cg_permutation->fp_Texture_SecondaryGlow  , R_GetTexture(rsurface.texture->backgroundglowtexture             ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Pants          ) CG_BindTexture(r_cg_permutation->fp_Texture_Pants          , R_GetTexture(rsurface.texture->pantstexture                      ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Shirt          ) CG_BindTexture(r_cg_permutation->fp_Texture_Shirt          , R_GetTexture(rsurface.texture->shirttexture                      ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_FogMask        ) CG_BindTexture(r_cg_permutation->fp_Texture_FogMask        , R_GetTexture(r_texture_fogattenuation                            ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Lightmap       ) CG_BindTexture(r_cg_permutation->fp_Texture_Lightmap       , R_GetTexture(r_texture_white                                     ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Deluxemap      ) CG_BindTexture(r_cg_permutation->fp_Texture_Deluxemap      , R_GetTexture(r_texture_blanknormalmap                            ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Attenuation    ) CG_BindTexture(r_cg_permutation->fp_Texture_Attenuation    , R_GetTexture(r_shadow_attenuationgradienttexture                 ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Refraction     ) CG_BindTexture(r_cg_permutation->fp_Texture_Refraction     , R_GetTexture(r_texture_white                                     ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Reflection     ) CG_BindTexture(r_cg_permutation->fp_Texture_Reflection     , R_GetTexture(r_texture_white                                     ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ScreenDepth    ) CG_BindTexture(r_cg_permutation->fp_Texture_ScreenDepth    , R_GetTexture(r_shadow_prepassgeometrydepthtexture                ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ScreenNormalMap) CG_BindTexture(r_cg_permutation->fp_Texture_ScreenNormalMap, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture            ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ScreenDiffuse  ) CG_BindTexture(r_cg_permutation->fp_Texture_ScreenDiffuse  , R_GetTexture(r_shadow_prepasslightingdiffusetexture              ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ScreenSpecular ) CG_BindTexture(r_cg_permutation->fp_Texture_ScreenSpecular , R_GetTexture(r_shadow_prepasslightingspeculartexture             ));CHECKCGERROR
+               if (rsurface.rtlight)
+               {
+                       if (r_cg_permutation->fp_Texture_Cube       ) CG_BindTexture(r_cg_permutation->fp_Texture_Cube           , R_GetTexture(rsurface.rtlight->currentcubemap                    ));CHECKCGERROR
+                       if (r_cg_permutation->fp_Texture_ShadowMapRect  ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMapRect  , R_GetTexture(r_shadow_shadowmaprectangletexture                  ));CHECKCGERROR
+                       if (r_shadow_usingshadowmapcube)
+                               if (r_cg_permutation->fp_Texture_ShadowMapCube  ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMapCube  , R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));CHECKCGERROR
+                       if (r_cg_permutation->fp_Texture_ShadowMap2D    ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMap2D    , R_GetTexture(r_shadow_shadowmap2dtexture                         ));CHECKCGERROR
+                       if (r_cg_permutation->fp_Texture_CubeProjection ) CG_BindTexture(r_cg_permutation->fp_Texture_CubeProjection , R_GetTexture(r_shadow_shadowmapvsdcttexture                      ));CHECKCGERROR
+               }
+
+               CHECKGLERROR
+#endif
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               break;
        }
-       if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4fARB(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
-       if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
-       if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
-       if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
-       if(permutation & SHADERPERMUTATION_EXACTSPECULARMATH)
+}
+
+void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
+{
+       // select a permutation of the lighting shader appropriate to this
+       // combination of texture, entity, light source, and fogging, only use the
+       // minimum features necessary to avoid wasting rendering time in the
+       // fragment shader on features that are not being used
+       unsigned int permutation = 0;
+       unsigned int mode = 0;
+       const float *lightcolorbase = rtlight->currentcolor;
+       float ambientscale = rtlight->ambientscale;
+       float diffusescale = rtlight->diffusescale;
+       float specularscale = rtlight->specularscale;
+       // this is the location of the light in view space
+       vec3_t viewlightorigin;
+       // this transforms from view space (camera) to light space (cubemap)
+       matrix4x4_t viewtolight;
+       matrix4x4_t lighttoview;
+       float viewtolight16f[16];
+       float range = 1.0f / r_shadow_deferred_8bitrange.value;
+       // light source
+       mode = SHADERMODE_DEFERREDLIGHTSOURCE;
+       if (rtlight->currentcubemap != r_texture_whitecube)
+               permutation |= SHADERPERMUTATION_CUBEFILTER;
+       if (diffusescale > 0)
+               permutation |= SHADERPERMUTATION_DIFFUSE;
+       if (specularscale > 0)
        {
-               if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * 0.25);
+               permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
+               if (r_shadow_glossexact.integer)
+                       permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
        }
-       else
+       if (r_shadow_usingshadowmaprect || r_shadow_usingshadowmap2d || r_shadow_usingshadowmapcube)
+       {
+               if (r_shadow_usingshadowmaprect)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
+               if (r_shadow_usingshadowmap2d)
+                       permutation |= SHADERPERMUTATION_SHADOWMAP2D;
+               if (r_shadow_usingshadowmapcube)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPCUBE;
+               else if(r_shadow_shadowmapvsdct)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
+
+               if (r_shadow_shadowmapsampler)
+                       permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
+               if (r_shadow_shadowmappcf > 1)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
+               else if (r_shadow_shadowmappcf)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+       }
+       Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
+       Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
+       Matrix4x4_Invert_Simple(&viewtolight, &lighttoview);
+       Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
+       switch(vid.renderpath)
        {
-               if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower);
+       case RENDERPATH_GL20:
+               R_SetupShader_SetPermutationGLSL(mode, permutation);
+               if (r_glsl_permutation->loc_ModelViewMatrix           >= 0) qglUniformMatrix4fvARB(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
+               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_Texture_Attenuation       >= 0) R_Mesh_TexBind(GL20TU_ATTENUATION       ,          R_GetTexture(r_shadow_attenuationgradienttexture                 ));
+               if (r_glsl_permutation->loc_Texture_ScreenDepth       >= 0) R_Mesh_TexBindAll(GL20TU_SCREENDEPTH    , 0, 0, 0, R_GetTexture(r_shadow_prepassgeometrydepthtexture                ));
+               if (r_glsl_permutation->loc_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBindAll(GL20TU_SCREENNORMALMAP, 0, 0, 0, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture            ));
+               if (r_glsl_permutation->loc_Texture_Cube              >= 0) R_Mesh_TexBindAll(GL20TU_CUBE           , 0, 0,    R_GetTexture(rsurface.rtlight->currentcubemap                    ), 0);
+               if (r_glsl_permutation->loc_Texture_ShadowMapRect     >= 0) R_Mesh_TexBindAll(GL20TU_SHADOWMAPRECT  , 0, 0, 0, R_GetTexture(r_shadow_shadowmaprectangletexture                  ));
+               if (r_shadow_usingshadowmapcube)
+                       if (r_glsl_permutation->loc_Texture_ShadowMapCube     >= 0) R_Mesh_TexBindAll(GL20TU_SHADOWMAPCUBE  , 0, 0,    R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);
+               if (r_glsl_permutation->loc_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(GL20TU_SHADOWMAP2D       ,          R_GetTexture(r_shadow_shadowmap2dtexture                         ));
+               if (r_glsl_permutation->loc_Texture_CubeProjection    >= 0) R_Mesh_TexBindAll(GL20TU_CUBEPROJECTION , 0, 0,    R_GetTexture(r_shadow_shadowmapvsdcttexture                      ), 0);
+               break;
+       case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+               R_SetupShader_SetPermutationCG(mode, permutation);
+               if (r_cg_permutation->vp_ModelViewMatrix          ) cgGLSetMatrixParameterfc(r_cg_permutation->vp_ModelViewMatrix, gl_modelviewprojection16f);CHECKCGERROR
+               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_Texture_Attenuation      ) CG_BindTexture(r_cg_permutation->fp_Texture_Attenuation    , R_GetTexture(r_shadow_attenuationgradienttexture                 ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ScreenDepth      ) CG_BindTexture(r_cg_permutation->fp_Texture_ScreenDepth    , R_GetTexture(r_shadow_prepassgeometrydepthtexture                ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ScreenNormalMap  ) CG_BindTexture(r_cg_permutation->fp_Texture_ScreenNormalMap, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture            ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Cube             ) CG_BindTexture(r_cg_permutation->fp_Texture_Cube           , R_GetTexture(rsurface.rtlight->currentcubemap                    ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ShadowMapRect    ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMapRect  , R_GetTexture(r_shadow_shadowmaprectangletexture                  ));CHECKCGERROR
+               if (r_shadow_usingshadowmapcube)
+                       if (r_cg_permutation->fp_Texture_ShadowMapCube    ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMapCube  , R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ShadowMap2D      ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMap2D    , R_GetTexture(r_shadow_shadowmap2dtexture                         ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_CubeProjection   ) CG_BindTexture(r_cg_permutation->fp_Texture_CubeProjection , R_GetTexture(r_shadow_shadowmapvsdcttexture                      ));CHECKCGERROR
+#endif
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               break;
        }
-       if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
-       CHECKGLERROR
 }
 
 #define SKINFRAME_HASH 1024
@@ -2871,7 +3888,7 @@ 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;
@@ -2942,11 +3959,23 @@ void R_Main_ResizeViewCache(void)
        }
 }
 
+extern rtexture_t *loadingscreentexture;
 void gl_main_start(void)
 {
+       loadingscreentexture = NULL;
+       r_texture_blanknormalmap = NULL;
+       r_texture_white = NULL;
+       r_texture_grey128 = NULL;
+       r_texture_black = NULL;
+       r_texture_whitecube = NULL;
+       r_texture_normalizationcube = NULL;
+       r_texture_fogattenuation = NULL;
+       r_texture_gammaramps = NULL;
+
        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);
@@ -3002,12 +4031,15 @@ 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);
+#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);
+#endif
        memset(&r_svbsp, 0, sizeof (r_svbsp));
 
        r_refdef.fogmasktable_density = 0;
 }
 
-extern rtexture_t *loadingscreentexture;
 void gl_main_shutdown(void)
 {
        R_AnimCache_Free();
@@ -3151,6 +4183,7 @@ 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_textureunits);
        Cvar_RegisterVariable(&gl_combine);
        Cvar_RegisterVariable(&r_glsl);
@@ -3212,12 +4245,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();
@@ -3384,7 +4419,7 @@ void R_FrameData_NewFrame(void)
 {
        size_t wantedsize;
        if (r_framedata_failed)
-               Cvar_SetValueQuick(&r_framedatasize, r_framedatasize.value * 1.25f);
+               Cvar_SetValueQuick(&r_framedatasize, r_framedatasize.value + 1.0f);
        wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
        wantedsize = bound(65536, wantedsize, 128*1024*1024);
        if (r_framedata_size != wantedsize)
@@ -3428,36 +4463,15 @@ void *R_FrameData_Store(size_t size, void *data)
 
 //==================================================================================
 
-// LordHavoc: animcache written by Echon, refactored and reformatted by me
+// LordHavoc: animcache originally written by Echon, rewritten since then
 
 /**
- * Animation cache helps save re-animating a player mesh if it's re-rendered again in a given frame
- * (reflections, lighting, etc). All animation cache becomes invalid on the next frame and is flushed
- * (well, over-wrote). The memory for each cache is kept around to save on allocation thrashing.
- */
-
-typedef struct r_animcache_entity_s
-{
-       float *vertex3f;
-       float *normal3f;
-       float *svector3f;
-       float *tvector3f;
-}
-r_animcache_entity_t;
-
-typedef struct r_animcache_s
-{
-       r_animcache_entity_t entity[MAX_EDICTS];
-       int maxindex;
-       int currentindex;
-}
-r_animcache_t;
-
-static r_animcache_t r_animcachestate;
+ * Animation cache prevents re-generating mesh data for an animated model
+ * multiple times in one frame for lighting, shadowing, reflections, etc.
+ */
 
 void R_AnimCache_Free(void)
 {
-       memset(&r_animcachestate, 0, sizeof(r_animcachestate));
 }
 
 void R_AnimCache_ClearCache(void)
@@ -3465,69 +4479,62 @@ void R_AnimCache_ClearCache(void)
        int i;
        entity_render_t *ent;
 
-       r_animcachestate.maxindex = sizeof(r_animcachestate.entity) / sizeof(r_animcachestate.entity[0]);
-       r_animcachestate.currentindex = 0;
-
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
                ent = r_refdef.scene.entities[i];
-               ent->animcacheindex = -1;
+               ent->animcache_vertex3f = NULL;
+               ent->animcache_normal3f = NULL;
+               ent->animcache_svector3f = NULL;
+               ent->animcache_tvector3f = NULL;
        }
 }
 
 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
 {
        dp_model_t *model = ent->model;
-       r_animcache_entity_t *c;
        int numvertices;
        // see if it's already cached this frame
-       if (ent->animcacheindex >= 0)
+       if (ent->animcache_vertex3f)
        {
                // add normals/tangents if needed
                if (wantnormals || wanttangents)
                {
-                       c = r_animcachestate.entity + ent->animcacheindex;
-                       if (c->normal3f)
+                       if (ent->animcache_normal3f)
                                wantnormals = false;
-                       if (c->svector3f)
+                       if (ent->animcache_svector3f)
                                wanttangents = false;
                        if (wantnormals || wanttangents)
                        {
                                numvertices = model->surfmesh.num_vertices;
                                if (wantnormals)
-                                       c->normal3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+                                       ent->animcache_normal3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
                                if (wanttangents)
                                {
-                                       c->svector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
-                                       c->tvector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+                                       ent->animcache_svector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+                                       ent->animcache_tvector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
                                }
                                if (!r_framedata_failed)
-                                       model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL);
+                                       model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
                        }
                }
        }
        else
        {
                // see if this ent is worth caching
-               if (r_animcachestate.maxindex <= r_animcachestate.currentindex)
-                       return false;
                if (!model || !model->Draw || !model->surfmesh.isanimated || !model->AnimateVertices || (ent->frameblend[0].lerp == 1 && ent->frameblend[0].subframe == 0 && !ent->skeleton))
                        return false;
-               // assign it a cache entry and get some temp memory
-               ent->animcacheindex = r_animcachestate.currentindex++;
-               c = r_animcachestate.entity + ent->animcacheindex;
+               // get some memory for this entity and generate mesh data
                numvertices = model->surfmesh.num_vertices;
-               memset(c, 0, sizeof(*c));
-               c->vertex3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+               ent->animcache_vertex3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
                if (wantnormals)
-                       c->normal3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+                       ent->animcache_normal3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
                if (wanttangents)
                {
-                       c->svector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
-                       c->tvector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+                       ent->animcache_svector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+                       ent->animcache_tvector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
                }
                if (!r_framedata_failed)
-                       model->AnimateVertices(model, ent->frameblend, ent->skeleton, c->vertex3f, c->normal3f, c->svector3f, c->tvector3f);
+                       model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
        }
        return !r_framedata_failed;
 }
@@ -3535,13 +4542,13 @@ qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qbool
 void R_AnimCache_CacheVisibleEntities(void)
 {
        int i;
-       entity_render_t *ent;
        qboolean wantnormals = !r_showsurfaces.integer;
        qboolean wanttangents = !r_showsurfaces.integer;
 
        switch(vid.renderpath)
        {
        case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
                break;
        case RENDERPATH_GL13:
        case RENDERPATH_GL11:
@@ -3550,16 +4557,16 @@ void R_AnimCache_CacheVisibleEntities(void)
        }
 
        // TODO: thread this
+       // NOTE: R_PrepareRTLights() also caches entities
 
        for (i = 0;i < r_refdef.scene.numentities;i++)
-       {
-               if (!r_refdef.viewcache.entityvisible[i])
-                       continue;
-               ent = r_refdef.scene.entities[i];
-               if (ent->animcacheindex >= 0)
-                       continue;
-               R_AnimCache_GetEntity(ent, wantnormals, wanttangents);
-       }
+               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);
 }
 
 //==================================================================================
@@ -3590,7 +4597,7 @@ static void R_View_UpdateEntityLighting (void)
                }
 
                // fetch the lighting from the worldmodel data
-               VectorSet(ent->modellight_ambient, r_refdef.scene.ambient * (2.0f / 128.0f), r_refdef.scene.ambient * (2.0f / 128.0f), r_refdef.scene.ambient * (2.0f / 128.0f));
+               VectorClear(ent->modellight_ambient);
                VectorClear(ent->modellight_diffuse);
                VectorClear(tempdiffusenormal);
                if ((ent->flags & RENDER_LIGHT) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
@@ -3697,9 +4704,6 @@ static void R_View_UpdateEntityVisible (void)
        int samples;
        entity_render_t *ent;
 
-       if (!r_drawentities.integer)
-               return;
-
        renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : ((chase_active.integer || r_waterstate.renderingscene) ? RENDER_VIEWMODEL : RENDER_EXTERIORMODEL);
        if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
        {
@@ -3748,9 +4752,6 @@ int R_DrawBrushModelsSky (void)
        int i, sky;
        entity_render_t *ent;
 
-       if (!r_drawentities.integer)
-               return false;
-
        sky = false;
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
@@ -3771,9 +4772,6 @@ static void R_DrawModels(void)
        int i;
        entity_render_t *ent;
 
-       if (!r_drawentities.integer)
-               return;
-
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
                if (!r_refdef.viewcache.entityvisible[i])
@@ -3792,9 +4790,6 @@ static void R_DrawModelsDepth(void)
        int i;
        entity_render_t *ent;
 
-       if (!r_drawentities.integer)
-               return;
-
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
                if (!r_refdef.viewcache.entityvisible[i])
@@ -3810,9 +4805,6 @@ static void R_DrawModelsDebug(void)
        int i;
        entity_render_t *ent;
 
-       if (!r_drawentities.integer)
-               return;
-
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
                if (!r_refdef.viewcache.entityvisible[i])
@@ -3828,9 +4820,6 @@ static void R_DrawModelsAddWaterPlanes(void)
        int i;
        entity_render_t *ent;
 
-       if (!r_drawentities.integer)
-               return;
-
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
                if (!r_refdef.viewcache.entityvisible[i])
@@ -4007,8 +4996,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
@@ -4032,6 +5021,37 @@ 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);
+                       qglLoadMatrixf(gl_modelview16f);CHECKGLERROR
+                       break;
+               case RENDERPATH_CGGL:
+#ifdef SUPPORTCG
+                       if (r_cg_permutation && r_cg_permutation->vp_ModelViewProjectionMatrix) cgGLSetMatrixParameterfc(r_cg_permutation->vp_ModelViewProjectionMatrix, gl_modelviewprojection16f);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;
@@ -4049,7 +5069,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
@@ -4059,7 +5079,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)
@@ -4076,7 +5095,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
@@ -4086,7 +5105,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);
@@ -4104,6 +5122,7 @@ static void R_Water_StartFrame(void)
        switch(vid.renderpath)
        {
        case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
                break;
        case RENDERPATH_GL13:
        case RENDERPATH_GL11:
@@ -4248,7 +5267,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_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
                        if (!p->texture_refraction)
                                goto error;
                }
@@ -4256,7 +5275,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_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
                        if (!p->texture_reflection)
                                goto error;
                }
@@ -4287,11 +5306,7 @@ static void R_Water_ProcessPlanes(void)
                        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
+                       R_Mesh_CopyToTexture(R_GetTexture(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);
                }
 
                if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
@@ -4319,10 +5334,7 @@ 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(R_GetTexture(p->texture_reflection), 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
                }
        }
        r_waterstate.renderingscene = false;
@@ -4346,6 +5358,7 @@ void R_Bloom_StartFrame(void)
        switch(vid.renderpath)
        {
        case RENDERPATH_GL20:
+       case RENDERPATH_CGGL:
                break;
        case RENDERPATH_GL13:
        case RENDERPATH_GL11:
@@ -4398,7 +5411,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_BGRA, TEXF_FORCENEAREST | TEXF_CLAMP, NULL);
        }
        if (r_bloomstate.bloomtexturewidth != bloomtexturewidth || r_bloomstate.bloomtextureheight != bloomtextureheight)
        {
@@ -4408,7 +5421,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_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
        }
 
        // when doing a reduced render (HDR) we want to use a smaller area
@@ -4459,27 +5472,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_GetTexture(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_GetTexture(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;
 }
 
@@ -4493,7 +5499,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
@@ -4505,7 +5510,7 @@ 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;
@@ -4524,7 +5529,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++)
@@ -4574,7 +5579,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);
@@ -4582,7 +5587,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);
@@ -4590,10 +5595,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_GetTexture(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;
        }
 }
@@ -4644,6 +5646,7 @@ void R_HDR_RenderBloomTexture(void)
        r_refdef.view.width = oldwidth;
        r_refdef.view.height = oldheight;
        r_refdef.view.colorscale = oldcolorscale;
+       r_frame++; // used only by R_GetCurrentTexture
 
        R_ResetViewRendering3D();
 
@@ -4655,10 +5658,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)
@@ -4674,8 +5679,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))
                        {
@@ -4708,10 +5711,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;
@@ -4719,11 +5721,25 @@ 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_GetTexture(r_bloomstate.texture_screen), 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
                        r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
                }
                else if (!r_bloomstate.texture_bloom)
+               {
+                       // we may still have to do view tint...
+                       if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
+                       {
+                               // apply a color tint to the whole view
+                               R_ResetViewRendering2D();
+                               R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
+                               R_Mesh_ColorPointer(NULL, 0, 0);
+                               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+                               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+                               GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
+                               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
+                       }
                        break; // no screen processing, no bloom, skip it
+               }
 
                if (r_bloomstate.texture_bloom && !r_bloomstate.hdr)
                {
@@ -4734,53 +5750,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_TintColor >= 0)
-                       qglUniform4fARB(r_glsl_permutation->loc_TintColor, r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
-               if (r_glsl_permutation->loc_ClientTime >= 0)
-                       qglUniform1fARB(r_glsl_permutation->loc_ClientTime, cl.time);
-               if (r_glsl_permutation->loc_PixelSize >= 0)
-                       qglUniform2fARB(r_glsl_permutation->loc_PixelSize, 1.0/r_bloomstate.screentexturewidth, 1.0/r_bloomstate.screentextureheight);
-               if (r_glsl_permutation->loc_UserVec1 >= 0)
-               {
-                       float a=0, b=0, c=0, d=0;
-#if _MSC_VER >= 1400
-#define sscanf sscanf_s
-#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_GetTexture(r_bloomstate.texture_screen));
+                       if (r_glsl_permutation->loc_Texture_Second     >= 0) R_Mesh_TexBind(GL20TU_SECOND    , R_GetTexture(r_bloomstate.texture_bloom ));
+                       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) 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);
+                       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_GetTexture(r_bloomstate.texture_screen));CHECKCGERROR
+                       if (r_cg_permutation->fp_Texture_Second    ) CG_BindTexture(r_cg_permutation->fp_Texture_Second    , R_GetTexture(r_bloomstate.texture_bloom ));CHECKCGERROR
+                       if (r_cg_permutation->fp_Texture_GammaRamps) CG_BindTexture(r_cg_permutation->fp_Texture_GammaRamps, R_GetTexture(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_ClientTime        ) cgGLSetParameter1f(     r_cg_permutation->fp_ClientTime        , cl.time);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
+#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;
@@ -4792,7 +5813,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);
@@ -4832,7 +5853,7 @@ void R_UpdateVariables(void)
 {
        R_Textures_Frame();
 
-       r_refdef.scene.ambient = r_ambient.value;
+       r_refdef.scene.ambient = r_ambient.value * (1.0f / 64.0f);
 
        r_refdef.farclip = r_farclip_base.value;
        if (r_refdef.scene.worldmodel)
@@ -4920,6 +5941,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)
@@ -4946,7 +5968,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);
                                }
                        }
                }
@@ -5005,6 +6027,9 @@ void R_RenderView(void)
        r_frame++; // used only by R_GetCurrentTexture
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 
+       if (!r_drawentities.integer)
+               r_refdef.scene.numentities = 0;
+
        R_AnimCache_ClearCache();
        R_FrameData_NewFrame();
 
@@ -5116,6 +6141,7 @@ static void R_DrawLocs(void);
 static void R_DrawEntityBBoxes(void);
 static void R_DrawModelDecals(void);
 extern cvar_t cl_decals_newsystem;
+extern qboolean r_shadow_usingdeferredprepass;
 void R_RenderScene(void)
 {
        r_refdef.stats.renders++;
@@ -5154,11 +6180,21 @@ void R_RenderScene(void)
                        R_SetupView(false);
                        R_Sky();
                        R_SetupView(true);
+                       if (r_timereport_active)
+                               R_TimeReport("sky");
                }
        }
 
        R_AnimCache_CacheVisibleEntities();
-       R_PrepareRTLights();
+       if (r_timereport_active)
+               R_TimeReport("animation");
+
+       R_Shadow_PrepareLights();
+       if (r_timereport_active)
+               R_TimeReport("preparelights");
+
+       if (r_shadow_usingdeferredprepass)
+               R_Shadow_DrawPrepass();
 
        if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
        {
@@ -5201,9 +6237,12 @@ void R_RenderScene(void)
                        S_ExtraUpdate ();
        }
 
-       R_ShadowVolumeLighting(false);
-       if (r_timereport_active)
-               R_TimeReport("rtlights");
+       if (!r_shadow_usingdeferredprepass)
+       {
+               R_Shadow_DrawLights();
+               if (r_timereport_active)
+                       R_TimeReport("rtlights");
+       }
 
        // don't let sound skip if going slow
        if (r_refdef.scene.extraupdate)
@@ -5246,7 +6285,6 @@ void R_RenderScene(void)
                        R_TimeReport("lightning");
        }
 
-       R_SetupGenericShader(true);
        VM_CL_AddPolygonsToMeshQueue();
 
        if (r_refdef.view.showdebug)
@@ -5273,13 +6311,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);
@@ -5290,11 +6325,9 @@ void R_RenderScene(void)
                        R_TimeReport("modeldebug");
        }
 
-       R_SetupGenericShader(true);
-
        if (cl.csqc_vidvars.drawworld)
        {
-               R_DrawCoronas();
+               R_Shadow_DrawCoronas();
                if (r_timereport_active)
                        R_TimeReport("coronas");
        }
@@ -5352,7 +6385,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);
 }
 
@@ -5368,7 +6401,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();
@@ -5484,7 +6517,7 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight
                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
                GL_DepthMask(false);
        }
-       else if (rsurface.ent_color[3] < 1)
+       else if (rsurface.colormod[3] < 1)
        {
                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                GL_DepthMask(false);
@@ -5498,16 +6531,16 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight
        GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
        GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
        GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
-       R_SetupGenericShader(false);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
        R_Mesh_VertexPointer(rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
        memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
        R_Mesh_ColorPointer(color4f, 0, 0);
        for (i = 0, c = color4f;i < 6;i++, c += 4)
        {
-               c[0] *= rsurface.ent_color[0];
-               c[1] *= rsurface.ent_color[1];
-               c[2] *= rsurface.ent_color[2];
-               c[3] *= rsurface.ent_color[3];
+               c[0] *= rsurface.colormod[0];
+               c[1] *= rsurface.colormod[1];
+               c[2] *= rsurface.colormod[2];
+               c[3] *= rsurface.colormod[3];
        }
        if (r_refdef.fogenabled)
        {
@@ -5688,9 +6721,9 @@ static void R_Texture_AddLayer(texture_t *t, qboolean depthmask, int blendfunc1,
        layer->blendfunc2 = blendfunc2;
        layer->texture = texture;
        layer->texmatrix = *matrix;
-       layer->color[0] = r * r_refdef.view.colorscale;
-       layer->color[1] = g * r_refdef.view.colorscale;
-       layer->color[2] = b * r_refdef.view.colorscale;
+       layer->color[0] = r;
+       layer->color[1] = g;
+       layer->color[2] = b;
        layer->color[3] = a;
 }
 
@@ -5788,7 +6821,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];
@@ -5875,7 +6908,7 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                t->backgroundcurrentskinframe = t->backgroundskinframes[(int)(t->backgroundskinframerate * (cl.time - rsurface.ent_shadertime)) % t->backgroundnumskinframes];
 
        t->currentmaterialflags = t->basematerialflags;
-       t->currentalpha = rsurface.ent_color[3];
+       t->currentalpha = rsurface.colormod[3];
        if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer))
                t->currentalpha *= r_wateralpha.value;
        if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_waterstate.enabled && !r_refdef.view.isoverlay)
@@ -5884,7 +6917,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))
@@ -5909,6 +6942,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)
@@ -5931,9 +6966,26 @@ 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;
+       t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
+       t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
+       t->nmaptexture = t->currentskinframe->nmap;
        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;
+       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;
+       }
+       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;
@@ -5965,17 +7017,25 @@ 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->backgroundbasetexture = NULL;
+               t->backgroundnmaptexture = r_texture_blanknormalmap;
+               t->backgroundglosstexture = r_texture_black;
+               t->backgroundglowtexture = NULL;
                t->specularscale = 0;
                t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_MODELLIGHT_DIRECTIONAL | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
        }
 
-       Vector4Set(t->lightmapcolor, rsurface.ent_color[0], rsurface.ent_color[1], rsurface.ent_color[2], t->currentalpha);
+       Vector4Set(t->lightmapcolor, rsurface.colormod[0], rsurface.colormod[1], rsurface.colormod[2], t->currentalpha);
        VectorClear(t->dlightcolor);
        t->currentnumlayers = 0;
        if (t->currentmaterialflags & MATERIALFLAG_WALL)
        {
-               int layerflags = 0;
                int blendfunc1, blendfunc2;
                qboolean depthmask;
                if (t->currentmaterialflags & MATERIALFLAG_ADD)
@@ -5999,23 +7059,21 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                        blendfunc2 = GL_ZERO;
                }
                depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
-               if (r_refdef.fogenabled && (t->currentmaterialflags & MATERIALFLAG_BLENDED))
-                       layerflags |= TEXTURELAYERFLAG_FOGDARKEN;
                if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
                {
                        // fullbright is not affected by r_refdef.lightmapintensity
                        R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, t->lightmapcolor[0], t->lightmapcolor[1], t->lightmapcolor[2], t->lightmapcolor[3]);
-                       if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * t->lightmapcolor[0], rsurface.colormap_pantscolor[1] * t->lightmapcolor[1], rsurface.colormap_pantscolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
-                       if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * t->lightmapcolor[0], rsurface.colormap_shirtcolor[1] * t->lightmapcolor[1], rsurface.colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
+                       if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->pantstexture)
+                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->pantstexture, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * t->lightmapcolor[0], rsurface.colormap_pantscolor[1] * t->lightmapcolor[1], rsurface.colormap_pantscolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
+                       if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->shirttexture)
+                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->shirttexture, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * t->lightmapcolor[0], rsurface.colormap_shirtcolor[1] * t->lightmapcolor[1], rsurface.colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
                }
                else
                {
                        vec3_t ambientcolor;
                        float colorscale;
                        // set the color tint used for lights affecting this surface
-                       VectorSet(t->dlightcolor, rsurface.ent_color[0] * t->lightmapcolor[3], rsurface.ent_color[1] * t->lightmapcolor[3], rsurface.ent_color[2] * t->lightmapcolor[3]);
+                       VectorSet(t->dlightcolor, t->lightmapcolor[0] * t->lightmapcolor[3], t->lightmapcolor[1] * t->lightmapcolor[3], t->lightmapcolor[2] * t->lightmapcolor[3]);
                        colorscale = 2;
                        // q3bsp has no lightmap updates, so the lightstylevalue that
                        // would normally be baked into the lightmap must be
@@ -6024,27 +7082,27 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                        if (model->type == mod_brushq3)
                                colorscale *= r_refdef.scene.rtlightstylevalue[0];
                        colorscale *= r_refdef.lightmapintensity;
-                       VectorScale(t->lightmapcolor, r_refdef.scene.ambient * (1.0f / 64.0f), ambientcolor);
+                       VectorScale(t->lightmapcolor, r_refdef.scene.ambient, ambientcolor);
                        VectorScale(t->lightmapcolor, colorscale, t->lightmapcolor);
                        // basic lit geometry
                        R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, t->lightmapcolor[0], t->lightmapcolor[1], t->lightmapcolor[2], t->lightmapcolor[3]);
                        // add pants/shirt if needed
-                       if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * t->lightmapcolor[0], rsurface.colormap_pantscolor[1] * t->lightmapcolor[1], rsurface.colormap_pantscolor[2]  * t->lightmapcolor[2], t->lightmapcolor[3]);
-                       if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
-                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * t->lightmapcolor[0], rsurface.colormap_shirtcolor[1] * t->lightmapcolor[1], rsurface.colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
+                       if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->pantstexture)
+                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->pantstexture, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * t->lightmapcolor[0], rsurface.colormap_pantscolor[1] * t->lightmapcolor[1], rsurface.colormap_pantscolor[2]  * t->lightmapcolor[2], t->lightmapcolor[3]);
+                       if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->shirttexture)
+                               R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->shirttexture, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * t->lightmapcolor[0], rsurface.colormap_shirtcolor[1] * t->lightmapcolor[1], rsurface.colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
                        // now add ambient passes if needed
                        if (VectorLength2(ambientcolor) >= (1.0f/1048576.0f))
                        {
                                R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, ambientcolor[0], ambientcolor[1], ambientcolor[2], t->lightmapcolor[3]);
-                               if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
-                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * ambientcolor[0], rsurface.colormap_pantscolor[1] * ambientcolor[1], rsurface.colormap_pantscolor[2] * ambientcolor[2], t->lightmapcolor[3]);
-                               if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
-                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * ambientcolor[0], rsurface.colormap_shirtcolor[1] * ambientcolor[1], rsurface.colormap_shirtcolor[2] * ambientcolor[2], t->lightmapcolor[3]);
+                               if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->pantstexture)
+                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->pantstexture, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * ambientcolor[0], rsurface.colormap_pantscolor[1] * ambientcolor[1], rsurface.colormap_pantscolor[2] * ambientcolor[2], t->lightmapcolor[3]);
+                               if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->shirttexture)
+                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->shirttexture, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * ambientcolor[0], rsurface.colormap_shirtcolor[1] * ambientcolor[1], rsurface.colormap_shirtcolor[2] * ambientcolor[2], t->lightmapcolor[3]);
                        }
                }
-               if (t->currentskinframe->glow != NULL && !gl_lightmaps.integer)
-                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->glow, &t->currenttexmatrix, r_hdr_glowintensity.value, r_hdr_glowintensity.value, r_hdr_glowintensity.value, t->lightmapcolor[3]);
+               if (t->glowtexture != NULL && !gl_lightmaps.integer)
+                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->glowtexture, &t->currenttexmatrix, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2], t->lightmapcolor[3]);
                if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
                {
                        // if this is opaque use alpha blend which will darken the earlier
@@ -6058,7 +7116,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]);
                }
        }
 
@@ -6099,7 +7157,6 @@ void RSurf_ActiveWorldEntity(void)
        rsurface.ent_skinnum = 0;
        rsurface.ent_qwskin = -1;
        rsurface.ent_shadertime = 0;
-       Vector4Set(rsurface.ent_color, 1, 1, 1, 1);
        rsurface.ent_flags = r_refdef.scene.worldentity->flags;
        if (rsurface.array_size < model->surfmesh.num_vertices)
                R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
@@ -6107,7 +7164,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;
@@ -6119,7 +7176,9 @@ void RSurf_ActiveWorldEntity(void)
        VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
        VectorSet(rsurface.colormap_pantscolor, 0, 0, 0);
        VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0);
-       VectorSet(rsurface.glowmod, 1, 1, 1);
+       VectorSet(rsurface.colormod, r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale);
+       rsurface.colormod[3] = 1;
+       VectorSet(rsurface.glowmod, r_refdef.view.colorscale * r_hdr_glowintensity.value, r_refdef.view.colorscale * r_hdr_glowintensity.value, r_refdef.view.colorscale * r_hdr_glowintensity.value);
        memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
        rsurface.frameblend[0].lerp = 1;
        rsurface.ent_alttextures = false;
@@ -6170,7 +7229,7 @@ void RSurf_ActiveWorldEntity(void)
        rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
 }
 
-void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
+void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
 {
        dp_model_t *model = ent->model;
        //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
@@ -6180,7 +7239,6 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        rsurface.ent_skinnum = ent->skinnum;
        rsurface.ent_qwskin = (ent->entitynumber <= cl.maxclients && ent->entitynumber >= 1 && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[ent->entitynumber - 1].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl")) ? (ent->entitynumber - 1) : -1;
        rsurface.ent_shadertime = ent->shadertime;
-       Vector4Set(rsurface.ent_color, ent->colormod[0], ent->colormod[1], ent->colormod[2], ent->alpha);
        rsurface.ent_flags = ent->flags;
        if (rsurface.array_size < model->surfmesh.num_vertices)
                R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
@@ -6188,7 +7246,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;
@@ -6200,24 +7258,26 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        VectorCopy(ent->modellight_lightdir, rsurface.modellight_lightdir);
        VectorCopy(ent->colormap_pantscolor, rsurface.colormap_pantscolor);
        VectorCopy(ent->colormap_shirtcolor, rsurface.colormap_shirtcolor);
-       VectorCopy(ent->glowmod, rsurface.glowmod);
+       VectorScale(ent->colormod, r_refdef.view.colorscale, rsurface.colormod);
+       rsurface.colormod[3] = ent->alpha;
+       VectorScale(ent->glowmod, r_refdef.view.colorscale * r_hdr_glowintensity.value, rsurface.glowmod);
        memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
        rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
        rsurface.basepolygonfactor = r_refdef.polygonfactor;
        rsurface.basepolygonoffset = r_refdef.polygonoffset;
-       if (ent->model->brush.submodel)
+       if (ent->model->brush.submodel && !prepass)
        {
                rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
                rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
        }
        if (model->surfmesh.isanimated && model->AnimateVertices && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].subframe != 0))
        {
-               if (R_AnimCache_GetEntity((entity_render_t *)ent, wantnormals, wanttangents))
+               if (ent->animcache_vertex3f && !r_framedata_failed)
                {
-                       rsurface.modelvertex3f = r_animcachestate.entity[ent->animcacheindex].vertex3f;
-                       rsurface.modelsvector3f = wanttangents ? r_animcachestate.entity[ent->animcacheindex].svector3f : NULL;
-                       rsurface.modeltvector3f = wanttangents ? r_animcachestate.entity[ent->animcacheindex].tvector3f : NULL;
-                       rsurface.modelnormal3f = wantnormals ? r_animcachestate.entity[ent->animcacheindex].normal3f : NULL;
+                       rsurface.modelvertex3f = ent->animcache_vertex3f;
+                       rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
+                       rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
+                       rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
                }
                else if (wanttangents)
                {
@@ -6308,7 +7368,6 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve
        rsurface.ent_skinnum = 0;
        rsurface.ent_qwskin = -1;
        rsurface.ent_shadertime = shadertime;
-       Vector4Set(rsurface.ent_color, r, g, b, a);
        rsurface.ent_flags = entflags;
        rsurface.modelnum_vertices = numvertices;
        rsurface.modelnum_triangles = numtriangles;
@@ -6318,7 +7377,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;
@@ -6330,7 +7389,8 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve
        VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
        VectorSet(rsurface.colormap_pantscolor, 0, 0, 0);
        VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0);
-       VectorSet(rsurface.glowmod, 1, 1, 1);
+       Vector4Set(rsurface.colormod, r * r_refdef.view.colorscale, g * r_refdef.view.colorscale, b * r_refdef.view.colorscale, a);
+       VectorSet(rsurface.glowmod, r_refdef.view.colorscale * r_hdr_glowintensity.value, r_refdef.view.colorscale * r_hdr_glowintensity.value, r_refdef.view.colorscale * r_hdr_glowintensity.value);
        memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
        rsurface.frameblend[0].lerp = 1;
        rsurface.ent_alttextures = false;
@@ -6892,7 +7952,7 @@ void RSurf_DrawBatch_Simple(int texturenumsurfaces, const msurface_t **texturesu
        {
                #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];
@@ -6947,60 +8007,86 @@ void RSurf_DrawBatch_Simple(int texturenumsurfaces, const msurface_t **texturesu
        }
 }
 
-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 , R_GetTexture(surface->lightmaptexture ));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Deluxemap) CG_BindTexture(r_cg_permutation->fp_Texture_Deluxemap, R_GetTexture(surface->deluxemaptexture));CHECKCGERROR
+#endif
+               break;
+       case RENDERPATH_GL20:
+               if (r_glsl_permutation->loc_Texture_Lightmap  >= 0) R_Mesh_TexBind(GL20TU_LIGHTMAP , R_GetTexture(surface->lightmaptexture ));
+               if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) R_Mesh_TexBind(GL20TU_DELUXEMAP, R_GetTexture(surface->deluxemaptexture));
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               R_Mesh_TexBind(0, R_GetTexture(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 ? R_GetTexture(bestp->texture_refraction) : R_GetTexture(r_texture_black));CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Reflection) CG_BindTexture(r_cg_permutation->fp_Texture_Reflection, bestp ? R_GetTexture(bestp->texture_reflection) : R_GetTexture(r_texture_black));CHECKCGERROR
+#endif
+               break;
+       case RENDERPATH_GL20:
+               if (r_glsl_permutation->loc_Texture_Refraction >= 0) R_Mesh_TexBind(GL20TU_REFRACTION, bestp ? R_GetTexture(bestp->texture_refraction) : R_GetTexture(r_texture_black));
+               if (r_glsl_permutation->loc_Texture_Reflection >= 0) R_Mesh_TexBind(GL20TU_REFLECTION, bestp ? R_GetTexture(bestp->texture_reflection) : R_GetTexture(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));
-               }
+               RSurf_BindLightmapForSurface(surface);
+               RSurf_BindReflectionForSurface(surface);
                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(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;
@@ -7010,26 +8096,21 @@ 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));
+               RSurf_BindLightmapForSurface(surface);
                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
+#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)
                        {
@@ -7073,9 +8154,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;
@@ -7097,9 +8176,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));
+                       RSurf_BindLightmapForSurface(surface);
                        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);
                }
@@ -7267,9 +8344,9 @@ static void RSurf_DrawBatch_GL11_ApplyAmbient(int texturenumsurfaces, const msur
                const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
                for (i = 0, c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4)
                {
-                       c2[0] = c[0] + r_refdef.scene.ambient / 128.0;
-                       c2[1] = c[1] + r_refdef.scene.ambient / 128.0;
-                       c2[2] = c[2] + r_refdef.scene.ambient / 128.0;
+                       c2[0] = c[0] + r_refdef.scene.ambient;
+                       c2[1] = c[1] + r_refdef.scene.ambient;
+                       c2[2] = c[2] + r_refdef.scene.ambient;
                        c2[3] = c[3];
                }
        }
@@ -7288,7 +8365,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)
@@ -7455,7 +8532,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);
@@ -7472,7 +8549,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
@@ -7481,7 +8558,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);
                }
@@ -7494,36 +8571,22 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_
        GL_Color(1, 1, 1, 1);
 }
 
-static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
+extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
+extern rtexture_t *r_shadow_prepasslightingspeculartexture;
+static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
 {
+       qboolean reflect = (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)) && !prepass;
+       qboolean refract = (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)) && !prepass;
+
        if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)))
                return;
 
-       R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
-       R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
-       R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
-       R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
-       R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
-       R_Mesh_TexBind(GL20TU_GLOW, R_GetTexture(rsurface.texture->currentskinframe->glow));
-       if (rsurface.texture->backgroundcurrentskinframe)
-       {
-               R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
-               R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
-               R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
-               R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
-       }
-       if(rsurface.texture->colormapping)
-       {
-               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 ((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))
+       if (refract)
        {
                // render background
                GL_BlendFunc(GL_ONE, GL_ZERO);
@@ -7533,17 +8596,14 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface
                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);
-               }
+               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND);
+               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);
                GL_LockArrays(0, 0);
 
                GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
@@ -7552,22 +8612,19 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface
                        R_Mesh_ColorPointer(NULL, 0, 0);
                else
                        R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
-               R_Mesh_TexBind(GL20TU_REFRACTION, R_GetTexture(r_texture_white)); // changed per surface
-               R_Mesh_TexBind(GL20TU_REFLECTION, R_GetTexture(r_texture_white)); // changed per surface
        }
 
-       R_SetupSurfaceShader(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE);
-       if (!r_glsl_permutation)
-               return;
+       R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, prepass ? RSURFPASS_DEFERREDGEOMETRY : RSURFPASS_BASE);
 
-       RSurf_PrepareVerticesForBatch(r_glsl_permutation->loc_Texture_Normal >= 0 || r_glsl_permutation->loc_LightDir >= 0, r_glsl_permutation->loc_Texture_Normal >= 0, texturenumsurfaces, texturesurfacelist);
+       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);
+       if (!prepass)
+               R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
 
-       if (r_glsl_permutation->loc_Texture_Refraction >= 0)
+       if (refract)
        {
                GL_BlendFunc(GL_ONE, GL_ZERO);
                GL_DepthMask(true);
@@ -7577,20 +8634,20 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface
        {
                GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
                GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
-               GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
+               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);
+               if (refract || reflect)
+                       RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist);
                else
-                       RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, GL20TU_LIGHTMAP, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? GL20TU_DELUXEMAP : -1);
+                       RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist);
        }
        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);
+               if (refract || reflect)
+                       RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist);
                else
                        RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
        }
@@ -7603,7 +8660,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);
@@ -7642,22 +8698,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_GetTexture(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, R_GetTexture(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)
@@ -7666,28 +8719,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, R_GetTexture(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, R_GetTexture(layer->texture));
+                               R_Mesh_TexMatrix(0, &layer->texmatrix);
+                               R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+                       }
+                       else
+                       {
+                               R_Mesh_TexBind(0, 0);
+                               R_Mesh_TexCoordPointer(0, 2, NULL, 0, 0);
                        }
-                       R_Mesh_TextureState(&m);
+                       R_Mesh_TexBind(1, 0);
+                       R_Mesh_TexCoordPointer(1, 2, NULL, 0, 0);
                        // generate a color array for the fog pass
                        R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
                        for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
@@ -7726,7 +8782,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);
@@ -7746,7 +8801,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:
@@ -7754,12 +8809,10 @@ 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_GetTexture(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)
@@ -7769,25 +8822,19 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
                                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, R_GetTexture(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, R_GetTexture(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
@@ -7796,31 +8843,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, R_GetTexture(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, R_GetTexture(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;
@@ -7859,7 +8903,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)
        {
@@ -7874,7 +8918,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);
@@ -7957,11 +9001,11 @@ static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, const
        RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
 }
 
-static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
+static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
 {
        CHECKGLERROR
        RSurf_SetupDepthAndCulling();
-       if (r_showsurfaces.integer == 3)
+       if (r_showsurfaces.integer == 3 && !prepass)
        {
                R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth);
                return;
@@ -7969,7 +9013,8 @@ static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface
        switch (vid.renderpath)
        {
        case RENDERPATH_GL20:
-               R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth);
+       case RENDERPATH_CGGL:
+               R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
                break;
        case RENDERPATH_GL13:
                R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist, writedepth);
@@ -7981,11 +9026,11 @@ static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface
        CHECKGLERROR
 }
 
-static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
+static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
 {
        CHECKGLERROR
        RSurf_SetupDepthAndCulling();
-       if (r_showsurfaces.integer == 3)
+       if (r_showsurfaces.integer == 3 && !prepass)
        {
                R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth);
                return;
@@ -7993,7 +9038,8 @@ static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface
        switch (vid.renderpath)
        {
        case RENDERPATH_GL20:
-               R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth);
+       case RENDERPATH_CGGL:
+               R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
                break;
        case RENDERPATH_GL13:
                R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist, writedepth);
@@ -8011,7 +9057,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
@@ -8019,21 +9065,67 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
        if (ent == r_refdef.scene.worldentity)
                RSurf_ActiveWorldEntity();
        else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
-               RSurf_ActiveModelEntity(ent, false, false);
+               RSurf_ActiveModelEntity(ent, false, false, false);
        else
        {
                switch (vid.renderpath)
                {
                case RENDERPATH_GL20:
-                       RSurf_ActiveModelEntity(ent, true, true);
+               case RENDERPATH_CGGL:
+                       RSurf_ActiveModelEntity(ent, true, true, false);
                        break;
                case RENDERPATH_GL13:
                case RENDERPATH_GL11:
-                       RSurf_ActiveModelEntity(ent, true, false);
+                       RSurf_ActiveModelEntity(ent, true, false, false);
                        break;
                }
        }
 
+       if (r_transparentdepthmasking.integer)
+       {
+               qboolean setup = false;
+               for (i = 0;i < numsurfaces;i = j)
+               {
+                       j = i + 1;
+                       surface = rsurface.modelsurfaces + surfacelist[i];
+                       texture = surface->texture;
+                       rsurface.texture = R_GetCurrentTexture(texture);
+                       rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
+                       // scan ahead until we find a different texture
+                       endsurface = min(i + 1024, numsurfaces);
+                       texturenumsurfaces = 0;
+                       texturesurfacelist[texturenumsurfaces++] = surface;
+                       for (;j < endsurface;j++)
+                       {
+                               surface = rsurface.modelsurfaces + surfacelist[j];
+                               if (texture != surface->texture || rsurface.uselightmaptexture != (surface->lightmaptexture != NULL))
+                                       break;
+                               texturesurfacelist[texturenumsurfaces++] = surface;
+                       }
+                       if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
+                               continue;
+                       // render the range of surfaces as depth
+                       if (!setup)
+                       {
+                               setup = true;
+                               GL_ColorMask(0,0,0,0);
+                               GL_Color(1,1,1,1);
+                               GL_DepthTest(true);
+                               GL_BlendFunc(GL_ONE, GL_ZERO);
+                               GL_DepthMask(true);
+                               GL_AlphaTest(false);
+                               R_Mesh_ColorPointer(NULL, 0, 0);
+                               R_Mesh_ResetTextureState();
+                               R_SetupShader_DepthOrShadow();
+                       }
+                       RSurf_SetupDepthAndCulling();
+                       RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+                       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+               }
+               if (setup)
+                       GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
+       }
+
        for (i = 0;i < numsurfaces;i = j)
        {
                j = i + 1;
@@ -8054,15 +9146,38 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
                }
                // render the range of surfaces
                if (ent == r_refdef.scene.worldentity)
-                       R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false);
+                       R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
                else
-                       R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false);
+                       R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
        }
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
        GL_AlphaTest(false);
 }
 
-static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly)
+static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, const entity_render_t *queueentity)
+{
+       // transparent surfaces get pushed off into the transparent queue
+       int surfacelistindex;
+       const msurface_t *surface;
+       vec3_t tempcenter, center;
+       for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
+       {
+               surface = texturesurfacelist[surfacelistindex];
+               tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
+               tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
+               tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
+               Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
+               if (queueentity->transparent_offset) // transparent offset
+               {
+                       center[0] += r_refdef.view.forward[0]*queueentity->transparent_offset;
+                       center[1] += r_refdef.view.forward[1]*queueentity->transparent_offset;
+                       center[2] += r_refdef.view.forward[2]*queueentity->transparent_offset;
+               }
+               R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight);
+       }
+}
+
+static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
 {
        const entity_render_t *queueentity = r_refdef.scene.worldentity;
        CHECKGLERROR
@@ -8076,13 +9191,22 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf
                RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
                RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
        }
-       else if (r_showsurfaces.integer && !r_refdef.view.showdebug)
+       else if (prepass)
+       {
+               if (!rsurface.texture->currentnumlayers)
+                       return;
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity);
+               else
+                       R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
+       }
+       else if (r_showsurfaces.integer && !r_refdef.view.showdebug && !prepass)
        {
                RSurf_SetupDepthAndCulling();
                GL_AlphaTest(false);
                R_Mesh_ColorPointer(NULL, 0, 0);
                R_Mesh_ResetTextureState();
-               R_SetupGenericShader(false);
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
                RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
                GL_DepthMask(true);
                GL_BlendFunc(GL_ONE, GL_ZERO);
@@ -8090,13 +9214,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);
@@ -8109,29 +9233,19 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf
                return;
        else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))) && queueentity)
        {
-               // transparent surfaces get pushed off into the transparent queue
-               int surfacelistindex;
-               const msurface_t *surface;
-               vec3_t tempcenter, center;
-               for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
-               {
-                       surface = texturesurfacelist[surfacelistindex];
-                       tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
-                       tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
-                       tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
-                       Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
-                       R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight);
-               }
+               // in the deferred case, transparent surfaces were queued during prepass
+               if (!r_shadow_usingdeferredprepass)
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity);
        }
        else
        {
                // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
-               R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST));
+               R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
        }
        CHECKGLERROR
 }
 
-void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly)
+void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
 {
        int i, j;
        texture_t *texture;
@@ -8145,7 +9259,7 @@ void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, in
                // use skin 1 instead)
                texture = surfacelist[i]->texture;
                rsurface.texture = R_GetCurrentTexture(texture);
-               rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
+               rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL && !depthonly && !prepass;
                if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
                {
                        // if this texture is not the kind we want, skip ahead to the next one
@@ -8157,11 +9271,11 @@ void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, in
                for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
                        ;
                // render the range of surfaces
-               R_ProcessWorldTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly);
+               R_ProcessWorldTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
        }
 }
 
-static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity)
+static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity, qboolean prepass)
 {
        CHECKGLERROR
        if (depthonly)
@@ -8174,13 +9288,22 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf
                RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
                RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
        }
+       else if (prepass)
+       {
+               if (!rsurface.texture->currentnumlayers)
+                       return;
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity);
+               else
+                       R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
+       }
        else if (r_showsurfaces.integer && !r_refdef.view.showdebug)
        {
                RSurf_SetupDepthAndCulling();
                GL_AlphaTest(false);
                R_Mesh_ColorPointer(NULL, 0, 0);
                R_Mesh_ResetTextureState();
-               R_SetupGenericShader(false);
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
                RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
                GL_DepthMask(true);
                GL_BlendFunc(GL_ONE, GL_ZERO);
@@ -8194,7 +9317,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);
@@ -8207,35 +9330,19 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf
                return;
        else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))) && queueentity)
        {
-               // transparent surfaces get pushed off into the transparent queue
-               int surfacelistindex;
-               const msurface_t *surface;
-               vec3_t tempcenter, center;
-               for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
-               {
-                       surface = texturesurfacelist[surfacelistindex];
-                       tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
-                       tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
-                       tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
-                       Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
-                       if (queueentity->transparent_offset) // transparent offset
-                       {
-                               center[0] += r_refdef.view.forward[0]*queueentity->transparent_offset;
-                               center[1] += r_refdef.view.forward[1]*queueentity->transparent_offset;
-                               center[2] += r_refdef.view.forward[2]*queueentity->transparent_offset;
-                       }
-                       R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight);
-               }
+               // in the deferred case, transparent surfaces were queued during prepass
+               if (!r_shadow_usingdeferredprepass)
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity);
        }
        else
        {
                // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
-               R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST));
+               R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
        }
        CHECKGLERROR
 }
 
-void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly)
+void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
 {
        int i, j;
        texture_t *texture;
@@ -8249,7 +9356,7 @@ void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurfa
                // use skin 1 instead)
                texture = surfacelist[i]->texture;
                rsurface.texture = R_GetCurrentTexture(texture);
-               rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
+               rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL && !depthonly && !prepass;
                if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
                {
                        // if this texture is not the kind we want, skip ahead to the next one
@@ -8261,7 +9368,7 @@ void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurfa
                for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
                        ;
                // render the range of surfaces
-               R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent);
+               R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent, prepass);
        }
 }
 
@@ -8298,12 +9405,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,
@@ -8484,7 +9591,7 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor
                R_DecalSystem_Reset(decalsystem);
        decalsystem->model = model;
 
-       RSurf_ActiveModelEntity(ent, false, false);
+       RSurf_ActiveModelEntity(ent, false, false, false);
 
        Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
        Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
@@ -8783,7 +9890,7 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
        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;
@@ -8805,7 +9912,7 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
        if (ent == r_refdef.scene.worldentity)
                RSurf_ActiveWorldEntity();
        else
-               RSurf_ActiveModelEntity(ent, false, false);
+               RSurf_ActiveModelEntity(ent, false, false, false);
 
        decalsystem->lastupdatetime = cl.time;
        decal = decalsystem->decals;
@@ -8822,7 +9929,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
@@ -8878,6 +9985,26 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
        if (numtris > 0)
        {
                r_refdef.stats.drawndecals += numtris;
+
+               if (r_refdef.fogenabled)
+               {
+                       switch(vid.renderpath)
+                       {
+                       case RENDERPATH_GL20:
+                       case RENDERPATH_CGGL:
+                       case RENDERPATH_GL13:
+                       case RENDERPATH_GL11:
+                               for (i = 0, v3f = decalsystem->vertex3f, c4f = decalsystem->color4f;i < numtris*3;i++, v3f += 3, c4f += 4)
+                               {
+                                       alpha = RSurf_FogVertex(v3f);
+                                       c4f[0] *= alpha;
+                                       c4f[1] *= alpha;
+                                       c4f[2] *= alpha;
+                               }
+                               break;
+                       }
+               }
+
                // 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);
@@ -8885,15 +10012,13 @@ 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));
+               R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1);
                GL_LockArrays(0, numtris * 3);
                R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, decalsystem->element3s, 0, 0);
                GL_LockArrays(0, 0);
@@ -8927,9 +10052,6 @@ static void R_DrawModelDecals(void)
 
        R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
 
-       if (!r_drawentities.integer)
-               return;
-
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
                if (!r_refdef.viewcache.entityvisible[i])
@@ -8953,7 +10075,7 @@ 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);
@@ -9085,7 +10207,7 @@ void R_DrawDebugModel(void)
 extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
 int r_maxsurfacelist = 0;
 const msurface_t **r_surfacelist = NULL;
-void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug)
+void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
 {
        int i, j, endj, f, flagsmask;
        texture_t *t;
@@ -9110,7 +10232,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep
        update = model->brushq1.lightmapupdateflags;
 
        // update light styles on this submodel
-       if (!skysurfaces && !depthonly && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0)
+       if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0)
        {
                model_brush_lightstyleinfo_t *style;
                for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
@@ -9149,17 +10271,38 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep
        }
        // update lightmaps if needed
        if (update)
+       {
+               int updated = 0;
                for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
+               {
                        if (r_refdef.viewcache.world_surfacevisible[j])
+                       {
                                if (update[j])
+                               {
+                                       updated++;
                                        R_BuildLightMap(r_refdef.scene.worldentity, surfaces + j);
+                               }
+                       }
+               }
+               if (updated)
+               {
+                       int count = model->brushq3.num_mergedlightmaps;
+                       for (i = 0;i < count;i++)
+                       {
+                               if (model->brushq3.data_deluxemaps[i])
+                                       R_FlushTexture(model->brushq3.data_deluxemaps[i]);
+                               if (model->brushq3.data_lightmaps[i])
+                                       R_FlushTexture(model->brushq3.data_lightmaps[i]);
+                       }
+               }
+       }
        // don't do anything if there were no surfaces
        if (!numsurfacelist)
        {
                rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
                return;
        }
-       R_QueueWorldSurfaceList(numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly);
+       R_QueueWorldSurfaceList(numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
        GL_AlphaTest(false);
 
        // add to stats if desired
@@ -9173,7 +10316,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
-void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug)
+void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
 {
        int i, j, endj, f, flagsmask;
        texture_t *t;
@@ -9198,19 +10341,22 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
        if (ent == r_refdef.scene.worldentity)
                RSurf_ActiveWorldEntity();
        else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
-               RSurf_ActiveModelEntity(ent, false, false);
+               RSurf_ActiveModelEntity(ent, false, false, false);
+       else if (prepass)
+               RSurf_ActiveModelEntity(ent, true, true, true);
        else if (depthonly)
-               RSurf_ActiveModelEntity(ent, false, false);
+               RSurf_ActiveModelEntity(ent, false, false, false);
        else
        {
                switch (vid.renderpath)
                {
                case RENDERPATH_GL20:
-                       RSurf_ActiveModelEntity(ent, true, true);
+               case RENDERPATH_CGGL:
+                       RSurf_ActiveModelEntity(ent, true, true, false);
                        break;
                case RENDERPATH_GL13:
                case RENDERPATH_GL11:
-                       RSurf_ActiveModelEntity(ent, true, false);
+                       RSurf_ActiveModelEntity(ent, true, false, false);
                        break;
                }
        }
@@ -9219,7 +10365,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
        update = model->brushq1.lightmapupdateflags;
 
        // update light styles
-       if (!skysurfaces && !depthonly && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0)
+       if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0)
        {
                model_brush_lightstyleinfo_t *style;
                for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
@@ -9259,11 +10405,34 @@ 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 (updated)
+               {
+                       int count = model->brushq3.num_mergedlightmaps;
+                       for (i = 0;i < count;i++)
+                       {
+                               if (model->brushq3.data_deluxemaps[i])
+                                       R_FlushTexture(model->brushq3.data_deluxemaps[i]);
+                               if (model->brushq3.data_lightmaps[i])
+                                       R_FlushTexture(model->brushq3.data_lightmaps[i]);
+                       }
+               }
+       }
        if (update)
                for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
                        if (update[j])
                                R_BuildLightMap(ent, surfaces + j);
-       R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly);
+       R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
        GL_AlphaTest(false);
 
        // add to stats if desired
@@ -9277,7 +10446,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
-void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth)
+void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
 {
        static texture_t texture;
        static msurface_t surface;
@@ -9301,5 +10470,24 @@ void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, i
        // now render it
        rsurface.texture = R_GetCurrentTexture(surface.texture);
        rsurface.uselightmaptexture = false;
-       R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth);
+       R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
+}
+
+void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
+{
+       static msurface_t surface;
+       const msurface_t *surfacelist = &surface;
+
+       // fake enough texture and surface state to render this geometry
+
+       surface.texture = texture;
+       surface.num_triangles = numtriangles;
+       surface.num_firsttriangle = firsttriangle;
+       surface.num_vertices = numvertices;
+       surface.num_firstvertex = firstvertex;
+
+       // now render it
+       rsurface.texture = R_GetCurrentTexture(surface.texture);
+       rsurface.uselightmaptexture = false;
+       R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
 }