code wiki / (root) / nx_gltf_pose_packet_t316.nx

nx_gltf_pose_packet_t316.nx source

↩ module page · 126 lines · 11139 B

1// Authored glTF track adapter: caller-owned storage, original hierarchy and world*IBM palette. 2import "nx_gltf_pose_math_t316.nx" 3const GPA_MAGIC:i64=0x47504131 4const GPA_HEADER:i64=20 5const GPA_TRACK:i64=8 6const GPA_NODE_WORK:i64=44 7const GPA_FIXED_WORK:i64=60 8func gpa_span(off:i64,count:i64,total:i64)->i64{if off<GPA_HEADER||count<0||off>total||count>total-off{return 0};return 1} 9func gltf_pose_work_words(nodes:i64)->i64{if nodes<1||nodes>(GLD_I64_MAX-GPA_FIXED_WORK)/GPA_NODE_WORK{return -1};return nodes*GPA_NODE_WORK+GPA_FIXED_WORK} 10func gpa_copy(a:*i64,b:*i64,n:i64)->i64{var i:i64=0;while i<n{b[i]=a[i];i=i+1};return 0} 11func gpa_trs_matrix(trs:*i64,out:*i64,r:*i64,s:*i64,tmp:*i64)->i64{ 12 let x:i64=trs[3];let y:i64=trs[4];let z:i64=trs[5];let w:i64=trs[6] 13 if x<0-VM_Q30||x>VM_Q30||y<0-VM_Q30||y>VM_Q30||z<0-VM_Q30||z>VM_Q30||w<0-VM_Q30||w>VM_Q30{return -2} 14 let xx:i64=x*x/VM_Q30;let yy:i64=y*y/VM_Q30;let zz:i64=z*z/VM_Q30 15 let xy:i64=x*y/VM_Q30;let xz:i64=x*z/VM_Q30;let yz:i64=y*z/VM_Q30 16 let wx:i64=w*x/VM_Q30;let wy:i64=w*y/VM_Q30;let wz:i64=w*z/VM_Q30 17 gld_identity(r);gld_identity(s) 18 r[0]=(VM_Q30-2*(yy+zz))/1024;r[1]=2*(xy+wz)/1024;r[2]=2*(xz-wy)/1024 19 r[4]=2*(xy-wz)/1024;r[5]=(VM_Q30-2*(xx+zz))/1024;r[6]=2*(yz+wx)/1024 20 r[8]=2*(xz+wy)/1024;r[9]=2*(yz-wx)/1024;r[10]=(VM_Q30-2*(xx+yy))/1024 21 s[0]=trs[7];s[5]=trs[8];s[10]=trs[9] 22 let rc:i64=fbb_compose_into(r,s,out,tmp,16);if rc!=0{return rc} 23 out[12]=trs[0];out[13]=trs[1];out[14]=trs[2];return 0 24} 25func gpa_frame(p:*i64,pw:i64,time:i64,wrap_time:i64,work:*i64,ww:i64,out:*i64,ow:i64)->i64{ 26 if (p as i64)<=0||(work as i64)<=0||(out as i64)<=0||pw<GPA_HEADER||time<0||(wrap_time!=0&&wrap_time!=1){return -1} 27 if p[0]!=GPA_MAGIC||p[1]!=1||p[2]!=pw||p[7]!=FBB_Q||p[8]!=VM_Q30||p[19]!=0{return -1} 28 let nodes:i64=p[3];let joints:i64=p[4];let tracks:i64=p[5];let duration:i64=p[6] 29 let needed:i64=gltf_pose_work_words(nodes) 30 if needed<0||ww<needed||nodes>pw/16||joints<1||joints>ow/16||joints>pw/16||tracks<0||tracks>pw/GPA_TRACK||duration<=0{return -1} 31 if gpa_span(p[9],nodes,pw)!=1||gpa_span(p[10],nodes*10,pw)!=1||gpa_span(p[11],nodes*16,pw)!=1||gpa_span(p[12],nodes,pw)!=1{return -1} 32 if gpa_span(p[13],joints,pw)!=1||gpa_span(p[14],joints*16,pw)!=1||gpa_span(p[15],tracks*GPA_TRACK,pw)!=1||p[16]<GPA_HEADER||p[16]>pw{return -1} 33 let parents:*i64=(p as i64+p[9]*8) as *i64;let flags:*i64=(p as i64+p[12]*8) as *i64 34 let trs:*i64=work;let local:*i64=(work as i64+nodes*80) as *i64 35 let world:*i64=(local as i64+nodes*128) as *i64;let done:*i64=(world as i64+nodes*128) as *i64 36 let masks:*i64=(done as i64+nodes*8) as *i64;let r:*i64=(masks as i64+nodes*8) as *i64 37 let s:*i64=(r as i64+128) as *i64;let tmp:*i64=(s as i64+128) as *i64;let qs:*i64=(tmp as i64+128) as *i64 38 gpa_copy((p as i64+p[10]*8) as *i64,trs,nodes*10) 39 var i:i64=0;while i<nodes{done[i]=0;masks[i]=0;if parents[i]<-1||parents[i]>=nodes||parents[i]==i||(flags[i]!=0&&flags[i]!=1){return -1};i=i+1} 40 var t:i64=time;if wrap_time==1{t=time%duration} 41 var ch:i64=0;while ch<tracks{ 42 let rec:*i64=(p as i64+(p[15]+ch*GPA_TRACK)*8) as *i64 43 let node:i64=rec[0];let flag:i64=rec[1];let mode:i64=rec[2];let keys:i64=rec[3];let nc:i64=rec[6] 44 if node<0||node>=nodes||flags[node]!=0||keys<1||keys>pw||rec[7]!=0||(mode!=0&&mode!=1){return -1} 45 var offset:i64=0;if flag==2{offset=3;if nc!=4{return -1}}else{if flag==4{offset=7}else{if flag!=1{return -1}};if nc!=3{return -1}} 46 if (masks[node]&flag)!=0{return -1};masks[node]=masks[node]|flag 47 if keys>pw/nc||rec[4]<p[16]||rec[5]<p[16]||gpa_span(rec[4],keys,pw)!=1||gpa_span(rec[5],keys*nc,pw)!=1{return -1} 48 let times:*i64=(p as i64+rec[4]*8) as *i64;let values:*i64=(p as i64+rec[5]*8) as *i64 49 var k:i64=0;var last:i64=-1;var lo:i64=0;var hi:i64=0;var lot:i64=0;var hit:i64=0;var found:i64=0 50 while k<keys{let kt:i64=times[k];if kt<0||kt<=last||kt>duration{return -1} 51 if kt<=t{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 52 } 53 var fraction:i64=0;if hi!=lo&&mode==0{let delta:i64=t-lot;if delta<0||delta>GLD_I64_MAX/VM_Q30{return -2};fraction=delta*VM_Q30/(hit-lot)} 54 let aa:*i64=(values as i64+lo*nc*8) as *i64;let bb:*i64=(values as i64+hi*nc*8) as *i64;let dest:*i64=(trs as i64+(node*10+offset)*8) as *i64 55 if flag==2{let rc:i64=vm_q_slerp_q30(aa,bb,fraction,1024,dest,qs);if rc!=0{return rc}} 56 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{return -2};let d:i64=bb[k]-aa[k];if vm_abs(d)>GLD_I64_MAX/VM_Q30{return -2};dest[k]=aa[k]+d*fraction/VM_Q30;k=k+1}} 57 ch=ch+1 58 } 59 i=0;while i<nodes{let dst:*i64=(local as i64+i*128) as *i64 60 if flags[i]==1{gpa_copy((p as i64+(p[11]+i*16)*8) as *i64,dst,16)}else{let rc:i64=gpa_trs_matrix((trs as i64+i*80) as *i64,dst,r,s,tmp);if rc!=0{return rc}};i=i+1 61 } 62 var left:i64=nodes;while left>0{var progress:i64=0;i=0;while i<nodes{if done[i]==0{let parent:i64=parents[i];if parent<0||done[parent]==1{ 63 let dst:*i64=(world as i64+i*128) as *i64;let src:*i64=(local as i64+i*128) as *i64 64 if parent<0{gpa_copy(src,dst,16)}else{let rc:i64=fbb_compose_into((world as i64+parent*128) as *i64,src,dst,tmp,16);if rc!=0{return rc}} 65 done[i]=1;left=left-1;progress=progress+1 66 }};i=i+1};if progress==0{return -4}} 67 i=0;while i<joints{let node:i64=p[p[13]+i];if node<0||node>=nodes{return -1} 68 let rc:i64=fbb_compose_into((world as i64+node*128) as *i64,(p as i64+(p[14]+i*16)*8) as *i64,(out as i64+i*128) as *i64,tmp,16);if rc!=0{return rc};i=i+1 69 };return joints 70} 71func gpa_memory(off:i64,words:i64,available:i64)->i64{if off<=0||off%8!=0||words<0||available<0||off>available||words>(available-off)/8{return 0};return 1} 72func gpa_overlap(a:i64,aw:i64,b:i64,bw:i64)->i64{if a<=b{if (b-a)/8<aw{return 1}}else{if (a-b)/8<bw{return 1}};return 0} 73func gltf_pose_frame(packet:i64,pw:i64,time:i64,wrap_time:i64,work:i64,ww:i64,out:i64,ow:i64,available:i64)->i64{ 74 if gpa_memory(packet,pw,available)!=1||gpa_memory(work,ww,available)!=1||gpa_memory(out,ow,available)!=1{return -30} 75 if gpa_overlap(packet,pw,work,ww)==1||gpa_overlap(packet,pw,out,ow)==1||gpa_overlap(work,ww,out,ow)==1{return -31} 76 return gpa_frame(packet as *i64,pw,time,wrap_time,work as *i64,ww,out as *i64,ow) 77} 78 79// Source-position LBS bounds, using the same per-term fixed rounding as gld_skin_vertex. 80// Each vertex has 11 words: position3 Q20, joint4 indices, weight4 Q30. 81func gpa_bounds(palette:*i64,joints:i64,vertices:*i64,count:i64,out:*i64,scratch:*i64)->i64{ 82 if (palette as i64)<=0||(vertices as i64)<=0||(out as i64)<=0||(scratch as i64)<=0||joints<1||count<1{return -1} 83 let blend:*i64=scratch;let point:*i64=(scratch as i64+128) as *i64;let result:*i64=(scratch as i64+256) as *i64;let tmp:*i64=(scratch as i64+384) as *i64 84 gld_identity(point);var vertex:i64=0 85 while vertex<count{let v:*i64=(vertices as i64+vertex*88) as *i64;var k:i64=0;while k<16{blend[k]=0;k=k+1} 86 k=0;while k<3{point[12+k]=v[k];k=k+1} 87 var influence:i64=0;while influence<4{let joint:i64=v[3+influence];let weight:i64=v[7+influence] 88 if joint<0||joint>=joints||weight<0||weight>VM_Q30{return -1} 89 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{return -2} 90 let term:i64=m*weight/VM_Q30;if term>0&&blend[k]>GLD_I64_MAX-term{return -2};if term<0&&blend[k]<0-GLD_I64_MAX-term{return -2};blend[k]=blend[k]+term;k=k+1 91 };influence=influence+1 92 } 93 let rc:i64=fbb_compose_into(blend,point,result,tmp,16);if rc!=0{return rc} 94 k=0;while k<3{let value:i64=result[12+k];if vertex==0{out[k]=value;out[3+k]=value}else{if value<out[k]{out[k]=value};if value>out[3+k]{out[3+k]=value}};k=k+1};vertex=vertex+1 95 };return count 96} 97func gltf_pose_bounds(palette:i64,joints:i64,vertices:i64,count:i64,out:i64,scratch:i64,available:i64)->i64{ 98 if joints<1||count<1||joints>available/128||count>available/88{return -30} 99 if gpa_memory(palette,joints*16,available)!=1||gpa_memory(vertices,count*11,available)!=1||gpa_memory(out,6,available)!=1||gpa_memory(scratch,64,available)!=1{return -30} 100 if gpa_overlap(palette,joints*16,vertices,count*11)==1||gpa_overlap(palette,joints*16,out,6)==1||gpa_overlap(palette,joints*16,scratch,64)==1||gpa_overlap(vertices,count*11,out,6)==1||gpa_overlap(vertices,count*11,scratch,64)==1||gpa_overlap(out,6,scratch,64)==1{return -31} 101 return gpa_bounds(palette as *i64,joints,vertices as *i64,count,out as *i64,scratch as *i64) 102} 103 104// Conservative source-skin bounds. Pack is audited against all positive-weight source vertices. 105func gpa_broad_bounds(palette:*i64,joints:i64,pack:*i64,words:i64,out:*i64,scratch:*i64)->i64{ 106 if joints<1||words!=10+joints*7||pack[0]!=1196442161||pack[1]!=1||pack[2]!=joints||pack[3]!=FBB_Q||pack[4]!=VM_Q30||pack[5]<=0||pack[6]<pack[5]||pack[6]>4*VM_Q30{return -1} 107 var margin:i64=1;var axis:i64=0;while axis<3{let a:i64=pack[7+axis];if a<0||a>GLD_I64_MAX/32{return -2};margin=margin+a/FBB_Q;if a%FBB_Q!=0{margin=margin+1};axis=axis+1};margin=margin*4+4 108 let point:*i64=scratch;let result:*i64=(scratch as i64+128) as *i64;let tmp:*i64=(scratch as i64+256) as *i64;gld_identity(point) 109 var seen:i64=0;var joint:i64=0;while joint<joints{let r:*i64=(pack as i64+(10+joint*7)*8) as *i64;if r[0]!=0&&r[0]!=1{return -1} 110 if r[0]==1{axis=0;while axis<3{if r[1+axis]>r[4+axis]||r[1+axis]<0-pack[7+axis]||r[4+axis]>pack[7+axis]{return -1};axis=axis+1} 111 var corner:i64=0;while corner<8{axis=0;var bits:i64=corner;while axis<3{point[12+axis]=r[1+axis];if bits%2==1{point[12+axis]=r[4+axis]};bits=bits/2;axis=axis+1} 112 let rc:i64=fbb_compose_into((palette as i64+joint*128) as *i64,point,result,tmp,16);if rc!=0{return rc} 113 axis=0;while axis<3{let v:i64=result[12+axis];if v<0-GLD_I64_MAX+4||v>GLD_I64_MAX-4{return -2};let low:i64=v-4;let high:i64=v+4;if seen==0{out[axis]=low;out[3+axis]=high}else{if low<out[axis]{out[axis]=low};if high>out[3+axis]{out[3+axis]=high}};axis=axis+1};seen=seen+1;corner=corner+1 114 }};joint=joint+1};if seen==0{return -1} 115 axis=0;while axis<3{let lo:i64=out[axis];let hi:i64=out[3+axis];var ls:i64=pack[5];var hs:i64=pack[6];if lo<0{ls=pack[6]};if hi<0{hs=pack[5]} 116 if lo<0-GLD_I64_MAX/ls||lo>GLD_I64_MAX/ls||hi<0-GLD_I64_MAX/hs||hi>GLD_I64_MAX/hs{return -2} 117 let lp:i64=lo*ls;let hp:i64=hi*hs;var l:i64=lp/VM_Q30;var h:i64=hp/VM_Q30;if lp<0&&lp%VM_Q30!=0{l=l-1};if hp>0&&hp%VM_Q30!=0{h=h+1} 118 if l<0-GLD_I64_MAX+margin||h>GLD_I64_MAX-margin{return -2};out[axis]=l-margin;out[3+axis]=h+margin;axis=axis+1 119 };return joints 120} 121func gltf_pose_broad_bounds(palette:i64,joints:i64,pack:i64,words:i64,out:i64,scratch:i64,available:i64)->i64{ 122 if joints<1||joints>available/128||words<10{return -30} 123 if gpa_memory(palette,joints*16,available)!=1||gpa_memory(pack,words,available)!=1||gpa_memory(out,6,available)!=1||gpa_memory(scratch,64,available)!=1{return -30} 124 if gpa_overlap(palette,joints*16,pack,words)==1||gpa_overlap(palette,joints*16,out,6)==1||gpa_overlap(palette,joints*16,scratch,64)==1||gpa_overlap(pack,words,out,6)==1||gpa_overlap(pack,words,scratch,64)==1||gpa_overlap(out,6,scratch,64)==1{return -31} 125 return gpa_broad_bounds(palette as *i64,joints,pack as *i64,words,out as *i64,scratch as *i64) 126}