float Tonemap_ACES(float x) {
    // Narkowicz 2015, "ACES Filmic Tone Mapping Curve"
    const float a = 2.51;
    const float b = 0.03;
    const float c = 2.43;
    const float d = 0.59;
    const float e = 0.14;
    return (x * (a * x + b)) / (x * (c * x + d) + e);
}

float Tonemap_Unreal(float x) {
    // Unreal 3, Documentation: "Color Grading"
    // Adapted to be close to Tonemap_ACES, with similar range
    // Gamma 2.2 correction is baked in, don't use with sRGB conversion!
    return x / (x + 0.155) * 1.019;
}

float Tonemap_Uchimura(float x, float P, float a, float m, float l, float c, float b) {
    // Uchimura 2017, "HDR theory and practice"
    // Math: <https://www.desmos.com/calculator/gslcdxvipg>
    // Source: <https://www.slideshare.net/nikuque/hdr-theory-and-practicce-jp>
    float l0 = ((P - m) * l) / a;
    float L0 = m - m / a;
    float L1 = m + (1.0 - m) / a;
    float S0 = m + l0;
    float S1 = m + a * l0;
    float C2 = (a * P) / (P - S1);
    float CP = -C2 / P;

    float w0 = 1.0 - smoothstep(0.0, m, x);
    float w2 = step(m + l0, x);
    float w1 = 1.0 - w0 - w2;

    float T = m * pow(x / m, c) + b;
    float S = P - (P - S1) * exp(CP * (x - S0));
    float L = m + a * (x - m);

    return T * w0 + L * w1 + S * w2;
}

float Tonemap_Uchimura(float x) {
    const float P = 1.0;  // max display brightness
    const float a = 1.0;  // contrast
    const float m = 0.22; // linear section start
    const float l = 0.4;  // linear section length
    const float c = 1.33; // black
    const float b = 0.0;  // pedestal
    return Tonemap_Uchimura(x, P, a, m, l, c, b);
}

float Tonemap_Lottes(float x) {
    // Lottes 2016, "Advanced Techniques and Optimization of HDR Color Pipelines"
    const float a = 1.6;
    const float d = 0.977;
    const float hdrMax = 8.0;
    const float midIn = 0.18;
    const float midOut = 0.267;

    // Can be precomputed
    const float b =
        (-pow(midIn, a) + pow(hdrMax, a) * midOut) /
        ((pow(hdrMax, a * d) - pow(midIn, a * d)) * midOut);
    const float c =
        (pow(hdrMax, a * d) * pow(midIn, a) - pow(hdrMax, a) * pow(midIn, a * d) * midOut) /
        ((pow(hdrMax, a * d) - pow(midIn, a * d)) * midOut);

    return pow(x, a) / (pow(x, a * d) * b + c);
}

float Tonemap_Simple(float x) {
    float exposure = 1.0f;
    return x/(x + exposure);

}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = fragCoord.xy / (iResolution.y * 0.8);
    uv.x += iMouse.x / iResolution.x * 9.0;

    float p = 1.0 / (iResolution.y * 0.8);
    float y = 0.0;

    // Show LDR range (thanks iq)
    fragColor.rgb = vec3(0.02) * step(uv.x, 1.0);

    y = Tonemap_Uchimura(uv.x);
    fragColor.rgb = mix(fragColor.rgb, vec3(1.0, 0.5, 0.0), 1.0 - smoothstep(0.0, 2.0 * p, abs(uv.y - y)));

    y = Tonemap_Uchimura(uv.x, 1.0, 1.7, 0.1, 0.0, 1.33, 0.0);
    fragColor.rgb = mix(fragColor.rgb, vec3(0.8, 0.2, 0.6), 1.0 - smoothstep(0.0, 2.0 * p, abs(uv.y - y)));

    y = Tonemap_ACES(uv.x);
    fragColor.rgb = mix(fragColor.rgb, vec3(0.8, 0.8, 0.0), 1.0 - smoothstep(0.0, 2.0 * p, abs(uv.y - y)));

    y = pow(Tonemap_Unreal(uv.x), 2.2);
    fragColor.rgb = mix(fragColor.rgb, vec3(0.0, 0.6, 0.1), 1.0 - smoothstep(0.0, 2.0 * p, abs(uv.y - y)));

    y = Tonemap_Lottes(uv.x);
    fragColor.rgb = mix(fragColor.rgb, vec3(0.0, 0.6, 0.8), 1.0 - smoothstep(0.0, 2.0 * p, abs(uv.y - y)));

    
    y = Tonemap_Simple(uv.x);
    fragColor.rgb = mix(fragColor.rgb, vec3(1.0, 1.0, 1.0), 1.0 - smoothstep(0.0, 1.0 * p, abs(uv.y - y)));
    
    y = 1.0;
    fragColor.rgb = mix(fragColor.rgb, vec3(1.0, 1.0, 1.0), 1.0 - smoothstep(0.0, 1.0 * p, abs(uv.y - y)));
    
    
    
    fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2));
}