/*
 * Bloom - downsampling step
 * "Next Generation Post Processing in Call of Duty Advanced Warfare"
 *      ACM Siggraph (2014)
 * Based on the implementation by Alexander Christensen
 * https://learnopengl.com/Guest-Articles/2022/Phys.-Based-Bloom
 */

#version 330 core

layout(location = 0) out vec3 fragColor;

in vec2 texcoord;

uniform sampler2D tex;
uniform bool is_first_downsample;

// color.glsl
float linear_srgb_to_luminance(vec3 color);
vec3 eotf_sRGB(vec3 linear_srgb);

float karis_average(vec3 color)
{
    return 1.0 / (1.0 + linear_srgb_to_luminance(color));
}

void main()
{
    vec2 texel_size = 1.0 / vec2(textureSize(tex, 0));
    float x = texel_size.x;
    float y = texel_size.y;

    // Take 13 samples around current texel
    // a - b - c
    // - j - k -
    // d - e - f
    // - l - m -
    // g - h - i
    // === ('e' is the current texel) ===
    vec3 a = texture(tex, vec2(texcoord.x - 2*x, texcoord.y + 2*y)).rgb;
    vec3 b = texture(tex, vec2(texcoord.x,       texcoord.y + 2*y)).rgb;
    vec3 c = texture(tex, vec2(texcoord.x + 2*x, texcoord.y + 2*y)).rgb;

    vec3 d = texture(tex, vec2(texcoord.x - 2*x, texcoord.y)).rgb;
    vec3 e = texture(tex, vec2(texcoord.x,       texcoord.y)).rgb;
    vec3 f = texture(tex, vec2(texcoord.x + 2*x, texcoord.y)).rgb;

    vec3 g = texture(tex, vec2(texcoord.x - 2*x, texcoord.y - 2*y)).rgb;
    vec3 h = texture(tex, vec2(texcoord.x,       texcoord.y - 2*y)).rgb;
    vec3 i = texture(tex, vec2(texcoord.x + 2*x, texcoord.y - 2*y)).rgb;

    vec3 j = texture(tex, vec2(texcoord.x - x, texcoord.y + y)).rgb;
    vec3 k = texture(tex, vec2(texcoord.x + x, texcoord.y + y)).rgb;
    vec3 l = texture(tex, vec2(texcoord.x - x, texcoord.y - y)).rgb;
    vec3 m = texture(tex, vec2(texcoord.x + x, texcoord.y - y)).rgb;

    vec3 downsample;
    if (is_first_downsample) {
        // Apply Karis average to each block of 4 samples to prevent fireflies.
        // Only done on the first downsampling step.
        vec3 group0 = (a+b+d+e) * 0.25;
        vec3 group1 = (b+c+e+f) * 0.25;
        vec3 group2 = (d+e+g+h) * 0.25;
        vec3 group3 = (e+f+h+i) * 0.25;
        vec3 group4 = (j+k+l+m) * 0.25;
        float kw0 = karis_average(group0);
        float kw1 = karis_average(group1);
        float kw2 = karis_average(group2);
        float kw3 = karis_average(group3);
        float kw4 = karis_average(group4);
        float kw_sum = kw0 + kw1 + kw2 + kw3 + kw4;
        downsample =
            kw0 * group0 +
            kw1 * group1 +
            kw2 * group2 +
            kw3 * group3 +
            kw4 * group4;
        downsample /= kw_sum;
    } else {
        downsample = e*0.125;
        downsample += (a+c+g+i)*0.03125;
        downsample += (b+d+f+h)*0.0625;
        downsample += (j+k+l+m)*0.125;
    }

    fragColor = downsample;
}