//////////////////////////////////////////////////////////////////////////////
//    ##      #####   ######   ######     ##     ####     #######  ##  ##   //
//   ####    ##   ##  # ## #    ##  ##   ####     ##       ##   #  ##  ##   //
//  ##  ##   #          ##      ##  ##  ##  ##    ##       ## #     ####    //
//  ##  ##    #####     ##      #####   ##  ##    ##       ####      ##     //
//  ######        ##    ##      ## ##   ######    ##   #   ## #     ####    //
//  ##  ##   ##   ##    ##      ##  ##  ##  ##    ##  ##   ##   #  ##  ##   //
//  ##  ##    #####    ####    #### ##  ##  ##   #######  #######  ##  ##   //
//--------------------------------------------------------------------------//
//--------------------------------------------------------------------------//
//      #####   ##   ##    ##     #####    #######  ######    #####         //
//     ##   ##  ##   ##   ####     ## ##    ##   #   ##  ##  ##   ##        //
//     #        ##   ##  ##  ##    ##  ##   ## #     ##  ##  #              //
//      #####   #######  ##  ##    ##  ##   ####     #####    #####         //
//          ##  ##   ##  ######    ##  ##   ## #     ## ##        ##        //
//          ##  ##   ##  ######    ##  ##   ## #     ## ##        ##        //
//     ##   ##  ##   ##  ##  ##    ## ##    ##   #   ##  ##  ##   ##        //
//      #####   ##   ##  ##  ##   #####    #######  #### ##   #####         //
/////(BSL Shaders Edit)//////////////////////////////////////By LexBoosT//////

uniform sampler2DShadow shadowtex0;

#ifdef SHADOW_COLOR
uniform sampler2DShadow shadowtex1;
uniform sampler2D shadowcolor0;
#endif

vec2 shadowOffsets[9] = vec2[9](
    vec2( 0.0, 0.0),
    vec2( 0.0, 1.0),
    vec2( 0.7, 0.7),
    vec2( 1.0, 0.0),
    vec2( 0.7,-0.7),
    vec2( 0.0,-1.0),
    vec2(-0.7,-0.7),
    vec2(-1.0, 0.0),
    vec2(-0.7, 0.7)
);

vec2 offsetDist(float x, float s) {
	float n = fract(x * 1.414) * 3.1415;
    return vec2(cos(n), sin(n)) * 1.4 * x / s;
}

vec3 SampleBasicShadow(vec3 shadowPos) {
    float shadow0 = shadow2D(shadowtex0, vec3(shadowPos.st, shadowPos.z)).x;

    vec3 shadowCol = vec3(0.0);
    #ifdef SHADOW_COLOR
    if(shadow0 < 1.0){
        shadowCol = texture2D(shadowcolor0, shadowPos.st).rgb *
                    shadow2D(shadowtex1, vec3(shadowPos.st, shadowPos.z)).x;
    }
    #endif

    return clamp(shadowCol * (1.0 - shadow0) + shadow0, vec3(0.0), vec3(1.0));
}

vec3 SampleFilteredShadow(vec3 shadowPos, float offset) {
    float shadow0 = 0.0;
    float dither = InterleavedGradientNoise();

    for(int i = 0; i < 9; i++){
        vec2 shadowOffset = shadowOffsets[i] * offset;
        shadow0 += shadow2D(shadowtex0, vec3(shadowPos.st + shadowOffset, shadowPos.z)).x;
    }
    shadow0 /= 9.0;

    vec3 shadowCol = vec3(0.0);
    #ifdef SHADOW_COLOR
    if(shadow0 < 0.999){
        for(int i = 0; i < 9; i++){
            vec2 shadowOffset = shadowOffsets[i] * offset;
            shadowCol += texture2D(shadowcolor0, shadowPos.st + shadowOffset).rgb *
                         shadow2D(shadowtex1, vec3(shadowPos.st + shadowOffset, shadowPos.z)).x;
        }
        shadowCol /= 9.0;
    }
    #endif

    return clamp(shadowCol * (1.0 - shadow0) + shadow0, vec3(0.0), vec3(1.0));
}

#if TAA_SHADOW_FILTER == 0

