#version 330 core
out vec4 FragColor;
uniform vec3 iResolution;
uniform float iTime;
uniform float uAlpha;
uniform sampler2D iChannel0;

// UnderWater shader converted

mat2 rotate2d(float a){
    return mat2(cos(a), -sin(a), sin(a), cos(a));
}

float hash(vec2 p) {
    p = fract(p * vec2(123.34, 456.21));
    p += dot(p, p + 45.32);
    return fract(p.x * p.y);
}

float noise(vec2 p) {
    vec2 i = floor(p);
    vec2 f = fract(p);
    f = f * f * (3.0 - 2.0 * f);
    float a = hash(i);
    float b = hash(i + vec2(1.0, 0.0));
    float c = hash(i + vec2(0.0, 1.0));
    float d = hash(i + vec2(1.0, 1.0));
    return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
}

float caustics(vec2 p, float t) {
    p *= 4.0;
    float c = 0.0;
    float amp = 1.0;
    for (int i = 0; i < 4; i++) {
        vec2 q = p + vec2(cos(t + p.y), sin(t + p.x));
        c += noise(q) * amp;
        p *= 2.1;
        amp *= 0.5;
        t *= 1.2;
    }
    c = pow(c, 4.0);
    return c * 1.5;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord / iResolution.xy;
    float t = iTime * 0.5;
    vec2 distuv = uv;
    float strength = 0.015;
    distuv.x += sin(uv.y * 10.0 + t * 2.0) * strength;
    distuv.y += cos(uv.x * 12.0 - t * 1.8) * strength;
    distuv += (vec2(noise(uv * 15.0 + t), noise(uv * 18.0 - t)) - 0.5) * 0.005;
    vec3 texColor = texture(iChannel0, distuv).rgb;
    float lightPatters = caustics(uv + distuv * 0.1, t);
    vec3 colorWithLight = texColor + vec3(lightPatters * 0.3);
    vec3 waterTint = vec3(0.4, 0.9, 1.0);
    vec3 finalCol = mix(colorWithLight, colorWithLight * waterTint, 0.6);
    finalCol *= smoothstep(1.2, -0.2, uv.y);
    finalCol.b += 0.05;
    // apply tanh tone mapping
    vec3 tone = vec3((exp(finalCol.r)-exp(-finalCol.r))/(exp(finalCol.r)+exp(-finalCol.r)),
                     (exp(finalCol.g)-exp(-finalCol.g))/(exp(finalCol.g)+exp(-finalCol.g)),
                     (exp(finalCol.b)-exp(-finalCol.b))/(exp(finalCol.b)+exp(-finalCol.b)));
    fragColor = vec4(tone, 1.0);
}

void main(){ mainImage(FragColor, gl_FragCoord.xy); FragColor.a *= uAlpha; }
