/********************************************************
    © 2020 Continuum Graphics LLC. All Rights Reserved
 ********************************************************/

#include "/../ContinuumLib/Syntax.glsl"

#define PostProcess0_glsl 39
#define DynamicShaderStage PostProcess0_glsl


varying vec2 texcoord;


/***********************************************************************/
#if defined vsh

uniform mat4 gbufferProjection;
uniform mat4 gbufferProjectionInverse;

uniform vec2 viewDimensions;

uniform float frameTime;
uniform float fov;

#include "/../ContinuumLib/Utilities.glsl"

#include "/../ContinuumLib/Uniform/ProjectionMatrices.glsl"

void main() {
    texcoord = gl_Vertex.xy;

    gl_Position = vec4(gl_Vertex.xy * 2.0 - 1.0, 0.0, 1.0);
}

#endif
/***********************************************************************/



/***********************************************************************/
#if defined fsh

#include "/../ContinuumLib/Debug.glsl"

uniform sampler2D colortex0;
uniform sampler2D colortex1;
uniform sampler2D colortex2;
uniform sampler2D colortex5;

uniform sampler2D depthtex0;

uniform mat4 gbufferProjectionInverse;

uniform vec2 viewDimensions;
uniform vec2 pixelSize;

uniform float frameTime;
uniform float fov;

/* DRAWBUFFERS:0 */
layout (location = 0) out vec4 Buffer0;
#define LAYOUT_0 Buffer0
#include "/../ContinuumLib/Exit.glsl"

#include "/../ContinuumLib/Utilities.glsl"

#include "/../ContinuumLib/Uniform/ProjectionMatrices.glsl"

#include "/../ContinuumLib/Fragment/Camera.glsl"
#include "/../ContinuumLib/Fragment/FilmicToningOperator.glsl"
#include "/../ContinuumLib/Fragment/ACES/ACES.fsh"
#include "/../UserLib/Toning/TonemapOverride.glsl"

const bool colortex0MipmapEnabled = true;

#if defined WORLD_1 || defined WORLD1
uniform mat4 gbufferModelViewInverse;
uniform vec2 taaJitter;

float GetDepth(vec2 coord) {
    return texture(depthtex0, coord).x;
}

vec3 CalculateViewSpacePosition(vec2 coord) {
    #ifdef TAA
        coord -= taaJitter * 0.5;
    #endif
    vec3 screenPos = vec3(coord, GetDepth(coord)) * 2.0 - 1.0;

    return projMAD(projInverseMatrix, screenPos) / (screenPos.z * projInverseMatrix[2].w + projInverseMatrix[3].w);
}

vec3 CalculateViewSpacePosition(vec2 coord, float depth) {
    #ifdef TAA
        coord -= taaJitter * 0.5;
    #endif
    vec3 screenPos = vec3(coord, depth) * 2.0 - 1.0;

    return projMAD(projInverseMatrix, screenPos) / (screenPos.z * projInverseMatrix[2].w + projInverseMatrix[3].w);
}

vec3 CalculateWorldSpacePosition(vec3 viewPos) {
    return mat3(gbufferModelViewInverse) * viewPos + gbufferModelViewInverse[3].xyz;
}
#endif

vec3 calculateNetherFogHaze(vec3 background, vec3 viewPos, vec3 light) {
    float od = length(viewPos);

    vec3 transmit = exp(-netherAbsorptionCoeff * od);
    vec3 scatter = 1.0 - transmit;
         scatter *= light;

    #if defined WORLD1
        return background * transmit + scatter;
    #endif

    return scatter + background;
}

vec3 calculateEndFogHaze(vec3 background, vec3 viewPos, vec3 light) {
    float od = length(viewPos);

    vec3 transmit = exp(-endAbsorptionCoeff * od);
    vec3 scatter = 1.0 - transmit;
         scatter *= light;

    return background * transmit + scatter;
}

