]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
added indirection cube map for shadowmapping and revised filtering modes
[xonotic/darkplaces.git] / gl_rmain.c
index f48f40863f4bcf55b74a78d2f7f5fbe71bf78156..473635b204a48e651f197446807736a46743dfd3 100644 (file)
@@ -75,7 +75,7 @@ cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows fro
 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_drawafterrtlighting = {CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
 cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
 cvar_t r_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"};
@@ -165,6 +165,8 @@ static struct r_bloomstate_s
        float screentexcoord2f[8];
        float bloomtexcoord2f[8];
        float offsettexcoord2f[8];
+
+       r_viewport_t viewport;
 }
 r_bloomstate;
 
@@ -193,7 +195,7 @@ char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH];
 skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD];
 
 /// vertex coordinates for a quad that covers the screen exactly
-const static float r_screenvertex3f[12] =
+const float r_screenvertex3f[12] =
 {
        0, 0, 0,
        1, 0, 0,
@@ -447,9 +449,14 @@ static const char *builtinshaderstring =
 "// 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"
+"# ifdef HASTEXTUREGATHER\n"
+"#   extension GL_ARB_texture_gather : enable\n"
+"# else\n"
+"#   ifdef HASTEXTURE4\n"
+"#     extension GL_AMD_texture_texture4 : enable\n"
+"#     define textureGather texture4\n"
+"#   endif\n"
+"# endif\n"
 "#endif\n"
 "\n"
 "// common definitions between vertex shader and fragment shader:\n"
@@ -457,7 +464,7 @@ static const char *builtinshaderstring =
 "//#ifdef __GLSL_CG_DATA_TYPES\n"
 "//# define myhalf half\n"
 "//# define myhalf2 half2\n"
-"//# define myhalf3 half3\n"
+"//# define myhalf3half3\n"
 "//# define myhalf4 half4\n"
 "//#else\n"
 "# define myhalf float\n"
@@ -552,7 +559,7 @@ static const char *builtinshaderstring =
 "      //apply saturation BEFORE gamma ramps, so v_glslgamma value does not matter\n"
 "      myhalf y = dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114));\n"
 "      //gl_FragColor = vec3(y) + (gl_FragColor.rgb - vec3(y)) * Saturation;\n"
-"      gl_FragColor.rgb = mix(vec3(y), gl_FragColor.rgb, Saturation);\n" // TODO: test this on ATI
+"      gl_FragColor.rgb = mix(vec3(y), gl_FragColor.rgb, Saturation);\n"
 "#endif\n"
 "\n"
 "#ifdef USEGAMMARAMPS\n"
@@ -759,32 +766,15 @@ static const char *builtinshaderstring =
 "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"
+"# ifdef USESHADOWSAMPLER\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"
+"uniform samplerCube Texture_CubeProjection;\n"
 "#endif\n"
 "\n"
 "uniform myhalf3 LightColor;\n"
@@ -882,59 +872,51 @@ 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"
+"#ifdef USESHADOWMAPRECT \n"
+"uniform vec4 ShadowMap_TextureScale;\n"
+"#if 0\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 0\n"
+"      vec2 tc;\n"
+"      vec2 offset;\n"
+"      float ma;\n"
 "      if (adir.x > adir.y)\n"
 "      {\n"
 "              if (adir.x > adir.z)\n"
 "              {\n"
-"                      d = 0.5 / adir.x;\n"
+"                      ma = 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"
+"                              tc = vec2(-dir.z, -dir.y);\n"
+"                              offset = vec2(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"
+"                              tc = vec2( dir.z, -dir.y);\n"
+"                              offset = vec2(1.5, 0.5);\n"
 "                      }\n"
 "              }\n"
 "              else\n"
 "              {\n"
-"                      d = 0.5 / adir.z;\n"
+"            ma = 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"
+"                              tc = vec2( dir.x, -dir.y);\n"
+"                              offset = vec2(0.5, 2.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"
+"                              tc = vec2(-dir.x, -dir.y);\n"
+"                              offset = vec2(1.5, 2.5);\n"
 "                      }\n"
 "              }\n"
 "      }\n"
@@ -942,69 +924,45 @@ static const char *builtinshaderstring =
 "      {\n"
 "              if (adir.y > adir.z)\n"
 "              {\n"
-"                      d = 0.5 / adir.y;\n"
+"            ma = 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"
+"                              tc = vec2( dir.x,  dir.z);\n"
+"                              offset = vec2(0.5, 1.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"
+"                              tc = vec2( dir.x, -dir.z);\n"
+"                              offset = vec2(1.5, 1.5);\n"
 "                      }\n"
 "              }\n"
 "              else\n"
 "              {\n"
-"                      d = 0.5 / adir.z;\n"
+"            ma = 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"
+"                              tc = vec2(dir.x, -dir.y);\n"
+"                              offset = vec2(0.5, 2.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"
+"                              tc = vec2(-dir.x, -dir.y);\n"
+"                              offset = vec2(1.5, 2.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"
+"      return vec3(tc * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma + vec3(offset * ShadowMap_Parameters.y, ShadowMap_Parameters.z);\n"
+"# else\n"
+"    return vec3(textureCube(Texture_CubeProjection, dir.xyz).ra * ShadowMap_TextureScale.xy, ShadowMap_TextureScale.z + ShadowMap_TextureScale.w / max(max(adir.x, adir.y), adir.z));\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"
+"#endif // USESHADOWMAPRECT\n"
 "\n"
 "#if !showshadowmap\n"
 "# ifdef USESHADOWMAPRECT\n"
@@ -1012,43 +970,80 @@ static const char *builtinshaderstring =
 "{\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"
+"#  ifdef USESHADOWSAMPLER\n"
+"\n"
+"#    ifdef USESHADOWMAPPCF\n"
+"      f = dot(vec4(0.25),\n"
+"                      vec4(shadow2DRect(Texture_ShadowMapRect, shadowmaptc.xyz + vec3(-0.4,  1.0, 0.0)).r,\n"
+"                               shadow2DRect(Texture_ShadowMapRect, shadowmaptc.xyz + vec3(-1.0, -0.4, 0.0)).r,\n"
+"                               shadow2DRect(Texture_ShadowMapRect, shadowmaptc.xyz + vec3( 0.4, -1.0, 0.0)).r,\n"
+"                               shadow2DRect(Texture_ShadowMapRect, shadowmaptc.xyz + vec3( 1.0,  0.4, 0.0)).r));\n"
+"#    else\n"
+"    f = shadow2DRect(Texture_ShadowMapRect, shadowmaptc).r;\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"
+"#    ifdef USESHADOWMAPPCF\n"
+"#      if defined(HASTEXTUREGATHER) || defined(HASTEXTURE4)\n"
+"    vec2 offset = fract(shadowmaptc.xy - 0.5);\n"
+"    vec4 group1 = step(shadowmaptc.z, textureGather(Texture_ShadowMapRect, shadowmaptc.xy + vec2(-1.0, -1.0))),\n"
+"         group2 = step(shadowmaptc.z, textureGather(Texture_ShadowMapRect, shadowmaptc.xy + vec2( 1.0, -1.0))),\n"
+"         group3 = step(shadowmaptc.z, textureGather(Texture_ShadowMapRect, shadowmaptc.xy + vec2(-1.0,  1.0))),\n"
+"         group4 = step(shadowmaptc.z, textureGather(Texture_ShadowMapRect, shadowmaptc.xy + vec2( 1.0,  1.0))),\n"
+"         cols = vec4(group1.ab, group2.ab) + vec4(group3.rg, group4.rg) +\n"
+"                mix(vec4(group1.rg, group2.rg), vec4(group3.ab, group4.ab), offset.y);\n"
+"    f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
+"#      elif 1\n"
+"    vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n"
+"    vec4 row1 = step(shadowmaptc.z,\n"
+"                    vec4(texture2DRect(Texture_ShadowMapRect, center + vec2(-1.0, -1.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, center + vec2( 0.0, -1.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, center + vec2( 1.0, -1.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, center + vec2( 2.0, -1.0)).r)),\n"
+"         row2 = step(shadowmaptc.z,\n"
+"                    vec4(texture2DRect(Texture_ShadowMapRect, center + vec2(-1.0,  0.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, center).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, center + vec2( 1.0,  0.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, center + vec2( 2.0,  0.0)).r)),\n"
+"         row3 = step(shadowmaptc.z,\n"
+"                    vec4(texture2DRect(Texture_ShadowMapRect, center + vec2(-1.0,  1.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, center + vec2( 0.0,  1.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, center + vec2( 1.0,  1.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, center + vec2( 2.0,  1.0)).r)),\n"
+"         row4 = step(shadowmaptc.z,\n"
+"                    vec4(texture2DRect(Texture_ShadowMapRect, center + vec2(-1.0,  2.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, center + vec2( 0.0,  2.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, center + vec2( 1.0,  2.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, center + vec2( 2.0,  2.0)).r)),\n"
+"         cols = row2 + row3 + mix(row1, row4, offset.y);\n"
+"    f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
+"#      else\n"
+"    vec2 offset = fract(shadowmaptc.xy);\n"
+"    vec3 row1 = step(shadowmaptc.z,\n"
+"                    vec3(texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2(-1.0, -1.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2( 0.0, -1.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2( 1.0, -1.0)).r)),\n"
+"         row2 = step(shadowmaptc.z,\n"
+"                    vec3(texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2(-1.0,  0.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2( 1.0,  0.0)).r)),\n"
+"         row3 = step(shadowmaptc.z,\n"
+"                    vec3(texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2(-1.0,  1.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2( 0.0,  1.0)).r,\n"
+"                         texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2( 1.0,  1.0)).r)),\n"
+"         cols = row2 + mix(row1, row3, offset.y);\n"
+"    f = dot(mix(cols.xy, cols.yz, offset.x), vec2(0.25));\n"
+"#      endif\n"
+"#    else\n"
+"    f = step(shadowmaptc.z, texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy).r);\n"
+"#    endif\n"
+"\n"
 "#  endif\n"
 "      return f;\n"
 "}\n"
 "# endif\n"
+"\n"
 "#endif\n"
 "\n"
 "\n"
@@ -1072,15 +1067,15 @@ static const char *builtinshaderstring =
 "      // content.\n"
 "      // Remove this 'ack once we have a better way to stop this thing from\n"
 "      // 'appening.\n"
-"      float f = min(1, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.05, 0.05))) / 0.02);\n"
-"      f      *= min(1, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.05, -0.05))) / 0.02);\n"
-"      f      *= min(1, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.05, 0.05))) / 0.02);\n"
-"      f      *= min(1, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.05, -0.05))) / 0.02);\n"
+"      float f = min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.01, -0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
 "      ScreenTexCoord.xy = mix(SafeScreenTexCoord.xy, ScreenTexCoord.xy, f);\n"
-"      f       = min(1, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.05, 0.05))) / 0.02);\n"
-"      f      *= min(1, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.05, -0.05))) / 0.02);\n"
-"      f      *= min(1, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.05, 0.05))) / 0.02);\n"
-"      f      *= min(1, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.05, -0.05))) / 0.02);\n"
+"      f       = min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.01, -0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
 "      ScreenTexCoord.zw = mix(SafeScreenTexCoord.zw, ScreenTexCoord.zw, f);\n"
 "      float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * ReflectFactor + ReflectOffset;\n"
 "      gl_FragColor = mix(texture2D(Texture_Refraction, ScreenTexCoord.xy) * RefractColor, texture2D(Texture_Reflection, ScreenTexCoord.zw) * ReflectColor, Fresnel);\n"
@@ -1107,10 +1102,10 @@ static const char *builtinshaderstring =
 "      // content.\n"
 "      // Remove this 'ack once we have a better way to stop this thing from\n"
 "      // 'appening.\n"
-"      float f = min(1, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.05, 0.05))) / 0.02);\n"
-"      f      *= min(1, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.05, -0.05))) / 0.02);\n"
-"      f      *= min(1, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.05, 0.05))) / 0.02);\n"
-"      f      *= min(1, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.05, -0.05))) / 0.02);\n"
+"      float f = min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, -0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
 "      ScreenTexCoord = mix(SafeScreenTexCoord, ScreenTexCoord, f);\n"
 "      gl_FragColor = texture2D(Texture_Refraction, ScreenTexCoord) * RefractColor;\n"
 "}\n"
@@ -1187,7 +1182,7 @@ static const char *builtinshaderstring =
 "#  endif\n"
 "# endif\n"
 "\n"
-"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAPCUBE) || defined(USESHADOWMAP2D)\n"
+"#ifdef USESHADOWMAPRECT\n"
 "#if !showshadowmap\n"
 "      color.rgb *= ShadowMapCompare(CubeVector);\n"
 "#endif\n"
@@ -1344,10 +1339,10 @@ static const char *builtinshaderstring =
 "      // content.\n"
 "      // Remove this 'ack once we have a better way to stop this thing from\n"
 "      // 'appening.\n"
-"      float f = min(1, length(texture2D(Texture_Reflection, ScreenTexCoord + vec2(0.05, 0.05))) / 0.02);\n"
-"      f      *= min(1, length(texture2D(Texture_Reflection, ScreenTexCoord + vec2(0.05, -0.05))) / 0.02);\n"
-"      f      *= min(1, length(texture2D(Texture_Reflection, ScreenTexCoord + vec2(-0.05, 0.05))) / 0.02);\n"
-"      f      *= min(1, length(texture2D(Texture_Reflection, ScreenTexCoord + vec2(-0.05, -0.05))) / 0.02);\n"
+"      float f = min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord + vec2(0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord + vec2(0.01, -0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
+"      f      *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
 "      ScreenTexCoord = mix(SafeScreenTexCoord, ScreenTexCoord, f);\n"
 "      color.rgb = mix(color.rgb, myhalf3(texture2D(Texture_Reflection, ScreenTexCoord)) * ReflectColor.rgb, ReflectColor.a);\n"
 "#endif\n"
@@ -1356,28 +1351,12 @@ static const char *builtinshaderstring =
 "\n"
 "#if showshadowmap\n"
 "# ifdef USESHADOWMAPRECT\n"
-"#  if useshadowsamplerrect\n"
+"#  ifdef USESHADOWSAMPLER\n"
 "      gl_FragColor = shadow2DRect(Texture_ShadowMapRect, GetShadowMapTC2D(CubeVector).xyz);\n"
 "#  else\n"
 "      gl_FragColor = texture2DRect(Texture_ShadowMapRect, GetShadowMapTC2D(CubeVector).xy);\n"
 "#  endif\n"
 "# endif\n"
-"\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"
@@ -1427,8 +1406,8 @@ typedef enum shaderpermutation_e
        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_SHADOWMAPPCF = 1<<12, //< (lightsource) use percentage closer filtering on shadowmap test results
+       SHADERPERMUTATION_SHADOWSAMPLER = 1<<13, //< (lightsource) use hardware shadowmap test
        SHADERPERMUTATION_LIMIT = 1<<14, ///< size of permutations array
        SHADERPERMUTATION_COUNT = 14 ///< size of shaderpermutationinfo array
 }
