#version 450


layout(location = 0) out vec4 fragColor;
layout(location = 0) in vec2 inUV;

layout(set = 1, binding = 0) uniform sampler2D inHdr;
layout(set = 1, binding = 1) uniform sampler2D inBloom;

layout( push_constant ) uniform constants
{
    float exposure;
    float gamma;
} PushConstants;

const mat3x3 ACESInputMat =
{
    {0.59719, 0.35458, 0.04823},
    {0.07600, 0.90834, 0.01566},
    {0.02840, 0.13383, 0.83777}
};

// ODT_SAT => XYZ => D60_2_D65 => sRGB
const mat3x3 ACESOutputMat =
{
    { 1.60475, -0.53108, -0.07367},
    {-0.10208,  1.10813, -0.00605},
    {-0.00327, -0.07276,  1.07602}
};

vec3 RRTAndODTFit(vec3 v)
{
    vec3 a = v * (v + 0.0245786f) - 0.000090537f;
    vec3 b = v * (0.983729f * v + 0.4329510f) + 0.238081f;
    return a / b;
}

vec3 ACESFitted(vec3 color)
{
    color = transpose(ACESInputMat) * color;

    // Apply RRT and ODT
    color = RRTAndODTFit(color);

    color = transpose(ACESOutputMat) * color;

    // Clamp to [0, 1]
    color = clamp(color, vec3(0.0f), vec3(1.0f));

    return color;
}

vec4 upscale() {
    vec2 srcTexelSize = 1.0f / vec2(1200, 800) * 2.0f;
    float x = srcTexelSize.x;
    float y = srcTexelSize.y;

    vec3
    color  = texture(inBloom, vec2(inUV.x + x, inUV.y + y)).rgb;
    color += texture(inBloom, vec2(inUV.x + x, inUV.y - y)).rgb;
    color += texture(inBloom, vec2(inUV.x - x, inUV.y + y)).rgb;
    color += texture(inBloom, vec2(inUV.x - x, inUV.y - y)).rgb;

    color += 2.0f * texture(inBloom, vec2(inUV.x + x, inUV.y)).rgb;
    color += 2.0f * texture(inBloom, vec2(inUV.x - x, inUV.y)).rgb;
    color += 2.0f * texture(inBloom, vec2(inUV.x, inUV.y + y)).rgb;
    color += 2.0f * texture(inBloom, vec2(inUV.x, inUV.y - y)).rgb;

    color += 4.0f * texture(inBloom, inUV).rgb;

    return vec4(color * (1.0f / 16.0f), 1.0f);
}

void main() {

    vec3 color = ACESFitted(texture(inHdr, inUV).rgb * PushConstants.exposure + upscale().rgb);

    color = pow(color.rgb, vec3(1.0/PushConstants.gamma));

    fragColor = vec4(color, 1.0);
}