DPSOFTRAST_UNIFORM_LightColor,
DPSOFTRAST_UNIFORM_LightDir,
DPSOFTRAST_UNIFORM_LightPosition,
- DPSOFTRAST_UNIFORM_OffsetMapping_Scale,
+ DPSOFTRAST_UNIFORM_OffsetMapping_ScaleSteps,
DPSOFTRAST_UNIFORM_PixelSize,
DPSOFTRAST_UNIFORM_ReflectColor,
DPSOFTRAST_UNIFORM_ReflectFactor,
cvar_t r_glsl_deluxemapping = {CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
+cvar_t r_glsl_offsetmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
+cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
cvar_t r_glsl_offsetmapping_scale = {CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
cvar_t r_glsl_postprocess = {CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
cvar_t r_glsl_postprocess_uservec1 = {CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
int loc_LightColor;
int loc_LightDir;
int loc_LightPosition;
- int loc_OffsetMapping_Scale;
+ int loc_OffsetMapping_ScaleSteps;
int loc_PixelSize;
int loc_ReflectColor;
int loc_ReflectFactor;
p->loc_LightColor = qglGetUniformLocation(p->program, "LightColor");
p->loc_LightDir = qglGetUniformLocation(p->program, "LightDir");
p->loc_LightPosition = qglGetUniformLocation(p->program, "LightPosition");
- p->loc_OffsetMapping_Scale = qglGetUniformLocation(p->program, "OffsetMapping_Scale");
+ p->loc_OffsetMapping_ScaleSteps = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
p->loc_PixelSize = qglGetUniformLocation(p->program, "PixelSize");
p->loc_ReflectColor = qglGetUniformLocation(p->program, "ReflectColor");
p->loc_ReflectFactor = qglGetUniformLocation(p->program, "ReflectFactor");
D3DPSREGISTER_LightColor = 21,
D3DPSREGISTER_LightDir = 22, // unused
D3DPSREGISTER_LightPosition = 23,
- D3DPSREGISTER_OffsetMapping_Scale = 24,
+ D3DPSREGISTER_OffsetMapping_ScaleSteps = 24,
D3DPSREGISTER_PixelSize = 25,
D3DPSREGISTER_ReflectColor = 26,
D3DPSREGISTER_ReflectFactor = 27,
hlslPSSetParameter1f(D3DPSREGISTER_FogPlaneViewDist, rsurface.fogplaneviewdist);
hlslPSSetParameter1f(D3DPSREGISTER_FogRangeRecip, rsurface.fograngerecip);
hlslPSSetParameter1f(D3DPSREGISTER_FogHeightFade, rsurface.fogheightfade);
- hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
+ hlslPSSetParameter3f(D3DPSREGISTER_OffsetMapping_ScaleSteps, r_glsl_offsetmapping_scale.value, max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer));
hlslPSSetParameter2f(D3DPSREGISTER_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
hlslPSSetParameter2f(D3DPSREGISTER_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height);
if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
- if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value*rsurface.texture->offsetscale);
+ if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform3f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps, r_glsl_offsetmapping_scale.value*rsurface.texture->offsetscale, max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer));
if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegridmatrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_FogPlaneViewDist, rsurface.fogplaneviewdist);
DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_FogRangeRecip, rsurface.fograngerecip);
DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_FogHeightFade, rsurface.fogheightfade);
- DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value*rsurface.texture->offsetscale);
+ DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_OffsetMapping_ScaleSteps, r_glsl_offsetmapping_scale.value*rsurface.texture->offsetscale, max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer));
DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
Cvar_RegisterVariable(&r_glsl);
Cvar_RegisterVariable(&r_glsl_deluxemapping);
Cvar_RegisterVariable(&r_glsl_offsetmapping);
+ Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
+ Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
Cvar_RegisterVariable(&r_glsl_postprocess);
Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
"#endif\n"
"\n"
"#ifdef USEOFFSETMAPPING\n"
-"uniform mediump float OffsetMapping_Scale;\n"
+"uniform mediump vec3 OffsetMapping_ScaleSteps;\n"
"vec2 OffsetMapping(vec2 TexCoord, vec2 dPdx, vec2 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"
-" //vec3 OffsetVector = vec3(EyeVectorFogDepth.xy * ((1.0 / EyeVectorFogDepth.z) * OffsetMapping_Scale) * vec2(-1, 1), -1);\n"
-" //vec3 OffsetVector = vec3(normalize(EyeVectorFogDepth.xy) * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
-" vec3 OffsetVector = vec3(normalize(EyeVectorFogDepth.xyz).xy * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
+" //vec3 OffsetVector = vec3(EyeVectorFogDepth.xy * ((1.0 / EyeVectorFogDepth.z) * OffsetMapping_ScaleSteps.x) * vec2(-1, 1), -1);\n"
+" //vec3 OffsetVector = vec3(normalize(EyeVectorFogDepth.xy) * OffsetMapping_ScaleSteps.x * vec2(-1, 1), -1);\n"
+" vec3 OffsetVector = vec3(normalize(EyeVectorFogDepth.xyz).xy * OffsetMapping_ScaleSteps.x * vec2(-1, 1), -1);\n"
" vec3 RT = vec3(TexCoord, 1);\n"
-" OffsetVector *= 0.1;\n"
-" RT += OffsetVector * step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
+" OffsetVector *= OffsetMapping_ScaleSteps.z;\n"
+" for(i = 1.0; i < OffsetMapping_ScaleSteps.y; ++i)\n"
+" RT += OffsetVector * step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
" RT += OffsetVector * (step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z) - 0.5);\n"
" RT += OffsetVector * (step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z) * 0.5 - 0.25);\n"
" RT += OffsetVector * (step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z) * 0.25 - 0.125);\n"
" return RT.xy;\n"
"#else\n"
" // 2 sample offset mapping (only 2 samples because of ATI Radeon 9500-9800/X300 limits)\n"
-" //vec2 OffsetVector = vec2(EyeVectorFogDepth.xy * ((1.0 / EyeVectorFogDepth.z) * OffsetMapping_Scale) * vec2(-1, 1));\n"
-" //vec2 OffsetVector = vec2(normalize(EyeVectorFogDepth.xy) * OffsetMapping_Scale * vec2(-1, 1));\n"
-" vec2 OffsetVector = vec2(normalize(EyeVectorFogDepth.xyz).xy * OffsetMapping_Scale * vec2(-1, 1));\n"
-" OffsetVector *= 0.5;\n"
-" TexCoord += OffsetVector * (1.0 - dp_textureGrad(Texture_Normal, TexCoord, dPdx, dPdy).a);\n"
-" TexCoord += OffsetVector * (1.0 - dp_textureGrad(Texture_Normal, TexCoord, dPdx, dPdy).a);\n"
+" //vec2 OffsetVector = vec2(EyeVectorFogDepth.xy * ((1.0 / EyeVectorFogDepth.z) * OffsetMapping_ScaleSteps.x) * vec2(-1, 1));\n"
+" //vec2 OffsetVector = vec2(normalize(EyeVectorFogDepth.xy) * OffsetMapping_ScaleSteps.x * vec2(-1, 1));\n"
+" vec2 OffsetVector = vec2(normalize(EyeVectorFogDepth.xyz).xy * OffsetMapping_ScaleSteps.x * vec2(-1, 1));\n"
+" OffsetVector *= OffsetMapping_ScaleSteps.z;\n"
+" for(i = 0.0; i < OffsetMapping_ScaleSteps.y; ++i)\n"
+" TexCoord += OffsetVector * (1.0 - dp_textureGrad(Texture_Normal, TexCoord, dPdx, dPdy).a);\n"
" return TexCoord;\n"
"#endif\n"
"}\n"
"#endif\n"
"\n"
"#ifdef USEOFFSETMAPPING\n"
-"float2 OffsetMapping(float2 TexCoord, float OffsetMapping_Scale, float3 EyeVector, sampler Texture_Normal, float2 dPdx, float2 dPdy)\n"
+"float2 OffsetMapping(float2 TexCoord, float3 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(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n"
-" RT += OffsetVector * step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\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"
" RT += OffsetVector * (step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z) - 0.5);\n"
" RT += OffsetVector * (step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z) * 0.5 - 0.25);\n"
" RT += OffsetVector * (step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z) * 0.25 - 0.125);\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 - tex2Dgrad(Texture_Normal, TexCoord, dPdx, dPdy).a);\n"
-" TexCoord += OffsetVector * (1.0 - tex2Dgrad(Texture_Normal, TexCoord, dPdx, dPdy).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 float3 OffsetMapping_ScaleSteps : register(c24),\n"
"#endif\n"
"uniform half SpecularPower : register(c36),\n"
"#ifdef HLSL\n"
" // apply offsetmapping\n"
" float2 dPdx = ddx(TexCoord);\n"
" float2 dPdy = ddy(TexCoord);\n"
-" float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_Scale, EyeVector, Texture_Normal, dPdx, dPdy);\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 USEOFFSETMAPPING\n"
-"uniform float OffsetMapping_Scale : register(c24),\n"
+"uniform float3 OffsetMapping_ScaleSteps : register(c24),\n"
"#endif\n"
"\n"
"#ifdef USEDEFERREDLIGHTMAP\n"
" // apply offsetmapping\n"
" float2 dPdx = ddx(TexCoord);\n"
" float2 dPdy = ddy(TexCoord);\n"
-" float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_Scale, EyeVector, Texture_Normal, dPdx, dPdy);\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"