code wiki / (root) / nx_nxa_garment_bind_candidate_t132.nx

nx_nxa_garment_bind_candidate_t132.nx source

↩ module page · 210 lines · 11926 B

1// Deterministic garment-to-body binding, shared by asset preparation and worker conversion. 2import "nx_nxa_gpu_lib.nx" 3 4const NGB_WORD: i64=8 5const NGB_COORD_LIMIT: i64=1<<NGP_F32_INTEGER_BITS // Exact integer positions in the incumbent float32 upload. 6const NGB_E_POLICY: i64=0-20 7const NGB_E_COORD: i64=0-21 8const NGB_E_CANDIDATE: i64=0-22 9 10func ngb_coordinates(h: *i64,at: i64) -> i64 { 11 var i: i64=0 12 while i<h[at]*NGP_COMPONENTS { 13 let v: i64=h[at+1+i] 14 if v<0-NGB_COORD_LIMIT || v>NGB_COORD_LIMIT { return NGB_E_COORD } 15 i=i+1 16 } 17 return 0 18} 19// step and lower_band are caller-owned binding policy, never hidden asset-specific constants. 20// Below lower_band, queries bind only above that band; otherwise the candidate floor is zero. 21// Coordinates are exact float32 integers and squared distances fit exact binary64 integers. 22// Ties select the lowest eligible source index. No candidate is an error, never vertex-zero fallback. 23func ngb_map(b: *u8,n: i64,out: *u8,cap: i64,step: i64,lower_band: i64) -> i64 { 24 if step<=0 || lower_band<0 || lower_band>NGB_COORD_LIMIT { return NGB_E_POLICY } 25 let va: i64=ngp_section(b,n,"VERT" as *u8) 26 if va<0 { return va } 27 let ga: i64=ngp_section(b,n,"GVRT" as *u8) 28 if ga<0 { return ga } 29 let h: *i64=b as *i64 30 let nv: i64=h[va];let ng: i64=h[ga] 31 let need: i64=ng*NGB_WORD 32 let valid: i64=ngp_output(b,n,out,cap,need) 33 if valid<0 { return valid } 34 let vc: i64=ngb_coordinates(h,va) 35 if vc<0 { return vc } 36 let gc: i64=ngb_coordinates(h,ga) 37 if gc<0 { return gc } 38 var above_zero: i64=0;var above_band: i64=0 39 var u: i64=0 40 while u<nv { 41 let z: i64=h[va+1+u*NGP_COMPONENTS+2] 42 if z>=0 { above_zero=1 } 43 if z>=lower_band { above_band=1 } 44 // Subtraction prevents an arbitrary caller stride overflowing the loop index. 45 if step>=nv-u { u=nv } else { u=u+step } 46 } 47 var v: i64=0 48 while v<ng { 49 let z: i64=h[ga+1+v*NGP_COMPONENTS+2] 50 if z<lower_band { if above_band==0 { return NGB_E_CANDIDATE } } 51 else { if above_zero==0 { return NGB_E_CANDIDATE } } 52 v=v+1 53 } 54 // Every refusal precedes the first destination write. 55 let dst: *i64=out as *i64 56 v=0 57 while v<ng { 58 let query: i64=ga+1+v*NGP_COMPONENTS 59 var floor: i64=0 60 if h[query+2]<lower_band { floor=lower_band } 61 var best: i64=0-1;var distance: i64=0 62 u=0 63 while u<nv { 64 let candidate: i64=va+1+u*NGP_COMPONENTS 65 if h[candidate+2]>=floor { 66 let dx: i64=h[candidate]-h[query] 67 let dy: i64=h[candidate+1]-h[query+1] 68 let dz: i64=h[candidate+2]-h[query+2] 69 let d: i64=dx*dx+dy*dy+dz*dz 70 if best<0 || d<distance { best=u;distance=d } 71 } 72 if step>=nv-u { u=nv } else { u=u+step } 73 } 74 dst[v]=best;v=v+1 75 } 76 return need 77} 78 79const NGB_CLIP_E_INPUT:i64=-30 80const NGB_CLIP_E_RANGE:i64=-32 81const NGB_CLIP_I64_MAX:i64=9223372036854775807 82func ngb_abs(x:i64)->i64{if x<0{return 0-x};return x} 83func ngb_clip_product(a:i64,b:i64)->i64 { 84 if a<0||b<0{return -1};if b>0{if a>NGB_CLIP_I64_MAX/b{return -1}};return a*b 85} 86func ngb_clip_gcd(a:i64,b:i64)->i64 {var x:i64=a;var y:i64=b;while y>0{let z:i64=x%y;x=y;y=z};return x} 87 88// Twice polygon area in the canonical source triangle's (bary1,bary2) plane. 89// Exact numerator/denominator; positive winding and <=1 means no inverted/expanded source coverage. 90// Input records are already validated by the clipping boundary. Large common denominators refuse. 91func ngb_clip_area_ratio_v1(poly:*i64,n:i64,result:*i64)->i64{ 92 if n<3||n>7{return NGB_CLIP_E_INPUT};var den:i64=1;var i:i64=0 93 while i<n{if poly[i*4+3]<=0{return NGB_CLIP_E_INPUT};den=ngb_clip_product(den,poly[i*4+3]);if den<0{return NGB_CLIP_E_RANGE};i=i+1} 94 var sum:i64=0;i=0 95 while i<n{let j:i64=(i+1)%n;let a:i64=ngb_clip_product(poly[i*4+1],poly[j*4+2]);let b:i64=ngb_clip_product(poly[i*4+2],poly[j*4+1]);if a<0||b<0{return NGB_CLIP_E_RANGE} 96 let pair:i64=ngb_clip_product(poly[i*4+3],poly[j*4+3]);if pair<=0{return NGB_CLIP_E_RANGE} 97 let term:i64=ngb_clip_product(ngb_abs(a-b),den/pair);if term<0{return NGB_CLIP_E_RANGE} 98 if a>=b{if sum>NGB_CLIP_I64_MAX-term{return NGB_CLIP_E_RANGE};sum=sum+term} 99 else{if sum<0-NGB_CLIP_I64_MAX+term{return NGB_CLIP_E_RANGE};sum=sum-term};i=i+1 100 } 101 let div:i64=ngb_clip_gcd(ngb_abs(sum),den);result[0]=sum/div;result[1]=den/div;return 0 102} 103 104// GAT1 v1: additive source-surface attachments; legacy GARM is unchanged. 105// Header 12 words: version,record_count,triangle_count,record_stride,VERT_check,TRIS_check, 106// source_nv,source_nt,kind,total_words,triangle_stride,reserved. 107// Record 8 words: source_face,bary0,bary1,bary2,denominator,normal_offset_units,material,flags. 108// Triangle 3 words: attachment record indices. Coefficients remain exact i64 on disk. 109const NGB_ATTACH_HDR:i64=12 110const NGB_ATTACH_REC:i64=8 111const NGB_ATTACH_COORD_MAX:i64=16777216 112const NGB_ATTACH_E_SOURCE:i64=-40 113const NGB_ATTACH_E_SHAPE:i64=-41 114const NGB_ATTACH_E_GEOMETRY:i64=-42 115// Exact integer coordinates and products of differences fit i64 under this boundary. 116func ngb_attach_source_v1(b:*u8,n:i64)->i64{ 117 if (b as i64)==0{return NGB_ATTACH_E_SOURCE} 118 let va:i64=nxa_counted_section(b,n,nxa_tag4("VERT"),3);let ta:i64=nxa_counted_section(b,n,nxa_tag4("TRIS"),3) 119 if va<0||ta<0{return NGB_ATTACH_E_SOURCE};let h:*i64=b as *i64;let nv:i64=h[va];let nt:i64=h[ta] 120 if nv<3||nt<1{return NGB_ATTACH_E_SOURCE};var i:i64=0 121 while i<nv*3{let p:i64=h[va+1+i];if p<0-NGB_ATTACH_COORD_MAX||p>NGB_ATTACH_COORD_MAX{return NGB_ATTACH_E_SOURCE};i=i+1} 122 i=0;while i<nt*3{let v:i64=h[ta+1+i];if v<0||v>=nv{return NGB_ATTACH_E_SOURCE};i=i+1};return 0 123} 124func ngb_attach_face_v1(pos:*i64,idx:*i64,face:i64)->i64{ 125 let a:i64=idx[face*3]*3;let b:i64=idx[face*3+1]*3;let c:i64=idx[face*3+2]*3 126 let x:i64=pos[b]-pos[a];let y:i64=pos[b+1]-pos[a+1];let z:i64=pos[b+2]-pos[a+2] 127 let u:i64=pos[c]-pos[a];let v:i64=pos[c+1]-pos[a+1];let w:i64=pos[c+2]-pos[a+2] 128 if y*w-z*v==0&&z*u-x*w==0&&x*v-y*u==0{return NGB_ATTACH_E_GEOMETRY};return 0 129} 130// Validate before consumer upload. Native NXA checks are integrity checks, not cryptographic authentication. 131// Caller workspace: 14 i64 words, disjoint from section/source; no output mesh or device mutation here. 132func ngb_attach_validate_v1(b:*u8,n:i64,s:*i64,nw:i64,work:*i64,work_words:i64)->i64{ 133 if (s as i64)==0||(work as i64)==0||nw<NGB_ATTACH_HDR||work_words<14{return NGB_ATTACH_E_SHAPE} 134 let sr:i64=ngb_attach_source_v1(b,n);if sr<0{return sr} 135 if s[0]!=1||s[3]!=NGB_ATTACH_REC||s[10]!=3||s[11]!=0||s[9]!=nw{return NGB_ATTACH_E_SHAPE} 136 let nr:i64=s[1];let nt:i64=s[2];if nr<3||nt<1||nr>(nw-NGB_ATTACH_HDR)/NGB_ATTACH_REC{return NGB_ATTACH_E_SHAPE} 137 let to:i64=NGB_ATTACH_HDR+nr*NGB_ATTACH_REC;if (nw-to)%3!=0||nt!=(nw-to)/3{return NGB_ATTACH_E_SHAPE} 138 if s[8]<1||s[8]>9{return NGB_ATTACH_E_SHAPE} 139 let ve:i64=nxa_section_entry(b,n,nxa_tag4("VERT"));let te:i64=nxa_section_entry(b,n,nxa_tag4("TRIS"));let h:*i64=b as *i64 140 let va:i64=h[ve+1]/8;let ta:i64=h[te+1]/8 141 if s[4]!=h[ve+3]||s[5]!=h[te+3]||s[6]!=h[va]||s[7]!=h[ta]{return NGB_ATTACH_E_SOURCE} 142 let pos:*i64=((b as i64)+(va+1)*8) as *i64;let idx:*i64=((b as i64)+(ta+1)*8) as *i64 143 var i:i64=0;while i<nr{let r:i64=NGB_ATTACH_HDR+i*NGB_ATTACH_REC;let face:i64=s[r];let den:i64=s[r+4] 144 if face<0||face>=s[7]||den<=0{return NGB_ATTACH_E_SHAPE} 145 var sum:i64=0;var k:i64=1;while k<4{let a:i64=s[r+k];if a<0||a>den-sum{return NGB_ATTACH_E_SHAPE};sum=sum+a;k=k+1} 146 if sum!=den||s[r+5]<0||s[r+5]>NGB_ATTACH_COORD_MAX||s[r+6]!=s[8]||s[r+7]!=0{return NGB_ATTACH_E_SHAPE} 147 if ngb_attach_face_v1(pos,idx,face)<0{return NGB_ATTACH_E_GEOMETRY};i=i+1 148 } 149 i=0;while i<nt{var face:i64=-1;var k:i64=0 150 while k<3{let v:i64=s[to+i*3+k];if v<0||v>=nr{return NGB_ATTACH_E_SHAPE};let r:i64=NGB_ATTACH_HDR+v*NGB_ATTACH_REC 151 if k==0{face=s[r]}else{if face!=s[r]{return NGB_ATTACH_E_GEOMETRY}} 152 var j:i64=0;while j<4{work[k*4+j]=s[r+1+j];j=j+1};k=k+1 153 } 154 let area:*i64=((work as i64)+96) as *i64;let ar:i64=ngb_clip_area_ratio_v1(work,3,area) 155 if ar<0{return ar};if area[0]<=0||area[0]>area[1]{return NGB_ATTACH_E_GEOMETRY};i=i+1 156 };return 0 157} 158 159// GAP1 upload v1: 16 uint32 header lanes, then position xyz, source-index xyzw, 160// barycentric xyz/source-unit normal-offset w and uint32 triangle indices. 161// Disk GAT1 remains exact i64. GPU conversion occurs only after complete native validation. 162const NGB_PACK_HEADER:i64=64 163const NGB_PACK_VERTEX:i64=44 164const NGB_E_PACK_INDEX:i64=-43 165const NGB_E_PACK_EXTENT:i64=-44 166// This is an integer-only exactness test; it does not round before checking. 167func ngb_source_index_f32_v1(v:i64,nv:i64)->i64{ 168 if v<0||v>=nv||v>2147483647{return NGB_E_PACK_INDEX} 169 var top:i64=16777216;var spacing:i64=1 170 while v>=top*2{top=top*2;spacing=spacing*2} 171 if v>top{spacing=spacing*2} 172 if v%spacing!=0{return NGB_E_PACK_INDEX};return 0 173} 174func ngb_attachment_bytes_v1(b:*u8,n:i64,work:*i64,work_bytes:i64)->i64{ 175 if (b as i64)==0||work_bytes<112{return NGB_ATTACH_E_SHAPE} 176 let wr:i64=ngp_output(b,n,work as *u8,work_bytes,112);if wr<0{return wr} 177 let ae:i64=nxa_section_entry(b,n,nxa_tag4("GAT1"));if ae<0{return ae} 178 let h:*i64=b as *i64;var vi:i64=0;var ti:i64=0;var ai:i64=0;var entry:i64=0 179 while entry<h[2]{let tag:i64=h[4+entry*4];if tag==nxa_tag4("VERT"){vi=vi+1};if tag==nxa_tag4("TRIS"){ti=ti+1};if tag==nxa_tag4("GAT1"){ai=ai+1};entry=entry+1} 180 if vi!=1||ti!=1||ai!=1{return NGB_ATTACH_E_SHAPE} 181 let s:*i64=((b as i64)+h[ae+1]) as *i64 182 let rc:i64=ngb_attach_validate_v1(b,n,s,h[ae+2],work,14);if rc<0{return rc} 183 let nr:i64=s[1];let nt:i64=s[2] 184 if nr>(4294967295-NGB_PACK_HEADER)/NGB_PACK_VERTEX{return NGB_E_PACK_EXTENT} 185 let base:i64=NGB_PACK_HEADER+nr*NGB_PACK_VERTEX 186 if nt>(4294967295-base)/12{return NGB_E_PACK_EXTENT} 187 let ta:i64=nxa_counted_section(b,n,nxa_tag4("TRIS"),3) 188 var i:i64=0;while i<nr{let face:i64=s[NGB_ATTACH_HDR+i*NGB_ATTACH_REC];var k:i64=0 189 while k<3{let si:i64=h[ta+1+face*3+k];if ngb_source_index_f32_v1(si,s[6])<0{return NGB_E_PACK_INDEX};k=k+1};i=i+1} 190 return base+nt*12 191} 192func ngb_attachment_pack_v1(b:*u8,n:i64,out:*u8,cap:i64,work:*i64,work_bytes:i64)->i64{ 193 if cap>0&&(out as i64)>0{let early:i64=ngp_output(work as *u8,112,out,cap,cap);if early<0{return early}} 194 let need:i64=ngb_attachment_bytes_v1(b,n,work,work_bytes);if need<0{return need} 195 let rc:i64=ngp_output(b,n,out,cap,need);if rc<0{return rc} 196 let overlap:i64=ngp_output(work as *u8,112,out,cap,need);if overlap<0{return overlap} 197 let ae:i64=nxa_section_entry(b,n,nxa_tag4("GAT1"));let h:*i64=b as *i64;let s:*i64=((b as i64)+h[ae+1]) as *i64 198 let va:i64=nxa_counted_section(b,n,nxa_tag4("VERT"),3);let ta:i64=nxa_counted_section(b,n,nxa_tag4("TRIS"),3) 199 let nr:i64=s[1];let nt:i64=s[2];let po:i64=64;let jo:i64=po+nr*12;let wo:i64=jo+nr*16;let io:i64=wo+nr*16 200 let dst:*u32=out as *u32;var i:i64=0;while i<16{dst[i]=0 as u32;i=i+1} 201 dst[0]=827343175 as u32;dst[1]=1 as u32;dst[2]=nr as u32;dst[3]=nt as u32;dst[4]=s[6] as u32;dst[5]=s[8] as u32 202 dst[6]=po as u32;dst[7]=jo as u32;dst[8]=wo as u32;dst[9]=io as u32;dst[10]=need as u32;dst[11]=1 as u32 203 i=0;while i<nr{let r:i64=NGB_ATTACH_HDR+i*NGB_ATTACH_REC;let face:i64=s[r];let den:i64=__f32_from_i64(s[r+4]);var k:i64=0 204 while k<3{let si:i64=h[ta+1+face*3+k];dst[jo/4+i*4+k]=__f32_from_i64(si) as u32;dst[wo/4+i*4+k]=__f32_div(__f32_from_i64(s[r+1+k]),den) as u32;k=k+1} 205 dst[jo/4+i*4+3]=0 as u32;dst[wo/4+i*4+3]=__f32_from_i64(s[r+5]) as u32 206 var q:i64=0;while q<3{var acc:i64=__f32_from_i64(0);k=0 207 while k<3{let si:i64=h[ta+1+face*3+k];let ratio:i64=dst[wo/4+i*4+k] as i64;acc=__f32_add(acc,__f32_mul(__f32_from_i64(h[va+1+si*3+q]),ratio));k=k+1} 208 dst[po/4+i*3+q]=acc as u32;q=q+1};i=i+1} 209 let to:i64=NGB_ATTACH_HDR+nr*NGB_ATTACH_REC;i=0;while i<nt*3{dst[io/4+i]=s[to+i] as u32;i=i+1};return need 210}