/*
    VertaLux 3.0 "Realis" - global settings.
    Options are grouped into categories in the "Shader Options" screen.
    Included FIRST by every program; nothing here may depend on other headers.
*/

// ============ SHADOWS ============
// Contact Shadows (SSCS): micro shadows between adjacent blocks.
// Improves corners and edges - off by default (GPU cost).
//#define CONTACT_SHADOWS

// Real shadow-map shadows on particles (smoke, drips, rain splashes...): a
// particle in tree shade goes dark like the terrain. 0 = legacy lightmap-only.
#define PARTICLE_SHADOWS 1 // [0 1]
// Far-particle fast path: beyond 24 blocks a particle spans 2-6 px and its
// PCSS penumbra is sub-pixel, so the full soft shadow (5-tap blocker search +
// SHADOW_SAMPLES PCF) is replaced by ONE hard shadowtex1 tap. Near particles
// keep the full PCSS. 0 = soft shadow at any distance.
#define PARTICLE_FAST_SHADOWS 1 // [0 1]

// ================== SIMPLIFIED QUALITY - 4 AXES ==================
// Each axis [0..3] = Low / Medium / High / Very high and DERIVES all the
// related technical settings (resolutions, sample counts, ranges) through the
// #if blocks below. The derived fine values are NOT menu options: they follow
// the axis.
// Note: the #define lines inside the #if branches are EXCLUSIVE redefinitions
// (only one branch compiles) - duplicate-define audits must skip this block.
#define SHADOW_QUALITY 1 // [0 1 2 3]
#define CLOUD_QUALITY 1 // [0 1 2 3]
#define VOLUMETRIC_QUALITY 1 // [0 1 2 3]
#define WATER_QUALITY 1 // [0 1 2 3]

#if SHADOW_QUALITY == 0
const int   shadowMapResolution     = 1024;
const float shadowDistance          = 128.0;
#define SHADOW_SAMPLES 4
#define CONTACT_SHADOW_STEPS 6
#define AO_SAMPLES 4
#elif SHADOW_QUALITY == 1
const int   shadowMapResolution     = 2048;
const float shadowDistance          = 192.0;
#define SHADOW_SAMPLES 8
#define CONTACT_SHADOW_STEPS 8
#define AO_SAMPLES 8
#elif SHADOW_QUALITY == 2
const int   shadowMapResolution     = 4096;
const float shadowDistance          = 256.0;
#define SHADOW_SAMPLES 12
#define CONTACT_SHADOW_STEPS 10
#define AO_SAMPLES 12
#else
const int   shadowMapResolution     = 4096;
const float shadowDistance          = 384.0;
#define SHADOW_SAMPLES 16
#define CONTACT_SHADOW_STEPS 16
#define AO_SAMPLES 16
#endif

#if CLOUD_QUALITY == 0
#define VC_SAMPLES 8
#define VC_RENDER_DISTANCE 700.0
#elif CLOUD_QUALITY == 1
#define VC_SAMPLES 16
#define VC_RENDER_DISTANCE 900.0
#elif CLOUD_QUALITY == 2
#define VC_SAMPLES 24
#define VC_RENDER_DISTANCE 1400.0
#else
#define VC_SAMPLES 48
#define VC_RENDER_DISTANCE 1800.0
#endif

#if VOLUMETRIC_QUALITY == 0
#define VL_SAMPLES 4
#define GODRAY_SAMPLES 8
#define UW_RAY_DISTANCE 24.0
#elif VOLUMETRIC_QUALITY == 1
#define VL_SAMPLES 8
#define GODRAY_SAMPLES 8
#define UW_RAY_DISTANCE 48.0
#elif VOLUMETRIC_QUALITY == 2
#define VL_SAMPLES 12
#define GODRAY_SAMPLES 12
#define UW_RAY_DISTANCE 96.0 // 12 steps, dt 8.0
#else
#define VL_SAMPLES 20
#define GODRAY_SAMPLES 16
#define UW_RAY_DISTANCE 112.0 // longest underwater ray range (20 steps, dt 5.6)
#endif

#if WATER_QUALITY == 0
#define WAVE_ITERATIONS 2
#elif WATER_QUALITY == 1
#define WAVE_ITERATIONS 3
#elif WATER_QUALITY == 2
#define WAVE_ITERATIONS 3
#else
#define WAVE_ITERATIONS 4
#endif
// 3 wave iterations by default, 4 only at Very high: fewer wave trains keeps
// the sea readable.
// ================ END SIMPLIFIED QUALITY ================
const float shadowDistanceRenderMul = 1.0;   // [-1.0 0.5 0.75 1.0 1.5 2.0 3.0 4.0]
// ENTITY shadow range = entityShadowDistanceMul * shadowDistance. This is an Iris GLSL CONST
// (read from composite/deferred/final - settings.glsl is included by final.fsh), NOT a
// shaders.properties key: an "entityShadowDistanceMul=1.0" line there is silently ignored.
// 1.0 = same range as terrain (Iris default); raise to 2.0 if distant entities lose shadows.
const float entityShadowDistanceMul = 1.0;
const float sunPathRotation         = -35.0; // [-90.0 -75.0 -60.0 -50.0 -40.0 -35.0 -25.0 -10.0 0.0 25.0 45.0 90.0]

// PSEUDO-CASCADES (rectilinear distortion, lib/distort.glsl): concentrates
// shadow map texels near the player. Iris has a SINGLE shadow pass (no real
// multi-cascade), so the distortion IS the pseudo-cascade - resolution decays
// continuously with distance, with no seams.
// 0.85 matches the old fixed constant at shadowDistance 256; 0.90 is calibrated
// for shadowDistance 384 (identical near sharpness, edge texel ~1.5x coarser).
// Do NOT exceed 0.92: beyond that the per-vertex distortion visibly bends the
// shadow edges of large triangles.
// PCSS, bias and texel size follow automatically (all depend on the factor f).
#define SHADOW_DISTORT_STRENGTH 0.90 // [0.80 0.85 0.88 0.90 0.92]
// SHADOW_Z_SCALE: shadow map Z packing (distortShadow, lib/distort.glsl).
// The Iris shadow frustum has a FIXED depth range (~near 0.05 / far 256, light
// camera 100 blocks from the player) INDEPENDENT of shadowDistance. A z*0.5
// packing only covers ~-230..+280 blocks ALONG THE SUN AXIS, so at low/medium
// sun the shadows die around 250-400 blocks whatever shadowDistance says (sun
// side: falsely lit terrain; opposite side: false darkening).
// 0.2 gives ~-612..+668 blocks, covering view distance 512 at any sun height.
// Reader-side biases rescale automatically through the (SHADOW_Z_SCALE * 2.0)
// factor - exact no-op at 0.5. GPU cost: zero, only z precision distribution
// changes.
#define SHADOW_Z_SCALE 0.2 // [0.5 0.3 0.25 0.2 0.15]
#define SHADOW_SOFTNESS 1.0 // [0.0 0.1 0.25 0.5 1.0 1.5 2.0 3.0 5.0 8.0 12.0]
// SHADOW_SAMPLES: derived from SHADOW_QUALITY (quality block at the top of this file)
#define PCSS
// PCSS penumbra growth (smaller = shadows stay sharp longer, spread more slowly).
// Visual sun disc size is SUN_SIZE, unrelated. User: 'less aggressive'.
#define LIGHT_SIZE 0.25 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]

// ---- Foliage/entity shadows: two independent fixes, each with a fallback ----
// (a) CASTER (shadow.fsh): the shadow-pass discard tests the TEXTURE alpha only.
//     When gl_Color.a arrives near 0 for entities/the player (vertex format or overlay in
//     the Iris shadow pass), a (tex.a * glcolor.a < 0.1) test erases their entire geometry
//     from the shadow map and they cast nothing. 0 = old combined test.
#define SHADOW_CUTOUT_FIX 1 // [0 1]
// (b) RECEIVER (lighting.glsl + composite1): when Iris writes foliage/entities into
//     shadowtex0 ONLY (tex1 excludes the translucent phase), an s1 gate makes them nearly
//     invisible (light tint instead of occlusion). The 3-state tag therefore lives in RGB
//     BANDS of shadowcolor0 with alpha forced to 1.0, so the write SURVIVES the Iris shadow
//     pass alpha blend (an alpha-encoded tag is destroyed even with blend.shadow=off).
//     Bands (encoded in shadow.fsh; decoded in lighting.glsl, composite1 x2, composite RSM,
//     final debug views): WATER rgb*0.30 [0..0.30], GLASS/PORTAL rgb*0.30+0.35, SOLID
//     rgb*0.30+0.70. The WHITE clear of shadowcolor0 lands in the SOLID band (fail-safe:
//     full occlusion even if the color write fails). 0 = old alpha encoding.
#define SHADOW_TEX1_GATE_FIX 1 // [0 1]

// ============ AMBIENT OCCLUSION (SSAO) ============
#define AO
#define AO_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.25 1.5 2.0 3.0 5.0 8.0]
#define AO_RADIUS 0.75 // [0.1 0.25 0.5 0.75 1.0 1.5 2.0 4.0 8.0]
// AO_SAMPLES: derived from SHADOW_QUALITY
// AO_QUALITY 1 (default) = modern estimator: cosine-weighted hemisphere
// (SAO/Alchemy - only occluders actually SEEN by the surface count), STRICT 3D
// range (no halo from distant occluders), 3x3 bilateral denoise (composite1),
// and SUN-AWARE application (AO occludes ambient, so it fades out in direct
// sunlight instead of dirtying it). 0 = legacy SSAO.
#define AO_QUALITY 1 // [0 1]

// GI_HALF_RES 1 (default) = SSGI/RTGI/RSM/SS lights/SSAO are computed at HALF
// resolution: composite.fsh shades only the lower-left quadrant of colortex4/6
// (1 quadrant texel = 1 full-res pixel at uv*2, ~4x fewer shaded pixels; the
// gathers keep the same radii/sample counts and still read the FULL-res
// gbuffers). The temporal history follows the same quadrant. Readers
// (composite1) re-expand with a 4-tap depth+normal bilateral upsample, so
// silhouettes and corners stay crisp. 0 = legacy full-res path, bit-identical.
#define GI_HALF_RES 1 // [0 1]

// ============ SSGI - ONE SUN BOUNCE (screen space) ============
// ONLY sunlight bounces: sunlit surfaces illuminate their neighbours (color
// bleeding, filled-in shadows). Block lights stay STRICTLY vanilla - emissive
// pixels are ignored and the torch share is subtracted at the source. It fades
// out naturally in caves (no sun to bounce). RSM_GI below is the off-screen
// counterpart.
#define SSGI
#define SSGI_STRENGTH 1.0 // [0.25 0.5 0.75 1.0 1.25 1.5 2.0 3.0 4.0]
#define SSGI_RADIUS 12.0 // [4.0 6.0 8.0 12.0 16.0 24.0 32.0 48.0]
#define SSGI_SAMPLES 8 // [4 6 8 12 16 24 32 48 64]
#define SSGI_ACCUM 0.92 // [0.0 0.5 0.70 0.80 0.85 0.90 0.92 0.95 0.97 0.99]

// ============ REAL-TIME GLOBAL ILLUMINATION (RTGI, legacy mode) ============
//#define RTGI
#define RTGI_STRENGTH 1.5 // [0.0 0.5 0.75 1.0 1.25 1.5 2.0 3.0 4.0 6.0 10.0 20.0 50.0]
#define RTGI_RADIUS 8.0 // [2.0 4.0 6.0 8.0 12.0 16.0 24.0 32.0 64.0 128.0]
#define RTGI_ACCUM 0.92 // [0.0 0.5 0.70 0.80 0.85 0.90 0.92 0.95 0.97 0.99]
#define RTGI_BOUNCE_AMBIENT 0.35 // [0.0 0.2 0.3 0.35 0.45 0.6 0.8 1.0 1.5 2.0 3.0 5.0]
//#define RSM_GI
#define RSM_STRENGTH 1.0 // [0.0 0.5 0.75 1.0 1.5 2.0 3.0 4.0 6.0 10.0 20.0 50.0]
#define RSM_RADIUS 10.0 // [2.0 4.0 6.0 8.0 10.0 14.0 20.0 32.0 64.0 128.0]
#define RSM_SAMPLES 12 // [4 8 12 16 24 32 48 64 128 256]

// ============ REAL LIGHTS (emissive sources - legacy mode) ============
//#define SS_LIGHTS
#define SS_LIGHT_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 10.0 20.0 50.0]
#define SS_LIGHT_RADIUS 16.0 // [4.0 8.0 12.0 16.0 24.0 32.0 48.0 64.0 128.0]
#define GI_SAMPLES 8 // [2 4 8 12 16 24 32 64 128]
#define EMISSIVE_BOOST 8.0 // [0.0 1.0 2.0 4.0 6.0 8.0 10.0 12.0 16.0 24.0 32.0 48.0 64.0 100.0]
#define LAVA_GLOW 1.0 // [0.0 0.5 1.0 1.5 2.0 3.0 5.0 8.0 12.0 20.0]
#define LAVA_ANIMATE
#define LAVA_FLOW_SPEED 0.06 // [0.0 0.03 0.06 0.1 0.2 0.4]
#define EMISSIVE_FLICKER
#define VANILLA_BLOCKLIGHT
#define VANILLA_TORCH 1.0 // [0.0 0.1 0.25 0.5 0.75 1.0 1.25 1.5 2.0 3.0 5.0 8.0]
#define HELD_LIGHT_STRENGTH 1.0 // [0.0 0.5 1.0 1.5 2.0 3.0 5.0 8.0 12.0]

// ---- PORTALS. Nether = parallax energy core, rendered in gbuffers_water because the
// nether_portal block is TRANSLUCENT and never reaches gbuffers_terrain, plus a "magic
// glass" background distortion in composite1 (flag colortex2.b = 0.85).
// End = parallax star well (block entity -> gbuffers_block fallback -> gbuffers_terrain,
// identified by uniform blockEntityId == 25).
// PORTAL_FX 0 = original rendering; PORTAL_GLOW = HDR intensity (feeds bloom).
#define PORTAL_FX 1 // [0 1]
#define PORTAL_GLOW 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0]

// ---- GLOWING RESOURCE BLOCKS (boolean toggles, OFF by default) ----
// The redstone torch (block family 26) ALWAYS emits red - no toggle. These toggles make
// SOLID resource blocks emit. Commented out = OFF = normal albedo. They are plain booleans:
// they appear as ON/OFF in screen.RTX_EMISSIVE, never in sliders=.
//#define REDSTONE_BLOCK_GLOW   // redstone block -> red
//#define EMERALD_BLOCK_GLOW    // emerald block -> green
//#define DIAMOND_BLOCK_GLOW    // diamond block -> cyan
// ---- Additional emissive resource blocks (families 31..38, OFF by default) ----
// Same rules: commented out = OFF = normal albedo. ON/OFF buttons in screen.RTX_EMISSIVE.
//#define GOLD_BLOCK_GLOW       // gold block -> warm gold
//#define IRON_BLOCK_GLOW       // iron block -> neutral white
//#define NETHERITE_BLOCK_GLOW  // netherite block -> dark purple
//#define AMETHYST_BLOCK_GLOW   // amethyst block (solid) -> purple
//#define COPPER_BLOCK_GLOW     // copper block (+ variants/waxed) -> copper orange
//#define RAW_IRON_BLOCK_GLOW   // raw iron block -> dull neutral
//#define RAW_GOLD_BLOCK_GLOW   // raw gold block -> dull gold
//#define RAW_COPPER_BLOCK_GLOW // raw copper block -> dull orange

#define SUN_INTENSITY 1.5 // [0.0 0.25 0.5 0.75 1.0 1.25 1.5 2.0 3.0 5.0 8.0 12.0 20.0]
#define MOON_INTENSITY 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0 12.0 20.0]
#define AMBIENT_INTENSITY 0.75 // [0.0 0.25 0.5 0.75 1.0 1.25 1.5 2.0 3.0 5.0 8.0]
#define SUN_TINT_TEMP 1.0 // [0.4 0.6 0.8 0.9 1.0 1.1 1.25 1.5 2.0 3.0]
// ---- CONFIG_LIGHT appearance dials (lib/lighting.glsl). Defaults = exact current render.
// Per-channel multipliers on the block-light tint (getTorchColor).
#define TORCH_R 1.0 // [0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4]
#define TORCH_G 1.0 // [0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4]
#define TORCH_B 1.0 // [0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4]
// DAY ambient temperature (getAmbientColor): >1 cooler (R down, B up), <1 warmer.
// Dusk/night ambients untouched.
#define AMBIENT_COOL 1.0 // [0.8 0.85 0.9 0.95 1.0 1.05 1.1 1.15 1.2]
// Saturation of the sky ambient inside SHADOWED areas (shadeSurface):
// 1.0 = full ambient tint (current look), 0.0 = neutral grey shadows.
#define SHADOW_TINT 1.0 // [0.0 0.15 0.3 0.45 0.6 0.75 0.9 1.0]

