// Rebase every union bone's palette rows from its OWNER part's draw space into the
// anchor's:  row' = row . K,  K = W_owner . inverse(W_anchor).  W = objectToWorld = vs-cb1 c0..c3,
// row-vector convention (c4..c7 is the root inverse, NOT necessarily this cb's own inverse, so
// the inverse is computed here instead of read).
// Runs at the anchor draw, where every part's cb was captured at the same draw as its vb0 — a
// segment and its K always come from the same frame, so conversion never mixes frames.
cbuffer PartCB0 : register(b5) { float4 W0[4]; }
cbuffer PartCB1 : register(b6) { float4 W1[4]; }
cbuffer PartCB2 : register(b7) { float4 W2[4]; }
cbuffer PartCB3 : register(b8) { float4 W3[4]; }
cbuffer AnchorCB : register(b13) { float4 WA[4]; }   // parts occupy b5..b12 (max 8), anchor b13
StructuredBuffer<float4> palRaw    : register(t0);
Buffer<uint>             ownerPart : register(t1);   // per union bone: owning part index
RWStructuredBuffer<float4> palOut  : register(u1);
static const uint ROWS=652;

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];
    float4x4 WP;
    if(pi==0) WP=float4x4(W0[0],W0[1],W0[2],W0[3]);
    else if(pi==1) WP=float4x4(W1[0],W1[1],W1[2],W1[3]);
    else if(pi==2) WP=float4x4(W2[0],W2[1],W2[2],W2[3]);
    else if(pi==3) WP=float4x4(W3[0],W3[1],W3[2],W3[3]);
    else WP=float4x4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
    float4x4 K=mul(WP, AffineInverse(WA[0],WA[1],WA[2],WA[3]));
    palOut[i]=mul(palRaw[i], K);
}
