#include "/lib/config.glsl"
#include "/lib/luma.glsl"


// Do not remove comments. It works!
/*

noisetex - Water normals
colortex0 - Unused
colortex1 - Antialiasing auxiliar
colortex2 - Balanced half-resolution firefly radiance
colortex3 - TAA Averages history
gaux1 - Screen-Space-Reflection / Bloom auxiliar
gaux2 - Clouds texture natural and vanilla
gaux3 - Exposure auxiliar
gaux4 - Fog auxiliar

const int noisetexFormat = RG8;
const int colortex0Format = R8;
*/
/*
const int colortex1Format = RGBA16;
const int colortex2Format = R11F_G11F_B10F;
const int colortex3Format = RGBA16;
*/
/*
const int gaux1Format = RGBA8;
const int gaux2Format = R8;
const int gaux3Format = R16F;
const int gaux4Format = R11F_G11F_B10F;

const int colortex8Format = RGBA8;
const int colortex9Format = RGBA8;

const int shadowcolor0Format = RGBA8;
*/

// Buffers clear
const bool colortex0Clear = false;
const bool colortex1Clear = false;
const bool colortex2Clear = false;
const bool colortex3Clear = false;
const bool gaux1Clear = false;
const bool gaux2Clear = false;
const bool gaux3Clear = false;
const bool gaux4Clear = false;
const bool colortex8Clear = true;
const bool colortex9Clear = true;

/* Uniforms */

#ifdef DEBUG_MODE
uniform sampler2D shadowtex1;
uniform sampler2D shadowcolor0;
uniform sampler2D colortex3;
#endif

uniform sampler2D gaux3;
uniform sampler2D colortex1;
uniform int isEyeInWater;
uniform float day_moment;
uniform float day_mixer;
uniform float night_mixer;
uniform float near;
uniform float far;
uniform sampler2D depthtex1;

/* Ins / Outs */

varying vec2 texcoord;
varying float exposure;

/* Utility functions */

#include "/lib/basic_utils.glsl"
#include "/lib/tone_maps.glsl"
#include "/lib/dither.glsl"

#ifdef CHROMA_ABER
    #include "/lib/aberration.glsl"
#endif

#include "/lib/day_blend.glsl"

// Vignette, Film grain, Sharpening and Fake bloom.
#if defined VIGNETTE || defined FAKE_BLOOM || defined FILM_GRAIN || AA_TYPE == 3
    #include "/lib/post_processing.glsl"    
#endif

#define FRAGMENT
#include "/lib/downscale.glsl"

