/*
====================================================================
  SXGG: Realis — Shader ultra-realistica per Minecraft
  Autore : Samax.GG
  File   : lib/water.glsl
  Modulo : 3 — Onde procedurali (somma di Gerstner semplificate + FBM),
           normali dell'acqua, assorbimento, SSR raymarch.

  Richiede: lib/common.glsl, lib/noise.glsl, lib/settings.glsl
====================================================================
*/

#ifndef WATER_GLSL
#define WATER_GLSL

// --- Altezza dell'onda in un punto del mondo ---
float waterHeight(vec2 pos, float time) {
    float t = time * WAVE_SPEED;
    float h = 0.0;
    // Due treni d'onda direzionali non allineati
    h += sin(dot(pos, vec2(0.16, 0.23)) * 4.0 + t * 1.4) * 0.30;
    h += sin(dot(pos, vec2(-0.21, 0.14)) * 6.5 + t * 1.9) * 0.18;
    // Chop irregolare FBM
    h += fbm2D(pos * 0.65 + vec2(t * 0.35, t * 0.28)) * 0.55;
    h += fbm2D(pos * 1.60 - vec2(t * 0.22, t * 0.40)) * 0.28;
    return h * 0.045 * WAVE_HEIGHT;
}

// --- Normale via differenze finite ---
vec3 waterNormal(vec2 pos, float time) {
    const float e = 0.08;
    float hC = waterHeight(pos, time);
    float hX = waterHeight(pos + vec2(e, 0.0), time);
    float hZ = waterHeight(pos + vec2(0.0, e), time);
    return normalize(vec3(hC - hX, e, hC - hZ));
}

/*
  Assorbimento: Beer-Lambert. L'acqua assorbe prima il rosso,
  poi il verde: profonda = blu scuro/torbida.
  waterDepth in blocchi.
*/
vec3 waterAbsorption(vec3 color, float waterDepth) {
    vec3 absorbCoeff = vec3(0.45, 0.12, 0.06) * WATER_ABSORPTION;
    vec3 transmit = exp(-absorbCoeff * waterDepth);
    // Scattering interno: vira al turchese scuro in profondità
    vec3 scatterColor = vec3(0.02, 0.10, 0.12);
    return mix(scatterColor, color, transmit);
}

/*
  Screen Space Reflections: raymarch nel depth buffer.
  viewPos/reflDir in view space. Ritorna rgb + confidenza in a.
  Richiede uniform: depthtex1, colortex0 (definiti nel chiamante),
  gbufferProjection.
*/
vec4 raytraceSSR(vec3 viewPos, vec3 reflDir, float dither,
                 sampler2D depthTex, sampler2D colorTex, mat4 proj) {
    #ifndef WATER_SSR
        return vec4(0.0);
    #endif

    // Step iniziale proporzionale alla distanza
    float stepLen = max(0.1, length(viewPos) * 0.04);
    vec3 rayPos = viewPos + reflDir * stepLen * dither;

    for (int i = 0; i < SSR_STEPS; i++) {
        rayPos += reflDir * stepLen;
        vec3 screenPos = viewToScreen(rayPos, proj);

        // Fuori schermo: fallback (cielo) gestito dal chiamante
        if (screenPos.x < 0.0 || screenPos.x > 1.0 ||
            screenPos.y < 0.0 || screenPos.y > 1.0 || screenPos.z > 1.0)
            return vec4(0.0);

        float sceneDepth = texture2D(depthTex, screenPos.xy).r;

        if (sceneDepth < screenPos.z) {
            // Colpito: raffina con 4 step binari
            vec3 halfStep = reflDir * stepLen * 0.5;
            for (int j = 0; j < 4; j++) {
                screenPos = viewToScreen(rayPos, proj);
                sceneDepth = texture2D(depthTex, screenPos.xy).r;
                rayPos += (sceneDepth < screenPos.z) ? -halfStep : halfStep;
                halfStep *= 0.5;
            }
            screenPos = viewToScreen(rayPos, proj);

            // Scarta hit troppo lontani dietro la superficie (ghosting)
            float depthDelta = abs(linearizeDepth(sceneDepth, 0.05, 256.0)
                             - linearizeDepth(screenPos.z, 0.05, 256.0));
            if (depthDelta > 0.05) return vec4(0.0);

            // Confidenza: sfuma ai bordi dello schermo
            vec2 edge = abs(screenPos.xy - 0.5) * 2.0;
            float conf = saturate(1.0 - pow(max(edge.x, edge.y), 8.0));
            return vec4(texture2D(colorTex, screenPos.xy).rgb, conf);
        }
        stepLen *= 1.18;   // step esponenziale: copre lunghe distanze
    }
    return vec4(0.0);
}

/*
  Maschera pozzanghere/bagnato per la pioggia (Modulo 3).
  Ritorna 0..1: quanto il punto è bagnato.
  wetness = uniform di OptiFine che sale gradualmente quando piove.
*/
float wetnessMask(vec3 worldPos, vec3 worldNormal, float wetness, float skyLight) {
    #ifndef WET_SURFACES
        return 0.0;
    #endif
    // Solo superfici esposte al cielo, prevalentemente orizzontali
    float exposure = smoothstep(0.85, 1.0, skyLight) * saturate(worldNormal.y);
    float wet = wetness * exposure;

    #ifdef PUDDLES
        // Pozzanghere: FBM a bassa frequenza, soglia con la wetness
        float puddle = fbm2D(worldPos.xz * 0.35);
        puddle = smoothstep(0.62 - wetness * 0.20, 0.72, puddle);
        wet = max(wet * 0.55, puddle * exposure);
    #endif

    return saturate(wet);
}

#endif // WATER_GLSL
