"#ifdef FRAGMENT_SHADER\n"
"\n"
"#ifdef USEFOG\n"
-"float3 FogVertex(float3 surfacecolor, float3 FogColor, float3 EyeVectorModelSpace, float FogPlaneVertexDist, float FogRangeRecip, float FogPlaneViewDist, float FogHeightFade, sampler Texture_FogMask, sampler Texture_FogHeightTexture)\n"
+"float3 FogVertex(float4 surfacecolor, float3 FogColor, float3 EyeVectorModelSpace, float FogPlaneVertexDist, float FogRangeRecip, float FogPlaneViewDist, float FogHeightFade, sampler Texture_FogMask, sampler Texture_FogHeightTexture)\n"
"{\n"
" float fogfrac;\n"
+" float3 fc = FogColor;\n"
+"#ifdef USEFOGALPHAHACK\n"
+" fc *= surfacecolor.a;\n"
+"#endif\n"
"#ifdef USEFOGHEIGHTTEXTURE\n"
" float4 fogheightpixel = tex2D(Texture_FogHeightTexture, float2(1,1) + float2(FogPlaneVertexDist, FogPlaneViewDist) * (-2.0 * FogHeightFade));\n"
" fogfrac = fogheightpixel.a;\n"
-" return lerp(fogheightpixel.rgb * FogColor, surfacecolor, tex2D(Texture_FogMask, float2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)).r);\n"
+" return lerp(fogheightpixel.rgb * fc, surfacecolor.rgb, tex2D(Texture_FogMask, float2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)).r);\n"
"#else\n"
"# ifdef USEFOGOUTSIDE\n"
" fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0, min(0.0, FogPlaneVertexDist) * FogHeightFade);\n"
"# else\n"
" fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist)) * min(1.0, (min(0.0, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);\n"
"# endif\n"
-" return lerp(FogColor, surfacecolor, tex2D(Texture_FogMask, float2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)).r);\n"
+" return lerp(fc, surfacecolor.rgb, tex2D(Texture_FogMask, float2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)).r);\n"
"#endif\n"
"}\n"
"#endif\n"
"\n"
"#ifdef USEOFFSETMAPPING\n"
-"float2 OffsetMapping(float2 TexCoord, float OffsetMapping_Scale, float3 EyeVector, sampler Texture_Normal)\n"
+"float2 OffsetMapping(float2 TexCoord, float4 OffsetMapping_ScaleSteps, float3 EyeVector, sampler Texture_Normal, float2 dPdx, float2 dPdy)\n"
"{\n"
+" float i;\n"
"#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n"
" // 14 sample relief mapping: linear search and then binary search\n"
" // this basically steps forward a small amount repeatedly until it finds\n"
" // itself inside solid, then jitters forward and back using decreasing\n"
" // amounts to find the impact\n"
-" //float3 OffsetVector = float3(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * float2(-1, 1), -1);\n"
-" //float3 OffsetVector = float3(normalize(EyeVector.xy) * OffsetMapping_Scale * float2(-1, 1), -1);\n"
-" float3 OffsetVector = float3(normalize(EyeVector).xy * OffsetMapping_Scale * float2(-1, 1), -1);\n"
+" //float3 OffsetVector = float3(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_ScaleSteps.x) * float2(-1, 1), -1);\n"
+" //float3 OffsetVector = float3(normalize(EyeVector.xy) * OffsetMapping_ScaleSteps.x * float2(-1, 1), -1);\n"
+" float3 OffsetVector = float3(normalize(EyeVector).xy * OffsetMapping_ScaleSteps.x * float2(-1, 1), -1);\n"
" float3 RT = float3(TexCoord, 1);\n"
-" OffsetVector *= 0.1;\n"
-" RT += OffsetVector * step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2D(Texture_Normal, RT.xy).a, RT.z);\n"
-" RT += OffsetVector * (step(tex2D(Texture_Normal, RT.xy).a, RT.z) - 0.5);\n"
-" RT += OffsetVector * (step(tex2D(Texture_Normal, RT.xy).a, RT.z) * 0.5 - 0.25);\n"
-" RT += OffsetVector * (step(tex2D(Texture_Normal, RT.xy).a, RT.z) * 0.25 - 0.125);\n"
-" RT += OffsetVector * (step(tex2D(Texture_Normal, RT.xy).a, RT.z) * 0.125 - 0.0625);\n"
-" RT += OffsetVector * (step(tex2D(Texture_Normal, RT.xy).a, RT.z) * 0.0625 - 0.03125);\n"
+" OffsetVector *= OffsetMapping_ScaleSteps.z;\n"
+" for(i = 1.0; i < OffsetMapping_ScaleSteps.y; ++i)\n"
+" RT += OffsetVector * step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
+" for(i = 0.0, f = 1.0; i < OffsetMapping_ScaleSteps.w; ++i, f *= 0.5)\n"
+" RT += OffsetVector * (step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z) * f - 0.5 * f);\n"
" return RT.xy;\n"
"#else\n"
" // 2 sample offset mapping (only 2 samples because of ATI Radeon 9500-9800/X300 limits)\n"
-" //float2 OffsetVector = float2(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * float2(-1, 1));\n"
-" //float2 OffsetVector = float2(normalize(EyeVector.xy) * OffsetMapping_Scale * float2(-1, 1));\n"
-" float2 OffsetVector = float2(normalize(EyeVector).xy * OffsetMapping_Scale * float2(-1, 1));\n"
-" OffsetVector *= 0.5;\n"
-" TexCoord += OffsetVector * (1.0 - tex2D(Texture_Normal, TexCoord).a);\n"
-" TexCoord += OffsetVector * (1.0 - tex2D(Texture_Normal, TexCoord).a);\n"
+" //float2 OffsetVector = float2(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_ScaleSteps.x) * float2(-1, 1));\n"
+" //float2 OffsetVector = float2(normalize(EyeVector.xy) * OffsetMapping_ScaleSteps.x * float2(-1, 1));\n"
+" float2 OffsetVector = float2(normalize(EyeVector).xy * OffsetMapping_ScaleSteps.x * float2(-1, 1));\n"
+" OffsetVector *= OffsetMapping_ScaleSteps.z;\n"
+" for(i = 0.0; i < OffsetMapping_ScaleSteps.y; ++i)\n"
+" TexCoord += OffsetVector * (1.0 - tex2Dgrad(Texture_Normal, TexCoord, dPdx, dPdy).a);\n"
" return TexCoord;\n"
"#endif\n"
"}\n"
"uniform sampler Texture_SecondaryGloss : register(s6),\n"
"#endif\n"
"#ifdef USEOFFSETMAPPING\n"
-"uniform float OffsetMapping_Scale : register(c24),\n"
+"uniform float4 OffsetMapping_ScaleSteps : register(c24),\n"
"#endif\n"
"uniform half SpecularPower : register(c36),\n"
"#ifdef HLSL\n"
" float2 TexCoord = TexCoordBoth.xy;\n"
"#ifdef USEOFFSETMAPPING\n"
" // apply offsetmapping\n"
-" float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_Scale, EyeVector, Texture_Normal);\n"
-"#define TexCoord TexCoordOffset\n"
+" float2 dPdx = ddx(TexCoord);\n"
+" float2 dPdy = ddy(TexCoord);\n"
+" float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_ScaleSteps, EyeVector, Texture_Normal, dPdx, dPdy);\n"
+"# define offsetMappedTexture2D(t) tex2Dgrad(t, TexCoordOffset, dPdx, dPdy)\n"
+"#else\n"
+"# define offsetMappedTexture2D(t) tex2D(t, TexCoord)\n"
"#endif\n"
"\n"
"#ifdef USEALPHAKILL\n"
-" if (tex2D(Texture_Color, TexCoord).a < 0.5)\n"
+" if (offsetMappedTexture2D(Texture_Color).a < 0.5)\n"
" discard;\n"
"#endif\n"
"\n"
"#ifdef USEVERTEXTEXTUREBLEND\n"
-" float alpha = tex2D(Texture_Color, TexCoord).a;\n"
+" float alpha = offsetMappedTexture2D(Texture_Color).a;\n"
" float terrainblend = clamp(float(gl_FrontColor.a) * alpha * 2.0 - 0.5, float(0.0), float(1.0));\n"
" //float terrainblend = min(float(gl_FrontColor.a) * alpha * 2.0, float(1.0));\n"
" //float terrainblend = float(gl_FrontColor.a) * alpha > 0.5;\n"
"#endif\n"
"\n"
"#ifdef USEVERTEXTEXTUREBLEND\n"
-" float3 surfacenormal = lerp(tex2D(Texture_SecondaryNormal, TexCoord2).rgb, tex2D(Texture_Normal, TexCoord).rgb, terrainblend) - float3(0.5, 0.5, 0.5);\n"
-" float a = lerp(tex2D(Texture_SecondaryGloss, TexCoord2).a, tex2D(Texture_Gloss, TexCoord).a, terrainblend);\n"
+" float3 surfacenormal = lerp(tex2D(Texture_SecondaryNormal, TexCoord2).rgb, offsetMappedTexture2D(Texture_Normal).rgb, terrainblend) - float3(0.5, 0.5, 0.5);\n"
+" float a = lerp(tex2D(Texture_SecondaryGloss, TexCoord2).a, offsetMappedTexture2D(Texture_Gloss).a, terrainblend);\n"
"#else\n"
-" float3 surfacenormal = tex2D(Texture_Normal, TexCoord).rgb - float3(0.5, 0.5, 0.5);\n"
-" float a = tex2D(Texture_Gloss, TexCoord).a;\n"
+" float3 surfacenormal = offsetMappedTexture2D(Texture_Normal).rgb - float3(0.5, 0.5, 0.5);\n"
+" float a = offsetMappedTexture2D(Texture_Gloss).a;\n"
"#endif\n"
"\n"
"#ifdef HLSL\n"
"#endif\n"
"\n"
"#ifdef USEOFFSETMAPPING\n"
-"uniform float OffsetMapping_Scale : register(c24),\n"
+"uniform float4 OffsetMapping_ScaleSteps : register(c24),\n"
"#endif\n"
"\n"
"#ifdef USEDEFERREDLIGHTMAP\n"
"#endif\n"
"#ifdef USEOFFSETMAPPING\n"
" // apply offsetmapping\n"
-" float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_Scale, EyeVector, Texture_Normal);\n"
-"#define TexCoord TexCoordOffset\n"
+" float2 dPdx = ddx(TexCoord);\n"
+" float2 dPdy = ddy(TexCoord);\n"
+" float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_ScaleSteps, EyeVector, Texture_Normal, dPdx, dPdy);\n"
+"# define offsetMappedTexture2D(t) tex2Dgrad(t, TexCoordOffset, dPdx, dPdy)\n"
+"#else\n"
+"# define offsetMappedTexture2D(t) tex2D(t, TexCoord)\n"
"#endif\n"
"\n"
" // combine the diffuse textures (base, pants, shirt)\n"
-" half4 color = half4(tex2D(Texture_Color, TexCoord));\n"
+" half4 color = half4(offsetMappedTexture2D(Texture_Color));\n"
"#ifdef USEALPHAKILL\n"
" if (color.a < 0.5)\n"
" discard;\n"
"#endif\n"
" color.a *= Alpha;\n"
"#ifdef USECOLORMAPPING\n"
-" color.rgb += half3(tex2D(Texture_Pants, TexCoord).rgb) * Color_Pants + half3(tex2D(Texture_Shirt, TexCoord).rgb) * Color_Shirt;\n"
+" color.rgb += half3(offsetMappedTexture2D(Texture_Pants).rgb) * Color_Pants + half3(offsetMappedTexture2D(Texture_Shirt).rgb) * Color_Shirt;\n"
"#endif\n"
"#ifdef USEVERTEXTEXTUREBLEND\n"
+"#ifdef USEBOTHALPHAS\n"
+" half4 color2 = half4(tex2D(Texture_SecondaryColor, TexCoord2));\n"
+" half terrainblend = clamp(half(gl_FrontColor.a) * color.a, half(1.0 - color2.a), half(1.0));\n"
+" color.rgb = lerp(color2.rgb, color.rgb, terrainblend);\n"
+"#else\n"
" half terrainblend = clamp(half(gl_FrontColor.a) * color.a * 2.0 - 0.5, half(0.0), half(1.0));\n"
" //half terrainblend = min(half(gl_FrontColor.a) * color.a * 2.0, half(1.0));\n"
" //half terrainblend = half(gl_FrontColor.a) * color.a > 0.5;\n"
" color.a = 1.0;\n"
" //color = half4(lerp(float4(1, 0, 0, 1), color, terrainblend));\n"
"#endif\n"
+"#endif\n"
"\n"
" // get the surface normal\n"
"#ifdef USEVERTEXTEXTUREBLEND\n"
-" half3 surfacenormal = normalize(half3(lerp(tex2D(Texture_SecondaryNormal, TexCoord2).rgb, tex2D(Texture_Normal, TexCoord).rgb, terrainblend)) - half3(0.5, 0.5, 0.5));\n"
+" half3 surfacenormal = normalize(half3(lerp(tex2D(Texture_SecondaryNormal, TexCoord2).rgb, offsetMappedTexture2D(Texture_Normal).rgb, terrainblend)) - half3(0.5, 0.5, 0.5));\n"
"#else\n"
-" half3 surfacenormal = half3(normalize(half3(tex2D(Texture_Normal, TexCoord).rgb) - half3(0.5, 0.5, 0.5)));\n"
+" half3 surfacenormal = half3(normalize(half3(offsetMappedTexture2D(Texture_Normal).rgb) - half3(0.5, 0.5, 0.5)));\n"
"#endif\n"
"\n"
" // get the material colors\n"
" half3 diffusetex = color.rgb;\n"
"#if defined(USESPECULAR) || defined(USEDEFERREDLIGHTMAP)\n"
"# ifdef USEVERTEXTEXTUREBLEND\n"
-" half4 glosstex = half4(lerp(tex2D(Texture_SecondaryGloss, TexCoord2), tex2D(Texture_Gloss, TexCoord), terrainblend));\n"
+" half4 glosstex = half4(lerp(tex2D(Texture_SecondaryGloss, TexCoord2), offsetMappedTexture2D(Texture_Gloss), terrainblend));\n"
"# else\n"
-" half4 glosstex = half4(tex2D(Texture_Gloss, TexCoord));\n"
+" half4 glosstex = half4(offsetMappedTexture2D(Texture_Gloss));\n"
"# endif\n"
"#endif\n"
"\n"
" float3 TangentReflectVector = reflect(-EyeVector, surfacenormal);\n"
" float3 ModelReflectVector = TangentReflectVector.x * VectorS + TangentReflectVector.y * VectorT + TangentReflectVector.z * VectorR;\n"
" float3 ReflectCubeTexCoord = mul(ModelToReflectCube, float4(ModelReflectVector, 0)).xyz;\n"
-" diffusetex += half3(tex2D(Texture_ReflectMask, TexCoord).rgb) * half3(texCUBE(Texture_ReflectCube, ReflectCubeTexCoord).rgb);\n"
+" diffusetex += half3(offsetMappedTexture2D(Texture_ReflectMask).rgb) * half3(texCUBE(Texture_ReflectCube, ReflectCubeTexCoord).rgb);\n"
"#endif\n"
"\n"
"\n"
"\n"
"#ifdef USEGLOW\n"
"#ifdef USEVERTEXTEXTUREBLEND\n"
-" color.rgb += half3(lerp(tex2D(Texture_SecondaryGlow, TexCoord2).rgb, tex2D(Texture_Glow, TexCoord).rgb, terrainblend)) * Color_Glow;\n"
+" color.rgb += half3(lerp(tex2D(Texture_SecondaryGlow, TexCoord2).rgb, offsetMappedTexture2D(Texture_Glow).rgb, terrainblend)) * Color_Glow;\n"
"#else\n"
-" color.rgb += half3(tex2D(Texture_Glow, TexCoord).rgb) * Color_Glow;\n"
+" color.rgb += half3(offsetMappedTexture2D(Texture_Glow).rgb) * Color_Glow;\n"
"#endif\n"
"#endif\n"
"\n"
"#ifdef USEFOG\n"
-" color.rgb = FogVertex(color.rgb, FogColor, EyeVectorModelSpaceFogPlaneVertexDist.xyz, EyeVectorModelSpaceFogPlaneVertexDist.w, FogRangeRecip, FogPlaneViewDist, FogHeightFade, Texture_FogMask, Texture_FogHeightTexture);\n"
+" color.rgb = half3(FogVertex(color, FogColor, EyeVectorModelSpaceFogPlaneVertexDist.xyz, EyeVectorModelSpaceFogPlaneVertexDist.w, FogRangeRecip, FogPlaneViewDist, FogHeightFade, Texture_FogMask, Texture_FogHeightTexture));\n"
"#endif\n"
"\n"
" // reflection must come last because it already contains exactly the correct fog (the reflection render preserves camera distance from the plane, it only flips the side) and ContrastBoost/SceneBrightness\n"
"#ifdef USEREFLECTION\n"
" float4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
-" //float4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(half3(tex2D(Texture_Normal, TexCoord).rgb) - half3(0.5,0.5,0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
+" //float4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(half3(offsetMappedTexture2D(Texture_Normal).rgb) - half3(0.5,0.5,0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
" float2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW.zw + ScreenCenterRefractReflect.zw;\n"
-" float2 ScreenTexCoord = SafeScreenTexCoord + float3(normalize(half3(tex2D(Texture_Normal, TexCoord).rgb) - half3(0.5,0.5,0.5))).xy * DistortScaleRefractReflect.zw;\n"
+" float2 ScreenTexCoord = SafeScreenTexCoord + float3(normalize(half3(offsetMappedTexture2D(Texture_Normal).rgb) - half3(0.5,0.5,0.5))).xy * DistortScaleRefractReflect.zw;\n"
" // FIXME temporary hack to detect the case that the reflection\n"
" // gets blackened at edges due to leaving the area that contains actual\n"
" // content.\n"