code wiki / (root) / nx_fbx_affine_t32.nx

nx_fbx_affine_t32.nx source

↩ module page · 235 lines · 14389 B

1// Private affine qualification in the existing FBX/NXA animation ownership chain. 2// Native full matrices are evaluation output only; no new NXA channel or playback claim. 3import "nx_nxa_anim_t30.nx" 4import "nx_nxa_bind.nx" 5import "nx_vecmath.nx" 6import "nx_f32_sincos.nx" 7const AF_UNSUPPORTED:i64=0-50 8const AF_CHANNEL:i64=0-51 9const AF_TIMING:i64=0-52 10const AF_CAPACITY:i64=0-53 11const AF_COMPONENT_LIMIT:i64=FBB_I64_MAX/(2*FBB_Q) 12const AF_RAD_PER_DEG_F32:i64=1016003125 13const AF_FULL_DEG_Q20:i64=360*FBB_Q 14const AF_HALF_DEG_Q20:i64=180*FBB_Q 15struct FbxAffineModel { id:i64,parent:i64,values:*i64,channels:*i64, } 16struct FbxAffineCurve { times:*u8,values:*u8,count:i64, } 17struct FbxAffineScene { models:*FbxAffineModel,count:i64,curves:*FbxAffineCurve,curve_count:i64,graph:*FbxClipGraph,selection:*FbxClipSelection, } 18func af_model(s:*FbxAffineScene,i:i64)->*FbxAffineModel{return ((s.models as i64)+i*__size_of(FbxAffineModel)) as *FbxAffineModel} 19func af_curve(s:*FbxAffineScene,i:i64)->*FbxAffineCurve{return ((s.curves as i64)+i*__size_of(FbxAffineCurve)) as *FbxAffineCurve} 20func af_find(s:*FbxAffineScene,id:i64)->i64{var i:i64=0;while i<s.count{if af_model(s,i).id==id{return i};i=i+1};return FC_MISSING} 21// Twelve words: T,R,S; rotation order; inheritance; unsupported-transform marker. 22func af_properties(b:*u8,n:i64,start:i64,end:i64,big:i64,v:*i64)->i64{ 23 let h:*i64=sys_mmap(FBXC_OUTN*8) as *i64 24 let hit:i64=fbb_find_child(b,n,start,end,big,"Properties70" as *u8,h) 25 if hit<=0{sys_munmap(h as *u8,FBXC_OUTN*8);return hit} 26 var p:i64=h[FBXC_PROPSOFF]+h[FBXC_PLEN];let pe:i64=h[FBXC_END] 27 var result:i64=0 28 while p<pe&&result==0{ 29 let rc:i64=fbb_node(b,n,p,pe,big,h) 30 if rc<=0{if rc<0{result=rc};p=pe} 31 else{ 32 let ep:i64=h[FBXC_PROPSOFF]+h[FBXC_PLEN];let po:i64=h[FBXC_PROPSOFF] 33 var slot:i64=0-1;var identity:i64=0 34 if fbb_string(b,po,ep,"Lcl Translation" as *u8)==1{slot=0} 35 if fbb_string(b,po,ep,"Lcl Rotation" as *u8)==1{slot=3} 36 if fbb_string(b,po,ep,"Lcl Scaling" as *u8)==1{slot=6} 37 if fbb_string(b,po,ep,"RotationOrder" as *u8)==1{slot=9} 38 if fbb_string(b,po,ep,"InheritType" as *u8)==1{slot=10} 39 if fbb_string(b,po,ep,"PreRotation" as *u8)==1||fbb_string(b,po,ep,"PostRotation" as *u8)==1{slot=11} 40 if fbb_string(b,po,ep,"RotationPivot" as *u8)==1||fbb_string(b,po,ep,"ScalingPivot" as *u8)==1{slot=11} 41 if fbb_string(b,po,ep,"RotationOffset" as *u8)==1||fbb_string(b,po,ep,"ScalingOffset" as *u8)==1{slot=11} 42 if fbb_string(b,po,ep,"GeometricTranslation" as *u8)==1||fbb_string(b,po,ep,"GeometricRotation" as *u8)==1{slot=11} 43 if fbb_string(b,po,ep,"GeometricScaling" as *u8)==1{slot=11;identity=FBB_Q} 44 if slot>=0{ 45 var q:i64=po;var k:i64=0 46 while k<4&&result==0{let size:i64=fbb_property_size(b,q,ep);if size<5||b[q]!=(83 as u8){result=FBB_BAD}else{q=q+size};k=k+1} 47 if result==0{ 48 if slot==9||slot==10{if fbb_property_size(b,q,ep)!=5||b[q]!=(73 as u8){result=FBB_BAD}else{v[slot]=fbxc_i32(b,q+1)}} 49 else{ 50 k=0;while k<3&&result==0{ 51 if fbb_property_size(b,q,ep)!=9||b[q]!=(68 as u8){result=FBB_BAD} 52 else{let bits:i64=fbxc_i64le(b,q+1);let exponent:i64=(bits>>52)&2047 53 if exponent>=1065{result=FBB_RANGE}else{let value:i64=fbxc_f64_p20(bits);if value<0-AF_COMPONENT_LIMIT||value>AF_COMPONENT_LIMIT{result=FBB_RANGE}else{if slot==11{if value!=identity{v[11]=1}}else{v[slot+k]=value}}} 54 };q=q+9;k=k+1 55 } 56 } 57 } 58 } 59 p=h[FBXC_END] 60 } 61 } 62 sys_munmap(h as *u8,FBXC_OUTN*8);return result 63} 64func af_template(b:*u8,n:i64,big:i64,v:*i64)->i64{ 65 let h:*i64=sys_mmap(FBXC_OUTN*8) as *i64 66 let c:*i64=sys_mmap(FBXC_OUTN*8) as *i64 67 if fbb_find_child(b,n,27,n,big,"Definitions" as *u8,h)!=1{return FBB_MISSING} 68 var p:i64=h[FBXC_PROPSOFF]+h[FBXC_PLEN];let end:i64=h[FBXC_END];var matches:i64=0;var result:i64=0 69 while p<end&&result==0{ 70 let rc:i64=fbb_node(b,n,p,end,big,h) 71 if rc<=0{if rc<0{result=rc};p=end}else{ 72 if fbxc_name_is(b,h[FBXC_NAMEOFF],h[FBXC_NAMELEN],"ObjectType" as *u8)==1&&fbb_string(b,h[FBXC_PROPSOFF],h[FBXC_PROPSOFF]+h[FBXC_PLEN],"Model" as *u8)==1{ 73 matches=matches+1 74 if fbb_find_child(b,n,h[FBXC_PROPSOFF]+h[FBXC_PLEN],h[FBXC_END],big,"PropertyTemplate" as *u8,c)!=1{result=FBB_MISSING}else{ 75 if fbb_string(b,c[FBXC_PROPSOFF],c[FBXC_PROPSOFF]+c[FBXC_PLEN],"FbxNode" as *u8)!=1{result=AF_UNSUPPORTED}else{result=af_properties(b,n,c[FBXC_PROPSOFF]+c[FBXC_PLEN],c[FBXC_END],big,v)} 76 } 77 };p=h[FBXC_END] 78 } 79 } 80 sys_munmap(h as *u8,FBXC_OUTN*8);sys_munmap(c as *u8,FBXC_OUTN*8) 81 if result!=0{return result};if matches!=1{return FC_AMBIGUOUS};return 0 82} 83func af_models(b:*u8,n:i64,g:*FbxClipGraph,max_models:i64,s:*FbxAffineScene)->i64{ 84 if max_models<=0||max_models>n/13{return AF_CAPACITY} 85 let defaults:*i64=sys_mmap(96) as *i64;defaults[6]=FBB_Q;defaults[7]=FBB_Q;defaults[8]=FBB_Q 86 let big:i64=fbxc_big(fbxc_version(b,n));let dr:i64=af_template(b,n,big,defaults);if dr!=0{return dr} 87 var i:i64=0;var count:i64=0;while i<g.count{if fc_object(g,i).kind==FC_MODEL{count=count+1};i=i+1} 88 if count<=0||count>max_models{return AF_CAPACITY} 89 s.models=sys_mmap(count*__size_of(FbxAffineModel)) as *FbxAffineModel;s.count=count 90 let h:*i64=sys_mmap(FBXC_OUTN*8) as *i64 91 i=0;var m:i64=0 92 while i<g.count{ 93 let object:*FbxClipObject=fc_object(g,i) 94 if object.kind==FC_MODEL{ 95 let model:*FbxAffineModel=af_model(s,m);model.id=object.id;model.parent=0-1;model.values=sys_mmap(96) as *i64;model.channels=sys_mmap(72) as *i64 96 var j:i64=0;while j<12{model.values[j]=defaults[j];j=j+1};j=0;while j<9{model.channels[j]=0-1;j=j+1} 97 if fbb_node(b,n,object.offset,n,big,h)!=1{return FBB_BAD} 98 let rc:i64=af_properties(b,n,h[FBXC_PROPSOFF]+h[FBXC_PLEN],h[FBXC_END],big,model.values);if rc!=0{return rc} 99 if model.values[9]!=0||model.values[10]!=1||model.values[11]!=0{return AF_UNSUPPORTED} 100 m=m+1 101 };i=i+1 102 } 103 i=0;while i<g.link_count{let link:*FbxClipLink=fc_link(g,i);if link.kind==1{let child:i64=af_find(s,link.src);let parent:i64=af_find(s,link.dst);if child>=0&&parent>=0{let model:*FbxAffineModel=af_model(s,child);if model.parent>=0{return FC_AMBIGUOUS};model.parent=parent}};i=i+1} 104 sys_munmap(defaults as *u8,96);sys_munmap(h as *u8,FBXC_OUTN*8);return 0 105} 106 107func af_linear(b:*u8,n:i64,offset:i64,nk:i64)->i64{ 108 let h:*i64=sys_mmap(FBXC_OUTN*8) as *i64;let c:*i64=sys_mmap(FBXC_OUTN*8) as *i64 109 let flags:*i64=sys_mmap(32) as *i64;let refs:*i64=sys_mmap(32) as *i64 110 let big:i64=fbxc_big(fbxc_version(b,n)) 111 if fbb_node(b,n,offset,n,big,h)!=1{return FBB_BAD} 112 let start:i64=h[FBXC_PROPSOFF]+h[FBXC_PLEN];let end:i64=h[FBXC_END] 113 if fbb_find_child(b,n,start,end,big,"KeyAttrFlags" as *u8,c)!=1{return AF_UNSUPPORTED} 114 if b[c[FBXC_PROPSOFF]]!=(105 as u8){return FBB_BAD} 115 if fbxc_array(b,c[FBXC_PROPSOFF]+1,4,flags)!=0{return FBB_BAD} 116 if fbb_find_child(b,n,start,end,big,"KeyAttrRefCount" as *u8,c)!=1{return AF_UNSUPPORTED} 117 if b[c[FBXC_PROPSOFF]]!=(105 as u8){return FBB_BAD} 118 if fbxc_array(b,c[FBXC_PROPSOFF]+1,4,refs)!=0{return FBB_BAD} 119 var rc:i64=0;var sum:i64=0;var i:i64=0 120 if flags[2]<=0||flags[2]!=refs[2]||flags[2]>nk||flags[1]!=flags[2]*4||refs[1]!=refs[2]*4{rc=FBB_BAD} 121 while i<flags[2]&&rc==0{ 122 if (fbxc_i32(flags[0] as *u8,i*4)&14)!=4{rc=AF_UNSUPPORTED} 123 let repeat:i64=fbxc_i32(refs[0] as *u8,i*4);if repeat<=0||repeat>nk-sum{rc=FBB_BAD}else{sum=sum+repeat};i=i+1 124 } 125 if sum!=nk{rc=FBB_BAD} 126 if flags[3]==1{sys_munmap(flags[0] as *u8,flags[1])};if refs[3]==1{sys_munmap(refs[0] as *u8,refs[1])} 127 sys_munmap(flags as *u8,32);sys_munmap(refs as *u8,32);sys_munmap(h as *u8,FBXC_OUTN*8);sys_munmap(c as *u8,FBXC_OUTN*8);return rc 128} 129func af_curves(b:*u8,n:i64,G:*i64,s:*FbxAffineScene,max_keys:i64)->i64{ 130 if max_keys<=0||max_keys>FBB_I64_MAX/8{return AF_CAPACITY} 131 s.curve_count=G[1];s.curves=sys_mmap(G[1]*__size_of(FbxAffineCurve)) as *FbxAffineCurve 132 var i:i64=0;var keys:i64=0 133 while i<G[1]{ 134 let nk:i64=G[A_CKT+i*4+1];if nk<=0||nk!=G[A_CKV+i*4+1]||nk>max_keys-keys{return AF_CAPACITY};keys=keys+nk 135 let object_index:i64=fc_find(s.graph,G[A_CID+i]);if object_index<0{return object_index} 136 let rc:i64=af_linear(b,n,fc_object(s.graph,object_index).offset,nk);if rc!=0{return rc} 137 let curve:*FbxAffineCurve=af_curve(s,i) 138 let times:*i64=sys_mmap(32) as *i64;let values:*i64=sys_mmap(32) as *i64 139 if b[G[A_CKT+i*4]-13]!=(108 as u8)||b[G[A_CKV+i*4]-13]!=(102 as u8){return FBB_BAD} 140 if fbxc_array(b,G[A_CKT+i*4]-12,8,times)!=0||fbxc_array(b,G[A_CKV+i*4]-12,4,values)!=0{return FBB_BAD} 141 if times[1]!=nk*8||values[1]!=nk*4{return FBB_BAD} 142 curve.times=times[0] as *u8;curve.values=values[0] as *u8;curve.count=nk 143 sys_munmap(times as *u8,32);sys_munmap(values as *u8,32) 144 var k:i64=0;var previous:i64=0-1 145 while k<nk{ 146 let ticks:i64=fbxc_i64le(curve.times,k*8);if ticks<0||ticks>FBB_I64_MAX/FBB_Q||ticks<=previous{return AF_TIMING};previous=ticks 147 let bits:i64=fbxc_u32(curve.values,k*4);if ((bits>>23)&255)>=149{return FBB_RANGE} 148 let value:i64=vm_f32_to_int(bits,FBB_Q);if value<0-AF_COMPONENT_LIMIT||value>AF_COMPONENT_LIMIT{return FBB_RANGE};k=k+1 149 } 150 var node:i64=0;var axis:i64=0-1;var seen:i64=0;k=0 151 while k<G[2]{if G[A_CONN+k*3]==G[A_CID+i]{let tag:i64=G[A_CONN+k*3+2];if tag>=3*256+88&&tag<=3*256+90{node=G[A_CONN+k*3+1];axis=tag-(3*256+88);seen=seen+1}};k=k+1} 152 if seen!=1{return AF_CHANNEL} 153 var model:i64=0-1;var slot:i64=0-1;seen=0;k=0 154 while k<G[2]{if G[A_CONN+k*3]==node{ 155 let index:i64=af_find(s,G[A_CONN+k*3+1]);if index>=0{let tag:i64=G[A_CONN+k*3+2] 156 if tag==15*256+110{slot=0};if tag==12*256+110{slot=3};if tag==11*256+103{slot=6} 157 if slot<0{return AF_CHANNEL};model=index;seen=seen+1 158 } 159 };k=k+1} 160 if seen!=1||model<0{return AF_CHANNEL};let target:*FbxAffineModel=af_model(s,model) 161 if target.channels[slot+axis]>=0{return FC_AMBIGUOUS};target.channels[slot+axis]=i 162 i=i+1 163 } 164 return 0 165} 166// Admission is bounded before any decoded array allocation. Buffers are owned by this offline job. 167func af_load(b:*u8,n:i64,stack:i64,array_budget:i64,depth_budget:i64,max_models:i64,max_keys:i64,s:*FbxAffineScene)->i64{ 168 if s.count!=0||s.curve_count!=0{return FBB_BAD} 169 let report:*NxaBindReport=sys_mmap(__size_of(NxaBindReport)) as *NxaBindReport 170 let admitted:i64=nb_preflight(b,n,array_budget,depth_budget,report);if admitted!=0{return admitted} 171 let G:*i64=sys_mmap(A_WORDS*8) as *i64 172 s.graph=sys_mmap(__size_of(FbxClipGraph)) as *FbxClipGraph;s.selection=sys_mmap(__size_of(FbxClipSelection)) as *FbxClipSelection 173 let selected:i64=a_load_selected(b,n,stack,G,s.graph,s.selection);if selected!=0{return selected} 174 let models:i64=af_models(b,n,s.graph,max_models,s);if models!=0{return models} 175 let curves:i64=af_curves(b,n,G,s,max_keys) 176 sys_munmap(G as *u8,A_WORDS*8);sys_munmap(report as *u8,__size_of(NxaBindReport));return curves 177} 178// Original authored linear scalar curve. Euler values are not rewritten to shortest-path angles. 179func af_sample(c:*FbxAffineCurve,ticks:i64)->i64{ 180 let last:i64=c.count-1 181 if ticks<=fbxc_i64le(c.times,0){return vm_f32_to_int(fbxc_u32(c.values,0),FBB_Q)} 182 if ticks>=fbxc_i64le(c.times,last*8){return vm_f32_to_int(fbxc_u32(c.values,last*4),FBB_Q)} 183 var i:i64=1;while i<c.count{ 184 let next:i64=fbxc_i64le(c.times,i*8) 185 if ticks<=next{let previous:i64=fbxc_i64le(c.times,(i-1)*8);let a:i64=vm_f32_to_int(fbxc_u32(c.values,(i-1)*4),FBB_Q);let z:i64=vm_f32_to_int(fbxc_u32(c.values,i*4),FBB_Q) 186 let fraction:i64=(ticks-previous)*FBB_Q/(next-previous);return a+(z-a)*fraction/FBB_Q 187 };i=i+1 188 };return vm_f32_to_int(fbxc_u32(c.values,last*4),FBB_Q) 189} 190 191func af_identity(m:*i64)->i64{var i:i64=0;while i<16{m[i]=0;i=i+1};m[0]=FBB_Q;m[5]=FBB_Q;m[10]=FBB_Q;m[15]=FBB_Q;return 0} 192func af_angle(value:i64)->i64{var angle:i64=value%AF_FULL_DEG_Q20;if angle>AF_HALF_DEG_Q20{angle=angle-AF_FULL_DEG_Q20};if angle<0-AF_HALF_DEG_Q20{angle=angle+AF_FULL_DEG_Q20};return nx_f32_mul(vm_int_to_f32(angle,FBB_Q),AF_RAD_PER_DEG_F32)} 193// Column-major Q20 T*Rz*Ry*Rx*S. Only admitted XYZ/RSrs/no-pivot models reach this owner. 194func af_local(v:*i64,out:*i64)->i64{ 195 let m:*i64=sys_mmap(128) as *i64;let rotation:*i64=sys_mmap(128) as *i64 196 af_identity(m);m[0]=v[6];m[5]=v[7];m[10]=v[8] 197 var axis:i64=0;var rc:i64=0 198 while axis<3&&rc==0{ 199 af_identity(rotation);let rad:i64=af_angle(v[3+axis]);let sn:i64=vm_f32_to_int(nx_f32_sin(rad),FBB_Q);let cs:i64=vm_f32_to_int(nx_f32_cos(rad),FBB_Q) 200 if axis==0{rotation[5]=cs;rotation[6]=sn;rotation[9]=0-sn;rotation[10]=cs} 201 if axis==1{rotation[0]=cs;rotation[2]=0-sn;rotation[8]=sn;rotation[10]=cs} 202 if axis==2{rotation[0]=cs;rotation[1]=sn;rotation[4]=0-sn;rotation[5]=cs} 203 rc=fbb_compose(rotation,m,m);axis=axis+1 204 } 205 if rc==0{m[12]=v[0];m[13]=v[1];m[14]=v[2];var i:i64=0;while i<16{out[i]=m[i];i=i+1}} 206 sys_munmap(m as *u8,128);sys_munmap(rotation as *u8,128);return rc 207} 208// Caller-owned column-major matrices; staged output stays unchanged on failed hierarchy/evaluation. 209func af_evaluate(s:*FbxAffineScene,ticks:i64,use_curves:i64,out:*i64,out_words:i64)->i64{ 210 if s.count<=0||s.count>FBB_I64_MAX/128||out_words<s.count*16{return AF_CAPACITY} 211 if ticks<0||ticks>FBB_I64_MAX/FBB_Q||use_curves<0||use_curves>1{return AF_TIMING} 212 let matrices:*i64=sys_mmap(s.count*128) as *i64;let done:*i64=sys_mmap(s.count*8) as *i64 213 let values:*i64=sys_mmap(72) as *i64;let local:*i64=sys_mmap(128) as *i64 214 var remaining:i64=s.count;var rc:i64=0 215 while remaining>0&&rc==0{ 216 var progress:i64=0;var i:i64=0 217 while i<s.count&&rc==0{ 218 let model:*FbxAffineModel=af_model(s,i) 219 if model.parent>=s.count{rc=FBB_BAD} 220 else{if done[i]==0{var ready:i64=0;if model.parent<0{ready=1}else{if done[model.parent]==1{ready=1}} 221 if ready==1{ 222 var k:i64=0;while k<9{values[k]=model.values[k];if use_curves==1&&model.channels[k]>=0{values[k]=af_sample(af_curve(s,model.channels[k]),ticks)};k=k+1} 223 rc=af_local(values,local) 224 if rc==0{let destination:*i64=((matrices as i64)+i*128) as *i64 225 if model.parent<0{k=0;while k<16{destination[k]=local[k];k=k+1}}else{rc=fbb_compose(((matrices as i64)+model.parent*128) as *i64,local,destination)} 226 if rc==0{done[i]=1;progress=progress+1;remaining=remaining-1} 227 } 228 } 229 }};i=i+1 230 } 231 if progress==0&&remaining>0&&rc==0{rc=FC_AMBIGUOUS} 232 } 233 if rc==0{var i:i64=0;while i<s.count*16{out[i]=matrices[i];i=i+1}} 234 sys_munmap(matrices as *u8,s.count*128);sys_munmap(done as *u8,s.count*8);sys_munmap(values as *u8,72);sys_munmap(local as *u8,128);return rc 235}