vec3 CalculateBloom(vec2 coord, inout vec3 haze) {
    vec3 bloom = vec3(0.0);

    const float scale0 = exp2(-2.0);
    const float scale1 = exp2(-3.0);
    const float scale2 = exp2(-4.0);
    const float scale3 = exp2(-5.0);
    const float scale4 = exp2(-6.0);
    const float scale5 = exp2(-7.0);

    vec3 tile0 = DecodeRGBE8(texture(colortex1, texcoord * scale0 + vec2(0.0, 0.0)));
    vec3 tile1 = DecodeRGBE8(texture(colortex1, texcoord * scale1 + vec2(0.0, 0.25 + pixelSize.y * 2.0)));
    vec3 tile2 = DecodeRGBE8(texture(colortex1, texcoord * scale2 + vec2(0.125 + pixelSize.x * 2.0, 0.25 + pixelSize.y * 2.0)));
    vec3 tile3 = DecodeRGBE8(texture(colortex1, texcoord * scale3 + vec2(0.1875 + pixelSize.x * 4.0, 0.25 + pixelSize.y * 2.0)));
    vec3 tile4 = DecodeRGBE8(texture(colortex1, texcoord * scale4 + vec2(0.125 + pixelSize.x * 2.0, 0.3125 + pixelSize.y * 4.0)));
    vec3 tile5 = DecodeRGBE8(texture(colortex1, texcoord * scale5 + vec2(0.140625 + pixelSize.x * 4.0, 0.3125 + pixelSize.y * 4.0)));

	bloom += tile0 * (1.0 / 2.0);
	bloom += tile1 * (1.0 / 3.0);
	bloom += tile2 * (1.0 / 4.0);
	bloom += tile3 * (1.0 / 5.0);
	bloom += tile4 * (1.0 / 6.0);
	bloom += tile5 * (1.0 / 7.0);

    #if defined WORLD_1
        haze = (tile3 + tile4 + tile5) * 0.166666667;
    #elif defined WORLD1
        haze = (tile0 + tile1 + tile2 + tile3) * 0.25;
    #endif

    return bloom * (1.0 / 2.45);
}

vec3 hableCurve(vec3 x) {
    const float hA = 0.15;
    const float hB = 0.50;
    const float hC = 0.10;
    const float hD = 0.20;
    const float hE = 0.02;
    const float hF = 0.30;

    return ((x*(hA*x+hC*hB)+hD*hE) / (x*(hA*x+hB)+hD*hF)) - hE/hF;
}

vec3 hableTonemap(vec3 color) {
    float hW = 11.2;
    float whiteScale = 1.0f / hableCurve(vec3(hW)).x;

    return hableCurve(color) * whiteScale;
}

vec3 calcRain(vec3 light) {
    float rainMask = texture(colortex5, texcoord).r;

    return rainMask * light;
}

void main() {
    vec3 color = DecodeRGBE8(texture(colortex0, texcoord));
    vec3 fogHaze = vec3(0.0);

    //Calculate EV and expose
    float EV = texture(colortex2, texcoord).a * 10.;
    vec3 bloom = CalculateBloom(texcoord, fogHaze);

    #if defined WORLD_1 || defined WORLD1
        vec3 viewPosition = CalculateViewSpacePosition(texcoord);

        color /= EV;
        fogHaze /= EV;
        #if defined WORLD_1
            color = calculateNetherFogHaze(color, viewPosition, fogHaze);
        #else
            color = calculateEndFogHaze(color, viewPosition, fogHaze);
        #endif
        color *= EV;
    #endif

    color += bloom * exp2(EV - 3.0 + BLOOM_EV);
    color += calcRain(bloom);

    //tonemap
    /*
    if(texcoord.x < 0.5) {
    color = hableTonemap(color * 2.0);
    color = linearToSrgb(color);
    } else {*/
    color = sRGB_to_ACES(color);
    color = LMT(color);
    color = RRT(color);
    color = ODT_pre(color); // Common to available ODT's. sRGB and Rec709 Only
    color = ODT_Rec709_100nits_dim(color);
    //}

    Buffer0 = vec4(color, 1.0);

	exit();
}

#endif
/***********************************************************************/
