// The tie underlay for one absent pool part. PAIR rows: a donor-ridden union row the part owns is
// filled with its nearest ANCHOR-owned ancestor's converted row, verbatim — palette rows are combined
// bind->posed affine maps, so a copy IS the rigid ride (the bind-relative delta cancels against the
// ancestor's inverse bind). SEED rows (no path / no anchor-owned ancestor): identity — bind-pose
// placement in the anchor's space. Both are needed because the converts rewrite EVERY union row: an
// absent part's constants-K is zero (its CB was never filled) and witness-K rides an arbitrary bone,
// so a row left to them collapses. Runs in the anchor's chains only while the part's presence latch is
// down; the frame the part returns, its own recover overwrites these rows again.
// Ancestor rows are read from a COPY of the converted palette, not the UAV: a typed UAV load of a
// 4-component format does not compile on cs_5_0 (single-component 32-bit only), which is why every
// compute in this emission reads through a StructuredBuffer and only WRITES its UAV.
StructuredBuffer<float4> palIn  : register(t0);   // the CONVERTED palette, pre-fill
RWStructuredBuffer<float4> palOut : register(u1);
static const uint PAIRS=2, SEEDS=0;
static const uint2 PAIR[2] = { uint2(18,9), uint2(19,6) };   // x = tied union slot, y = ancestor union slot
static const uint  SEED[1] = { 0 };   // union slots reset to identity
[numthreads(64,1,1)]
void main(uint3 tid : SV_DispatchThreadID){
    uint i=tid.x; if(i>=(PAIRS+SEEDS)*4) return;
    uint p=i>>2, comp=i&3;
    if(p<PAIRS){ palOut[(PAIR[p].x<<2)|comp]=palIn[(PAIR[p].y<<2)|comp]; return; }
    palOut[(SEED[p-PAIRS]<<2)|comp]=float4(comp==0?1.0:0.0,comp==1?1.0:0.0,comp==2?1.0:0.0,comp==3?1.0:0.0);
}