// ============ VOLUMETRIC LIGHT ============
// VL_RAIN: precipitation visible inside light shafts (rain streaks)
#define VL_RAIN
#define VOLUMETRIC_LIGHT
#define VL_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.25 1.5 2.0 3.0 5.0 8.0 12.0 20.0]
// VL_SAMPLES: derived from VOLUMETRIC_QUALITY
#define VL_BLOCKLIGHT
#define VL_BLOCK_STRENGTH 1.0 // [0.0 0.25 0.5 1.0 1.5 2.0 3.0 5.0 8.0 12.0]
// VL_HALF_RES 1 (default) = the unified volumetric march (height fog + sun
// shafts + underwater god rays) runs at HALF resolution in composite.fsh
// (same lower-left-quadrant pattern as GI_HALF_RES, lib/vl_halfres.glsl)
// with TWO endpoint integrations (wMirror 0 / wMirror 1); composite1
// recombines them with the pixel's real water-mirror weight (transmittance
// EXACT, in-scatter endpoint-lerped, mid-range error < ~2% typical) behind a
// depth-aware bilateral upsample -> the VL_SAMPLES march is paid on ~1/4 of
// the pixels (~4x cheaper). Underwater god-ray striations soften slightly
// (half-res + bilateral). 0 = original full-res inline march in composite1,
// bit-identical.
#define VL_HALF_RES 1 // [0 1]

// ============ HEIGHT FOG (cinematic) ============
#define HEIGHT_FOG
// SEALEVEL_MIST: mist sheet just above water at dawn/dusk. It produces a golden horizontal
// BAND at Y=63, so it is OFF by default. Define it to restore the old behaviour.
//#define SEALEVEL_MIST
#define HEIGHT_FOG_DENSITY 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0 12.0 20.0]
#define HEIGHT_FOG_FALLOFF 1.0 // [0.1 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]

// ---- Mid-field atmospheric fog + biome tint + dusk boosts ----
// ATMO_FOG: progressive Beer-Lambert layer starting around 60 blocks (the vanilla layer
// only kicks in at the very end of the far plane). Boolean toggle (VOLUMETRICS menu).
#define ATMO_FOG
#define ATMO_FOG_DENSITY 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]
// Dusk mist boost. 1.0 is the anti-wash default: four luminance boosts stack at
// sunset, so the defaults are deliberately staggered.
#define ATMO_FOG_DUSK_BOOST 1.0 // [0.0 0.5 1.0 1.5 2.0 3.0 4.0 6.0]
// FOG_BIOME_TINT: volumetric mist takes the biome tint (greenish swamp, etc). OFF by default.
//#define FOG_BIOME_TINT
#define FOG_BIOME_TINT_STRENGTH 0.6 // [0.0 0.25 0.4 0.6 0.8 1.0]
// Dusk boost of the VL phase function (more directional shafts; NaN clamped in code).
#define VL_DUSK_BOOST 1.0 // [0.0 0.5 1.0 1.5 2.0 3.0]
// Dusk boost of the screen-space godrays. 0.5 is the anti-wash default.
#define GODRAY_DUSK_BOOST 0.5 // [0.0 0.5 1.0 1.5 2.0 3.0]

// ============ WATER ============
#define WATER_WAVES
#define WAVE_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.25 1.5 2.0 3.0 5.0 8.0 12.0]
#define WAVE_SPEED 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0 12.0]
// WAVES_V2: coherent directional spectrum (lib/water.glsl) - one dominant
// ANALYTIC Gerstner-lite SWELL (lambda ~26 blocks, fixed wind direction,
// trochoidal profile with tight crests and wide troughs, wave groups) + a
// medium ANISOTROPIC CHOP in wind space (crests elongated perpendicular to the
// wind, 2 trains drifting downwind) + micro capillaries (WATER_MICRONORMAL).
// The final normal is still the SUM, so ripples/foam/glint/whitecaps keep
// working and whitecaps ride the swell crests. Calibrated for
// WATER_NORMAL_STRENGTH 0.75-1.5. 0 = the original "Seascape" sea.
#define WAVES_V2 1 // [0 1]
// Number of swell TRAINS: the first train is full strength, each following one
// heads in another direction (~58 deg plus variation), shorter, weaker (x0.55)
// and faster, giving a rich but readable cross sea. Fronts are NOT parallel
// (domain warp ~9 blocks). The analytic caustics (causticFieldH, lib/water.glsl)
// derive from the SAME trains, so they follow the waves.
// WAVE_ITERATIONS: derived from WATER_QUALITY
// WAVE_NORMALS_V3 1 = "two smooth layers" water normals (SEUS PTGI style): two
// soft noise sheets drifting downwind with ROUND lobes and no choppy profile,
// giving coherent reflections and a smooth surface.
// 0 (default) = the original SEASCAPE generator: two counter-drifting fields
// whose interference keeps transforming (crests are born and dissolve) instead
// of a sheet that merely slides. Displacement, whitecaps and CAUSTICS are the
// same either way.
#define WAVE_NORMALS_V3 0 // [0 1]
// Fast water normals (Seascape v2 path, i.e. WAVES_V2=1 + WAVE_NORMALS_V3=0):
// the wind-space transform is hoisted out of the 3 finite-difference chop
// evaluations, and the octave LOD tiers are tightened to the measured
// sub-pixel distances at 1080p (see waveNormalWorldFast, lib/water.glsl).
// 0 = original per-call transform and the legacy 25/142-block tiers.
#define WAVE_FAST_NORMALS 1 // [0 1]
// Dominant swell amplitude (crest ~+0.6 block at 1.0). 0.0 disables the swell
// and leaves only the anisotropic chop.
#define SWELL_AMOUNT 0.75 // [0.0 0.5 0.75 1.0 1.5 2.0]
// Wind direction in degrees (swell AND chop are aligned; 0 = east, 90 = south).
#define WIND_DIRECTION 25.0 // [0.0 25.0 45.0 70.0 90.0 115.0 135.0 160.0 180.0 205.0 225.0 250.0 270.0 295.0 315.0 340.0]
#define WATER_DISPLACEMENT
#define SSR_ENABLED
// SSR fast march: clip(p) is AFFINE in p, so each march step and each binary
// refinement midpoint reuses incremental clip-space values instead of a full
// mat4 multiply (same step count, growth and hit validation; result identical
// up to float rounding). 0 = original per-step projection.
#define SSR_FAST 1 // [0 1]
#define WATER_REFRACTION
#define REFRACTION_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]
#define WATER_CAUSTICS
#define CAUSTIC_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0 12.0]
#define CAUSTIC_SCALE 1.0 // [0.1 0.25 0.5 0.75 1.0 1.5 2.0 4.0 8.0]
// Focusing of the PHYSICAL caustics: multiplies the paraxial focal length
// cf = 0.25 * depth (convergence of rays refracted by the REAL wave field).
// Higher = sharper, more contrasted filaments focusing at a shallower depth;
// the focal depth stays EMERGENT, nothing is stamped on.
#define CAUSTIC_FOCUS 1.0 // [0.25 0.5 0.75 1.0 1.5 2.0 3.0]
// NOTE: CAUSTIC_SCALE above is INERT - caustic scale IS the wave scale (the
// pattern is stenciled from the real field). Removed from the menus, the define
// is kept only for .txt profile compatibility.
#define CAUSTIC_SPEED 1.0 // [0.0 0.5 1.0 1.5 2.0 3.0 5.0 8.0]
// Depth at which caustics start defocusing. Keep it low: past ~6 blocks the
// water is opaque enough to hide the bottom, so the blur would be invisible.
#define CAUSTIC_DEPTH_BLUR 3.0 // [1.0 2.0 3.0 4.0 6.0 8.0 12.0 16.0 24.0]
#define CAUSTIC_LARGE_SCALE 0.28 // [0.1 0.15 0.2 0.28 0.4 0.5 0.75 1.0]
#define CAUSTIC_LARGE_STRENGTH 0.6 // [0.0 0.25 0.4 0.6 0.8 1.0 1.5 2.0 3.0]
// All foam is OFF by default - re-enable from the Water menu.
//#define WATER_FOAM
//#define WHITECAPS
//#define WATER_RIPPLES
// RIPPLES - (a) water entry/exit impulse: ONE expanding, damped ring driven by two custom
// Iris smooth() uniforms (ids 41/42, shaders.properties); (b) a discreet Kelvin-V swim wake
// behind the motion (speed from previousCameraPosition/frameTime); (c) rain impact rings
// under open sky. All of it is NORMAL DEFORMATION - no painted circles.
// Exposed in the WATER menu: dive/surface ring, wake + lapping (including at rest), rain
// impacts. 0.0 mutes a component and falls back to waves alone. Ripple slopes also follow
// WATER_NORMAL_STRENGTH so they stay consistent with the swell.
#define RIPPLE_WAKE_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0]
#define RIPPLE_SPLASH_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0]
#define RIPPLE_RAIN_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0]
// Camera-biome gate on rain effects (rings + wet ground): Iris >= 1.6.1 provides the
// built-in uniform int biome_precipitation (0 none, 1 rain, 2 snow). 1 = no rain rings
// or wet gloss in deserts / snowy biomes; 0 = legacy behavior (fallback if the uniform
// is unavailable and reads 0). Not in the menu.
#define RIPPLE_BIOME_GATE 1 // [0 1]
// PLAYER-CENTERED BOAT WAKE: Kelvin V anchored on eyePosition (player model head, camera
// fallback when the uniform stays 0), oriented along the SMOOTHED heading (smooth uniforms
// 55/56 on cameraPosition, half-life 0.5 s; per-frame velocity fallback), 13-18 blocks of
// trail: diverging arms at ~19.5 deg + TRANSVERSE waves inside the V + bow bulge (normals,
// gbuffers_water) AND white foam painted into the whitecap channel (composite1: arms,
// turbulence behind the hull, bow; analytic masks laced with foamPattern).
// Boat gate: water plane -0.6..2.15 blocks below the eye (seated tolerance) and speed
// > ~1.5 b/s - NOT isEyeInWater, which is false in a boat. At-rest lapping is cut while
// moving; entry/exit rings stay silent during the isEyeInWater flicker of surface swimming.
// With no GPU history a turn folds the template (no persistent curved trail; the smoothed
// heading softens the fold). 0 = camera-centered legacy behaviour (anchors 43-48).
#define RIPPLES_V5 1 // [0 1]
#define WATER_REFLECTIVITY 1.5 // [0.0 0.25 0.5 0.65 0.8 1.0 1.3 1.5 2.0 3.0]
// Live water-look dials (added after remote screenshot tuning proved hopeless:
// the user dials these in-game). BRIGHT scales the veil luminance, BLUE slides
// the slate hue toward gray, PRESENCE restores near-field surface visibility.
#define WATER_FOG_BRIGHT 0.75 // [0.25 0.5 0.75 1.0 1.5 2.0]
#define WATER_FOG_BLUE 0.85 // [0.25 0.5 0.75 0.85 1.0 1.25]
#define WATER_SURFACE_PRESENCE 1.0 // [0.0 0.5 1.0 1.5 2.0]
// Sun glint = SINGLE tight GGX lobe (alpha 0.006 near -> 0.016 far, fresnel
// folded in, HDR-clamped): pin-point sparkles carried by the wave normals,
// no wide Blinn blob and no painted sun trail (both removed).
#define WATER_SUN_GLINT 1.0 // [0.0 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0 12.0]
// WATER_GLINT_SHADOW: the water's SUN SPECULAR (GGX glint +
// WATER_SPARKLE) is masked by shadow VISIBILITY at the surface, so water in the
// shade of a cliff or building shows no sun reflection (same for the moon at
// night - shadowLightPosition follows). One shadowtex1 tap (shadowVis1, same
// infrastructure as composite1 caustics/AO); opaque only, so water never
// self-shadows; outside the shadow map it returns 1.0 (fail-safe: glint intact
// beyond range). Affects NEITHER the sky reflection NOR the SSR.
// 0 = legacy behaviour.
#define WATER_GLINT_SHADOW 1 // [0 1]
//#define WATER_SPARKLE
#define WATER_SPARKLE_AMOUNT 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]
//#define WATER_MICRONORMAL
#define WATER_SKY_REFLECT
// WATER_CLOUD_REFLECT: the sky reflection samples the REAL sky pixels on screen (colortex0:
// atmosphere + VOLUMETRIC CLOUDS, already painted by deferred) whenever the reflected
// direction lands on screen, so the ocean actually reflects cumulus.
// Off-screen or below the horizon it falls back to getSkyAll (analytic gradient).
// Note that getSkyAll contains NO volumetric clouds (getClouds only exists under CLOUDS_2D,
// which is off), which is why the analytic fallback reflects an empty gradient.
#define WATER_CLOUD_REFLECT
#define WATER_NORMAL_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]
// ANTI-MARBLING: fraction of the wave normal kept for the SKY reflection only (screen-space
// skyReflect + analytic). With the full normal, the sampled screen UV jumps pixel to pixel
// between "white volumetric cloud" and "cloudless analytic blue" (getSkyAll), producing a
// blue-white marbled net across the whole water plane. Fresnel, sun glint and geometry SSR
// keep the FULL normal. 1.0 = no flattening (legacy).
// 0.5 (was 0.35): more wave life in the sky mirror -- reference-style cloud
// patches, distorted by the swell yet sharp.
#define WATER_SKY_DISTORT 0.5 // [0.0 0.15 0.25 0.35 0.5 0.75 1.0]
// EDGE FOAM (composite1): organic shoreline band - VERTICAL column depth (the band hugs
// the shore from any view angle), spatially phased ebb and flow (each stretch of coast
// breathes at its own rhythm), holed multi-octave lace, contact fringe, scattered micro
// bubbles. FOAM_AMOUNT 0.0 mutes it.
#define FOAM_AMOUNT 1.0 // [0.0 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]
#define WHITECAP_NEAR_FADE 14.0 // [6.0 10.0 14.0 20.0 30.0 50.0]
#define WATER_FALL_SPEED 3.5 // [1.0 2.0 3.5 5.0 8.0 12.0]
#define WATER_FALL_RELIEF 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0]
// Fresnel reflectivity floor on VERTICAL water (waterfalls/walls). On a vertical face the
// base Fresnel term collapses and the water looks dull; this floor brings the sky
// reflection back. 0.0 = legacy, 0.25 = bright water wall. Not exposed in the menu.
#define WATER_FALL_REFLECT_FLOOR 0.25 // [0.0 0.1 0.25 0.4 0.6]
#define WATER_ROUGH_REFLECT
// 0.05 (was 0.08): the reference water is a near-mirror -- cloud/sky patches
// stay soft-edged through the waves but SHARP, not smeared by distance blur.
#define WATER_ROUGHNESS 0.05 // [0.0 0.05 0.08 0.10 0.15 0.20 0.30 0.50]
// REFLECT_DESAT: desaturates the FINAL water reflection (SSR + sky + horizon floor
// combined) by mixing toward its luma, just before composition. A very saturated sky
// otherwise gives "candy blue" water; this pulls it toward a more photographic silver
// mirror. Applied by MULTIPLICATION inside the mix (no #if on a float).
// 0.0 = legacy behaviour.
#define REFLECT_DESAT 0.40 // [0.0 0.05 0.10 0.15 0.20 0.25 0.30 0.35 0.40 0.50]
// WATER_HORIZON_SKY: fixes water turning BLACK at grazing angles / toward the horizon.
// At grazing distance the SSR hits dark shadowed terrain (or near-black absorbed water)
// instead of reflecting the sky. This fix (a) lowers SSR confidence with distance so far
// water reflects the clean analytic SKY rather than a dark screen smear, and (b) applies a
// sky FLOOR to both the reflection and the base color so distant water can never be black.
// Near glossy reflections are preserved. Undefine for the original unclamped behaviour.
#define WATER_HORIZON_SKY
// Distance (blocks) at which water switches to a pure sky reflection.
// LOWER = the sky takes over earlier (less black, but shorter near-field SSR).
#define WATER_HORIZON_DIST 96.0 // [16.0 24.0 32.0 48.0 64.0 96.0 128.0 256.0]
// Strength of the sky floor (fraction of sky reflection forced in at the horizon).
// 1.0 = the farthest/most grazing water is ~100% sky. 0.0 disables the floor (SSR/base can
// still go black).
#define WATER_HORIZON_SKY_STRENGTH 1.0 // [0.0 0.25 0.5 0.65 0.75 0.85 1.0]
// MID-DISTANCE BLACK WATER (a near-black band around 40-120 blocks on a daylit ocean while
// near water looks fine). At medium grazing angles the SSR hits DARK distant terrain with a
// still-high hit confidence, so the sky floor (weighted by 1-hit) stays inactive and the
// dark reflection wins. Physically, choppy water seen from afar reflects mostly SKY
// (micro-facets), so the GEOMETRY reflection is faded toward the sky with distance
// (progressive mix from WATER_DSKY_NEAR, full at WATER_DSKY_FAR - deliberately not a
// full-sky max() that would wash out near reflections), and only when it is darker than the
// sky (a bright reflection - sunlit wall, sail - stays intact at range).
// Undefine for legacy behaviour. Not exposed in the menu.
#define WATER_DIST_SKY_MIX
// Window 48..160 with strength 0.65: a tighter/stronger window eats legitimate geometry
// reflections (mountains, trees) from 40-80 blocks out.
#define WATER_DSKY_NEAR 48.0 // [24.0 32.0 40.0 48.0 64.0 96.0]
#define WATER_DSKY_FAR 160.0 // [80.0 100.0 120.0 140.0 160.0 180.0 240.0]
#define WATER_DSKY_STRENGTH 0.65 // [0.0 0.25 0.5 0.65 0.75 0.85 1.0]
//#define UW_BIOME_TINT
// (off by default: no biome tint underwater)
#define UW_BIOME_TINT_STRENGTH 0.6 // [0.0 0.25 0.5 0.6 0.75 1.0 1.5]
#define UW_DENSITY_BOOST 1.0 // [0.5 0.75 1.0 1.25 1.5 2.0 3.0]
#define UW_FOG_DEPTH_TINT 1.0 // [0.0 0.5 1.0 1.5 2.0]
#define WATER_CLARITY 1.5 // [0.1 0.25 0.5 0.75 1.0 1.5 2.0 3.0 4.0 6.0 10.0 20.0 50.0]
// Higher = clearer column (the DEPTH_DENSITY/CLARITY ratio scales the in-water
// path length that feeds BOTH the absorption and the path veil in composite1).
#define WATER_FOG_DENSITY 1.0 // [0.0 0.1 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]
// Reference water column (calibrated defaults, not exposed in the menu):
// TINT_DESAT now only desaturates the SURFACE albedo (gbuffers_water/dh_water);
// the column itself uses a fixed slate palette. SCATTER_DARKEN scales the slate
// in-scatter, DEPTH_DENSITY densifies the path, REFLECT_FLOOR is the
// normal-incidence reflection floor modulated by sky light (0.0 = legacy).
#define WATER_TINT_DESAT 0.7 // [0.0 0.2 0.3 0.4 0.55 0.65 0.7 1.0]
#define WATER_SCATTER_DARKEN 0.80 // [0.5 0.65 0.8 0.9 1.0]
#define WATER_DEPTH_DENSITY 1.5 // [0.5 0.75 1.0 1.25 1.5 1.75 2.0 3.0]
#define WATER_REFLECT_FLOOR 0.06 // [0.0 0.04 0.06 0.08 0.12 0.2]
// UW_VOLUMETRICS: underwater volumetric fog + caustic god-rays.
// Depth-graded density with shafts modulated by the caustics. WATER_FOG_DENSITY is the
// density slider.
#define UW_VOLUMETRICS
#define UW_GODRAY_STRENGTH 2.0 // [0.0 0.5 1.0 1.5 2.0 3.0 5.0]
// Shaft geometry. FINESSE: higher = THINNER and RARER rays (raised aperture thresholds).
// SCALE: higher = WIDER pattern = more SPACE between blades (spectral sigma).
// Tune FINESSE first, then SCALE.
#define UW_SHAFT_FINESSE 1.3 // [0.6 0.8 1.0 1.3 1.6 2.0 2.6]
#define UW_SHAFT_SCALE 1.0 // [0.8 1.0 1.25 1.5 1.8]
// Eye-distance render limit (blocks) for the god-ray term ONLY: shafts fade out between
// 0.7x and 1.0x this distance; the UW fog, ambient and darkness continue beyond it.
#define UW_SHAFT_RENDER_DIST 24.0 // [8.0 16.0 24.0 32.0 48.0 64.0 96.0]
// Underwater god-ray directionality. 0.0 = vertical columns stamped in xz, 1.0 = shafts
// fully aligned with the sun/moon axis (they move with the cycle). Not in the menu.
#define UW_GODRAY_DIRECTIONAL 0.8 // [0.0 0.25 0.5 0.8 1.0]
// Frequency/tilt of the light blades along the sun axis. Keep <=0.5: rel = wp -
// cameraPosition can get large and the sine aliases beyond that. Not in the menu.
#define UW_GODRAY_TILT 0.35 // [0.15 0.25 0.35 0.5 0.75 1.0]
// 1 = the shaft pattern IS the caustic projected PER MARCH STEP (physically shafts are
// caustic apertures: columns parallel to the sun/moon axis that dance with the waves and
// follow the light). 0 = legacy camera-relative sine blades (read as vertical and static).
// Not in the menu.
#define UW_GODRAY_CAUSTIC_LOCK 1 // [0 1]
// Anti-starburst (a): 1 = the caustic god-ray term only applies to the march segment that
// is ACTUALLY submerged (wp.y below the surface). Otherwise the march (depthtex1 = opaque)
// crosses the surface and steps ABOVE the water receive sharp caustics (toSurf=0 ->
// beerR=1, shrp=1), producing a frozen radial starburst around the sun seen from below.
// 0 = legacy. Not in the menu.
#define UW_SURFACE_CLAMP 1 // [0 1]
// Anti-starburst (b): 1 = when STARING at the light source underwater (~<17 deg off axis),
// the caustic modulation of the shafts tends toward its mean, giving a smooth halo around
// the disc instead of hard radial rays; tilted columns off axis are untouched.
// 0 = legacy. Not in the menu.
#define UW_SUNGAZE_SOFT 1 // [0 1]
// Anti-starburst (c): 1 = lens flare CUT underwater (there is no lens flare below the
// surface; refraction and the Snell window do that job). 0 = legacy. Not in the menu.
#define UW_FLARE_CUT 1 // [0 1]
// Caustic treatment with view distance. With CAUSTIC_BLUR_FADE=1 this factor doses the
// distance BLUR (40..110 blocks from above, 20..56 underwater) plus a slight hold-back
// (x0.75 far away). With CAUSTIC_BLUR_FADE=0 it is the legacy ALPHA fade 48..120 (28..64
// underwater). 0.0 = no treatment. Not in the menu.
#define CAUSTIC_DIST_FADE 1.0 // [0.0 0.5 1.0]
// "Fade to blur" caustic policy: 1 = distance SOFTENS the web (waveCausticSoft) instead of
// extinguishing it, with lowered thresholds (-0.30 -> -0.22 surface site, 0.25 -> 0.20
// chroma sites), depth extinction pushed back ~3-4 blocks (exp(-0.22*d) -> exp(-0.13*d)),
// a tighter shallow fade (0.05..0.55 block) and cap 0.32 -> 0.38.
// 0 = previous policy. Not in the menu.
#define CAUSTIC_BLUR_FADE 1 // [0 1]
// Caustic fade in VERY shallow water (bottom seen through the surface): the light has not
// focused yet (ripple focal distance ~1 block), so below 0.10 block of column there is
// nothing and full strength is reached at ~1.1 block. This stops shallow sand from
// saturating to white. 1.0 = full fade, 0.0 = no fade. Not in the menu.
#define CAUSTIC_SHALLOW_FADE 1.0 // [0.0 0.5 1.0]
#define UNDERWATER_FX
//#define UW_VIGNETTE
#define UW_PARTICLES
#define WATER_LEVEL 63.0 // [-200.0 -150.0 -100.0 -64.0 -32.0 -16.0 0.0 16.0 32.0 48.0 63.0 96.0 128.0 160.0 200.0]
// PER-PIXEL water detection (fixes cyan patches in dry ravines below Y63):
// 1 = water effects seen from outside the water measure REAL water (shadow map water RGB
// tag + delta-z, colortex2 screen probes) instead of assuming "below Y63 = underwater".
// 0 = legacy behaviour. With the fix on, WATER_LEVEL only serves as an altitude reference
// for the mists (ATMO/CAVE/HEIGHT_FOG, SEALEVEL_MIST) and for eye-submerged heuristics.
// Kept an int so it can be used in #if (WATER_LEVEL is a float and cannot).
#define PIXEL_WATER_FIX 1 // [0 1]
// UW_RAY_DISTANCE: derived from VOLUMETRIC_QUALITY

