]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
new commands: prvm_edictget, prvm_globalget - read values from edicts/globals into...
[xonotic/darkplaces.git] / gl_rmain.c
index 52a10187eea6b515b3f3fa397f3ed0efcdbb913a..a30e6e6072251acc68ccd76f1a017e3c2dd65c3a 100644 (file)
@@ -43,7 +43,6 @@ cvar_t r_motionblur_bmin = {CVAR_SAVE, "r_motionblur_bmin", "0.5", "velocity at
 cvar_t r_motionblur_vcoeff = {CVAR_SAVE, "r_motionblur_vcoeff", "0.05", "sliding average reaction time for velocity"};
 cvar_t r_motionblur_maxblur = {CVAR_SAVE, "r_motionblur_maxblur", "0.88", "cap for motionblur alpha value"};
 cvar_t r_motionblur_randomize = {CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
-cvar_t r_motionblur_debug = {0, "r_motionblur_debug", "0", "outputs current motionblur alpha value"};
 
 cvar_t r_animcache = {CVAR_SAVE, "r_animcache", "1", "cache animation frames to save CPU usage, primarily optimizes shadows and reflections"};
 
@@ -72,8 +71,12 @@ cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders
 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
-cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows DOWN, otherwise use the model lighting"};
+cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
+cvar_t r_shadows_darken = {CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
 cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
+cvar_t r_shadows_throwdirection = {CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
+cvar_t r_shadows_drawafterrtlightning = {CVAR_SAVE, "r_shadows_drawafterrtlightning", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
+cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
 cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
 cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
 cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "2", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
@@ -92,7 +95,6 @@ cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the re
 cvar_t r_textureunits = {0, "r_textureunits", "32", "number of hardware texture units reported by driver (note: setting this to 1 turns off gl_combine)"};
 
 cvar_t r_glsl = {CVAR_SAVE, "r_glsl", "1", "enables use of OpenGL 2.0 pixel shaders for lighting"};
-cvar_t r_glsl_contrastboost = {CVAR_SAVE, "r_glsl_contrastboost", "1", "by how much to multiply the contrast in dark areas (1 is no change)"};
 cvar_t r_glsl_deluxemapping = {CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
 cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
@@ -443,6 +445,12 @@ static void R_BuildFogTexture(void)
 static const char *builtinshaderstring =
 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
 "// written by Forest 'LordHavoc' Hale\n"
+"#ifdef USESHADOWMAPRECT\n"
+"#extension GL_ARB_texture_rectangle : enable\n"
+"#endif\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"#extension GL_EXT_gpu_shader4 : enable\n"
+"#endif\n"
 "\n"
 "// common definitions between vertex shader and fragment shader:\n"
 "\n"
@@ -468,6 +476,22 @@ static const char *builtinshaderstring =
 "# endif\n"
 "\n"
 "#else\n"
+"#ifdef MODE_SHOWDEPTH\n"
+"# ifdef VERTEX_SHADER\n"
+"void main(void)\n"
+"{\n"
+"      gl_Position = ftransform();\n"
+"      gl_FrontColor = vec4(gl_Position.z, gl_Position.z, gl_Position.z, 1.0);\n"
+"}\n"
+"# endif\n"
+"# ifdef FRAGMENT_SHADER\n"
+"void main(void)\n"
+"{\n"
+"      gl_FragColor = gl_Color;\n"
+"}\n"
+"# endif\n"
+"\n"
+"#else // !MODE_SHOWDEPTH\n"
 "\n"
 "#ifdef MODE_POSTPROCESS\n"
 "# ifdef VERTEX_SHADER\n"
@@ -476,7 +500,7 @@ static const char *builtinshaderstring =
 "      gl_FrontColor = gl_Color;\n"
 "      gl_Position = ftransform();\n"
 "      gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
-"#ifdef USEGLOW\n"
+"#ifdef USEBLOOM\n"
 "      gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;\n"
 "#endif\n"
 "}\n"
@@ -484,7 +508,7 @@ static const char *builtinshaderstring =
 "# ifdef FRAGMENT_SHADER\n"
 "\n"
 "uniform sampler2D Texture_First;\n"
-"#ifdef USEGLOW\n"
+"#ifdef USEBLOOM\n"
 "uniform sampler2D Texture_Second;\n"
 "#endif\n"
 "#ifdef USEGAMMARAMPS\n"
@@ -493,12 +517,9 @@ static const char *builtinshaderstring =
 "#ifdef USESATURATION\n"
 "uniform float Saturation;\n"
 "#endif\n"
-"#ifdef USEVERTEXTEXTUREBLEND\n"
+"#ifdef USEVIEWTINT\n"
 "uniform vec4 TintColor;\n"
 "#endif\n"
-"#ifdef USECOLORMOD\n"
-"uniform vec3 Gamma;\n"
-"#endif\n"
 "//uncomment these if you want to use them:\n"
 "uniform vec4 UserVec1;\n"
 "// uniform vec4 UserVec2;\n"
@@ -509,10 +530,10 @@ static const char *builtinshaderstring =
 "void main(void)\n"
 "{\n"
 "      gl_FragColor = texture2D(Texture_First, gl_TexCoord[0].xy);\n"
-"#ifdef USEGLOW\n"
+"#ifdef USEBLOOM\n"
 "      gl_FragColor += texture2D(Texture_Second, gl_TexCoord[1].xy);\n"
 "#endif\n"
-"#ifdef USEVERTEXTEXTUREBLEND\n"
+"#ifdef USEVIEWTINT\n"
 "      gl_FragColor = mix(gl_FragColor, TintColor, TintColor.a);\n"
 "#endif\n"
 "\n"
@@ -737,6 +758,35 @@ static const char *builtinshaderstring =
 "uniform sampler2D Texture_Attenuation;\n"
 "uniform samplerCube Texture_Cube;\n"
 "\n"
+"#define showshadowmap 0\n"
+"#define useshadowsamplerrect 0\n"
+"#define useshadowsampler2d 0\n"
+"#define useshadowsamplercube 1\n"
+"\n"
+"#ifdef USESHADOWMAPRECT\n"
+"# if useshadowsamplerrect\n"
+"uniform sampler2DRectShadow Texture_ShadowMapRect;\n"
+"# else\n"
+"uniform sampler2DRect Texture_ShadowMapRect;\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAP2D\n"
+"# if useshadowsampler2d\n"
+"uniform sampler2DShadow Texture_ShadowMap2D;\n"
+"# else\n"
+"uniform sampler2D Texture_ShadowMap2D;\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"# if useshadowsamplercube\n"
+"uniform samplerCubeShadow Texture_ShadowMapCube;\n"
+"# else\n"
+"uniform samplerCube Texture_ShadowMapCube;\n"
+"# endif\n"
+"#endif\n"
+"\n"
 "uniform myhalf3 LightColor;\n"
 "uniform myhalf3 AmbientColor;\n"
 "uniform myhalf3 DiffuseColor;\n"
@@ -777,9 +827,6 @@ static const char *builtinshaderstring =
 "\n"
 "uniform myhalf GlowScale;\n"
 "uniform myhalf SceneBrightness;\n"
-"#ifdef USECONTRASTBOOST\n"
-"uniform myhalf ContrastBoostCoeff;\n"
-"#endif\n"
 "\n"
 "uniform float OffsetMapping_Scale;\n"
 "uniform float OffsetMapping_Bias;\n"
@@ -835,6 +882,176 @@ static const char *builtinshaderstring =
 "}\n"
 "#endif // USEOFFSETMAPPING\n"
 "\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D) || defined(USESHADOWMAPCUBE)\n"
+"//float ShadowMap_TextureSize = 1024.0;\n"
+"//float ShadowMap_BorderSize = 6.0;\n"
+"//float ShadowMap_NearClip = 0.0001;\n"
+"//float ShadowMap_FarClip = 1.0;\n"
+"//float ShadowMap_Bias = ShadowMap_NearClip * 64.0 / ShadowMap_TextureSize;\n"
+"//vec2 ShadowMap_TextureScale = vec2(0.5, 0.25);\n"
+"//vec4 ShadowMap_Parameters = vec3(1.0 - ShadowMap_BorderSize / ShadowMap_TextureSize, 1.0 - ShadowMap_BorderSize / ShadowMap_TextureSize, -(ShadowMap_FarClip + ShadowMap_NearClip) / (ShadowMap_FarClip - ShadowMap_NearClip), -2.0 * ShadowMap_NearClip * ShadowMap_FarClip / (ShadowMap_FarClip - ShadowMap_NearClip));\n"
+"uniform float ShadowMap_Bias;\n"
+"uniform vec2 ShadowMap_TextureScale;\n"
+"uniform vec4 ShadowMap_Parameters;\n"
+"#endif\n"
+"\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
+"vec3 GetShadowMapTC2D(vec3 dir)\n"
+"{\n"
+"      vec3 adir = abs(dir);\n"
+"      vec3 tc;\n"
+"      vec3 offset;\n"
+"# if 1\n"
+"      float d;\n"
+"      if (adir.x > adir.y)\n"
+"      {\n"
+"              if (adir.x > adir.z)\n"
+"              {\n"
+"                      d = 0.5 / adir.x;\n"
+"                      if (dir.x >= 0.0)\n"
+"                      {\n"
+"                              // +X\n"
+"                              tc = vec3(-dir.z, -dir.y, -dir.x);\n"
+"                              offset = vec3(0.5, 0.5, 0.5);\n"
+"                      }\n"
+"                      else\n"
+"                      {\n"
+"                              // -X\n"
+"                              tc = vec3( dir.z, -dir.y,  dir.x);\n"
+"                              offset = vec3(1.5, 0.5, 0.5);\n"
+"                      }\n"
+"              }\n"
+"              else\n"
+"              {\n"
+"                      d = 0.5 / adir.z;\n"
+"                      if (dir.z >= 0.0)\n"
+"                      {\n"
+"                              // +Z\n"
+"                              tc = vec3( dir.x, -dir.y, -dir.z);\n"
+"                              offset = vec3(0.5, 2.5, 0.5);\n"
+"                      }\n"
+"                      else\n"
+"                      {\n"
+"                              // -Z\n"
+"                              tc = vec3(-dir.x, -dir.y,  dir.z);\n"
+"                              offset = vec3(1.5, 2.5, 0.5);\n"
+"                      }\n"
+"              }\n"
+"      }\n"
+"      else\n"
+"      {\n"
+"              if (adir.y > adir.z)\n"
+"              {\n"
+"                      d = 0.5 / adir.y;\n"
+"                      if (dir.y >= 0.0)\n"
+"                      {\n"
+"                              // +Y\n"
+"                              tc = vec3( dir.x,  dir.z, -dir.y);\n"
+"                              offset = vec3(0.5, 1.5, 0.5);\n"
+"                      }\n"
+"                      else\n"
+"                      {\n"
+"                              // -Y\n"
+"                              tc = vec3( dir.x, -dir.z, dir.y);\n"
+"                              offset = vec3(1.5, 1.5, 0.5);\n"
+"                      }\n"
+"              }\n"
+"              else\n"
+"              {\n"
+"                      d = 0.5 / adir.z;\n"
+"                      if (dir.z >= 0.0)\n"
+"                      {\n"
+"                              // +Z\n"
+"                              tc = vec3(dir.x, -dir.y, -dir.z);\n"
+"                              offset = vec3(0.5, 2.5, 0.5);\n"
+"                      }\n"
+"                      else\n"
+"                      {\n"
+"                              // -Z\n"
+"                              tc = vec3(-dir.x, -dir.y, dir.z);\n"
+"                              offset = vec3(1.5, 2.5, 0.5);\n"
+"                      }\n"
+"              }\n"
+"      }\n"
+"      tc = tc * ShadowMap_Parameters.xyz * d + offset;\n"
+"      tc.xy *= ShadowMap_TextureScale;\n"
+"      tc.z += ShadowMap_Parameters.w * d - ShadowMap_Bias * d;\n"
+"# else\n"
+"      // experimental method by eihrul, needs overhaul\n"
+"      vec3 ma = vec3(0.0, 0.0, 1.0);\n"
+"      if (adir.x > adir.y)\n"
+"      {\n"
+"              if (adir.x > adir.z)\n"
+"                      ma = vec3(1.0, 0.0, 0.0);\n"
+"      }\n"
+"      else if (adir.y > adir.z)\n"
+"              ma = vec3(0.0, 1.0, 0.0);\n"
+"\n"
+"      tc.xy = dir.xy - ma.xy*(dir.xy - dir.z);\n"
+"      tc.xy = (tc.xy/dot(ma, dir))*0.5 + 0.5;\n"
+"      tc.z = dot(ma, adir);\n"
+"      tc.xy = (tc.xy * tcscale + offset) * vec2(0.5, 0.25);\n"
+"# endif\n"
+"      return tc;\n"
+"}\n"
+"\n"
+"#endif // defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
+"\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"vec4 GetShadowMapTCCube(vec3 dir)\n"
+"{\n"
+"      vec3 adir = abs(dir);\n"
+"      float sidedist = max(adir.x, max(adir.y, adir.z));\n"
+"      return vec4(dir, 0.5 - 0.5 * (ShadowMap_Parameters.z - (-ShadowMap_Bias + ShadowMap_Parameters.w) / sidedist));\n"
+"}\n"
+"#endif\n"
+"\n"
+"#if !showshadowmap\n"
+"# ifdef USESHADOWMAPRECT\n"
+"float ShadowMapCompare(vec3 dir)\n"
+"{\n"
+"      vec3 shadowmaptc = GetShadowMapTC2D(dir);\n"
+"      float f;\n"
+"#  if useshadowsamplerrect\n"
+"      f = shadow2DRect(Texture_ShadowMapRect, shadowmaptc).a;\n"
+"#  else\n"
+"      f = step(shadowmaptc.z, texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy).r);\n"
+"#  endif\n"
+"      return f;\n"
+"}\n"
+"# endif\n"
+"\n"
+"# ifdef USESHADOWMAP2D\n"
+"float ShadowMapCompare(vec3 dir)\n"
+"{\n"
+"      vec3 shadowmaptc = GetShadowMapTC2D(dir);\n"
+"      float f;\n"
+"#  if useshadowsampler2d\n"
+"      f = shadow2D(Texture_ShadowMap2D, shadowmaptc).a;\n"
+"#  else\n"
+"      f = step(shadowmaptc.z, texture2D(Texture_ShadowMap2D, shadowmaptc.xy).r);\n"
+"#  endif\n"
+"      return f;\n"
+"}\n"
+"# endif\n"
+"\n"
+"# ifdef USESHADOWMAPCUBE\n"
+"float ShadowMapCompare(vec3 dir)\n"
+"{\n"
+"      // apply depth texture cubemap as light filter\n"
+"      vec4 shadowmaptc = GetShadowMapTCCube(dir);\n"
+"      float f;\n"
+"#  if useshadowsamplercube\n"
+"      f = shadowCube(Texture_ShadowMapCube, shadowmaptc).a;\n"
+"#  else\n"
+"      f = step(shadowmaptc.w, textureCube(Texture_ShadowMapCube, shadowmaptc.xyz).r);\n"
+"#  endif\n"
+"      return f;\n"
+"}\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"\n"
 "#ifdef MODE_WATER\n"
 "\n"
 "// water pass\n"
@@ -943,6 +1160,12 @@ static const char *builtinshaderstring =
 "#  endif\n"
 "# endif\n"
 "\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAPCUBE) || defined(USESHADOWMAP2D)\n"
+"#if !showshadowmap\n"
+"      color.rgb *= ShadowMapCompare(CubeVector);\n"
+"#endif\n"
+"#endif\n"
+"\n"
 "# ifdef USECUBEFILTER\n"
 "      // apply light cubemap filter\n"
 "      //color.rgb *= normalize(CubeVector) * 0.5 + 0.5;//vec3(textureCube(Texture_Cube, CubeVector));\n"
@@ -1076,10 +1299,6 @@ static const char *builtinshaderstring =
 "#endif\n"
 "#endif\n"
 "\n"
-"#ifdef USECONTRASTBOOST\n"
-"      color.rgb = color.rgb / (ContrastBoostCoeff * color.rgb + myhalf3(1, 1, 1));\n"
-"#endif\n"
-"\n"
 "      color.rgb *= SceneBrightness;\n"
 "\n"
 "      // apply fog after Contrastboost/SceneBrightness because its color is already modified appropriately\n"
@@ -1096,6 +1315,32 @@ static const char *builtinshaderstring =
 "#endif\n"
 "\n"
 "      gl_FragColor = vec4(color);\n"
+"\n"
+"#if showshadowmap\n"
+"# ifdef USESHADOWMAPRECT\n"
+"#  if useshadowsamplerrect\n"
+"      gl_FragColor = shadow2DRect(Texture_ShadowMapRect, GetShadowMapTC2D(CubeVector).xyz);\n"
+"#  else\n"
+"      gl_FragColor = texture2DRect(Texture_ShadowMapRect, GetShadowMapTC2D(CubeVector).xy);\n"
+"#  endif\n"
+"# endif\n"
+"\n"
+"# ifdef USESHADOWMAP2D\n"
+"#  if useshadowsampler2d\n"
+"      gl_FragColor = shadow2D(Texture_ShadowMap2D, GetShadowMapTC2D(CubeVector).xyz);\n"
+"#  else\n"
+"      gl_FragColor = texture2D(Texture_ShadowMap2D, GetShadowMapTC2D(CubeVector).xy);\n"
+"#  endif\n"
+"# endif\n"
+"\n"
+"# ifdef USESHADOWMAPCUBE\n"
+"#  if useshadowsamplercube\n"
+"      gl_FragColor = shadowCube(Texture_ShadowMapCube, GetShadowMapTCCube(CubeVector));\n"
+"#  else\n"
+"      gl_FragColor = textureCube(Texture_ShadowMapCube, GetShadowMapTCCube(CubeVector).xyz);\n"
+"#  endif\n"
+"# endif\n"
+"#endif\n"
 "}\n"
 "#endif // !MODE_REFRACTION\n"
 "#endif // !MODE_WATER\n"
@@ -1104,6 +1349,7 @@ static const char *builtinshaderstring =
 "\n"
 "#endif // !MODE_GENERIC\n"
 "#endif // !MODE_POSTPROCESS\n"
+"#endif // !MODE_SHOWDEPTH\n"
 "#endif // !MODE_DEPTH_OR_SHADOW\n"
 ;
 
@@ -1128,21 +1374,25 @@ typedef enum shaderpermutation_e
 {
        SHADERPERMUTATION_DIFFUSE = 1<<0, ///< (lightsource) whether to use directional shading
        SHADERPERMUTATION_VERTEXTEXTUREBLEND = 1<<1, ///< indicates this is a two-layer material blend based on vertex alpha (q3bsp)
+       SHADERPERMUTATION_VIEWTINT = 1<<1, ///< view tint (postprocessing only)
        SHADERPERMUTATION_COLORMAPPING = 1<<2, ///< indicates this is a colormapped skin
-       SHADERPERMUTATION_CONTRASTBOOST = 1<<3, ///< r_glsl_contrastboost boosts the contrast at low color levels (similar to gamma)
-       SHADERPERMUTATION_FOG = 1<<4, ///< tint the color by fog color or black if using additive blend mode
-       SHADERPERMUTATION_CUBEFILTER = 1<<5, ///< (lightsource) use cubemap light filter
-       SHADERPERMUTATION_GLOW = 1<<6, ///< (lightmap) blend in an additive glow texture
-       SHADERPERMUTATION_SPECULAR = 1<<7, ///< (lightsource or deluxemapping) render specular effects
-       SHADERPERMUTATION_EXACTSPECULARMATH = 1<<8, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
-       SHADERPERMUTATION_REFLECTION = 1<<9, ///< normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
-       SHADERPERMUTATION_OFFSETMAPPING = 1<<10, ///< adjust texcoords to roughly simulate a displacement mapped surface
-       SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<11, ///< adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
-       SHADERPERMUTATION_GAMMARAMPS = 1<<12, ///< gamma (postprocessing only)
-       SHADERPERMUTATION_POSTPROCESSING = 1<<13, ///< user defined postprocessing
-       SHADERPERMUTATION_SATURATION = 1<<14, ///< user defined postprocessing
-       SHADERPERMUTATION_LIMIT = 1<<15, ///< size of permutations array
-       SHADERPERMUTATION_COUNT = 15 ///< size of shaderpermutationinfo array
+       SHADERPERMUTATION_SATURATION = 1<<2, ///< saturation (postprocessing only)
+       SHADERPERMUTATION_FOG = 1<<3, ///< tint the color by fog color or black if using additive blend mode
+       SHADERPERMUTATION_GAMMARAMPS = 1<<3, ///< gamma (postprocessing only)
+       SHADERPERMUTATION_CUBEFILTER = 1<<4, ///< (lightsource) use cubemap light filter
+       SHADERPERMUTATION_GLOW = 1<<5, ///< (lightmap) blend in an additive glow texture
+       SHADERPERMUTATION_BLOOM = 1<<5, ///< bloom (postprocessing only)
+       SHADERPERMUTATION_SPECULAR = 1<<6, ///< (lightsource or deluxemapping) render specular effects
+       SHADERPERMUTATION_POSTPROCESSING = 1<<6, ///< user defined postprocessing (postprocessing only)
+       SHADERPERMUTATION_EXACTSPECULARMATH = 1<<7, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
+       SHADERPERMUTATION_REFLECTION = 1<<8, ///< normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
+       SHADERPERMUTATION_OFFSETMAPPING = 1<<9, ///< adjust texcoords to roughly simulate a displacement mapped surface
+       SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<10, ///< adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
+       SHADERPERMUTATION_SHADOWMAPRECT = 1<<11, ///< (lightsource) use shadowmap rectangle texture as light filter
+       SHADERPERMUTATION_SHADOWMAPCUBE = 1<<12, ///< (lightsource) use shadowmap cubemap texture as light filter
+       SHADERPERMUTATION_SHADOWMAP2D = 1<<13, ///< (lightsource) use shadowmap rectangle texture as light filter
+       SHADERPERMUTATION_LIMIT = 1<<14, ///< size of permutations array
+       SHADERPERMUTATION_COUNT = 14 ///< size of shaderpermutationinfo array
 }
 shaderpermutation_t;
 
@@ -1150,20 +1400,19 @@ shaderpermutation_t;
 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
 {
        {"#define USEDIFFUSE\n", " diffuse"},
-       {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
-       {"#define USECOLORMAPPING\n", " colormapping"},
-       {"#define USECONTRASTBOOST\n", " contrastboost"},
-       {"#define USEFOG\n", " fog"},
+       {"#define USEVERTEXTEXTUREBLEND\n#define USEVIEWTINT\n", " vertextextureblend/tint"},
+       {"#define USECOLORMAPPING\n#define USESATURATION\n", " colormapping/saturation"},
+       {"#define USEFOG\n#define USEGAMMARAMPS\n", " fog/gammaramps"},
        {"#define USECUBEFILTER\n", " cubefilter"},
-       {"#define USEGLOW\n", " glow"},
-       {"#define USESPECULAR\n", " specular"},
+       {"#define USEGLOW\n#define USEBLOOM\n", " glow/bloom"},
+       {"#define USESPECULAR\n#define USEPOSTPROCESSING", " specular/postprocessing"},
        {"#define USEEXACTSPECULARMATH\n", " exactspecularmath"},
        {"#define USEREFLECTION\n", " reflection"},
        {"#define USEOFFSETMAPPING\n", " offsetmapping"},
        {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
-       {"#define USEGAMMARAMPS\n", " gammaramps"},
-       {"#define USEPOSTPROCESSING\n", " postprocessing"},
-       {"#define USESATURATION\n", " saturation"},
+       {"#define USESHADOWMAPRECT\n", " shadowmaprect"},
+       {"#define USESHADOWMAPCUBE\n", " shadowmapcube"},
+       {"#define USESHADOWMAP2D\n", " shadowmap2d"},
 };
 
 /// this enum is multiplied by SHADERPERMUTATION_MODEBASE
@@ -1181,6 +1430,7 @@ typedef enum shadermode_e
        SHADERMODE_LIGHTSOURCE, ///< (lightsource) use directional pixel shading from light source (rtlight)
        SHADERMODE_REFRACTION, ///< refract background (the material is rendered normally after this pass)
        SHADERMODE_WATER, ///< refract background and reflection (the material is rendered normally after this pass)
+       SHADERMODE_SHOWDEPTH, ///< (debugging) renders depth as color
        SHADERMODE_COUNT
 }
 shadermode_t;
@@ -1200,6 +1450,7 @@ shadermodeinfo_t shadermodeinfo[SHADERMODE_COUNT] =
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTSOURCE\n", " lightsource"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_REFRACTION\n", " refraction"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_WATER\n", " water"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_SHOWDEPTH\n", " showdepth"},
 };
 
 typedef struct r_glsl_permutation_s
@@ -1229,6 +1480,9 @@ typedef struct r_glsl_permutation_s
        int loc_Texture_Cube;
        int loc_Texture_Refraction;
        int loc_Texture_Reflection;
+       int loc_Texture_ShadowMapRect;
+       int loc_Texture_ShadowMapCube;
+       int loc_Texture_ShadowMap2D;
        int loc_FogColor;
        int loc_LightPosition;
        int loc_EyePosition;
@@ -1263,6 +1517,9 @@ typedef struct r_glsl_permutation_s
        int loc_ClientTime;
        int loc_PixelSize;
        int loc_Saturation;
+       int loc_ShadowMap_Bias;
+       int loc_ShadowMap_TextureScale;
+       int loc_ShadowMap_Parameters;
 }
 r_glsl_permutation_t;
 
@@ -1390,6 +1647,9 @@ static void R_GLSL_CompilePermutation(unsigned int mode, unsigned int permutatio
                p->loc_Texture_Reflection         = qglGetUniformLocationARB(p->program, "Texture_Reflection");
                p->loc_Texture_Attenuation        = qglGetUniformLocationARB(p->program, "Texture_Attenuation");
                p->loc_Texture_Cube               = qglGetUniformLocationARB(p->program, "Texture_Cube");
+               p->loc_Texture_ShadowMapRect      = qglGetUniformLocationARB(p->program, "Texture_ShadowMapRect");
+               p->loc_Texture_ShadowMapCube      = qglGetUniformLocationARB(p->program, "Texture_ShadowMapCube");
+               p->loc_Texture_ShadowMap2D        = qglGetUniformLocationARB(p->program, "Texture_ShadowMap2D");
                p->loc_FogColor                   = qglGetUniformLocationARB(p->program, "FogColor");
                p->loc_LightPosition              = qglGetUniformLocationARB(p->program, "LightPosition");
                p->loc_EyePosition                = qglGetUniformLocationARB(p->program, "EyePosition");
@@ -1424,6 +1684,9 @@ static void R_GLSL_CompilePermutation(unsigned int mode, unsigned int permutatio
                p->loc_ClientTime                 = qglGetUniformLocationARB(p->program, "ClientTime");
                p->loc_PixelSize                  = qglGetUniformLocationARB(p->program, "PixelSize");
                p->loc_Saturation                 = qglGetUniformLocationARB(p->program, "Saturation");
+               p->loc_ShadowMap_Bias             = qglGetUniformLocationARB(p->program, "ShadowMap_Bias");
+               p->loc_ShadowMap_TextureScale     = qglGetUniformLocationARB(p->program, "ShadowMap_TextureScale");
+               p->loc_ShadowMap_Parameters       = qglGetUniformLocationARB(p->program, "ShadowMap_Parameters");
                // 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);
@@ -1445,6 +1708,9 @@ static void R_GLSL_CompilePermutation(unsigned int mode, unsigned int permutatio
                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_ShadowMapCube   >= 0) qglUniform1iARB(p->loc_Texture_ShadowMapCube  , GL20TU_SHADOWMAPCUBE);
+               if (p->loc_Texture_ShadowMap2D     >= 0) qglUniform1iARB(p->loc_Texture_ShadowMap2D    , GL20TU_SHADOWMAP2D);
                CHECKGLERROR
                if (developer.integer)
                        Con_Printf("GLSL shader %s compiled.\n", permutationname);
@@ -1483,13 +1749,13 @@ void R_GLSL_DumpShader_f(void)
                return;
        }
 
-       FS_Print(file, "// The engine may define the following macros:\n");
-       FS_Print(file, "// #define VERTEX_SHADER\n// #define GEOMETRY_SHADER\n// #define FRAGMENT_SHADER\n");
+       FS_Print(file, "/* The engine may define the following macros:\n");
+       FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
        for (i = 0;i < SHADERMODE_COUNT;i++)
-               FS_Printf(file, "// %s", shadermodeinfo[i].pretext);
+               FS_Print(file, shadermodeinfo[i].pretext);
        for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
-               FS_Printf(file, "// %s", shaderpermutationinfo[i].pretext);
-       FS_Print(file, "\n");
+               FS_Print(file, shaderpermutationinfo[i].pretext);
+       FS_Print(file, "*/\n");
        FS_Print(file, builtinshaderstring);
        FS_Close(file);
 
@@ -1585,9 +1851,29 @@ void R_SetupDepthOrShadowShader(void)
        }
 }
 
+void R_SetupShowDepthShader(void)
+{
+       if (gl_support_fragment_shader)
+       {
+               if (r_glsl.integer && r_glsl_usegeneric.integer)
+                       R_SetupShader_SetPermutation(SHADERMODE_SHOWDEPTH, 0);
+               else if (r_glsl_permutation)
+               {
+                       r_glsl_permutation = NULL;
+                       qglUseProgramObjectARB(0);CHECKGLERROR
+               }
+       }
+}
+
 extern rtexture_t *r_shadow_attenuationgradienttexture;
 extern rtexture_t *r_shadow_attenuation2dtexture;
 extern rtexture_t *r_shadow_attenuation3dtexture;
+extern qboolean r_shadow_usingshadowmaprect;
+extern qboolean r_shadow_usingshadowmapcube;
+extern qboolean r_shadow_usingshadowmap2d;
+extern float r_shadow_shadowmap_bias;
+extern float r_shadow_shadowmap_texturescale[2];
+extern float r_shadow_shadowmap_parameters[4];
 void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass)
 {
        // select a permutation of the lighting shader appropriate to this
@@ -1627,8 +1913,12 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                        permutation |= SHADERPERMUTATION_FOG;
                if (rsurface.texture->colormapping)
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
-               if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
-                       permutation |= SHADERPERMUTATION_CONTRASTBOOST;
+               if (r_shadow_usingshadowmaprect)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
+               if (r_shadow_usingshadowmapcube)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPCUBE;
+               if (r_shadow_usingshadowmap2d)
+                       permutation |= SHADERPERMUTATION_SHADOWMAP2D;
        }
        else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
        {
@@ -1648,8 +1938,6 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                        if (r_glsl_offsetmapping_reliefmapping.integer)
                                permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
                }
-               if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
-                       permutation |= SHADERPERMUTATION_CONTRASTBOOST;
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
        }
@@ -1668,8 +1956,6 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                        permutation |= SHADERPERMUTATION_FOG;
                if (rsurface.texture->colormapping)
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
-               if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
-                       permutation |= SHADERPERMUTATION_CONTRASTBOOST;
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
        }
