// ============================================================
//  voxy_translucent.glsl
// ============================================================

#include "voxy_common.glsl"

// Local defines
#define WATER_SHADOW_BIAS_MULTIPLIER 0.2
#define WATER_PCF_SAMPLES 8
#define WATER_SHADOW_SOFTNESS 0.5
#define WATER_FOG_ENABLED 1 // [0 1] Enable fog

#define VOXY_AMBIENT_COMPENSATION_DAY   1.00 // [0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0] Lower = dimmer voxy LOD ambient floor during the day. Default 1.0 = unchanged from before this setting existed.
#define VOXY_AMBIENT_COMPENSATION_NIGHT 0.30 // [0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0] Lower = dimmer voxy LOD ambient floor at night.
#define VOXY_DIRECT_COMPENSATION_DAY   1.00 // [0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0] Lower = dimmer voxy LOD fake-shadow direct light during the day. Default 1.0 = unchanged from before this setting existed.
#define VOXY_DIRECT_COMPENSATION_NIGHT 0.40 // [0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0] Lower = dimmer voxy LOD fake-shadow direct light at night.
#define VOXY_VERTEX_AO_COMPENSATION 0.85 // [0.2 0.5 0.6 0.7 0.75 0.8 0.85 0.9 0.95 1.0] Lower = darker, mimicking missing corner/edge AO.

layout(location = 0) out vec4 voxy_outColor;
layout(location = 1) out vec4 voxy_outOriginal;

void voxy_emitFragment(VoxyFragmentParameters parameters) {
    vec3 viewPos = voxy_viewPos();
    vec3 world = voxy_worldPos(viewPos);
    vec3 vPos = viewPos;
    float distToCamera = length(world);

    vec3 norm = voxy_faceNormal(parameters.face);
    vec2 voxyLightMap = vec2(parameters.lightMap.x, voxy_softenSkyLight(parameters.lightMap.y));

    vec3 dir = normalize((vxModelViewInv * vec4(shadowLightPosition, 0.0)).xyz);
    float flip = clamp(dir.y / .1, -1., 1.);
    dir *= flip;
    // Water is always treated as a horizontal surface for lambert/sun-glare
    float lambert = dir.y * .5 + .5;
    float sun = exp((dot(reflect(normalize(world), norm), dir) - 1.) * 15. * (1.5 - .5 * flip));

    float skyLightFactor = clamp(eyeBrightnessSmooth.y / 240.0, 0.0, 1.0);
    vec3 skyFog = voxy_skyFog(viewPos, sunAngle, rainStrength, fogColor, skyColor, upPosition, isEyeInWater, skyLightFactor);

    vec4 col = parameters.sampledColour;
    vec4 originalTexture = col;

    #ifdef TEXTURE_PAPER_STYLE
    if (TEXTURE_PAPER_STYLE == 1) {
        float brightness = dot(col.rgb, vec3(0.299, 0.587, 0.114));
        vec3 grayscaleTexture = vec3(brightness);
        vec3 mixedTexture = mix(col.rgb, grayscaleTexture, TEXTURE_GRAYSCALE_STRENGTH);

        vec3 paperBase = vec3(TEXTURE_PAPER_WHITENESS);
        float mixedBrightness = dot(mixedTexture, vec3(0.299, 0.587, 0.114));

        vec3 coloredPaper = mixedTexture * paperBase * (0.6 + 0.4 * mixedBrightness);
        vec3 grayscalePaper = paperBase * (0.6 + 0.4 * mixedBrightness);

        col.rgb = mix(coloredPaper, grayscalePaper, TEXTURE_GRAYSCALE_STRENGTH);
    }
    #endif

    col.rgb *= parameters.tinting.rgb;
    col.rgb *= VOXY_VERTEX_AO_COMPENSATION;

    // WATER-SPECIFIC SHADOW CALCULATION
    vec3 sLight = vec3(1.0);
    float shadowFactor = 1.0;
    #if ENABLE_SHADOWS == 1
    {
        float ndotl = clamp(dot(dir, norm), 0.0, 1.0);
        // Use the RAW sky light here, not voxyLightMap.y, which is softened for the ambient texture lookup only.
        float fakeShadow = voxy_fakeShadow(parameters.lightMap.y, norm) * ndotl * 2.0;

        sLight = vec3(fakeShadow);
        shadowFactor = fakeShadow;
    }
    #endif

    vec4 shine = vec4(vec3(sun) * flip * flip, 0) * Shininess * shadowFactor;
    #if TEXTURE_PAPER_STYLE == 1
        shine *= 3.0;
    #endif

    vec3 sunlightColorVal = getSunlightColor(sunAngle);
    float sunlightFadeVal = voxy_sunlightFade(sunAngle);
    sLight = mix(vec3(1.0), sLight, sunlightFadeVal);
    sLight *= sunlightColorVal;
    sLight *= mix(DAY_DIRECT_BRIGHTNESS, NIGHT_DIRECT_BRIGHTNESS * getMoonPhaseBrightness(moonPhase), getNightAmount(sunAngle));
    sLight *= voxy_ambientCompensation(VOXY_DIRECT_COMPENSATION_DAY, VOXY_DIRECT_COMPENSATION_NIGHT, sunAngle);

    // LIGHTING CALCULATION
    float sBright = mix(SHADOW_BRIGHTNESS, 1.0, rainStrength);
    float lVis = texture2D(lightmap, vec2(0.0, voxyLightMap.y)).r;

    vec3 lMap = getDecoupledLightmap(lightmap, voxyLightMap, skyLightFactor, sBright, sunlightColorVal, voxy_pseudoAO(norm), sunAngle, moonPhase);
    lMap *= voxy_ambientCompensation(VOXY_AMBIENT_COMPENSATION_DAY, VOXY_AMBIENT_COMPENSATION_NIGHT, sunAngle);

    lMap *= parameters.tinting.a;
    sBright += (1.0 - lVis) * (1.0 - sBright);
    lMap += sLight * (1.0 - sBright) * skyLightFactor;
    lMap *= mix(CAVE_DARKNESS, 1.0, skyLightFactor);

    vec3 effectiveSkyColor = mix(vec3(0.6), skyColor, skyLightFactor);

    #if ENABLE_DIRECTIONAL_LIGHTING == 1
        vec3 directionalShad = mix(effectiveSkyColor * .5 + .2, vec3(1), lambert) * lMap;
        vec3 flatShad = vec3(1) * lMap;
        vec3 shad = mix(flatShad, directionalShad, skyLightFactor);
    #else
        vec3 shad = vec3(1) * lMap;
    #endif

    col *= vec4(shad * (1.0 - blindness), 1) + shine;

    col.rgb = mix(col.rgb, entityColor.rgb, entityColor.a);

    #if WATER_FOG_ENABLED == 1
        col.rgb = voxy_applyFog(col.rgb, distToCamera, voxy_fogFarDist(), isEyeInWater, rainStrength, skyFog, nightVision);
    #endif

    #if TEXTURE_PAPER_STYLE == 1
        col.rgb = voxy_applyGrayBias(col.rgb, originalTexture.rgb, parameters.tinting.rgb);
    #endif

    vec4 originalTextureColor = originalTexture * vec4(parameters.tinting.rgb, 1.0);

    voxy_outColor = vec4(col.rgb, col.a);
    voxy_outOriginal = vec4(originalTextureColor.rgb, 1.0);
}
