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

#ifdef FRAGMENT_SHADER

noperspective in vec2 texCoord;

flat in vec3 upVec, sunVec;

#if defined LU_LIGHTSHAFTS_ACTIVE && (LU_LIGHTSHAFT_BEHAVIOUR == 1 && LU_SHADOW_QUALITY >= 1 || defined END)
    flat in float vlFactor;
#endif

const bool colortex0MipmapEnabled = true;

float SdotU = dot(sunVec, upVec);
float sunFactor = SdotU < 0.0 ? clamp(SdotU + 0.375, 0.0, 0.75) / 0.75 : clamp(SdotU + 0.03125, 0.0, 0.0625) / 0.0625;
float sunVisibility = clamp(SdotU + 0.0625, 0.0, 0.125) / 0.125;
float sunVisibility2 = sunVisibility * sunVisibility;
float shadowTimeVar1 = abs(sunVisibility - 0.5) * 2.0;
float shadowTimeVar2 = shadowTimeVar1 * shadowTimeVar1;
float shadowTime = shadowTimeVar2 * shadowTimeVar2;
float farMinusNear = far - near;

vec2 view = vec2(viewWidth, viewHeight);

#ifdef OVERWORLD
    vec3 lightVec = sunVec * ((timeAngle < 0.5325 || timeAngle > 0.9675) ? 1.0 : -1.0);
#else
    vec3 lightVec = sunVec;
#endif

#if defined LU_LIGHTSHAFTS_ACTIVE && (LU_LIGHTSHAFT_BEHAVIOUR == 1 && LU_SHADOW_QUALITY >= 1 || defined END)
#else
    float vlFactor = 0.0;
#endif

float lu_GetLinearDepth(float depth) {
    return (2.0 * near) / (far + near - depth * farMinusNear);
}

#if LU_SSAO_QUALI > 0
    vec2 OffsetDist(float x, int s) {
        float n = fract(x * 1.414) * 3.1415;
        return lu_pow2(vec2(cos(n), sin(n)) * x / s);
    }

    float DoAmbientOcclusion(float z0, float linearZ0, float dither) {
        if (z0 < 0.56) return 1.0;
        float ao = 0.0;

        #if LU_SSAO_QUALI == 2
            int samples = 4;
            float scm = 0.4;
        #elif LU_SSAO_QUALI == 3
            int samples = 12;
            float scm = 0.6;
        #endif

        #define LU_SSAO_I_FACTOR 0.004

        float sampleDepth = 0.0, angle = 0.0, dist = 0.0;
        float fovScale = gbufferProjection[1][1];
        float distScale = max(farMinusNear * linearZ0 + near, 3.0);
        vec2 scale = vec2(scm / aspectRatio, scm) * fovScale / distScale;

        for (int i = 1; i <= samples; i++) {
            vec2 offset = OffsetDist(i + dither, samples) * scale;
            if (i % 2 == 0) offset.y = -offset.y;

            vec2 coord1 = texCoord + offset;
            vec2 coord2 = texCoord - offset;

            sampleDepth = lu_GetLinearDepth(texture2D(depthtex0, coord1).r);
            float aosample = farMinusNear * (linearZ0 - sampleDepth) * 2.0;
            angle = clamp(0.5 - aosample, 0.0, 1.0);
            dist = clamp(0.5 * aosample - 1.0, 0.0, 1.0);

            sampleDepth = lu_GetLinearDepth(texture2D(depthtex0, coord2).r);
            aosample = farMinusNear * (linearZ0 - sampleDepth) * 2.0;
            angle += clamp(0.5 - aosample, 0.0, 1.0);
            dist += clamp(0.5 * aosample - 1.0, 0.0, 1.0);

            ao += clamp(angle + dist, 0.0, 1.0);
        }
        ao /= samples;

        #define LU_SSAO_IM LU_SSAO_I * LU_SSAO_I_FACTOR
        return pow(ao, LU_SSAO_IM);
    }
#endif