vec3 SampleTAAFilteredShadow(vec3 shadowPos, float offset) {
    float shadow0 = 0.0;
    float dither = InterleavedGradientNoise();
    
    offset = offset * (2.0 - 0.5 * (0.85 + 0.25 * (3072.0 / shadowMapResolution)));
    if (shadowMapResolution < 400.0) offset *= 30.0;

    for(int i = 0; i < 2; i++){
        vec2 shadowOffset = offsetDist(dither + i, 2) * offset;
        shadow0 += shadow2D(shadowtex0, vec3(shadowPos.st + shadowOffset, shadowPos.z)).x;
        shadow0 += shadow2D(shadowtex0, vec3(shadowPos.st - shadowOffset, shadowPos.z)).x;

    }
    shadow0 /= 2.0;

    vec3 shadowCol = vec3(0.0);
    #ifdef SHADOW_COLOR
    if(shadow0 < 0.999){
        for(int i = 0; i < 3; i++){
            vec2 shadowOffset = offsetDist(dither + i, 3) * offset;
            shadowCol += texture2D(shadowcolor0, shadowPos.st + shadowOffset).rgb *
                         shadow2D(shadowtex1, vec3(shadowPos.st + shadowOffset, shadowPos.z)).x;
        }
        shadowCol /= 3.0;
    }
    #endif

    return clamp(shadowCol * (1.0 - shadow0) + shadow0, vec3(0.0), vec3(1.0));
}

#endif

#if TAA_SHADOW_FILTER == 1

vec3 SampleTAAFilteredShadow(vec3 shadowPos, float offset) {
    float shadow0 = 0.0;
    float dither = InterleavedGradientNoise();

    offset = offset * (2.0 - 0.5 * (0.85 + 0.25 * (3072.0 / shadowMapResolution)));
    if (shadowMapResolution < 400.0) offset *= 30.0;

    for(int i = 0; i < 9; i++){
        vec2 shadowOffset = offsetDist(dither + i, 2) * offset;
        shadow0 += shadow2D(shadowtex0, vec3(shadowPos.st + shadowOffset, shadowPos.z)).x;
        shadow0 += shadow2D(shadowtex0, vec3(shadowPos.st - shadowOffset, shadowPos.z)).x;
    }
    shadow0 /= 9.0;

    vec3 shadowCol = vec3(0.0);
    #ifdef SHADOW_COLOR
    if(shadow0 < 1.0){
        for(int i = 0; i < 9; i++){
            vec2 shadowOffset = offsetDist(dither + i, 2) * offset;
            shadowCol += texture2D(shadowcolor0, shadowPos.st + shadowOffset).rgb *
                         shadow2D(shadowtex1, vec3(shadowPos.st + shadowOffset, shadowPos.z)).x;
        }
        shadowCol /= 9.0;
    }
    #endif

    return clamp(shadowCol * (1.0 - shadow0) + shadow0, vec3(0.0), vec3(1.0));
}

#endif

vec3 CausticsFilteredShadow(vec3 shadowPos, float offset) {
    float dither = InterleavedGradientNoise();

    float shadow0 = 0.0;
    
    offset = offset * (2.0 - 0.5 * (0.85 + 0.25 * (3072.0 / shadowMapResolution)));
    if (shadowMapResolution < 400.0) offset *= 30.0;

    for(int i = 0; i < 4; i++){
        vec2 shadowOffset = offsetDist(dither + i, -1) * offset;
        shadow0 += shadow2D(shadowtex0, vec3(shadowPos.st + shadowOffset, shadowPos.z)).x;
        shadow0 += shadow2D(shadowtex0, vec3(shadowPos.st - shadowOffset, shadowPos.z)).x;
    }
    shadow0 /= 9.0;

    vec3 shadowCol = vec3(0.0);
    #ifdef SHADOW_COLOR
    if(shadow0 < 1.0){
        for(int i = 0; i < 4; i++){
            vec2 shadowOffset = offsetDist(dither + i, -1) * offset;
            shadowCol += texture2D(shadowcolor0, shadowPos.st + shadowOffset).rgb *
                         shadow2D(shadowtex1, vec3(shadowPos.st + shadowOffset, shadowPos.z)).x;
        }
        shadowCol /= 9.0;
    }
    #endif

    return clamp(shadowCol * (1.0 - shadow0) + shadow0, vec3(0.0), vec3(1.0));
}


vec3 GetShadow(vec3 shadowPos,float bias,float offset){
vec3 shadow = vec3(0.0);
#ifdef WATER_CAUSTICS
if(isEyeInWater == 1)
{ 
    shadow=CausticsFilteredShadow(shadowPos,offset);
}
else
#endif
{

    #ifdef SHADOW_FILTER
    #if AA > 0
    shadow=SampleTAAFilteredShadow(shadowPos,offset);
    #else
    shadow=SampleFilteredShadow(shadowPos,offset);
    #endif
    #else
    shadow=SampleBasicShadow(shadowPos);
    #endif
}
return shadow;
}