#version 400 compatibility

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

    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.

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

#include "/lib/head.glsl"
#include "/lib/util/encoders.glsl"
#include "/lib/util/colorspace.glsl"

in vec2 coord;

flat in mat2x3 lightColor;

uniform sampler2D colortex0;
uniform sampler2D colortex1;
uniform sampler2D colortex2;
uniform sampler2D colortex3;
uniform sampler2D colortex6;

#ifdef rtaoEnabled
uniform sampler2D colortex7;
#endif

uniform sampler2D depthtex0;

uniform float aspectRatio;
uniform float far, near;
uniform float sunAngle;

uniform vec2 taaOffset;
uniform vec2 viewSize;

uniform vec3 lightvec, lightvecView;

uniform mat4 gbufferModelView, gbufferModelViewInverse;
uniform mat4 gbufferProjection, gbufferProjectionInverse;

/* ------ includes ------ */
#include "/lib/util/transforms.glsl"

#define FUTIL_LINDEPTH
#define FUTIL_MAT16
#define FUTIL_LIGHTMAP
#include "/lib/fUtil.glsl"

#define ATROUS_POSTRT
#include "/lib/util/kernel.glsl"
#include "/lib/light/atrousLightmap.glsl"

vec4 textureBilateral(sampler2D tex, sampler2D depth, const int lod, float fdepth) {
    vec4 data   = vec4(0.0);
    float sum   = 0.0;
    ivec2 posD  = ivec2(coord*viewSize);
    ivec2 posT  = ivec2(coord*viewSize*rcp(float(lod)));
    vec3 zmult  = vec3((far*near)*2.0, far+near, far-near);
        fdepth  = depthLinear(fdepth);
    //ivec2 p     = (ivec2(gl_FragCoord.xy + frameCounter) % 2 - 1)*0;
    
    for (int i = -1; i<2; i++) {
        for (int j = -1; j<2; j++) {
            ivec2 tcDepth = posD + ivec2(i, j)*lod;
            float dsample = depthLinear(texelFetch(depth, tcDepth, 0).x);
            float w     = abs(dsample-fdepth)*zmult.x<1.0 ? 1.0 : 1e-5;
            ivec2 ct    = posT + ivec2(i, j);
            data       += texelFetch(tex, ct, 0)*w;
            sum        += w;
        }
    }
    data *= rcp(sum);

    return data;
}

void main() {
    vec4 sceneColor   = stex(colortex0);
    float sceneDepth = stex(depthtex0).x;

    if (landMask(sceneDepth)) {
        sceneColor.rgb  = linearToAP1Albedo(sceneColor.rgb);
        vec4 tex1       = stex(colortex1);
        vec2 sceneLmap  = decode2x8(tex1.z);

        vec4 tex2       = stex(colortex2);
        int matID       = decodeMatID16(tex2.x);

        #if DEBUG_VIEW==1
        sceneColor.rgb    = vec3(1.0);
        #endif

        float rtao      = 1.0;

        #ifdef lightmapSmoothingEnabled
        vec4 tex3       = lightmap3x3(colortex3, depthtex0, colortex6, coord, 1);
            sceneLmap   = tex3.xy;
            sceneColor.a = tex3.z;
            rtao        = tex3.a;
        #else
            rtao        = stex(colortex3).a;
        #endif

        float ao        = sqr(sceneColor.a)*0.8+0.2;

        #ifdef ambientOcclusionEnabled
            vec4 upscale3 = textureBilateral(colortex3, depthtex0, 2, sceneDepth);
                ao     *= upscale3.w;
        #endif

        /* ------ lighting ------ */

        vec3 indirectLight = lightColor[0] * rtao;
            indirectLight += vec3(0.5, 0.7, 1.0)*0.01*minLightLuma;

        #ifdef rtaoEnabled
            ao  *= rtao * 0.66 + 0.34;
        #endif

        vec3 result     = indirectLight;
            result     += getBlocklightMap(lightColor[1], sceneLmap.x)*ao;

        #ifdef emitterBoostEnabled
        if (matID == 5) {
            float albedoLum     = getLuma(sceneColor.rgb);
            vec3 emitterCol     = mix(lightColor[1], vec3(v3avg(lightColor[1])), emitterRecoloring);
                //emitterCol     *= cubeSmooth(saturate(v3avg(sceneColor.rgb) * 1.5));
                emitterCol    *= saturate(mix(cube(albedoLum) * normalize(sceneColor.rgb), sceneColor.rgb, albedoLum));
            result += emitterCol * 2.0;
        }
        #endif

        sceneColor.rgb *= result;

        #if DEBUG_VIEW==2
        sceneColor.rgb    = ao * lightColor[0] * 2.0;
        #endif

        #if DEBUG_VIEW==3
            sceneColor.rgb    = indirectLight;

            #ifdef DEBUG_WITH_ALBEDO
                sceneColor.rgb *= albedo;
            #endif
        #endif
    } else {
        sceneColor.rgb  = vec3(1.0, 0.2, 0.05) * 0.02;
    }

    /*DRAWBUFFERS:03*/
    gl_FragData[0]  = makeDrawbuffer(sceneColor);
    gl_FragData[1]  = vec4(0.0);
}