/**
 * Copyright (c) 2022-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
 *
 * @author Ludovic Autin <ludovic.autin@gmail.com>
 * @author Alexander Rose <alexander.rose@weirdbyte.de>
 */
export declare const shadows_frag = "\nprecision highp float;\nprecision highp int;\nprecision highp sampler2D;\n\n#include common\n\nuniform sampler2D tDepth;\nuniform vec2 uTexSize;\nuniform vec4 uBounds;\n\nuniform float uNear;\nuniform float uFar;\n\n#if dLightCount != 0\n    uniform vec3 uLightDirection[dLightCount];\n    uniform vec3 uLightColor[dLightCount];\n#endif\n\nuniform vec3 uAmbientColor;\n\nuniform mat4 uProjection;\nuniform mat4 uInvProjection;\n\nuniform float uMaxDistance;\nuniform float uTolerance;\n\n// Map full [0,1] coords -> bounds [0,1] coords\nvec2 fullCoordsToBoundsCoords(vec2 fullCoords) {\n    return (fullCoords - uBounds.xy) / (uBounds.zw - uBounds.xy);\n}\n\n// Map bounds [0,1] coords -> full [0,1] coords\nvec2 boundsCoordsToFullCoords(vec2 boundsCoords) {\n    return uBounds.xy + (uBounds.zw - uBounds.xy) * boundsCoords;\n}\n\nbool isBackground(const in float depth) {\n    return depth == 1.0;\n}\n\nbool outsideBounds(const in vec2 p) {\n    return p.x < uBounds.x || p.y < uBounds.y || p.x > uBounds.z || p.y > uBounds.w;\n}\n\nfloat getViewZ(const in float depth) {\n    #if dOrthographic == 1\n        return orthographicDepthToViewZ(depth, uNear, uFar);\n    #else\n        return perspectiveDepthToViewZ(depth, uNear, uFar);\n    #endif\n}\n\nfloat getDepth(const in vec2 coords) {\n    #ifdef depthTextureSupport\n        return texture2D(tDepth, coords).r;\n    #else\n        return unpackRGBAToDepth(texture2D(tDepth, coords));\n    #endif\n}\n\nfloat screenFade(const in vec2 coords) {\n    vec2 c = (coords - uBounds.xy) / (uBounds.zw - uBounds.xy);\n    vec2 fade = max(12.0 * abs(c - 0.5) - 5.0, vec2(0.0));\n    return saturate(1.0 - dot(fade, fade));\n}\n\n// based on https://panoskarabelas.com/posts/screen_space_shadows/\nvec3 screenSpaceShadow(const in vec3 position, const in vec3 lightDirection, const in vec3 lightColor, const in float stepLength) {\n    // Ray position and direction (in view-space)\n    vec3 rayPos = position;\n    vec3 rayDir = -lightDirection;\n\n    // Compute ray step\n    vec3 rayStep = rayDir * stepLength;\n\n    // Ray march towards the light\n    vec4 rayCoords = vec4(0.0);\n    for (int i = 0; i < dSteps; ++i) {\n        // Step the ray\n        rayPos += rayStep;\n\n        rayCoords = uProjection * vec4(rayPos, 1.0);\n        rayCoords.xyz = (rayCoords.xyz / rayCoords.w) * 0.5 + 0.5;\n        rayCoords.xy = boundsCoordsToFullCoords(rayCoords.xy);\n\n        if (outsideBounds(rayCoords.xy)) {\n            return lightColor;\n        }\n\n        // Compute the difference between the ray's and the camera's depth\n        float depth = getDepth(rayCoords.xy);\n        float viewZ = getViewZ(depth);\n        float zDelta = rayPos.z - viewZ;\n\n        if (zDelta < uTolerance) {\n            // Fade out as we approach the edges of the screen\n            return mix(vec3(0.0), lightColor, 1.0 - screenFade(rayCoords.xy));\n        }\n    }\n\n    return lightColor;\n}\n\nvoid main(void) {\n    vec2 invTexSize = 1.0 / uTexSize;\n    vec2 selfCoords = gl_FragCoord.xy * invTexSize;\n    float selfDepth = getDepth(selfCoords);\n\n    if (isBackground(selfDepth)) {\n        gl_FragColor = vec4(0.0);\n        return;\n    }\n\n    vec2 selfBoundsCoords = fullCoordsToBoundsCoords(selfCoords);\n    if (any(lessThan(selfBoundsCoords, vec2(0.0))) || any(greaterThan(selfBoundsCoords, vec2(1.0)))) {\n        gl_FragColor = vec4(0.0);\n        return;\n    }\n\n    vec3 selfViewPos = screenSpaceToViewSpace(vec3(selfBoundsCoords, selfDepth), uInvProjection);\n    float stepLength = uMaxDistance / float(dSteps);\n\n    float l = length(uAmbientColor);\n    float a = l;\n    #if dLightCount != 0\n        vec3 s;\n        #pragma unroll_loop_start\n        for (int i = 0; i < dLightCount; ++i) {\n            s = screenSpaceShadow(selfViewPos, uLightDirection[i], uLightColor[i], stepLength);\n            l += length(s);\n            a += length(uLightColor[i]);\n        }\n        #pragma unroll_loop_end\n    #endif\n\n    gl_FragColor = vec4(l / a);\n}\n";
