uniform sampler2DShadow shadow;

uniform ivec2 eyeBrightnessSmooth;
uniform mat4 shadowModelView;
uniform mat4 shadowProjection;

const vec2 shadowOffsets[6] = vec2[6](vec2(0.5303, 0.5303), vec2(-0.6250, -0.0000), vec2(0.3536, -0.3536),
                                      vec2(-0.0000, 0.3750), vec2(-0.1768, -0.1768), vec2(0.1250, 0.0000));

uniform float biasblend;
uniform float biasblend2;

float shadowFunc(float diffuseSun, float sssAmount, vec3 p3, float noise, vec2 lightmap, vec3 normals)
{
    float mix1 = 1.0;
    float mix2 = -0.0002;

#ifdef DISTANT_HORIZONS
    mix1 = mix(1, 1, biasblend2);
    mix2 = mix(0.01, 0.0001, biasblend);
#endif

    float shading = 1.0;
    vec3 ProjShadowPos = (mat3(shadowModelView) * p3) + shadowModelView[3].xyz;

    ProjShadowPos = vec3(ProjShadowPos.x * shadowProjection[0].x + shadowProjection[3].x,
                         ProjShadowPos.y * shadowProjection[1].y + shadowProjection[3].y,
                         ProjShadowPos.z * shadowProjection[2].z + shadowProjection[3].z);

    float distortFac = calcDistort(ProjShadowPos.xy);

    ProjShadowPos.xy *= distortFac;
    diffuseSun = mix(diffuseSun, max(diffuseSun, 0.5), float(sssAmount > 0.0));

    vec2 bounds = vec2(1.0, 1.0) - 1.5 / shadowMapResolution;
    if (all(lessThan(abs(ProjShadowPos.xy), bounds)) && abs(ProjShadowPos.z) < 6 && diffuseSun > 0.001)
    {
        shading = 0.0;
        ProjShadowPos = ProjShadowPos * vec3(0.5, 0.5, 0.0833333) + vec3(0.5);

        vec3 shadowOffset = vec3(shadowProjection[0].x, shadowProjection[1].y, shadowProjection[2].z);
        vec3 modelViewNormals = mat3(shadowModelView) * normals;
        ProjShadowPos += shadowOffset * modelViewNormals * distortFac * mix2;

        float scaleFac = mix(distortFac, noise * 20.0, float(sssAmount > 0.0));

        const float threshMul = max(2048.0 / shadowMapResolution * shaddist / 128.0, 0.95);

        float distortThresh = clamp(sqrt(1.0 - diffuseSun * diffuseSun) / diffuseSun, 0.0, mix1) / scaleFac;

        float diffthresh = distortThresh / 6000.0 * threshMul;

#if SHADOW_FILTERING == 1

        float prec = noise * 6.2831;
        mat2 noiseM = mat2(cos(prec), -sin(prec), sin(prec), cos(prec)) * 0.001;
        float weight = 1.0 + noise * shadowMapResolution * 0.00016;
        float dweight = -diffthresh * weight;

        for (int i = 0; i < 6; i++)
        {
            vec2 offset = noiseM * shadowOffsets[i];

            vec3 shadowCoordWeighted = ProjShadowPos + vec3(offset, dweight);

            shading += texture(shadow, shadowCoordWeighted);
        }
        shading *= 0.1666;
#else
        ProjShadowPos.z -= diffthresh;
        shading = texture(shadow, ProjShadowPos);

#endif

        // shading = clamp((pow(lightmap.y, 16.0) * 2 - 1) * 2.0 + lightmap.y * lightmap.y, 0, 1);

        shading = mix(1.0, shading, nightblendShadows);
    }

    return diffuseSun * shading * lightmap.y * (1 - rainStrength * 0.9);
}