#ifdef LU_TEMPORAL_FILTER
    float lu_GetApproxDistance(float depth) {
        return near * far / (far - depth * far);
    }

    vec2 lu_Reprojection(vec3 pos, vec3 cameraOffset) {
        pos = pos * 2.0 - 1.0;

        vec4 viewPosPrev = gbufferProjectionInverse * vec4(pos, 1.0);
        viewPosPrev /= viewPosPrev.w;
        viewPosPrev = gbufferModelViewInverse * viewPosPrev;

        vec4 previousPosition = viewPosPrev + vec4(cameraOffset, 0.0);
        previousPosition = gbufferPreviousModelView * previousPosition;
        previousPosition = gbufferPreviousProjection * previousPosition;
        return previousPosition.xy / previousPosition.w * 0.5 + 0.5;
    }

    vec3 FHalfReprojection(vec3 pos) {
        pos = pos * 2.0 - 1.0;

        vec4 viewPosPrev = gbufferProjectionInverse * vec4(pos, 1.0);
        viewPosPrev /= viewPosPrev.w;
        viewPosPrev = gbufferModelViewInverse * viewPosPrev;

        return viewPosPrev.xyz;
    }

    vec2 SHalfReprojection(vec3 playerPos, vec3 cameraOffset) {
        vec4 proPos = vec4(playerPos + cameraOffset, 1.0);
        vec4 previousPosition = gbufferPreviousModelView * proPos;
        previousPosition = gbufferPreviousProjection * previousPosition;
        return previousPosition.xy / previousPosition.w * 0.5 + 0.5;
    }
#endif

#include "/lib/sky/globals.glsl"
#include "/lib/sky/aero/main.glsl"
#include "/lib/colors/core.glsl"

#if LU_AURORA_STYLE > 0 || defined NIGHT_NEBULA || defined END
    #include "/lib/sky/volumetric.glsl"
#endif

#ifdef LU_VL_CLOUDS_ACTIVE
    #include "/lib/sky/scatter/main.glsl"
#endif

#include "/lib/mtl_method/reflect.glsl"

#if defined WORLD_OUTLINE || defined DARK_OUTLINE || defined LU_DISTANT_LIGHT_BOKEH
    #include "/lib/fx/unified.glsl"
#endif

#ifdef ATM_COLOR_MULTS
    #include "/lib/colors/effects.glsl"
#endif
#ifdef MOON_PHASE_INF_ATMOSPHERE
    #include "/lib/colors/effects.glsl"
#endif

