]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
try to cache fewer animations for entities when r_shadows is used by using cull box
[xonotic/darkplaces.git] / gl_rmain.c
index a9c9294017a950c0608bd54751c5627bce7b1e68..22c99ef12be07a8a675a41194422d1f1236cd926 100644 (file)
@@ -112,6 +112,12 @@ cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the re
 cvar_t r_texture_dds_load = {CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
 cvar_t r_texture_dds_save = {CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
 
+cvar_t r_texture_convertsRGB_2d = {0, "r_texture_convertsRGB_2d", "0", "load textures as sRGB and convert to linear for proper shading"};
+cvar_t r_texture_convertsRGB_skin = {0, "r_texture_convertsRGB_skin", "0", "load textures as sRGB and convert to linear for proper shading"};
+cvar_t r_texture_convertsRGB_cubemap = {0, "r_texture_convertsRGB_cubemap", "0", "load textures as sRGB and convert to linear for proper shading"};
+cvar_t r_texture_convertsRGB_skybox = {0, "r_texture_convertsRGB_skybox", "0", "load textures as sRGB and convert to linear for proper shading"};
+cvar_t r_texture_convertsRGB_particles = {0, "r_texture_convertsRGB_particles", "0", "load textures as sRGB and convert to linear for proper shading"};
+
 cvar_t r_textureunits = {0, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
 static cvar_t gl_combine = {CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
 static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
@@ -211,6 +217,18 @@ rtexture_t *r_texture_fogattenuation;
 rtexture_t *r_texture_gammaramps;
 unsigned int r_texture_gammaramps_serial;
 //rtexture_t *r_texture_fogintensity;
+rtexture_t *r_texture_reflectcube;
+
+// TODO: hash lookups?
+typedef struct cubemapinfo_s
+{
+       char basename[64];
+       rtexture_t *texture;
+}
+cubemapinfo_t;
+
+int r_texture_numcubemaps;
+cubemapinfo_t r_texture_cubemaps[MAX_CUBEMAPS];
 
 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
 unsigned int r_numqueries;
@@ -235,8 +253,6 @@ const float r_screenvertex3f[12] =
        0, 1, 0
 };
 
-extern void R_DrawModelShadows(void);
-
 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
 {
        int i;
@@ -477,7 +493,7 @@ static const char *builtinshaderstring =
 "#if defined(MODE_LIGHTMAP) || defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
 "#define USELIGHTMAP\n"
 "#endif\n"
-"#if defined(USESPECULAR) || defined(USEOFFSETMAPPING)\n"
+"#if defined(USESPECULAR) || defined(USEOFFSETMAPPING) || defined(USEREFLECTCUBE)\n"
 "#define USEEYEVECTOR\n"
 "#endif\n"
 "\n"
@@ -804,6 +820,7 @@ static const char *builtinshaderstring =
 "      vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
 "      //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
 "      vec4 SafeScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
+"      //SafeScreenTexCoord = gl_FragCoord.xyxy * vec4(1.0 / 1920.0, 1.0 / 1200.0, 1.0 / 1920.0, 1.0 / 1200.0);\n"
 "      vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5))).xyxy * DistortScaleRefractReflect;\n"
 "      // FIXME temporary hack to detect the case that the reflection\n"
 "      // gets blackened at edges due to leaving the area that contains actual\n"
@@ -854,7 +871,7 @@ static const char *builtinshaderstring =
 "varying vec4 EyeVectorModelSpaceFogPlaneVertexDist;\n"
 "#endif\n"
 "\n"
-"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_DEFERREDGEOMETRY)\n"
+"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_DEFERREDGEOMETRY) || defined(USEREFLECTCUBE)\n"
 "varying vec3 VectorS; // direction of S texcoord (sometimes crudely called tangent)\n"
 "varying vec3 VectorT; // direction of T texcoord (sometimes crudely called binormal)\n"
 "varying vec3 VectorR; // direction of R texcoord (surface normal)\n"
@@ -877,6 +894,10 @@ static const char *builtinshaderstring =
 "#endif\n"
 "uniform vec4 FogPlane;\n"
 "\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"varying vec3 ShadowMapTC;\n"
+"#endif\n"
+"\n"
 "\n"
 "\n"
 "\n"
@@ -888,18 +909,14 @@ static const char *builtinshaderstring =
 "\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"
@@ -1001,6 +1018,9 @@ static const char *builtinshaderstring =
 "#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE)\n"
 "uniform sampler2D Texture_Attenuation;\n"
 "uniform samplerCube Texture_Cube;\n"
+"#endif\n"
+"\n"
+"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE) || defined(USESHADOWMAPORTHO)\n"
 "\n"
 "#ifdef USESHADOWMAPRECT\n"
 "# ifdef USESHADOWSAMPLER\n"
@@ -1036,7 +1056,21 @@ static const char *builtinshaderstring =
 "#endif\n"
 "\n"
 "#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
-"# ifndef USESHADOWMAPVSDCT\n"
+"# ifdef USESHADOWMAPORTHO\n"
+"#  define GetShadowMapTC2D(dir) (min(dir, vec3(ShadowMap_Parameters.zw, 1.0)))\n"
+"# else\n"
+"#  ifdef USESHADOWMAPVSDCT\n"
+"vec3 GetShadowMapTC2D(vec3 dir)\n"
+"{\n"
+"   vec3 adir = abs(dir);\n"
+"   vec4 proj = textureCube(Texture_CubeProjection, dir);\n"
+"   float ma = max(max(adir.x, adir.y), adir.z);\n"
+"   vec3 stc = vec3(mix(dir.xy, dir.zz, proj.xy) * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
+"   stc.xy += proj.zw * ShadowMap_Parameters.y;\n"
+"   stc.z += ShadowMap_Parameters.z;\n"
+"   return stc;\n"
+"}\n"
+"#  else\n"
 "vec3 GetShadowMapTC2D(vec3 dir)\n"
 "{\n"
 "      vec3 adir = abs(dir);\n"
@@ -1079,17 +1113,7 @@ static const char *builtinshaderstring =
 "      stc.z += ShadowMap_Parameters.z;\n"
 "      return stc;\n"
 "}\n"
-"# else\n"
-"vec3 GetShadowMapTC2D(vec3 dir)\n"
-"{\n"
-"      vec3 adir = abs(dir);\n"
-"      vec4 proj = textureCube(Texture_CubeProjection, dir);\n"
-"      float ma = max(max(adir.x, adir.y), adir.z);\n"
-"      vec3 stc = vec3(mix(dir.xy, dir.zz, proj.xy) * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
-"      stc.xy += proj.zw * ShadowMap_Parameters.y;\n"
-"      stc.z += ShadowMap_Parameters.z;\n"
-"      return stc;\n"
-"}\n"
+"#  endif\n"
 "# endif\n"
 "#endif // defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
 "\n"
@@ -1141,7 +1165,11 @@ static const char *builtinshaderstring =
 "#    endif\n"
 "\n"
 "#  endif\n"
+"#  ifdef USESHADOWMAPORTHO\n"
+"      return mix(ShadowMap_Parameters.x, ShadowMap_Parameters.y, f);\n"
+"#  else\n"
 "      return f;\n"
+"#  endif\n"
 "}\n"
 "# endif\n"
 "\n"
@@ -1204,7 +1232,11 @@ static const char *builtinshaderstring =
 "      f = step(shadowmaptc.z, texture2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale).r);\n"
 "#    endif\n"
 "#  endif\n"
+"#  ifdef USESHADOWMAPORTHO\n"
+"      return mix(ShadowMap_Parameters.x, ShadowMap_Parameters.y, f);\n"
+"#  else\n"
 "      return f;\n"
+"#  endif\n"
 "}\n"
 "# endif\n"
 "\n"
@@ -1222,7 +1254,7 @@ static const char *builtinshaderstring =
 "      return f;\n"
 "}\n"
 "# endif\n"
-"#endif // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE)\n"
+"#endif // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE) && !defined(USESHADOWMAPORTHO)\n"
 "#endif // FRAGMENT_SHADER\n"
 "\n"
 "\n"
@@ -1281,11 +1313,13 @@ static const char *builtinshaderstring =
 "\n"
 "#ifdef USEVERTEXTEXTUREBLEND\n"
 "      vec3 surfacenormal = mix(vec3(texture2D(Texture_SecondaryNormal, TexCoord2)), vec3(texture2D(Texture_Normal, TexCoord)), terrainblend) - vec3(0.5, 0.5, 0.5);\n"
+"      float a = mix(texture2D(Texture_SecondaryGloss, TexCoord2).a, texture2D(Texture_Gloss, TexCoord).a, terrainblend);\n"
 "#else\n"
 "      vec3 surfacenormal = vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5, 0.5, 0.5);\n"
+"      float a = texture2D(Texture_Gloss, TexCoord).a;\n"
 "#endif\n"
 "\n"
-"      gl_FragColor = vec4(normalize(surfacenormal.x * VectorS + surfacenormal.y * VectorT + surfacenormal.z * VectorR) * 0.5 + vec3(0.5, 0.5, 0.5), 1);\n"
+"      gl_FragColor = vec4(normalize(surfacenormal.x * VectorS + surfacenormal.y * VectorT + surfacenormal.z * VectorR) * 0.5 + vec3(0.5, 0.5, 0.5), a);\n"
 "}\n"
 "#endif // FRAGMENT_SHADER\n"
 "#else // !MODE_DEFERREDGEOMETRY\n"
@@ -1339,10 +1373,10 @@ static const char *builtinshaderstring =
 "      // calculate directional shading\n"
 "      vec3 eyevector = position * -1.0;\n"
 "#  ifdef USEEXACTSPECULARMATH\n"
-"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(eyevector)))*-1.0, 0.0)), SpecularPower);\n"
+"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(eyevector)))*-1.0, 0.0)), SpecularPower * normalmap.a);\n"
 "#  else\n"
 "      myhalf3 specularnormal = normalize(lightnormal + myhalf3(normalize(eyevector)));\n"
-"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
+"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * normalmap.a);\n"
 "#  endif\n"
 "#endif\n"
 "\n"
@@ -1381,6 +1415,9 @@ static const char *builtinshaderstring =
 "#ifdef MODE_LIGHTSOURCE\n"
 "uniform mat4 ModelToLight;\n"
 "#endif\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"uniform mat4 ShadowMapMatrix;\n"
+"#endif\n"
 "void main(void)\n"
 "{\n"
 "#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND)\n"
@@ -1430,7 +1467,7 @@ static const char *builtinshaderstring =
 "      EyeVectorModelSpaceFogPlaneVertexDist.w = dot(FogPlane, gl_Vertex);\n"
 "#endif\n"
 "\n"
-"#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
+"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(USEREFLECTCUBE)\n"
 "      VectorS = gl_MultiTexCoord1.xyz;\n"
 "      VectorT = gl_MultiTexCoord2.xyz;\n"
 "      VectorR = gl_MultiTexCoord3.xyz;\n"
@@ -1439,6 +1476,10 @@ static const char *builtinshaderstring =
 "      // transform vertex to camera space, using ftransform to match non-VS rendering\n"
 "      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
 "\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"      ShadowMapTC = vec3(ShadowMapMatrix * gl_Position);\n"
+"#endif\n"
+"\n"
 "#ifdef USEREFLECTION\n"
 "      ModelViewProjectionPosition = gl_Position;\n"
 "#endif\n"
@@ -1468,6 +1509,11 @@ static const char *builtinshaderstring =
 "uniform vec4 ScreenCenterRefractReflect;\n"
 "uniform myhalf4 ReflectColor;\n"
 "#endif\n"
+"#ifdef USEREFLECTCUBE\n"
+"uniform mat4 ModelToReflectCube;\n"
+"uniform sampler2D Texture_ReflectMask;\n"
+"uniform samplerCube Texture_ReflectCube;\n"
+"#endif\n"
 "#ifdef MODE_LIGHTDIRECTION\n"
 "uniform myhalf3 LightColor;\n"
 "#endif\n"
@@ -1512,12 +1558,19 @@ static const char *builtinshaderstring =
 "      myhalf3 diffusetex = color.rgb;\n"
 "#if defined(USESPECULAR) || defined(USEDEFERREDLIGHTMAP)\n"
 "# ifdef USEVERTEXTEXTUREBLEND\n"
-"      myhalf3 glosstex = mix(myhalf3(texture2D(Texture_SecondaryGloss, TexCoord2)), myhalf3(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n"
+"      myhalf4 glosstex = mix(myhalf4(texture2D(Texture_SecondaryGloss, TexCoord2)), myhalf4(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n"
 "# else\n"
-"      myhalf3 glosstex = myhalf3(texture2D(Texture_Gloss, TexCoord));\n"
+"      myhalf4 glosstex = myhalf4(texture2D(Texture_Gloss, TexCoord));\n"
 "# endif\n"
 "#endif\n"
 "\n"
+"#ifdef USEREFLECTCUBE\n"
+"      vec3 TangentReflectVector = reflect(-EyeVector, surfacenormal);\n"
+"      vec3 ModelReflectVector = TangentReflectVector.x * VectorS + TangentReflectVector.y * VectorT + TangentReflectVector.z * VectorR;\n"
+"      vec3 ReflectCubeTexCoord = vec3(ModelToReflectCube * vec4(ModelReflectVector, 0));\n"
+"      diffusetex += myhalf3(texture2D(Texture_ReflectMask, TexCoord)) * myhalf3(textureCube(Texture_ReflectCube, ReflectCubeTexCoord));\n"
+"#endif\n"
+"\n"
 "\n"
 "\n"
 "\n"
@@ -1529,12 +1582,12 @@ static const char *builtinshaderstring =
 "      color.rgb = diffusetex * (Color_Ambient + diffuse * Color_Diffuse);\n"
 "#ifdef USESPECULAR\n"
 "#ifdef USEEXACTSPECULARMATH\n"
-"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
+"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower * glosstex.a);\n"
 "#else\n"
 "      myhalf3 specularnormal = normalize(lightnormal + myhalf3(normalize(EyeVector)));\n"
-"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
+"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * glosstex.a);\n"
 "#endif\n"
-"      color.rgb += glosstex * (specular * Color_Specular);\n"
+"      color.rgb += glosstex.rgb * (specular * Color_Specular);\n"
 "#endif\n"
 "#else\n"
 "      color.rgb = diffusetex * Color_Ambient;\n"
@@ -1608,12 +1661,12 @@ static const char *builtinshaderstring =
 "      myhalf diffuse = myhalf(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
 "#  ifdef USESPECULAR\n"
 "#   ifdef USEEXACTSPECULARMATH\n"
-"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
+"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower * glosstex.a);\n"
 "#   else\n"
 "      myhalf3 specularnormal = normalize(lightnormal + myhalf3(normalize(EyeVector)));\n"
-"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
+"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * glosstex.a);\n"
 "#   endif\n"
-"      color.rgb = diffusetex * Color_Ambient + (diffusetex * Color_Diffuse * diffuse + glosstex * Color_Specular * specular) * lightcolor;\n"
+"      color.rgb = diffusetex * Color_Ambient + (diffusetex * Color_Diffuse * diffuse + glosstex.rgb * Color_Specular * specular) * lightcolor;\n"
 "#  else\n"
 "      color.rgb = diffusetex * (Color_Ambient + Color_Diffuse * diffuse * lightcolor);\n"
 "#  endif\n"
@@ -1622,10 +1675,14 @@ static const char *builtinshaderstring =
 "# endif\n"
 "#endif\n"
 "\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"      color.rgb *= ShadowMapCompare(ShadowMapTC);\n"
+"#endif\n"
+"\n"
 "#ifdef USEDEFERREDLIGHTMAP\n"
 "      vec2 ScreenTexCoord = gl_FragCoord.xy * PixelToScreenTexCoord;\n"
 "      color.rgb += diffusetex * myhalf3(texture2D(Texture_ScreenDiffuse, ScreenTexCoord)) * DeferredMod_Diffuse;\n"
-"      color.rgb += glosstex * myhalf3(texture2D(Texture_ScreenSpecular, ScreenTexCoord)) * DeferredMod_Specular;\n"
+"      color.rgb += glosstex.rgb * myhalf3(texture2D(Texture_ScreenSpecular, ScreenTexCoord)) * DeferredMod_Specular;\n"
 "#endif\n"
 "\n"
 "#ifdef USEGLOW\n"
@@ -1717,7 +1774,7 @@ const char *builtincgshaderstring =
 "#if defined(MODE_LIGHTMAP) || defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
 "#define USELIGHTMAP\n"
 "#endif\n"
-"#if defined(USESPECULAR) || defined(USEOFFSETMAPPING)\n"
+"#if defined(USESPECULAR) || defined(USEOFFSETMAPPING) || defined(USEREFLECTCUBE)\n"
 "#define USEEYEVECTOR\n"
 "#endif\n"
 "\n"
@@ -2155,9 +2212,23 @@ const char *builtincgshaderstring =
 "}\n"
 "#endif // USEOFFSETMAPPING\n"
 "\n"
-"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE)\n"
+"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE) || defined(USESHADOWMAPORTHO)\n"
 "#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
-"# ifndef USESHADOWMAPVSDCT\n"
+"# ifdef USESHADOWMAPORTHO\n"
+"#  define GetShadowMapTC2D(dir, ShadowMap_Parameters) (min(dir, float3(ShadowMap_Parameters.zw, 1.0)))\n"
+"# else\n"
+"#  ifdef USESHADOWMAPVSDCT\n"
+"float3 GetShadowMapTC2D(float3 dir, float4 ShadowMap_Parameters, samplerCUBE Texture_CubeProjection)\n"
+"{\n"
+"   float3 adir = abs(dir);\n"
+"   float4 proj = texCUBE(Texture_CubeProjection, dir);\n"
+"   float ma = max(max(adir.x, adir.y), adir.z);\n"
+"   float3 stc = float3(lerp(dir.xy, dir.zz, proj.xy) * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
+"   stc.xy += proj.zw * ShadowMap_Parameters.y;\n"
+"   stc.z += ShadowMap_Parameters.z;\n"
+"   return stc;\n"
+"}\n"
+"#  else\n"
 "float3 GetShadowMapTC2D(float3 dir, float4 ShadowMap_Parameters)\n"
 "{\n"
 "      float3 adir = abs(dir);\n"
@@ -2200,19 +2271,9 @@ const char *builtincgshaderstring =
 "      stc.z += ShadowMap_Parameters.z;\n"
 "      return stc;\n"
 "}\n"
-"# else\n"
-"float3 GetShadowMapTC2D(float3 dir, float4 ShadowMap_Parameters, samplerCUBE Texture_CubeProjection)\n"
-"{\n"
-"      float3 adir = abs(dir);\n"
-"      float4 proj = texCUBE(Texture_CubeProjection, dir);\n"
-"      float ma = max(max(adir.x, adir.y), adir.z);\n"
-"      float3 stc = float3(lerp(dir.xy, dir.zz, proj.xy) * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
-"      stc.xy += proj.zw * ShadowMap_Parameters.y;\n"
-"      stc.z += ShadowMap_Parameters.z;\n"
-"      return stc;\n"
-"}\n"
+"#  endif\n"
 "# endif\n"
-"#endif // defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
+"#endif // defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D) || defined(USESHADOWMAPORTHO)\n"
 "\n"
 "#ifdef USESHADOWMAPCUBE\n"
 "float4 GetShadowMapTCCube(float3 dir, float4 ShadowMap_Parameters)\n"
@@ -2270,7 +2331,11 @@ const char *builtincgshaderstring =
 "#    endif\n"
 "\n"
 "#  endif\n"
+"#  ifdef USESHADOWMAPORTHO\n"
+"      return lerp(ShadowMap_Parameters.x, ShadowMap_Parameters.y, f);\n"
+"#  else\n"
 "      return f;\n"
+"#  endif\n"
 "}\n"
 "# endif\n"
 "\n"
@@ -2337,7 +2402,11 @@ const char *builtincgshaderstring =
 "    f = step(shadowmaptc.z, tex2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale).r);\n"
 "#    endif\n"
 "#  endif\n"
-"    return f;\n"
+"#  ifdef USESHADOWMAPORTHO\n"
+"      return lerp(ShadowMap_Parameters.x, ShadowMap_Parameters.y, f);\n"
+"#  else\n"
+"      return f;\n"
+"#  endif\n"
 "}\n"
 "# endif\n"
 "\n"
@@ -2426,8 +2495,10 @@ const char *builtincgshaderstring =
 "#ifdef USEALPHAKILL\n"
 "uniform sampler2D Texture_Color,\n"
 "#endif\n"
+"uniform sampler2D Texture_Gloss,\n"
 "#ifdef USEVERTEXTEXTUREBLEND\n"
 "uniform sampler2D Texture_SecondaryNormal,\n"
+"uniform sampler2D Texture_SecondaryGloss,\n"
 "#endif\n"
 "#ifdef USEOFFSETMAPPING\n"
 "uniform float OffsetMapping_Scale,\n"
@@ -2457,8 +2528,10 @@ const char *builtincgshaderstring =
 "\n"
 "#ifdef USEVERTEXTEXTUREBLEND\n"
 "      float3 surfacenormal = lerp(float3(tex2D(Texture_SecondaryNormal, TexCoord2)), float3(tex2D(Texture_Normal, TexCoord)), terrainblend) - float3(0.5, 0.5, 0.5);\n"
+"      float a = lerp(tex2D(Texture_SecondaryGloss, TexCoord2), tex2D(Texture_Gloss, TexCoord).a, terrainblend);\n"
 "#else\n"
 "      float3 surfacenormal = float3(tex2D(Texture_Normal, TexCoord)) - float3(0.5, 0.5, 0.5);\n"
+"      float a = tex2D(Texture_Gloss, TexCoord).a;\n"
 "#endif\n"
 "\n"
 "      gl_FragColor = float4(normalize(surfacenormal.x * VectorS + surfacenormal.y * VectorT + surfacenormal.z * VectorR) * 0.5 + float3(0.5, 0.5, 0.5), 1);\n"
@@ -2565,10 +2638,10 @@ const char *builtincgshaderstring =
 "      // calculate directional shading\n"
 "      float3 eyevector = position * -1.0;\n"
 "#  ifdef USEEXACTSPECULARMATH\n"
-"      half specular = pow(half(max(float(dot(reflect(lightnormal, surfacenormal), normalize(eyevector)))*-1.0, 0.0)), SpecularPower);\n"
+"      half specular = pow(half(max(float(dot(reflect(lightnormal, surfacenormal), normalize(eyevector)))*-1.0, 0.0)), SpecularPower * normalmap.a);\n"
 "#  else\n"
 "      half3 specularnormal = normalize(lightnormal + half3(normalize(eyevector)));\n"
-"      half specular = pow(half(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
+"      half specular = pow(half(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * normalmap.a);\n"
 "#  endif\n"
 "#endif\n"
 "\n"
@@ -2645,6 +2718,9 @@ const char *builtincgshaderstring =
 "#ifdef MODE_DEFERREDLIGHTSOURCE\n"
 "uniform float3 LightPosition,\n"
 "#endif\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"uniform float4x4 ShadowMapMatrix,\n"
+"#endif\n"
 "\n"
 "out float4 gl_FrontColor : COLOR,\n"
 "out float4 TexCoordBoth : TEXCOORD0,\n"
@@ -2666,11 +2742,14 @@ const char *builtincgshaderstring =
 "#ifdef MODE_LIGHTSOURCE\n"
 "out float3 CubeVector : TEXCOORD3,\n"
 "#endif\n"
-"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_DEFERREDGEOMETRY)\n"
+"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_DEFERREDGEOMETRY) || defined(USEREFLECTCUBE)\n"
 "out float3 VectorS : TEXCOORD5, // direction of S texcoord (sometimes crudely called tangent)\n"
 "out float3 VectorT : TEXCOORD6, // direction of T texcoord (sometimes crudely called binormal)\n"
 "out float3 VectorR : TEXCOORD7, // direction of R texcoord (surface normal)\n"
 "#endif\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"out float3 ShadowMapTC : TEXCOORD8,\n"
+"#endif\n"
 "out float4 gl_Position : POSITION\n"
 ")\n"
 "{\n"
@@ -2730,6 +2809,10 @@ const char *builtincgshaderstring =
 "      // transform vertex to camera space, using ftransform to match non-VS rendering\n"
 "      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
 "\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"      ShadowMapTC = float3(mul(ShadowMapMatrix, gl_Position));\n"
+"#endif\n"
+"\n"
 "#ifdef USEREFLECTION\n"
 "      ModelViewProjectionPosition = gl_Position;\n"
 "#endif\n"
@@ -2768,11 +2851,14 @@ const char *builtincgshaderstring =
 "#ifdef MODE_DEFERREDLIGHTSOURCE\n"
 "float4 ModelViewPosition : TEXCOORD0,\n"
 "#endif\n"
-"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_DEFERREDGEOMETRY)\n"
+"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_DEFERREDGEOMETRY) || defined(USEREFLECTCUBE)\n"
 "float3 VectorS : TEXCOORD5, // direction of S texcoord (sometimes crudely called tangent)\n"
 "float3 VectorT : TEXCOORD6, // direction of T texcoord (sometimes crudely called binormal)\n"
 "float3 VectorR : TEXCOORD7, // direction of R texcoord (surface normal)\n"
 "#endif\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"float3 ShadowMapTC : TEXCOORD8\n"
+"#endif\n"
 "\n"
 "uniform sampler2D Texture_Normal,\n"
 "uniform sampler2D Texture_Color,\n"
@@ -2852,6 +2938,11 @@ const char *builtincgshaderstring =
 "uniform float4 ScreenCenterRefractReflect,\n"
 "uniform half4 ReflectColor,\n"
 "#endif\n"
+"#ifdef USEREFLECTCUBE\n"
+"uniform float4x4 ModelToReflectCube,\n"
+"uniform sampler2D Texture_ReflectMask,\n"
+"uniform samplerCUBE Texture_ReflectCube,\n"
+"#endif\n"
 "#ifdef MODE_LIGHTDIRECTION\n"
 "uniform half3 LightColor,\n"
 "#endif\n"
@@ -2862,6 +2953,9 @@ const char *builtincgshaderstring =
 "#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE)\n"
 "uniform sampler2D Texture_Attenuation,\n"
 "uniform samplerCUBE Texture_Cube,\n"
+"#endif\n"
+"\n"
+"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE) || defined(USESHADOWMAPORTHO)\n"
 "\n"
 "#ifdef USESHADOWMAPRECT\n"
 "# ifdef USESHADOWSAMPLER\n"
@@ -2895,7 +2989,7 @@ const char *builtincgshaderstring =
 "uniform float2 ShadowMap_TextureScale,\n"
 "uniform float4 ShadowMap_Parameters,\n"
 "#endif\n"
-"#endif // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE)\n"
+"#endif // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE) && !defined(USESHADOWMAPORTHO)\n"
 "\n"
 "out float4 gl_FragColor : COLOR\n"
 ")\n"
@@ -2940,12 +3034,19 @@ const char *builtincgshaderstring =
 "      half3 diffusetex = color.rgb;\n"
 "#if defined(USESPECULAR) || defined(USEDEFERREDLIGHTMAP)\n"
 "# ifdef USEVERTEXTEXTUREBLEND\n"
-"      half3 glosstex = half3(lerp(float3(tex2D(Texture_SecondaryGloss, TexCoord2)), float3(tex2D(Texture_Gloss, TexCoord)), terrainblend));\n"
+"      half4 glosstex = half4(lerp(float4(tex2D(Texture_SecondaryGloss, TexCoord2)), float4(tex2D(Texture_Gloss, TexCoord)), terrainblend));\n"
 "# else\n"
-"      half3 glosstex = half3(tex2D(Texture_Gloss, TexCoord));\n"
+"      half4 glosstex = half4(tex2D(Texture_Gloss, TexCoord));\n"
 "# endif\n"
 "#endif\n"
 "\n"
+"#ifdef USEREFLECTCUBE\n"
+"      vec3 TangentReflectVector = reflect(-EyeVector, surfacenormal);\n"
+"      vec3 ModelReflectVector = TangentReflectVector.x * VectorS + TangentReflectVector.y * VectorT + TangentReflectVector.z * VectorR;\n"
+"      vec3 ReflectCubeTexCoord = float3(mul(ModelToReflectCube, float4(ModelReflectVector, 0)));\n"
+"      diffusetex += half3(tex2D(Texture_ReflectMask, TexCoord)) * half3(texCUBE(Texture_ReflectCube, ReflectCubeTexCoord));\n"
+"#endif\n"
+"\n"
 "\n"
 "\n"
 "\n"
@@ -2957,12 +3058,12 @@ const char *builtincgshaderstring =
 "      color.rgb = diffusetex * (Color_Ambient + diffuse * Color_Diffuse);\n"
 "#ifdef USESPECULAR\n"
 "#ifdef USEEXACTSPECULARMATH\n"
-"      half specular = pow(half(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
+"      half specular = pow(half(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower * glosstex.a);\n"
 "#else\n"
 "      half3 specularnormal = normalize(lightnormal + half3(normalize(EyeVector)));\n"
-"      half specular = pow(half(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
+"      half specular = pow(half(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * glosstex.a);\n"
 "#endif\n"
-"      color.rgb += glosstex * (specular * Color_Specular);\n"
+"      color.rgb += glosstex.rgb * (specular * Color_Specular);\n"
 "#endif\n"
 "#else\n"
 "      color.rgb = diffusetex * Color_Ambient;\n"
@@ -3051,12 +3152,12 @@ const char *builtincgshaderstring =
 "      half diffuse = half(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
 "#  ifdef USESPECULAR\n"
 "#   ifdef USEEXACTSPECULARMATH\n"
-"      half specular = pow(half(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
+"      half specular = pow(half(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower * glosstex.a);\n"
 "#   else\n"
 "      half3 specularnormal = normalize(lightnormal + half3(normalize(EyeVector)));\n"
-"      half specular = pow(half(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
+"      half specular = pow(half(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * glosstex.a);\n"
 "#   endif\n"
-"      color.rgb = diffusetex * Color_Ambient + (diffusetex * Color_Diffuse * diffuse + glosstex * Color_Specular * specular) * lightcolor;\n"
+"      color.rgb = diffusetex * Color_Ambient + (diffusetex * Color_Diffuse * diffuse + glosstex.rgb * Color_Specular * specular) * lightcolor;\n"
 "#  else\n"
 "      color.rgb = diffusetex * (Color_Ambient + Color_Diffuse * diffuse * lightcolor);\n"
 "#  endif\n"
@@ -3065,10 +3166,21 @@ const char *builtincgshaderstring =
 "# endif\n"
 "#endif\n"
 "\n"
+"#ifdef USESHADOWMAPORTHO\n"
+"      color.rgb *= ShadowMapCompare(ShadowMapTC,\n"
+"# if defined(USESHADOWMAP2D)\n"
+"Texture_ShadowMap2D, ShadowMap_Parameters, ShadowMap_TextureScale\n"
+"# endif\n"
+"# if defined(USESHADOWMAPRECT)\n"
+"Texture_ShadowMapRect, ShadowMap_Parameters\n"
+"# endif\n"
+"      );\n"
+"#endif\n"
+"\n"
 "#ifdef USEDEFERREDLIGHTMAP\n"
 "      float2 ScreenTexCoord = Pixel * PixelToScreenTexCoord;\n"
 "      color.rgb += diffusetex * half3(tex2D(Texture_ScreenDiffuse, ScreenTexCoord)) * DeferredMod_Diffuse;\n"
-"      color.rgb += glosstex * half3(tex2D(Texture_ScreenSpecular, ScreenTexCoord)) * DeferredMod_Specular;\n"
+"      color.rgb += glosstex.rgb * half3(tex2D(Texture_ScreenSpecular, ScreenTexCoord)) * DeferredMod_Specular;\n"
 "#endif\n"
 "\n"
 "#ifdef USEGLOW\n"
@@ -3169,10 +3281,12 @@ typedef enum shaderpermutation_e
        SHADERPERMUTATION_SHADOWMAPPCF2 = 1<<21, ///< (lightsource) use higher quality percentage closer filtering on shadowmap test results
        SHADERPERMUTATION_SHADOWSAMPLER = 1<<22, ///< (lightsource) use hardware shadowmap test
        SHADERPERMUTATION_SHADOWMAPVSDCT = 1<<23, ///< (lightsource) use virtual shadow depth cube texture for shadowmap indexing
-       SHADERPERMUTATION_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 = 26 ///< size of shaderpermutationinfo array
+       SHADERPERMUTATION_SHADOWMAPORTHO = 1<<24, //< (lightsource) use orthographic shadowmap projection
+       SHADERPERMUTATION_DEFERREDLIGHTMAP = 1<<25, ///< (lightmap) read Texture_ScreenDiffuse/Specular textures and add them on top of lightmapping
+       SHADERPERMUTATION_ALPHAKILL = 1<<26, ///< (deferredgeometry) discard pixel if diffuse texture alpha below 0.5
+       SHADERPERMUTATION_REFLECTCUBE = 1<<27, ///< fake reflections using global cubemap (not HDRI light probe)
+       SHADERPERMUTATION_LIMIT = 1<<28, ///< size of permutations array
+       SHADERPERMUTATION_COUNT = 28 ///< size of shaderpermutationinfo array
 }
 shaderpermutation_t;
 
@@ -3203,8 +3317,10 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
        {"#define USESHADOWMAPPCF 2\n", " shadowmappcf2"},
        {"#define USESHADOWSAMPLER\n", " shadowsampler"},
        {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"},
+       {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
        {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
        {"#define USEALPHAKILL\n", " alphakill"},
+       {"#define USEREFLECTCUBE\n", " reflectcube"},
 };
 
 /// this enum is multiplied by SHADERPERMUTATION_MODEBASE
@@ -3311,6 +3427,8 @@ typedef struct r_glsl_permutation_s
        int loc_Texture_ScreenNormalMap;
        int loc_Texture_ScreenDiffuse;
        int loc_Texture_ScreenSpecular;
+       int loc_Texture_ReflectMask;
+       int loc_Texture_ReflectCube;
        int loc_Alpha;
        int loc_BloomBlur_Parameters;
        int loc_ClientTime;
@@ -3360,6 +3478,8 @@ typedef struct r_glsl_permutation_s
        int loc_ModelViewProjectionMatrix;
        int loc_ModelViewMatrix;
        int loc_PixelToScreenTexCoord;
+       int loc_ModelToReflectCube;
+       int loc_ShadowMapMatrix;        
 }
 r_glsl_permutation_t;
 
@@ -3533,6 +3653,8 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                p->loc_Texture_ScreenNormalMap    = qglGetUniformLocationARB(p->program, "Texture_ScreenNormalMap");
                p->loc_Texture_ScreenDiffuse      = qglGetUniformLocationARB(p->program, "Texture_ScreenDiffuse");
                p->loc_Texture_ScreenSpecular     = qglGetUniformLocationARB(p->program, "Texture_ScreenSpecular");
+               p->loc_Texture_ReflectMask        = qglGetUniformLocationARB(p->program, "Texture_ReflectMask");
+               p->loc_Texture_ReflectCube        = qglGetUniformLocationARB(p->program, "Texture_ReflectCube");
                p->loc_Alpha                      = qglGetUniformLocationARB(p->program, "Alpha");
                p->loc_BloomBlur_Parameters       = qglGetUniformLocationARB(p->program, "BloomBlur_Parameters");
                p->loc_ClientTime                 = qglGetUniformLocationARB(p->program, "ClientTime");
@@ -3582,6 +3704,8 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                p->loc_ModelViewMatrix            = qglGetUniformLocationARB(p->program, "ModelViewMatrix");
                p->loc_ModelViewProjectionMatrix  = qglGetUniformLocationARB(p->program, "ModelViewProjectionMatrix");
                p->loc_PixelToScreenTexCoord      = qglGetUniformLocationARB(p->program, "PixelToScreenTexCoord");
+               p->loc_ModelToReflectCube         = qglGetUniformLocationARB(p->program, "ModelToReflectCube");
+               p->loc_ShadowMapMatrix            = qglGetUniformLocationARB(p->program, "ShadowMapMatrix");            
                // initialize the samplers to refer to the texture units we use
                if (p->loc_Texture_First           >= 0) qglUniform1iARB(p->loc_Texture_First          , GL20TU_FIRST);
                if (p->loc_Texture_Second          >= 0) qglUniform1iARB(p->loc_Texture_Second         , GL20TU_SECOND);
@@ -3603,14 +3727,16 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                if (p->loc_Texture_Cube            >= 0) qglUniform1iARB(p->loc_Texture_Cube           , GL20TU_CUBE);
                if (p->loc_Texture_Refraction      >= 0) qglUniform1iARB(p->loc_Texture_Refraction     , GL20TU_REFRACTION);
                if (p->loc_Texture_Reflection      >= 0) qglUniform1iARB(p->loc_Texture_Reflection     , GL20TU_REFLECTION);
-               if (p->loc_Texture_ShadowMapRect   >= 0) qglUniform1iARB(p->loc_Texture_ShadowMapRect  , GL20TU_SHADOWMAPRECT);
+               if (p->loc_Texture_ShadowMapRect   >= 0) qglUniform1iARB(p->loc_Texture_ShadowMapRect  , permutation & SHADERPERMUTATION_SHADOWMAPORTHO ? GL20TU_SHADOWMAPORTHORECT : GL20TU_SHADOWMAPRECT);
                if (p->loc_Texture_ShadowMapCube   >= 0) qglUniform1iARB(p->loc_Texture_ShadowMapCube  , GL20TU_SHADOWMAPCUBE);
-               if (p->loc_Texture_ShadowMap2D     >= 0) qglUniform1iARB(p->loc_Texture_ShadowMap2D    , GL20TU_SHADOWMAP2D);
+               if (p->loc_Texture_ShadowMap2D     >= 0) qglUniform1iARB(p->loc_Texture_ShadowMap2D    , permutation & SHADERPERMUTATION_SHADOWMAPORTHO ? GL20TU_SHADOWMAPORTHO2D : GL20TU_SHADOWMAP2D);
                if (p->loc_Texture_CubeProjection  >= 0) qglUniform1iARB(p->loc_Texture_CubeProjection , GL20TU_CUBEPROJECTION);
                if (p->loc_Texture_ScreenDepth     >= 0) qglUniform1iARB(p->loc_Texture_ScreenDepth    , GL20TU_SCREENDEPTH);
                if (p->loc_Texture_ScreenNormalMap >= 0) qglUniform1iARB(p->loc_Texture_ScreenNormalMap, GL20TU_SCREENNORMALMAP);
                if (p->loc_Texture_ScreenDiffuse   >= 0) qglUniform1iARB(p->loc_Texture_ScreenDiffuse  , GL20TU_SCREENDIFFUSE);
                if (p->loc_Texture_ScreenSpecular  >= 0) qglUniform1iARB(p->loc_Texture_ScreenSpecular , GL20TU_SCREENSPECULAR);
+               if (p->loc_Texture_ReflectMask     >= 0) qglUniform1iARB(p->loc_Texture_ReflectMask    , GL20TU_REFLECTMASK);
+               if (p->loc_Texture_ReflectCube     >= 0) qglUniform1iARB(p->loc_Texture_ReflectCube    , GL20TU_REFLECTCUBE);
                CHECKGLERROR
                Con_DPrintf("^5GLSL shader %s compiled.\n", permutationname);
        }
@@ -3667,6 +3793,7 @@ void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int permutatio
        }
        if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fvARB(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
        if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fvARB(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
+       if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1fARB(r_glsl_permutation->loc_ClientTime, cl.time);
 }
 
 #ifdef SUPPORTCG
@@ -3694,6 +3821,7 @@ typedef struct r_cg_permutation_s
        CGparameter vp_BackgroundTexMatrix;
        CGparameter vp_ModelViewProjectionMatrix;
        CGparameter vp_ModelViewMatrix;
+       CGparameter vp_ShadowMapMatrix;
 
        CGparameter fp_Texture_First;
        CGparameter fp_Texture_Second;
@@ -3723,6 +3851,8 @@ typedef struct r_cg_permutation_s
        CGparameter fp_Texture_ScreenNormalMap;
        CGparameter fp_Texture_ScreenDiffuse;
        CGparameter fp_Texture_ScreenSpecular;
+       CGparameter fp_Texture_ReflectMask;
+       CGparameter fp_Texture_ReflectCube;
        CGparameter fp_Alpha;
        CGparameter fp_BloomBlur_Parameters;
        CGparameter fp_ClientTime;
@@ -3767,6 +3897,7 @@ typedef struct r_cg_permutation_s
        CGparameter fp_ViewTintColor;
        CGparameter fp_ViewToLight;
        CGparameter fp_PixelToScreenTexCoord;
+       CGparameter fp_ModelToReflectCube;
 }
 r_cg_permutation_t;
 
@@ -3982,6 +4113,7 @@ static void R_CG_CompilePermutation(r_cg_permutation_t *p, unsigned int mode, un
                p->vp_BackgroundTexMatrix        = cgGetNamedParameter(p->vprogram, "BackgroundTexMatrix");
                p->vp_ModelViewProjectionMatrix  = cgGetNamedParameter(p->vprogram, "ModelViewProjectionMatrix");
                p->vp_ModelViewMatrix            = cgGetNamedParameter(p->vprogram, "ModelViewMatrix");
+               p->vp_ShadowMapMatrix            = cgGetNamedParameter(p->vprogram, "ShadowMapMatrix");
                CHECKCGERROR
        }
        if (p->fprogram)
@@ -4017,6 +4149,8 @@ static void R_CG_CompilePermutation(r_cg_permutation_t *p, unsigned int mode, un
                p->fp_Texture_ScreenNormalMap    = cgGetNamedParameter(p->fprogram, "Texture_ScreenNormalMap");
                p->fp_Texture_ScreenDiffuse      = cgGetNamedParameter(p->fprogram, "Texture_ScreenDiffuse");
                p->fp_Texture_ScreenSpecular     = cgGetNamedParameter(p->fprogram, "Texture_ScreenSpecular");
+               p->fp_Texture_ReflectMask        = cgGetNamedParameter(p->fprogram, "Texture_ReflectMask");
+               p->fp_Texture_ReflectCube        = cgGetNamedParameter(p->fprogram, "Texture_ReflectCube");
                p->fp_Alpha                      = cgGetNamedParameter(p->fprogram, "Alpha");
                p->fp_BloomBlur_Parameters       = cgGetNamedParameter(p->fprogram, "BloomBlur_Parameters");
                p->fp_ClientTime                 = cgGetNamedParameter(p->fprogram, "ClientTime");
@@ -4061,6 +4195,7 @@ static void R_CG_CompilePermutation(r_cg_permutation_t *p, unsigned int mode, un
                p->fp_ViewTintColor              = cgGetNamedParameter(p->fprogram, "ViewTintColor");
                p->fp_ViewToLight                = cgGetNamedParameter(p->fprogram, "ViewToLight");
                p->fp_PixelToScreenTexCoord      = cgGetNamedParameter(p->fprogram, "PixelToScreenTexCoord");
+               p->fp_ModelToReflectCube         = cgGetNamedParameter(p->fprogram, "ModelToReflectCube");
                CHECKCGERROR
        }
 
@@ -4149,6 +4284,7 @@ void R_SetupShader_SetPermutationCG(unsigned int mode, unsigned int permutation)
        CHECKCGERROR
        if (r_cg_permutation->vp_ModelViewProjectionMatrix) cgGLSetMatrixParameterfc(r_cg_permutation->vp_ModelViewProjectionMatrix, gl_modelviewprojection16f);CHECKCGERROR
        if (r_cg_permutation->vp_ModelViewMatrix) cgGLSetMatrixParameterfc(r_cg_permutation->vp_ModelViewMatrix, gl_modelview16f);CHECKCGERROR
+       if (r_cg_permutation->fp_ClientTime) cgGLSetParameter1f(r_cg_permutation->fp_ClientTime, cl.time);CHECKCGERROR
 }
 
 void CG_BindTexture(CGparameter param, rtexture_t *tex)
@@ -4339,6 +4475,7 @@ extern rtexture_t *r_shadow_attenuation3dtexture;
 extern qboolean r_shadow_usingshadowmaprect;
 extern qboolean r_shadow_usingshadowmapcube;
 extern qboolean r_shadow_usingshadowmap2d;
+extern qboolean r_shadow_usingshadowmaportho;
 extern float r_shadow_shadowmap_texturescale[2];
 extern float r_shadow_shadowmap_parameters[4];
 extern qboolean r_shadow_shadowmapvsdct;
@@ -4348,6 +4485,7 @@ extern rtexture_t *r_shadow_shadowmaprectangletexture;
 extern rtexture_t *r_shadow_shadowmap2dtexture;
 extern rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
 extern rtexture_t *r_shadow_shadowmapvsdcttexture;
+extern matrix4x4_t r_shadow_shadowmapmatrix;
 extern int r_shadow_shadowmaplod; // changes for each light based on distance
 extern int r_shadow_prepass_width;
 extern int r_shadow_prepass_height;
@@ -4454,6 +4592,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        else if (r_shadow_shadowmappcf)
                                permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
                }
+               if (rsurface.texture->reflectmasktexture)
+                       permutation |= SHADERPERMUTATION_REFLECTCUBE;
                R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING))
                {
@@ -4494,8 +4634,25 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE;
                if (rsurface.texture->colormapping)
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
+               if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
+               {
+                       permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
+                       if (r_shadow_usingshadowmaprect)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
+                       if (r_shadow_usingshadowmap2d)
+                               permutation |= SHADERPERMUTATION_SHADOWMAP2D;
+
+                       if (r_shadow_shadowmapsampler)
+                               permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
+                       if (r_shadow_shadowmappcf > 1)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
+                       else if (r_shadow_shadowmappcf)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+               }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
+               if (rsurface.texture->reflectmasktexture)
+                       permutation |= SHADERPERMUTATION_REFLECTCUBE;
                R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING))
                {
@@ -4542,10 +4699,27 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE;
                if (rsurface.texture->colormapping)
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
+               if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
+               {
+                       permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
+                       if (r_shadow_usingshadowmaprect)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
+                       if (r_shadow_usingshadowmap2d)
+                               permutation |= SHADERPERMUTATION_SHADOWMAP2D;
+
+                       if (r_shadow_shadowmapsampler)
+                               permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
+                       if (r_shadow_shadowmappcf > 1)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
+                       else if (r_shadow_shadowmappcf)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+               }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
                if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
                        permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
+               if (rsurface.texture->reflectmasktexture)
+                       permutation |= SHADERPERMUTATION_REFLECTCUBE;
                R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING))
                {
@@ -4582,10 +4756,27 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE;
                if (rsurface.texture->colormapping)
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
+               if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
+               {
+                       permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
+                       if (r_shadow_usingshadowmaprect)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
+                       if (r_shadow_usingshadowmap2d)
+                               permutation |= SHADERPERMUTATION_SHADOWMAP2D;
+
+                       if (r_shadow_shadowmapsampler)
+                               permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
+                       if (r_shadow_shadowmappcf > 1)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
+                       else if (r_shadow_shadowmappcf)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+               }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
                if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
                        permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
+               if (rsurface.texture->reflectmasktexture)
+                       permutation |= SHADERPERMUTATION_REFLECTCUBE;
                R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING))
                {
@@ -4621,10 +4812,27 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE;
                if (rsurface.texture->colormapping)
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
+               if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
+               {
+                       permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
+                       if (r_shadow_usingshadowmaprect)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
+                       if (r_shadow_usingshadowmap2d)
+                               permutation |= SHADERPERMUTATION_SHADOWMAP2D;
+
+                       if (r_shadow_shadowmapsampler)
+                               permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
+                       if (r_shadow_shadowmappcf > 1)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
+                       else if (r_shadow_shadowmappcf)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+               }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
                if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
                        permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
+               if (rsurface.texture->reflectmasktexture)
+                       permutation |= SHADERPERMUTATION_REFLECTCUBE;
                if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
                {
                        // deluxemapping (light direction texture)
@@ -4699,6 +4907,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        {
        case RENDERPATH_GL20:
                R_SetupShader_SetPermutationGLSL(mode, permutation);
+               if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
                if (mode == SHADERMODE_LIGHTSOURCE)
                {
                        if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
@@ -4711,8 +4920,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        // 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
@@ -4758,6 +4965,10 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                }
                if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
                if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
+               if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
+               if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2fARB(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
+               if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4fARB(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+
                if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]);
                if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1fARB(r_glsl_permutation->loc_Alpha, rsurface.texture->lightmapcolor[3]);
                if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
@@ -4796,6 +5007,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                if (r_glsl_permutation->loc_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(GL20TU_SECONDARY_GLOW    , rsurface.texture->backgroundglowtexture             );
                if (r_glsl_permutation->loc_Texture_Pants           >= 0) R_Mesh_TexBind(GL20TU_PANTS             , rsurface.texture->pantstexture                      );
                if (r_glsl_permutation->loc_Texture_Shirt           >= 0) R_Mesh_TexBind(GL20TU_SHIRT             , rsurface.texture->shirttexture                      );
+               if (r_glsl_permutation->loc_Texture_ReflectMask     >= 0) R_Mesh_TexBind(GL20TU_REFLECTMASK       , rsurface.texture->reflectmasktexture                );
+               if (r_glsl_permutation->loc_Texture_ReflectCube     >= 0) R_Mesh_TexBind(GL20TU_REFLECTCUBE       , rsurface.texture->reflectcubetexture ? rsurface.texture->reflectcubetexture : r_texture_whitecube);
                if (r_glsl_permutation->loc_Texture_FogMask         >= 0) R_Mesh_TexBind(GL20TU_FOGMASK           , r_texture_fogattenuation                            );
                if (r_glsl_permutation->loc_Texture_Lightmap        >= 0) R_Mesh_TexBind(GL20TU_LIGHTMAP          , r_texture_white                                     );
                if (r_glsl_permutation->loc_Texture_Deluxemap       >= 0) R_Mesh_TexBind(GL20TU_LIGHTMAP          , r_texture_blanknormalmap                            );
@@ -4806,20 +5019,24 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                if (r_glsl_permutation->loc_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(GL20TU_SCREENNORMALMAP   , r_shadow_prepassgeometrynormalmaptexture            );
                if (r_glsl_permutation->loc_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(GL20TU_SCREENDIFFUSE     , r_shadow_prepasslightingdiffusetexture              );
                if (r_glsl_permutation->loc_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(GL20TU_SCREENSPECULAR    , r_shadow_prepasslightingspeculartexture             );
-               if (rsurface.rtlight)
+               if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
                {
-                       if (r_glsl_permutation->loc_Texture_Cube            >= 0) R_Mesh_TexBind(GL20TU_CUBE              , rsurface.rtlight->currentcubemap                    );
-                       if (r_glsl_permutation->loc_Texture_ShadowMapRect   >= 0) R_Mesh_TexBind(GL20TU_SHADOWMAPRECT     , r_shadow_shadowmaprectangletexture                  );
-                       if (r_shadow_usingshadowmapcube)
-                               if (r_glsl_permutation->loc_Texture_ShadowMapCube   >= 0) R_Mesh_TexBind(GL20TU_SHADOWMAPCUBE     , r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
-                       if (r_glsl_permutation->loc_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(GL20TU_SHADOWMAP2D       , r_shadow_shadowmap2dtexture                         );
-                       if (r_glsl_permutation->loc_Texture_CubeProjection  >= 0) R_Mesh_TexBind(GL20TU_CUBEPROJECTION    , r_shadow_shadowmapvsdcttexture                      );
+                       if (r_glsl_permutation->loc_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_shadow_usingshadowmaportho ? GL20TU_SHADOWMAPORTHO2D : GL20TU_SHADOWMAP2D, r_shadow_shadowmap2dtexture                         );
+                       if (r_glsl_permutation->loc_Texture_ShadowMapRect   >= 0) R_Mesh_TexBind(r_shadow_usingshadowmaportho ? GL20TU_SHADOWMAPORTHORECT : GL20TU_SHADOWMAPRECT, r_shadow_shadowmaprectangletexture                  );
+                       if (rsurface.rtlight)
+                       {
+                               if (r_glsl_permutation->loc_Texture_Cube            >= 0) R_Mesh_TexBind(GL20TU_CUBE              , rsurface.rtlight->currentcubemap                    );
+                               if (r_shadow_usingshadowmapcube)
+                                       if (r_glsl_permutation->loc_Texture_ShadowMapCube   >= 0) R_Mesh_TexBind(GL20TU_SHADOWMAPCUBE     , r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
+                               if (r_glsl_permutation->loc_Texture_CubeProjection  >= 0) R_Mesh_TexBind(GL20TU_CUBEPROJECTION    , r_shadow_shadowmapvsdcttexture                      );
+                       }
                }
                CHECKGLERROR
                break;
        case RENDERPATH_CGGL:
 #ifdef SUPPORTCG
                R_SetupShader_SetPermutationCG(mode, permutation);
+               if (r_cg_permutation->fp_ModelToReflectCube) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);cgGLSetMatrixParameterfc(r_cg_permutation->fp_ModelToReflectCube, m16f);}CHECKCGERROR
                if (mode == SHADERMODE_LIGHTSOURCE)
                {
                        if (r_cg_permutation->vp_ModelToLight) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);cgGLSetMatrixParameterfc(r_cg_permutation->vp_ModelToLight, m16f);}CHECKCGERROR
@@ -4834,6 +5051,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                }
                if (r_cg_permutation->vp_TexMatrix) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);cgGLSetMatrixParameterfc(r_cg_permutation->vp_TexMatrix, m16f);}CHECKCGERROR
                if (r_cg_permutation->vp_BackgroundTexMatrix) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);cgGLSetMatrixParameterfc(r_cg_permutation->vp_BackgroundTexMatrix, m16f);}CHECKCGERROR
+               if (r_cg_permutation->vp_ShadowMapMatrix) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);cgGLSetMatrixParameterfc(r_cg_permutation->vp_ShadowMapMatrix, m16f);}CHECKGLERROR
                if (r_cg_permutation->vp_EyePosition) cgGLSetParameter3f(r_cg_permutation->vp_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);CHECKCGERROR
                if (r_cg_permutation->vp_FogPlane) cgGLSetParameter4f(r_cg_permutation->vp_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);CHECKCGERROR
                CHECKGLERROR