@@ -1685,8 +1971,6 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                        permutation |= SHADERPERMUTATION_FOG;
                if (rsurface.texture->colormapping)
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
-               if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
-                       permutation |= SHADERPERMUTATION_CONTRASTBOOST;
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
        }
@@ -1730,8 +2014,6 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                        permutation |= SHADERPERMUTATION_FOG;
                if (rsurface.texture->colormapping)
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
-               if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
-                       permutation |= SHADERPERMUTATION_CONTRASTBOOST;
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
        }
@@ -1760,6 +2042,9 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                // 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_Bias >= 0) qglUniform1fARB(r_glsl_permutation->loc_ShadowMap_Bias, r_shadow_shadowmap_bias);
+               if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2fARB(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
+               if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4fARB(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
        }
        else
        {
@@ -1794,19 +2079,7 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin);
                if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectOffset, rsurface.texture->reflectmin);
        }
-       if (r_glsl_permutation->loc_ContrastBoostCoeff >= 0)
-       {
-               // The formula used is actually:
-               //   color.rgb *= ContrastBoost / ((ContrastBoost - 1) * color.rgb + 1);
-               //   color.rgb *= SceneBrightness;
-               // simplified:
-               //   color.rgb = [[SceneBrightness * ContrastBoost]] * color.rgb / ([[ContrastBoost - 1]] * color.rgb + 1);
-               // and do [[calculations]] here in the engine
-               qglUniform1fARB(r_glsl_permutation->loc_ContrastBoostCoeff, r_glsl_contrastboost.value - 1);
-               if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_refdef.view.colorscale * r_glsl_contrastboost.value);
-       }
-       else
-               if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_refdef.view.colorscale);
+       if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_refdef.view.colorscale);
        if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface.modelorg[0], rsurface.modelorg[1], rsurface.modelorg[2]);
        if (r_glsl_permutation->loc_Color_Pants >= 0)
        {
@@ -2408,7 +2681,6 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_motionblur_randomize);
        Cvar_RegisterVariable(&r_damageblur);
        Cvar_RegisterVariable(&r_animcache);