void main() {
    vec3 color = texelFetch(colortex0, texelCoord, 0).rgb;
    float z0 = texelFetch(depthtex0, texelCoord, 0).r;

    vec4 screenPos = vec4(texCoord, z0, 1.0);
    vec4 viewPos = gbufferProjectionInverse * (screenPos * 2.0 - 1.0);
    viewPos /= viewPos.w;
    float lViewPos = length(viewPos);
    vec3 nViewPos = normalize(viewPos.xyz);
    vec3 playerPos = lu_ViewToPlayer(viewPos.xyz);

    float dither = texture2D(noisetex, texCoord * vec2(viewWidth, viewHeight) / 128.0).b;
    #if defined LU_TAA || defined LU_TEMPORAL_FILTER
        dither = fract(dither + goldenRatio * mod(float(frameCounter), 3600.0));
    #endif

    #ifdef ATM_COLOR_MULTS
        atmColorMult = GetAtmColorMult();
        sqrtAtmColorMult = sqrt(atmColorMult);
    #endif

    float VdotU = dot(nViewPos, upVec);
    float VdotS = dot(nViewPos, sunVec);
    float skyFade = 0.0;
    vec3 waterRefColor = vec3(0.0);
    vec3 auroraBorealis = vec3(0.0);
    vec3 nightNebula = vec3(0.0);

    #ifdef LU_TEMPORAL_FILTER
        vec4 refToWrite = vec4(0.0);
    #endif

    if (z0 < 1.0) {
        #ifdef LU_DISTANT_LIGHT_BOKEH
            int dlbo = 1;
            vec3 dlbColor = color;
            dlbColor += texelFetch(colortex0, texelCoord + ivec2( 0, dlbo), 0).rgb;
            dlbColor += texelFetch(colortex0, texelCoord + ivec2( 0,-dlbo), 0).rgb;
            dlbColor += texelFetch(colortex0, texelCoord + ivec2( dlbo, 0), 0).rgb;
            dlbColor += texelFetch(colortex0, texelCoord + ivec2(-dlbo, 0), 0).rgb;
            dlbColor = max(color, dlbColor * 0.2);
            float dlbMix = lu_GetDistantLightBokehMix(lViewPos);
            color = mix(color, dlbColor, dlbMix);
        #endif

        #if LU_SSAO_QUALI > 0 || defined WORLD_OUTLINE || defined LU_TEMPORAL_FILTER
            float linearZ0 = lu_GetLinearDepth(z0);
        #endif

        #if LU_SSAO_QUALI > 0
            float ssao = DoAmbientOcclusion(z0, linearZ0, dither);
        #else
            float ssao = 1.0;
        #endif

        vec3 texture6 = texelFetch(colortex6, texelCoord, 0).rgb;
        bool entityOrHand = z0 < 0.56;
        int materialMaskInt = int(texture6.g * 255.1);
        float intenseFresnel = 0.0;
        float smoothnessD = texture6.r;
        vec3 reflectColor = vec3(1.0);

        if (materialMaskInt <= 240) {
            #ifdef LU_IPBR
                #include "/lib/mtl_handle/deferred.glsl"
            #elif defined LU_CUSTOM_PBR
                #if LU_RP_MODE == 2
                    float metalness = materialMaskInt / 240.0;

                    intenseFresnel = metalness;
                #elif LU_RP_MODE == 3
                    float metalness = float(materialMaskInt >= 230);

                    intenseFresnel = materialMaskInt / 240.0;
                #endif
                reflectColor = mix(reflectColor, color.rgb / max(color.r + 0.00001, max(color.g, color.b)), metalness);
            #endif
        } else {
            if (materialMaskInt == 254) {
                ssao = 1.0;
                entityOrHand = true;
            }
        }

        color.rgb *= ssao;

        #ifdef LU_PBR_REFLECTIONS
            float skyLightFactor = texture6.b;
            vec3 texture5 = texelFetch(colortex5, texelCoord, 0).rgb;
            vec3 normalM = mat3(gbufferModelView) * texture5;

            float fresnel = clamp(1.0 + dot(normalM, nViewPos), 0.0, 1.0);

            float fresnelFactor = (1.0 - smoothnessD) * 0.7;
            float fresnelM = max(fresnel - fresnelFactor, 0.0) / (1.0 - fresnelFactor);
            #ifdef LU_IPBR
                fresnelM = mix(lu_pow2(fresnelM), fresnelM * 0.75 + 0.25, intenseFresnel);
            #else
                fresnelM = mix(lu_pow2(fresnelM), fresnelM * 0.5 + 0.5, intenseFresnel);
            #endif
            fresnelM = fresnelM * lu_sqrt1(smoothnessD) - dither * 0.001;

            if (fresnelM > 0.0) {
                #ifdef LU_TAA
                    float noiseMult = 0.3;
                #else
                    float noiseMult = 0.1;
                #endif
                #ifdef LU_TEMPORAL_FILTER
                    float blendFactor = 1.0;
                    float writeFactor = 1.0;
                #endif
                #if defined LU_CUSTOM_PBR || defined LU_IPBR && defined IS_IRIS
                    if (entityOrHand) {
                        noiseMult *= 0.1;
                        #ifdef LU_TEMPORAL_FILTER
                            blendFactor = 0.0;
                            writeFactor = 0.0;
                        #endif
                    }
                #endif
                noiseMult *= lu_pow2(1.0 - smoothnessD);

                vec2 roughCoord = gl_FragCoord.xy / 128.0;
                vec3 roughNoise = vec3(
                    texture2D(noisetex, roughCoord).r,
                    texture2D(noisetex, roughCoord + 0.09375).r,
                    texture2D(noisetex, roughCoord + 0.1875).r
                );
                roughNoise = fract(roughNoise + vec3(dither, dither * goldenRatio, dither * lu_pow2(goldenRatio)));
                roughNoise = noiseMult * (roughNoise - vec3(0.5));

                normalM += roughNoise;

                vec4 reflection = lu_GetReflection(normalM, viewPos.xyz, nViewPos, playerPos, lViewPos, z0,
                                                depthtex0, dither, skyLightFactor, fresnel,
                                                smoothnessD, vec3(0.0), vec3(0.0), vec3(0.0), 0.0);

                vec3 colorAdd = reflection.rgb * reflectColor;

                float colorMultInv = 1.0;

                vec3 colorP = color;

                #ifdef LU_TEMPORAL_FILTER
                    vec3 cameraOffset = cameraPosition - previousCameraPosition;
                    vec2 prvCoord = SHalfReprojection(playerPos, cameraOffset);
                    #if defined LU_IPBR && !defined LU_GENERATED_NORMALS
                        vec2 prvRefCoord = lu_Reprojection(vec3(texCoord, max(refPos.z, z0)), cameraOffset);
                        vec4 oldRef = texture2D(colortex7, prvRefCoord);
                    #else
                        vec2 prvRefCoord = lu_Reprojection(vec3(texCoord, z0), cameraOffset);
                        vec2 prvRefCoord2 = lu_Reprojection(vec3(texCoord, max(refPos.z, z0)), cameraOffset);
                        vec4 oldRef1 = texture2D(colortex7, prvRefCoord);
                        vec4 oldRef2 = texture2D(colortex7, prvRefCoord2);
                        vec3 dif1 = colorAdd - oldRef1.rgb;
                        vec3 dif2 = colorAdd - oldRef2.rgb;
                        float dotDif1 = dot(dif1, dif1);
                        float dotDif2 = dot(dif2, dif2);

                        float oldRefMixer = lu_clamp01((dotDif1 - dotDif2) * 500.0);
                        vec4 oldRef = mix(oldRef1, oldRef2, oldRefMixer);
                    #endif

                    vec4 newRef = vec4(colorAdd, colorMultInv);
                    vec2 oppositePreCoord = texCoord - 2.0 * (prvCoord - texCoord);

                    blendFactor *= float(prvCoord.x > 0.0 && prvCoord.x < 1.0 && prvCoord.y > 0.0 && prvCoord.y < 1.0);
                    float velocity = length(cameraOffset) * max(16.0 - lViewPos / gbufferProjection[1][1], 3.0);
                    blendFactor *= mix(1.0, exp(-velocity) * 0.5 + 0.5, smoothnessD);

                    float linearZDif = abs(lu_GetLinearDepth(texture2D(colortex1, oppositePreCoord).r) - linearZ0) * far;
                    blendFactor *= lu_max0(2.0 - linearZDif) * 0.5;

                    vec3 texture5P = texture2D(colortex5, oppositePreCoord, 0).rgb;
                    vec3 texture5Dif = abs(texture5 - texture5P);
                    if (texture5Dif != clamp(texture5Dif, vec3(-0.004), vec3(0.004))) {
                        blendFactor = 0.0;

                    }

                    blendFactor = lu_max0(blendFactor);
                    newRef = max(newRef, vec4(0.0));
                    refToWrite = mix(newRef, oldRef, blendFactor * 0.95);
                    refToWrite = mix(max(refToWrite, newRef), refToWrite, lu_pow2(lu_pow2(lu_pow2(refToWrite.a))));

                    color.rgb *= 1.0 - refToWrite.a * fresnelM;
                    color.rgb += refToWrite.rgb * fresnelM;
                    refToWrite *= writeFactor;
                #else
                    color *= 1.0 - colorMultInv * fresnelM;
                    color += colorAdd * fresnelM;
                #endif

                color = max(colorP, color);

            }
        #endif

        #ifdef WORLD_OUTLINE
            #ifndef LU_WORLD_OUTLINE_ON_ENTITIES
                if (!entityOrHand)
            #endif
            lu_DoWorldOutline(color, linearZ0);
        #endif

        #ifndef LU_SKY_EFFECT_REFLECTION
            waterRefColor = sqrt(color) - 1.0;
        #else
            waterRefColor = color;
        #endif

        #ifdef END
        {
            vec3 worldNormal_em = texelFetch(colortex5, texelCoord, 0).rgb;

            if (length(worldNormal_em) > 0.1) {
                worldNormal_em = normalize(worldNormal_em);
                vec3  moonDir_em = normalize(vec3(0.35, 0.55, -0.75));
                float NdotM      = dot(worldNormal_em, moonDir_em);

                float litWrap    = clamp(NdotM * 0.5 + 0.5, 0.0, 1.0);
                float litFront   = max(NdotM, 0.0);
                vec3  moonLight  = vec3(0.75, 0.10, 0.06) * 0.18 * litFront;

                float shadowAmt  = 1.0 - litWrap;
                float shadowMul  = mix(1.0, 0.55, shadowAmt * 0.85);

                color.rgb = color.rgb * shadowMul + moonLight;
            }
        }
        #endif

        lu_DoFog(color, skyFade, lViewPos, playerPos, VdotU, VdotS, dither);
    } else {
        #ifdef DISTANT_HORIZONS
            float z0DH = texelFetch(dhDepthTex, texelCoord, 0).r;
            if (z0DH < 1.0) {
                vec4 screenPosDH = vec4(texCoord, z0DH, 1.0);
                vec4 viewPosDH = dhProjectionInverse * (screenPosDH * 2.0 - 1.0);
                viewPosDH /= viewPosDH.w;
                lViewPos = length(viewPosDH.xyz);
                playerPos = lu_ViewToPlayer(viewPosDH.xyz);

                #ifndef LU_SKY_EFFECT_REFLECTION
                    waterRefColor = sqrt(color) - 1.0;
                #else
                    waterRefColor = color;
                #endif

                lu_DoFog(color.rgb, skyFade, lViewPos, playerPos, VdotU, VdotS, dither);
            } else {
        #endif

        skyFade = 1.0;

        #ifdef OVERWORLD
            #if LU_AURORA_STYLE > 0
                auroraBorealis = lu_GetAuroraBorealis(viewPos.xyz, VdotU, dither);
                color.rgb += auroraBorealis;
            #endif
            #ifdef NIGHT_NEBULA
                nightNebula += lu_GetNightNebula(viewPos.xyz, VdotU, VdotS);
                color.rgb += nightNebula;
            #endif
        #endif
        #ifdef NETHER
            color.rgb = netherColor * (1.0 - maxBlindnessDarkness);

            #ifdef ATM_COLOR_MULTS
                color.rgb *= atmColorMult;
            #endif
        #endif
        #ifdef END
            color.rgb = endSkyColor;
            color.rgb += lu_GetEnderStars(viewPos.xyz, VdotU);

            {
                vec3 nWorldDir = normalize(mat3(gbufferModelViewInverse) * viewPos.xyz);
                vec3 moonDir   = normalize(vec3(0.35, 0.55, -0.75));
                float md       = dot(nWorldDir, moonDir);

                float halo = smoothstep(0.935, 0.985, md);
                color.rgb += vec3(0.55, 0.07, 0.03) * halo * halo * 0.85;

                if (md > 0.985) {
                    float t    = (md - 0.985) / 0.015;
                    float edge = smoothstep(0.0, 0.04, t);

                    vec3 ortho1 = normalize(cross(moonDir, vec3(0.0, 1.0, 0.0)));
                    vec3 ortho2 = cross(moonDir, ortho1);
                    vec2 uv = vec2(dot(nWorldDir, ortho1), dot(nWorldDir, ortho2)) * 18.0;
                    float n1 = texture2D(noisetex, uv * 0.50).r;
                    float n2 = texture2D(noisetex, uv * 1.70 + 0.31).g;
                    float craters = smoothstep(0.42, 0.78, n1 * 0.6 + n2 * 0.4);

                    float blotch  = smoothstep(0.55, 0.95, texture2D(noisetex, uv * 0.18).b);

                    vec3 moonBase   = vec3(0.95, 0.18, 0.12);
                    vec3 moonShadow = vec3(0.22, 0.03, 0.02);
                    vec3 moonCol    = mix(moonBase, moonShadow, craters * 0.85);
                    moonCol         = mix(moonCol, moonShadow * 1.4, blotch * 0.6);

                    moonCol *= 0.55 + 0.45 * t;

                    color.rgb = mix(color.rgb, moonCol, edge);
                }
            }

            {
                vec3 nWorldDir_bh = normalize(mat3(gbufferModelViewInverse) * viewPos.xyz);
                vec3 bhDir        = normalize(vec3(-0.40, 0.35, 0.85));
                float bd          = dot(nWorldDir_bh, bhDir);

                float outerHalo = smoothstep(0.940, 0.985, bd);
                color.rgb += vec3(0.30, 0.10, 0.55) * outerHalo * outerHalo * 0.55;

                if (bd > 0.978) {
                    float t   = (bd - 0.978) / 0.022;

                    vec3 oA = normalize(cross(bhDir, vec3(0.0, 1.0, 0.0)));
                    vec3 oB = cross(bhDir, oA);
                    vec2 luv = vec2(dot(nWorldDir_bh, oA), dot(nWorldDir_bh, oB));
                    float radius = length(luv);
                    float angle  = atan(luv.y, luv.x);

                    float spin   = frameTimeCounter * 0.04;
                    vec2 swirlUV = vec2(angle / 6.2831853 + radius * 1.6 + spin,
                                        radius * 4.0 - spin * 0.5);
                    float n1 = texture2D(noisetex, swirlUV * 0.50).r;
                    float n2 = texture2D(noisetex, swirlUV * 1.30 + 0.21).g;
                    float discN = n1 * 0.6 + n2 * 0.4;

                    float photonRing = smoothstep(0.30, 0.55, t) * (1.0 - smoothstep(0.55, 0.78, t));

                    float discFalloff = smoothstep(0.95, 0.55, t);
                    vec3  discColor   = mix(vec3(0.55, 0.10, 0.85),
                                            vec3(0.95, 0.35, 0.20),
                                            discN);
                    vec3 accretion = discColor * discFalloff * (0.55 + discN * 0.85);

                    accretion += vec3(1.20, 0.70, 0.45) * photonRing * 1.4;

                    float core = 1.0 - smoothstep(0.0, 0.30, t);
                    vec3 finalCol = accretion * (1.0 - core);
                    finalCol = mix(finalCol, vec3(0.0), core);

                    float discMask = smoothstep(0.0, 0.04, t) * smoothstep(1.02, 0.95, t);
                    color.rgb = mix(color.rgb, finalCol, discMask);
                }
            }

            color.rgb *= 1.0 - maxBlindnessDarkness;

            #ifdef ATM_COLOR_MULTS
                color.rgb *= atmColorMult;
            #endif
        #endif

        #ifdef DISTANT_HORIZONS
        }
        #endif
    }

    #ifdef END
    {
        vec3 nWorldDir_gr = normalize(mat3(gbufferModelViewInverse) * viewPos.xyz);
        vec3 moonDir_gr   = normalize(vec3(0.35, 0.55, -0.75));
        float md_gr       = max(dot(nWorldDir_gr, moonDir_gr), 0.0);

        float cone   = pow(md_gr, 6.0);

        vec2 nUV     = nWorldDir_gr.xy * 4.0 + nWorldDir_gr.z * 2.0;
        float streak = texture2D(noisetex, nUV * 0.35).r;
        streak       = mix(0.55, 1.30, streak);

        float skyMask = step(0.999, z0);
        float surfaceWeight = mix(0.30, 1.00, skyMask);

        vec3  rayColor = vec3(0.85, 0.10, 0.06);
        float rayInt   = cone * streak * 0.55 * surfaceWeight;
        color.rgb += rayColor * rayInt;
    }
    #endif

    float cloudLinearDepth = 1.0;
    vec4 clouds = vec4(0.0);

    #ifdef LU_VL_CLOUDS_ACTIVE
        float cloudZCheck = 0.56;

        if (z0 > cloudZCheck) {
            clouds = LU_GetClouds(cloudLinearDepth, skyFade, cameraPosition, playerPos,
                               lViewPos, VdotS, VdotU, dither, auroraBorealis, nightNebula);

            color = mix(color, clouds.rgb, clouds.a);
        }
    #endif

    #ifdef LU_SKY_EFFECT_REFLECTION
        waterRefColor = mix(waterRefColor, clouds.rgb, clouds.a);
        waterRefColor = sqrt(waterRefColor) - 1.0;
    #endif

    #if defined LU_LIGHTSHAFTS_ACTIVE && (LU_LIGHTSHAFT_BEHAVIOUR == 1 && LU_SHADOW_QUALITY >= 1 || defined END)
        if (viewWidth + viewHeight - gl_FragCoord.x - gl_FragCoord.y < 1.5)
            cloudLinearDepth = vlFactor;
    #endif

    #if defined OVERWORLD && defined LU_ATMOSPHERIC_FOG && (defined SPECIAL_BIOME_WEATHER || LU_RAIN_STYLE == 2)
        float altitudeFactorRaw = GetAtmFogAltitudeFactor(playerPos.y + cameraPosition.y);
        vec3 atmFogColor = GetAtmFogColor(altitudeFactorRaw, VdotS);

        #if LU_RAIN_STYLE == 2
            float factor = 1.0;
        #else
            float factor = max(inSnowy, inDry);
        #endif

        color = mix(color, atmFogColor, 0.5 * rainFactor * factor * lu_sqrt1(skyFade));
    #endif

    #ifdef DARK_OUTLINE
        if (clouds.a < 0.5) lu_DoDarkOutline(color, skyFade, z0, dither);
    #endif

    /*DRAWBUFFERS:054*/
    gl_FragData[0] = vec4(color, 1.0);
    gl_FragData[1] = vec4(waterRefColor, 1.0 - skyFade);
    gl_FragData[2] = vec4(cloudLinearDepth, 0.0, 0.0, 1.0);
    #ifdef LU_TEMPORAL_FILTER

        /*DRAWBUFFERS:0547*/
        gl_FragData[3] = refToWrite;
    #endif
}

