code wiki / (root) / nx_gltf_pose_scratch_candidate_t181.nx

nx_gltf_pose_scratch_candidate_t181.nx source

↩ module page · 175 lines · 13847 B

1// nx_gltf_pose_scratch_candidate_t181.nx -- Implements high-precision quaternion interpolation and fixed-point number conversion for GLTF pose data. 2import "nx_gltf_accessor_candidate_t181.nx" 3import "nx_fbx_bind_scratch_candidate_t181.nx" 4 5// High-precision geodesic quaternion interpolation. Repeated normalized midpoints 6// bisect the short great-circle arc; binary fraction selection avoids low-Q12 angles. 7const VM_Q30:i64=1073741824 8const VM_Q30_BITS:i64=30 9func vm_q_norm_q30(a:*i64,out:*i64,tolerance:i64)->i64 { 10 if tolerance<0||tolerance>VM_Q30{return -1} 11 var sum:i64=0;var i:i64=0 12 while i<4{if a[i]<0-VM_Q30||a[i]>VM_Q30{return -1};sum=sum+a[i]*a[i];i=i+1} 13 let length:i64=vm_isqrt(sum);if length<=0||vm_abs(length-VM_Q30)>tolerance{return -2} 14 i=0;while i<4{out[i]=a[i]*VM_Q30/length;i=i+1};return 0 15} 16func vm_q_slerp_q30(a:*i64,b:*i64,t:i64,tolerance:i64,out:*i64,scratch:*i64)->i64 { 17 if t<0||t>VM_Q30{return -1} 18 let lo:*i64=scratch;let hi:*i64=(scratch as i64+32) as *i64;let mid:*i64=(scratch as i64+64) as *i64 19 let lowrc:i64=vm_q_norm_q30(a,lo,tolerance);if lowrc!=0{return lowrc} 20 let highrc:i64=vm_q_norm_q30(b,hi,tolerance);if highrc!=0{return highrc} 21 var dot:i64=0;var i:i64=0;while i<4{dot=dot+lo[i]*hi[i];i=i+1} 22 if dot<0{i=0;while i<4{hi[i]=0-hi[i];i=i+1}} 23 var left:i64=0;var right:i64=VM_Q30;var step:i64=0 24 while step<VM_Q30_BITS{ 25 if t==left{i=0;while i<4{out[i]=lo[i];i=i+1};return 0} 26 if t==right{i=0;while i<4{out[i]=hi[i];i=i+1};return 0} 27 i=0;var sum:i64=0;while i<4{mid[i]=(lo[i]+hi[i])/2;sum=sum+mid[i]*mid[i];i=i+1} 28 let length:i64=vm_isqrt(sum);if length<=0{return -2} 29 i=0;while i<4{mid[i]=mid[i]*VM_Q30/length;i=i+1} 30 let center:i64=(left+right)/2 31 if t==center{i=0;while i<4{out[i]=mid[i];i=i+1};return 0} 32 if t<center{i=0;while i<4{hi[i]=mid[i];i=i+1};right=center}else{i=0;while i<4{lo[i]=mid[i];i=i+1};left=center} 33 step=step+1 34 };return -3 35} 36 37// Decimal JSON number to caller-selected fixed precision, toward zero. 38// Error is less than one output unit; overflow refuses instead of saturating. 39func gld_number_fixed(s:*u8,n:i64,q:i64,out:*i64)->i64 { 40 if (s as i64)<=0||(out as i64)<=0||n<=0||n>GLD_I64_MAX-64||q<=0||q>GLD_I64_MAX/10{return -1} 41 var start:i64=0;var sign:i64=1;if s[0]==(45 as u8){start=1;sign=0-1};if start>=n{return -1} 42 var i:i64=start;var digits:i64=0;var before:i64=0;var dot:i64=0;var nonzero:i64=0 43 while i<n&&s[i]!=(101 as u8)&&s[i]!=(69 as u8){ 44 let c:i64=s[i] as i64;if c==46{if dot!=0||digits==0{return -1};dot=1;before=digits}else{if c<48||c>57{return -1};if c!=48{nonzero=1};digits=digits+1};i=i+1 45 } 46 let mend:i64=i;if digits==0||(dot==1&&s[mend-1]==(46 as u8)){return -1};if dot==0{before=digits} 47 if s[start]==(48 as u8)&&before>1{return -1} 48 var ex:i64=0;var es:i64=1;let bound:i64=n+64 49 if i<n{i=i+1;if i<n&&s[i]==(45 as u8){es=0-1;i=i+1}else{if i<n&&s[i]==(43 as u8){i=i+1}};if i>=n{return -1} 50 while i<n{let d:i64=(s[i] as i64)-48;if d<0||d>9{return -1};if ex>(bound-d)/10{ex=bound}else{ex=ex*10+d};i=i+1} 51 } 52 if nonzero==0{out[0]=0;return 0} 53 var point:i64=before;if es>0{if ex>bound-before{point=bound}else{point=before+ex}}else{point=before-ex} 54 let wholemax:i64=GLD_I64_MAX/q;var whole:i64=0;var index:i64=0;i=start 55 while i<mend{let c:i64=s[i] as i64;if c!=46{if index<point{let d:i64=c-48;if whole>(wholemax-d)/10{return -2};whole=whole*10+d};index=index+1};i=i+1} 56 while index<point{if whole>wholemax/10{return -2};whole=whole*10;index=index+1} 57 var fraction:i64=0;index=digits-1;i=mend-1 58 while i>=start{let c:i64=s[i] as i64;if c!=46{if index>=point{fraction=((c-48)*q+fraction)/10};index=index-1};i=i-1} 59 var zeros:i64=0-point;while zeros>0&&fraction>0{fraction=fraction/10;zeros=zeros-1} 60 let base:i64=whole*q;if fraction>GLD_I64_MAX-base{return -2};out[0]=(base+fraction)*sign;return 0 61} 62 63func gld_array_fixed(cx:*i64,parent:i64,key:*u8,q:i64,out:*i64,count:i64)->i64 { 64 let have:i64=gli_member(cx,parent,key);if have<=0{return have};let sp:*i64=cx[4] as *i64;let t:*NxJsonTok=cx[2] as *NxJsonTok 65 glp_reset(t,cx[0] as *u8,cx[1],sp[0]);if t.kind!=NX_JSON_LBRACKET{return -1};nx_json_next(t);var i:i64=0 66 while i<count{if t.kind!=NX_JSON_NUMBER{return -1};if gld_number_fixed((t.src as i64+t.tok_off) as *u8,t.tok_len,q,(out as i64+i*8) as *i64)!=0{return -2};i=i+1;nx_json_next(t);if i<count{if t.kind!=NX_JSON_COMMA{return -1};nx_json_next(t)}} 67 if t.kind!=NX_JSON_RBRACKET{return -1};return 1 68} 69func gld_identity(out:*i64)->i64 {var i:i64=0;while i<16{out[i]=0;i=i+1};out[0]=FBB_Q;out[5]=FBB_Q;out[10]=FBB_Q;out[15]=FBB_Q;return 0} 70// TRS occupies translation Q20, normalized quaternion Q30, scale Q20. 71func gld_trs_matrix(trs:*i64,out:*i64)->i64 { 72 let x:i64=trs[3];let y:i64=trs[4];let z:i64=trs[5];let w:i64=trs[6] 73 let xx:i64=x*x/VM_Q30;let yy:i64=y*y/VM_Q30;let zz:i64=z*z/VM_Q30 74 let xy:i64=x*y/VM_Q30;let xz:i64=x*z/VM_Q30;let yz:i64=y*z/VM_Q30 75 let wx:i64=w*x/VM_Q30;let wy:i64=w*y/VM_Q30;let wz:i64=w*z/VM_Q30 76 let r:*i64=sys_mmap(128) as *i64;let s:*i64=sys_mmap(128) as *i64;gld_identity(r);gld_identity(s) 77 r[0]=(VM_Q30-2*(yy+zz))/1024;r[1]=2*(xy+wz)/1024;r[2]=2*(xz-wy)/1024 78 r[4]=2*(xy-wz)/1024;r[5]=(VM_Q30-2*(xx+zz))/1024;r[6]=2*(yz+wx)/1024 79 r[8]=2*(xz+wy)/1024;r[9]=2*(yz-wx)/1024;r[10]=(VM_Q30-2*(xx+yy))/1024 80 s[0]=trs[7];s[5]=trs[8];s[10]=trs[9];let rc:i64=fbb_compose(r,s,out) 81 if rc==0{out[12]=trs[0];out[13]=trs[1];out[14]=trs[2]};sys_munmap(r as *u8,128);sys_munmap(s as *u8,128);return rc 82} 83func gld_node_trs(cx:*i64,node:i64,trs:*i64,matrix:*i64)->i64 { 84 let at:i64=gld_nth(cx,0,"nodes",node);if at<0{return -1};var i:i64=0;while i<10{trs[i]=0;i=i+1};trs[6]=VM_Q30;trs[7]=FBB_Q;trs[8]=FBB_Q;trs[9]=FBB_Q 85 let mh:i64=gli_member(cx,at,"matrix");if mh<0{return -1};if mh==1{if gli_member(cx,at,"translation")!=0||gli_member(cx,at,"rotation")!=0||gli_member(cx,at,"scale")!=0{return -1};if gld_array_fixed(cx,at,"matrix",FBB_Q,matrix,16)!=1{return -1};return 1} 86 if gld_array_fixed(cx,at,"translation",FBB_Q,trs,3)<0{return -1} 87 if gld_array_fixed(cx,at,"rotation",VM_Q30,(trs as i64+24) as *i64,4)<0{return -1} 88 if gld_array_fixed(cx,at,"scale",FBB_Q,(trs as i64+56) as *i64,3)<0{return -1} 89 if vm_q_norm_q30((trs as i64+24) as *i64,(trs as i64+24) as *i64,1024)!=0{return -2} 90 return gld_trs_matrix(trs,matrix) 91} 92 93func gld_parents(cx:*i64,count:i64,parents:*i64)->i64 { 94 var i:i64=0;while i<count{parents[i]=0-1;i=i+1};i=0 95 while i<count{let at:i64=gld_nth(cx,0,"nodes",i);if at<0{return -1};let have:i64=gli_member(cx,at,"children");if have<0{return -1} 96 if have==1{let sp:*i64=cx[4] as *i64;let t:*NxJsonTok=cx[2] as *NxJsonTok;glp_reset(t,cx[0] as *u8,cx[1],sp[0]);if t.kind!=NX_JSON_LBRACKET{return -1};nx_json_next(t) 97 while t.kind!=NX_JSON_RBRACKET{let child:i64=gld_uint(t);if child<0||child>=count||child==i{return -2};if parents[child]!=0-1{return -2};parents[child]=i;nx_json_next(t);if t.kind!=NX_JSON_RBRACKET{if t.kind!=NX_JSON_COMMA{return -1};nx_json_next(t)}} 98 };i=i+1 99 };return 0 100} 101func gld_world_matrices(count:i64,parents:*i64,local:*i64,world:*i64,done:*i64)->i64 { 102 var i:i64=0;while i<count{done[i]=0;i=i+1};var left:i64=count 103 while left>0{var progress:i64=0;i=0 104 while i<count{if done[i]==0{let p:i64=parents[i];if p<0||done[p]==1{let dst:*i64=(world as i64+i*128) as *i64;let src:*i64=(local as i64+i*128) as *i64 105 if p<0{var k:i64=0;while k<16{dst[k]=src[k];k=k+1}}else{if fbb_compose((world as i64+p*128) as *i64,src,dst)!=0{return -3}} 106 done[i]=1;left=left-1;progress=progress+1 107 }};i=i+1 108 };if progress==0{return -4} 109 };return 0 110} 111 112func gld_float_fixed(bits:i64,q:i64,out:*i64)->i64 { 113 if q<=0||q>VM_Q30{return -1};let ex:i64=(bits>>23)&255;if ex==255{return -1};let m:i64=((bits&8388607)|8388608)*q;let e:i64=ex-150 114 if e>=0{if e>=63{return -2};if m>(GLD_I64_MAX>>e){return -2}} 115 out[0]=vm_f32_to_int(bits,q);return 0 116} 117func gld_view_float(cx:*i64,v:*i64,element:i64,component:i64,q:i64,out:*i64)->i64 { 118 if v[3]!=5126||element<0||element>=v[1]||component<0||component>=v[5]{return -1} 119 return gld_float_fixed(gll_ru32(cx[8] as *u8,v[0]+element*v[2]+component*4),q,out) 120} 121func gld_animate(cx:*i64,animation:i64,time:i64,trs:*i64,nodes:i64,masks:*i64)->i64 { 122 if time<0{return -1};let an:i64=gld_nth(cx,0,"animations",animation);if an<0{return -1} 123 var ni:i64=0;while ni<nodes{masks[ni]=0;ni=ni+1} 124 let iv:*i64=sys_mmap(GLD_VIEW_WORDS*8) as *i64;let ov:*i64=sys_mmap(GLD_VIEW_WORDS*8) as *i64;let st:*i64=cx[5] as *i64 125 let aa:*i64=sys_mmap(32) as *i64;let bb:*i64=sys_mmap(32) as *i64;let val:*i64=sys_mmap(8) as *i64;let scratch:*i64=sys_mmap(96) as *i64 126 var ch:i64=0;var rc:i64=0 127 while rc==0{let channel:i64=gld_nth(cx,an,"channels",ch);if channel<0{break};let sampler:i64=gld_int(cx,channel,"sampler",-1) 128 if sampler<0||gli_member(cx,channel,"target")!=1{rc=-1;break};let sp:*i64=cx[4] as *i64;let target:i64=sp[0];let node:i64=gld_int(cx,target,"node",-1) 129 if node<0||node>=nodes||gli_member(cx,target,"path")!=1{rc=-1;break};let tok:*NxJsonTok=cx[2] as *NxJsonTok;glp_reset(tok,cx[0] as *u8,cx[1],sp[0]);var offset:i64=0;var nc:i64=3;var q:i64=FBB_Q;var flag:i64=0 130 if glp_eq(tok,"translation")==1{flag=1};if glp_eq(tok,"rotation")==1{flag=2;offset=3;nc=4;q=VM_Q30};if glp_eq(tok,"scale")==1{flag=4;offset=7} 131 if flag==0{rc=-2;break};if (masks[node]&flag)!=0{rc=-1;break};masks[node]=masks[node]|flag 132 let nat:i64=gld_nth(cx,0,"nodes",node);if gli_member(cx,nat,"matrix")!=0{rc=-2;break} 133 let sa:i64=gld_nth(cx,an,"samplers",sampler);if sa<0{rc=-1;break};var step:i64=0;let ih:i64=gli_member(cx,sa,"interpolation");if ih<0{rc=-1;break} 134 if ih==1{glp_reset(tok,cx[0] as *u8,cx[1],sp[0]);if glp_eq(tok,"STEP")==1{step=1}else{if glp_eq(tok,"LINEAR")!=1{rc=-2;break}}} 135 let input:i64=gld_int(cx,sa,"input",-1);let output:i64=gld_int(cx,sa,"output",-1) 136 if gltf_accessor_view(cx,input,st[2],iv)!=0||gltf_accessor_view(cx,output,st[2],ov)!=0{rc=-1;break} 137 if iv[3]!=5126||iv[5]!=1||ov[3]!=5126||ov[5]!=nc||iv[1]!=ov[1]{rc=-1;break} 138 var k:i64=0;var last:i64=0-1;var lo:i64=0;var hi:i64=0;var lot:i64=0;var hit:i64=0;var found:i64=0 139 while k<iv[1]{if gld_view_float(cx,iv,k,0,VM_Q30,val)!=0{rc=-1;break};let kt:i64=val[0];if kt<0||kt<=last{rc=-1;break} 140 if kt<=time{lo=k;hi=k;lot=kt;hit=kt}else{if found==0{hi=k;hit=kt;found=1;if k==0{lo=0;lot=kt}}};last=kt;k=k+1 141 };if rc!=0{break};var fraction:i64=0 142 if hi!=lo&&step==0{let span:i64=hit-lot;let delta:i64=time-lot;if delta<0||delta>GLD_I64_MAX/VM_Q30{rc=-2;break};fraction=delta*VM_Q30/span} 143 k=0;while k<nc{if gld_view_float(cx,ov,lo,k,q,(aa as i64+k*8) as *i64)!=0||gld_view_float(cx,ov,hi,k,q,(bb as i64+k*8) as *i64)!=0{rc=-1;break};k=k+1};if rc!=0{break} 144 let dest:*i64=(trs as i64+node*80+offset*8) as *i64 145 if flag==2{rc=vm_q_slerp_q30(aa,bb,fraction,1024,dest,scratch)}else{k=0;while k<nc{if aa[k]<0-GLD_I64_MAX/2||aa[k]>GLD_I64_MAX/2||bb[k]<0-GLD_I64_MAX/2||bb[k]>GLD_I64_MAX/2{rc=-2;break};let d:i64=bb[k]-aa[k];if vm_abs(d)>GLD_I64_MAX/VM_Q30{rc=-2;break};dest[k]=aa[k]+d*fraction/VM_Q30;k=k+1}} 146 ch=ch+1 147 } 148 sys_munmap(iv as *u8,GLD_VIEW_WORDS*8);sys_munmap(ov as *u8,GLD_VIEW_WORDS*8);sys_munmap(aa as *u8,32);sys_munmap(bb as *u8,32);sys_munmap(val as *u8,8);sys_munmap(scratch as *u8,96) 149 if rc!=0{return rc};return ch 150} 151 152func gld_skin_palette(cx:*i64,skin:i64,world:*i64,nodes:i64,palette:*i64,capacity:i64)->i64 { 153 let sk:i64=gld_nth(cx,0,"skins",skin);if sk<0{return -1};let ib:i64=gld_int(cx,sk,"inverseBindMatrices",-1);if ib<0{return -2} 154 let v:*i64=sys_mmap(GLD_VIEW_WORDS*8) as *i64;let m:*i64=sys_mmap(128) as *i64;let st:*i64=cx[5] as *i64;var rc:i64=gltf_accessor_view(cx,ib,st[2],v);var count:i64=0 155 if rc==0{if v[3]!=5126||v[5]!=16||v[1]>capacity{rc=-1}else{count=v[1]}} 156 var i:i64=0;while i<count&&rc==0{let at:i64=gld_nth(cx,sk,"joints",i);if at<0{rc=-1;break};let t:*NxJsonTok=cx[2] as *NxJsonTok;glp_reset(t,cx[0] as *u8,cx[1],at);let node:i64=gld_uint(t);if node<0||node>=nodes{rc=-1;break} 157 var k:i64=0;while k<16{if gld_view_float(cx,v,i,k,FBB_Q,(m as i64+k*8) as *i64)!=0{rc=-1;break};k=k+1} 158 if rc==0{rc=fbb_compose((world as i64+node*128) as *i64,m,(palette as i64+i*128) as *i64)};i=i+1 159 };if rc==0&&gld_nth(cx,sk,"joints",count)>=0{rc=-1} 160 sys_munmap(v as *u8,GLD_VIEW_WORDS*8);sys_munmap(m as *u8,128);if rc!=0{return rc};return count 161} 162// Source-position LBS using the original joint indices and floating weights. 163// The skinned mesh node transform is deliberately absent, per glTF skin semantics. 164func gld_skin_vertex(cx:*i64,pv:*i64,jv:*i64,wv:*i64,vertex:i64,palette:*i64,joints:i64,out:*i64)->i64 { 165 if pv[5]!=3||jv[5]!=4||wv[5]!=4||pv[1]!=jv[1]||pv[1]!=wv[1]||vertex<0||vertex>=pv[1]{return -1} 166 if jv[3]!=5121&&jv[3]!=5123{return -2} 167 let blend:*i64=sys_mmap(128) as *i64;let point:*i64=sys_mmap(128) as *i64;let result:*i64=sys_mmap(128) as *i64;let weight:*i64=sys_mmap(8) as *i64;gld_identity(point);var k:i64=0;while k<16{blend[k]=0;k=k+1} 168 var rc:i64=0;k=0;while k<3{if gld_view_float(cx,pv,vertex,k,FBB_Q,(point as i64+96+k*8) as *i64)!=0{rc=-1;break};k=k+1} 169 var influence:i64=0;while influence<4&&rc==0{let off:i64=jv[0]+vertex*jv[2]+influence*jv[4];let bin:*u8=cx[8] as *u8;var joint:i64=bin[off] as i64;if jv[3]==5123{joint=joint+(bin[off+1] as i64)*256};if joint<0||joint>=joints{rc=-1;break} 170 if gld_view_float(cx,wv,vertex,influence,VM_Q30,weight)!=0||weight[0]<0||weight[0]>VM_Q30{rc=-1;break} 171 k=0;while k<16{let m:i64=palette[joint*16+k];if m<0-GLD_I64_MAX/VM_Q30||m>GLD_I64_MAX/VM_Q30{rc=-2;break};let term:i64=m*weight[0]/VM_Q30;if term>0&&blend[k]>GLD_I64_MAX-term{rc=-2;break};if term<0&&blend[k]<0-GLD_I64_MAX-term{rc=-2;break};blend[k]=blend[k]+term;k=k+1};influence=influence+1 172 } 173 if rc==0{rc=fbb_compose(blend,point,result)};if rc==0{out[0]=result[12];out[1]=result[13];out[2]=result[14]} 174 sys_munmap(blend as *u8,128);sys_munmap(point as *u8,128);sys_munmap(result as *u8,128);sys_munmap(weight as *u8,8);return rc 175}