-       Cvar_RegisterVariable(&r_motionblur_debug);
        Cvar_RegisterVariable(&r_depthfirst);
        Cvar_RegisterVariable(&r_useinfinitefarclip);
        Cvar_RegisterVariable(&r_nearclip);
@@ -2435,7 +2707,11 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_dynamic);
        Cvar_RegisterVariable(&r_fullbright);
        Cvar_RegisterVariable(&r_shadows);
+       Cvar_RegisterVariable(&r_shadows_darken);
+       Cvar_RegisterVariable(&r_shadows_drawafterrtlightning);
+       Cvar_RegisterVariable(&r_shadows_castfrombmodels);
        Cvar_RegisterVariable(&r_shadows_throwdistance);
+       Cvar_RegisterVariable(&r_shadows_throwdirection);
        Cvar_RegisterVariable(&r_q1bsp_skymasking);
        Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
        Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
@@ -2443,7 +2719,6 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_drawfog);
        Cvar_RegisterVariable(&r_textureunits);
        Cvar_RegisterVariable(&r_glsl);
-       Cvar_RegisterVariable(&r_glsl_contrastboost);
        Cvar_RegisterVariable(&r_glsl_deluxemapping);
        Cvar_RegisterVariable(&r_glsl_offsetmapping);
        Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
@@ -2653,133 +2928,148 @@ int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, c
 
 //==================================================================================
 
