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

    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.

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

/*
const int colortex0Format   = RGBA16F;
const int colortex1Format   = RGBA32UI;
const int colortex2Format   = RGB16;
const int colortex3Format   = RGBA16F;
const int colortex4Format   = RGBA16F;
const int colortex5Format   = RGBA16F;  
const int colortex6Format   = RGB16;
const int colortex7Format   = RGBA32UI;

const vec4 colortex0ClearColor = vec4(0.0, 0.0, 0.0, 1.0);
const vec4 colortex3ClearColor = vec4(0.0, 0.0, 0.0, 0.0);

const bool colortex7Clear   = false;

c0  - 4x16 scene color (full)

c1  
    32R - 2x16 scene normals
    32G - 1x16 lightmaps, 1x16 matID
    32B - 4x8 specular texture
    32A - pom shadows, direct shadows

c2  - 2x16 direct light + emitter mask for ssrt, 3x16 SSRT Emission, 3x16 translucents data
c3  - 3x16 lightmap+vao, 4x16 translucencies  (water -> composite0), bloom (composite7 -> final)
    - 3x16 indirect light, 1x16 SSRT emission alpha
c4  - temporals (full)
c5  - skybox data (deferred0 -> composite)
c6  - decoded normals for lightmap filter, 3x16 translucents data
c7  - indirect light accumulation

c7 RGBA32UI
    - 2x16 indirect RG
    - 2x16 indirect BM
    - 2x16 emission RG
    - 1x16 emission B, 1x16 previous depth
*/

layout(location = 0) out vec3 sceneImage;

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

in vec2 coord;

uniform sampler2D colortex0;

uniform float aspectRatio;

uniform vec2 pixelSize;
uniform vec2 viewSize;

float bayer2  (vec2 c) { c = 0.5 * floor(c); return fract(1.5 * fract(c.y) + c.x); }
float bayer4  (vec2 c) { return 0.25 * bayer2 (0.5 * c) + bayer2(c); }
float bayer8  (vec2 c) { return 0.25 * bayer4 (0.5 * c) + bayer2(c); }
float bayer16 (vec2 c) { return 0.25 * bayer8 (0.5 * c) + bayer2(c); }

#define screenBitdepth 8   //[1 2 4 6 8]

vec3 ditherImage(vec3 color) {
    const uint bits = uint(pow(2, screenBitdepth));

    vec3 cDither    = color;
        cDither    *= bits;
        cDither    += bayer16(gl_FragCoord.xy) - 0.5;

    return round(cDither)/bits;
}

#include "/lib/util/bicubic.glsl"

vec3 textureCAS(sampler2D tex, vec2 uv, const float w) {   //~8fps
    vec2 res    = textureSize(tex, 0);
    vec2 pixelSize = rcp(res);

    vec3 tl     = textureLod(tex, uv + vec2( 1.0,  1.0)*pixelSize, 0).rgb;
    vec3 tc     = textureLod(tex, uv + vec2( 0.0,  1.0)*pixelSize, 0).rgb;
    vec3 tr     = textureLod(tex, uv + vec2(-1.0,  1.0)*pixelSize, 0).rgb;

    vec3 ml     = textureLod(tex, uv + vec2( 1.0,  0.0)*pixelSize, 0).rgb;
    vec3 mc     = textureLod(tex, uv, 0).rgb;
    vec3 mr     = textureLod(tex, uv + vec2(-1.0,  0.0)*pixelSize, 0).rgb;

    vec3 bl     = textureLod(tex, uv + vec2( 1.0, -1.0)*pixelSize, 0).rgb;
    vec3 bc     = textureLod(tex, uv + vec2( 0.0, -1.0)*pixelSize, 0).rgb;
    vec3 br     = textureLod(tex, uv + vec2(-1.0, -1.0)*pixelSize, 0).rgb;

    vec3 avg    = (tl + tc + tr + ml + mc + mr + bl + bc + br) * rcp(9.0);

    vec3 delta  = abs(tl - avg) + abs(tc - avg) + abs(tr - avg) + 
                abs(ml - avg) + abs(mc - avg) + abs(mr - avg) +
                abs(bl - avg) + abs(bc - avg) + abs(br - avg);
    
    float contrast  = 1.0 - getLuma(delta) * rcp(9.0);

    vec3 color  = mc * (1.0 + w * contrast);
        color  -= (tc + bc + ml + mr + (tl + tr + bl + br) * rcp(2.0)) * rcp(6.0) * w * contrast;

    if (color.x < 0.0 || color.y < 0.0 || color.z < 0.0) color = mc;

    return max(color, 0.0);
}

int drawLine(float x, float value, const float thickness) {
    return int(saturate(step(value - thickness, x) - step(value + thickness, x)));
}

//#define framingToolEnabled
//#define framingThirdsHor
//#define framingToAspect
#define framingAspectX 21   //[3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21]
#define framingAspectY 9    //[2 3 4 5 6 7 8 9 10 11 12]
#define framingToAspectCenter 0.5   //[0.0 0.05 0.1 0.15 0.2 0.25 0.3 0.35 0.4 0.45 0.5 0.55 0.6 0.65 0.7 0.75 0.8 0.85 0.9 0.95 1.0]

vec3 framingGuide(vec2 coord, vec3 color) {
    int frame   = 0;

    #ifdef framingThirdsHor
        frame  += drawLine(coord.x, rcp(3.0), pixelSize.x * 2);
        frame  += drawLine(coord.x, rcp(3.0) * 2.0, pixelSize.x * 2);
        frame  += drawLine(coord.y, rcp(3.0), pixelSize.y * 2);
        frame  += drawLine(coord.y, rcp(3.0) * 2.0, pixelSize.y * 2);
    #endif

    #ifdef framingToAspect
        const float targetAspect = float(framingAspectX) / float(framingAspectY);

        if (targetAspect < aspectRatio) {
            float aspectCoeff = targetAspect * rcp(aspectRatio);
            float invCoeff  = 1.0 - aspectCoeff;

            frame  += drawLine(coord.x, invCoeff * framingToAspectCenter, pixelSize.x * 2);
            frame  += drawLine(coord.x, aspectCoeff + invCoeff * framingToAspectCenter, pixelSize.x * 2);

        } else if (targetAspect > aspectRatio) {
            float aspectCoeff = aspectRatio * rcp(targetAspect);
            float invCoeff  = 1.0 - aspectCoeff;

            frame  += drawLine(coord.y, invCoeff * framingToAspectCenter, pixelSize.y * 2);
            frame  += drawLine(coord.y, aspectCoeff + invCoeff * framingToAspectCenter, pixelSize.y * 2);
        }
    #endif

    if (frame != 0) return vec3(1.0);
    else return color;
}

void main() {
    sceneImage      = vec3(0.0);
    
    #ifdef imageSharpenEnabled
        if (MC_RENDER_QUALITY > 0.9) {
            sceneImage  = textureCAS(colortex0, coord, 0.2).rgb;
        } else if (MC_RENDER_QUALITY < 0.6) {
            sceneImage  = textureCAS(colortex0, coord, 0.6).rgb;
        } else {
            sceneImage  = textureCAS(colortex0, coord, 0.4).rgb;
        }
    #else
        if (MC_RENDER_QUALITY > 0.9) {
            sceneImage  = stexLod(colortex0, 0).rgb;
        } else {
            sceneImage  = textureBicubic(colortex0, coord).rgb;
        }
    #endif

    #ifdef framingToolEnabled
        sceneImage      = framingGuide(coord, sceneImage);
    #endif

    sceneImage  = ditherImage(sceneImage);
}