
#include "/lib/fog/fog_common.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 estEyeDepth = clamp(14.0 - eyeBrightnessSmooth.y / 240.0, 0.0, 1.0);
    estEyeDepth = estEyeDepth * estEyeDepth * estEyeDepth * 24.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

    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);
    vec3 transmittance;
    float rayLength;

    vec3 refractedSunVec = refract(lightPos, -vec3(0.0, 1.0, 0.0), 0.9);
    vec3 fragposmixed = mix(fragpos0, fragpos, 1);
    float SdotV = dot(sunVec, normalize(fragpos));

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

    if (isEyeInWater == 1)
    {

        rayLength = length(fragpos) * maxZ;
    }
    else
    {
        rayLength = gbf(fragposmixed, far, 0) * 1028;
        if (iswater)
        {
            rayLength = distance(fragpos, fragpos0);
            rayLength = estimatedDepth_a * 1.2;
        }
    }

#endif

    if (!(isEyeInWater == 0 && !iswater))
        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);

    vL_a = vL_a + (vL_a - dot(vL_a, vec3(0.299, 0.587, 0.114))) * 0.1;

#ifdef OVERWORLD

    float rayLengthGround0 = pow(length(fragpos0), 1.75) * fogAmount * mix(1, 10, rainStrength);
    float rayLengthGround1 = pow(length(fragposmixed), 1.75) * fogAmount * mix(1, 10, rainStrength);
#else
    float rayLengthGround0 = pow(length(fragpos0), 2.3);
    float rayLengthGround1 = pow(length(fragpos), 2.3);

#endif

    vL_a0 =
        fogAtmosphere2(mat3(gbufferModelViewInverse) * fragpos0, rayLengthGround0, rayLengthGround0, transmittance);
    vL_a1 =
        fogAtmosphere2(p3, rayLengthGround1, rayLengthGround1, transmittance);
    vL_a = mix(vL_a0, vL_a1, translucent.a);
    if (!iswater || isEyeInWater == 1)
        vL_a = mix(vL_a0, vL_a1, translucent.a);
    else
        vL_a = vL_a1;
#ifdef OVERWORLD
    vL_a = vL_a * eyeBrightnessSmooth.y / vec3(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:
        float blend = gbf(mat3(gbufferModelViewInverse) * fragpos0, far, 0.0);

        if (iswater)
        {

            for (int i = 0; i < 4; i++)
            {
                solid *= absorbance_w;
            //    solid += vL_w;
            }
            //   solid = mix(solid, vL_w, blend);
        }

        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)

        {

            for (int i = 0; i < 4; i++)
            {
                solid *= absorbance_w;
                solid += vL_w;
            }
        }

        for (int i = 0; i < 4; i++)
        {
            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(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;
}