nx_nxa_rig_motion_stream.nx source
↩ module page · 127 lines · 4566 B
1// nx_nxa_rig_motion_stream.nx -- Computes motion transformations for animated entities using basis matrices and affine composition.
2import "nx_nxa_rig_motion_20260909.nx"
3
4import "nx_nxa_anim_lib.nx"
5
6// Continuous frame evaluation uses the same admitted map and source ANIM as the native gate.
7// Workspace and rows belong to one caller; no global palette, entity count or joint ceiling.
8func nrm_frame_words(ns:i64,nt:i64)->i64 {
9 if ns<1||nt<1 {return 0}
10 let max:i64=9223372036854775807/8
11 if nt>(max-64)/10 {return 0}
12 let rest:i64=max-64-nt*10
13 if ns>rest/7 {return 0}
14 return ns*7+nt*10+64
15}
16func nrm_basis(v:*i64,out:*i64,sax:*i64,ssg:*i64,tax:*i64,tsg:*i64)->i64 {
17 var c:i64=0
18 while c<3 {out[tax[c]]=v[sax[c]]*ssg[c]*tsg[c];c=c+1}
19 return 0
20}
21func nrm_basis_det(sax:*i64,ssg:*i64,tax:*i64,tsg:*i64,m:*i64)->i64 {
22 var i:i64=0
23 while i<9 {m[i]=0;i=i+1}
24 i=0
25 while i<3 {m[tax[i]*3+sax[i]]=ssg[i]*tsg[i];i=i+1}
26 return m[0]*(m[4]*m[8]-m[5]*m[7])-m[1]*(m[3]*m[8]-m[5]*m[6])+m[2]*(m[3]*m[7]-m[4]*m[6])
27}
28// External initialization must admit the ANIM index, signed-permutation frame and disjoint spans.
29// Time is source clip milliseconds; caller retains phase and actor/root policy.
30struct NrmFrameInput {
31 anim: *i64
32 tidx: *i64
33 order: *i64
34 ns: i64
35 nt: i64
36 sax: *i64
37 ssg: *i64
38 tax: *i64
39 tsg: *i64
40 map: *i64
41 tpar: *i64
42 tbind: *i64
43 bdst: *i64
44 bound: i64
45 sse: i64
46 tse: i64
47}
48func nrm_frame(frame:*NrmFrameInput,t:i64,rows:*i64,row_words:i64,work:*i64,work_words:i64)->i64 {
49 let anim:*i64=frame.anim
50 let tidx:*i64=frame.tidx
51 let order:*i64=frame.order
52 let ns:i64=frame.ns
53 let nt:i64=frame.nt
54 let sax:*i64=frame.sax
55 let ssg:*i64=frame.ssg
56 let tax:*i64=frame.tax
57 let tsg:*i64=frame.tsg
58 let map:*i64=frame.map
59 let tpar:*i64=frame.tpar
60 let tbind:*i64=frame.tbind
61 let bdst:*i64=frame.bdst
62 let bound:i64=frame.bound
63 let sse:i64=frame.sse
64 let tse:i64=frame.tse
65 let need:i64=nrm_frame_words(ns,nt)
66 if need==0||work_words<need {return 0-10}
67 if row_words/8<nt {return 0-11}
68 let q:*i64=work
69 let d:*i64=((q as i64)+ns*32) as *i64
70 let W:*i64=((d as i64)+ns*24) as *i64
71 let P:*i64=((W as i64)+nt*32) as *i64
72 let dt:*i64=((P as i64)+nt*24) as *i64
73 let scratch:*i64=((dt as i64)+nt*24) as *i64
74 let tmp:*i64=((scratch as i64)+64) as *i64
75 let matrix:*i64=((scratch as i64)+128) as *i64
76 let det:i64=nrm_basis_det(sax,ssg,tax,tsg,matrix)
77 var j:i64=0
78 while j<ns {
79 let qp:*i64=((q as i64)+j*32) as *i64
80 let dp:*i64=((d as i64)+j*24) as *i64
81 qp[0]=0;qp[1]=0;qp[2]=0;qp[3]=NRM_Q12
82 dp[0]=0;dp[1]=0;dp[2]=0
83 if tidx[j*2]>=0 {
84 if order[j]==1 {na_eval_track_ordered(anim,tidx[j*2],tidx[j*2+1],t,qp,dp,scratch)}
85 else {na_eval_track(anim,tidx[j*2],tidx[j*2+1],t,qp,dp,scratch)}
86 }
87 nrm_basis(qp,tmp,sax,ssg,tax,tsg)
88 qp[0]=tmp[0]*det;qp[1]=tmp[1]*det;qp[2]=tmp[2]*det
89 nrm_basis(dp,tmp,sax,ssg,tax,tsg)
90 dp[0]=tmp[0];dp[1]=tmp[1];dp[2]=tmp[2]
91 j=j+1
92 }
93 let rc:i64=nrm_compose(ns,nt,q,d,map,tpar,tbind,bdst,bound,sse,tse,W,P,dt,scratch)
94 if rc!=0 {return rc}
95 return nrm_affine_rows(nt,tbind,W,dt,rows,scratch)
96}
97
98func nrm_affine_rows(nj:i64,bind:*i64,q:*i64,dt:*i64,out:*i64,scr:*i64)->i64 {
99 // Bound both quaternion products and the three-term affine dual sum in i64.
100 let coordinate_limit:i64=9223372036854775807/(64*NRM_Q12)
101 var lane:i64=0
102 while lane<nj*4 {if q[lane]<0-NRM_Q12||q[lane]>NRM_Q12 {return 0-1}lane=lane+1}
103 lane=0
104 while lane<nj*3 {
105 if bind[lane]<0-coordinate_limit||bind[lane]>coordinate_limit {return 0-1}
106 if dt[lane]<0-coordinate_limit||dt[lane]>coordinate_limit {return 0-1}
107 lane=lane+1
108 }
109 let rot:*i64=scr
110 let work:*i64=((scr as i64)+32) as *i64
111 var j:i64=0
112 while j<nj {
113 let r:i64=j*4;let d:i64=nj*4+r
114 let qp:*i64=((q as i64)+r*8) as *i64
115 nf_qrotv(qp,bind[j*3],bind[j*3+1],bind[j*3+2],rot,work)
116 let tx:i64=bind[j*3]+dt[j*3]-rot[0]
117 let ty:i64=bind[j*3+1]+dt[j*3+1]-rot[1]
118 let tz:i64=bind[j*3+2]+dt[j*3+2]-rot[2]
119 out[r]=q[r];out[r+1]=q[r+1];out[r+2]=q[r+2];out[r+3]=q[r+3]
120 out[d]=(tx*q[r+3]+ty*q[r+2]-tz*q[r+1])/2
121 out[d+1]=(0-tx*q[r+2]+ty*q[r+3]+tz*q[r])/2
122 out[d+2]=(tx*q[r+1]-ty*q[r]+tz*q[r+3])/2
123 out[d+3]=(0-tx*q[r]-ty*q[r+1]-tz*q[r+2])/2
124 j=j+1
125 }
126 return 0
127}