// ============ GLASS ============
#define GLASS_EFFECTS
// Glass refraction/distortion OFF by default (user request) -- WATER refraction
// (REFRACTION_STRENGTH) is untouched. Turn back on from the glass screen.
#define GLASS_REFRACTION 0.0 // [0.0 0.25 0.5 1.0 1.5 2.0 3.0 5.0 8.0]
#define GLASS_DISTORTION 0.0 // [0.0 0.5 1.0 2.0 3.0 5.0 8.0]
#define GLASS_ROUGH_REFLECT

// ============ PLANET ============
#define PLANET_RADIUS 9000.0 // [1000.0 3000.0 5000.0 9000.0 15000.0 30000.0 100000.0 1000000.0 10000000.0]
//#define CLOUD_CURVATURE

// ============ CLOUDS ============
#define VOLUMETRIC_CLOUDS
// VC_SAMPLES: derived from CLOUD_QUALITY
// VC_COVERAGE: fraction of the sky covered. 0.70 = heavily clouded,
// 1.00 = overcast, 0.20 = a few scattered clouds.
// At 0.40 the cumulus are SEPARATE masses with blue sky between them; higher
// values merge them into continuous sheets.
#define VC_COVERAGE 0.40 // [0.0 0.05 0.10 0.20 0.30 0.40 0.50 0.60 0.70 0.80 0.90 0.95 1.00]
// VC_OPACITY: opacity of the cloud material. 1.0 = semi-transparent (light),
// 3.0 = solid clouds, 8.0 = fully opaque (stormy).
#define VC_OPACITY 2.0 // [0.1 0.5 1.0 1.5 2.0 3.0 5.0 8.0 12.0 20.0 50.0]
// VC_RENDER_DISTANCE: cloud draw distance in blocks, derived from CLOUD_QUALITY (capped at 1000)
#define VC_BASE 150.0 // [64.0 120.0 140.0 150.0 160.0 192.0 256.0 384.0 512.0 1024.0]
// Thick slab (160) gives real budding towers instead of flat pancakes.
#define VC_THICK 160.0 // [20.0 60.0 90.0 120.0 160.0 256.0 384.0 512.0]
#define VC_DENSITY 1.0 // [0.0 0.1 0.3 0.5 0.75 1.0 1.25 1.5 2.0 3.0 5.0 8.0 12.0]
#define VC_WIND 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 4.0 6.0 10.0 20.0]
#define VC_GROUND_SHADOWS
#define CLOUD_SHADOW_DARKNESS 0.75 // [0.0 0.25 0.4 0.5 0.6 0.75 0.85 0.95 1.0]
#define CLOUD_SHADOW_SOFTNESS 1.0 // [0.0 0.5 1.0 1.5 2.0 3.0]
// Perf: cloud self-shadowing in 3 steps instead of 4 (cheaper, slightly softer).
//#define CLOUD_FAST_SHADOW
// Silver lining: cloud edges flaring toward the sun (forward scatter).
//#define CLOUD_SILVER_LINING
// CLOUD_EDGE_FADE: soft cloud fade at the render distance, removing the visible dome/arc
// where the march stops abruptly. Recommended ON; undefine for the original behaviour.
#define CLOUD_EDGE_FADE
#define CLOUD_BRIGHTNESS 1.0 // [0.0 0.25 0.5 0.75 1.0 1.25 1.5 2.0 3.0 5.0 8.0]
// ---- CONFIG_CLOUDS appearance dials: cumulus/alto SHADING only (lib/clouds.glsl).
// Density fields and masks are untouched - cloudShadow (lib/lighting.glsl)
// mirrors the cumulus mask and must keep matching. Defaults = exact current render.
// Brightness of the sunlit cumulus tops (scales the top ambient term).
#define CLOUD_WHITE 1.0 // [0.8 0.85 0.9 0.95 1.0 1.05 1.1 1.15 1.2]
// Brightness of the shaded cumulus bellies.
#define CLOUD_BELLY_BRIGHT 1.0 // [0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4]
// Blue bias of the belly shade: >1 cooler/bluer, <1 warmer/greyer.
#define CLOUD_BELLY_COOL 1.0 // [0.7 0.8 0.9 1.0 1.1 1.2 1.3]
// Silver-lining strength (sunward edge flare); stacks with VC_CUMULUS_SILVER.
#define CLOUD_SILVER 1.0 // [0.0 0.25 0.5 0.75 1.0 1.25 1.5 2.0]
// Brightness of the altocumulus layer (layer 2, volumetric and 2D variants).
#define CLOUD_ALTO_BRIGHT 1.0 // [0.7 0.8 0.9 1.0 1.1 1.2 1.3]
// ---- Cumulus shaping: layer 1 reuses the altocumulus slab recipe (sharply
// thresholded vnoise cells + low-frequency banks) at cumulus scale: cells ~2.5x
// the alto ones (masses ~100-250 blocks, separated by 60-150 blocks of blue
// sky), flat base, bulging domed tops.
// VC_CUMULUS_SHAPES=1 -> this field; 0 = the original raymarch.
#define VC_CUMULUS_SHAPES 1 // [0 1]
// Horizontal cell scale (larger = wider, more spaced cumulus).
#define VC_CUMULUS_SCALE 1.5 // [0.5 0.75 1.0 1.5 2.0]
// VC_TEXTURED=1: layer-1 cumulus density comes from the PRECOMPUTED textures
// (Nubis / Horizon Zero Dawn technique): a 1024^2 coverage map, two 128^3
// erosion volumes and a 64^3 curl volume, loaded as customTexture in
// shaders.properties. Per marched sample: 1 small 2D tap on clear sky, 9 under
// cloud (width-gated column height - no more pillars), plus 2-3 3D erosion
// taps and 1 refresh tap on lit samples; the procedural path evaluated ~27
// noise octaves. Ground shadows read the very same field. Only active when
// VC_CUMULUS_SHAPES=1. 0 = procedural v5 field, kept bit-identical as fallback.
#define VC_TEXTURED 1 // [0 1]
// Curl-noise swirl on the erosion lookup: wind-torn turbulent tops, calm base.
// Only used when VC_TEXTURED=1 (and VC_DETAIL=1).
#define VC_CURL 1.0 // [0.0 0.5 1.0 1.5 2.0 3.0]
// 3D erosion/detail: wispy edges + internal structure. 0.0 = OFF (first lever to pull for perf).
#define VC_CUMULUS_EROSION 1.5 // [0.0 0.5 0.75 1.0 1.25 1.5 2.0]
// Darkening of the flat cumulus underside.
#define VC_CUMULUS_BASE_DARK 0.65 // [0.0 0.25 0.4 0.5 0.65 0.8 1.0]
// Silver lining strength (edge flare toward the sun).
#define VC_CUMULUS_SILVER 1.0 // [0.0 0.5 0.75 1.0 1.5 2.0]
// ---- Cumulus detail ----
// VC_DETAIL=1: fine 4th octave on the cell silhouette (bays and capes),
// high-frequency micro erosion at the edges, internal albedo micro variation
// (wisps). 0 = smooth shapes (cheaper).
#define VC_DETAIL 1 // [0 1]
// Strength of the high-frequency edge erosion (0 = plain edges).
#define VC_DETAIL_STRENGTH 1.0 // [0.0 0.5 0.75 1.0 1.25 1.5 2.0]
// Internal albedo micro variation (wisps): 0 = uniform material.
#define VC_DETAIL_WISPS 0.5 // [0.0 0.25 0.5 0.75 1.0]
// ---- High layers ----
// CLOUD_HIGH_V3=1: cirrus as thin anisotropic filaments (stretched x13, curved)
// and altocumulus as a field of small lit puffs. 0 = the original simple layers.
#define CLOUD_HIGH_V3 1 // [0 1]
// Cirrus amount/opacity (filament banks).
#define CLOUD_CIRRUS_AMOUNT 1.0 // [0.25 0.5 0.75 1.0 1.5 2.0]
// Altocumulus amount/opacity (puff sheets).
#define CLOUD_ALTO_AMOUNT 1.0 // [0.25 0.5 0.75 1.0 1.5 2.0]
// Keep this ABOVE the cumulus tops (VC_BASE + VC_THICK) to avoid overlap.
#define CLOUD_ALTO_HEIGHT 340.0 // [120.0 220.0 280.0 340.0 420.0 600.0 1000.0 2000.0]
// VOLUMETRIC ALTOCUMULUS (second 3D layer): thin slab marched in 6 steps -
// real domed puffs instead of a flat 2D sheet.
#define ALTO_VOLUMETRIC 1 // [0 1]
#define CLOUD_CIRRUS_HEIGHT 460.0 // [200.0 380.0 460.0 560.0 700.0 1000.0 2000.0 4000.0]
#define CLOUD_LAYER_ALTO
#define CLOUD_LAYER_CIRRUS
//#define CLOUDS_2D
// ---- Blue-noise march dither ----
// BLUE_NOISE=1: the volumetric marches (cumulus, 3D alto, fog / god rays)
// jitter with a tileable 64^3 blue-noise texture, one z-slice per frame, and
// TAA averages it into smooth gradients - kills the banding terraces seen from
// above the cloud slab. Other dither users (SSR, PCF, contact shadows) are NOT
// affected. 0 = the previous static Bayer dither, bit-identical.
#define BLUE_NOISE 1 // [0 1]
// ---- Baked-noise texture ----
// NOISE_TEX=1: decorative noise fields (VL fog banks, procedural alto/cirrus
// layers, Nether/End skies, Milky Way nebulosity) read a 256^2 baked RGBA8
// texture (vlNoiseTex) instead of stacking arithmetic hash octaves: one
// bilinear tap replaces 4 hashes + 3 mixes per octave. The pattern differs
// slightly (another noise instance); water waves, caustics and every
// cloudShadow-mirrored field keep the arithmetic vnoise (sync). 0 = original
// arithmetic noise, bit-identical.
#define NOISE_TEX 1 // [0 1]
// ---- Half-res cloud pass ----
// CLOUD_HALF_RES=1 (default): the ENTIRE sky cloud chain (cirrus/2D alto
// sheet, volumetric 3D alto, VC_SAMPLES cumulus march, rainbow) is baked by
// a PREPARE pass (prepare.fsh, runs before the gbuffers - clouds only need
// the view ray, never the frame depth) into the lower-left quadrant of
// colortex15 as ONE premultiplied (rgb, coverage) pair - same quadrant
// convention as GI_HALF_RES / VL_HALF_RES, same uv -> NDC mapping as
// deferred (TAAU sub-rect included). deferred.fsh then rebuilds its exact
// layer mix() chain with a single bilinear tap + one composite: the march is
// paid on ~1/4 of the pixels -> cloud cost / ~4 on open skies. Trade-offs:
// cloud edges are reconstructed bilinearly (the sky is smooth; a small
// TAA-averaged jitter hides the 2x2 grid), and the bake also covers sky
// hidden behind terrain, so cave/indoor frames pay a small fixed cost. The
// clouds-in-front-of-terrain pass (composite1) is untouched, still full-res.
// 0 = inline evaluation in deferred.fsh, bit-identical to the legacy path.
#define CLOUD_HALF_RES 1 // [0 1]
// Derived gate shared by prepare.fsh (writer) and deferred.fsh (reader) so
// the two programs can never disagree about the buffer being live.
#if CLOUD_HALF_RES == 1 && (defined VOLUMETRIC_CLOUDS || defined CLOUD_LAYER_ALTO || defined CLOUD_LAYER_CIRRUS)
#define CLOUD_PREPARE_ACTIVE
#endif