@@ -4848,8 +5066,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
 
                        // 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
@@ -4894,6 +5110,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        if (r_cg_permutation->fp_ReflectOffset) cgGLSetParameter1f(r_cg_permutation->fp_ReflectOffset, rsurface.texture->reflectmin);CHECKCGERROR
                        if (r_cg_permutation->fp_SpecularPower) cgGLSetParameter1f(r_cg_permutation->fp_SpecularPower, rsurface.texture->specularpower * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));CHECKCGERROR
                }
+               if (r_cg_permutation->fp_ShadowMap_TextureScale) cgGLSetParameter2f(r_cg_permutation->fp_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);CHECKCGERROR
+               if (r_cg_permutation->fp_ShadowMap_Parameters) cgGLSetParameter4f(r_cg_permutation->fp_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);CHECKCGERROR
                if (r_cg_permutation->fp_Color_Glow) cgGLSetParameter3f(r_cg_permutation->fp_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]);CHECKCGERROR
                if (r_cg_permutation->fp_Alpha) cgGLSetParameter1f(r_cg_permutation->fp_Alpha, rsurface.texture->lightmapcolor[3]);CHECKCGERROR
                if (r_cg_permutation->fp_EyePosition) cgGLSetParameter3f(r_cg_permutation->fp_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);CHECKCGERROR
