]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
fix bug that prevented reflection cubemaps from working with Cg shaders
[xonotic/darkplaces.git] / gl_rmain.c
index a5f3513f3a671cf574328fa2fa14614ba79eb738..28fff13a6d25dd51392324cd40e59fc71f8638a6 100644 (file)
@@ -92,6 +92,7 @@ cvar_t r_shadows_throwdirection = {CVAR_SAVE, "r_shadows_throwdirection", "0 0 -
 cvar_t r_shadows_drawafterrtlighting = {CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
 cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
 cvar_t r_shadows_focus = {CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
+cvar_t r_shadows_shadowmapscale = {CVAR_SAVE, "r_shadows_shadowmapscale", "1", "increases shadowmap quality (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
 cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
 cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
 cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
@@ -1064,11 +1065,9 @@ static const char *builtinshaderstring =
 "vec3 GetShadowMapTC2D(vec3 dir)\n"
 "{\n"
 "      vec3 adir = abs(dir);\n"
-"      float ma = max(max(adir.x, adir.y), adir.z);\n"
+"      vec2 aparams = ShadowMap_Parameters.xy / max(max(adir.x, adir.y), adir.z);\n"
 "      vec4 proj = textureCube(Texture_CubeProjection, dir);\n"
-"      vec3 stc = vec3(mix(dir.xy, dir.zz, proj.xy) * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
-"      stc += vec3(proj.zw * ShadowMap_Parameters.y, ShadowMap_Parameters.z);\n"
-"      return stc;\n"
+"      return vec3(mix(dir.xy, dir.zz, proj.xy) * aparams.x + proj.zw * ShadowMap_Parameters.z, aparams.y + ShadowMap_Parameters.w);\n"
 "}\n"
 "#  else\n"
 "vec3 GetShadowMapTC2D(vec3 dir)\n"
@@ -1078,9 +1077,8 @@ static const char *builtinshaderstring =
 "      vec4 proj = vec4(dir, 2.5);\n"
 "      if (adir.x > ma) { ma = adir.x; proj = vec4(dir.zyx, 0.5); }\n"
 "      if (adir.y > ma) { ma = adir.y; proj = vec4(dir.xzy, 1.5); }\n"
-"      vec3 stc = vec3(proj.xy * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
-"      stc += vec3(vec2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.y, ShadowMap_Parameters.z);\n"
-"      return stc;\n"
+"      vec2 aparams = ShadowMap_Parameters.xy / ma;\n"
+"      return vec3(proj.xy * aparams.x + vec2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.z, aparams.y + ShadowMap_Parameters.w);\n"
 "}\n"
 "#  endif\n"
 "# endif\n"
@@ -1164,8 +1162,28 @@ static const char *builtinshaderstring =
 "#      else\n"
 "#        define texval(x, y) texture4(Texture_ShadowMap2D, center + vec2(x, y)*ShadowMap_TextureScale)\n"
 "#      endif\n"
-"      vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n"
-"      center *= ShadowMap_TextureScale;\n"
+"      vec2 offset = fract(shadowmaptc.xy - 0.5), center = (shadowmaptc.xy - offset)*ShadowMap_TextureScale;\n"
+"#      if USESHADOWMAPPCF > 1\n"
+"   vec4 group1 = step(shadowmaptc.z, texval(-2.0, -2.0));\n"
+"   vec4 group2 = step(shadowmaptc.z, texval( 0.0, -2.0));\n"
+"   vec4 group3 = step(shadowmaptc.z, texval( 2.0, -2.0));\n"
+"   vec4 group4 = step(shadowmaptc.z, texval(-2.0,  0.0));\n"
+"   vec4 group5 = step(shadowmaptc.z, texval( 0.0,  0.0));\n"
+"   vec4 group6 = step(shadowmaptc.z, texval( 2.0,  0.0));\n"
+"   vec4 group7 = step(shadowmaptc.z, texval(-2.0,  2.0));\n"
+"   vec4 group8 = step(shadowmaptc.z, texval( 0.0,  2.0));\n"
+"   vec4 group9 = step(shadowmaptc.z, texval( 2.0,  2.0));\n"
+"      vec4 locols = vec4(group1.ab, group3.ab);\n"
+"      vec4 hicols = vec4(group7.rg, group9.rg);\n"
+"      locols.yz += group2.ab;\n"
+"      hicols.yz += group8.rg;\n"
+"      vec4 midcols = vec4(group1.rg, group3.rg) + vec4(group7.ab, group9.ab) +\n"
+"                              vec4(group4.rg, group6.rg) + vec4(group4.ab, group6.ab) +\n"
+"                              mix(locols, hicols, offset.y);\n"
+"      vec4 cols = group5 + vec4(group2.rg, group8.ab);\n"
+"      cols.xyz += mix(midcols.xyz, midcols.yzw, offset.x);\n"
+"      f = dot(cols, vec4(1.0/25.0));\n"
+"#      else\n"
 "      vec4 group1 = step(shadowmaptc.z, texval(-1.0, -1.0));\n"
 "      vec4 group2 = step(shadowmaptc.z, texval( 1.0, -1.0));\n"
 "      vec4 group3 = step(shadowmaptc.z, texval(-1.0,  1.0));\n"
@@ -1173,6 +1191,7 @@ static const char *builtinshaderstring =
 "      vec4 cols = vec4(group1.rg, group2.rg) + vec4(group3.ab, group4.ab) +\n"
 "                              mix(vec4(group1.ab, group2.ab), vec4(group3.rg, group4.rg), offset.y);\n"
 "      f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
+"#      endif\n"
 "#     else\n"
 "#      ifdef GL_EXT_gpu_shader4\n"
 "#        define texval(x, y) texture2DOffset(Texture_ShadowMap2D, center, ivec2(x, y)).r\n"
@@ -2190,11 +2209,9 @@ const char *builtincgshaderstring =
 "float3 GetShadowMapTC2D(float3 dir, float4 ShadowMap_Parameters, samplerCUBE Texture_CubeProjection)\n"
 "{\n"
 "      float3 adir = abs(dir);\n"
-"      float ma = max(max(adir.x, adir.y), adir.z);\n"
+"      float2 aparams = ShadowMap_Parameters.xy / max(max(adir.x, adir.y), adir.z);\n"
 "      float4 proj = texCUBE(Texture_CubeProjection, dir);\n"
-"      float3 stc = float3(lerp(dir.xy, dir.zz, proj.xy) * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
-"      stc += float3(proj.zw * ShadowMap_Parameters.y, ShadowMap_Parameters.z);\n"
-"      return stc;\n"
+"      return float3(lerp(dir.xy, proj.xy, dir.zz) * aparams.x + proj.zw * ShadowMap_Parameters.z, aparams.y + ShadowMap_Parameters.w);\n"
 "}\n"
 "#  else\n"
 "float3 GetShadowMapTC2D(float3 dir, float4 ShadowMap_Parameters)\n"
@@ -2204,9 +2221,8 @@ const char *builtincgshaderstring =
 "      float4 proj = float4(dir, 2.5);\n"
 "      if (adir.x > ma) { ma = adir.x; proj = float4(dir.zyx, 0.5); }\n"
 "      if (adir.y > ma) { ma = adir.y; proj = float4(dir.xzy, 1.5); }\n"
-"      float3 stc = float3(proj.xy * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
-"      stc += float3(vec2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.y, ShadowMap_Parameters.z);\n"
-"      return stc;\n"
+"      float2 aparams = ShadowMap_Parameters.xy / ma;\n"
+"      return float3(proj.xy * aparams.x + float2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.z, aparams.y + ShadowMap_Parameters.w);\n"
 "}\n"
 "#  endif\n"
 "# endif\n"
@@ -2302,19 +2318,40 @@ const char *builtincgshaderstring =
 "#    ifdef USESHADOWMAPPCF\n"
 "#     if defined(GL_ARB_texture_gather) || defined(GL_AMD_texture_texture4)\n"
 "#      ifdef GL_ARB_texture_gather\n"
-"#        define texval(x, y) textureGatherOffset(Texture_ShadowMap2D, center, ivec(x, y))\n"
+"#        define texval(x, y) textureGatherOffset(Texture_ShadowMap2D, center, ivec2(x, y))\n"
 "#      else\n"
-"#        define texval(x, y) texture4(Texture_ShadowMap2D, center + float2(x,y)*ShadowMap_TextureScale)\n"
+"#        define texval(x, y) texture4(Texture_ShadowMap2D, center + float2(x, y)*ShadowMap_TextureScale)\n"
+"#      endif\n"
+"      float2 offset = frac(shadowmaptc.xy - 0.5), center = (shadowmaptc.xy - offset)*ShadowMap_TextureScale;\n"
+"#      if USESHADOWMAPPCF > 1\n"
+"      float4 group1 = step(shadowmaptc.z, texval(-2.0, -2.0));\n"
+"      float4 group2 = step(shadowmaptc.z, texval( 0.0, -2.0));\n"
+"      float4 group3 = step(shadowmaptc.z, texval( 2.0, -2.0));\n"
+"      float4 group4 = step(shadowmaptc.z, texval(-2.0,  0.0));\n"
+"      float4 group5 = step(shadowmaptc.z, texval( 0.0,  0.0));\n"
+"      float4 group6 = step(shadowmaptc.z, texval( 2.0,  0.0));\n"
+"      float4 group7 = step(shadowmaptc.z, texval(-2.0,  2.0));\n"
+"      float4 group8 = step(shadowmaptc.z, texval( 0.0,  2.0));\n"
+"      float4 group9 = step(shadowmaptc.z, texval( 2.0,  2.0));\n"
+"      float4 locols = float4(group1.ab, group3.ab);\n"
+"      float4 hicols = float4(group7.rg, group9.rg);\n"
+"      locols.yz += group2.ab;\n"
+"      hicols.yz += group8.rg;\n"
+"      float4 midcols = float4(group1.rg, group3.rg) + float4(group7.ab, group9.ab) +\n"
+"                  float4(group4.rg, group6.rg) + float4(group4.ab, group6.ab) +\n"
+"                  lerp(locols, hicols, offset.y);\n"
+"      float4 cols = group5 + float4(group2.rg, group8.ab);\n"
+"      cols.xyz += lerp(midcols.xyz, midcols.yzw, offset.x);\n"
+"      f = dot(cols, float4(1.0/25.0));\n"
+"#      else\n"
+"      float4 group1 = step(shadowmaptc.z, texval(-1.0, -1.0));\n"
+"      float4 group2 = step(shadowmaptc.z, texval( 1.0, -1.0));\n"
+"      float4 group3 = step(shadowmaptc.z, texval(-1.0,  1.0));\n"
+"      float4 group4 = step(shadowmaptc.z, texval( 1.0,  1.0));\n"
+"      float4 cols = float4(group1.rg, group2.rg) + float4(group3.ab, group4.ab) +\n"
+"                              lerp(float4(group1.ab, group2.ab), float4(group3.rg, group4.rg), offset.y);\n"
+"      f = dot(lerp(cols.xyz, cols.yzw, offset.x), float3(1.0/9.0));\n"
 "#      endif\n"
-"    float2 center = shadowmaptc.xy - 0.5, offset = frac(center);\n"
-"    center *= ShadowMap_TextureScale;\n"
-"    float4 group1 = step(shadowmaptc.z, texval(-1.0, -1.0));\n"
-"    float4 group2 = step(shadowmaptc.z, texval( 1.0, -1.0));\n"
-"    float4 group3 = step(shadowmaptc.z, texval(-1.0,  1.0));\n"
-"    float4 group4 = step(shadowmaptc.z, texval( 1.0,  1.0));\n"
-"    float4 cols = float4(group1.rg, group2.rg) + float4(group3.ab, group4.ab) +\n"
-"                lerp(float4(group1.ab, group2.ab), float4(group3.rg, group4.rg), offset.y);\n"
-"    f = dot(lerp(cols.xyz, cols.yzw, offset.x), float3(1.0/9.0));\n"
 "#     else\n"
 "#        define texval(x, y) texDepth2D(Texture_ShadowMap2D, center + float2(x, y)*ShadowMap_TextureScale)  \n"
 "#      if USESHADOWMAPPCF > 1\n"
@@ -2674,7 +2711,7 @@ const char *builtincgshaderstring =
 "out float4 EyeVectorModelSpaceFogPlaneVertexDist : TEXCOORD4,\n"
 "#endif\n"
 "#if defined(MODE_LIGHTSOURCE) || defined(MODE_LIGHTDIRECTION)\n"
-"out float3 LightVector : TEXCOORD5,\n"
+"out float3 LightVector : TEXCOORD1,\n"
 "#endif\n"
 "#ifdef MODE_LIGHTSOURCE\n"
 "out float3 CubeVector : TEXCOORD3,\n"
@@ -2737,7 +2774,7 @@ const char *builtincgshaderstring =
 "      EyeVectorModelSpaceFogPlaneVertexDist.w = dot(FogPlane, gl_Vertex);\n"
 "#endif\n"
 "\n"
-"#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
+"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(USEREFLECTCUBE)\n"
 "      VectorS = gl_MultiTexCoord1.xyz;\n"
 "      VectorT = gl_MultiTexCoord2.xyz;\n"
 "      VectorR = gl_MultiTexCoord3.xyz;\n"
@@ -2780,7 +2817,7 @@ const char *builtincgshaderstring =
 "float4 EyeVectorModelSpaceFogPlaneVertexDist : TEXCOORD4,\n"
 "#endif\n"
 "#if defined(MODE_LIGHTSOURCE) || defined(MODE_LIGHTDIRECTION)\n"
-"float3 LightVector : TEXCOORD5,\n"
+"float3 LightVector : TEXCOORD1,\n"
 "#endif\n"
 "#ifdef MODE_LIGHTSOURCE\n"
 "float3 CubeVector : TEXCOORD3,\n"
@@ -2794,7 +2831,7 @@ const char *builtincgshaderstring =
 "float3 VectorR : TEXCOORD7, // direction of R texcoord (surface normal)\n"
 "#endif\n"
 "#ifdef USESHADOWMAPORTHO\n"
-"float3 ShadowMapTC : TEXCOORD8\n"
+"float3 ShadowMapTC : TEXCOORD8,\n"
 "#endif\n"
 "\n"
 "uniform sampler2D Texture_Normal,\n"
@@ -2978,9 +3015,9 @@ const char *builtincgshaderstring =
 "#endif\n"
 "\n"
 "#ifdef USEREFLECTCUBE\n"
-"      vec3 TangentReflectVector = reflect(-EyeVector, surfacenormal);\n"
-"      vec3 ModelReflectVector = TangentReflectVector.x * VectorS + TangentReflectVector.y * VectorT + TangentReflectVector.z * VectorR;\n"
-"      vec3 ReflectCubeTexCoord = float3(mul(ModelToReflectCube, float4(ModelReflectVector, 0)));\n"
+"      float3 TangentReflectVector = reflect(-EyeVector, surfacenormal);\n"
+"      float3 ModelReflectVector = TangentReflectVector.x * VectorS + TangentReflectVector.y * VectorT + TangentReflectVector.z * VectorR;\n"
+"      float3 ReflectCubeTexCoord = float3(mul(ModelToReflectCube, float4(ModelReflectVector, 0)));\n"
 "      diffusetex += half3(tex2D(Texture_ReflectMask, TexCoord)) * half3(texCUBE(Texture_ReflectCube, ReflectCubeTexCoord));\n"
 "#endif\n"
 "\n"
@@ -4459,9 +4496,16 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        {
                if (r_glsl_offsetmapping.integer)
                {
-                       permutation |= SHADERPERMUTATION_OFFSETMAPPING;
-                       if (r_glsl_offsetmapping_reliefmapping.integer)
-                               permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       if (rsurface.texture->offsetmapping == OFFSETMAPPING_LINEAR)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                       else if (rsurface.texture->offsetmapping == OFFSETMAPPING_RELIEF)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       else if (rsurface.texture->offsetmapping != OFFSETMAPPING_OFF)
+                       {
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                               if (r_glsl_offsetmapping_reliefmapping.integer)
+                                       permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       }
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
@@ -4487,9 +4531,16 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        {
                if (r_glsl_offsetmapping.integer)
                {
-                       permutation |= SHADERPERMUTATION_OFFSETMAPPING;
-                       if (r_glsl_offsetmapping_reliefmapping.integer)
-                               permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       if (rsurface.texture->offsetmapping == OFFSETMAPPING_LINEAR)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                       else if (rsurface.texture->offsetmapping == OFFSETMAPPING_RELIEF)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       else if (rsurface.texture->offsetmapping != OFFSETMAPPING_OFF)
+                       {
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                               if (r_glsl_offsetmapping_reliefmapping.integer)
+                                       permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       }
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
@@ -4556,9 +4607,16 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        {
                if (r_glsl_offsetmapping.integer)
                {
-                       permutation |= SHADERPERMUTATION_OFFSETMAPPING;
-                       if (r_glsl_offsetmapping_reliefmapping.integer)
-                               permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       if (rsurface.texture->offsetmapping == OFFSETMAPPING_LINEAR)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                       else if (rsurface.texture->offsetmapping == OFFSETMAPPING_RELIEF)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       else if (rsurface.texture->offsetmapping != OFFSETMAPPING_OFF)
+                       {
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                               if (r_glsl_offsetmapping_reliefmapping.integer)
+                                       permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       }
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
@@ -4615,9 +4673,16 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        {
                if (r_glsl_offsetmapping.integer)
                {
-                       permutation |= SHADERPERMUTATION_OFFSETMAPPING;
-                       if (r_glsl_offsetmapping_reliefmapping.integer)
-                               permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       if (rsurface.texture->offsetmapping == OFFSETMAPPING_LINEAR)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                       else if (rsurface.texture->offsetmapping == OFFSETMAPPING_RELIEF)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       else if (rsurface.texture->offsetmapping != OFFSETMAPPING_OFF)
+                       {
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                               if (r_glsl_offsetmapping_reliefmapping.integer)
+                                       permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       }
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
@@ -4679,9 +4744,16 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        {
                if (r_glsl_offsetmapping.integer)
                {
-                       permutation |= SHADERPERMUTATION_OFFSETMAPPING;
-                       if (r_glsl_offsetmapping_reliefmapping.integer)
-                               permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       if (rsurface.texture->offsetmapping == OFFSETMAPPING_LINEAR)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                       else if (rsurface.texture->offsetmapping == OFFSETMAPPING_RELIEF)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       else if (rsurface.texture->offsetmapping != OFFSETMAPPING_OFF)
+                       {
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                               if (r_glsl_offsetmapping_reliefmapping.integer)
+                                       permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       }
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
@@ -4736,9 +4808,16 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        {
                if (r_glsl_offsetmapping.integer)
                {
-                       permutation |= SHADERPERMUTATION_OFFSETMAPPING;
-                       if (r_glsl_offsetmapping_reliefmapping.integer)
-                               permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       if (rsurface.texture->offsetmapping == OFFSETMAPPING_LINEAR)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                       else if (rsurface.texture->offsetmapping == OFFSETMAPPING_RELIEF)
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       else if (rsurface.texture->offsetmapping != OFFSETMAPPING_OFF)
+                       {
+                               permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+                               if (r_glsl_offsetmapping_reliefmapping.integer)
+                                       permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+                       }
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
@@ -4927,7 +5006,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
                if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
                if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
-               if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
+               if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value*rsurface.texture->offsetscale);
                if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2fARB(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
                if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2fARB(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
 
@@ -6108,10 +6187,12 @@ void gl_main_start(void)
        //r_texture_fogintensity = NULL;
        memset(&r_bloomstate, 0, sizeof(r_bloomstate));
        memset(&r_waterstate, 0, sizeof(r_waterstate));
+       r_glsl_permutation = NULL;
        memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
        Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
        glslshaderstring = NULL;
 #ifdef SUPPORTCG
+       r_cg_permutation = NULL;
        memset(r_cg_permutationhash, 0, sizeof(r_cg_permutationhash));
        Mem_ExpandableArray_NewArray(&r_cg_permutationarray, r_main_mempool, sizeof(r_cg_permutation_t), 256);
        cgshaderstring = NULL;
@@ -6159,6 +6240,14 @@ void gl_main_shutdown(void)
        //r_texture_fogintensity = NULL;
        memset(&r_bloomstate, 0, sizeof(r_bloomstate));
        memset(&r_waterstate, 0, sizeof(r_waterstate));
+       r_glsl_permutation = NULL;
+       memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
+       glslshaderstring = NULL;
+#ifdef SUPPORTCG
+       r_cg_permutation = NULL;
+       memset(r_cg_permutationhash, 0, sizeof(r_cg_permutationhash));
+       cgshaderstring = NULL;
+#endif
        R_GLSL_Restart_f();
 }
 
@@ -6259,6 +6348,7 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_shadows_throwdistance);
        Cvar_RegisterVariable(&r_shadows_throwdirection);
        Cvar_RegisterVariable(&r_shadows_focus);
+       Cvar_RegisterVariable(&r_shadows_shadowmapscale);
        Cvar_RegisterVariable(&r_q1bsp_skymasking);
        Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
        Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
@@ -6796,7 +6886,10 @@ static void R_View_UpdateEntityVisible (void)
        int samples;
        entity_render_t *ent;
 
-       renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : ((chase_active.integer || r_waterstate.renderingscene) ? RENDER_VIEWMODEL : RENDER_EXTERIORMODEL);
+       renderimask = r_refdef.envmap                                    ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL)
+               : r_waterstate.renderingrefraction                       ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL)
+               : (chase_active.integer || r_waterstate.renderingscene)  ? RENDER_VIEWMODEL
+               :                                                          RENDER_EXTERIORMODEL;
        if (!r_drawviewmodel.integer)
                renderimask |= RENDER_VIEWMODEL;
        if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
@@ -7420,6 +7513,7 @@ static void R_Water_ProcessPlanes(void)
                // (except that a clipping plane should be used to hide everything on one side of the water, and the viewer's weapon model should be omitted)
                if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
                {
+                       r_waterstate.renderingrefraction = true;
                        r_refdef.view = myview;
                        r_refdef.view.clipplane = p->plane;
                        VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
@@ -7432,6 +7526,7 @@ static void R_Water_ProcessPlanes(void)
                        R_RenderScene();
 
                        R_Mesh_CopyToTexture(p->texture_refraction, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
+                       r_waterstate.renderingrefraction = false;
                }
 
        }
@@ -7802,7 +7897,7 @@ static void R_BlendView(void)
                                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 (cl.motionbluralpha > 0)
+                               if (cl.motionbluralpha > 0 && !r_refdef.envmap)
                                {
                                        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                                        GL_Color(1, 1, 1, cl.motionbluralpha);
@@ -8245,6 +8340,9 @@ void R_RenderScene(void)
 {
        qboolean shadowmapping = false;
 
+       if (r_timereport_active)
+               R_TimeReport("beginscene");
+
        r_refdef.stats.renders++;
 
        R_UpdateFogColor();
@@ -8259,6 +8357,9 @@ void R_RenderScene(void)
 
        Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.scene.time) * 0.025 * r_waterscroll.value, sin(r_refdef.scene.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
 
+       if (r_timereport_active)
+               R_TimeReport("skystartframe");
+
        if (cl.csqc_vidvars.drawworld)
        {
                // don't let sound skip if going slow
@@ -10070,7 +10171,7 @@ void RSurf_DrawBatch_Simple(int texturenumsurfaces, const msurface_t **texturesu
                R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
        else if (r_batchmode.integer == 2)
        {
-               #define MAXBATCHTRIANGLES 4096
+               #define MAXBATCHTRIANGLES 65536
                int batchtriangles = 0;
                static int batchelements[MAXBATCHTRIANGLES*3];
                for (i = 0;i < texturenumsurfaces;i = j)
@@ -10220,7 +10321,6 @@ static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, const
        }
        else if (r_batchmode.integer == 2)
        {
-#define MAXBATCHTRIANGLES 4096
                int batchtriangles = 0;
                static int batchelements[MAXBATCHTRIANGLES*3];
                for (i = 0;i < texturenumsurfaces;i = j)
@@ -11125,7 +11225,8 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
        int texturenumsurfaces, endsurface;
        texture_t *texture;
        const msurface_t *surface;
-       const msurface_t *texturesurfacelist[256];
+#define MAXBATCH_TRANSPARENTSURFACES 256
+       const msurface_t *texturesurfacelist[MAXBATCH_TRANSPARENTSURFACES];
 
        // if the model is static it doesn't matter what value we give for
        // wantnormals and wanttangents, so this logic uses only rules applicable
@@ -11202,7 +11303,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
                rsurface.texture = R_GetCurrentTexture(texture);
                rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
                // scan ahead until we find a different texture
-               endsurface = min(i + 1024, numsurfaces);
+               endsurface = min(i + MAXBATCH_TRANSPARENTSURFACES, numsurfaces);
                texturenumsurfaces = 0;
                texturesurfacelist[texturenumsurfaces++] = surface;
                for (;j < endsurface;j++)
@@ -12034,6 +12135,16 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
                        VectorCopy(decal->vertex3f[2], v3f + 6);
                }
 
+               if (r_refdef.fogenabled)
+               {
+                       alpha = RSurf_FogVertex(v3f);
+                       VectorScale(c4f, alpha, c4f);
+                       alpha = RSurf_FogVertex(v3f + 3);
+                       VectorScale(c4f + 4, alpha, c4f + 4);
+                       alpha = RSurf_FogVertex(v3f + 6);
+                       VectorScale(c4f + 8, alpha, c4f + 8);
+               }
+
                v3f += 9;
                c4f += 12;
                t2f += 6;
@@ -12044,25 +12155,6 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
        {
                r_refdef.stats.drawndecals += numtris;
 
-               if (r_refdef.fogenabled)
-               {
-                       switch(vid.renderpath)
-                       {
-                       case RENDERPATH_GL20:
-                       case RENDERPATH_CGGL:
-                       case RENDERPATH_GL13:
-                       case RENDERPATH_GL11:
-                               for (i = 0, v3f = decalsystem->vertex3f, c4f = decalsystem->color4f;i < numtris*3;i++, v3f += 3, c4f += 4)
-                               {
-                                       alpha = RSurf_FogVertex(v3f);
-                                       c4f[0] *= alpha;
-                                       c4f[1] *= alpha;
-                                       c4f[2] *= alpha;
-                               }
-                               break;
-                       }
-               }
-
                // now render the decals all at once
                // (this assumes they all use one particle font texture!)
                RSurf_ActiveCustomEntity(&rsurface.matrix, &rsurface.inversematrix, rsurface.ent_flags, rsurface.ent_shadertime, 1, 1, 1, 1, numdecals*3, decalsystem->vertex3f, decalsystem->texcoord2f, NULL, NULL, NULL, decalsystem->color4f, numtris, decalsystem->element3i, decalsystem->element3s, false, false);
@@ -12117,11 +12209,11 @@ static void R_DrawModelDecals(void)
        }
 }
 
+extern cvar_t mod_collision_bih;
 void R_DrawDebugModel(void)
 {
        entity_render_t *ent = rsurface.entity;
        int i, j, k, l, flagsmask;
-       q3mbrush_t *brush;
        const msurface_t *surface;
        dp_model_t *model = ent->model;
        vec3_t v;
@@ -12136,25 +12228,50 @@ void R_DrawDebugModel(void)
        GL_DepthMask(false);
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
-       if (r_showcollisionbrushes.value > 0 && model->brush.num_brushes)
+       if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
        {
+               int triangleindex;
+               int bihleafindex;
+               qboolean cullbox = ent == r_refdef.scene.worldentity;
+               const q3mbrush_t *brush;
+               const bih_t *bih = &model->collision_bih;
+               const bih_leaf_t *bihleaf;
+               float vertex3f[3][3];
                GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
-               for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
+               cullbox = false;
+               for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
                {
-                       if (brush->colbrushf && brush->colbrushf->numtriangles)
-                       {
-                               R_Mesh_VertexPointer(brush->colbrushf->points->v, 0, 0);
-                               GL_Color((i & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((i >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((i >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
-                               R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, 0);
-                       }
-               }
-               for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
-               {
-                       if (surface->num_collisiontriangles)
+                       if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
+                               continue;
+                       switch (bihleaf->type)
                        {
-                               R_Mesh_VertexPointer(surface->data_collisionvertex3f, 0, 0);
-                               GL_Color((i & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((i >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((i >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
-                               R_Mesh_Draw(0, surface->num_collisionvertices, 0, surface->num_collisiontriangles, surface->data_collisionelement3i, NULL, 0, 0);
+                       case BIH_BRUSH:
+                               brush = model->brush.data_brushes + bihleaf->itemindex;
+                               if (brush->colbrushf && brush->colbrushf->numtriangles)
+                               {
+                                       R_Mesh_VertexPointer(brush->colbrushf->points->v, 0, 0);
+                                       GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
+                                       R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, 0);
+                               }
+                               break;
+                       case BIH_COLLISIONTRIANGLE:
+                               triangleindex = bihleaf->itemindex;
+                               VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
+                               VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
+                               VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
+                               R_Mesh_VertexPointer(vertex3f[0], 0, 0);
+                               GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
+                               R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);
+                               break;
+                       case BIH_RENDERTRIANGLE:
+                               triangleindex = bihleaf->itemindex;
+                               VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
+                               VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
+                               VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
+                               R_Mesh_VertexPointer(vertex3f[0], 0, 0);
+                               GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
+                               R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);
+                               break;
                        }
                }
        }
@@ -12495,6 +12612,8 @@ void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, i
        texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
        texture.currentskinframe = skinframe;
        texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
+       texture.offsetmapping = OFFSETMAPPING_OFF;
+       texture.offsetscale = 1;
        texture.specularscalemod = 1;
        texture.specularpowermod = 1;