// ============ WEATHER ============
#define RAIN_WET

// ============ BIOMES & CAVES ============
#define BIOME_ATMOSPHERE
#define BIOME_ATMO_STRENGTH 1.0 // [0.0 0.5 1.0 1.5 2.0 3.0 5.0 8.0]
// Cave fog OFF by default (user: distant dark areas were not blending into
// the fog; deep-fog fix lives in composite1). Toggle still available in menu.
//#define CAVE_FOG
#define CAVE_FOG_STRENGTH 1.0 // [0.0 0.5 1.0 1.5 2.0 3.0 5.0 8.0]

// ============ ATMOSPHERE ============
// ---- DIMENSION DETECTION FIX (deferred.fsh). The naive heuristic
// (luma(skyColor) > 0.004 || fogColor.g > fogColor.r) fails in the Overworld at night
// (skyColor ~ black) as soon as the fog turns NEUTRAL GREY or warm (rain, deep night:
// g <= r), which paints the End's PINK nebula sky over open plains.
// ON: (1) eyeBrightnessSmooth.y > 8 forces Overworld - the Nether and the End have NO
// skylight (y=0 there), so an eye receiving sky light must be in the Overworld;
// (2) neutral grey fog (g >= r) counts as Overworld (the End is purple r>g and the Nether
// orange/crimson r>g, so neither is ever caught by this test).
// 0 = legacy heuristic.
#define DIM_DETECT_FIX 1 // [0 1]
//#define PHYSICAL_SKY
// (off by default: the analytic atmosphere is lighter)
#define ATMO_INTENSITY 1.0 // [0.0 0.25 0.5 0.75 1.0 1.25 1.5 2.0 3.0 5.0 8.0]
#define RAYLEIGH_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.25 1.5 2.0 3.0 5.0 8.0]
#define MIE_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0 12.0]
#define ATMO_ALTITUDE_BOOST 1.0 // [0.0 0.5 1.0 2.0 4.0 8.0 16.0 32.0]
#define FOG_DENSITY 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 4.0 6.0 10.0 20.0]
// DISTANCE_FOG : le "mur" de brouillard vanilla en toute fin de render distance
// (fogF exponentiel de composite1, rescale a dhRenderDistance quand DH est actif).
// 0 = OFF (defaut) : seuls les brouillards VOLUMETRIQUES (ATMO_FOG, HEIGHT_FOG,
// VOLUMETRIC_LIGHT, CAVE_FOG) habillent la distance. 1 = ancien comportement EXACT.
// NB : FOG_DENSITY ne pilote QUE ce mur -> inerte quand DISTANCE_FOG=0.
#define DISTANCE_FOG 0 // [0 1]
// DH_EDGE_FADE : avec DISTANCE_FOG=0, la fin des LODs Distant Horizons couperait
// NET contre le ciel (silhouette de terrain tronquee a dhRenderDistance -> pop).
// 1 = fondu doux des ~10 derniers % de dhRenderDistance vers la couleur d'horizon
// (pixels DH uniquement, terrain vanilla et ciel intacts). 0 = coupe brute.
#define DH_EDGE_FADE 1 // [0 1]
// Perspective aérienne : in-scattering doré vers le soleil sur les reliefs lointains.
//#define AERIAL_PERSPECTIVE
//#define SQUARE_SUN
#define SUN_SIZE 0.04 // [0.005 0.01 0.02 0.03 0.04 0.06 0.08 0.10 0.2 0.5 1.0]
// ---- CONFIG_SKY appearance dials (getSkyBase, lib/sky.glsl). The analytic
// gradient is THE shared source: sky dome, reflections and fogs all inherit
// any tint set here (intended). Defaults = exact current render.
// Final per-channel multipliers on the whole gradient.
#define SKY_TINT_R 1.0 // [0.7 0.8 0.9 0.95 1.0 1.05 1.1 1.2 1.3]
#define SKY_TINT_G 1.0 // [0.7 0.8 0.9 0.95 1.0 1.05 1.1 1.2 1.3]
#define SKY_TINT_B 1.0 // [0.7 0.8 0.9 0.95 1.0 1.05 1.1 1.2 1.3]
// Horizon-band brightness relative to the zenith (scales the horizon colors, day and night).
#define SKY_HORIZON_LIFT 1.0 // [0.7 0.8 0.9 0.95 1.0 1.05 1.1 1.2 1.3]
// Night-sky luminance (scales the night zenith/horizon base colors only).
#define SKY_NIGHT_BRIGHT 1.0 // [0.5 0.65 0.8 0.9 1.0 1.15 1.3 1.6 2.0]

// DEBANDING : bruit triangulaire +-1/255 juste avant la quantification 8 bits
// (final.fsh) — les MARCHES de degrade (ciel, brouillard, flous, bloom)
// deviennent invisibles. Demande user : "AUCUN pixel visible".
#define DEBAND 1 // [0 1]

// ============ ANTI-ALIASING TEMPOREL ============
// TAA : accumulation frame-à-frame → edges lisses + GI stabilisé
#define TAA
// audit : TAA ON par defaut — le denoiser PT, le motion blur (compile DANS
// #ifdef TAA) et la stabilite des reflets en dependent ; il etait off.
// ISSUE 1 : force du jitter sous-pixel (transforme le TAA en supersampling temporel).
// Gate par MULTIPLICATION dans les vsh (jamais #if sur un float). 0.0 = pas de jitter.
#define TAA_JITTER 1.0 // [0.0 0.25 0.5 0.75 1.0]
// ISSUE 3 : rejet du fantome TAA sur les silhouettes d'entites mobiles devant le ciel.
// Selection RUNTIME sur un INT (#if sur int autorise). 0 = off, 1 = on.
#define TAA_GHOST_REJECT 1 // [0 1]
// A2 TAAU : TAA UPSCALING (experimental, defaut OFF). Le rendu 3D tourne en
// sous-resolution dans le coin BAS-GAUCHE du framebuffer (echelle lineaire
// TAAU_RENDER_SCALE) et composite4 reconstruit la pleine resolution avec le
// jitter temporel Halton. TAAU_S (lib/common.glsl) = TAAU_RENDER_SCALE quand
// actif, sinon 1.0 — toutes les multiplications se plient alors a la
// compilation (zero cout, zero difference OFF). Necessite TAA actif (gate
// "defined TAA" dans common.glsl). Slider int : #if autorise.
#define TAA_UPSCALING 0 // [0 1]
// Echelle lineaire du rendu TAAU (0.75 = ~56% des pixels shades par frame).
// Inerte tant que TAA_UPSCALING = 0.
#define TAAU_RENDER_SCALE 0.75 // [0.5 0.55 0.6 0.66 0.7 0.75 0.8 0.85 0.9]

// ============ POST-PROCESS ============
#define BLOOM
#define BLOOM_STRENGTH 1.2 // [0.0 0.25 0.5 0.75 1.0 1.2 1.5 2.0 3.0 5.0 8.0 12.0 20.0]
#define BLOOM_THRESHOLD 1.5 // [0.0 0.25 0.5 0.8 1.0 1.2 1.5 1.8 2.2 3.0 5.0 8.0]
#define EXPOSURE 0.85 // [0.1 0.25 0.4 0.6 0.7 0.8 0.85 0.9 1.0 1.1 1.2 1.35 1.5 1.75 2.0 3.0 5.0 8.0]
#define AUTO_EXPOSURE
#define SATURATION 1.05 // [0.0 0.25 0.5 0.7 0.8 0.9 1.0 1.05 1.1 1.15 1.25 1.4 1.6 2.0 3.0]
#define VIGNETTE 0.15 // [0.0 0.05 0.1 0.15 0.2 0.25 0.35 0.5 0.75 1.0]
#define TONEMAP_CONTRAST 1.0 // [0.0 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]
#define VIBRANCE 1.0 // [0.0 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]
#define WB_TEMPERATURE 0.0 // [-0.5 -0.35 -0.25 -0.15 -0.10 -0.05 0.0 0.05 0.10 0.15 0.25 0.35 0.5]
#define WB_TINT 0.0 // [-0.5 -0.35 -0.25 -0.10 -0.05 0.0 0.05 0.10 0.25 0.35 0.5]
//#define FXAA
#define PURKINJE
#define FILM_GRAIN

// ============ TEXTURES PBR (labPBR : Patrix, Vanilla PBR…) ============
#define PBR_TEXTURES
#define NORMAL_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]
#define PBR_EMISSIVE 1.0 // [0.0 0.5 1.0 1.5 2.0 3.0 5.0 8.0 12.0 20.0]
//#define PBR_REFLECTIONS
#define PBR_REFLECT_STRENGTH 1.0 // [0.0 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]
// ============ RAY TRACED REFLECTIONS (SSR complet, labPBR + repli vanilla) ============
// Le rayon marche la VRAIE geometrie de la scene. Smoothness/metalness :
// specular map labPBR si presente, sinon REPLI PAR BLOC (block.properties
// 40/41 + blocs-metal) -> fonctionne aussi en textures vanilla. Desaturation
// REFLECT_DESAT partagee avec l'eau. L'EAU N'EST PAS CONCERNEE (elle garde
// toujours son propre SSR). Pas de RT = toggle RT_REFLECTIONS OFF.
// MODE : 0 = RT pur (seule la geometrie TOUCHEE par le rayon se reflete,
// aucun repli ciel — le rendu le plus "RTX") ; 1 = combine (RT + repli ciel
// analytique quand le rayon sort de l'ecran — le plus complet visuellement).
#define RT_REFLECTIONS
// MODE 3 = PT PUR : AUCUN rayon ecran, TOUT passe par le monde voxel (+ repli
// ciel) — reflets 100% coherents (rien ne disparait aux bords d'ecran), mais
// tout ce qui est reflete est voxelise (denoiser PT_REFLECT_SOFT conseille).
// PT EN VEILLE (demande user 2026-08) : mode 1 par defaut = reflets ecran +
// ciel, la voxelisation ne tourne pas. Tout le systeme PT (modes 2/3, grille
// bloc, DDA) reste dans le code — remettre 2 ici pour le reactiver. Les
// reglages PT sont retires du MENU en attendant.
// !! REACTIVATION : remettre AUSSI clear=true (1er bool) sur les image.voxelImg*
// dans shaders.properties (passes a false par l'audit perf, PT dormant) !!
#define RT_REFLECT_MODE 1 // [0 1 2 3]
// ============ PT REFLECTIONS — reflets HORS-ECRAN (mode 2, voxel) ============
// Quand le rayon ECRAN ne touche rien (sort du champ, geometrie cachee), il
// CONTINUE dans la copie VOXEL du monde (grille clipmap ecrite par la passe
// d'ombre) -> les reflets montrent AUSSI ce qui est hors ecran / derriere la
// camera. Hit voxel : albedo x (soleil x ombre shadow-map + ambiant ciel),
// emissifs boostes. Portee/finesse : VOXEL_SCALE et VOXEL_CASCADES.
#define PT_REFLECT_STEPS 64 // [16 24 32 48 64 96 128 192 256]
// Portee des rayons hors-ecran : le fondu d'approche suit CETTE distance
// (pas de clip net — les hits proches de la limite fondent vers le repli).
// Portee en CHUNKS (1 chunk = 16 blocs) — demande user. PT_REFLECT_DISTANCE
// (blocs) est DERIVE : le code en aval n'a pas change.
#define PT_REFLECT_CHUNKS 6 // [2 4 6 8]
// audit : liste plafonnee a 8 chunks — la portee reelle = min(128 blocs grille
// bloc, couverture cascades ~96, shadowDistance) ; la plage 12..32 etait inerte.
#define PT_REFLECT_DISTANCE (float(PT_REFLECT_CHUNKS) * 16.0)
#define PT_REFLECT_WATER 1 // [0 1]
#define PT_REFLECT_STRENGTH 1.0 // [0.25 0.5 0.75 1.0 1.25 1.5 2.0]
#define PT_REFLECT_SUN 0.85 // [0.3 0.5 0.7 0.85 1.0 1.3]
#define PT_REFLECT_AMBIENT 0.45 // [0.2 0.3 0.45 0.6 0.8 1.0]
#define PT_REFLECT_EMISSIVE 2.0 // [0.0 0.5 1.0 1.5 2.0 3.0 5.0 8.0]
// PT_WATER_NORMAL : influence des VAGUES sur la direction des rayons PT de
// l'eau. 0 = normale aplatie (parfaitement stable), 1 = normale complete
// (pleine distorsion). Le DDA bloc rend les hits stables -> 0.3 ne scintille pas.
#define PT_WATER_NORMAL 0.3 // [0.0 0.15 0.3 0.5 0.75 1.0]
// PT_REFLECT_SOFT : DENOISER des reflets voxel — jitter conique du rayon par
// pixel/frame (le crenelage voxel devient un bruit fin que le TAA lisse en
// FLOU doux) + fondu des hits lointains. 0.0 = rayons nets (voxels visibles).
#define PT_REFLECT_SOFT 0.3 // [0.0 0.15 0.3 0.5 0.75 1.0]
// SSR_PREV_FRAME : reflets DANS les reflets — la couleur des hits SSR vient
// de la frame PRECEDENTE COMPLETE (sortie TAA colortex7 : reflets, brouillards
// et volumetriques deja composes) reprojetee -> l'eau reflete une eau qui
// reflete, les miroirs se repondent. 0 = frame courante sans reflets (ancien).
#define SSR_PREV_FRAME 1 // [0 1]
//#define PBR_POM
#define POM_DEPTH 0.15 // [0.01 0.05 0.10 0.15 0.25 0.35 0.50 0.75 1.0 2.0]
#define POM_SAMPLES 16 // [4 8 16 24 32 48 64 128 256]