@@ -4934,6 +5152,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                if (r_cg_permutation->fp_Texture_SecondaryGlow  ) CG_BindTexture(r_cg_permutation->fp_Texture_SecondaryGlow  , rsurface.texture->backgroundglowtexture             );CHECKCGERROR
                if (r_cg_permutation->fp_Texture_Pants          ) CG_BindTexture(r_cg_permutation->fp_Texture_Pants          , rsurface.texture->pantstexture                      );CHECKCGERROR
                if (r_cg_permutation->fp_Texture_Shirt          ) CG_BindTexture(r_cg_permutation->fp_Texture_Shirt          , rsurface.texture->shirttexture                      );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ReflectMask    ) CG_BindTexture(r_cg_permutation->fp_Texture_ReflectMask    , rsurface.texture->reflectmasktexture                );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_ReflectCube    ) CG_BindTexture(r_cg_permutation->fp_Texture_ReflectCube    , rsurface.texture->reflectcubetexture ? rsurface.texture->reflectcubetexture : r_texture_whitecube);CHECKCGERROR
                if (r_cg_permutation->fp_Texture_FogMask        ) CG_BindTexture(r_cg_permutation->fp_Texture_FogMask        , r_texture_fogattenuation                            );CHECKCGERROR
                if (r_cg_permutation->fp_Texture_Lightmap       ) CG_BindTexture(r_cg_permutation->fp_Texture_Lightmap       , r_texture_white                                     );CHECKCGERROR
                if (r_cg_permutation->fp_Texture_Deluxemap      ) CG_BindTexture(r_cg_permutation->fp_Texture_Deluxemap      , r_texture_blanknormalmap                            );CHECKCGERROR
