
#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 = 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_w1 = vec3(0.0);
    vec3 vL_w0 = vec3(0.0);
    vec3 vL_w = vec3(0.0);
    vec3 transmittance;
    float rayLength;
    float rayLength0;
    vec3 absorbance0 = vec3(1.0);
    vec3 absorbance1 = vec3(1.0);
    vec3 refractedSunVec = refract(lightPos, -vec3(0.0, 1.0, 0.0), 0.9);
    float SdotV = dot(sunVec, normalize(fragpos));

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

    if (isEyeInWater == 1)
    {

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

#endif



#ifdef OVERWORLD

    float rayLengthGround0 = pow(length(fragpos0), 1.75) * fogAmount * mix(1, 10, rainStrength);
    float rayLengthGround1 = pow(length(fragpos), 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));

    vL_w0 = fogfunc(mat3(gbufferModelViewInverse) * fragpos0, rayLength0, estEyeDepth, absorbance0, 1.0);
    vL_w1 = fogfunc(p3, rayLength, estEyeDepth, absorbance1, 1.0);
    switch (isEyeInWater)
    {
    case 0:
        float blend = gbf(mat3(gbufferModelViewInverse) * fragpos0, far, 0.0);

        if (iswater)
        {

            solid *= absorbance1;
            solid += vL_w1;
        }

        translucent.rgb *= transmittance;
        translucent.rgb += vL_a;

        solid *= transmittance;
        solid += vL_a;

        break;
    case 1:


        solid *= absorbance0;
        solid += vL_w0;
        translucent.rgb *= absorbance1;
        translucent.rgb += vL_w1;
        sky *= absorbance1;
        sky += vL_w0;

        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(estimatedDepth_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;
}