
#include "/lib/fog/fog_common.glsl"
#include "/lib/fog/fogloop.glsl"
vec3 shadowSpace0()
{
    vec3 p3 = gbufferModelViewInverse[3].xyz;
    p3 = mat3(shadowModelView) * p3 + shadowModelView[3].xyz;
    p3 = diagonal3(shadowProjection) * p3 + shadowProjection[3].xyz;
    return p3;
}
vec3 getVolumetricRays3(vec3 solid, vec4 translucent, inout vec3 sky, float border, vec3 fragpos, vec3 fragpos0,
                        bool iswater, float light, float skylight)
{
    // midnight, morning, day
    // float fogAmount = mix5(1 - normWT, 0.65, 0.65, 0.5, 0.25, 0.1);
    float fogAmount = getFogDensity();

    float ebs = eyeBrightnessSmooth.y / 240.0;
    float dither = noise_standard(gl_FragCoord.xy);
    float bff = gbf(fragpos, far, 0);
    float estEyeDepth = clamp(14.0 - eyeBrightnessSmooth.y / 240.0, 0.0, 1.0);
    estEyeDepth = estEyeDepth * estEyeDepth * estEyeDepth * 16.0;
    vec3 p3 = mat3(gbufferModelViewInverse) * fragpos + gbufferModelViewInverse[3].xyz;
    float Vdiff = distance(fragpos, fragpos0);
    float VdotU = normalize(p3).y;
    float estimatedDepth_a = Vdiff * abs(VdotU); // assuming water plane

    bool noWater = (isEyeInWater == 0 && !iswater);

    vec3 absorbance_a = vec3(1.0);
    vec3 absorbance_w = vec3(1.0);
    vec3 vL_a1 = vec3(0.0);
    vec3 vL_a0 = vec3(0.0);
    vec3 vL_a = vec3(0.0);
    vec3 vL_w = vec3(0.0);
    float density = 0;

    vec3 start = shadowSpace0();
    vec3 end = toShadowSpaceProjected(fragpos);
    vec3 refractedSunVec = refract(lightPos, -vec3(0.0, 1.0, 0.0), 0.9);

    float rayLength = length(fragpos);
    float maxZ = min(rayLength, 32.0) / (1e-8 + rayLength);

    vec3 dV = end - start;
    vec3 dVWorld = mat3(gbufferModelViewInverse) * fragpos;
    float SdotV = dot(sunVec, normalize(fragpos));
    vec3 ambient;
    vec3 sunColor;
#ifdef NETHER
    ambient = vec3(fogColor);
    sunColor = vec3(fogColor);
    fogAmount = 0.1;
#endif

#ifdef OVERWORLD
    ambient = atmosphereUp;
    sunColor = sunLight;

    if (isEyeInWater == 1)
    {

        rayLength = length(fragpos) * maxZ;
    }
    else
    {
        rayLength = bff * 1028;
        if (iswater)
        {
            rayLength = distance(fragpos, fragpos0);
            rayLength = estimatedDepth_a * 1.2;
        }
    }
#endif

#ifdef END
    ambient = vec3(fogColor) * 0.25;
    sunColor = vec3(fogColor);
    fogAmount = 5;
#endif

    float darknessEye = 1;
    float mie_water = phaseg(SdotV, 0.4);
    float Rayleigh = phaseRayleigh(SdotV);
    float expFactor = 11.0;
    float dY = normalize(mat3(gbufferModelViewInverse) * fragpos).y * rayLength;
    float sh0 = 1.0;

#ifdef VOLUMETRIC_LIGHTING
    AtmosphereLoop(VL_SAMPLES, expFactor, dither, rayLength, start, dV, dY, mie_water, Rayleigh, noWater, estEyeDepth,
                   refractedSunVec, ambient, sunColor, sh0, absorbance_w, vL_w, density, dVWorld, fogAmount);
#else
    vec3 fragposmixed = mix(fragpos0, fragpos, 1.0);
    AtmosphereNoLoop(6, 11.0, rayLength, normalize(mat3(gbufferModelViewInverse) * fragposmixed).y * rayLength,
                     phaseg(SdotV, 0.4), phaseRayleigh(SdotV), estEyeDepth, refractedSunVec, atmosphereUp, sunLight,
                     absorbance_w, vL_w);
#endif
    sh0 += 0.001;
    vec3 transmittance;

#ifdef OVERWORLD
    float rayLengthGround0 = pow(length(fragpos0), 1.75) * fogAmount * mix(5, 10, rainStrength);

    float rayLengthGround1 = pow(length(fragpos), 1.75) * fogAmount * mix(5, 10, rainStrength);

#ifdef VL_NOISE_DENSITY



    rayLengthGround0 = pow(length(fragpos0), 1.75) * density * mix(5, 10, rainStrength);

    rayLengthGround1 = pow(length(fragpos), 1.75) * density * mix(5, 10, rainStrength);

#endif
#ifdef DISTANT_HORIZONS

    float mult0 = rayLengthGround0 / dhFarPlane;
    float mult1 = rayLengthGround1 / dhFarPlane;
#else
    float mult0 = rayLengthGround0 / far;
    float mult1 = rayLengthGround1 / far;

#endif
    vL_a0 = fogAtmosphereALT(mat3(gbufferModelViewInverse) * fragpos0, rayLengthGround0, rayLengthGround0, transmittance, clamp((density / 32) * (mult0 / 32) * 0.1, 0.0, 1.0));
    vL_a1 = fogAtmosphereALT(p3, rayLengthGround1, rayLengthGround1, transmittance, clamp((density / 32) * (mult1 / 32) * 0.1, 0.0, 1.0));
#ifdef VL_NOISE_DENSITY

    if (!iswater || isEyeInWater == 1)
        vL_a = mix(vL_a0, vL_a1, translucent.a) ;
    else
        vL_a = vL_a1;
#else
    if (!iswater || isEyeInWater == 1)
        vL_a = mix(vL_a0, vL_a1, translucent.a) * sh0;
    else
        vL_a = vL_a1;
#endif
#else
#ifdef NETHER
    float rayLengthGround0 = pow(length(fragpos0), 2.0) * density;
    float rayLengthGround1 = pow(length(fragpos), 2.0) * density;
#else
    float rayLengthGround0 = pow(length(fragpos0), 1.0) * density;
    float rayLengthGround1 = pow(length(fragpos), 1.0) * density;
#endif
    vL_a0 = fogAtmosphereALT(mat3(gbufferModelViewInverse) * fragpos0, rayLengthGround0, rayLengthGround0, transmittance, 0.0);
    vL_a1 = fogAtmosphereALT(p3, rayLengthGround1, rayLengthGround1, transmittance, 0.0);

    if (!iswater || isEyeInWater == 1)
        vL_a = mix(vL_a0, vL_a1, translucent.a);
    else
        vL_a = vL_a1;

#endif

#ifdef OVERWORLD
    vL_a *= eyeBrightnessSmooth.y / 240.0;
#endif

    float linearDistance = length(vec3(p3.x, max(-p3.y, 0.0), p3.z));
    float fogfade = exp(-0.000001 * (linearDistance * linearDistance * linearDistance));

    switch (isEyeInWater)
    {
    case 0:
        if (iswater)
        {

            solid *= absorbance_w;
            solid += vL_w;
        }
        translucent.rgb *= transmittance;
        translucent.rgb += vL_a;

        solid *= transmittance;
        solid += vL_a;

        break;
    case 1:

        vL_w = mix(vL_w, vL_w, clamp(fogfade, 0.0, 1.0));
        absorbance_w = mix(vec3(0.0), absorbance_w, clamp(fogfade, 0.0, 1.0));

        if (!iswater)

        {

            solid *= absorbance_w;
            solid += vL_w;
        }

        translucent.rgb *= absorbance_w;
        translucent.rgb += vL_w;

        sky *= absorbance_w;
        sky += vL_w;

        break;
    case 2:
    case 3:
        solid *= exp(-length(fragpos) * 1);
        solid += fogColor;
        break;
    }
#if defined SKYBLEND

    float blend_transparent = gbf(p3, far, 0.0);
    float blend_solid = gbf(mat3(gbufferModelViewInverse) * fragpos0, far, 0.0);
    if (iswater)
        blend_solid = blend_transparent;

    solid = mix(solid, sky, blend_solid * blend_solid);
    translucent.rgb = mix(translucent.rgb, sky, blend_transparent * blend_transparent);
#endif

    vec3 color = mix(solid, translucent.rgb, translucent.a);

    //return vec3(vL_a);
    return vec3(color);
}

float GetBorderFogMixFactor(in vec3 eyePlayerPos, in float far, in float z0)
{

    float eyeDist = length(eyePlayerPos);
    float borderFogFactor = smoothstep(far * 0.5, far, eyeDist);
    borderFogFactor *= borderFogFactor * borderFogFactor;
    return (eyeDist > far * 0.5) ? borderFogFactor : 0.0;
}