@@ -4944,14 +5164,17 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                if (r_cg_permutation->fp_Texture_ScreenNormalMap) CG_BindTexture(r_cg_permutation->fp_Texture_ScreenNormalMap, r_shadow_prepassgeometrynormalmaptexture            );CHECKCGERROR
                if (r_cg_permutation->fp_Texture_ScreenDiffuse  ) CG_BindTexture(r_cg_permutation->fp_Texture_ScreenDiffuse  , r_shadow_prepasslightingdiffusetexture              );CHECKCGERROR
                if (r_cg_permutation->fp_Texture_ScreenSpecular ) CG_BindTexture(r_cg_permutation->fp_Texture_ScreenSpecular , r_shadow_prepasslightingspeculartexture             );CHECKCGERROR
-               if (rsurface.rtlight)
+               if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
                {
-                       if (r_cg_permutation->fp_Texture_Cube           ) CG_BindTexture(r_cg_permutation->fp_Texture_Cube           , rsurface.rtlight->currentcubemap                    );CHECKCGERROR
-                       if (r_cg_permutation->fp_Texture_ShadowMapRect  ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMapRect  , r_shadow_shadowmaprectangletexture                  );CHECKCGERROR
-                       if (r_shadow_usingshadowmapcube)
-                               if (r_cg_permutation->fp_Texture_ShadowMapCube  ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMapCube  , r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);CHECKCGERROR
                        if (r_cg_permutation->fp_Texture_ShadowMap2D    ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMap2D    , r_shadow_shadowmap2dtexture                         );CHECKCGERROR
-                       if (r_cg_permutation->fp_Texture_CubeProjection ) CG_BindTexture(r_cg_permutation->fp_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture                      );CHECKCGERROR
+                       if (r_cg_permutation->fp_Texture_ShadowMapRect  ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMapRect  , r_shadow_shadowmaprectangletexture                  );CHECKCGERROR
+                       if (rsurface.rtlight)
+                       {
+                               if (r_cg_permutation->fp_Texture_Cube           ) CG_BindTexture(r_cg_permutation->fp_Texture_Cube           , rsurface.rtlight->currentcubemap                    );CHECKCGERROR
+                               if (r_shadow_usingshadowmapcube)
+                                       if (r_cg_permutation->fp_Texture_ShadowMapCube  ) CG_BindTexture(r_cg_permutation->fp_Texture_ShadowMapCube  , r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);CHECKCGERROR
+                               if (r_cg_permutation->fp_Texture_CubeProjection ) CG_BindTexture(r_cg_permutation->fp_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture                      );CHECKCGERROR
+                       }
                }
 
                CHECKGLERROR