void main() {
    vec2 pixelUV = texcoord;

    #ifdef PS1_LIKE
        pixelUV = floor(texcoord * vec2(viewWidth, viewHeight) / PIXEL_SIZE) * PIXEL_SIZE / vec2(viewWidth, viewHeight) * RENDER_SCALE;
    #endif // PS1 filter

    #ifdef CHROMA_ABER
        vec3 block_color = color_aberration();
    #else
       vec3 block_color = texture2DLod(colortex1, pixelUV, 0.0).rgb;

       #if AA_TYPE == 3 && !defined PS1_LIKE
            block_color = sharpen(colortex1, block_color, pixelUV);
        #endif
    #endif

    // Dark areas dessaturation and blueness.
    if (isEyeInWater == 1) {
        float luma_factor = luma(block_color);
        float shadow_desaturation = smoothstep(0.01, 0.455, luma_factor);
        // Blue-green tint stronger in darker underwater areas, natural in lit areas
        block_color = mix(block_color * vec3(0.7, 0.95, 1.3), block_color, shadow_desaturation);
    } else {
        float luma_factor = luma(block_color);
        float shadow_desaturation = smoothstep(0.01, 0.175, luma_factor);
        block_color = mix(saturate(block_color, clamp(luma_factor + 0.5, 0.7, 1.0)) * vec3(0.9, 0.95, 1.1), block_color, shadow_desaturation);
    } // Water overlay

    #if defined SIMPLE_AUTOEXP && COLOR_SCHEME != 11
        float exposure_final = day_blend_float(1.5, 0.85, 2.25);
    #elif COLOR_SCHEME == 11 && defined SIMPLE_AUTOEXP
        float exposure_final = day_blend_float(0.75, 0.75, 2.0);
    #elif COLOR_SCHEME == 11 && !defined SIMPLE_AUTOEXP
        float exposure_final = exposure * day_blend_float(0.8, 1.0, 1.0);
    #else
        float exposure_final = exposure;
    #endif

    #if COLOR_SCHEME == 13 && !defined THE_END && !defined NETHER
        // A restrained scene-linear split tone ties terrain to the sky before
        // the display transform. Shadows inherit the rift's indigo/cyan while
        // sunlit energy receives a complementary champagne/amber bias.
        float astral_grade_luma = luma(block_color);
        float astral_shadow_mask = 1.0 - smoothstep(0.055, 0.48, astral_grade_luma);
        float astral_highlight_mask = smoothstep(0.32, 1.20, astral_grade_luma);
        vec3 astral_shadow_tint = day_blend(
            vec3(0.94, 0.91, 1.08),
            vec3(0.97, 0.995, 1.025),
            vec3(0.82, 0.91, 1.16)
        );
        vec3 astral_highlight_tint = day_blend(
            vec3(1.15, 0.96, 0.78),
            vec3(1.045, 1.015, 0.955),
            vec3(1.04, 0.94, 1.08)
        );
        block_color *= mix(vec3(1.0), astral_shadow_tint, astral_shadow_mask * day_blend_float(0.16, 0.08, 0.22));
        block_color *= mix(vec3(1.0), astral_highlight_tint, astral_highlight_mask * day_blend_float(0.14, 0.08, 0.18));

        // Gentle density in the mid-tones gives the image a filmic shoulder
        // without crushing caves or bleaching luminous cosmic detail.
        float astral_mid_mask = 1.0 - abs(clamp(astral_grade_luma, 0.0, 1.0) * 2.0 - 1.0);
        block_color = mix(block_color, block_color * block_color * 1.85, astral_mid_mask * 0.035);
    #elif COLOR_SCHEME == 13 && defined NETHER
        float astral_nether_luma = luma(block_color);
        float astral_nether_shadow = 1.0 - smoothstep(0.045, 0.42, astral_nether_luma);
        float astral_nether_highlight = smoothstep(0.30, 1.15, astral_nether_luma);
        block_color *= mix(vec3(1.0), vec3(0.88, 0.76, 1.06), astral_nether_shadow * 0.15);
        block_color *= mix(vec3(1.0), vec3(1.14, 0.91, 0.72), astral_nether_highlight * 0.20);
    #elif COLOR_SCHEME == 13 && defined THE_END
        float astral_end_luma = luma(block_color);
        float astral_end_shadow = 1.0 - smoothstep(0.04, 0.50, astral_end_luma);
        float astral_end_highlight = smoothstep(0.28, 1.10, astral_end_luma);
        // Keep cosmic violet in the image without painting every terrain
        // shadow blue. Highlights receive only a very small magenta response.
        block_color *= mix(vec3(1.0), vec3(1.035, 0.985, 1.015), astral_end_shadow * 0.12);
        block_color *= mix(vec3(1.0), vec3(1.045, 0.990, 1.030), astral_end_highlight * 0.10);
        // Filmic toe lift exclusive to genuinely dark values. It reveals the
        // faces of obsidian pillars and deep terrain cavities without raising
        // End-stone, stars or nebular highlights.
        float astral_end_deep_shadow = 1.0
            - smoothstep(0.018, 0.19, astral_end_luma);
        block_color += vec3(0.016, 0.013, 0.019)
            * astral_end_deep_shadow;
    #endif

    block_color *= vec3(RED, GREEN, BLUE) * vec3(exposure_final * EXPOSURE) * BRIGHTNESS; // Color balance, Exposure, Brightness. 
    block_color = (block_color - 0.5) * CONTRAST + 0.5; // Contrast
    block_color = saturate(block_color.rgb, SATURATION); // Saturation
    block_color = vibrance(block_color.rgb, VIBRANCE); // Vibrance

    #if COLOR_SCHEME == 13 && !defined THE_END && !defined NETHER
        // Compress only colors nearing the display gamut boundary. Neutral
        // materials remain untouched, while foliage and cyan sky retain hue
        // detail instead of clipping into flat neon channels at midday.
        float astral_chroma = max(block_color.r, max(block_color.g, block_color.b))
            - min(block_color.r, min(block_color.g, block_color.b));
        float astral_day_chroma = day_blend_float(0.62, 1.0, 0.08);
        float astral_chroma_compression = smoothstep(0.18, 0.72, astral_chroma)
            * astral_day_chroma;
        block_color = mix(
            block_color,
            saturate(block_color, 0.70),
            astral_chroma_compression * 0.58
        );
    #endif

    block_color = pow(block_color.rgb, vec3(1 / GAMMA)); // Gamma
    
    #if TONEMAPPING == 0
        block_color = custom_sigmoid_alt(block_color);
    #elif TONEMAPPING == 1
        #ifdef HDR
        block_color = Lottes(block_color, 1.75);
        #else
        block_color = Lottes(block_color, 1.3);
        #endif
    #elif TONEMAPPING == 2
        #if COLOR_SCHEME == 13
            block_color = ACESFilm(block_color, 4.0);
        #else
            block_color = ACESFilm(block_color, 2.6);
        #endif
    #elif TONEMAPPING == 3
        block_color = Lottes(block_color, 0.1);
    #endif

    #ifdef VIGNETTE
        block_color *= vignette(texcoord); // Vignette
    #endif

    #ifdef FAKE_BLOOM
        float threshold = 0.5; 
        block_color = fakeBloom(block_color, threshold); // Fake Bloom
    #endif
    
    #ifdef FILM_GRAIN
        float grainIntensity = GRAIN_FACTOR; 
        block_color = filmGrain(block_color, grainIntensity, texcoord); // Film grain
    #endif

    // Final display-space quantization dither. A stable, zero-mean signal
    // smaller than one 8-bit code value removes visible gradient bands without
    // blur, extra texture samples, or temporal shimmer.
    #if !defined DEBUG_MODE && !defined PS1_LIKE
        vec3 quantizationDither = vec3(
            dither_makeup(gl_FragCoord.xy),
            dither_makeup(gl_FragCoord.xy + vec2(19.0, 7.0)),
            dither_makeup(gl_FragCoord.xy + vec2(43.0, 29.0))
        ) - vec3(0.5);
        block_color += quantizationDither * (1.0 / 255.0);
    #endif

    #ifdef DEBUG_MODE
        if(texcoord.x < 0.5 && texcoord.y < 0.5) {
            block_color = texture2D(shadowtex1, texcoord * 2.0).rrr;
        } else if(texcoord.x >= 0.5 && texcoord.y >= 0.5) {
            block_color = vec3(texture2D(gaux3, vec2(0.5)).r * 0.25);
        } else if(texcoord.x < 0.5 && texcoord.y >= 0.5) {
            block_color = texture2D(colortex1, ((texcoord - vec2(0.0, 0.5)) * 2.0)).rgb;
        } else if(texcoord.x >= 0.5 && texcoord.y < 0.5) {
            block_color = texture2D(shadowcolor0, ((texcoord - vec2(0.5, 0.0)) * 2.0)).rgb;
        } else {
            block_color = vec3(0.5);
        }

        gl_FragData[0] = vec4(block_color, 1.0);

    #else
        gl_FragData[0] = vec4(block_color, 1.0);
    #endif
}
