#version 330 core
// Final pass of the cutout stroke's signed distance field: turns the
// jump-flooded nearest-seed COORDINATES into a signed distance expressed in
// CANVAS PIXELS, so cutout_stroke.fs can compare it directly against
// outlineWidth / distance (which CutoutStrokeMath.h produces in canvas px).
//
// Two things happen here that matter for macOS parity:
//
//  1. The scale-up. When the canvas exceeds kStrokeSdfComputeMaxSize the field
//     was computed on a downscaled raster, so a texel of distance is
//     u_pxPerTexel canvas pixels. macOS does exactly this
//     (`resultDistance = sdfDistance * upscale`, PR #277 §6.9.1) and accepts
//     the same precision loss on video.
//
//  2. The sign. Distance alone is unsigned; the inside/outside decision comes
//     from the matte, which already has Expand's dilate/erode baked in --
//     the SAME silhouette the seed pass used. §6.9.1's post-decode
//     convention is POSITIVE OUTSIDE, negative inside -- match it exactly,
//     every downstream style threshold is written against it.
//
// Output goes into the other RG32F ping-pong slot and is read back with
// ordinary bilinear texture() sampling, which is what makes a 720-wide field
// upscale smoothly onto a 4K canvas instead of blocking up.

layout (location = 0) out vec2 FragOut;

uniform sampler2D u_field;
uniform sampler2D u_matte;
uniform vec2      u_sdfSize;
uniform vec2      u_matteUvScale;
// Canvas pixels per SDF texel (dstW / sdfW).
uniform float     u_pxPerTexel;
// Saturation cap: texels the flood never reached are pinned here rather than
// left at infinity, so a style threshold can never accidentally match them.
uniform float     u_maxDistPx;

void main() {
    ivec2 p      = ivec2(floor(gl_FragCoord.xy));
    vec2  centre = vec2(p) + 0.5;

    vec2  nearest = texelFetch(u_field, p, 0).rg;
    float distPx  = (nearest.x < -1.0e5)
                      ? u_maxDistPx
                      : min(distance(centre, nearest) * u_pxPerTexel, u_maxDistPx);

    vec2  uv = (centre / u_sdfSize) * u_matteUvScale;
    bool  inside = texture(u_matte, uv).r >= 0.5;

    FragOut = vec2(inside ? -distPx : distPx, 0.0);
}
