#include "/prelude/core.glsl"

// --- TOGGLEABLE FEATURES ---
#define EXPOSURE 0.00 // [-1.00 -0.95 -0.90 -0.85 -0.80 -0.75 -0.70 -0.65 -0.60 -0.55 -0.50 -0.45 -0.40 -0.35 -0.30 -0.25 -0.20 -0.15 -0.10 -0.05 0.00 0.05 0.10 0.15 0.20 0.25 0.30 0.35 0.40 0.45 0.50 0.55 0.60 0.65 0.70 0.75 0.80 0.85 0.90 0.95 1.00]
#define VIBRANCE 0.00 // [-1.00 -0.95 -0.90 -0.85 -0.80 -0.75 -0.70 -0.65 -0.60 -0.55 -0.50 -0.45 -0.40 -0.35 -0.30 -0.25 -0.20 -0.15 -0.10 -0.05 0.00 0.05 0.10 0.15 0.20 0.25 0.30 0.35 0.40 0.45 0.50 0.55 0.60 0.65 0.70 0.75 0.80 0.85 0.90 0.95 1.00]
#define UNDERWATER_VIGNETTE 1 // [0 1]

#if ANTIALIASING == 1
    #define SMAA_ENABLED
#endif

layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
const vec2 workGroupsRender = vec2(1.0, 1.0);

uniform sampler2D colortex0;
uniform layout(rg8) restrict writeonly image2D edge;
uniform layout(rgba16) restrict writeonly image2D tempCol;

uniform int isEyeInWater; // 1 if underwater, 0 if not
uniform vec2 pixSize;     // Screen resolution info

float redmeanSq(vec3 a, vec3 b) {
	immut float r = step(0.5, mix(a.r, b.r, 0.5));
	immut vec3 d = a - b;
	return dot(d*d, vec3(2.0 + r, 4.0, 3.0 - r));
}

void main() {
	immut ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
	immut vec3 color = texelFetch(colortex0, texel, 0).rgb;

    vec3 adjustedColor = color;
    adjustedColor *= (1.0 + EXPOSURE);
    float l = dot(adjustedColor, vec3(0.2126, 0.7152, 0.0722));
    adjustedColor = mix(vec3(l), adjustedColor, 1.0 + VIBRANCE);

    #if UNDERWATER_VIGNETTE == 1
    if (isEyeInWater == 1) {
        vec2 uv = (vec2(texel) + 0.5) * pixSize;
        float dist = distance(uv, vec2(0.5));
        float vignetteStrength = smoothstep(0.15, 0.85, dist);
        vec3 deepBlue = vec3(0.02, 0.15, 0.5); 
        adjustedColor = mix(adjustedColor, deepBlue * l, vignetteStrength * 0.85);
    }
    #endif

	imageStore(tempCol, texel, vec4(linear(adjustedColor), 0.0));

#ifdef SMAA_ENABLED
	immut vec3 left = texelFetchOffset(colortex0, texel, 0, ivec2(-1, 0)).rgb;
	immut vec3 top = texelFetchOffset(colortex0, texel, 0, ivec2(0, -1)).rgb;

	vec4 delta;
	delta.xy = vec2(redmeanSq(color, left), redmeanSq(color, top));

    const float THRESHOLD_SQ = SMAA_THRESHOLD * SMAA_THRESHOLD;
	immut bvec2 edges = greaterThanEqual(delta.xy, vec2(THRESHOLD_SQ));

	if (any(edges)) {
		delta.zw = vec2(
			redmeanSq(color, texelFetchOffset(colortex0, texel, 0, ivec2(1, 0)).rgb),
			redmeanSq(color, texelFetchOffset(colortex0, texel, 0, ivec2(0, 1)).rgb)
		);
		vec2 delta_max = max(delta.xy, delta.zw);
		delta.zw = vec2(
			redmeanSq(left, texelFetchOffset(colortex0, texel, 0, ivec2(-2, 0)).rgb),
			redmeanSq(top, texelFetchOffset(colortex0, texel, 0, ivec2(0, -2)).rgb)
		);
		delta_max = max(delta_max.xy, delta.zw);

		const float local_contrast_factor_sq = 4.0;
		immut bvec2 temp = greaterThanEqual(delta.xy, (max(delta_max.x, delta_max.y) / local_contrast_factor_sq).xx);
		immut bvec2 result = bvec2(edges.x && temp.x, edges.y && temp.y);

		if (any(result)) imageStore(edge, texel, vec4(result, 0.0, 0.0));
	}
#endif
}