+// LordHavoc: animcache written by Echon, refactored and reformatted by me
+
 /**
  * Animation cache helps save re-animating a player mesh if it's re-rendered again in a given frame
  * (reflections, lighting, etc). All animation cache becomes invalid on the next frame and is flushed
  * (well, over-wrote). The memory for each cache is kept around to save on allocation thrashing.
  */
 
-typedef struct
+typedef struct r_animcache_entity_s
 {
-       int numVerts;
-       float *vertexes;
-       float *normals;
-       float *sVectors;
-       float *tVectors;
-} anim_cache_t;
+       float *vertex3f;
+       float *normal3f;
+       float *svector3f;
+       float *tvector3f;
+       int maxvertices;
+       qboolean wantnormals;
+       qboolean wanttangents;
+}
+r_animcache_entity_t;
+
+typedef struct r_animcache_s
+{
+       r_animcache_entity_t entity[MAX_EDICTS*2];
+       int maxindex;
+       int currentindex;
+}
+r_animcache_t;
 
-static anim_cache_t r_animCache[MAX_EDICTS];
-static int r_numAnimCache;
+static r_animcache_t r_animcachestate;
 
-void R_EmptyAnimCache(void)
+void R_AnimCache_Free(void)
 {
        int idx;
-       for (idx=0 ; idx<r_numAnimCache ; idx++)
+       for (idx=0 ; idx<r_animcachestate.maxindex ; idx++)
        {
-               r_animCache[idx].numVerts = 0;
-               Mem_Free(r_animCache[idx].vertexes);
-               r_animCache[idx].vertexes = NULL;
-               r_animCache[idx].normals = NULL;
-               r_animCache[idx].sVectors = NULL;
-               r_animCache[idx].tVectors = NULL;
+               r_animcachestate.entity[idx].maxvertices = 0;
+               Mem_Free(r_animcachestate.entity[idx].vertex3f);
+               r_animcachestate.entity[idx].vertex3f = NULL;
+               r_animcachestate.entity[idx].normal3f = NULL;
+               r_animcachestate.entity[idx].svector3f = NULL;
+               r_animcachestate.entity[idx].tvector3f = NULL;
        }
-       r_numAnimCache = 0;
+       r_animcachestate.currentindex = 0;
+       r_animcachestate.maxindex = 0;
 }
 
