// TruVisuals - CRT / VHS ChromaBleed
// Chromatic aberration / VHS colour bleed.
// Samples RED a few px to the RIGHT and BLUE a few px to the LEFT of the
// current pixel (Green stays put), producing subtle RGB fringing on edges.
// Edge Falloff optionally weights the offset stronger toward the frame edges,
// like a real lens (radial). Keyframeable, subtle defaults.
//
// Uses the texture transform signature because it must read neighbouring pixels.

DEFINE_UI_PARAMS(amount, Amount px, DCTLUI_SLIDER_FLOAT, 2.5, 0.0, 12.0, 0.1)
DEFINE_UI_PARAMS(edgeFalloff, Edge Falloff, DCTLUI_SLIDER_FLOAT, 0.5, 0.0, 1.0, 0.01)

__DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, __TEXTURE__ p_TexR, __TEXTURE__ p_TexG, __TEXTURE__ p_TexB)
{
    // Radial falloff weight: 0 at frame centre -> ~1 at the corners.
    float cx = (float)p_Width  * 0.5f;
    float cy = (float)p_Height * 0.5f;
    float dx = ((float)p_X - cx) / cx;   // ~[-1, 1] across width
    float dy = ((float)p_Y - cy) / cy;   // ~[-1, 1] across height
    float rNorm = _saturatef((dx * dx + dy * dy) * 0.5f);

    // Edge Falloff = 0 -> uniform offset everywhere.
    // Edge Falloff = 1 -> offset only builds up toward the edges.
    float w   = 1.0f + edgeFalloff * (rNorm - 1.0f);   // mix(1.0, rNorm, edgeFalloff)
    float off = amount * w;                            // per-pixel horizontal offset (px)

    float fx = (float)p_X;
    float fy = (float)p_Y;

    // Bilinear (clamped) neighbour sampling. Green is untouched.
    float r = _tex2D(p_TexR, fx + off, fy);   // red  pulled from the RIGHT
    float g = _tex2D(p_TexG, fx,       fy);   // green stays
    float b = _tex2D(p_TexB, fx - off, fy);   // blue pulled from the LEFT

    return make_float3(r, g, b);
}
