nx_nxa_rig_motion_context.nx source
↩ module page · 171 lines · 6279 B
1// Caller-owned staging boundary for the existing native rig-motion frame evaluator.
2// This is an in-memory ABI, not an NXA replacement or a sampled animation format.
3import "nx_nxa_rig_motion_stream.nx"
4const NRC_HEADER_W:i64=8
5const NRC_INPUT_W:i64=18
6const NRC_MAGIC:i64=1314014001
7const NRC_VERSION:i64=1
8const NRC_I64_MAX:i64=9223372036854775807
9func nrc_ptr(p:*i64,w:i64)->*i64 {return ((p as i64)+w*8) as *i64}
10func nrc_input_words(ns:i64,nt:i64,aw:i64)->i64 {
11 if ns<1||nt<1||aw<1 {return 0}
12 let max:i64=NRC_I64_MAX/8
13 if aw>max-NRC_INPUT_W {return 0}
14 if nt>(max-NRC_INPUT_W-aw)/6 {return 0}
15 return NRC_INPUT_W+nt*6+aw
16}
17func nrc_words(ns:i64,nt:i64,aw:i64)->i64 {
18 let input:i64=nrc_input_words(ns,nt,aw)
19 let work:i64=nrm_frame_words(ns,nt)
20 if input==0||work==0 {return 0}
21 let max:i64=NRC_I64_MAX/8
22 if input>max-NRC_HEADER_W {return 0}
23 var used:i64=NRC_HEADER_W+input
24 if __size_of(NrmFrameInput)/8>max-used {return 0}
25 used=used+__size_of(NrmFrameInput)/8
26 if work>max-used {return 0}
27 used=used+work
28 if ns>(max-used)/3 {return 0}
29 used=used+ns*3
30 if nt>(max-used)/8 {return 0}
31 return used+nt*8
32}
33func nrc_span(p:*i64,w:i64)->i64 {
34 let b:i64=p as i64
35 if b<=0||b%8!=0||w<1 {return 0}
36 if w>(NRC_I64_MAX-b)/8 {return 0}
37 return 1
38}
39// Bound every evaluated parent position and derived dt before arithmetic, from this rig's edges.
40// A q12 quaternion with components bounded by Q rotates each component by at most 4*L1(v).
41func nrc_envelope(input:*i64)->i64 {
42 let nt:i64=input[1]
43 let par:*i64=nrc_ptr(input,NRC_INPUT_W+nt)
44 let bind:*i64=nrc_ptr(par,nt)
45 let limit:i64=NRC_I64_MAX/(64*NRM_Q12)
46 let root_motion:i64=(32768*NA_DT_MM_TO_MODEL)*input[5]/input[4]
47 var j:i64=0
48 while j<nt {
49 var own:i64=0
50 var a:i64=0
51 while a<3 {let v:i64=na_abs(bind[j*3+a]);if v>own {own=v}a=a+1}
52 let budget:i64=limit-own
53 var total:i64=0
54 var k:i64=j
55 while par[k]>=0 {
56 let p:i64=par[k]
57 var edge:i64=0
58 a=0
59 while a<3 {edge=edge+na_abs(bind[k*3+a]-bind[p*3+a]);a=a+1}
60 if edge>(budget-total)/4 {return 0-28}
61 total=total+edge*4
62 k=p
63 }
64 var root:i64=0
65 a=0
66 while a<3 {let v:i64=na_abs(bind[k*3+a]);if v>root {root=v}a=a+1}
67 if root>budget-total {return 0-28}
68 total=total+root
69 if root_motion>budget-total {return 0-28}
70 j=j+1
71 }
72 return 0
73}
74func nrc_bind(ctx:*i64,capacity:i64,input:*i64,input_words:i64)->i64 {
75 if input_words<NRC_INPUT_W||nrc_span(input,input_words)==0 {return 0-20}
76 let ns:i64=input[0];let nt:i64=input[1];let aw:i64=input[2]
77 let iw:i64=nrc_input_words(ns,nt,aw)
78 let need:i64=nrc_words(ns,nt,aw)
79 if iw==0||iw!=input_words||need==0||capacity<need||nrc_span(ctx,need)==0 {return 0-20}
80 let cb:i64=ctx as i64;let ib:i64=input as i64
81 if cb<ib+iw*8&&ib<cb+need*8 {return 0-21}
82 if input[3]<0||input[4]<1||input[5]<1 {return 0-22}
83 // Packed ANIM translations have signed-i16 millimetre lanes; size scaling must fit i64.
84 if input[5]>NRC_I64_MAX/(32768*NA_DT_MM_TO_MODEL) {return 0-22}
85 var i:i64=0
86 while i<3 {
87 let sa:i64=input[6+i];let ta:i64=input[12+i]
88 if sa<0||sa>2||ta<0||ta>2 {return 0-23}
89 if input[9+i]!=1&&input[9+i]!=(0-1) {return 0-23}
90 if input[15+i]!=1&&input[15+i]!=(0-1) {return 0-23}
91 var k:i64=0
92 while k<i {if input[6+k]==sa||input[12+k]==ta {return 0-23}k=k+1}
93 i=i+1
94 }
95 let map:*i64=nrc_ptr(input,NRC_INPUT_W)
96 let par:*i64=nrc_ptr(map,nt)
97 let bind:*i64=nrc_ptr(par,nt)
98 let dist:*i64=nrc_ptr(bind,nt*3)
99 let limit:i64=NRC_I64_MAX/(64*NRM_Q12)
100 i=0
101 while i<nt {
102 if map[i]<0||map[i]>=ns||par[i]<(0-1)||par[i]>=i||dist[i]<0 {return 0-24}
103 var a:i64=0
104 while a<3 {if bind[i*3+a]<0-limit||bind[i*3+a]>limit {return 0-24}a=a+1}
105 i=i+1
106 }
107 if nrc_envelope(input)!=0 {return 0-28}
108 // Ready contexts are immutable: same-input retry succeeds; replacement needs a new context.
109 if ctx[0]==NRC_MAGIC {
110 if ctx[1]!=NRC_VERSION||ctx[2]!=need {return 0-27}
111 let previous:*i64=nrc_ptr(ctx,NRC_HEADER_W)
112 i=0
113 while i<iw {if previous[i]!=input[i] {return 0-27}i=i+1}
114 return 0
115 }
116 ctx[0]=0;ctx[7]=0-25
117 let copy:*i64=nrc_ptr(ctx,NRC_HEADER_W)
118 i=0
119 while i<iw {copy[i]=input[i];i=i+1}
120 let anim:*i64=nrc_ptr(copy,NRC_INPUT_W+nt*6)
121 let idx:*i64=nrc_ptr(copy,iw)
122 let order:*i64=nrc_ptr(idx,ns*2)
123 let dur:i64=na_index(anim,aw,ns,idx)
124 if dur<=0 {return 0-25}
125 na_index_order(anim,idx,ns,order)
126 ctx[1]=NRC_VERSION;ctx[2]=need;ctx[3]=ns;ctx[4]=nt;ctx[5]=aw;ctx[6]=dur;ctx[7]=0
127 ctx[0]=NRC_MAGIC
128 return 0
129}
130func nrc_frame(ctx:*i64,capacity:i64,time:i64)->i64 {
131 if capacity<NRC_HEADER_W||nrc_span(ctx,capacity)==0 {return 0-26}
132 if ctx[0]!=NRC_MAGIC||ctx[1]!=NRC_VERSION {return 0-26}
133 let ns:i64=ctx[3];let nt:i64=ctx[4];let aw:i64=ctx[5]
134 let need:i64=nrc_words(ns,nt,aw)
135 if need==0||need!=ctx[2]||need>capacity||ctx[6]<1 {return 0-26}
136 let input:*i64=nrc_ptr(ctx,NRC_HEADER_W)
137 let iw:i64=nrc_input_words(ns,nt,aw)
138 let map:*i64=nrc_ptr(input,NRC_INPUT_W)
139 let par:*i64=nrc_ptr(map,nt)
140 let bind:*i64=nrc_ptr(par,nt)
141 let dist:*i64=nrc_ptr(bind,nt*3)
142 let anim:*i64=nrc_ptr(dist,nt)
143 let idx:*i64=nrc_ptr(input,iw)
144 let order:*i64=nrc_ptr(idx,ns*2)
145 let frame:*NrmFrameInput=nrc_ptr(order,ns) as *NrmFrameInput
146 let work:*i64=((frame as i64)+__size_of(NrmFrameInput)) as *i64
147 let ww:i64=nrm_frame_words(ns,nt)
148 let rows:*i64=nrc_ptr(work,ww)
149 var t:i64=time%ctx[6]
150 if t<0 {t=t+ctx[6]}
151 frame.anim=anim
152 frame.tidx=idx
153 frame.order=order
154 frame.ns=ns
155 frame.nt=nt
156 frame.sax=nrc_ptr(input,6)
157 frame.ssg=nrc_ptr(input,9)
158 frame.tax=nrc_ptr(input,12)
159 frame.tsg=nrc_ptr(input,15)
160 frame.map=map
161 frame.tpar=par
162 frame.tbind=bind
163 frame.bdst=dist
164 frame.bound=input[3]
165 frame.sse=input[4]
166 frame.tse=input[5]
167 let rc:i64=nrm_frame(frame,t,rows,nt*8,work,ww)
168 ctx[7]=rc
169 if rc!=0 {return rc}
170 return rows as i64
171}