-void R_ResizeAnimCache(const int cacheIdx, const int numVerts)
+void R_AnimCache_ResizeEntityCache(const int cacheIdx, const int numvertices)
 {
        int arraySize;
        float *base;
-       anim_cache_t *cache = &r_animCache[cacheIdx];
+       r_animcache_entity_t *cache = &r_animcachestate.entity[cacheIdx];
 
-       if (cache->numVerts >= numVerts)
+       if (cache->maxvertices >= numvertices)
                return;
 
        // Release existing memory
-       if (cache->vertexes)
-               Mem_Free(cache->vertexes);
+       if (cache->vertex3f)
+               Mem_Free(cache->vertex3f);
 
        // Pad by 1024 verts
-       cache->numVerts = (numVerts + 1023) & ~1023;
-       arraySize = cache->numVerts * 3;
+       cache->maxvertices = (numvertices + 1023) & ~1023;
+       arraySize = cache->maxvertices * 3;
 
        // Allocate, even if we don't need this memory in this instance it will get ignored and potentially used later
        base = (float *)Mem_Alloc(r_main_mempool, arraySize * sizeof(float) * 4);
-       r_animCache[cacheIdx].vertexes = base;
-       r_animCache[cacheIdx].normals = base + arraySize;
-       r_animCache[cacheIdx].sVectors = base + arraySize*2;
-       r_animCache[cacheIdx].tVectors = base + arraySize*3;
+       r_animcachestate.entity[cacheIdx].vertex3f = base;
+       r_animcachestate.entity[cacheIdx].normal3f = base + arraySize;
+       r_animcachestate.entity[cacheIdx].svector3f = base + arraySize*2;
+       r_animcachestate.entity[cacheIdx].tvector3f = base + arraySize*3;
 
 //     Con_Printf("allocated cache for %i (%f KB)\n", cacheIdx, (arraySize*sizeof(float)*4)/1024.0f);
 }
 
