in vec2 uv;
in vec2 uvn;

out vec4 C;

uniform int taa_tex;
uniform int prev_gi_tex;
uniform int gi_tex;
uniform int depth_tex;
uniform int pt_light;


#define SPAN_MAX   (8.0)
#define REDUCE_MIN (1.0/128.0)
#define REDUCE_MUL (1.0/32.0)

vec4 tex_tonemapped(sampler2D tex, vec2 uv);
vec4 FXAA(sampler2D tex, vec2 uv) {
    vec2 size = R;
    vec2 px = 1.0 / size;
    vec3 col   = tex_tonemapped(tex, uv).rgb;
    vec3 col00 = tex_tonemapped(tex, uv + vec2(-0.5) * px).rgb;
    vec3 col11 = tex_tonemapped(tex, uv + vec2( 0.5) * px).rgb;
    vec3 col10 = tex_tonemapped(tex, uv + vec2(0.5, -0.5) * px).rgb;
    vec3 col01 = tex_tonemapped(tex, uv + vec2(-0.5, 0.5) * px).rgb;

    float lum = luma(col);
    float lum00 = luma(col00);
    float lum11 = luma(col11);
    float lum10 = luma(col10);
    float lum01 = luma(col01);

    vec2 dir = vec2((lum01 + lum11) - (lum00 + lum10),
    (lum00 + lum01) - (lum10 + lum11));

    float dirReduce = max((lum00 + lum10 + lum01 + lum11) * REDUCE_MUL, REDUCE_MIN);

    float rcpDir = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);

    dir = clamp(dir * rcpDir, -SPAN_MAX, SPAN_MAX) * px;

    vec4 A = 0.5 * (
    tex_tonemapped(tex, uv - dir * (1.0/6.0)) +
    tex_tonemapped(tex, uv + dir * (1.0/6.0)));

    vec4 B = A * 0.5 + 0.25 * (
    tex_tonemapped(tex, uv - dir * 0.5) +
    tex_tonemapped(tex, uv + dir * 0.5));

    float lumMin = min(lum, min(min(lum00, lum10), min(lum01, lum11)));
    float lumMax = max(lum, max(max(lum00, lum10), max(lum01, lum11)));

    float lumB = luma(B.rgb);

    return ((lumB < lumMin) || (lumB > lumMax)) ? A : B;
}
#define AGX_LOOK 0

// AgX
// ->

// Mean error^2: 3.6705141e-06
//vec3 agxDefaultContrastApprox(vec3 x) {
//}

vec3 agx(vec3 val) {
    const mat3 agx_mat = mat3(
    0.842479062253094, 0.0423282422610123, 0.0423756549057051,
    0.0784335999999992,  0.878468636469772,  0.0784336,
    0.0792237451477643, 0.0791661274605434, 0.879142973793104);

    const float min_ev = -12.47393f;
    const float max_ev = 4.026069f;

    // Input transform
    val = agx_mat * val;

    // Log2 space encoding
    val = clamp(log2(val), min_ev, max_ev);
    val = (val - min_ev) / (max_ev - min_ev);


    vec3 x = val;
    vec3 x2 = x * x;
    vec3 x4 = x2 * x2;

    val = + 15.5 * x4 * x2
    - 40.14 * x4 * x
    + 31.96 * x4
    - 6.868 * x2 * x
    + 0.4298 * x2
    + 0.1191 * x
    - 0.00232;


    const vec3 lw = vec3(0.2126, 0.7152, 0.0722);
    float luma = dot(val, lw);

    // Default
    vec3 offset = vec3(0.0);

    vec3 slope = vec3(1.0);
    vec3 power = vec3(1., 1., 1.)*1.4;
    float sat = 1.5;

    val = pow(val * slope + offset, power);
    return luma + sat * (val - luma);

    return val;
}