@@ -1449,8 +1428,8 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
        {"#define USEOFFSETMAPPING\n", " offsetmapping"},
        {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
        {"#define USESHADOWMAPRECT\n", " shadowmaprect"},
-       {"#define USESHADOWMAPCUBE\n", " shadowmapcube"},
-       {"#define USESHADOWMAP2D\n", " shadowmap2d"},
+       {"#define USESHADOWMAPPCF\n", " shadowmappcf"},
+       {"#define USESHADOWSAMPLER\n", " shadowsampler"},
 };
 
 /// this enum is multiplied by SHADERPERMUTATION_MODEBASE
@@ -1519,8 +1498,7 @@ typedef struct r_glsl_permutation_s
        int loc_Texture_Refraction;
        int loc_Texture_Reflection;
        int loc_Texture_ShadowMapRect;
-       int loc_Texture_ShadowMapCube;
-       int loc_Texture_ShadowMap2D;
+       int loc_Texture_CubeProjection;
        int loc_FogColor;
        int loc_LightPosition;
        int loc_EyePosition;
@@ -1555,7 +1533,6 @@ 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;
 }
@@ -1686,8 +1663,7 @@ static void R_GLSL_CompilePermutation(unsigned int mode, unsigned int permutatio
                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_Texture_CubeProjection     = qglGetUniformLocationARB(p->program, "Texture_CubeProjection");  
                p->loc_FogColor                   = qglGetUniformLocationARB(p->program, "FogColor");
                p->loc_LightPosition              = qglGetUniformLocationARB(p->program, "LightPosition");
                p->loc_EyePosition                = qglGetUniformLocationARB(p->program, "EyePosition");
@@ -1722,7 +1698,6 @@ 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
@@ -1747,8 +1722,7 @@ static void R_GLSL_CompilePermutation(unsigned int mode, unsigned int permutatio
                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);
+               if (p->loc_Texture_CubeProjection  >= 0) qglUniform1iARB(p->loc_Texture_CubeProjection , GL20TU_CUBEPROJECTION);
                CHECKGLERROR
                if (developer.integer)
                        Con_Printf("GLSL shader %s compiled.\n", permutationname);
@@ -1906,12 +1880,11 @@ void R_SetupShowDepthShader(void)
 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_texturescale[4];
 extern float r_shadow_shadowmap_parameters[4];
+extern int r_shadow_shadowmode;
+extern int r_shadow_shadowmapfilter;
 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
@@ -1951,12 +1924,14 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                        permutation |= SHADERPERMUTATION_FOG;
                if (rsurface.texture->colormapping)
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
-               if (r_shadow_usingshadowmaprect)
+               if (r_shadow_shadowmode)
                        permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
-               if (r_shadow_usingshadowmapcube)
-                       permutation |= SHADERPERMUTATION_SHADOWMAPCUBE;
-               if (r_shadow_usingshadowmap2d)
-                       permutation |= SHADERPERMUTATION_SHADOWMAP2D;
+               if (r_shadow_shadowmapfilter == 3)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+               else if (r_shadow_shadowmapfilter == 2)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPPCF | SHADERPERMUTATION_SHADOWSAMPLER;
+               else if (r_shadow_shadowmapfilter == 1)
+                       permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
        }
        else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
        {
@@ -2080,8 +2055,7 @@ 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_TextureScale >= 0) qglUniform4fARB(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1], r_shadow_shadowmap_texturescale[2], r_shadow_shadowmap_texturescale[3]);
                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