#endif

#ifdef VERTEX_SHADER

noperspective out vec2 texCoord;

flat out vec3 upVec, sunVec;

#if defined LU_LIGHTSHAFTS_ACTIVE && (LU_LIGHTSHAFT_BEHAVIOUR == 1 && LU_SHADOW_QUALITY >= 1 || defined END)
    flat out float vlFactor;
#endif

void main() {
    gl_Position = ftransform();
    texCoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;

    upVec = normalize(gbufferModelView[1].xyz);
    sunVec = GetSunVector();

    #if defined LU_LIGHTSHAFTS_ACTIVE && (LU_LIGHTSHAFT_BEHAVIOUR == 1 && LU_SHADOW_QUALITY >= 1 || defined END)
        vlFactor = texelFetch(colortex4, ivec2(viewWidth-1, viewHeight-1), 0).r;

        #ifdef END
            if (frameCounter % int(0.06666 / frameTimeSmooth + 0.5) == 0) {
                vec2 absCamPosXZ = abs(cameraPosition.xz);
                float maxCamPosXZ = max(absCamPosXZ.x, absCamPosXZ.y);

                if (gl_Fog.start / far > 0.5 || maxCamPosXZ > 350.0) vlFactor = max(vlFactor - OSIEBCA*2, 0.0);
                else                                                 vlFactor = min(vlFactor + OSIEBCA*2, 1.0);
            }
        #endif
    #endif
}

#endif
