/***********************************************/
/*           Copyright (c) 2025 Belmu          */
/*             All Rights Reserved             */
/***********************************************/

#include "/settings.glsl"

#if defined DOWNSAMPLE_PASS
    const int lod = DOWNSAMPLE_PASS_INDEX;
#elif defined UPSAMPLE_PASS
    const int lod = UPSAMPLE_PASS_INDEX;
#endif

const float lodFactor = exp2(-lod); 

#if defined STAGE_VERTEX

    void main() {
        vec2 tileCoords = gl_Vertex.xy * lodFactor * 0.5 + 1.0 - lodFactor;

        gl_Position = vec4(tileCoords * 2.0 - 1.0, 0.0, 1.0);
    }

#elif defined STAGE_FRAGMENT

    /* RENDERTARGETS: 3 */

    layout (location = 0) out vec4 downsampled;

    #include "/include/uniforms.glsl"

    #include "/include/utility/math.glsl"

    #if defined DOWNSAMPLE_PASS

        const vec2 filterOffsets[12] = vec2[12](
            vec2( 1.0,  1.0),
            vec2(-1.0,  1.0),
            vec2( 1.0, -1.0),
            vec2(-1.0, -1.0),

            vec2( 0.0,  2.0),
            vec2( 0.0, -2.0),
            vec2( 2.0,  0.0),
            vec2(-2.0,  0.0),

            vec2( 2.0,  2.0),
            vec2(-2.0,  2.0),
            vec2( 2.0, -2.0),
            vec2(-2.0, -2.0)
        );

        const float filterWeights[3] = float[3](0.125, 0.0625, 0.03125);

        #if DOWNSAMPLE_PASS_INDEX == 0
            #define SAMPLER MAIN_BUFFER
        #else
            #define SAMPLER DOWNSAMPLED_BUFFER
        #endif

        vec3 sampleDownsampledBuffer(vec2 coords) {
            return textureLod(SAMPLER, coords, 0).rgb;
        }

    #elif defined UPSAMPLE_PASS

        #define SAMPLER DOWNSAMPLED_BUFFER

        #include "/include/utility/sampling.glsl"

        float tileWeight(int lod) {
            return exp2(-0.5 * lod);
        }

    #endif

    void main() {
        vec2 coords = gl_FragCoord.xy * texelSize;

        #if defined DOWNSAMPLE_PASS
            #if DOWNSAMPLE_PASS_INDEX == 0
                coords = coords * 2.0;
            #else
                coords = coords * 2.0 - 1.0;
            #endif
        #else
            coords = coords * 0.5 + 0.5;
        #endif

        #if defined DOWNSAMPLE_PASS

            downsampled.rgb  = sampleDownsampledBuffer(coords).rgb * filterWeights[0];

            downsampled.rgb += sampleDownsampledBuffer(coords + filterOffsets[0]  * texelSize) * filterWeights[0];
            downsampled.rgb += sampleDownsampledBuffer(coords + filterOffsets[1]  * texelSize) * filterWeights[0];
            downsampled.rgb += sampleDownsampledBuffer(coords + filterOffsets[2]  * texelSize) * filterWeights[0];
            downsampled.rgb += sampleDownsampledBuffer(coords + filterOffsets[3]  * texelSize) * filterWeights[0];

            downsampled.rgb += sampleDownsampledBuffer(coords + filterOffsets[4]  * texelSize) * filterWeights[1];
            downsampled.rgb += sampleDownsampledBuffer(coords + filterOffsets[5]  * texelSize) * filterWeights[1];
            downsampled.rgb += sampleDownsampledBuffer(coords + filterOffsets[6]  * texelSize) * filterWeights[1];
            downsampled.rgb += sampleDownsampledBuffer(coords + filterOffsets[7]  * texelSize) * filterWeights[1];

            downsampled.rgb += sampleDownsampledBuffer(coords + filterOffsets[8]  * texelSize) * filterWeights[2];
            downsampled.rgb += sampleDownsampledBuffer(coords + filterOffsets[9]  * texelSize) * filterWeights[2];
            downsampled.rgb += sampleDownsampledBuffer(coords + filterOffsets[10] * texelSize) * filterWeights[2];
            downsampled.rgb += sampleDownsampledBuffer(coords + filterOffsets[11] * texelSize) * filterWeights[2];

            downsampled.a = 0.0;

        #elif defined UPSAMPLE_PASS

            float normalization = 0.0;
            for (int tile = 0; tile < 8; tile++) normalization += tileWeight(tile);
            normalization = 1.0 / normalization;

            downsampled.rgb = textureBicubic(SAMPLER, coords).rgb;
            downsampled.a   = tileWeight(UPSAMPLE_PASS_INDEX) * normalization;

            #if UPSAMPLE_PASS_INDEX == 7
                downsampled.rgb *= tileWeight(UPSAMPLE_PASS_INDEX + 1) * normalization;
            #endif

        #endif
    }
    
#endif