@@ -2746,7 +2720,7 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_fullbright);
        Cvar_RegisterVariable(&r_shadows);
        Cvar_RegisterVariable(&r_shadows_darken);
-       Cvar_RegisterVariable(&r_shadows_drawafterrtlightning);
+       Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
        Cvar_RegisterVariable(&r_shadows_castfrombmodels);
        Cvar_RegisterVariable(&r_shadows_throwdistance);
        Cvar_RegisterVariable(&r_shadows_throwdirection);
@@ -3485,11 +3459,11 @@ void R_SetupView(qboolean allowwaterclippingplane)
        }
 
        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);
+               R_Viewport_InitOrtho(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, vid.height - r_refdef.view.height - 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);
+               R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, vid.height - r_refdef.view.height - 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_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, vid.height - r_refdef.view.height - 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);
 }
 
@@ -3499,9 +3473,9 @@ void R_ResetViewRendering2D(void)
        DrawQ_Finish();
 
        // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
-       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_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, vid.height - r_refdef.view.height - 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_Scissor(viewport.x, viewport.y, viewport.width, viewport.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);
@@ -3527,10 +3501,8 @@ void R_ResetViewRendering3D(void)
 {
        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
        R_SetupView(true);
-       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_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.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);
@@ -3563,8 +3535,8 @@ static void R_Water_StartFrame(void)
 
        // set waterwidth and waterheight to the water resolution that will be
        // used (often less than the screen resolution for faster rendering)