// ============ TONEMAP ============
// AgX : tonemap filmique moderne, garde la teinte des hautes lumières. Prioritaire
// sur ACES s'il est activé. OFF par défaut — active-le pour comparer avec ACES.
//#define AGX_TONEMAP
// ACES filmic : noirs profonds, hautes lumières crémeuses, couleurs cinématiques
#define ACES_TONEMAP

// ============ EXTRAS CINÉMATIQUES ============
#define LENS_FLARE
#define LENS_FLARE_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0]
//#define AURORA
#define AURORA_BRIGHTNESS 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0 12.0]
// E5 STARS_V2 : refonte realiste du champ d'etoiles — amas & vides, magnitudes
// en loi de puissance (rares brillantes, myriade de faibles), couleurs
// stellaires subtiles, pole celeste incline, scintillement discret par etoile,
// coeur de largeur angulaire fixe (stable en TAA). 0 = ancien champ 3 couches.
// Star engine locked to v2 (user removed the selector; v1 kept as dead fallback).
#define STARS_V2 1
#define STAR_BRIGHTNESS 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0 12.0]
// [E6] Taille angulaire du coeur gaussien des etoiles (multiplicateur de la
// largeur ~1.4 px de STARS_V2). 1.0 = ancienne taille exacte ; defaut 1.2 =
// un poil plus grandes (retour user). Le halo des brillantes suit (x9 sigma2).
#define STAR_SIZE 1.2 // [0.8 0.9 1.0 1.1 1.2 1.35 1.5 1.75 2.0]
#define MILKYWAY_BRIGHTNESS 0.0 // [0.0 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0 12.0]
//#define SHOOTING_STARS
// R6 lens droplets rework (composite5): a few near-still drops that refract
// slightly + rare thin trails sliding down, quick fade. No full-screen warp.
// 0 = off, 1 = subtle (default), 2 = strong.
#define CAMERA_DROPLETS 0 // [0 1 2]
//#define DOF
#define DOF_STRENGTH 1.0 // [0.0 0.25 0.5 1.0 1.5 2.0 3.0 5.0 8.0]
#define CHROMATIC_ABERRATION
#define RAINBOW
#define GODRAYS
#define GODRAY_STRENGTH 1.0 // [0.0 0.25 0.5 1.0 1.5 2.0 3.0 5.0 8.0 12.0]
// GODRAY_SAMPLES : derive de VOLUMETRIC_QUALITY
// R5 ancre solaire (godrays ecran, composite5) : 1 = l'extraction ne retient que les
// pixels de CIEL (depth>=1) situes dans le disque circumsolaire -> les nuages/terrain/
// eau brillants LOIN du soleil ne peuvent plus semer de raies (ancre "haut-gauche"
// fantome observee alors que le soleil etait au centre). 0 = ancien comportement exact.
// HORS menu (gate technique reversible).
#define GODRAY_ANCHOR_FIX 1 // [0 1]
#define TAA_CLAMP_TONEMAP 1 // [0 1]
#define BLOOM_PHYSICAL 1 // [0 1]
// C: bloom pyramide MIP — brightpass dedie (composite2) + somme LOD 1..6 (composite5,
// colortex3 mippee). Poids normalises a 1.0 = energie constante. 0 = chaine d'origine.
#define BLOOM_MIP 1 // [0 1]
// C: half-res bloom -- composite2 (brightpass+blurH) and composite3 (blurV)
// shade only the lower-left quadrant of colortex3 (1 quadrant texel = 1
// full-res pixel at uv*2, ~4x fewer bloom pixels; outside the quadrant they
// write black so the BLOOM_MIP pyramid never averages stale texels). Tap
// offsets are HALVED in quadrant space so the on-screen blur radius stays
// unchanged (composite2's scene taps land on the exact legacy full-res
// coordinates). composite5 reads the quadrant at uv*0.5 -- plain bilinear is
// enough, bloom has no silhouettes -- and the MIP ladder shifts 1..6 -> 0..5
// (one quadrant mip == one full-res mip coarser => same on-screen halo
// widths). Composes with TAAU: quadrant of the render sub-rect (0.5*TAAU_S).
// 0 = legacy full-res chain, bit-identical.
#define BLOOM_HALF_RES 1 // [0 1]
#define MOTION_BLUR_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0]
#define MOTION_BLUR_SAMPLES 8 // [4 6 8 12 16]
//#define MOTION_BLUR
//#define HEAT_SHIMMER
#define LIGHTNING_FX
#define BOSS_FX
#define LAVA_OVERLAY
// DAMAGE_FX (composite5): dark blood-red edge flash + brief radial blur when the
// player takes damage, scaled by the fraction of max health just lost (Iris
// currentPlayerHealth vs its smooth()-lagged copy, shaders.properties id 57).
// Half heart = subtle rim, 3+ hearts = violent flash; decays with a 0.7 s
// half-life (~gone in 1.5 s). Inert in creative/spectator and on respawn.
#define DAMAGE_FX 1 // [0 1]
#define DAMAGE_FX_STRENGTH 1.0 // [0.0 0.5 1.0 1.5 2.0]
#define MOON_HALO
//#define SHARPEN
// Force de la nettete adaptative (unsharp mask, final.fsh). Etait codee en dur a 0.38 (trop douce).
// 0.38 = ancien comportement EXACT. 0.6 = nette franche. 1.0+ = tres marquee (peut creer des halos
// aux contours / faire ressortir le grain). Sans effet si SHARPEN est OFF.
#define SHARPEN_STRENGTH 0.6 // [0.0 0.15 0.25 0.38 0.5 0.6 0.75 0.9 1.1 1.3 1.6 2.0]
const float centerDepthHalflife = 1.0; // [0.0 0.1 0.25 0.5 1.0 2.0 4.0 8.0 16.0]

// ============ RAY TRACING VOXEL (RTX maison — GI path-tracee) ============
// VOXEL_GI : illumination globale par lancer de rayons dans la grille voxel.
// La lumiere rebondit depuis le monde voxelise, HORS-ECRAN inclus. Le vrai "RTX".
// (En chantier : lourd + bruite pour l'instant. Necessite shadowDistance pour remplir la grille.)
// On/off en SLIDER (1=ON, 0=OFF) car les toggles booleens ne s'affichent pas dans
// le menu de cet Iris. ON par defaut pour que tu voies la GI tout de suite.
#define VOXEL_GI 0 // [0 1]
#define VOXEL_GI_STRENGTH 1.0 // [0.0 0.1 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0 12.0 20.0 50.0 100.0]
// RTX_BUFFER_PURGE : VRAM-only gate, the image is bit-identical in both states.
// 1 (default) = when RTX is fully OFF (VOXEL_GI=0, FULL_PATH_TRACE=0) the RTX-only
// history buffers colortex8/9/10/12 (40 bytes/px total: ~79 MiB @1080p, ~141 MiB
// @1440p per copy; Iris keeps main+alt pairs, so up to double) keep ZERO
// reference in any program (format block in
// composite5 compiled out; samplers and RENDERTARGETS already gated), so Iris
// never allocates them. 0 = legacy: format declarations always present.
// Has no effect while VOXEL_GI=1 (buffers are then needed and allocated anyway).
#define RTX_BUFFER_PURGE 1 // [0 1]
// ---- CLIPMAP VOXEL (cascades imbriquees) ----
// VOXEL_CASCADES grilles 256^3 centrees camera, echelles croissantes : cascade i a une
// taille de voxel s_i = VOXEL_SCALE * 2^i. Cascade 0 = la plus FINE (detail pres),
// cascades suivantes = 2x/4x/8x plus grossieres mais 2x/4x/8x plus de portee. La GI lit
// toujours la cascade la plus fine qui couvre le point -> fin PRES + portee LOIN.
// VOXEL_CASCADES=1 = ancienne grille mono (securite, RENDU IDENTIQUE a avant).
// VRAM : 128 MiB / cascade (256^3 RGBA16F). 6 images sont declarees inconditionnellement
// dans shaders.properties (les directives image.X ne sont PAS gatables par #if) -> 768 MiB
// alloues MEME a VOXEL_CASCADES<6. Pour recuperer la VRAM en mono-grille (debug VRAM), il
// FAUT aussi supprimer a la main les lignes image.voxelImg1..voxelImg5 (pas seulement baisser le slider).
// COUT CONSTANT : passer de 4 a 6 images = +256 MiB allous EN PERMANENCE meme si le slider reste a 3.
// A render distance 32 (deja lourde, RTX 3070 Ti 8 Go) c'est soutenable ; NE PAS depasser 6 cascades
// par defaut (8 images = 1 GiB = risque d'eviction VRAM a RD32).
// PLUS DE DETAIL : le detail PRES vient UNIQUEMENT d'un VOXEL_SCALE plus fin (cascade 0 plus fine,
// ex 0.125/0.25). Les cascades 4/5 (grossieres) n'ajoutent PAS de detail pres : elles donnent une
// couverture LOINTAINE plus large (moins de bruit/cout loin), TOUJOURS plafonnee par shadowDistance.
// Recette "plus de detail a portee egale" : baisse VOXEL_SCALE ET monte VOXEL_CASCADES pour que les
// cascades grossieres couvrent encore shadowDistance. Garde 128*VOXEL_SCALE <= shadowDistance (cascade 0).
// LIMITE REELLE DE PORTEE : la passe d'ombre ne voxelise que dans shadowDistance (ci-dessus,
// 128 blocs par defaut). Les cascades grossieres ne se remplissent donc QUE jusqu'a
// shadowDistance ; au-dela elles restent vides (= miss, pas d'occlusion fantome). Ajouter des
// cascades NE REPOUSSE PAS la portee au-dela de shadowDistance : ca reduit le bruit/cout loin
// a portee egale. Pour vraiment porter plus loin : monte shadowDistance (slider Ombres) ET
// VOXEL_GI_DISTANCE, au prix du FPS (cout dominant = passe d'ombre, ~ rayon^2).
#define VOXEL_CASCADES 3 // [1 2 3 4 5]
// (plafonne a 5 : voxelImg5 est reserve a la GRILLE BLOC des PT reflections)

// Taille d'un voxel en blocs pour la cascade 0 (BASE du clipmap). Cascade i = VOXEL_SCALE*2^i.
// Plus PETIT = plus fin pres ; les cascades suivantes prennent le relais pour la portee.
// La grille fait 256^3 cellules FIXES par cascade. CONTRAINTE CLIPMAP : garde
// 128*VOXEL_SCALE <= shadowDistance, sinon la cascade 0 a des cellules exterieures NON
// remplissables (au-dela de shadowDistance) qui, etant la cascade la plus fine, masquent
// les cascades grossieres = anneau de faux miss. Avec base 0.5 (extent 64 <= 128) c'est
// automatique ; evite VOXEL_SCALE 2.0/4.0 (extent 256/512 > 128) sauf si tu montes shadowDistance.
// 0.1875 = 3 texels d'une texture 16x16 (3/16) — assez fin pour lire le motif
// des textures dans les reflets voxel, assez gros pour que la passe d'ombre
// remplisse la grille sans trous (8192 sur 384 blocs ~ 2 fragments/cellule).
// LUMIERES COLOREES : 0.5 par defaut -> cellule LPV = 1 bloc, flood 15 cellules
// = ~15 blocs de portee de COULEUR (aligne sur la portee lightmap vanilla).
// L'ancien 0.1875 (reflets PT fins) ne portait la teinte qu'a ~5.6 blocs.
#define VOXEL_SCALE 0.5 // [0.0625 0.1 0.125 0.1875 0.25 0.5 1.0]
// audit : 2.0/4.0 retires de la liste (extent 512/1024 > fenetre ±128 = anneau
// de faux miss, la doc du fichier les declarait deja casses).

// DEBUG : quelle cascade afficher en DEBUG_VIEW==13 (0 = la plus fine). Constante de
// compilation. Si DEBUG_CASCADE >= VOXEL_CASCADES, retombe proprement sur la cascade 0.
#define DEBUG_CASCADE 0 // [0 1 2 3 4 5]
#define VOXEL_GI_SAMPLES 4 // [1 2 4 6 8 12 16 24 32 48 64 96 128 256]
#define VOXEL_GI_DISTANCE 24 // [4 8 12 16 24 32 48 64 96 128 192 256 384 512]

// JALON 11 — NB DE REBONDS GI. 1 = comportement mono-rebond historique (porte de secours).
// >1 = chaque rayon REBONDIT : a chaque hit albedo il accumule sa contribution puis CONTINUE
// (nouvelle dir = cosineHemisphere(-dir), faute de normale voxel = approximation) ; un hit
// emissif termine le chemin (source). Le multi-rebond ETALE l'emissif (glowstone remplit la
// piece = resout le "pur RTX un seul cote") et multiplie le color-bleeding. Cout ~lineaire en
// BOUNCES ; bruit croissant (variance Monte-Carlo composee). A BOUNCES>=2 monter VOXEL_GI_SAMPLES
// (>=6) ou TAA_GI_FRAMES pour compenser le 2e rebond emissif tres bruite.
#define BOUNCES 2 // [1 2 3 4 5 6 8 12 16]

// JALON 11 — CIEL EN GI (sky-on-miss). 0 = un rayon GI qui MISS renvoie 0 (actuel : le ciel
// n'eclaire pas la GI). 1 = on ajoute la vraie couleur du ciel dans la direction du rayon
// (eclairage d'environnement reel). N'affecte PAS les ombres directes (shadow map). [0 1]
// car les toggles booleens ne s'affichent pas dans ce menu Iris (cf. VOXEL_GI/VOXEL_REFLECTIONS).
#define SKY_GI 0 // [0 1]

// JALON 11 — force du terme ciel-en-GI. ATTENTION : ce terme passe ENSUITE par la teinte chaude
// (1.0,0.95,0.82) * VOXEL_GI_STRENGTH (composite5:809) -> il STACKE multiplicativement avec
// VOXEL_GI_STRENGTH (2.0 en profile.RTX). 0.5 = point de depart calibre pour ce stacking ; baisse
// encore si l'exterieur est delave/jaune cote soleil, monte pour un environment lighting plus marque.
// Sans effet si SKY_GI=0.
#define SKY_GI_STRENGTH 0.5 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]

// JALON 5 : fraction de l'ambiant ciel PLAT conservee quand VOXEL_GI==1. La GI voxel
// fournit desormais l'indirect/ambiant directionnel -> on baisse l'ambiant plat pour
// eviter le double-comptage (sinon scene ~2x trop claire). 1.0 = comme avant (GI=bonus) ;
// 0.0 = GI voxel seule. Defaut 0.35 = filet de securite (8 rayons -> evite les coins
// noirs bruites) ; le profil RTX le pinne a 0.0 (le RTX fournit tout l'indirect).
// N'affecte PAS le fog/eau (getAmbientColor reste intact) ni les ombres directes.
#define VOXEL_GI_AMBIENT 0.35 // [0.0 0.1 0.2 0.25 0.35 0.5 0.75 1.0 1.5 2.0 3.0]

