/*
====================================================================================================

    Copyright (C) 2020 RRe36

    All Rights Reserved unless otherwise explicitly stated.


    By downloading this you have agreed to the license and terms of use.
    These can be found inside the included license-file
    or here: https://rre36.com/copyright-license

    Violating these terms may be penalized with actions according to the Digital Millennium
    Copyright Act (DMCA), the Information Society Directive and/or similar laws
    depending on your country.

====================================================================================================
*/

float computeVariance(sampler2D tex, ivec2 pos) {
    float sum_msqr  = 0.0;
    float sum_mean  = 0.0;

    for (int i = 0; i<9; i++) {
        ivec2 deltaPos     = kernelO_3x3[i];
        //float weight        = kernelW_5x5[i];

        vec3 col    = texelFetch(tex, pos + deltaPos, 0).rgb;
        float lum   = getLuma(col);

        sum_msqr   += sqr(lum);
        sum_mean   += lum;
    }
    sum_msqr /= 9.0;
    sum_mean /= 9.0;

    return abs(sum_msqr - sqr(sum_mean)) * rcp(max(sum_mean, 1e-25));
}

#define atrousLumaExp 4.0
#define atrousLumaOffset 0.5

vec4 atrous3x3(sampler2D tex, sampler2D depth, sampler2D normals, vec2 coord, const int size) {
    ivec2 pixelPos  = ivec2(coord * viewSize);

    float expDepthCenter = texelFetch(depth, ivec2(pixelPos), 0).x;

    vec4 colorCenter    = texelFetch(tex, ivec2(floor(pixelPos * indirectResScale)), 0);
    if (!landMask(expDepthCenter)) return colorCenter;

    float depthCenter   = depthLinear(expDepthCenter) * far;
    vec3 normalCenter   = texelFetch(normals, ivec2(pixelPos), 0).xyz * 2.0 - 1.0;

    #define kernelMidIndex 4

    vec4 totalColor     = vec4(0.0);
    float totalWeight   = 0.0;

    float sigmaL        = rcp(atrousLumaExp * (computeVariance(tex, pixelPos)) + atrousLumaOffset);

    vec3 viewDir        = normalize(screenToViewSpace(vec3(coord, 1.0)));
    vec3 viewNorm       = mat3(gbufferModelView) * normalCenter;

    float depthExp      = 10.0 * (cube(saturate(-dot(viewNorm, viewDir))) * 0.75 + 0.25);

    for (int i = 0; i < 25; i++) {
        //if (i == kernelMidIndex) continue;

        ivec2 delta     = kernelO_5x5[i] * size;

        ivec2 currPos   = pixelPos + delta;
        if (clamp(currPos, ivec2(0), ivec2(viewSize)-1) != currPos) continue;
        ivec2 currPosScaled = ivec2(floor(currPos * indirectResScale));

        vec3 normalCurr = texelFetch(normals, ivec2(currPosScaled / indirectResScale), 0).xyz * 2.0 - 1.0;

        float normalWeight = pow(saturate(dot(normalCurr, normalCenter)), 16.0);

        if (normalWeight < 1e-5) continue;

        float depthCurr = texelFetch(depth, ivec2(currPosScaled / indirectResScale), 0).x;
        if (depthCurr == 1.0) continue;
            depthCurr   = depthLinear(depthCurr) * far;
        float depthWeight = expf(-abs(depthCurr - depthCenter) * depthExp - sigmaL);
        if (depthWeight < 1e-5) continue;

        vec4 colorCurr  = texelFetch(tex, currPosScaled, 0);

        float weight = normalWeight * depthWeight;

        totalColor.rgb += colorCurr.rgb * weight;
        totalWeight += weight;
    }

    totalColor.rgb *= rcp(max(totalWeight, 1e-16));
    totalColor.a    = 1.0;

    //return colorCenter;
    return vec4(totalColor);
}