#define WATER_NOISE_BUFFER waterNoise

vec3 change_flow_dir(vec3 Coords, vec3 WorldNormal) {
    Coords.xz -= frameTimeCounter * normalize(WorldNormal.xz) * 5 * (1 - pow2(WorldNormal.y));
    return Coords;
}

float get_water_height(vec3 WorldPos) {
    vec2 Coords = WorldPos.xz + WorldPos.y;
    float color = texture(WATER_NOISE_BUFFER, (Coords - frameTimeCounter * 0.7) / 8).x * 0.2;
    Coords.y += sin(Coords.x / 12) * 2;
    color += texture(WATER_NOISE_BUFFER, (Coords + frameTimeCounter * 0.4) / 24).x * 0.3;
    Coords.y += cos(Coords.x / 20) * 2.5;
    color += texture(WATER_NOISE_BUFFER, (Coords + frameTimeCounter * 0.6) / 32).x * 0.5;
    return (color - 0.5) * 3;
}

vec2 get_water_height_d(vec3 WorldPos) {
    vec2 Coords = WorldPos.xz + WorldPos.y;
    vec2 color = (texture(WATER_NOISE_BUFFER, (Coords - frameTimeCounter * 0.7) / 8).yz * 2 - 1) * 0.2;
    Coords.y += sin(Coords.x / 12) * 2.5;
    color += (texture(WATER_NOISE_BUFFER, (Coords + frameTimeCounter * 0.4) / 24).yz * 2 - 1) * 0.3;
    Coords.y += cos(Coords.x / 20) * 2;
    color += (texture(WATER_NOISE_BUFFER, (Coords + frameTimeCounter * 0.6) / 32).yz * 2 - 1) * 0.5;
    return color * 2;
}

vec3 get_water_normal(vec3 Coords, vec3 WorldNormal, float Dist) {
    Coords = change_flow_dir(Coords, WorldNormal);
    vec2 H = get_water_height_d(Coords); // * pow(max(1+Dist/128, 0), 4);

    return normalize(vec3(H.x, H.y, 1 - (H.x * H.x + H.y * H.y)));
}

float get_water_caustics(vec3 PlayerPos) {
    vec3 WorldPos = PlayerPos + cameraPosition;
    vec3 slpP = view_player(sLightPosN);
    vec3 PlayerPosS = WorldPos - slpP / slpP.y * WorldPos.y;
    float WaterHeight = get_water_height(PlayerPosS);
    float CausticsColor = 3 * exp(-abs(WaterHeight) * 10) + 0.5;
    return CausticsColor;
}

// Water scattering as described in https://gpuopen.com/gdc-presentations/2019/gdc-2019-agtd6-interactive-water-simulation-in-atlas.pdf#page=52
vec3 get_water_scattering(vec3 V, vec3 Normal, vec3 SunD, vec3 WaterColor) {
    const float k1 = 0.2;
    const float k2 = 0.4;
    const float k3 = 0.3;

    float LScatter = k1 * pow4(max(0, dot(-V, sLightPosN))) * pow((0.5 - 0.5 * dot(sLightPosN, Normal)), 3);
    LScatter += k2 * pow2(max(0, dot(V, Normal)));
    vec3 WaterFinal = LScatter * WaterColor * SunD;
    WaterFinal += k3 * max(0, dot(sLightPosN, Normal)) * SunD * WaterColor;

    return WaterFinal;
}