// JALON 5 : gain HDR pre-tonemap de l'emissif voxel. L'emissif est ajoute AVANT ACES :
// pour qu'il survive a la compression de la courbe (et reste lumineux apres tonemap), on
// le multiplie ici. 3.0 = bon point de depart ; monte si la lave/glowstone parait fade,
// baisse si ca crame. Se combine avec EMISSIVE_VOXEL_STRENGTH (cote shadow.fsh).
#define EMISSIVE_GI_GAIN 3.0 // [0.0 0.5 1.0 1.5 2.0 3.0 4.0 6.0 8.0 12.0 20.0 50.0 100.0]

// ---- JALON 7 : REFLETS VOXEL HORS-ECRAN (eau) ----
// Tire 1 rayon miroir dans le clipmap voxel pour les surfaces d'EAU HORIZONTALE (lac/ocean) :
// ramene le reflet de la GEOMETRIE HORS-ECRAN (derriere / hors champ) que le SSR ecran
// (composite1) ne peut PAS voir. COMPLEMENT du SSR, pas un remplacement : on AJOUTE seulement
// ce que le SSR rate (un HIT de geometrie voxel), attenue par Fresnel. Le CIEL n'est PAS
// re-reflete ici (composite1 le fait deja analytiquement via getSkyAll, sans bornes ecran) :
// un MISS voxel (ciel / hors grille) ne touche PAS l'image -> aucun double-comptage du ciel,
// l'eau a ciel ouvert reste IDENTIQUE a avant le Jalon 7. PORTEE : EAU SEULEMENT, par choix.
// Les reflets PBR des blocs lisses (pierre/metal) restent en SCREEN-SPACE via composite1 ;
// les etendre au voxel ici serait risque (pas de lecture rugosite, overlap SSR PBR) -> hors
// scope volontaire. Tres econome (1 rayon, eau horizontale uniquement) mais l'utilisateur lag
// deja a 6 cascades / RD32 -> defaut ON avec une FORCE moderee (0.35, anti double-comptage
// on-screen residuel). Le profil non-RTX (VOXEL_GI=0) le desactive AUTO (bloc gate #if
// VOXEL_GI==1). On/off en SLIDER [0 1] (les toggles booleens ne s'affichent pas dans ce menu
// Iris), comme VOXEL_GI. Porte de secours = VOXEL_REFLECTIONS 0 -> rendu actuel exact.
#define VOXEL_REFLECTIONS 0 // [0 1]
// Force du reflet voxel ajoute. 0.35 = complement discret (defaut, anti-lag + anti sur-comptage
// de la geometrie deja reflechie a l'ecran par le SSR) ; monte vers 0.75-1.0 pour des reflets
// hors-ecran plus francs, baisse si l'eau parait surchargee par rapport au SSR.
#define REFLECTION_STRENGTH 0.35 // [0.0 0.1 0.25 0.35 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]
// Budget d'iterations du rayon de reflexion (le pas grossit avec la distance, comme la GI).
// Plus haut = reflets hors-ecran plus lointains mais plus cher. 24 = bon compromis (proche de
// la portee GI), baisse a 16 si lag, monte a 32-48 pour de l'eau face a des builds lointains.
#define REFLECTION_STEPS 24 // [4 8 12 16 20 24 32 48 64 96 128 256]

// ---- JALON 7b : REFLETS VOXEL HORS-ECRAN sur OPAQUE GLOSSY/METAL ----
// Etend le repli reflets voxel (eau seule) aux surfaces opaques lisses/metal : complement
// hors-ecran du SSR de composite1. 0 = OFF -> rendu EXACT actuel (gate #if). HONNETE :
// depend d'un pack LabPBR (smoothness colortex2.a + metalness colortex11.g) ; SANS pack,
// smoothness=0 ET metalness=0 -> aucun pixel ne passe le seuil -> effet ET cout NULS.
// Le profil non-RTX (VOXEL_GI=0) le desactive AUTO (le bloc est sous #if VOXEL_GI==1).
#define VOXEL_REFLECTIONS_OPAQUE 0 // [0 1]
// Seuil de gloss = max(smoothness, metalness) au-dessus duquel on trace un rayon voxel.
// Haut = moins de pixels tracent (moins cher) ; bas = plus de surfaces refletent (plus cher).
// 0.5 = surfaces franchement lisses/metal. Monte a 0.6-0.7 si lag (le rayon voxel est partage
// avec l'eau via REFLECTION_STEPS, pas de budget separe). Compare en RUNTIME (jamais en #if).
#define REFLECT_OPAQUE_THRESHOLD 0.5 // [0.2 0.3 0.4 0.5 0.6 0.7 0.8]
// Force du reflet voxel opaque ADD. PLUS FAIBLE que l'eau (0.35) car le SSR ecran a deja
// ajoute le reflet on-screen a color -> anti double-comptage residuel. Monte pour des metaux
// plus francs hors-ecran, baisse si l'opaque parait surcharge par rapport au SSR.
#define REFLECTION_STRENGTH_OPAQUE 0.25 // [0.0 0.1 0.15 0.25 0.35 0.5 0.75 1.0 1.5 2.0]

// ---- TUNING CONTACT_SHADOWS (composite1) : defauts = valeurs actuelles -> aucun changement
// visuel hors activation du toggle. Ajuster si le contact parait trop fort/faible apres test.
// STEPS/BIAS sont des constantes int/float comparees/utilisees en RUNTIME (jamais en #if).
// CONTACT_SHADOW_STEPS : derive de SHADOW_QUALITY
#define CONTACT_SHADOW_STRENGTH 0.55 // [0.1 0.25 0.35 0.45 0.55 0.7 0.85 1.0]
#define CONTACT_SHADOW_THICKNESS 0.55 // [0.1 0.2 0.35 0.45 0.55 0.75 1.0 2.0]
#define CONTACT_SHADOW_BIAS 0.012 // [0.004 0.008 0.012 0.02 0.03 0.05]

// ---- JALON 6 : BLOCS EMISSIFS DANS LA GI VOXEL ----
// Les blocs lumineux (lave, glowstone, torches, lanternes, sea lantern, shroomlight,
// froglights, magma, feu, end rod, soul fire, amethyste...) EMETTENT leur propre lumiere
// coloree DANS la GI voxel : ils eclairent les surfaces autour, HORS-ECRAN inclus.
// Detection = material ID (block.properties 20-24), deja porte par matS dans la passe d'ombre.
// Encodage : le voxel reste 1 RGBA16F ; alpha=2.0 => emissif & rgb=radiance emise (alpha=1.0
// => solide & rgb=albedo, comportement Jalon 3). L'occupation reste alpha>0.5 (occlusion +
// 1er-hit) pour les deux : un bloc emissif occulte comme un solide.
// PORTE DE SECOURS : EMISSIVE_VOXEL 0 => comportement Jalon 3 EXACT (l'emissif est traite
// comme un albedo ordinaire). On/off en SLIDER (les toggles booleens ne s'affichent pas dans
// ce menu Iris), comme VOXEL_GI. ON par defaut.
#define EMISSIVE_VOXEL 0 // [0 1]
// Force de l'emission injectee dans la GI. Grosses limites : la lave/glowstone doivent
// pouvoir illuminer franchement une piece sombre. Defaut 0.5 : au-dela la couleur (rouge
// lave, blanc-chaud glowstone) tend a clipper au blanc dans le buffer sRGB ou la GI est
// ajoutee -> monte le slider pour plus de puissance, baisse-le pour garder la teinte.
#define EMISSIVE_VOXEL_STRENGTH 0.5 // [0.0 0.1 0.25 0.5 0.75 1.0 1.5 2.0 3.0 4.0 6.0 8.0 12.0 20.0 50.0 100.0]

// ---- FIX ECRITURE : PRIORITE + DILATATION EMISSIVE (voxelisation, shadow.fsh) ----
// Corrige le bug "un bloc emissif n'eclaire que d'un cote / seulement une partie de ses voxels".
// 0 = imageStore direct ACTUEL (comportement identique : meme test de bornes, meme store unique).
// 1 = au write voxel (ON gate aussi sur EMISSIVE_VOXEL=1, sinon sans effet ET sans surcout) :
//  (a) PRIORITE : une cellule deja emissive (a=2) n'est PLUS ecrasee par un bloc solide voisin (a=1) ;
//  (b) DILATATION : un bloc emissif remplit aussi ses voxels voisins VIDES (halo 1 voxel, 6 faces)
//      -> le 2x2x2 complet du bloc devient emissif et il emet de TOUS les cotes. La dilatation
//      n'ecrit QUE dans les cellules vides (a<0.5) -> ne transforme jamais un mur solide adjacent en
//      source (anti-fuite a travers les murs). LIMITE CONNUE : une geometrie SOUS-BLOC d'1 voxel
//      d'epaisseur (vitre/dalle/tapis a VOXEL_SCALE=0.5) collee a une source PEUT laisser fuir un peu
//      de lumiere (la course non atomique peut lire 'vide' et ecrire l'emissif dans l'unique voxel) ;
//      mettre 0 si une fuite est visible sur vitres fines.
// HONNETE : imageLoad/imageStore non atomiques entre fragments concurrents -> best-effort statistique,
// pas une garantie 100%. La grille etant re-voxelisee chaque frame + l'accumulation temporelle lissent
// le residuel. La dilatation ajoute aussi de l'OCCUPATION (a>0.5) aux cellules d'air voisines -> les
// sources voxelisees grossissent d'~1/2 bloc pour l'occlusion/les reflets voxel (benin, voulu pour
// emettre de tous cotes). COUT par fragment et PAR cascade ACTIVE (VOXEL_CASCADES=3 par defaut, PAS 6) :
// +1 imageLoad/fragment albedo (cout dominant), +6 imageLoad et jusqu'a +6 imageStore/fragment emissif.
// Le levier de cout est shadowDistance + densite de geometrie ombree. Si lag : voir la variante
// "cascade 0 seulement" dans shadow.fsh. VALIDATION : DEBUG_VIEW 13 (le cube emeraude devient plein/
// teinte au raymarch) + DEBUG_VIEW 18 (heatmap des hits : les deux cotes chauffent). NB la vue 17 lit
// la cellule d'AIR devant la face -> elle peut rester partielle cote ombre, ce n'est PAS la bonne preuve.
#define EMISSIVE_VOXEL_FILL 1 // [0 1]

// ---- JALON 12 : NEE EMISSIF (gather voxel local) ----
// FIX du bug "emissif un seul cote / selon l'angle". 0 = emissif RANDOM-HIT ACTUEL EXACT
// (porte de secours byte-identique). 1 = a chaque point ombre on echantillonne le champ
// emissif LOCAL par rayons courts (marchVoxelP) aimes par la normale, avec falloff 1/r^2
// -> eclairage OMNIDIRECTIONNEL propre depuis les blocs lumineux (chaque surface FACE a la
// source est eclairee, pas seulement celle qui capte un rayon aleatoire). Alimente la MEME
// giEmissive -> accumulation/checkerboard/gain INCHANGES. Inerte si EMISSIVE_VOXEL=0.
// HONNETE : ce n'est PAS du vrai NEE (les rayons qui ratent une source sont jetes) ; le grain
// residuel est masque par l'EMA colortex10. COUT : aux defauts (VOXEL_GI_SAMPLES=4, BOUNCES=1)
// ce gather DOUBLE ~ le cout de ray-march voxel par pixel ; sur profile.RTX (samples=6,
// BOUNCES=2) il ajoute ~33%. Le damier (GI_CHECKERBOARD=1) le paie sur 1 pixel/2. Si lag :
// baisse EMISSIVE_NEE_SAMPLES (4-6) ou EMISSIVE_NEE_RADIUS d'abord.
#define EMISSIVE_NEE 0 // [0 1]
// Nb de rayons de gather par pixel. 12 par defaut = assez de hits pour tuer le "un seul cote"
// pres d'une petite source ; baisse a 6-8 si lag sur 3070 Ti, monte a 16-24 si grain residuel.
#define EMISSIVE_NEE_SAMPLES 12 // [1 2 4 6 8 12 16 24 32 48 64 128]
// Rayon de gather en BLOCS : porte des rayons courts. Plus grand = capte des sources plus
// lointaines mais plus cher (reach grimpe). 8 = bon compromis interieur.
#define EMISSIVE_NEE_RADIUS 8.0 // [1.0 3.0 5.0 8.0 12.0 16.0 24.0 32.0 48.0 64.0 128.0]
// Gain de calibrage : l'integration (1/r^2) a une echelle DIFFERENTE du random-hit ET passe
// ENSUITE par EMISSIVE_GI_GAIN (3.0 en profile.RTX) -> le niveau changera a l'activation.
// Calibre ici jusqu'a retrouver le rendu voulu. 1.0 = depart ; descends a 0.5 si EMISSIVE_GI_GAIN
// est deja eleve (profile.RTX).
#define EMISSIVE_NEE_GAIN 1.0 // [0.0 0.1 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0 12.0 20.0]

// ---- JALON 13 : DOUCEUR / PORTEE DU FALLOFF EMISSIF ----
// 0.0 = falloff 1/(1+0.5 d^2) ACTUEL EXACT (porte de secours ; la lampe meurt en ~4 blocs).
// >0 = inverse-carre FENETRE borne au rayon : noyau brillant pres de la source + remplissage doux
// jusqu'a ~EMISSIVE_NEE_RADIUS puis extinction smoothstep -> 0 EXACTEMENT au rayon (facon lumiere
// de bloc MC). Plus grand = remplit plus loin / plus doux. 0.5 = noyau marque, 2.0+ = halo large.
// NOTE : la selection est RUNTIME (pas #if) cote shader -> ce define est un FLOAT (pas un entier).
// IMPORTANT CALIBRAGE : ce falloff est BEAUCOUP plus lumineux a mi-distance que l'ancien (~8x a 5
// blocs a R=12). Avec EMISSIVE_NEE_GAIN=2.0 le proche-champ peut cramer : 1er reglage si trop vif =
// baisser EMISSIVE_NEE_GAIN (2.0 -> 1.5). Mettre 0.0 retablit l'ancien falloff a l'identique.
#define EMISSIVE_NEE_SOFT 1.0 // [0.0 0.5 1.0 1.5 2.0 3.0 5.0 8.0 12.0]

// ---- JALON 14 : BIAIS D'ORIGINE DU GATHER EMISSIF (debug anti-leak) ----
// Decalage de l'origine du rayon de gather emissif (gatherEmissiveNEE, composite5) en MULTIPLES
// de VOXEL_SCALE, AVANT le ray-march. 0.0 = origine pile sur la surface (capte le voxel emissif
// adjacent au max, mais risque self-hit / leak d'arete). 0.25 = comportement ACTUEL EXACT (quart
// de voxel anti-leak). Plus HAUT = pousse l'origine loin de la surface -> moins de leak mais
// l'emissif des sources collees au sol/mur s'eteint (etouffe). Teste 0.0 si une glowstone au sol
// parait trop sombre, 0.5-1.0 si la lumiere fuit a travers un mur fin.
#define EMISSIVE_NEE_BIAS 0.25 // [0.0 0.1 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0]

// ---- JALON 16 : FIX ONE-SIDED — part de rayons SPHERE complete (omnidirectionnel) ----
// 0.0 = repli EXACT actuel (100% cosine-hemisphere aimee par la normale : un bloc emissif
// n'eclaire que les faces qui le regardent -> emeraude one-sided). >0 = fraction de rayons tires
// sur la SPHERE complete -> capte une source sur le cote / derriere -> un bloc emissif eclaire de
// maniere plus omnidirectionnelle. Visibilite (marchVoxelP, 1er occupant) INCHANGEE -> anti-leak garde.
// FLOAT (selection runtime cote shader, comme EMISSIVE_NEE_SOFT). 0.5 = moitie/moitie.
// NOTE : ~la moitie des rayons sphere partent SOUS la surface (perdus) -> pour un cote sombre propre,
// monte EMISSIVE_NEE_SAMPLES (16-24) quand OMNI>0, ou augmente EMISSIVE_NEE_OMNI_GAIN.
#define EMISSIVE_NEE_OMNI 0.0 // [0.0 0.25 0.5 0.75 1.0]
// Poids relatif des rayons sphere vs hemisphere (calibrage luminosite cote sombre). 1.0 = neutre.
#define EMISSIVE_NEE_OMNI_GAIN 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0]