-void R_RunAnimCache(void)
+void R_AnimCache_NewFrame(void)
 {
-       int entIdx, cacheIdx;
-       entity_render_t *ent;
-       dp_model_t *model;
-       qboolean bWantNormals;
-       qboolean bWantTangents;
+       int i;
+
+       if (r_animcache.integer && r_drawentities.integer)
+               r_animcachestate.maxindex = sizeof(r_animcachestate.entity) / sizeof(r_animcachestate.entity[0]);
+       else if (r_animcachestate.maxindex)
+               R_AnimCache_Free();
 
-       // Only proceed if desired
-       if (!r_animcache.integer || !r_drawentities.integer)
+       r_animcachestate.currentindex = 0;
+
+       for (i = 0;i < r_refdef.scene.numentities;i++)
+               r_refdef.scene.entities[i]->animcacheindex = -1;
+}
+
+qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
+{
+       dp_model_t *model = ent->model;
+       r_animcache_entity_t *c;
+       // see if it's already cached this frame
+       if (ent->animcacheindex >= 0)
+       {
+               // add normals/tangents if needed
+               c = r_animcachestate.entity + ent->animcacheindex;
+               if (c->wantnormals)
+                       wantnormals = false;
+               if (c->wanttangents)
+                       wanttangents = false;
+               if (wantnormals || wanttangents)
+                       model->AnimateVertices(model, ent->frameblend, NULL, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL);
+       }
+       else
        {
-               // Flush memory
-               if (r_numAnimCache != 0)
-               {
-                       R_EmptyAnimCache();
+               // see if this ent is worth caching
+               if (r_animcachestate.maxindex <= r_animcachestate.currentindex)
+                       return false;
+               if (!model || !model->Draw || !model->surfmesh.isanimated || !model->AnimateVertices || (ent->frameblend[0].lerp == 1 && ent->frameblend[0].subframe == 0))
+                       return false;
+               // assign it a cache entry and make sure the arrays are big enough
+               R_AnimCache_ResizeEntityCache(r_animcachestate.currentindex, model->surfmesh.num_vertices);
+               ent->animcacheindex = r_animcachestate.currentindex++;
+               c = r_animcachestate.entity + ent->animcacheindex;
+               c->wantnormals = wantnormals;
+               c->wanttangents = wanttangents;
+               model->AnimateVertices(model, ent->frameblend, c->vertex3f, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL);
+       }
+       return true;
+}
 
-                       // Clear any existing animcacheindex references
-                       for (entIdx=0 ; entIdx<r_refdef.scene.numentities ; entIdx++)
-                       {
-                               ent = r_refdef.scene.entities[entIdx];
-                               ent->animcacheindex = 0;
-                       }
-               }
+void R_AnimCache_CacheVisibleEntities(void)
+{
+       int i;
+       qboolean wantnormals;
+       qboolean wanttangents;
+
+       if (!r_animcachestate.maxindex)
                return;
-       }
 
-       // Generate new cache
-       cacheIdx = 0;
-       for (entIdx=0 ; entIdx<r_refdef.scene.numentities ; entIdx++)
-       {
-               ent = r_refdef.scene.entities[entIdx];
+       wantnormals = !r_showsurfaces.integer;
+       wanttangents = !r_showsurfaces.integer && (r_glsl.integer || r_refdef.scene.rtworld || r_refdef.scene.rtdlight);
 
-               if (!r_refdef.viewcache.entityvisible[entIdx])
-               {
-                       ent->animcacheindex = 0;
-                       continue;
-               }
+       // TODO: thread this?
 
-               model = ent->model;
-               if (model && model->Draw != NULL
-               && model->surfmesh.isanimated && model->AnimateVertices && (ent->frameblend[0].lerp != 1 || ent->frameblend[0].subframe != 0))
-               {
-                       R_ResizeAnimCache(cacheIdx, model->surfmesh.num_vertices);
-
-                       // FIXME: Some stable way of determining if normals/tangets aren't going to be needed would be good for optimizing this
-                       // Need to consider deformvertexes and tcgens that need normals and/or tangents (otherwise they'll slow-path generate them later), as well as some rendering settings
-                       bWantNormals = true;
-                       bWantTangents = true;//bWantNormals && (r_glsl.integer && gl_support_fragment_shader);
-                       model->AnimateVertices(
-                               model, ent->frameblend,
-                               r_animCache[cacheIdx].vertexes,
-                               bWantNormals ? r_animCache[cacheIdx].normals : NULL,
-                               bWantTangents ? r_animCache[cacheIdx].sVectors : NULL,
-                               bWantTangents ? r_animCache[cacheIdx].tVectors : NULL
-                       );
-
-                       cacheIdx++;
-                       ent->animcacheindex = cacheIdx;
-               }
-               else
-               {
-                       ent->animcacheindex = 0;
-               }
+       for (i = 0;i < r_refdef.scene.numentities;i++)
+       {
+               if (!r_refdef.viewcache.entityvisible[i])
+                       continue;
+               R_AnimCache_GetEntity(r_refdef.scene.entities[i], wantnormals, wanttangents);
        }
-
-       // Increase our limit if necessary
-       r_numAnimCache = max(r_numAnimCache, cacheIdx);
 }
 
 //==================================================================================