-       waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
-       waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
+       waterwidth = (int)bound(1, vid.width * r_water_resolutionmultiplier.value, vid.width);
+       waterheight = (int)bound(1, vid.height * r_water_resolutionmultiplier.value, vid.height);
 
        // calculate desired texture sizes
        // can't use water if the card does not support the texture size
@@ -3601,6 +3573,10 @@ static void R_Water_StartFrame(void)
                r_waterstate.textureheight = textureheight;
        }
 
+       // when doing a reduced render (HDR) we want to use a smaller area
+       waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
+       waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
+
        if (r_waterstate.waterwidth)
        {
                r_waterstate.enabled = true;
@@ -3740,7 +3716,7 @@ static void R_Water_ProcessPlanes(void)
                        R_Mesh_TexBind(0, R_GetTexture(p->texture_refraction));
                        GL_ActiveTexture(0);
                        CHECKGLERROR
-                       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
+                       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);CHECKGLERROR
                }
 
                if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
@@ -3771,7 +3747,7 @@ static void R_Water_ProcessPlanes(void)
                        R_Mesh_TexBind(0, R_GetTexture(p->texture_reflection));
                        GL_ActiveTexture(0);
                        CHECKGLERROR
-                       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
+                       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);CHECKGLERROR
                }
        }
        r_waterstate.renderingscene = false;