@@ -5121,6 +5344,7 @@ void R_SkinFrame_Purge(void)
                                R_PurgeTexture(s->gloss );s->gloss  = NULL;
                                R_PurgeTexture(s->glow  );s->glow   = NULL;
                                R_PurgeTexture(s->fog   );s->fog    = NULL;
+                               R_PurgeTexture(s->reflect);s->reflect = NULL;
                                s->loadsequence = 0;
                        }
                }
@@ -5257,7 +5481,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        // check for DDS texture file first
        if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s.dds", basename), textureflags, &ddshasalpha, ddsavgcolor)))
        {
-               basepixels = loadimagepixelsbgra(name, complain, true);
+               basepixels = loadimagepixelsbgra(name, complain, true, r_texture_convertsRGB_skin.integer);
                if (basepixels == NULL)
                        return NULL;
        }
@@ -5277,6 +5501,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        skinframe->gloss = NULL;
        skinframe->glow = NULL;
        skinframe->fog = NULL;
+       skinframe->reflect = NULL;
        skinframe->hasalpha = false;
 
        if (ddsbase)
@@ -5335,18 +5560,19 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                        skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_gloss.dds", skinframe->basename), textureflags, NULL, NULL);
                skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_pants.dds", skinframe->basename), textureflags, NULL, NULL);
                skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_shirt.dds", skinframe->basename), textureflags, NULL, NULL);