@@ -3065,10 +3355,10 @@ static void R_View_SetFrustum(void)
                VectorNormalize(r_refdef.view.frustum[3].normal);
 
                // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
-               VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, -1024 * slopex, left, -1024 * slopey, up, r_refdef.view.frustumcorner[0]);
-               VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward,  1024 * slopex, left, -1024 * slopey, up, r_refdef.view.frustumcorner[1]);
-               VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, -1024 * slopex, left,  1024 * slopey, up, r_refdef.view.frustumcorner[2]);
-               VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward,  1024 * slopex, left,  1024 * slopey, up, r_refdef.view.frustumcorner[3]);
+               VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, -1024 * r_refdef.view.frustum_x, left, -1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[0]);
+               VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward,  1024 * r_refdef.view.frustum_x, left, -1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[1]);
+               VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, -1024 * r_refdef.view.frustum_x, left,  1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[2]);
+               VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward,  1024 * r_refdef.view.frustum_x, left,  1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[3]);
 
                r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
                r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
@@ -3140,15 +3430,8 @@ void R_View_Update(void)
 
 void R_SetupView(qboolean allowwaterclippingplane)
 {
-       if (!r_refdef.view.useperspective)
-               GL_SetupView_Mode_Ortho(-r_refdef.view.ortho_x, -r_refdef.view.ortho_y, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip);
-       else if (gl_stencil && r_useinfinitefarclip.integer)
-               GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip);
-       else
-               GL_SetupView_Mode_Perspective(r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip);
-
-       GL_SetupView_Orientation_FromEntity(&r_refdef.view.matrix);
-
+       const double *customclipplane = NULL;
+       double plane[4];
        if (r_refdef.view.useclipplane && allowwaterclippingplane)
        {
                // LordHavoc: couldn't figure out how to make this approach the
@@ -3156,18 +3439,31 @@ void R_SetupView(qboolean allowwaterclippingplane)
                vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
                if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
                        dist = r_refdef.view.clipplane.dist;
-               GL_SetupView_ApplyCustomNearClipPlane(r_refdef.view.clipplane.normal[0], r_refdef.view.clipplane.normal[1], r_refdef.view.clipplane.normal[2], dist);
+               plane[0] = r_refdef.view.clipplane.normal[0];
+               plane[1] = r_refdef.view.clipplane.normal[1];
+               plane[2] = r_refdef.view.clipplane.normal[2];
+               plane[3] = dist;
+               customclipplane = plane;
        }
+
+       if (!r_refdef.view.useperspective)
+               R_Viewport_InitOrtho(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, -r_refdef.view.ortho_x, -r_refdef.view.ortho_y, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
+       else if (gl_stencil && r_useinfinitefarclip.integer)
+               R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
+       else
+               R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
+       R_SetViewport(&r_refdef.view.viewport);
 }
 
 void R_ResetViewRendering2D(void)
 {
+       r_viewport_t viewport;
        DrawQ_Finish();
 
        // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
-       qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
-       GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
-       GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
+       R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, 0, 0, 1, 1, -10, 100, NULL);
+       R_SetViewport(&viewport);
+       GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
        GL_Color(1, 1, 1, 1);
        GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
        GL_BlendFunc(GL_ONE, GL_ZERO);
@@ -3196,7 +3492,7 @@ void R_ResetViewRendering3D(void)
        // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
        qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
        R_SetupView(true);
-       GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
+       GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
        GL_Color(1, 1, 1, 1);
        GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
        GL_BlendFunc(GL_ONE, GL_ZERO);
@@ -3702,7 +3998,7 @@ void R_HDR_RenderBloomTexture(void)
 
        // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer?  it might improve SLI performance.
        // TODO: add exposure compensation features
-       // TODO: add fp16 framebuffer support
+       // TODO: add fp16 framebuffer support (using GL_EXT_framebuffer_object)
 
        r_refdef.view.showdebug = false;
        r_refdef.view.colorscale *= r_bloom_colorscale.value / bound(1, r_hdr_range.value, 16);
@@ -3757,22 +4053,21 @@ static void R_BlendView(void)
 
                if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))
                {  
-                       // declare alpha variable
-                       float a;
+                       // declare variables
                        float speed;
                        static float avgspeed;
 
                        speed = VectorLength(cl.movement_velocity);
 
-                       a = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_vcoeff.value), 1);
-                       avgspeed = avgspeed * (1 - a) + speed * a;
+                       cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_vcoeff.value), 1);
+                       avgspeed = avgspeed * (1 - cl.motionbluralpha) + speed * cl.motionbluralpha;
 
                        speed = (avgspeed - r_motionblur_vmin.value) / max(1, r_motionblur_vmax.value - r_motionblur_vmin.value);
                        speed = bound(0, speed, 1);
                        speed = speed * (1 - r_motionblur_bmin.value) + r_motionblur_bmin.value;
 
                        // calculate values into a standard alpha