@@ -3794,11 +3770,11 @@ void R_Bloom_StartFrame(void)
 
        // set bloomwidth and bloomheight to the bloom resolution that will be
        // used (often less than the screen resolution for faster rendering)
-       r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
-       r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_refdef.view.height / r_refdef.view.width;
-       r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_refdef.view.height);
-       r_bloomstate.bloomwidth = min(r_bloomstate.bloomwidth, gl_max_texture_size);
-       r_bloomstate.bloomheight = min(r_bloomstate.bloomheight, gl_max_texture_size);
+       r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, vid.height);
+       r_bloomstate.bloomheight = r_bloomstate.bloomwidth * vid.height / vid.width;
+       r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, vid.height);
+       r_bloomstate.bloomwidth = bound(1, r_bloomstate.bloomwidth, gl_max_texture_size);
+       r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, gl_max_texture_size);
 
        // calculate desired texture sizes
        if (gl_support_arb_texture_non_power_of_two)
@@ -3851,6 +3827,13 @@ void R_Bloom_StartFrame(void)
                        r_bloomstate.texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", r_bloomstate.bloomtexturewidth, r_bloomstate.bloomtextureheight, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
        }
 
+       // when doing a reduced render (HDR) we want to use a smaller area
+       r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.height);
+       r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_refdef.view.height / r_refdef.view.width;
+       r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_refdef.view.height);
+       r_bloomstate.bloomwidth = bound(1, r_bloomstate.bloomwidth, r_bloomstate.bloomtexturewidth);
+       r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_bloomstate.bloomtextureheight);
+
        // set up a texcoord array for the full resolution screen image
        // (we have to keep this around to copy back during final render)
        r_bloomstate.screentexcoord2f[0] = 0;