// ===================== HYBRIDE TEINTE (Architecte) =====================
// CHEMIN PRINCIPAL anti 3-symptomes. 0 = pur-RTX gather actuel (repli byte-identique).
// 1 = base d'eclairage emissif = lightmap vanilla colortex2.x (OMNI+STABLE+LISSE+gratuite),
// TEINTEE par la couleur du gather voxel (or/vert/cyan) ; le gather voxel retrograde a un
// simple BOUNCE de contact colore (EMISSIVE_HYBRID_BOUNCE). Resout #1 #2 #3 par construction.
#define EMISSIVE_HYBRID 0 // [0 1]
// Intensite de la base lightmap teintee (terme stable). 1.0 = niveau lampe MC nominal.
#define EMISSIVE_HYBRID_GAIN 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 4.0 6.0]
// Part residuelle du gather voxel path-trace (bounce de contact colore). 0.0 = base seule
// (le plus stable). 0.3 = soupcon de rebond RTX. 1.0 = gather a pleine force (en plus de la base).
#define EMISSIVE_HYBRID_BOUNCE 0.3 // [0.0 0.1 0.25 0.3 0.5 0.75 1.0]
// Courbe gamma de la lightmap (comme lighting.glsl lm.x^curve). 2.0 = doux, 3.0 = contraste MC.
#define EMISSIVE_HYBRID_CURVE 2.2 // [1.0 1.5 2.0 2.2 2.5 3.0]

// ===================== FIX VOXELISATION E/W (Expert voxel) =====================
// 0 = halo 6-faces actuel (repli byte-exact). 1 = stamp 3x3x3 (26 voisins) only-empty :
// remplit le 2x2x2 complet du bloc + halo 1-voxel SYMETRIQUE (faces ET diagonales) -> les
// cotes E/W sont semes meme si la passe d'ombre ne rasterise que la face haut/bas. Resout
// 'un seul cote' a la SOURCE (benefique en pur-RTX ET en bounce hybride). Anti-leak preserve
// (ecriture conditionnee a la cellule vide a<0.5).
#define EMISSIVE_FILL_RADIUS 1 // [0 1]

// ===================== FIX GATHER PUR-RTX (Experts temporel+sampling) =====================
// Lecture TRILINEAIRE du champ emissif au point d'impact (au lieu du nearest hit.rgb) -> la
// radiance lue est CONTINUE en translation = attenue le step de re-snap. Cellules vides
// MASQUEES (on ne mixe que les voisins .a>0.5) pour ne pas baver du noir aux bords. 0 = nearest (repli).
#define EMISSIVE_VOXEL_TRILINEAR 1 // [0 1]
// Reset DOUX de l'accumulation : sur disocclusion, repart de N frames (alpha=1/N) au lieu de
// count=1 (alpha=1 = re-roll franc). 1 = reset sec actuel (repli). 4 = transition ~invisible.
#define EMISSIVE_RESET_FRAMES 4 // [1 2 4 8]
// Tolerance de disocclusion emissive (multiplicateur). 0.5 = actuel (trop strict en mouvement).
// 1.0 = aussi tolerant que l'albedo (le reset doux gere deja la trainee).
#define EMISSIVE_DISOCC_SCALE 1.0 // [0.25 0.5 0.75 1.0 1.5 2.0]
// =======================================================================

// ---- JALON 15 : LPV — INJECTION + PROPAGATION DE LUMIERE (remplace le gather emissif) ----
// 0 = gather actuel EXACT (gatherEmissiveNEE, byte-identique). 1 = champ LPV (compute composite.csh).
// STAGE 1 = injection + lecture DIRECTE trilineaire (PAS de propagation) : SEULES les surfaces a
// ~1 bloc d'une source s'eclairent. STAGE 2 (a venir) = flood -> la lave inonde la zone.
// Mutuellement exclusif avec EMISSIVE_NEE cote consommation : sous EMISSIVE_LPV=1, le #elif de
// composite5 fait que NEE n'alimente plus giEmissive, et la garde de la boucle GI (ligne ~980)
// inclut EMISSIVE_LPV pour que la branche emissive 'break' sans accumuler (anti double-comptage).
// Slider [0 1] (les toggles booleens ne s'affichent pas dans ce menu Iris, cf. VOXEL_GI/EMISSIVE_NEE).
// LUMIERES COLOREES (A3) : 1 par DEFAUT — la chaine LPV alimente le pont forward de
// lib/lighting.glsl (sampleLPVForward) SANS PT : voxelisation cascade 0 (shadow.fsh),
// injection (composite.csh), flood (composite_a..d). Le chemin composite5 reste gate VOXEL_GI.
#define EMISSIVE_LPV 0 // [0 1]
// Gain de calibrage du champ -> giEmissive. Echelle DIFFERENTE du random-hit/NEE et passe ENSUITE
// par EMISSIVE_GI_GAIN (1.0 en profile.RTX) -> RECALIBRER a l'activation. EN STAGE 1 (lecture directe,
// effet faible et tres local), monter a 5-8 pour VOIR si l'infra marche, puis recalibrer en Stage 2.
#define LPV_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]
// (STAGE 2, documentaire en Stage 1) Attenuation PAR BLOC du flood : att = LPV_ATTEN^step. Plus bas =
// portee courte, plus haut = inonde plus loin. 0.78 = depart interieur MC. INERTE tant qu'aucun .csh de flood.
#define LPV_ATTEN 0.78 // [0.5 0.6 0.7 0.78 0.85 0.9 0.95 0.97]
// (STAGE 2) Portee du flood. 0 = injection seule (= Stage 1 exact, pas de propagation).
// 2 = flood court (passes step 8+4 ; c/d en copie). 4 = flood complet (step 8+4+2+1, portee ~15 blocs).
// Les passes desactivees deviennent des copies de parite (resultat toujours en lightImg/A). INERTE si EMISSIVE_LPV=0.
#define LPV_PASSES 4 // [0 2 4]

// ---- LUMIERES COLOREES (pont forward LPV -> gbuffers, lib/lighting.glsl sampleLPVForward) ----
// Force du POP additif : radiance LPV coloree AJOUTEE au shading (falloff par le flood = lumiere
// spherique), garde-fou lightmap contre les fuites. 0.0 = teinte seule (aucun ajout d'energie).
// 0.35 defaut (demande user « juste colorer vanilla mais colore et jolie ») : la TEINTE fait
// le travail (CL_TINT_MIX), le pop additif reste discret — zero look « RTX ».
#define CL_STRENGTH 0.35 // [0.0 0.25 0.35 0.5 0.75 1.0 1.5 2.0 3.0]
// Part de la TEINTE LPV dans la couleur torche vanilla la ou le champ a de l'energie
// (l'INTENSITE reste pilotee par la lightmap = falloff spherique fiable, zero fuite).
// 0.0 = teinte orange vanilla partout ; 1.0 = couleur du champ seule.
#define CL_TINT_MIX 0.85 // [0.0 0.25 0.5 0.7 0.85 1.0]

// ---- JALON 3 : ACCUMULATION TEMPORELLE DE LA GI VOXEL ----
// Lisse le scintillement de la GI en moyennant la frame courante avec les frames
// precedentes (reprojection + rejet d'historique en disocclusion). PORTE DE SECOURS :
// mets 0 pour revenir a la GI brute du Jalon 2 (utile si l'accumulation casse).
#define TEMPORAL_ACCUM 1 // [0 1]
// Fenetre d'accumulation : nb max de frames moyennees. + bas = reagit vite mais reste
// un peu bruite ; + haut = tres lisse mais "traine" sur les changements lents (jour/nuit).
#define TAA_GI_FRAMES 32 // [2 4 8 12 16 24 32 48 64 128 256]
// Seuil de disocclusion en BLOCS (a la distance de l'oeil = 1 ; mis a l'echelle plus loin) :
// si le pixel reprojete s'est deplace de plus que ca, on jette l'historique (nouvelle geo).
#define DISOCCLUSION_THRESHOLD 0.5 // [0.1 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]

// ============ JALON 4 : DENOISE ============
// ---- STABILISATION TEMPORELLE DE L'EMISSIF (priorite : tue le clignotement) ----
// L'emissif voxel (Jalon 6) etait ajoute HORS accumulation -> clignote (peu de rayons
// touchent une petite source par frame + textures lave/feu animees). On l'accumule
// desormais dans un buffer dedie (colortex10) avec la MEME reprojection que la GI albedo,
// MAIS sans le clamp anti-firefly dur (c'est lui qui causait le fade-in du Jalon 5). Un gate
// anti-trainee + une montee rapide sur allumage evitent smear et fade-in d'etat.
// PORTE DE SECOURS : EMISSIVE_ACCUM 0 => add brut exact (comportement Jalon 6).
// Slider (les toggles booleens ne s'affichent pas dans ce menu Iris), comme VOXEL_GI.
#define EMISSIVE_ACCUM 1 // [0 1]
// Fenetre d'accumulation de l'emissif. + bas = reagit vite mais reste un peu instable ;
// + haut = tres lisse mais traine un peu sur la lave animee. 16 = bon compromis.
#define EMISSIVE_ACCUM_FRAMES 16 // [1 2 4 8 12 16 24 32 48 64 128]

// ---- JALON 13 : DENOISE SPATIAL DE L'EMISSIF (tue le grain) ----
// A-trous edge-aware (depth + normale + variance-luma) sur colortex10 (emissif accumule), applique
// UNIQUEMENT a la valeur ajoutee a l'image -> colortex10 reste NON denoise (jamais de re-entree dans
// l'historique, comme le denoise GI). Coherent checkerboard (colortex10 est dense). TOGGLE SEPARE de
// GI_DENOISE : tu peux isoler l'emissif (VOXEL_GI_STRENGTH=0) et le denoiser quand meme.
// 0 = OFF (ajout brut, EXACTEMENT le comportement d'avant ce jalon).
#define EMISSIVE_DENOISE 1 // [0 1]
// Force : 0 = quasi passthrough, 1 = nominal, >1 = sigmas plus larges (plus lisse, bave un peu plus
// aux aretes). Baisse a 0.75 si un halo apparait autour d'une glowstone.
#define EMISSIVE_DENOISE_STRENGTH 1.0 // [0.0 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]
// Permissivite du wL variance-aware : sigma_luma = PHI x ecart-type local (plafonne). Plus HAUT =
// lisse plus fort les surfaces planes (tue plus de grain) ; baisse a 2 si un halo borde les sources.
#define EMISSIVE_LUMA_PHI 3.0 // [0.5 1.0 2.0 3.0 4.0 6.0 8.0 12.0 20.0 50.0]

// ---- DENOISE SPATIAL A-TROUS (edge-avoiding wavelet) sur la GI diffuse ----
// Lisse le grain residuel de la GI diffuse accumulee (colortex8) par un filtre a-trous
// edge-aware : poids d'arret sur depth RELATIF (depthtex0 linearise), normale monde
// (colortex1) et luminance. Lit les voisins de colortex8 frame n-1 (1 frame de retard,
// acceptable car la GI est deja lissee temporellement). PORTE DE SECOURS : GI_DENOISE 0 = Jalon 5 exact.
#define GI_DENOISE 1 // [0 1]
// Force du filtre : 0 = quasi passthrough, 1 = nominal, >1 = elargit les sigmas (plus lisse,
// bave un peu plus aux aretes). Baisse a 0.5 si les coins/contacts paraissent etales.
#define DENOISE_STRENGTH 1.0 // [0.0 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]

// ============ FIX A : ANTI-FIREFLY / FIX B : ANTI LIGHT-LEAK (rayons GI) ============
// ---- ANTI-FIREFLY (clamp RELATIF par rayon ; couvre 1ere frame / disocclusion / damier frais) ----
// Le clamp EMA (accumulateGI) ne s'applique QUE quand un historique est trouve : 1ere frame,
// disocclusion et pixels frais du checkerboard = un seul rayon touchant une source vive passe SANS
// borne = point lumineux. Ici on borne chaque rayon par rapport a la MOYENNE COURANTE des rayons
// deja tires (un outlier isole est ecrete, une GI uniformement vive n'est PAS bridee car sa moyenne
// monte avec elle). Agit donc meme sans historique temporel. 0 = OFF (comportement actuel exact).
#define GI_FIREFLY_CLAMP 1 // [0 1]
// MULTIPLICATEUR du clamp : un rayon est limite a GI_FIREFLY_MAX x (moyenne courante des rayons) +
// un petit plancher absolu. PLUS BAS = tue plus de points mais peut adoucir la GI a fort contraste ;
// PLUS HAUT = laisse passer des rayons plus vifs (moins de clamp). 3 = bon compromis (un rayon vaut
// au plus 3x la moyenne locale). La charge utile voxel etant sous-unitaire, ce reglage RELATIF est
// ce qui tue reellement les "points qui font la lumiere" (un cap absolu eleve serait inerte).
#define GI_FIREFLY_MAX 3.0 // [1.0 1.5 2.0 2.5 3.0 4.0 6.0 8.0 12.0 20.0 50.0]

// ---- DENOISE A-TROUS MULTI-PASS (style SVGF : paliers a dilatation croissante 1,2,4) ----
// atrousGI fait deja 2 paliers (1,2) en un appel. 3 AJOUTE un palier (dilatation 4) = noyau effectif
// plus large -> tue le grain basse-frequence residuel SANS latence (toujours 1 appel, voisins frame
// n-1, memes arrets depth/normale/luma). 2 = comportement actuel EXACT (porte de secours). Si les
// contacts/geometries fines paraissent floues, repasser a 2 ou baisser DENOISE_STRENGTH a 0.75.
#define GI_DENOISE_PASSES 3 // [2 3]

// ---- CLAMP SPATIAL ANTI-FIREFLY (tue les outliers isoles que le clamp par-rayon laisse passer) ----
// atrousGI ne fait qu'un BLUR pondere : il moyenne un pixel trop vif sans jamais l'ECRETER. Le clamp
// par-rayon (GI_FIREFLY_CLAMP) part d'une moyenne nulle -> le 1er rayon d'un pixel frais (disocclusion
// / 1ere frame / damier) n'est PAS borne ; le clamp EMA (accumulateGI) n'agit que s'il existe un
// historique. Resultat : un point lumineux isole survit -> "le pixel qui apparait". Ici on borne la
// luminance du pixel CENTRAL a moyenne_voisins + K*ecart-type (et au plus le voisin le plus brillant),
// AVANT le filtrage, en gardant la teinte (ratio luma). Ne touche QUE les vrais spikes (centre >>
// voisinage) ; une zone uniformement vive n'est PAS ecretee. ~8 texelFetch. 0 = OFF (comportement
// actuel EXACT, code non compile). C'est le levier DECISIF du Jalon 10 contre le grain residuel.
// NOTE : les stats viennent de colortex8 (GI frame n-1, comme le filtre a-trous) -> sur un pixel
// FRAICHEMENT disoccle, si tous les voisins ont gN.a<0.5, cnt reste bas et le clamp ne fait rien :
// dans ce cas la mitigation reelle est TAA_GI_FRAMES (fenetre EMA plus longue), pas ce clamp.
#define GI_SPATIAL_CLAMP 1 // [0 1]
// Tolerance : centre limite a moyenne + K x ecart-type des voisins valides. PLUS BAS = ecrete plus
// agressivement (tue plus de points, peut adoucir un peu le contraste de contact / manger les petits
// contacts lumineux 1px) ; PLUS HAUT = plus permissif. 2.0 = defaut sur : seuls les outliers francs
// sont touches (le clamp est unidirectionnel + alimente un denoise luma-aware, mieux vaut prudent).
// Baisser vers 1.25-1.5 si le grain persiste ; monter si la GI parait plate/terne.
#define GI_SPATIAL_CLAMP_K 2.0 // [0.5 0.75 1.0 1.25 1.5 2.0 2.5 3.0 5.0 8.0]

