Index: ps/trunk/binaries/data/mods/public/gui/session/developer_overlay/DeveloperOverlayControlDropDowns.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/developer_overlay/DeveloperOverlayControlDropDowns.js (revision 25995) +++ ps/trunk/binaries/data/mods/public/gui/session/developer_overlay/DeveloperOverlayControlDropDowns.js (revision 25996) @@ -1,37 +1,39 @@ /** * This class stores the handlers for the individual dropdowns available in the developer overlay. * Such a class must have onSelectionChange function. * If the class has a selected property, then that will be called every simulation update to * synchronize the state of the dropdown (only if the developer overaly is opened). */ class DeveloperOverlayControlDrowDowns { } DeveloperOverlayControlDrowDowns.prototype.RenderDebugMode = class { constructor() { this.selectedIndex = this.values().map(e => e.value).indexOf( Engine.Renderer_GetRenderDebugMode()); } values() { return [ { "value": "RENDER_DEBUG_MODE_NONE", "label": translate("Render Debug Mode Disabled") }, - { "value": "RENDER_DEBUG_MODE_AO", "label": translate("Render Debug Mode AO") } + { "value": "RENDER_DEBUG_MODE_AO", "label": translate("Render Debug Mode AO") }, + { "value": "RENDER_DEBUG_MODE_ALPHA", "label": translate("Render Debug Mode Alpha") }, + { "value": "RENDER_DEBUG_MODE_CUSTOM", "label": translate("Render Debug Mode Custom") } ]; } onSelectionChange(selectedIndex) { this.selectedIndex = selectedIndex; Engine.Renderer_SetRenderDebugMode(this.values()[this.selectedIndex].value); } selected() { return this.selectedIndex; } }; Index: ps/trunk/binaries/data/mods/public/shaders/glsl/common/debug_fragment.h =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/common/debug_fragment.h (revision 25995) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/common/debug_fragment.h (revision 25996) @@ -1,20 +1,26 @@ #ifndef INCLUDED_DEBUG_FRAGMENT #define INCLUDED_DEBUG_FRAGMENT #define RENDER_DEBUG_MODE_NONE 0 #define RENDER_DEBUG_MODE_AO 1 +#define RENDER_DEBUG_MODE_ALPHA 2 +#define RENDER_DEBUG_MODE_CUSTOM 3 #ifndef RENDER_DEBUG_MODE #define RENDER_DEBUG_MODE RENDER_DEBUG_MODE_NONE #endif -vec3 applyDebugColor(vec3 color, float ao) +vec3 applyDebugColor(vec3 color, float ao, float alpha, float custom) { #if RENDER_DEBUG_MODE == RENDER_DEBUG_MODE_AO return vec3(ao); +#elif RENDER_DEBUG_MODE == RENDER_DEBUG_MODE_ALPHA + return vec3(alpha); +#elif RENDER_DEBUG_MODE == RENDER_DEBUG_MODE_CUSTOM + return vec3(custom); #else return color; #endif } #endif // INCLUDED_DEBUG_FRAGMENT Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.fs (revision 25995) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.fs (revision 25996) @@ -1,180 +1,180 @@ #version 120 #include "common/debug_fragment.h" #include "common/fog.h" #include "common/los_fragment.h" #include "common/shadows_fragment.h" uniform sampler2D baseTex; uniform sampler2D aoTex; uniform sampler2D normTex; uniform sampler2D specTex; #if USE_OBJECTCOLOR uniform vec3 objectColor; #else #if USE_PLAYERCOLOR uniform vec3 playerColor; #endif #endif uniform vec3 shadingColor; uniform vec3 ambient; uniform vec3 sunColor; uniform vec3 sunDir; varying vec4 v_lighting; varying vec2 v_tex; #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO varying vec2 v_tex2; #endif #if USE_SPECULAR uniform float specularPower; uniform vec3 specularColor; #endif #if USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX || USE_AO uniform vec4 effectSettings; #endif #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX varying vec4 v_normal; #if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_NORMAL_MAP || USE_PARALLAX) varying vec4 v_tangent; //varying vec3 v_bitangent; #endif #if USE_SPECULAR || USE_SPECULAR_MAP varying vec3 v_half; #endif #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_PARALLAX varying vec3 v_eyeVec; #endif #endif void main() { vec2 coord = v_tex; #if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_PARALLAX || USE_NORMAL_MAP) vec3 bitangent = vec3(v_normal.w, v_tangent.w, v_lighting.w); mat3 tbn = mat3(v_tangent.xyz, bitangent, v_normal.xyz); #endif #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_PARALLAX { float h = texture2D(normTex, coord).a; vec3 eyeDir = normalize(v_eyeVec * tbn); float dist = length(v_eyeVec); vec2 move; float height = 1.0; float scale = effectSettings.z; int iter = int(min(20.0, 25.0 - dist/10.0)); if (iter > 0) { float s = 1.0/float(iter); float t = s; move = vec2(-eyeDir.x, eyeDir.y) * scale / (eyeDir.z * float(iter)); vec2 nil = vec2(0.0); for (int i = 0; i < iter; ++i) { height -= t; t = (h < height) ? s : 0.0; vec2 temp = (h < height) ? move : nil; coord += temp; h = texture2D(normTex, coord).a; } // Move back to where we collided with the surface. // This assumes the surface is linear between the sample point before we // intersect the surface and after we intersect the surface float hp = texture2D(normTex, coord - move).a; coord -= move * ((h - height) / (s + h - hp)); } } #endif vec4 tex = texture2D(baseTex, coord); // Alpha-test as early as possible #ifdef REQUIRE_ALPHA_GEQUAL if (tex.a < REQUIRE_ALPHA_GEQUAL) discard; #endif #if USE_TRANSPARENT - gl_FragColor.a = tex.a; + float alpha = tex.a; #else - gl_FragColor.a = 1.0; + float alpha = 1.0; #endif vec3 texdiffuse = tex.rgb; // Apply-coloring based on texture alpha #if USE_OBJECTCOLOR texdiffuse *= mix(objectColor, vec3(1.0, 1.0, 1.0), tex.a); #else #if USE_PLAYERCOLOR texdiffuse *= mix(playerColor, vec3(1.0, 1.0, 1.0), tex.a); #endif #endif #if USE_SPECULAR || USE_SPECULAR_MAP || USE_NORMAL_MAP vec3 normal = v_normal.xyz; #endif #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_NORMAL_MAP vec3 ntex = texture2D(normTex, coord).rgb * 2.0 - 1.0; ntex.y = -ntex.y; normal = normalize(tbn * ntex); vec3 bumplight = max(dot(-sunDir, normal), 0.0) * sunColor; vec3 sundiffuse = (bumplight - v_lighting.rgb) * effectSettings.x + v_lighting.rgb; #else vec3 sundiffuse = v_lighting.rgb; #endif vec4 specular = vec4(0.0); #if USE_SPECULAR || USE_SPECULAR_MAP vec3 specCol; float specPow; #if USE_SPECULAR_MAP vec4 s = texture2D(specTex, coord); specCol = s.rgb; specular.a = s.a; specPow = effectSettings.y; #else specCol = specularColor; specPow = specularPower; #endif specular.rgb = sunColor * specCol * pow(max(0.0, dot(normalize(normal), v_half)), specPow); #endif #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO float ao = texture2D(aoTex, v_tex2).r; ao = mix(1.0, ao * 2.0, effectSettings.w); #else float ao = 1.0; #endif vec3 ambientColor = texdiffuse * ambient * ao; vec3 color = (texdiffuse * sundiffuse + specular.rgb) * getShadow() + ambientColor; #if USE_SPECULAR_MAP && USE_SELF_LIGHT color = mix(texdiffuse, color, specular.a); #endif color = applyFog(color); color *= getLOS(); color *= shadingColor; - color = applyDebugColor(color, ao); + color = applyDebugColor(color, ao, alpha, 0.0); - gl_FragColor.rgb = color; + gl_FragColor = vec4(color, alpha); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.fs (revision 25995) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.fs (revision 25996) @@ -1,102 +1,102 @@ #version 120 #include "common/debug_fragment.h" #include "common/los_fragment.h" #include "common/shadows_fragment.h" uniform sampler2D baseTex; uniform sampler2D aoTex; uniform sampler2D normTex; uniform sampler2D specTex; uniform sampler2D waterTex; uniform samplerCube skyCube; #if USE_OBJECTCOLOR uniform vec3 objectColor; #else #if USE_PLAYERCOLOR uniform vec3 playerColor; #endif #endif uniform vec3 shadingColor; uniform vec3 ambient; uniform vec3 sunColor; uniform vec3 sunDir; uniform vec3 cameraPos; uniform float specularStrength; uniform float waviness; uniform vec3 waterTint; uniform float murkiness; uniform vec3 reflectionTint; uniform float reflectionTintStrength; float waterDepth = 4.0; float fullDepth = 5.0; // Depth at which to use full murkiness (shallower water will be clearer) varying vec4 worldPos; varying vec4 v_tex; void main() { vec3 n, l, h, v; // Normal, light vector, half-vector and view vector (vector to eye) float ndotl, ndoth, ndotv; float fresnel; float t; // Temporary variable vec2 reflCoords, refrCoords; vec3 reflColor, refrColor, specular; //vec4 wtex = textureGrad(waterTex, vec3(fract(v_tex.xy), v_tex.z), dFdx(v_tex.xy), dFdy(v_tex.xy)); vec4 wtex = texture2D(waterTex, fract(v_tex.xy)); n = normalize(wtex.xzy - vec3(0.5, 0.5, 0.5)); l = -sunDir; v = normalize(cameraPos - worldPos.xyz); h = normalize(l + v); ndotl = dot(n, l); ndoth = dot(n, h); ndotv = dot(n, v); fresnel = pow(1.0 - ndotv, 0.8); // A rather random Fresnel approximation //refrCoords = (0.5*gl_TexCoord[2].xy - 0.8*waviness*n.xz) / gl_TexCoord[2].w + 0.5; // Unbias texture coords //reflCoords = (0.5*gl_TexCoord[1].xy + waviness*n.xz) / gl_TexCoord[1].w + 0.5; // Unbias texture coords //vec3 dir = normalize(v + vec3(waviness*n.x, 0.0, waviness*n.z)); vec3 eye = reflect(v, n); vec3 tex = textureCube(skyCube, eye).rgb; reflColor = mix(tex, sunColor * reflectionTint, reflectionTintStrength); //waterDepth = 4.0 + 2.0 * dot(abs(v_tex.zw - 0.5), vec2(0.5)); waterDepth = 4.0; //refrColor = (0.5 + 0.5*ndotl) * mix(texture2D(refractionMap, refrCoords).rgb, sunColor * tint, refrColor = (0.5 + 0.5*ndotl) * mix(vec3(0.3), sunColor * waterTint, murkiness * clamp(waterDepth / fullDepth, 0.0, 1.0)); // Murkiness and tint at this pixel (tweaked based on lighting and depth) specular = pow(max(0.0, ndoth), 150.0f) * sunColor * specularStrength; #if USE_SHADOW float shadow = getShadowOnLandscape(); float fresShadow = mix(fresnel, fresnel*shadow, dot(sunColor, vec3(0.16666))); #else float fresShadow = fresnel; #endif vec3 color = mix(refrColor + 0.3*specular, reflColor + specular, fresShadow); color *= getLOS(); - gl_FragColor.rgb = applyDebugColor(color, 1.0); - // Make alpha vary based on both depth (so it blends with the shore) and view angle (make it // become opaque faster at lower view angles so we can't look "underneath" the water plane) t = 18.0 * max(0.0, 0.7 - v.y); - gl_FragColor.a = 0.15 * waterDepth * (1.2 + t + fresnel); + float alpha = 0.15 * waterDepth * (1.2 + t + fresnel); + + gl_FragColor = vec4(applyDebugColor(color, 1.0, alpha, 0.0), alpha); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.fs (revision 25995) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.fs (revision 25996) @@ -1,43 +1,42 @@ #version 120 #include "common/debug_fragment.h" #include "common/los_fragment.h" #include "common/shadows_fragment.h" uniform sampler2D baseTex; uniform vec3 shadingColor; uniform vec3 ambient; uniform vec3 sunColor; uniform vec3 sunDir; uniform vec3 cameraPos; uniform float specularPower; uniform vec3 specularColor; varying vec4 v_tex; varying vec3 v_half; varying vec3 v_normal; varying float v_transp; varying vec3 v_lighting; void main() { //vec4 texdiffuse = textureGrad(baseTex, vec3(fract(v_tex.xy), v_tex.z), dFdx(v_tex.xy), dFdy(v_tex.xy)); vec4 texdiffuse = texture2D(baseTex, fract(v_tex.xy)); if (texdiffuse.a < 0.25) discard; texdiffuse.a *= v_transp; vec3 specular = sunColor * specularColor * pow(max(0.0, dot(normalize(v_normal), v_half)), specularPower); vec3 color = (texdiffuse.rgb * v_lighting + specular) * getShadowOnLandscape(); color += texdiffuse.rgb * ambient; color *= getLOS(); - gl_FragColor.rgb = applyDebugColor(color, 1.0); - gl_FragColor.a = texdiffuse.a; + gl_FragColor = vec4(applyDebugColor(color, 1.0, texdiffuse.a, 0.0), texdiffuse.a); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/overlayline.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/overlayline.fs (revision 25995) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/overlayline.fs (revision 25996) @@ -1,34 +1,34 @@ #version 120 #include "common/debug_fragment.h" #include "common/los_fragment.h" uniform sampler2D baseTex; uniform sampler2D maskTex; #if USE_OBJECTCOLOR uniform vec4 objectColor; #else varying vec4 v_color; #endif varying vec2 v_tex; void main() { #if USE_OBJECTCOLOR vec3 color = objectColor.rgb; float alpha = objectColor.a; #else vec3 color = v_color.rgb; float alpha = v_color.a; #endif vec4 base = texture2D(baseTex, v_tex); vec4 mask = texture2D(maskTex, v_tex); color = mix(base.rgb, color, mask.r); color *= getLOS(); - gl_FragColor = vec4(applyDebugColor(color, 1.0), alpha * base.a); + gl_FragColor = vec4(applyDebugColor(color, 1.0, alpha * base.a, 0.0), alpha * base.a); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.fs (revision 25995) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.fs (revision 25996) @@ -1,192 +1,194 @@ #version 120 #include "common/debug_fragment.h" #include "common/fog.h" #include "common/los_fragment.h" #include "common/shadows_fragment.h" uniform sampler2D baseTex; uniform sampler2D blendTex; uniform sampler2D normTex; uniform sampler2D specTex; uniform vec3 shadingColor; uniform vec3 ambient; uniform vec3 sunColor; uniform vec3 sunDir; uniform vec2 textureTransform; varying vec3 v_lighting; varying vec2 v_blend; #if USE_TRIPLANAR varying vec3 v_tex; #else varying vec2 v_tex; #endif #if USE_SPECULAR uniform float specularPower; uniform vec3 specularColor; #endif #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_AO uniform vec4 effectSettings; #endif varying vec3 v_normal; #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP #if USE_NORMAL_MAP varying vec4 v_tangent; varying vec3 v_bitangent; #endif #if USE_SPECULAR || USE_SPECULAR_MAP varying vec3 v_half; #endif #endif #if USE_TRIPLANAR vec4 triplanar(sampler2D sampler, vec3 wpos) { float tighten = 0.4679; vec3 blending = abs(normalize(v_normal)) - tighten; blending = max(blending, 0.0); blending /= vec3(blending.x + blending.y + blending.z); vec3 signedBlending = sign(v_normal) * blending; vec3 coords = wpos; coords.xyz /= 32.0; // Ugh. vec4 col1 = texture2D(sampler, coords.yz); vec4 col2 = texture2D(sampler, coords.zx); vec4 col3 = texture2D(sampler, coords.yx); vec4 colBlended = col1 * blending.x + col2 * blending.y + col3 * blending.z; return colBlended; } vec4 triplanarNormals(sampler2D sampler, vec3 wpos) { float tighten = 0.4679; vec3 blending = abs(normalize(v_normal)) - tighten; blending = max(blending, 0.0); blending /= vec3(blending.x + blending.y + blending.z); vec3 signedBlending = sign(v_normal) * blending; vec3 coords = wpos; coords.xyz /= 32.0; // Ugh. vec4 col1 = texture2D(sampler, coords.yz).xyzw; col1.y = 1.0 - col1.y; vec4 col2 = texture2D(sampler, coords.zx).yxzw; col2.y = 1.0 - col2.y; vec4 col3 = texture2D(sampler, coords.yx).yxzw; col3.y = 1.0 - col3.y; vec4 colBlended = col1 * blending.x + col2 * blending.y + col3 * blending.z; return colBlended; } #endif void main() { + float alpha = 0.0; + #if BLEND // Use alpha from blend texture - gl_FragColor.a = 1.0 - texture2D(blendTex, v_blend).a; + alpha = 1.0 - texture2D(blendTex, v_blend).a; #if USE_GRASS - if (gl_FragColor.a < LAYER / 10.0) + if (alpha < LAYER / 10.0) discard; #endif #else - gl_FragColor.a = 1.0; + alpha = 1.0; #endif #if USE_TRIPLANAR vec4 tex = triplanar(baseTex, v_tex); #else vec4 tex = texture2D(baseTex, v_tex.xy); #endif #if USE_GRASS && LAYER if (tex.a < 0.05) discard; #endif #if DECAL // Use alpha from main texture - gl_FragColor.a = tex.a; + alpha = tex.a; #endif vec3 texdiffuse = tex.rgb; #if USE_SPECULAR || USE_SPECULAR_MAP || USE_NORMAL_MAP vec3 normal = v_normal; #endif #if USE_NORMAL_MAP float sign = v_tangent.w; mat3 tbn = mat3(v_tangent.xyz, v_bitangent * -sign, v_normal); #if USE_TRIPLANAR vec3 ntex = triplanarNormals(normTex, v_tex).rgb * 2.0 - 1.0; #else vec3 ntex = texture2D(normTex, v_tex).rgb * 2.0 - 1.0; #endif normal = normalize(tbn * ntex); vec3 bumplight = max(dot(-sunDir, normal), 0.0) * sunColor; vec3 sundiffuse = (bumplight - v_lighting.rgb) * effectSettings.x + v_lighting.rgb; #else vec3 sundiffuse = v_lighting; #endif vec4 specular = vec4(0.0); #if USE_SPECULAR || USE_SPECULAR_MAP vec3 specCol; float specPow; #if USE_SPECULAR_MAP #if USE_TRIPLANAR vec4 s = triplanar(specTex, v_tex); #else vec4 s = texture2D(specTex, v_tex); #endif specCol = s.rgb; specular.a = s.a; specPow = effectSettings.y; #else specCol = specularColor; specPow = specularPower; #endif specular.rgb = sunColor * specCol * pow(max(0.0, dot(normalize(normal), v_half)), specPow); #endif vec3 color = (texdiffuse * sundiffuse + specular.rgb) * getShadowOnLandscape() + texdiffuse * ambient; #if USE_SPECULAR_MAP && USE_SELF_LIGHT color = mix(texdiffuse, color, specular.a); #endif color = applyFog(color); color *= getLOS(); #if DECAL color *= shadingColor; #endif - gl_FragColor.rgb = applyDebugColor(color, 1.0); - #if USE_GRASS - gl_FragColor.a = tex.a; + alpha = tex.a; #endif + + gl_FragColor = vec4(applyDebugColor(color, 1.0, 1.0, 0.0), alpha); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/water_high.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/water_high.fs (revision 25995) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/water_high.fs (revision 25996) @@ -1,309 +1,310 @@ #version 110 +#include "common/debug_fragment.h" #include "common/fog.h" #include "common/los_fragment.h" #include "common/shadows_fragment.h" // Environment settings uniform vec3 ambient; uniform vec3 sunDir; uniform vec3 sunColor; uniform mat4 skyBoxRot; uniform float waviness; // "Wildness" of the reflections and refractions; choose based on texture uniform vec3 color; // color of the water uniform vec3 tint; // Tint for refraction (used to simulate particles in water) uniform float murkiness; // Amount of tint to blend in with the refracted color uniform float windAngle; varying vec2 WindCosSin; uniform vec2 screenSize; varying float moddedTime; varying vec3 worldPos; varying float waterDepth; varying vec2 waterInfo; varying vec3 v_eyeVec; varying vec4 normalCoords; #if USE_REFLECTION varying vec3 reflectionCoords; #endif #if USE_REFRACTION varying vec3 refractionCoords; #endif varying float fwaviness; uniform samplerCube skyCube; uniform sampler2D normalMap; uniform sampler2D normalMap2; #if USE_FANCY_EFFECTS uniform sampler2D waterEffectsTex; #endif uniform vec4 waveParams1; // wavyEffect, BaseScale, Flattenism, Basebump uniform vec4 waveParams2; // Smallintensity, Smallbase, Bigmovement, Smallmovement #if USE_REFLECTION uniform sampler2D reflectionMap; #endif #if USE_REFRACTION uniform sampler2D refractionMap; #if USE_REAL_DEPTH uniform sampler2D depthTex; uniform mat4 projInvTransform; uniform mat4 viewInvTransform; #endif #endif vec3 getNormal(vec4 fancyeffects) { float wavyEffect = waveParams1.r; float baseScale = waveParams1.g; float flattenism = waveParams1.b; float baseBump = waveParams1.a; float BigMovement = waveParams2.b; // This method uses 60 animated water frames. We're blending between each two frames // Scale the normal textures by waviness so that big waviness means bigger waves. vec3 ww1 = texture2D(normalMap, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).xzy; vec3 ww2 = texture2D(normalMap2, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).xzy; vec3 wwInterp = mix(ww1, ww2, moddedTime) - vec3(0.5, 0.0, 0.5); ww1.x = wwInterp.x * WindCosSin.x - wwInterp.z * WindCosSin.y; ww1.z = wwInterp.x * WindCosSin.y + wwInterp.z * WindCosSin.x; ww1.y = wwInterp.y; // Flatten them based on waviness. vec3 normal = normalize(mix(vec3(0.0, 1.0, 0.0), ww1, clamp(baseBump + fwaviness / flattenism, 0.0, 1.0))); #if USE_FANCY_EFFECTS normal = mix(vec3(0.0, 1.0, 0.0), normal, 0.5 + waterInfo.r / 2.0); normal.xz = mix(normal.xz, fancyeffects.rb, fancyeffects.a / 2.0); #else normal = mix(vec3(0.0, 1.0, 0.0), normal, 0.5 + waterInfo.r / 2.0); #endif return vec3(-normal.x, normal.y, -normal.z); } vec3 getSpecular(vec3 normal, vec3 eyeVec) { // Specular lighting vectors vec3 specularVector = reflect(sunDir, normal); // pow is undefined for null or negative values, except on intel it seems. float specularIntensity = pow(max(dot(specularVector, eyeVec), 0.0), 100.0); // Workaround to fix too flattened water. specularIntensity = smoothstep(0.6, 1.0, specularIntensity) * 1.2; return clamp(specularIntensity * sunColor, 0.0, 1.0); } vec4 getReflection(vec3 normal, vec3 eyeVec) { // Reflections // 3 level of settings: // -If a player has refraction and reflection disabled, we return a gradient of blue based on the Y component. // -If a player has refraction OR reflection, we return a reflection of the actual skybox used. // -If a player has reflection enabled, we also return a reflection of actual entities where applicable. // reflMod reduces the intensity of reflections somewhat since they kind of wash refractions out otherwise. float reflMod = 0.75; vec3 eye = reflect(eyeVec, normal); #if USE_REFLECTION float refVY = clamp(eyeVec.y * 2.0, 0.05, 1.0); // Distort the reflection coords based on waves. vec2 reflCoords = (0.5 * reflectionCoords.xy - 15.0 * normal.zx / refVY) / reflectionCoords.z + 0.5; vec4 refTex = texture2D(reflectionMap, reflCoords); vec3 reflColor = refTex.rgb; // Interpolate between the sky color and nearby objects. // Only do this when alpha is rather low, or transparent leaves show up as extremely white. if (refTex.a < 0.4) reflColor = mix(textureCube(skyCube, (vec4(eye, 0.0) * skyBoxRot).xyz).rgb, refTex.rgb, refTex.a); // Let actual objects be reflected fully. reflMod = max(refTex.a, 0.75); #else vec3 reflColor = textureCube(skyCube, (vec4(eye, 0.0) * skyBoxRot).xyz).rgb; #endif return vec4(reflColor, reflMod); } #if USE_REFRACTION && USE_REAL_DEPTH vec3 getWorldPositionFromRefractionDepth(vec2 uv) { float depth = texture2D(depthTex, uv).x; vec4 viewPosition = projInvTransform * (vec4((uv - vec2(0.5)) * 2.0, depth * 2.0 - 1.0, 1.0)); viewPosition /= viewPosition.w; vec3 refrWorldPos = (viewInvTransform * viewPosition).xyz; // Depth buffer precision errors can give heights above the water. refrWorldPos.y = min(refrWorldPos.y, worldPos.y); return refrWorldPos; } #endif vec4 getRefraction(vec3 normal, vec3 eyeVec, float depthLimit) { #if USE_REFRACTION && USE_REAL_DEPTH // Compute real depth at the target point. vec2 coords = (0.5 * refractionCoords.xy) / refractionCoords.z + 0.5; vec3 refrWorldPos = getWorldPositionFromRefractionDepth(coords); // Set depth to the depth at the undistorted point. float depth = distance(refrWorldPos, worldPos); #else // fake depth computation: take the value at the vertex, add some if we are looking at a more oblique angle. float depth = waterDepth / (min(0.5, eyeVec.y) * 1.5 * min(0.5, eyeVec.y) * 2.0); #endif #if USE_REFRACTION // for refraction we want to distort more as depth goes down. // 1) compute a distortion based on depth at the pixel. // 2) Re-sample the depth at the target point // 3) Sample refraction texture // distoFactor controls the amount of distortion relative to wave normals. float distoFactor = 0.5 + clamp(depth / 2.0, 0.0, 7.0); #if USE_REAL_DEPTH // Distort the texture coords under where the water is to simulate refraction. vec2 shiftedCoords = (0.5 * refractionCoords.xy - normal.xz * distoFactor) / refractionCoords.z + 0.5; vec3 refrWorldPos2 = getWorldPositionFromRefractionDepth(shiftedCoords); float newDepth = distance(refrWorldPos2, worldPos); // try to correct for fish. In general they'd look weirder without this fix. if (depth > newDepth + 3.0) distoFactor /= 2.0; // this in general will not fall on the fish but still look distorted. else depth = newDepth; #endif #if USE_FANCY_EFFECTS depth = max(depth, depthLimit); if (waterDepth < 0.0) depth = 0.0; #endif // Distort the texture coords under where the water is to simulate refraction. vec2 refrCoords = (0.5 * refractionCoords.xy - normal.xz * distoFactor) / refractionCoords.z + 0.5; vec3 refColor = texture2D(refractionMap, refrCoords).rgb; // Note, the refraction map is cleared using (255, 0, 0), so pixels outside of the water plane are pure red. // If we get a pure red fragment, use an undistorted/less distorted coord instead. // blur the refraction map, distoring using normal so that it looks more random than it really is // and thus looks much better. float blur = (0.1 + clamp(normal.x, -0.1, 0.1)) / refractionCoords.z; vec4 blurColor = vec4(refColor, 1.0); vec4 tex = texture2D(refractionMap, refrCoords + vec2(blur + normal.x, blur + normal.z)); blurColor += vec4(tex.rgb * tex.a, tex.a); tex = texture2D(refractionMap, refrCoords + vec2(-blur, blur + normal.z)); blurColor += vec4(tex.rgb * tex.a, tex.a); tex = texture2D(refractionMap, refrCoords + vec2(-blur, -blur + normal.x)); blurColor += vec4(tex.rgb * tex.a, tex.a); tex = texture2D(refractionMap, refrCoords + vec2(blur + normal.z, -blur)); blurColor += vec4(tex.rgb * tex.a, tex.a); blurColor /= blurColor.a; float blurFactor = (distoFactor / 7.0); refColor = (refColor + blurColor.rgb * blurFactor) / (1.0 + blurFactor); #else // !USE_REFRACTION #if USE_FANCY_EFFECTS depth = max(depth, depthLimit); #endif vec3 refColor = color; #endif // for refraction, we want to adjust the value by v.y slightly otherwise it gets too different between "from above" and "from the sides". // And it looks weird (again, we are not used to seeing water from above). float fixedVy = max(eyeVec.y, 0.01); float murky = mix(200.0, 0.1, pow(murkiness, 0.25)); // Apply water tint and murk color. float extFact = max(0.0, 1.0 - (depth * fixedVy / murky)); float ColextFact = max(0.0, 1.0 - (depth * fixedVy / murky)); vec3 colll = mix(refColor * tint, refColor, ColextFact); vec3 refrColor = mix(color, colll, extFact); float alpha = clamp(depth, 0.0, 1.0); #if !USE_REFRACTION alpha = (1.4 - extFact) * alpha; #endif return vec4(refrColor, alpha); } vec4 getFoam(vec4 fancyeffects, float shadow) { #if USE_FANCY_EFFECTS float wavyEffect = waveParams1.r; float baseScale = waveParams1.g; float BigMovement = waveParams2.b; vec3 foam1 = texture2D(normalMap, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).aaa; vec3 foam2 = texture2D(normalMap2, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).aaa; vec3 foam3 = texture2D(normalMap, normalCoords.st / 6.0 - normalCoords.zw * 0.02).aaa; vec3 foam4 = texture2D(normalMap2, normalCoords.st / 6.0 - normalCoords.zw * 0.02).aaa; vec3 foaminterp = mix(foam1, foam2, moddedTime); foaminterp *= mix(foam3, foam4, moddedTime); foam1.x = abs(foaminterp.x * WindCosSin.x) + abs(foaminterp.z * WindCosSin.y); float alpha = (fancyeffects.g + pow(foam1.x * (3.0 + waviness), 2.6 - waviness / 5.5)) * 2.0; return vec4(sunColor * shadow + ambient, clamp(alpha, 0.0, 1.0)); #else return vec4(0.0); #endif } void main() { #if USE_FANCY_EFFECTS vec4 fancyeffects = texture2D(waterEffectsTex, gl_FragCoord.xy / screenSize); #else vec4 fancyeffects = vec4(0.0); #endif vec3 eyeVec = normalize(v_eyeVec); vec3 normal = getNormal(fancyeffects); vec4 refrColor = getRefraction(normal, eyeVec, fancyeffects.a); vec4 reflColor = getReflection(normal, eyeVec); // How perpendicular to the normal our view is. Used for fresnel. float ndotv = clamp(dot(normal, eyeVec), 0.0, 1.0); // Fresnel for "how much reflection vs how much refraction". float fresnel = clamp(((pow(1.1 - ndotv, 2.0)) * 1.5), 0.1, 0.75); // Approximation. I'm using 1.1 and not 1.0 because it causes artifacts, see #1714 vec3 specular = getSpecular(normal, eyeVec); #if USE_SHADOW float shadow = getShadowOnLandscape(); fresnel = mix(fresnel, fresnel * shadow, 0.05 + murkiness * 0.2); #else float shadow = 1.0; #endif vec3 color = mix(refrColor.rgb, reflColor.rgb, fresnel * reflColor.a); color += shadow * specular; vec4 foam = getFoam(fancyeffects, shadow); color = clamp(mix(color, foam.rgb, foam.a), 0.0, 1.0); color = applyFog(color); - gl_FragColor = vec4(color * getLOS(), refrColor.a); + gl_FragColor = vec4(applyDebugColor(color * getLOS(), 1.0, refrColor.a, 0.0), refrColor.a); } Index: ps/trunk/source/ps/CStrInternStatic.h =================================================================== --- ps/trunk/source/ps/CStrInternStatic.h (revision 25995) +++ ps/trunk/source/ps/CStrInternStatic.h (revision 25996) @@ -1,185 +1,187 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ // This file defines global CStrIntern variables, to avoid the cost of // constructing CStrInterns frequently at runtime. // // A line like // X(foo) // defines a variable str_foo with value "foo". // // A line like // X2(foo_0, "foo[0]") // defines a variable str_foo_0 with value "foo[0]". // For direct inclusion, we presumably just want the extern definitions. #ifndef X #include "CStrIntern.h" #define X(id) extern CStrIntern str_##id; #define X2(id, str) extern CStrIntern str_##id; #endif X(0) X(1) X(2) X(3) X(4) X(ALPHABLEND_PASS_BLEND) X(ALPHABLEND_PASS_OPAQUE) X(BLEND) X(BLOOM_NOP) X(BLOOM_PASS_H) X(BLOOM_PASS_V) X(DECAL) X(DISABLE_RECEIVE_SHADOWS) X(IGNORE_LOS) X(MINIMAP_BASE) X(MINIMAP_LINE) X(MINIMAP_LOS) X(MINIMAP_MASK) X(MINIMAP_POINT) X(MODE_SHADOWCAST) X(MODE_SILHOUETTEDISPLAY) X(MODE_SILHOUETTEOCCLUDER) X(MODE_WIREFRAME) X(RENDER_DEBUG_MODE) X(RENDER_DEBUG_MODE_AO) +X(RENDER_DEBUG_MODE_ALPHA) +X(RENDER_DEBUG_MODE_CUSTOM) X(RENDER_DEBUG_MODE_NONE) X(SHADOWS_CASCADE_COUNT) X(SYS_HAS_ARB) X(SYS_HAS_GLSL) X(SYS_PREFER_GLSL) X(USE_FANCY_EFFECTS) X(USE_FP_SHADOW) X(USE_GPU_SKINNING) X(USE_INSTANCING) X(USE_NORMALS) X(USE_OBJECTCOLOR) X(USE_REAL_DEPTH) X(USE_REFLECTION) X(USE_REFRACTION) X(USE_SHADOW) X(USE_SHADOW_PCF) X(USE_SHADOW_SAMPLER) X(USE_FOG) X(WATERTYPE_CLAP) X(WATERTYPE_LAKE) X2(_emptystring, "") X(a_apexPosition) X(a_otherPosition) X(a_retreatPosition) X(a_skinJoints) X(a_skinWeights) X(a_splashPosition) X(a_tangent) X(a_waterInfo) X(ambient) X(baseTex) X(blendTex) X(bloom) X(blurTex2) X(blurTex4) X(blurTex8) X(brightness) X(cameraForward) X(cameraPos) X(canvas2d) X(color) X(colorAdd) X(colorMul) X(debug_line) X(debug_overlay) X(delta) X(depthTex) X(foamTex) X(fogColor) X(fogParams) X(foreground_overlay) X(grayscaleFactor) X(hdr) X(height) X(instancingTransform) X(losTex) X(losTex1) X(losTex2) X(losTransform) X(los_interp) X(mapSize) X(maskTex) X(maskTextureTransform) X(minimap) X(modelViewMatrix) X(murkiness) X(normalMap) X(normalMap2) X(objectColor) X(overlay_solid) X(particle) X(particle_solid) X(playerColor) X(pointSize) X(projInvTransform) X(qualityLevel) X(reflectionMap) X(reflectionMatrix) X(refractionMap) X(refractionMatrix) X(renderedTex) X(repeatScale) X2(sans_10, "sans-10"); X(saturation) X(screenSize) X(shadingColor) X(shadowDistance) X(shadowDistances) X2(shadowDistances_0, "shadowDistances[0]") X(shadowScale) X(shadowTex) X(shadowTransform) X(shadowTransforms) X2(shadowTransforms_0, "shadowTransforms[0]") X(sharpness) X(skinBlendMatrices) X2(skinBlendMatrices_0, "skinBlendMatrices[0]") X(skyBoxRot) X(skyCube) X(sky_simple) X(solid) X(sunColor) X(sunDir) X(tex) X(texSize) X(textureTransform) X(time) X(tint) X(transform) X(translation) X(viewInvTransform) X(water_simple) X(waterEffectsTex) X(waterTex) X(waveTex) X(waviness) X(waveParams1) X(waveParams2) X(width) X(windAngle) X(zFar) X(zNear) #undef X #undef X2 Index: ps/trunk/source/renderer/RenderingOptions.cpp =================================================================== --- ps/trunk/source/renderer/RenderingOptions.cpp (revision 25995) +++ ps/trunk/source/renderer/RenderingOptions.cpp (revision 25996) @@ -1,282 +1,290 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "RenderingOptions.h" #include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/CStr.h" #include "ps/CStrInternStatic.h" #include "renderer/Renderer.h" #include "renderer/PostprocManager.h" #include "renderer/ShadowMap.h" CRenderingOptions g_RenderingOptions; class CRenderingOptions::ConfigHooks { public: std::vector::iterator begin() { return hooks.begin(); } std::vector::iterator end() { return hooks.end(); } template void Setup(CStr8 name, T& variable) { hooks.emplace_back(g_ConfigDB.RegisterHookAndCall(name, [name, &variable]() { CFG_GET_VAL(name, variable); })); } void Setup(CStr8 name, std::function hook) { hooks.emplace_back(g_ConfigDB.RegisterHookAndCall(name, hook)); } void clear() { hooks.clear(); } private: std::vector hooks; }; RenderPath RenderPathEnum::FromString(const CStr8& name) { if (name == "default") return DEFAULT; if (name == "fixed") return FIXED; if (name == "shader") return SHADER; LOGWARNING("Unknown render path %s", name.c_str()); return DEFAULT; } CStr8 RenderPathEnum::ToString(RenderPath path) { switch (path) { case RenderPath::DEFAULT: return "default"; case RenderPath::FIXED: return "fixed"; case RenderPath::SHADER: return "shader"; } return "default"; // Silence warning about reaching end of non-void function. } RenderDebugMode RenderDebugModeEnum::FromString(const CStr8& name) { if (name == str_RENDER_DEBUG_MODE_NONE.c_str()) return RenderDebugMode::NONE; if (name == str_RENDER_DEBUG_MODE_AO.c_str()) return RenderDebugMode::AO; + if (name == str_RENDER_DEBUG_MODE_ALPHA.c_str()) + return RenderDebugMode::ALPHA; + if (name == str_RENDER_DEBUG_MODE_CUSTOM.c_str()) + return RenderDebugMode::CUSTOM; LOGWARNING("Unknown render debug mode %s", name.c_str()); return RenderDebugMode::NONE; } CStrIntern RenderDebugModeEnum::ToString(RenderDebugMode mode) { switch (mode) { case RenderDebugMode::AO: return str_RENDER_DEBUG_MODE_AO; + case RenderDebugMode::ALPHA: + return str_RENDER_DEBUG_MODE_ALPHA; + case RenderDebugMode::CUSTOM: + return str_RENDER_DEBUG_MODE_CUSTOM; default: break; } return str_RENDER_DEBUG_MODE_NONE; } CRenderingOptions::CRenderingOptions() : m_ConfigHooks(new ConfigHooks()) { m_RenderPath = RenderPath::DEFAULT; m_Shadows = false; m_WaterEffects = false; m_WaterFancyEffects = false; m_WaterRealDepth = false; m_WaterRefraction = false; m_WaterReflection = false; m_ShadowAlphaFix = false; m_ARBProgramShadow = true; m_ShadowPCF = false; m_Particles = false; m_Silhouettes = false; m_PreferGLSL = false; m_Fog = false; m_ForceAlphaTest = false; m_GPUSkinning = false; m_SmoothLOS = false; m_PostProc = false; m_DisplayFrustum = false; m_DisplayShadowsFrustum = false; m_RenderActors = true; } CRenderingOptions::~CRenderingOptions() { ClearHooks(); } void CRenderingOptions::ReadConfigAndSetupHooks() { m_ConfigHooks->Setup("renderpath", [this]() { CStr renderPath; CFG_GET_VAL("renderpath", renderPath); SetRenderPath(RenderPathEnum::FromString(renderPath)); }); m_ConfigHooks->Setup("preferglsl", [this]() { bool enabled; CFG_GET_VAL("preferglsl", enabled); SetPreferGLSL(enabled); if (CRenderer::IsInitialised()) g_Renderer.GetShadowMap().RecreateTexture(); }); m_ConfigHooks->Setup("shadowquality", []() { if (CRenderer::IsInitialised()) g_Renderer.GetShadowMap().RecreateTexture(); }); m_ConfigHooks->Setup("shadowscascadecount", []() { if (CRenderer::IsInitialised()) { g_Renderer.GetShadowMap().RecreateTexture(); g_Renderer.MakeShadersDirty(); } }); m_ConfigHooks->Setup("shadowscovermap", []() { if (CRenderer::IsInitialised()) { g_Renderer.GetShadowMap().RecreateTexture(); g_Renderer.MakeShadersDirty(); } }); m_ConfigHooks->Setup("shadowscutoffdistance", []() { if (CRenderer::IsInitialised()) g_Renderer.GetShadowMap().RecreateTexture(); }); m_ConfigHooks->Setup("shadows", [this]() { bool enabled; CFG_GET_VAL("shadows", enabled); SetShadows(enabled); }); m_ConfigHooks->Setup("shadowpcf", [this]() { bool enabled; CFG_GET_VAL("shadowpcf", enabled); SetShadowPCF(enabled); }); m_ConfigHooks->Setup("postproc", m_PostProc); m_ConfigHooks->Setup("antialiasing", []() { if (CRenderer::IsInitialised()) g_Renderer.GetPostprocManager().UpdateAntiAliasingTechnique(); }); m_ConfigHooks->Setup("sharpness", []() { if (CRenderer::IsInitialised()) g_Renderer.GetPostprocManager().UpdateSharpnessFactor(); }); m_ConfigHooks->Setup("sharpening", []() { if (CRenderer::IsInitialised()) g_Renderer.GetPostprocManager().UpdateSharpeningTechnique(); }); m_ConfigHooks->Setup("smoothlos", m_SmoothLOS); m_ConfigHooks->Setup("watereffects", m_WaterEffects); m_ConfigHooks->Setup("waterfancyeffects", m_WaterFancyEffects); m_ConfigHooks->Setup("waterrealdepth", m_WaterRealDepth); m_ConfigHooks->Setup("waterrefraction", m_WaterRefraction); m_ConfigHooks->Setup("waterreflection", m_WaterReflection); m_ConfigHooks->Setup("particles", m_Particles); m_ConfigHooks->Setup("fog", [this]() { bool enabled; CFG_GET_VAL("fog", enabled); SetFog(enabled); }); m_ConfigHooks->Setup("silhouettes", m_Silhouettes); m_ConfigHooks->Setup("forcealphatest", m_ForceAlphaTest); m_ConfigHooks->Setup("gpuskinning", [this]() { bool enabled; CFG_GET_VAL("gpuskinning", enabled); if (enabled && !m_PreferGLSL) LOGWARNING("GPUSkinning has been disabled, because it is not supported with PreferGLSL disabled."); else if (enabled) m_GPUSkinning = true; }); m_ConfigHooks->Setup("renderactors", m_RenderActors); } void CRenderingOptions::ClearHooks() { m_ConfigHooks->clear(); } void CRenderingOptions::SetShadows(bool value) { m_Shadows = value; if (CRenderer::IsInitialised()) g_Renderer.MakeShadersDirty(); } void CRenderingOptions::SetShadowPCF(bool value) { m_ShadowPCF = value; if (CRenderer::IsInitialised()) g_Renderer.MakeShadersDirty(); } void CRenderingOptions::SetFog(bool value) { m_Fog = value; if (CRenderer::IsInitialised()) g_Renderer.MakeShadersDirty(); } void CRenderingOptions::SetPreferGLSL(bool value) { if (m_GPUSkinning && !value) { LOGWARNING("GPUSkinning have been disabled, because it is not supported with PreferGLSL disabled."); m_GPUSkinning = false; } else if (!m_GPUSkinning && value) CFG_GET_VAL("gpuskinning", m_GPUSkinning); m_PreferGLSL = value; if (!CRenderer::IsInitialised()) return; g_Renderer.MakeShadersDirty(); g_Renderer.RecomputeSystemShaderDefines(); } void CRenderingOptions::SetRenderPath(RenderPath value) { m_RenderPath = value; if (CRenderer::IsInitialised()) g_Renderer.SetRenderPath(m_RenderPath); } void CRenderingOptions::SetRenderDebugMode(RenderDebugMode value) { m_RenderDebugMode = value; if (CRenderer::IsInitialised()) g_Renderer.MakeShadersDirty(); } Index: ps/trunk/source/renderer/RenderingOptions.h =================================================================== --- ps/trunk/source/renderer/RenderingOptions.h (revision 25995) +++ ps/trunk/source/renderer/RenderingOptions.h (revision 25996) @@ -1,139 +1,141 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ /** * Keeps track of the settings used for rendering. * Ideally this header file should remain very quick to parse, * so avoid including other headers here unless absolutely necessary. * * Lifetime concerns: g_RenderingOptions always exists, but hooks are tied to the configDB's lifetime * an the renderer may or may not actually exist. */ #ifndef INCLUDED_RENDERINGOPTIONS #define INCLUDED_RENDERINGOPTIONS #include "ps/CStr.h" #include "ps/CStrIntern.h" class CRenderer; enum RenderPath { // If no rendering path is configured explicitly, the renderer // will choose the path when Open() is called. DEFAULT, // Classic fixed function. FIXED, // Use new ARB/GLSL system SHADER }; struct RenderPathEnum { static RenderPath FromString(const CStr8& name); static CStr8 ToString(RenderPath); }; enum class RenderDebugMode { NONE, - AO + AO, + ALPHA, + CUSTOM }; struct RenderDebugModeEnum { static RenderDebugMode FromString(const CStr8& name); static CStrIntern ToString(RenderDebugMode mode); }; class CRenderingOptions { // The renderer needs access to our private variables directly because capabilities have not yet been extracted // and thus sometimes it needs to change the rendering options without the side-effects. friend class CRenderer; public: CRenderingOptions(); ~CRenderingOptions(); void ReadConfigAndSetupHooks(); void ClearHooks(); #define OPTION_DEFAULT_SETTER(NAME, TYPE) \ public: void Set##NAME(TYPE value) { m_##NAME = value; }\ #define OPTION_CUSTOM_SETTER(NAME, TYPE) \ public: void Set##NAME(TYPE value);\ #define OPTION_GETTER(NAME, TYPE)\ public: TYPE Get##NAME() const { return m_##NAME; }\ #define OPTION_DEF(NAME, TYPE)\ private: TYPE m_##NAME; #define OPTION(NAME, TYPE)\ OPTION_DEFAULT_SETTER(NAME, TYPE); OPTION_GETTER(NAME, TYPE); OPTION_DEF(NAME, TYPE); #define OPTION_WITH_SIDE_EFFECT(NAME, TYPE)\ OPTION_CUSTOM_SETTER(NAME, TYPE); OPTION_GETTER(NAME, TYPE); OPTION_DEF(NAME, TYPE); OPTION_WITH_SIDE_EFFECT(Shadows, bool); OPTION_WITH_SIDE_EFFECT(ShadowPCF, bool); OPTION_WITH_SIDE_EFFECT(PreferGLSL, bool); OPTION_WITH_SIDE_EFFECT(Fog, bool); OPTION_WITH_SIDE_EFFECT(RenderPath, RenderPath); OPTION_WITH_SIDE_EFFECT(RenderDebugMode, RenderDebugMode); OPTION(WaterEffects, bool); OPTION(WaterFancyEffects, bool); OPTION(WaterRealDepth, bool); OPTION(WaterRefraction, bool); OPTION(WaterReflection, bool); OPTION(ShadowAlphaFix, bool); OPTION(ARBProgramShadow, bool); OPTION(Particles, bool); OPTION(ForceAlphaTest, bool); OPTION(GPUSkinning, bool); OPTION(Silhouettes, bool); OPTION(SmoothLOS, bool); OPTION(PostProc, bool); OPTION(DisplayFrustum, bool); OPTION(DisplayShadowsFrustum, bool); OPTION(RenderActors, bool); #undef OPTION_DEFAULT_SETTER #undef OPTION_CUSTOM_SETTER #undef OPTION_GETTER #undef OPTION_DEF #undef OPTION #undef OPTION_WITH_SIDE_EFFECT private: class ConfigHooks; std::unique_ptr m_ConfigHooks; // Hide this via PImpl to avoid including ConfigDB.h here. }; extern CRenderingOptions g_RenderingOptions; #endif // INCLUDED_RENDERINGOPTIONS