@@ -3878,6 +3861,8 @@ void R_Bloom_StartFrame(void)
                r_bloomstate.enabled = true;
                r_bloomstate.hdr = r_hdr.integer != 0;
        }
+
+       R_Viewport_InitOrtho(&r_bloomstate.viewport, &identitymatrix, r_refdef.view.x, vid.height - r_bloomstate.bloomheight - r_refdef.view.y, r_bloomstate.bloomwidth, r_bloomstate.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
 }
 
 void R_Bloom_CopyBloomTexture(float colorscale)
@@ -3886,7 +3871,7 @@ void R_Bloom_CopyBloomTexture(float colorscale)
 
        // scale down screen texture to the bloom texture size
        CHECKGLERROR
-       qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
+       R_SetViewport(&r_bloomstate.viewport);
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_Color(colorscale, colorscale, colorscale, 1);
        // TODO: optimize with multitexture or GLSL
@@ -3901,8 +3886,8 @@ void R_Bloom_CopyBloomTexture(float colorscale)
        R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
        GL_ActiveTexture(0);
        CHECKGLERROR
-       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
-       r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height);CHECKGLERROR
+       r_refdef.stats.bloom_copypixels += r_bloomstate.viewport.width * r_bloomstate.viewport.height;
 }
 
 void R_Bloom_CopyHDRTexture(void)
@@ -3910,8 +3895,8 @@ void R_Bloom_CopyHDRTexture(void)
        R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
        GL_ActiveTexture(0);
        CHECKGLERROR
-       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
-       r_refdef.stats.bloom_copypixels += r_refdef.view.width * r_refdef.view.height;
+       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);CHECKGLERROR
+       r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
 }
 
 void R_Bloom_MakeTexture(void)
