#include "ShaderConstants.fxh"

struct PS_Input
{
    float4 position : SV_Position;
    float4 color : COLOR;
    float2 uv : TEXCOORD_0_FB_MSAA;
};

struct PS_Output
{
    float4 color : SV_Target;
};

float median(float a, float b, float c) {
    return max(min(a, b), min(max(a, b), c));
}

static const float GLYPH_UV_SIZE = 1.0 / 16.0;

ROOT_SIGNATURE
void main(in PS_Input PSInput, out PS_Output PSOutput)
{
    float4 diffuse = TEXTURE_0.Sample(TextureSampler0, PSInput.uv);

#ifdef SMOOTH
    const float center = 0.4f;
    const float radius = 0.1f;

    diffuse = smoothstep(center - radius, center + radius, diffuse);
#endif

#ifdef ALPHA_TEST
    if (diffuse.a < 0.5)
    {
        discard;
    }
#endif

#ifdef MSDF
    float4 resultColor = PSInput.color;

    const float sampleDistance = median(diffuse.r, diffuse.g, diffuse.b);

    const float innerEdgeAlpha = smoothstep(max(0.0, GLYPH_CUTOFF - GLYPH_SMOOTH_RADIUS), min(1.0, GLYPH_CUTOFF + GLYPH_SMOOTH_RADIUS), sampleDistance);
    // Apply fill cutoff
    resultColor = lerp(OUTLINE_COLOR, resultColor, innerEdgeAlpha);

    const float outerEdgeAlpha = smoothstep(max(0.0, OUTLINE_CUTOFF - GLYPH_SMOOTH_RADIUS), min(1.0, OUTLINE_CUTOFF + GLYPH_SMOOTH_RADIUS), sampleDistance);
    // Apply stroke (outline) cutoff
    resultColor = float4(resultColor.rgb, resultColor.a * outerEdgeAlpha);

    const float2 topLeft = floor(PSInput.uv / GLYPH_UV_SIZE) * GLYPH_UV_SIZE;
    const float2 bottomRight = floor(PSInput.uv / GLYPH_UV_SIZE) * GLYPH_UV_SIZE + GLYPH_UV_SIZE;

    const float4 shadowSample = TEXTURE_0.Sample(TextureSampler0, clamp(PSInput.uv - SHADOW_OFFSET, topLeft, bottomRight));
    const float shadowDistance = shadowSample.a;
    const float shadowAlpha = smoothstep(max(0.0, OUTLINE_CUTOFF - SHADOW_SMOOTH_RADIUS), min(1.0, OUTLINE_CUTOFF + SHADOW_SMOOTH_RADIUS), shadowDistance);
    // Apply shadow past the stroke
    resultColor = lerp(float4(SHADOW_COLOR.rgb, SHADOW_COLOR.a * shadowAlpha), resultColor, outerEdgeAlpha);

    diffuse = resultColor;
#else
    diffuse *= PSInput.color;
#endif

    PSOutput.color = diffuse * DARKEN;
}