-                       a = 1 - exp(-
+                       cl.motionbluralpha = 1 - exp(-
                                        (
                                         (r_motionblur.value * speed / 80)
                                         +
@@ -3782,18 +4077,14 @@ static void R_BlendView(void)
                                        max(0.0001, cl.time - cl.oldtime) // fps independent
                                   );
 
-                       a *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
-                       a = bound(0, a, r_motionblur_maxblur.value);
-
-                       // developer debug of current value
-                       if (r_motionblur_debug.value) { Con_Printf("blur alpha = %f\n", a); }
-
+                       cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
+                       cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
                        // apply the blur
-                       if (a > 0)
+                       if (cl.motionbluralpha > 0)
                        {
                                R_SetupGenericShader(true);
                                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-                               GL_Color(1, 1, 1, a); // to do: add color changing support for damage blur
+                               GL_Color(1, 1, 1, cl.motionbluralpha);
                                R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
                                R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
                                R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
@@ -3809,8 +4100,8 @@ static void R_BlendView(void)
        if (r_glsl.integer && gl_support_fragment_shader && (r_bloomstate.texture_screen || r_bloomstate.texture_bloom))
        {
                unsigned int permutation =
-                         (r_bloomstate.texture_bloom ? SHADERPERMUTATION_GLOW : 0)
-                       | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0)
+                         (r_bloomstate.texture_bloom ? SHADERPERMUTATION_BLOOM : 0)
+                       | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
                        | ((v_glslgamma.value && !vid_gammatables_trivial) ? SHADERPERMUTATION_GAMMARAMPS : 0)
                        | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
                        | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
@@ -3956,13 +4247,6 @@ void R_UpdateFogColor(void) // needs to be called before HDR subrender too, as t
                {
                        vec3_t fogvec;
                        VectorCopy(r_refdef.fogcolor, fogvec);
-                       if(r_glsl.integer && (r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)) // need to support contrast boost
-                       {
-                               //   color.rgb /= ((ContrastBoost - 1) * color.rgb + 1);
-                               fogvec[0] *= r_glsl_contrastboost.value / ((r_glsl_contrastboost.value - 1) * fogvec[0] + 1);
-                               fogvec[1] *= r_glsl_contrastboost.value / ((r_glsl_contrastboost.value - 1) * fogvec[1] + 1);
-                               fogvec[2] *= r_glsl_contrastboost.value / ((r_glsl_contrastboost.value - 1) * fogvec[2] + 1);
-                       }
                        //   color.rgb *= ContrastBoost * SceneBrightness;
                        VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
                        r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
@@ -3990,7 +4274,7 @@ void R_UpdateVariables(void)
        r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
        r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
 
-       r_refdef.scene.rtworld = r_shadow_realtime_world.integer;
+       r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
        r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
        r_refdef.scene.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer;
        r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && gl_stencil;
@@ -4132,9 +4416,13 @@ R_RenderView
 */
 void R_RenderView(void)
 {
+       if (r_timereport_active)
+               R_TimeReport("start");
        r_frame++; // used only by R_GetCurrentTexture
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 
+       R_AnimCache_NewFrame();
+
        if (r_refdef.view.isoverlay)
        {
                // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
@@ -4274,6 +4562,8 @@ void R_RenderScene(void)
                        R_TimeReport("bmodelsky");
        }
 
+       R_AnimCache_CacheVisibleEntities();
+
        if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
        {
                r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
@@ -4298,7 +4588,6 @@ void R_RenderScene(void)
        if (r_refdef.scene.extraupdate)
                S_ExtraUpdate ();
 
-       R_RunAnimCache();
        R_DrawModels();
        if (r_timereport_active)
                R_TimeReport("models");
@@ -4307,12 +4596,10 @@ void R_RenderScene(void)
        if (r_refdef.scene.extraupdate)
                S_ExtraUpdate ();
 
-       if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
+       if (r_shadows.integer > 0 && !r_shadows_drawafterrtlightning.integer && r_refdef.lightmapintensity > 0)
        {
                R_DrawModelShadows();
-
                R_ResetViewRendering3D();
-
                // don't let sound skip if going slow
                if (r_refdef.scene.extraupdate)
                        S_ExtraUpdate ();
@@ -4326,6 +4613,15 @@ void R_RenderScene(void)
        if (r_refdef.scene.extraupdate)
                S_ExtraUpdate ();
 
+       if (r_shadows.integer > 0 && r_shadows_drawafterrtlightning.integer && r_refdef.lightmapintensity > 0)
+       {
+               R_DrawModelShadows();
+               R_ResetViewRendering3D();
+               // don't let sound skip if going slow
+               if (r_refdef.scene.extraupdate)
+                       S_ExtraUpdate ();
+       }
+
        if (cl.csqc_vidvars.drawworld)
        {
                R_DrawLightningBeams();
@@ -5069,7 +5365,8 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        if (t->currentmaterialflags & MATERIALFLAG_WALL)
        {
                int layerflags = 0;
-               int blendfunc1, blendfunc2, depthmask;
+               int blendfunc1, blendfunc2;
+               qboolean depthmask;
                if (t->currentmaterialflags & MATERIALFLAG_ADD)
                {
                        blendfunc1 = GL_SRC_ALPHA;
@@ -5279,12 +5576,12 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        }
        if (model->surfmesh.isanimated && model->AnimateVertices && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].subframe != 0))
        {
-               if (ent->animcacheindex != 0)
+               if (R_AnimCache_GetEntity((entity_render_t *)ent, wantnormals, wanttangents))
                {
-                       rsurface.modelvertex3f = r_animCache[ent->animcacheindex-1].vertexes;
-                       rsurface.modelsvector3f = wanttangents ? r_animCache[ent->animcacheindex-1].sVectors : NULL;
-                       rsurface.modeltvector3f = wanttangents ? r_animCache[ent->animcacheindex-1].tVectors : NULL;
-                       rsurface.modelnormal3f = wantnormals ? r_animCache[ent->animcacheindex-1].normals : NULL;
+                       rsurface.modelvertex3f = r_animcachestate.entity[ent->animcacheindex].vertex3f;
+                       rsurface.modelsvector3f = wanttangents ? r_animcachestate.entity[ent->animcacheindex].svector3f : NULL;
+                       rsurface.modeltvector3f = wanttangents ? r_animcachestate.entity[ent->animcacheindex].tvector3f : NULL;
+                       rsurface.modelnormal3f = wantnormals ? r_animcachestate.entity[ent->animcacheindex].normal3f : NULL;
                }
                else if (wanttangents)
                {
@@ -5402,7 +5699,7 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta
                        rsurface.normal3f = rsurface.modelnormal3f = rsurface.array_modelnormal3f;
                        rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject = 0;
                        rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset = 0;
-                       Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer);
+                       Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
                }
                if (generatetangents && !rsurface.modelsvector3f)
                {
@@ -5412,7 +5709,7 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta
                        rsurface.tvector3f = rsurface.modeltvector3f = rsurface.array_modeltvector3f;
                        rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject = 0;
                        rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset = 0;
-                       Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f, r_smoothnormals_areaweighting.integer);
+                       Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
                }
        }
        rsurface.vertex3f  = rsurface.modelvertex3f;
@@ -5475,8 +5772,8 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta
                                                VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
                                        }
                                }
-                               Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer);
-                               Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer);
+                               Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer != 0);
+                               Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0);
                        }
                        rsurface.vertex3f = rsurface.array_deformedvertex3f;
                        rsurface.vertex3f_bufferobject = 0;
@@ -5606,8 +5903,8 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta
                                                VectorMAMAM(1, v1, -f, right, f, newright, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
                                        }
                                }
-                               Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer);
-                               Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer);
+                               Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer != 0);
+                               Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0);
                        }
                        rsurface.vertex3f = rsurface.array_deformedvertex3f;
                        rsurface.vertex3f_bufferobject = 0;
@@ -5638,7 +5935,7 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta
                                        normal[2] += deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]);
                                        VectorNormalize(normal);
                                }
-                               Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer);
+                               Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0);
                        }
                        rsurface.svector3f = rsurface.array_deformedsvector3f;
                        rsurface.svector3f_bufferobject = 0;
@@ -6464,7 +6761,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **t
                GL_Color(1, 1, 1, 1);
                R_Mesh_ColorPointer(NULL, 0, 0);
 
-               R_SetupSurfaceShader(vec3_origin, rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND);
+               R_SetupSurfaceShader(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND);
                if (r_glsl_permutation)
                {
                        RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist);
@@ -6487,7 +6784,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **t
                R_Mesh_TexBind(GL20TU_REFLECTION, R_GetTexture(r_texture_white)); // changed per surface
        }
 
-       R_SetupSurfaceShader(vec3_origin, rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE);
+       R_SetupSurfaceShader(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE);
        if (!r_glsl_permutation)
                return;
 
@@ -6927,7 +7224,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
        // to a model, knowing that they are meaningless otherwise
        if (ent == r_refdef.scene.worldentity)
                RSurf_ActiveWorldEntity();
-       else if ((ent->effects & EF_FULLBRIGHT) || (r_showsurfaces.integer && r_showsurfaces.integer != 3) || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
+       else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
                RSurf_ActiveModelEntity(ent, false, false);
        else
                RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
@@ -7490,7 +7787,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
        // to a model, knowing that they are meaningless otherwise
        if (ent == r_refdef.scene.worldentity)
                RSurf_ActiveWorldEntity();
-       else if ((ent->effects & EF_FULLBRIGHT) || (r_showsurfaces.integer && r_showsurfaces.integer != 3) || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
+       else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
                RSurf_ActiveModelEntity(ent, false, false);
        else
                RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader && !depthonly);