@@ -3928,7 +3913,7 @@ void R_Bloom_MakeTexture(void)
 
        // we have a bloom image in the framebuffer
        CHECKGLERROR
-       qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
+       R_SetViewport(&r_bloomstate.viewport);
 
        for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
        {
@@ -3944,8 +3929,8 @@ void R_Bloom_MakeTexture(void)
                // copy the vertically blurred bloom view to a texture
                GL_ActiveTexture(0);
                CHECKGLERROR
-               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
-               r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height);CHECKGLERROR
+               r_refdef.stats.bloom_copypixels += r_bloomstate.viewport.width * r_bloomstate.viewport.height;
        }
 
        range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320;
@@ -3990,8 +3975,8 @@ void R_Bloom_MakeTexture(void)
                // copy the vertically blurred bloom view to a texture
                GL_ActiveTexture(0);
                CHECKGLERROR
-               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
-               r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height);CHECKGLERROR
+               r_refdef.stats.bloom_copypixels += r_bloomstate.viewport.width * r_bloomstate.viewport.height;
        }
 
        // apply subtract last
@@ -4018,8 +4003,8 @@ void R_Bloom_MakeTexture(void)
                R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
                GL_ActiveTexture(0);
                CHECKGLERROR
-               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
-               r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height);CHECKGLERROR
+               r_refdef.stats.bloom_copypixels += r_bloomstate.viewport.width * r_bloomstate.viewport.height;
        }
 }
 
@@ -4051,8 +4036,9 @@ void R_HDR_RenderBloomTexture(void)
        if (r_timereport_active)
                R_TimeReport("visibility");
 
+       // only do secondary renders with HDR if r_hdr is 2 or higher
        r_waterstate.numwaterplanes = 0;
-       if (r_waterstate.enabled)
+       if (r_waterstate.enabled && r_hdr.integer >= 2)
                R_RenderWaterPlanes();
 
        r_refdef.view.showdebug = true;
@@ -4126,13 +4112,13 @@ static void R_BlendView(void)
                                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);
-                               r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
+                               r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
                        }
                }
 
                // copy view into the screen texture
-               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
-               r_refdef.stats.bloom_copypixels += r_refdef.view.width * r_refdef.view.height;
+               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);CHECKGLERROR
+               r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
        }
 
        if (r_glsl.integer && gl_support_fragment_shader && (r_bloomstate.texture_screen || r_bloomstate.texture_bloom))
@@ -4201,7 +4187,7 @@ static void R_BlendView(void)
                if (r_glsl_permutation->loc_Saturation >= 0)
                        qglUniform1fARB(r_glsl_permutation->loc_Saturation, r_glsl_saturation.value);
                R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
-               r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
+               r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
                return;
        }
 
@@ -4221,7 +4207,7 @@ static void R_BlendView(void)
                R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
                R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
                R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
-               r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
+               r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
        }
        else if (r_bloomstate.texture_bloom)
        {
@@ -4250,14 +4236,14 @@ static void R_BlendView(void)
                {
                        R_SetupGenericShader(true);
                        R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
-                       r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
+                       r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
                        // now blend on the bloom texture
                        GL_BlendFunc(GL_ONE, GL_ONE);
                        R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
                        R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
                }
                R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
-               r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
+               r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
        }
        if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
        {
@@ -4634,7 +4620,7 @@ void R_RenderScene(void)
        if (r_refdef.scene.extraupdate)
                S_ExtraUpdate ();
 
-       if (r_shadows.integer > 0 && !r_shadows_drawafterrtlightning.integer && r_refdef.lightmapintensity > 0)
+       if (r_shadows.integer > 0 && !r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
        {
                R_DrawModelShadows();
                R_ResetViewRendering3D();
@@ -4651,7 +4637,7 @@ void R_RenderScene(void)
        if (r_refdef.scene.extraupdate)
                S_ExtraUpdate ();
 
-       if (r_shadows.integer > 0 && r_shadows_drawafterrtlightning.integer && r_refdef.lightmapintensity > 0)
+       if (r_shadows.integer > 0 && r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
        {
                R_DrawModelShadows();
                R_ResetViewRendering3D();