+               skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_reflect.dds", skinframe->basename), textureflags, NULL, NULL);
        }
 
        // _norm is the name used by tenebrae and has been adopted as standard
        if (r_loadnormalmap && skinframe->nmap == NULL)
        {
-               if ((pixels = loadimagepixelsbgra(va("%s_norm", skinframe->basename), false, false)) != NULL)
+               if ((pixels = loadimagepixelsbgra(va("%s_norm", skinframe->basename), false, false, false)) != NULL)
                {
                        skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | skinframe->textureflags) & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL);
                        Mem_Free(pixels);
                        pixels = NULL;
                }
-               else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va("%s_bump", skinframe->basename), false, false)) != NULL)
+               else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va("%s_bump", skinframe->basename), false, false, false)) != NULL)
                {
                        pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
                        Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
@@ -5367,7 +5593,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
 
        // _luma is supported only for tenebrae compatibility
        // _glow is the preferred name
-       if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va("%s_glow",  skinframe->basename), false, false)) || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false))))
+       if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va("%s_glow",  skinframe->basename), false, false, r_texture_convertsRGB_skin.integer)) || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer))))
        {
                skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_glow.integer ? ~0 : ~TEXF_COMPRESS), NULL);
                if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow)
@@ -5375,7 +5601,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                Mem_Free(pixels);pixels = NULL;
        }
 
