// Rebase every union bone's palette rows from its OWNER part's draw space into the anchor's,
// with K solved from GEOMETRY instead of draw constants: each non-anchor part designates a
// WITNESS bone it shares with the anchor. Both parts recover that bone (each in its own space);
// the recoveries land in reserved palette slots via the scatter maps, and
// K = inverse(M_witness_part) . M_witness_anchor. Constants stay untouched — some renderers
// (the battle movement-preview hologram) bind vs-cb1 as a WINDOW into one shared buffer
// (VSSetConstantBuffers1 FirstConstant), which a whole-resource copy cannot see through.
StructuredBuffer<float4> palRaw    : register(t0);   // 4*(unionBones + witness slots) rows
Buffer<uint>             ownerPart : register(t1);   // per union bone: owning part index
RWStructuredBuffer<float4> palOut  : register(u1);
static const uint ROWS=652;      // 4*unionBones — witness slots beyond are inputs only
static const uint ANCHOR=2;
static const uint2 WIT[4] = { uint2(0x0000028c,0x00000000), uint2(0x00000290,0x0000000c), uint2(0xffffffff,0xffffffff), uint2(0x00000294,0x00000010) };   // per part: base row of (partSide, anchorSide) witness; x=0xFFFFFFFF = no witness (keep the row as-is)

float4x4 AffineInverse(float4 r0, float4 r1, float4 r2, float4 r3){
    float3 a=r0.xyz, b=r1.xyz, c=r2.xyz, t=r3.xyz;
    float3 bc=cross(b,c), ca=cross(c,a), ab=cross(a,b);
    float det=dot(a,bc);
    float3 i0=float3(bc.x,ca.x,ab.x)/det;    // rows of R^-1 (row-vector convention)
    float3 i1=float3(bc.y,ca.y,ab.y)/det;
    float3 i2=float3(bc.z,ca.z,ab.z)/det;
    float3 ti=-(t.x*i0+t.y*i1+t.z*i2);
    return float4x4(float4(i0,0),float4(i1,0),float4(i2,0),float4(ti,1));
}

[numthreads(64,1,1)]
void main(uint3 tid : SV_DispatchThreadID){
    uint i=tid.x; if(i>=ROWS) return;
    uint bone=i>>2;
    uint pi=ownerPart[bone];
    if(pi==ANCHOR || pi>=4 || WIT[pi].x==0xFFFFFFFF){ palOut[i]=palRaw[i]; return; }
    uint2 w=WIT[pi];
    float4x4 MP=float4x4(palRaw[w.x],palRaw[w.x+1],palRaw[w.x+2],palRaw[w.x+3]);
    float4x4 MA=float4x4(palRaw[w.y],palRaw[w.y+1],palRaw[w.y+2],palRaw[w.y+3]);
    float4x4 K=mul(AffineInverse(MP[0],MP[1],MP[2],MP[3]), MA);
    palOut[i]=mul(palRaw[i], K);
}
