// ============================================================================
// SHADOW FILTERING
// ============================================================================
#ifndef SHADOW_FILTER_GLSL
#define SHADOW_FILTER_GLSL

#include "/lib/settings.glsl"

// Hard shadow calculation with acne prevention.
float getHardShadow(sampler2D shadowTex, vec3 shadowPos, float NdotL, float distortFactor) {
    // Apply slope-scaled bias based on light angle to prevent acne.
    float dynamicBias = max(0.001 * (1.0 - NdotL), 0.0005) * distortFactor;
    
    #if ENABLE_SMOOTH_SHADOWS == 1
        // Lightweight 4-tap PCF to smooth shadow edges without blurring.
        float shadow = 0.0;
        float texel = 1.0 / float(shadowMapResolution);
        
        float d1 = texture2D(shadowTex, shadowPos.xy + vec2(-0.5, -0.5) * texel).r;
        float d2 = texture2D(shadowTex, shadowPos.xy + vec2( 0.5, -0.5) * texel).r;
        float d3 = texture2D(shadowTex, shadowPos.xy + vec2(-0.5,  0.5) * texel).r;
        float d4 = texture2D(shadowTex, shadowPos.xy + vec2( 0.5,  0.5) * texel).r;
        
        float targetZ = shadowPos.z - dynamicBias;
        
        shadow += (d1 < targetZ) ? 0.0 : 1.0;
        shadow += (d2 < targetZ) ? 0.0 : 1.0;
        shadow += (d3 < targetZ) ? 0.0 : 1.0;
        shadow += (d4 < targetZ) ? 0.0 : 1.0;
        
        return shadow * 0.25;
    #else
        // Single-tap shadow map read for hard cel-shading.
        float recordedDepth = texture2D(shadowTex, shadowPos.xy).r;
        
        // Check if the current fragment is in shadow.
        if (recordedDepth < shadowPos.z - dynamicBias) {
            return 0.0;
        }
        return 1.0; 
    #endif
}

#endif