-       if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false)))
+       if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer)))
        {
                skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_gloss.integer ? ~0 : ~TEXF_COMPRESS), NULL);
                if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss)
@@ -5384,7 +5610,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                pixels = NULL;
        }
 
-       if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false)))
+       if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer)))
        {
                skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);
                if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants)
@@ -5393,7 +5619,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                pixels = NULL;
        }
 
-       if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false)))
+       if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer)))
        {
                skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);
                if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt)
@@ -5402,6 +5628,15 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                pixels = NULL;
        }
 
+       if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va("%s_reflect", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer)))
+       {
+               skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va("%s_reflect", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_reflectmask.integer ? ~0 : ~TEXF_COMPRESS), NULL);
+               if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect)
+                       R_SaveTextureDDSFile(skinframe->reflect, va("dds/%s_reflect.dds", skinframe->basename), true);
+               Mem_Free(pixels);
+               pixels = NULL;
+       }
+
        if (basepixels)
                Mem_Free(basepixels);
 
@@ -5432,6 +5667,7 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co
        skinframe->gloss = NULL;
        skinframe->glow = NULL;
        skinframe->fog = NULL;
+       skinframe->reflect = NULL;
        skinframe->hasalpha = false;
 
        // if no data was provided, then clearly the caller wanted to get a blank skinframe
@@ -5500,6 +5736,7 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i
        skinframe->gloss = NULL;
        skinframe->glow = NULL;
        skinframe->fog = NULL;
+       skinframe->reflect = NULL;
        skinframe->hasalpha = false;
 
        // if no data was provided, then clearly the caller wanted to get a blank skinframe
@@ -5620,6 +5857,7 @@ skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, co
        skinframe->gloss = NULL;
        skinframe->glow = NULL;
        skinframe->fog = NULL;
+       skinframe->reflect = NULL;
        skinframe->hasalpha = false;
 
        // if no data was provided, then clearly the caller wanted to get a blank skinframe
@@ -5667,6 +5905,7 @@ skinframe_t *R_SkinFrame_LoadMissing(void)
        skinframe->gloss = NULL;
        skinframe->glow = NULL;
        skinframe->fog = NULL;
+       skinframe->reflect = NULL;
        skinframe->hasalpha = false;
 
        skinframe->avgcolor[0] = rand() / RAND_MAX;
@@ -5677,6 +5916,136 @@ skinframe_t *R_SkinFrame_LoadMissing(void)
        return skinframe;
 }
 
+//static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
+typedef struct suffixinfo_s
+{
+       char *suffix;
+       qboolean flipx, flipy, flipdiagonal;
+}
+suffixinfo_t;
+static suffixinfo_t suffix[3][6] =
+{
+       {
+               {"px",   false, false, false},
+               {"nx",   false, false, false},
+               {"py",   false, false, false},
+               {"ny",   false, false, false},
+               {"pz",   false, false, false},
+               {"nz",   false, false, false}
+       },
+       {
+               {"posx", false, false, false},
+               {"negx", false, false, false},
+               {"posy", false, false, false},
+               {"negy", false, false, false},
+               {"posz", false, false, false},
+               {"negz", false, false, false}
+       },
+       {
+               {"rt",    true, false,  true},
+               {"lf",   false,  true,  true},
+               {"ft",    true,  true, false},
+               {"bk",   false, false, false},
+               {"up",    true, false,  true},
+               {"dn",    true, false,  true}
+       }
+};
+
+static int componentorder[4] = {0, 1, 2, 3};
+
+rtexture_t *R_LoadCubemap(const char *basename)
+{
+       int i, j, cubemapsize;
+       unsigned char *cubemappixels, *image_buffer;
+       rtexture_t *cubemaptexture;
+       char name[256];
+       // must start 0 so the first loadimagepixels has no requested width/height
+       cubemapsize = 0;
+       cubemappixels = NULL;
+       cubemaptexture = NULL;
+       // keep trying different suffix groups (posx, px, rt) until one loads
+       for (j = 0;j < 3 && !cubemappixels;j++)
+       {
+               // load the 6 images in the suffix group
+               for (i = 0;i < 6;i++)
+               {
+                       // generate an image name based on the base and and suffix
+                       dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
+                       // load it
+                       if ((image_buffer = loadimagepixelsbgra(name, false, false, r_texture_convertsRGB_cubemap.integer)))
+                       {
+                               // an image loaded, make sure width and height are equal
+                               if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
+                               {
+                                       // if this is the first image to load successfully, allocate the cubemap memory
+                                       if (!cubemappixels && image_width >= 1)
+                                       {
+                                               cubemapsize = image_width;
+                                               // note this clears to black, so unavailable sides are black
+                                               cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
+                                       }
+                                       // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
+                                       if (cubemappixels)
+                                               Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
+                               }
+                               else
+                                       Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
+                               // free the image
+                               Mem_Free(image_buffer);
+                       }
+               }
+       }
+       // if a cubemap loaded, upload it
+       if (cubemappixels)
+       {
+               if (developer_loading.integer)
+                       Con_Printf("loading cubemap \"%s\"\n", basename);
+
+               cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
+               Mem_Free(cubemappixels);
+       }
+       else
+       {
+               Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
+               if (developer_loading.integer)
+               {
+                       Con_Printf("(tried tried images ");
+                       for (j = 0;j < 3;j++)
+                               for (i = 0;i < 6;i++)
+                                       Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
+                       Con_Print(" and was unable to find any of them).\n");
+               }
+       }
+       return cubemaptexture;
+}
+
+rtexture_t *R_GetCubemap(const char *basename)
+{
+       int i;
+       for (i = 0;i < r_texture_numcubemaps;i++)
+               if (!strcasecmp(r_texture_cubemaps[i].basename, basename))
+                       return r_texture_cubemaps[i].texture ? r_texture_cubemaps[i].texture : r_texture_whitecube;
+       if (i >= MAX_CUBEMAPS)
+               return r_texture_whitecube;
+       r_texture_numcubemaps++;
+       strlcpy(r_texture_cubemaps[i].basename, basename, sizeof(r_texture_cubemaps[i].basename));
+       r_texture_cubemaps[i].texture = R_LoadCubemap(r_texture_cubemaps[i].basename);
+       return r_texture_cubemaps[i].texture;
+}
+
+void R_FreeCubemaps(void)
+{
+       int i;
+       for (i = 0;i < r_texture_numcubemaps;i++)
+       {
+               if (developer_loading.integer)
+                       Con_DPrintf("unloading cubemap \"%s\"\n", r_texture_cubemaps[i].basename);
+               if (r_texture_cubemaps[i].texture)
+                       R_FreeTexture(r_texture_cubemaps[i].texture);
+       }
+       r_texture_numcubemaps = 0;
+}
+
 void R_Main_FreeViewCache(void)
 {
        if (r_refdef.viewcache.entityvisible)
@@ -5740,6 +6109,7 @@ void gl_main_start(void)
        r_texture_normalizationcube = NULL;
        r_texture_fogattenuation = NULL;
        r_texture_gammaramps = NULL;
+       r_texture_numcubemaps = 0;
 
        r_loaddds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_load.integer;
        r_savedds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
@@ -5848,6 +6218,7 @@ void gl_main_shutdown(void)
        r_texture_normalizationcube = NULL;
        r_texture_fogattenuation = NULL;
        r_texture_gammaramps = NULL;
+       r_texture_numcubemaps = 0;
        //r_texture_fogintensity = NULL;
        memset(&r_bloomstate, 0, sizeof(r_bloomstate));
        memset(&r_waterstate, 0, sizeof(r_waterstate));
@@ -5960,6 +6331,11 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_transparentdepthmasking);
        Cvar_RegisterVariable(&r_texture_dds_load);
        Cvar_RegisterVariable(&r_texture_dds_save);
+       Cvar_RegisterVariable(&r_texture_convertsRGB_2d);
+       Cvar_RegisterVariable(&r_texture_convertsRGB_skin);
+       Cvar_RegisterVariable(&r_texture_convertsRGB_cubemap);
+       Cvar_RegisterVariable(&r_texture_convertsRGB_skybox);
+       Cvar_RegisterVariable(&r_texture_convertsRGB_particles);
        Cvar_RegisterVariable(&r_textureunits);
        Cvar_RegisterVariable(&gl_combine);
        Cvar_RegisterVariable(&r_glsl);
@@ -6340,11 +6716,6 @@ void R_AnimCache_CacheVisibleEntities(void)
        for (i = 0;i < r_refdef.scene.numentities;i++)
                if (r_refdef.viewcache.entityvisible[i])
                        R_AnimCache_GetEntity(r_refdef.scene.entities[i], wantnormals, wanttangents);
-
-       if (r_shadows.integer)
-               for (i = 0;i < r_refdef.scene.numentities;i++)
-                       if (!r_refdef.viewcache.entityvisible[i])
-                               R_AnimCache_GetEntity(r_refdef.scene.entities[i], false, false);
 }
 
 //==================================================================================
@@ -6457,6 +6828,10 @@ static qboolean R_CanSeeBox(int numsamples, vec_t enlarge, vec3_t eye, vec3_t en
        boxmins[2] = (enlarge+1) * entboxmins[2] - enlarge * entboxmaxs[2];
        boxmaxs[2] = (enlarge+1) * entboxmaxs[2] - enlarge * entboxmins[2];
 
+       // return true if eye is inside enlarged box
+       if (BoxesOverlap(boxmins, boxmaxs, eye, eye))
+               return true;
+
        // try center
        VectorCopy(eye, start);
        VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, end);
