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,int 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) {
        float shadow1 = shadow2D(shadowtex1, vec3(shadowPos.st, shadowPos.z)).x;

        if (shadow1 > 0.0) shadowcol = texture2D(shadowcolor0, shadowPos.st).rgb * shadow1;
}
#endif

return shadowcol * (1.0 - shadow0) + shadow0;
}

vec3 SampleFilteredShadow(vec3 shadowPos,float offset){
vec3 shadow=SampleBasicShadow(vec3(shadowPos.st,shadowPos.z));

for(int i=0;i<9;i++){
    shadow+=SampleBasicShadow(vec3(offset*shadowoffsets[i]+shadowPos.st,shadowPos.z));
}

return shadow*.1;
}

#if TAA_SHADOW_FILTER == 0

vec3 SampleTAAFilteredShadow(vec3 shadowPos,float offset){
float noise=InterleavedGradientNoise();

vec3 shadow=vec3(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<2;++i){
    vec2 offset=offsetDist(noise+i,2)*offset;
    shadow+=SampleBasicShadow(vec3(shadowPos.st+offset,shadowPos.z));
    shadow+=SampleBasicShadow(vec3(shadowPos.st-offset,shadowPos.z));
    
}
return shadow*.25;
}
#endif

#if TAA_SHADOW_FILTER == 1

vec3 SampleTAAFilteredShadow(vec3 shadowPos,float offset){
float noise=InterleavedGradientNoise();
vec3 shadow=vec3(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<2;++i){
    vec2 offset=offsetDist(noise+i,-1)*offset;
    shadow+=SampleBasicShadow(vec3(shadowPos.st+offset,shadowPos.z));
    shadow+=SampleBasicShadow(vec3(shadowPos.st-offset,shadowPos.z));
}

return shadow*.25;
}
#endif

vec3 GetShadow(vec3 shadowPos,float bias,float offset){
shadowPos.z-=bias;

#ifdef SHADOW_FILTER
#if AA > 1
vec3 shadow=SampleTAAFilteredShadow(shadowPos,offset);
#else
vec3 shadow=SampleFilteredShadow(shadowPos,offset);
#endif
#else
vec3 shadow=SampleBasicShadow(shadowPos);
#endif

return shadow;
}