vec3 agxEotf(vec3 val) {
    const mat3 agx_mat_inv = mat3(
    1.19687900512017, -0.0528968517574562, -0.0529716355144438,
    -0.0980208811401368, 1.15190312990417, -0.0980434501171241,
    -0.0990297440797205, -0.0989611768448433, 1.15107367264116);

    // Undo input transform
    val = agx_mat_inv * val;

    // sRGB IEC 61966-2-1 2.2 Exponent Reference EOTF Display
//    val = pow(val, vec3(2.2));

    return val;
}


vec4 tex_tonemapped(sampler2D tex, vec2 _uv){
    vec4 C = texture(tex,_uv);
    C.rgb = agx(C.rgb);
    C.rgb = agxEotf(C.rgb);
    C = max(C,0.);
    return C;
}
//vec3 agxLook(vec3 val) {
//}


void main(){

    imageStore(
        f_images[prev_gi_tex],
        ivec2(gl_FragCoord),
//        imageLoad(f_images[gi_tex], ivec2(gl_FragCoord))
        texelFetch(textures[gi_tex], ivec2(gl_FragCoord),0)
    );
//    C = tex(taa_tex, uvn);

    C = tex_tonemapped(textures[taa_tex], uvn);

//    vec3 srgb_to_oklch( in vec3 c ) { return lab2lch(srgb2oklab(c)); }
//    vec3 oklch_to_srgb( in vec3 c ) { return oklab2srgb(lch2lab(c)); }
//    return;

    vec4 fxaa_col = FXAA(textures[taa_tex], uvn);

    vec3 cmin = vec3(100);
    vec3 cmax = vec3(-100);
    for(int x = -1; x <= 1; x++){
        for(int y = -1; y <= 1; y++){
            cmin = min(cmin, texFetch(taa_tex, U + vec2(x,y)).xyz);
            cmax = max(cmax, texFetch(taa_tex, U + vec2(x,y)).xyz);
        }
    }

    float fac = smoothstep(0.2,0.9,abs(luma(cmin)-luma(cmax)));
//    fac = 1.0;
//    fac = 0.0;
//    fac = 1.0;
    C = mix(C,fxaa_col, fac);
    

    if(fac > 0.1){
//        C.r = 1.0;
    }


    vec3 ro;
    vec3 rd;
    get_ro_and_rd(ro, rd, uv, false);
//
//    C.rgb = rd*0.5 + 0.5;
//    C = max(C,0.0);
//    C.rgb = agxLook(C.rgb);
//    C = tex_tonemapped(textures[taa_tex], uvn);

//    C.xyz = fract(texture(textures_cube[light_textures[1]], rd).xxx*10.0);
//    C.xyz = texture(textures_cube[light_textures[3]], rd).xxx*1.0;
    //    C.xyz = fract(texture(textures[light_textures[0]], uvn).xxx*1.0);
    if(dbg_frag(vec2(200,200))){
        print(C.xyz);
    }


    C = max(C,0.0);
    C.rgb += h33(vec3(uv*100,fract(T)))*0.01;

    C *= 1.-dot(uv,uv)*0.34;

    C = pow(max(C,0.),vec4(0.45454545));
    //	C += 40.;
    C.a = 1.0;
//    C.x = fract(
//        texture(textures[depth_tex], uvn).x
//    );
//    C += 0.4;
//    C.xyz = fract(texelFetch(textures_cube[pt_light], uvec2(U),0).xxx*1000.0);

    if(dbg_frag(ivec2(200,200))){
//        print(mouse_ndc);
//        print(mouse_uv);
    }

//    C.rgb = vec3(0);
    // ------- storage
    uint dbg = imageLoad(u32_images[dbg_tex], ivec2(gl_FragCoord)).x;
    if(dbg != 0){
        C.rgb = vec3(0);
        C.r = 1.0;
//        C.rgb = 1.-C.rgb;
//        C.rgb = mix(vec3(0,1,0), C.rgb, smoothstep(0.1,0.3, length(C.rgb - vec3(0.5))));
//        C += float(dbg);
    }

//    C.rgb = textureLod(textures[hdri_tex],fract(uvn), 4).rgb*1.0;
//    C = vec4(1,1,1,1);
}