// ---- DENOISE GI FORT (Jalon 10C : tue le grain des surfaces planes) ----
// Le wL (poids luma) de l'a-trous legacy utilise un sigma FIXE : sur une zone PLATE mais BRUITEE
// (VOXEL_GI_SAMPLES rayons), il prend le bruit Monte-Carlo pour un bord de luminance et PROTEGE les
// points brillants au lieu de les moyenner (auto-sabotage : le denoise preserve le grain qu'il
// devrait tuer). STRONG=1 rend wL VARIANCE-AWARE (sigma_luma = GI_LUMA_PHI x ecart-type local de la
// luma, deja calcule par le bloc clamp 3x3, PLAFONNE a l'echelle legacy pour ne pas baver sur les
// vrais gradients de contact/ombre douce) : permissif quand c'est bruite (VRAI lissage des surfaces
// planes), strict SEULEMENT sur un vrai bord. Ajoute aussi un 4e palier (dilatation 8 = noyau ~17x17)
// SI GI_DENOISE_PASSES=3. depth+normale INCHANGES -> AUCUNE bavure d'arete. 0 = comportement actuel
// EXACT (porte de secours byte-identique ET zero-cout). Levier DECISIF du Jalon 10C contre le grain.
#define GI_DENOISE_STRONG 1 // [0 1]
// Permissivite du wL variance-aware : sigma_luma = GI_LUMA_PHI x sqrt(variance 3x3), PLAFONNE a
// l'echelle legacy (le plafond empeche le box-blur sur les vrais gradients). PLUS HAUT = lisse plus
// fort les surfaces planes (tue plus de grain) ; PLUS BAS = preserve mieux les contacts/ombres douces.
// 3.0 = depart SUR (conservateur) ; monte a 4-6-8 si du grain persiste, baisse a 2 si les contacts/
// ombres douces bavent ou si un halo apparait autour de la glowstone. Sans effet si GI_DENOISE_STRONG=0.
#define GI_LUMA_PHI 3.0 // [0.5 1.0 2.0 3.0 4.0 6.0 8.0 12.0 20.0 50.0]

// ---- ANTI LIGHT-LEAK (biais d'origine du rayon GI) ----
// L'origine GI etait wpos + wn*0.6 : biais FIXE, normale seule, non proportionnel a VOXEL_SCALE ->
// la lumiere fuit a travers blocs fins / aretes. Ce reglage cale le biais sur la taille de voxel
// cascade-0 (comme les reflets, composite5:781). EN MULTIPLES de VOXEL_SCALE. Trop BAS = self-
// occlusion (points noirs sur surfaces planes) ; trop HAUT = la GI "decolle" des surfaces et le
// contact darkening disparait. 1.2 (~0.6 bloc a scale 0.5) reproduit ~l'ancien comportement ;
// 1.5 = compromis anti-leak conseille (combine au pre-pas demi-voxel cote composite5).
#define GI_RAY_BIAS 1.5 // [0.0 0.25 0.5 0.75 1.0 1.2 1.5 2.0 2.5 3.0 5.0 8.0]

// Test d'occlusion au TOUT 1er pas du rayon (arete). marchVoxel saute le test au i==0 (anti self-
// hit) : a une arete convexe, la cellule occluante adjacente est justement celle sautee = fuite.
// Comme l'origine est deja poussee > 1 voxel hors de la surface (GI_RAY_BIAS + pre-pas demi-voxel),
// tester i==0 redevient SUR et bouche la fuite d'arete. ATTENTION : marchVoxel est PARTAGE avec le
// chemin reflets eau (originR deja biaise > 1 voxel, sur la aussi). DEFAUT 0 = saut i==0 actuel
// (porte de secours, AUCUN changement sur la GI NI sur les reflets). Passer a 1 SEULEMENT si, apres
// GI_RAY_BIAS=1.5 + pre-pas, une fuite d'arete persiste ; si des surfaces planes noircissent,
// repasser a 0 et/ou monter GI_RAY_BIAS d'un cran.
#define GI_EDGE_OCCLUSION 0 // [0 1]

// ============ MODE EXPERIMENTAL : OMBRE SOLEIL FULL PATH-TRACED (voxel) ============
// 0 = HYBRIDE ACTUEL EXACT (ombre directe = shadow map PCSS, BYTE-identique). 1 = l'ombre
// directe du soleil/lune vient d'un RAY-MARCH dans les voxels (toute la lumiere passe par le
// path tracer). HONNETE : ombres cubiques/blocky (resolution VOXEL_SCALE), plus de bruit, plus
// lent, et PROBABLEMENT MOINS BEAU que la PCSS. Necessite VOXEL_GI=1 (sans grille, pas d'ombre
// voxel -> on garde la shadow map). GATE STRICT : ABSENT des profils -> defaut 0 = repli hybride exact.
#define FULL_PATH_TRACE 0 // [0 1]
// Rayons d'ombre soleil par pixel (penombre). 1 = ombre dure, 1 march (le moins cher). 2-8 =
// penombre douce jitteree dans le cone solaire (plus cher, plus de bruit ; pas de denoise temporel
// dedie au 1er jet -> scintillement en mouvement).
#define FPT_SUN_SAMPLES 1 // [1 2 4 8]
// Pas du ray-march d'ombre (budget perf). Plafonne par shadowDistance (la grille n'est remplie que la).
// Baisse si lag. Le pas est FIXE (cascade-locale) pour ce march d'ombre -> anti light-leak murs fins.
#define FPT_SUN_STEPS 24 // [8 16 24 32 48 64 96 128]
// Rayon angulaire du "soleil" pour la penombre (tan de l'angle ; ~0.03 = disque un peu elargi,
// plus grand = ombres plus molles). Sans effet si FPT_SUN_SAMPLES=1.
#define FPT_SUN_RADIUS 0.03 // [0.005 0.01 0.02 0.03 0.05 0.08 0.12 0.2]
// Biais anti self-shadow le long du rayon soleil, en multiples de VOXEL_SCALE. Trop BAS = acne
// (points noirs sur surfaces planes ensoleillees) ; trop HAUT = peter-panning (l'ombre se detache
// du pied des objets). marchVoxel saute deja i==0 -> 0.25 suffit en general.
#define FPT_LIGHT_BIAS 0.25 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0]

// ============ JALON 8 : CHECKERBOARD GI (demi-cadence) ============
// OPTIMISATION : ne lance le ray-march cher (VOXEL_GI_SAMPLES rayons) que sur la MOITIE des
// pixels par frame (damier 2x2 alternant avec frameCounter). Les pixels "sautes" reutilisent
// l'historique temporel reprojete (colortex8/9 GI + colortex10 emissif) au lieu de relancer
// des rayons -> ~2x moins de rayons. Invisible car la GI est diffuse basse-frequence, accumulee
// (TAA_GI_FRAMES) et denoisee (a-trous) : le damier est masque. Un pixel saute SANS historique
// valide (disocclusion / 1ere frame / hors-ecran) ray-marche QUAND MEME (anti trou-noir).
// PORTE DE SECOURS : GI_CHECKERBOARD 0 => comportement EXACT d'avant (chaque pixel ray-marche).
// Slider (les toggles booleens ne s'affichent pas dans ce menu Iris), comme VOXEL_GI. Se cumule
// avec la baisse de VOXEL_GI_SAMPLES/VOXEL_GI_DISTANCE du profil RTX. NE PAS desactiver
// TEMPORAL_ACCUM ni GI_DENOISE avec ce mode : ce sont eux qui rendent le damier invisible.
#define GI_CHECKERBOARD 1 // [0 1]

// ============ DEBUG ============
#define DEBUG_VIEW 0 // [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24]
// R6 EAU : vue 23 = refl RGB final de l'eau (composite1, transporte via colortex5) ;
// vue 24 = R confiance SSR (hit) / G poids reflet (reflW) / B fresnel. Hors eau : albedo attenue.
// H: vues 19/20 = shadow map couleur / profondeur (final.fsh). 13/14 pris par composite6.
// R5 OMBRES : vue 21 = facteur d'ombre RECU par pixel (luma BRUT de sampleShadowPCF,
// recalcule dans gbuffers_terrain/entities, transporte via colortex5 et affiche TEL QUEL
// par final.fsh — aucun post-process). Vue 22 = classification du texel d'ombre au pixel
// recepteur (R6 tag-RGB) : BLANC eclaire, NOIR ombre opaque (occludeur dans shadowtex1),
// ROUGE bande SOLIDE tex0-only (le fix occulte pleinement ici — rouge sous poulet/sapling
// = ombre attendue en jeu), BLEU bande EAU, CYAN bande VERRE/PORTAIL, VERT bande solide
// a alpha<0.9 (ecriture partielle, occulte quand meme), JAUNE anomalie s0>s1, MAGENTA
// hors shadow map. BLANC sous une entite = profondeur ABSENTE de shadowtex0 (probleme
// emetteur Iris, pas le tag). Eau/mains : albedo inchange.
//#define DEBUG_SPLIT

// ============ DIVERS ============
#define MIN_LIGHT 0.0 // [0.0 0.005 0.01 0.02 0.03 0.05 0.08 0.12]
#define WAVING_FOLIAGE
#define WAVING_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0 12.0]
#define WAVING_SPEED 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0 12.0]
#define WAVING_WATER_PLANTS
#define SUBSURFACE_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0 5.0 8.0]
// Plancher d'ombre du feuillage : 0 = ombres dures (avant), 0.45 = douces, 0.75 = tres douces.
#define FOLIAGE_SHADOW_FLOOR 0.2 // [0.0 0.1 0.2 0.3 0.45 0.6 0.8 1.0]
// Force de l'ombre RECUE sous le feuillage (subsurface>0 uniquement) : 1.0 = ombre
// pleine/dense, 0.0 = comportement plancher seul (ancien). No-op EXACT hors feuillage.
#define FOLIAGE_SHADOW_STRENGTH 1.0 // [0.0 0.25 0.5 0.75 1.0]
// Teinte VERTE de l'ombre sous le feuillage (lumiere filtree par les feuilles).
// 0.0 = ombre neutre, 0.35 = verdit franchement les zones sombres, 1.0 = tres vert.
#define FOLIAGE_SHADOW_TINT 0.35 // [0.0 0.15 0.25 0.35 0.5 0.75 1.0]

// ============ [CONFIG] - CREATOR'S TUNING LAB ============
// Expert dials behind the main-menu CONFIG screen. EVERY default equals the
// exact current behavior: the pack renders identically until a slider moves.

// ---- Water seen from OUTSIDE (composite1 reference column) ----
// Per-channel multipliers of the aWat absorption: raising a channel kills
// that channel FASTER with depth (shallow-water tint, channel by channel).
#define WATER_ABSORB_R 1.0 // [0.25 0.5 0.75 1.0 1.25 1.5 2.0 2.5 3.0]
#define WATER_ABSORB_G 1.0 // [0.25 0.5 0.75 1.0 1.25 1.5 2.0 2.5 3.0]
#define WATER_ABSORB_B 1.0 // [0.25 0.5 0.75 1.0 1.25 1.5 2.0 2.5 3.0]
// Multiplies the 0.29 path-veil rate (how fast the floor dissolves).
#define WATER_VEIL_DENSITY 1.0 // [0.5 0.65 0.8 0.9 1.0 1.15 1.3 1.6 2.0]
// Veil hold-off in blocks of path: the first WATER_VEIL_START blocks stay
// veil-free (absorption untouched). 0.0 = veil from the first millimetre.
#define WATER_VEIL_START 0.0 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0 3.0]
// Multiplies the GGX alpha of the sun glint (size/softness of the sparkle
// lobe; intensity stays on WATER_SUN_GLINT).
#define WATER_GLINT_SIZE 1.0 // [0.25 0.5 0.75 1.0 1.5 2.0 3.0 4.0]
// Scales the MID-ANGLE Fresnel damper (0.95 * this): mirror presence at
// medium view angles; the grazing mirror is untouched (damper fades to 1).
#define WATER_MIRROR_ANGLE 1.0 // [0.5 0.65 0.8 0.9 1.0 1.15 1.3 1.6 2.0]
// Weight of the refracted-sun forward-scatter glow at sunset (glowW).
#define WATER_SCATTER_SUNSET 1.0 // [0.0 0.25 0.5 0.75 1.0 1.25 1.5 2.0]

// ---- Submerged eye (composite1 UW paths) ----
// Per-channel multipliers of the shared submerged-column in-scatter chroma
// (slate 0.19/0.42/0.72 x 0.80, three sites factored into SCAT_UW_BASE).
#define UW_FOG_R 1.0 // [0.25 0.5 0.75 1.0 1.25 1.5 2.0 2.5 3.0]
#define UW_FOG_G 1.0 // [0.25 0.5 0.75 1.0 1.25 1.5 2.0 2.5 3.0]
#define UW_FOG_B 1.0 // [0.25 0.5 0.75 1.0 1.25 1.5 2.0 2.5 3.0]
// Luminance of the eye-submerged fog color (wfogC light drive).
#define UW_FOG_BRIGHT 1.0 // [0.25 0.4 0.6 0.8 1.0 1.25 1.5 2.0]
// DIVIDES the eye-submerged fog density: higher = longer sight underwater.
#define UW_CLARITY 1.0 // [0.5 0.75 1.0 1.25 1.5 2.0 2.5 3.0]
// Strength of the caustic light dancing on the floor while submerged.
#define UW_CAUSTIC_LIGHT 1.0 // [0.0 0.25 0.5 0.75 1.0 1.25 1.5 2.0]

// ---- Time-of-day color grade (composite5, post-tonemap) ----
// 4 periods with CONTINUOUS weights: day/night from sun height, the twilight
// band split into dawn vs dusk by the MC clock (worldTime 0 = sunrise,
// 6000 = noon, 12000 = sunset, 18000 = midnight). Per period: TEMP warm/cool
// shift (R vs B), SAT saturation, BRIGHT multiplier. Applied as DELTAS from
// neutral -> all-default sliders leave the pixel bit-identical.
// TC_ENABLE 0 compiles the whole grade out.
#define TC_ENABLE 1 // [0 1]
#define TC_DAWN_TEMP 0.0 // [-1.0 -0.6 -0.3 -0.15 0.0 0.15 0.3 0.6 1.0]
#define TC_DAWN_SAT 1.0 // [0.5 0.7 0.85 0.95 1.0 1.05 1.15 1.3 1.5]
#define TC_DAWN_BRIGHT 1.0 // [0.7 0.8 0.9 0.95 1.0 1.05 1.1 1.2 1.3]
#define TC_DAY_TEMP 0.0 // [-1.0 -0.6 -0.3 -0.15 0.0 0.15 0.3 0.6 1.0]
#define TC_DAY_SAT 1.0 // [0.5 0.7 0.85 0.95 1.0 1.05 1.15 1.3 1.5]
#define TC_DAY_BRIGHT 1.0 // [0.7 0.8 0.9 0.95 1.0 1.05 1.1 1.2 1.3]
#define TC_DUSK_TEMP 0.0 // [-1.0 -0.6 -0.3 -0.15 0.0 0.15 0.3 0.6 1.0]
#define TC_DUSK_SAT 1.0 // [0.5 0.7 0.85 0.95 1.0 1.05 1.15 1.3 1.5]
#define TC_DUSK_BRIGHT 1.0 // [0.7 0.8 0.9 0.95 1.0 1.05 1.1 1.2 1.3]
#define TC_NIGHT_TEMP 0.0 // [-1.0 -0.6 -0.3 -0.15 0.0 0.15 0.3 0.6 1.0]
#define TC_NIGHT_SAT 1.0 // [0.5 0.7 0.85 0.95 1.0 1.05 1.15 1.3 1.5]
#define TC_NIGHT_BRIGHT 1.0 // [0.7 0.8 0.9 0.95 1.0 1.05 1.1 1.2 1.3]

// ============ FIX MENU IRIS (warnings "unable to resolve") ============
// Iris ne reconnait un #define booleen comme OPTION que s'il apparait dans AU MOINS
// un #ifdef/#ifndef simple quelque part dans le pack. Les usages composes
// ("#if defined X && defined Y", "#elif defined X") n'enregistrent PAS l'usage.
// VL_BLOCKLIGHT / ACES_TONEMAP / PBR_REFLECTIONS / PBR_POM n'etaient utilises QUE
// dans de tels composes (composite1:1207/1250, composite5:1515, composite1:557,
// gbuffers_terrain:30/221) -> "Unable to resolve ... menu element" au chargement.
// Ces 4 blocs vides sont des NO-OPS de compilation (aucun code genere) dont le seul
// role est d'enregistrer l'usage aupres du scanner d'options d'Iris. REVERSIBLE :
// supprimer ce bloc restaure exactement l'etat precedent (warnings compris).
#ifdef VL_BLOCKLIGHT
#endif
#ifdef ACES_TONEMAP
#endif
#ifdef PBR_REFLECTIONS
#endif
#ifdef PBR_POM
#endif