@@ -6483,6 +6858,8 @@ static void R_View_UpdateEntityVisible (void)
        entity_render_t *ent;
 
        renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : ((chase_active.integer || r_waterstate.renderingscene) ? RENDER_VIEWMODEL : RENDER_EXTERIORMODEL);
+       if (!r_drawviewmodel.integer)
+               renderimask |= RENDER_VIEWMODEL;
        if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
        {
                // worldmodel can check visibility
@@ -7552,7 +7929,6 @@ static void R_BlendView(void)
                        if (r_glsl_permutation->loc_Texture_Second     >= 0) R_Mesh_TexBind(GL20TU_SECOND    , r_bloomstate.texture_bloom );
                        if (r_glsl_permutation->loc_Texture_GammaRamps >= 0) R_Mesh_TexBind(GL20TU_GAMMARAMPS, r_texture_gammaramps       );
                        if (r_glsl_permutation->loc_ViewTintColor      >= 0) qglUniform4fARB(r_glsl_permutation->loc_ViewTintColor     , r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
-                       if (r_glsl_permutation->loc_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]);
@@ -7568,7 +7944,6 @@ static void R_BlendView(void)
                        if (r_cg_permutation->fp_Texture_Second    ) CG_BindTexture(r_cg_permutation->fp_Texture_Second    , r_bloomstate.texture_bloom );CHECKCGERROR
                        if (r_cg_permutation->fp_Texture_GammaRamps) CG_BindTexture(r_cg_permutation->fp_Texture_GammaRamps, r_texture_gammaramps       );CHECKCGERROR
                        if (r_cg_permutation->fp_ViewTintColor     ) cgGLSetParameter4f(     r_cg_permutation->fp_ViewTintColor     , r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);CHECKCGERROR
-                       if (r_cg_permutation->fp_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
@@ -7923,10 +8298,14 @@ extern cvar_t cl_locs_show;
 static void R_DrawLocs(void);
 static void R_DrawEntityBBoxes(void);
 static void R_DrawModelDecals(void);
+extern void R_DrawModelShadows(void);
+extern void R_DrawModelShadowMaps(void);
 extern cvar_t cl_decals_newsystem;
 extern qboolean r_shadow_usingdeferredprepass;
 void R_RenderScene(void)
 {
+       qboolean shadowmapping = false;
+
        r_refdef.stats.renders++;
 
        R_UpdateFogColor();
@@ -7973,9 +8352,14 @@ void R_RenderScene(void)
                R_TimeReport("animation");
 
        R_Shadow_PrepareLights();
+       if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
+               R_Shadow_PrepareModelShadows();
        if (r_timereport_active)
                R_TimeReport("preparelights");
 
+       if (R_Shadow_ShadowMappingEnabled())
+               shadowmapping = true;
+
        if (r_shadow_usingdeferredprepass)
                R_Shadow_DrawPrepass();
 
@@ -7992,6 +8376,15 @@ void R_RenderScene(void)
                        R_TimeReport("modeldepth");
        }
 
+       if (r_shadows.integer > 0 && shadowmapping && r_refdef.lightmapintensity > 0)
+       {
+               R_DrawModelShadowMaps();
+               R_ResetViewRendering3D();
+               // don't let sound skip if going slow
+               if (r_refdef.scene.extraupdate)
+                       S_ExtraUpdate ();
+       }
+
        if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
        {
                r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
@@ -8011,7 +8404,7 @@ void R_RenderScene(void)
        if (r_refdef.scene.extraupdate)
                S_ExtraUpdate ();
 
-       if (r_shadows.integer > 0 && !r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
+       if (r_shadows.integer > 0 && !shadowmapping && !r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
        {
                R_DrawModelShadows();
                R_ResetViewRendering3D();
@@ -8031,7 +8424,7 @@ void R_RenderScene(void)
        if (r_refdef.scene.extraupdate)
                S_ExtraUpdate ();
 
-       if (r_shadows.integer > 0 && r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
+       if (r_shadows.integer > 0 && !shadowmapping && r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
        {
                R_DrawModelShadows();
                R_ResetViewRendering3D();
@@ -8621,7 +9014,7 @@ void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
                f = FS_LoadFile(name, tempmempool, true, &filesize);
                if (f)
                {
-                       if (LoadPCX_QWSkin(f, filesize, pixels, 296, 194))
+                       if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
                                skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
                        Mem_Free(f);
                }
@@ -8759,6 +9152,7 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        t->glosstexture = r_texture_black;
        t->glowtexture = t->currentskinframe->glow;
        t->fogtexture = t->currentskinframe->fog;
+       t->reflectmasktexture = t->currentskinframe->reflect;
        if (t->backgroundnumskinframes)
        {
                t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
@@ -8812,6 +9206,7 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                t->glosstexture = r_texture_black;
                t->glowtexture = NULL;
                t->fogtexture = NULL;
+               t->reflectmasktexture = NULL;
                t->backgroundbasetexture = NULL;
                t->backgroundnmaptexture = r_texture_blanknormalmap;
                t->backgroundglosstexture = r_texture_black;
@@ -10739,7 +11134,7 @@ static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface
 {
        CHECKGLERROR
        RSurf_SetupDepthAndCulling();
-       if (r_showsurfaces.integer == 3 && !prepass)
+       if (r_showsurfaces.integer == 3 && !prepass && (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY))
        {
                R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth);
                return;
@@ -10764,7 +11159,7 @@ static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface
 {
        CHECKGLERROR
        RSurf_SetupDepthAndCulling();
-       if (r_showsurfaces.integer == 3 && !prepass)
+       if (r_showsurfaces.integer == 3 && !prepass && (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY))
        {
                R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth);
                return;
@@ -11195,7 +11590,6 @@ static void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float
        tridecal_t *decal;
        tridecal_t *decals;
        int i;
-       int maxdecals;
 
        // expand or initialize the system
        if (decalsystem->maxdecals <= decalsystem->numdecals)
@@ -11222,7 +11616,6 @@ static void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float
        }
 
        // grab a decal and search for another free slot for the next one
-       maxdecals = decalsystem->maxdecals;
        decals = decalsystem->decals;
        decal = decalsystem->decals + (i = decalsystem->freedecal++);
        for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4ub[0][3];i++)
@@ -11279,13 +11672,11 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor
        const msurface_t *surfaces;
        const int *surfacelist;
        const texture_t *texture;
-       int numvertices;
        int numtriangles;
        int numsurfacelist;
        int surfacelistindex;
        int surfaceindex;
        int triangleindex;
-       int decalsurfaceindex;
        int cornerindex;
        int index;
        int numpoints;
@@ -11295,7 +11686,6 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor
        float localmins[3];
        float localmaxs[3];
        float localsize;
-       float ilocalsize;
        float v[9][3];
        float tc[9][2];
        float c[9][4];
@@ -11331,7 +11721,6 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor
        Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
        VectorNormalize(localnormal);
        localsize = worldsize*rsurface.inversematrixscale;
-       ilocalsize = 1.0f / localsize;
        localmins[0] = localorigin[0] - localsize;
        localmins[1] = localorigin[1] - localsize;
        localmins[2] = localorigin[2] - localsize;
@@ -11401,8 +11790,6 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor
                        continue;
                if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
                        continue;
-               decalsurfaceindex = ent == r_refdef.scene.worldentity ? surfaceindex : -1;
-               numvertices = surface->num_vertices;
                numtriangles = surface->num_triangles;
                for (triangleindex = 0, e = model->surfmesh.data_element3i + 3*surface->num_firsttriangle;triangleindex < numtriangles;triangleindex++, e += 3)
                {
@@ -11617,7 +12004,6 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
        decalsystem_t *decalsystem = &ent->decalsystem;
        int numdecals;
        tridecal_t *decal;
-       float fadedelay;
        float faderate;
        float alpha;
        float *v3f;
@@ -11651,7 +12037,6 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
        decalsystem->lastupdatetime = cl.time;
        decal = decalsystem->decals;
 
-       fadedelay = cl_decals_time.value;
        faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
 
        // update vertex positions for animated models
@@ -11797,7 +12182,6 @@ void R_DrawDebugModel(void)
 {
        entity_render_t *ent = rsurface.entity;
        int i, j, k, l, flagsmask;
-       const int *elements;
        q3mbrush_t *brush;
        const msurface_t *surface;
        dp_model_t *model = ent->model;
@@ -11866,7 +12250,6 @@ void R_DrawDebugModel(void)
                                                GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
                                        else
                                                GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
-                                       elements = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
                                        R_Mesh_VertexPointer(rsurface.vertex3f, 0, 0);
                                        R_Mesh_ColorPointer(NULL, 0, 0);
                                        R_Mesh_TexCoordPointer(0, 0, NULL, 0, 0);
@@ -11941,8 +12324,7 @@ int r_maxsurfacelist = 0;
 const msurface_t **r_surfacelist = NULL;
 void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
 {
-       int i, j, endj, f, flagsmask;
-       texture_t *t;
+       int i, j, endj, flagsmask;
        dp_model_t *model = r_refdef.scene.worldmodel;
        msurface_t *surfaces;
        unsigned char *update;
@@ -11988,8 +12370,6 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep
                return;
        }
 
-       f = 0;
-       t = NULL;
        rsurface.uselightmaptexture = false;
        rsurface.texture = NULL;
        rsurface.rtlight = NULL;
@@ -12038,8 +12418,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep
 
 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
 {
-       int i, j, endj, f, flagsmask;
-       texture_t *t;
+       int i, j, endj, flagsmask;
        dp_model_t *model = ent->model;
        msurface_t *surfaces;
        unsigned char *update;
@@ -12065,7 +12444,19 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
        else if (prepass)
                RSurf_ActiveModelEntity(ent, true, true, true);
        else if (depthonly)
-               RSurf_ActiveModelEntity(ent, false, false, false);
+       {
+               switch (vid.renderpath)
+               {
+               case RENDERPATH_GL20:
+               case RENDERPATH_CGGL:
+                       RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
+                       break;
+               case RENDERPATH_GL13:
+               case RENDERPATH_GL11:
+                       RSurf_ActiveModelEntity(ent, model->wantnormals, false, false);
+                       break;
+               }
+       }
        else
        {
                switch (vid.renderpath)
@@ -12109,8 +12500,6 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
                return;
        }
 
-       f = 0;
-       t = NULL;
        rsurface.uselightmaptexture = false;
        rsurface.texture = NULL;
        rsurface.rtlight = NULL;