preset raw;

#include "/Shaders/Internal/shadow_cast_shared.swsl"

const highp float LIGHTING_HEIGHT = 1.0;

const highp float g_MinVariance = 0.0;

varying highp vec2 worldPosition;

uniform highp vec4 lightColor;
// Position of the light, in world coordinates.
uniform highp vec2 lightCenter;
uniform highp float lightRange;
uniform highp float lightPower;
uniform highp float lightSoftness;
uniform highp float lightFalloff;
uniform highp float lightCurveFactor;
uniform highp float lightIndex;
uniform sampler2D shadowMap;

void vertex()
{
    highp vec3 transformed = modelMatrix * vec3(VERTEX, 1.0);
    worldPosition = transformed.xy;
    transformed = projectionMatrix * viewMatrix * transformed;

    VERTEX = transformed.xy;
}

highp float shadowContrib(highp vec2 diff)
{
    highp float dist = length(diff);

    return smoothstep(0.0, 1.0, ChebyshevUpperBound(occludeDepth(diff, shadowMap, lightIndex), dist));
}

void fragment()
{
    highp float mask = zTexture(UV).r;

    highp vec2 diff = worldPosition - lightCenter;

    // Totally not hacky PCF on top of VSM.
    highp float occlusion = lightIndex < 0.0 ? 1.0 : createOcclusion(diff);

    if (occlusion == 0.0)
    {
        discard;
    }

    // this implementation of light attenuation primarily adapted from
    // https://lisyarus.github.io/blog/posts/point-light-attenuation.html
    highp float sqr_dist = dot(diff, diff) + LIGHTING_HEIGHT;

    highp float s = clamp(sqrt(sqr_dist) / lightRange, 0.0, 1.0);
    highp float s2 = s * s;
    // controls curve by lerping between two variants (inverse-shape and inversequadratic-shape)
    highp float curveFactor = mix(s, s2, clamp(lightCurveFactor, 0.0, 1.0));
    highp float val = clamp(((1.0 - s2) * (1.0 - s2)) / (1.0 + lightFalloff * curveFactor), 0.0, 1.0);

    val *= lightPower;
    val *= mask;

    COLOR = vec4(lightColor.rgb, val * occlusion);
}

