/***********************************************/
/*           Copyright (c) 2025 Belmu          */
/*             All Rights Reserved             */
/***********************************************/

float gerstnerWaves(vec2 coords, float time, float steepness, float amplitude, float lambda, vec2 direction) {
    const float g = 9.81; // Earth's gravity constant

    float k = TAU / lambda;
    float x = (sqrt(g * k)) * time - k * dot(direction, coords);

    return amplitude * pow(sin(x) * 0.5 + 0.5, steepness);
}

float calculateWaveHeightGerstner(vec2 position, int octaves) {
    float height = 0.0;

    float speed     = 1.2;
    float time      = 1.0;
    float steepness = WAVE_STEEPNESS;
    float amplitude = WAVE_AMPLITUDE;
    float lambda    = WAVE_LENGTH;

    const float angle   = TAU * 0.4;
    const mat2 rotation = mat2(cos(angle), -sin(angle), sin(angle), cos(angle));

    vec2 direction = vec2(0.786, 0.352);

    for (int i = 0; i < octaves; i++) {
        float noise   = FBM(position * inversesqrt(lambda) - (speed * direction), 3, 0.3);
              height -= gerstnerWaves(position +  vec2(noise, -noise) * sqrt(lambda), time, steepness, amplitude, lambda, direction) - noise * amplitude;

        steepness *= 1.02;
        amplitude *= 0.83;
        lambda    *= 0.85;
        direction *= rotation;
    }
    return height;
}

const vec2 offset = vec2(0.05, 0.0);

vec3 getWaterNormals(vec3 worldPos, int octaves) {
    vec2 position = worldPos.xz;

    float pos0 = calculateWaveHeightGerstner(position,             WATER_OCTAVES);
    float pos1 = calculateWaveHeightGerstner(position + offset.xy, WATER_OCTAVES);
    float pos2 = calculateWaveHeightGerstner(position + offset.yx, WATER_OCTAVES);

    return vec3(pos0 - pos1, pos0 - pos2, 1.0);
}
