code wiki / (root) / nx_nxa_tier.nx

nx_nxa_tier.nx source

↩ module page · 588 lines · 27317 B

1// nx_nxa_tier.nx -- THE INGEST TIER LADDER FOR NXA ASSETS (/compare/modding MD5 ingest_tier_emit, 2026-09-05). 2// 3// WHY (measured 2026-09-05 on the served /world/beach cast through nx_nxa_play): every visiting-cast donor 4// carries a COMPLETE rig (zero_weight_verts=0 on all five assets), and the cast still fails to arrive -- 5// toon3d8.nxa is 61,939,208 B with 370 joints and 423,919 verts against the house girl's 11,728,120 B and 6// 14,164 verts, and NOTHING on the ingest side emits a smaller tier, so the heaviest rip is served at full 7// weight or not at all. This organ turns one NXA into a SMALLER NXA under a declared vertex budget, so a 8// world can pick a door for every device (the scale-from-a-sensor-to-a-supercomputer law applied to assets). 9// 10// HOW: dense-grid vertex clustering (Rossignac-Borrel 1993, the same idea nx_mesh_decimate applies to an 11// NxMesh) applied DIRECTLY to the NXA sections, with the cell size DERIVED by binary search so the result 12// is a measured grid whose occupied-cell count fits the budget -- never a hand-picked cell. Each occupied 13// cell becomes one vertex at the integer centroid of its members; the member NEAREST that centroid lends 14// its SKIN row (four joints and q12 weights summing 4096, so no weight is ever invented) and its TEXC row 15// (the bone-anchored UV, so the TEXM atlas still samples). Triangles are remapped and the collapsed ones 16// (two corners in one cell) dropped. Sections that do not index vertices or triangles (SKEL ANIM POSE MATL 17// TEXM HSTR) are copied verbatim with their checksums RECOMPUTED, never copied; any other section is 18// DROPPED BY NAME and counted, because a per-vertex or per-triangle section this rung does not understand 19// would silently desynchronise from the new VERT -- CLUS, MORF and the garment sections are the known 20// cases and each is a later rung, not a silent loss. 21// 22// REFUSALS, each by name and each writing NOTHING: unreadable or corrupt input, no VERT or TRIS, a budget 23// at or above the source vertex count (a tier is never an upsample), a budget under 3, a degenerate bbox. 24// 25// Usage: nx_nxa_tier <in.nxa> <out.nxa> <max_verts> 26// nx_nxa_tier ladder <in.nxa> <out_prefix> [ladder.conf] rows tier|<id>|<max_verts>|<why> 27// Exits: 0 ok | 2 usage | 3 refused-by-name | 5 missing section 28// 100% sovereign, integer only. No hw writes (Rule 26). license_tier: ORIGINAL expect_exit: 0 29import "nx_syscalls.nx" 30import "nx_nxa.nx" 31 32const TR_HDR: i64 = 32 33const TR_TOCE: i64 = 32 34const TR_TOC_W: i64 = 4 35const TR_MAXSEC: i64 = 64 36const TR_MODE: i64 = 0x1a4 // 0644 on the published asset, matching every sibling NXA writer 37const TR_PAD: i64 = 4096 38const TR_SKIN_W: i64 = 8 // SKIN row: 4 joints + 4 q12 weights (spec) 39const TR_Q12: i64 = 4096 40const TR_TEXC_HDR: i64 = 4 // TEXC payload header words: nverts, stride, grid, 0 (nx_nxa_texc_lib) 41const TR_MIN_VERTS: i64 = 3 42const TR_HASH_A: i64 = 73856093 // the classic spatial-hash primes (Teschner 2003), integer only 43const TR_HASH_B: i64 = 19349663 44const TR_HASH_C: i64 = 83492791 45const TR_TAG_BYTES: i64 = 4 46const TR_ERRFD: i64 = 2 47const TR_OUTFD: i64 = 1 48const TR_EXIT_USAGE: i64 = 2 49const TR_EXIT_REFUSE: i64 = 3 50const TR_EXIT_NOSEC: i64 = 5 51const TR_LADDER_DEFAULT: *u8 = "knowledge/nxa_tier_ladder.conf" 52const TR_MAXTIERS: i64 = 16 53const TR_PATH_CAP: i64 = 1024 54const TR_ASCII_ZERO: i64 = 48 55const TR_ASCII_NINE: i64 = 57 56const TR_ASCII_NL: i64 = 10 57const TR_ASCII_PIPE: i64 = 124 58const TR_ASCII_HASH: i64 = 35 59const TR_ASCII_US: i64 = 95 60const TR_ASCII_DOT: i64 = 46 61const TR_ASCII_MINUS: i64 = 45 62const TR_ASCII_T: i64 = 116 63const TR_ASCII_I: i64 = 105 64const TR_ASCII_E: i64 = 101 65const TR_ASCII_R: i64 = 114 66const TR_ASCII_L: i64 = 108 67const TR_ASCII_A: i64 = 97 68const TR_ASCII_D: i64 = 100 69const TR_ASCII_N: i64 = 110 70const TR_ASCII_X: i64 = 120 71const TR_LADDER_F: i64 = 4 // tier|id|max_verts|why 72 73func tr_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 74func tr_out(s: *u8) -> i64 { sys_write(TR_OUTFD, s, tr_slen(s)); return 0 } 75func tr_err(s: *u8) -> i64 { sys_write(TR_ERRFD, s, tr_slen(s)); return 0 } 76func tr_num(v: i64) -> i64 { 77 let b: *u8 = sys_mmap(32) 78 var x: i64 = v 79 if x < 0 { b[0] = TR_ASCII_MINUS as u8; sys_write(TR_OUTFD, b, 1); x = 0 - x } 80 if x == 0 { b[0] = TR_ASCII_ZERO as u8; sys_write(TR_OUTFD, b, 1); return 0 } 81 var d: i64 = 0 82 var y: i64 = x 83 while y > 0 { d = d + 1; y = y / 10 } 84 var i: i64 = d 85 while i > 0 { i = i - 1; b[i] = ((x % 10) + TR_ASCII_ZERO) as u8; x = x / 10 } 86 sys_write(TR_OUTFD, b, d) 87 return 0 88} 89func tr_atoi(s: *u8) -> i64 { 90 var v: i64 = 0 91 var i: i64 = 0 92 while s[i] != (0 as u8) { 93 let c: i64 = s[i] as i64 94 if c >= TR_ASCII_ZERO { if c <= TR_ASCII_NINE { v = v * 10 + (c - TR_ASCII_ZERO) } } 95 i = i + 1 96 } 97 return v 98} 99func tr_rd64(b: *u8, off: i64) -> i64 { let p: *i64 = ((b as i64) + off) as *i64; return p[0] } 100func tr_wr64(b: *u8, off: i64, v: i64) -> i64 { let p: *i64 = ((b as i64) + off) as *i64; p[0] = v; return 0 } 101func tr_tagout(tag: i64) -> i64 { 102 let t: *u8 = sys_mmap(8) 103 t[0] = (tag & 255) as u8 104 t[1] = ((tag >> 8) & 255) as u8 105 t[2] = ((tag >> 16) & 255) as u8 106 t[3] = ((tag >> 24) & 255) as u8 107 sys_write(TR_OUTFD, t, TR_TAG_BYTES) 108 return 0 109} 110// a section whose payload never indexes VERT or TRIS may be copied verbatim into a tier 111func tr_copyable(tag: i64) -> i64 { 112 if tag == nxa_tag4("SKEL" as *u8) { return 1 } 113 if tag == nxa_tag4("ANIM" as *u8) { return 1 } 114 if tag == nxa_tag4("POSE" as *u8) { return 1 } 115 if tag == nxa_tag4("MATL" as *u8) { return 1 } 116 if tag == nxa_tag4("TEXM" as *u8) { return 1 } 117 if tag == nxa_tag4("HSTR" as *u8) { return 1 } 118 return 0 119} 120 121// ---- the spatial hash: open addressing over (cx,cy,cz), table size a power of two >= 2*nv ---- 122func tr_pow2_at_least(n: i64) -> i64 { var p: i64 = 1; while p < n { p = p * 2 } return p } 123func tr_hslot(hx: *i64, hy: *i64, hz: *i64, hu: *i64, mask: i64, cx: i64, cy: i64, cz: i64, hr: *i64, region: i64) -> i64 { 124 var h: i64 = cx * TR_HASH_A + cy * TR_HASH_B + cz * TR_HASH_C 125 if h < 0 { h = 0 - h } 126 var s: i64 = h & mask 127 while hu[s] == 1 { 128 if hx[s] == cx { if hy[s] == cy { if hz[s] == cz { if hr[s] == region { return s } } } } 129 s = (s + 1) & mask 130 } 131 return s 132} 133// occupied-cell count for one cell size; the table is cleared here so the caller never forgets 134func tr_occupied(vw: *i64, nv: i64, minx: i64, miny: i64, minz: i64, cell: i64, hx: *i64, hy: *i64, hz: *i64, hu: *i64, tsize: i64, hr: *i64, regions: *i64) -> i64 { 135 var i: i64 = 0 136 while i < tsize { hu[i] = 0; i = i + 1 } 137 let mask: i64 = tsize - 1 138 var occ: i64 = 0 139 var v: i64 = 0 140 while v < nv { 141 let cx: i64 = (vw[v*3] - minx) / cell 142 let cy: i64 = (vw[v*3 + 1] - miny) / cell 143 let cz: i64 = (vw[v*3 + 2] - minz) / cell 144 let s: i64 = tr_hslot(hx, hy, hz, hu, mask, cx, cy, cz, hr, regions[v]) 145 if hu[s] == 0 { hu[s] = 1; hx[s] = cx; hy[s] = cy; hz[s] = cz; hr[s] = regions[v]; occ = occ + 1 } 146 v = v + 1 147 } 148 return occ 149} 150 151func tr_section_words(b:*u8,tag:i64)->i64 { 152 let ns:i64=tr_rd64(b,16);var i:i64=0 153 while i<ns {let e:i64=TR_HDR+i*TR_TOCE;if tr_rd64(b,e)==tag{return tr_rd64(b,e+16)};i=i+1} 154 return 0-1 155} 156 157// ---- ONE tier: read, cluster, remap, write. Returns the exit code; prints its own receipt. ---- 158func tr_tier(inp: *u8, outp: *u8, target: i64) -> i64 { 159 if target < TR_MIN_VERTS { tr_err("NXA-TIER-REFUSE budget under 3 vertices\n" as *u8); return TR_EXIT_REFUSE } 160 let lp: *i64 = sys_mmap(64) as *i64 161 let b: *u8 = sys_read_file(inp, lp) 162 if (b as i64) == 0 { tr_err("NXA-TIER-REFUSE cannot read input\n" as *u8); return TR_EXIT_REFUSE } 163 let flen: i64 = lp[0] 164 let w: *i64 = b as *i64 165 let vwo: i64 = nxa_find(b, flen, nxa_tag4("VERT" as *u8)) 166 if vwo == 0 - 2 { tr_err("NXA-TIER-REFUSE future NXA version\n" as *u8); return TR_EXIT_REFUSE } 167 if vwo == 0 - 3 { tr_err("NXA-TIER-REFUSE corrupt NXA (TOC or VERT checksum failed)\n" as *u8); return TR_EXIT_REFUSE } 168 if vwo < 0 { tr_err("NXA-TIER-REFUSE no VERT section\n" as *u8); return TR_EXIT_NOSEC } 169 let two: i64 = nxa_find(b, flen, nxa_tag4("TRIS" as *u8)) 170 if two == 0 - 3 { tr_err("NXA-TIER-REFUSE corrupt NXA (TRIS checksum failed)\n" as *u8); return TR_EXIT_REFUSE } 171 if two < 0 { tr_err("NXA-TIER-REFUSE no TRIS section\n" as *u8); return TR_EXIT_NOSEC } 172 let kwo: i64 = nxa_find(b, flen, nxa_tag4("SKIN" as *u8)) 173 if kwo == 0 - 3 { tr_err("NXA-TIER-REFUSE corrupt NXA (SKIN checksum failed)\n" as *u8); return TR_EXIT_REFUSE } 174 let xwo: i64 = nxa_find(b, flen, nxa_tag4("TEXC" as *u8)) 175 if xwo == 0 - 3 { tr_err("NXA-TIER-REFUSE corrupt NXA (TEXC checksum failed)\n" as *u8); return TR_EXIT_REFUSE } 176 let nv: i64 = w[vwo] 177 let nt: i64 = w[two] 178 if nv < TR_MIN_VERTS { tr_err("NXA-TIER-REFUSE source has fewer than 3 vertices\n" as *u8); return TR_EXIT_REFUSE } 179 if nt < 1 { tr_err("NXA-TIER-REFUSE source has no triangles\n" as *u8); return TR_EXIT_REFUSE } 180 if target >= nv { tr_err("NXA-TIER-REFUSE budget at or above the source vertex count -- a tier is never an upsample\n" as *u8); return TR_EXIT_REFUSE } 181 if kwo >= 0 { if w[kwo] != nv { tr_err("NXA-TIER-REFUSE SKIN vertex count does not match VERT\n" as *u8); return TR_EXIT_REFUSE } } 182 var xstride: i64 = 0 183 if xwo >= 0 { 184 if w[xwo] != nv { tr_err("NXA-TIER-REFUSE TEXC vertex count does not match VERT\n" as *u8); return TR_EXIT_REFUSE } 185 xstride = w[xwo + 1] 186 if xstride < 1 { tr_err("NXA-TIER-REFUSE TEXC stride invalid\n" as *u8); return TR_EXIT_REFUSE } 187 } 188 let vwords:i64=tr_section_words(b,nxa_tag4("VERT" as *u8)) 189 let twords:i64=tr_section_words(b,nxa_tag4("TRIS" as *u8)) 190 if nv>(vwords-1)/3||nt>(twords-1)/3 {tr_err("NXA-TIER-REFUSE geometry count exceeds section extent\n" as *u8);return TR_EXIT_REFUSE} 191 if kwo>=0 {if nv>(tr_section_words(b,nxa_tag4("SKIN" as *u8))-1)/TR_SKIN_W {tr_err("NXA-TIER-REFUSE SKIN rows exceed section extent\n" as *u8);return TR_EXIT_REFUSE}} 192 if xwo>=0 {if nv>(tr_section_words(b,nxa_tag4("TEXC" as *u8))-TR_TEXC_HDR)/xstride {tr_err("NXA-TIER-REFUSE TEXC rows exceed section extent\n" as *u8);return TR_EXIT_REFUSE}} 193 var checked_tri:i64=0 194 while checked_tri<nt*3 {let index:i64=w[two+1+checked_tri];if index<0||index>=nv {tr_err("NXA-TIER-REFUSE triangle index outside VERT\n" as *u8);return TR_EXIT_REFUSE};checked_tri=checked_tri+1} 195 let vw: *i64 = ((w as i64) + (vwo + 1) * 8) as *i64 196 let tw: *i64 = ((w as i64) + (two + 1) * 8) as *i64 197 var minx: i64 = vw[0] 198 var maxx: i64 = vw[0] 199 var miny: i64 = vw[1] 200 var maxy: i64 = vw[1] 201 var minz: i64 = vw[2] 202 var maxz: i64 = vw[2] 203 var v: i64 = 1 204 while v < nv { 205 let x: i64 = vw[v*3] 206 let y: i64 = vw[v*3 + 1] 207 let z: i64 = vw[v*3 + 2] 208 if x < minx { minx = x } 209 if x > maxx { maxx = x } 210 if y < miny { miny = y } 211 if y > maxy { maxy = y } 212 if z < minz { minz = z } 213 if z > maxz { maxz = z } 214 v = v + 1 215 } 216 var ext: i64 = maxx - minx 217 if maxy - miny > ext { ext = maxy - miny } 218 if maxz - minz > ext { ext = maxz - minz } 219 if ext < 1 { tr_err("NXA-TIER-REFUSE degenerate bbox (every vertex at one point)\n" as *u8); return TR_EXIT_REFUSE } 220 let tsize: i64 = tr_pow2_at_least(nv * 2) 221 let hx: *i64 = sys_mmap(tsize * 8) as *i64 222 let hy: *i64 = sys_mmap(tsize * 8) as *i64 223 let hz: *i64 = sys_mmap(tsize * 8) as *i64 224 let hu: *i64 = sys_mmap(tsize * 8) as *i64 225 let hrep: *i64 = sys_mmap(tsize * 8) as *i64 226 let hr: *i64 = sys_mmap(tsize * 8) as *i64 227 let regions: *i64 = sys_mmap(nv * 8) as *i64 228 if (hx as i64)<=0||(hy as i64)<=0||(hz as i64)<=0||(hu as i64)<=0||(hrep as i64)<=0||(hr as i64)<=0||(regions as i64)<=0 { tr_err("NXA-TIER-REFUSE cannot allocate region clustering\n" as *u8); return TR_EXIT_REFUSE } 229 // TEXC word 2 in each stride-3 row is an opaque ownership tag. 230 // Near-coincident surfaces must not borrow another region's UV/skin representative. 231 v = 0 232 while v < nv { 233 regions[v] = 0 234 if xwo >= 0 { if xstride == 3 { regions[v] = w[xwo + TR_TEXC_HDR + v*xstride + 2] } } 235 v = v + 1 236 } 237 let coarse: i64 = tr_occupied(vw,nv,minx,miny,minz,ext+1,hx,hy,hz,hu,tsize,hr,regions) 238 if coarse > target { tr_err("NXA-TIER-REFUSE budget incompatible with retained TEXC region ownership\n" as *u8); return TR_EXIT_REFUSE } 239 // Search a budget-fitting grid; aligned occupancy is not globally monotone, 240 // so no finest-grid claim is made. The final count is measured before output. 241 var lo: i64 = 1 242 var hi: i64 = ext + 1 243 var probes: i64 = 0 244 while lo < hi { 245 let mid: i64 = (lo + hi) / 2 246 let occ: i64 = tr_occupied(vw, nv, minx, miny, minz, mid, hx, hy, hz, hu, tsize, hr, regions) 247 probes = probes + 1 248 if occ <= target { hi = mid } else { lo = mid + 1 } 249 } 250 let cell: i64 = lo 251 let measured: i64 = tr_occupied(vw,nv,minx,miny,minz,cell,hx,hy,hz,hu,tsize,hr,regions) 252 if measured > target { tr_err("NXA-TIER-REFUSE measured region clusters exceed requested budget\n" as *u8); return TR_EXIT_REFUSE } 253 var i: i64 = 0 254 while i < tsize { hu[i] = 0; i = i + 1 } 255 let mask: i64 = tsize - 1 256 let cap: i64 = target + 1 257 let sx: *i64 = sys_mmap(cap * 8) as *i64 258 let sy: *i64 = sys_mmap(cap * 8) as *i64 259 let sz: *i64 = sys_mmap(cap * 8) as *i64 260 let cnt: *i64 = sys_mmap(cap * 8) as *i64 261 let vrep: *i64 = sys_mmap(nv * 8) as *i64 262 var nout: i64 = 0 263 v = 0 264 while v < nv { 265 let cx: i64 = (vw[v*3] - minx) / cell 266 let cy: i64 = (vw[v*3 + 1] - miny) / cell 267 let cz: i64 = (vw[v*3 + 2] - minz) / cell 268 let s: i64 = tr_hslot(hx, hy, hz, hu, mask, cx, cy, cz, hr, regions[v]) 269 if hu[s] == 0 { 270 if nout >= cap { tr_err("NXA-TIER-REFUSE occupied cells exceeded the searched budget (internal)\n" as *u8); return TR_EXIT_REFUSE } 271 hu[s] = 1 272 hx[s] = cx 273 hy[s] = cy 274 hz[s] = cz 275 hr[s] = regions[v] 276 hrep[s] = nout 277 nout = nout + 1 278 } 279 let r: i64 = hrep[s] 280 vrep[v] = r 281 sx[r] = sx[r] + vw[v*3] 282 sy[r] = sy[r] + vw[v*3 + 1] 283 sz[r] = sz[r] + vw[v*3 + 2] 284 cnt[r] = cnt[r] + 1 285 v = v + 1 286 } 287 let cxv: *i64 = sys_mmap(cap * 8) as *i64 288 let cyv: *i64 = sys_mmap(cap * 8) as *i64 289 let czv: *i64 = sys_mmap(cap * 8) as *i64 290 let bestd: *i64 = sys_mmap(cap * 8) as *i64 291 let bestv: *i64 = sys_mmap(cap * 8) as *i64 292 var r2: i64 = 0 293 while r2 < nout { 294 cxv[r2] = sx[r2] / cnt[r2] 295 cyv[r2] = sy[r2] / cnt[r2] 296 czv[r2] = sz[r2] / cnt[r2] 297 bestd[r2] = 0 - 1 298 bestv[r2] = 0 - 1 299 r2 = r2 + 1 300 } 301 v = 0 302 while v < nv { 303 let r: i64 = vrep[v] 304 let dx: i64 = vw[v*3] - cxv[r] 305 let dy: i64 = vw[v*3 + 1] - cyv[r] 306 let dz: i64 = vw[v*3 + 2] - czv[r] 307 let d2: i64 = dx*dx + dy*dy + dz*dz 308 if bestd[r] < 0 { bestd[r] = d2; bestv[r] = v } 309 if d2 < bestd[r] { bestd[r] = d2; bestv[r] = v } 310 v = v + 1 311 } 312 var tkeep: i64 = 0 313 var t: i64 = 0 314 while t < nt { 315 let a: i64 = vrep[tw[t*3]] 316 let bb: i64 = vrep[tw[t*3 + 1]] 317 let c: i64 = vrep[tw[t*3 + 2]] 318 if a != bb { if bb != c { if a != c { tkeep = tkeep + 1 } } } 319 t = t + 1 320 } 321 if tkeep < 1 { tr_err("NXA-TIER-REFUSE every triangle collapsed at this budget\n" as *u8); return TR_EXIT_REFUSE } 322 // ---- output layout: walk the input TOC in order; remap VERT TRIS SKIN TEXC, copy the copyable, drop the rest ---- 323 let ns: i64 = w[2] 324 var nsec: i64 = 0 325 var dropped: i64 = 0 326 var copied: i64 = 0 327 var remapped: i64 = 0 328 var total: i64 = 0 329 var s0: i64 = 0 330 while s0 < ns { 331 let e: i64 = TR_HDR + s0 * TR_TOCE 332 let tag: i64 = tr_rd64(b, e) 333 let wl: i64 = tr_rd64(b, e + 16) 334 var handled: i64 = 0 335 if tag == nxa_tag4("VERT" as *u8) { handled = 1; nsec = nsec + 1; remapped = remapped + 1; total = total + (1 + nout*3) * 8 } 336 if tag == nxa_tag4("TRIS" as *u8) { handled = 1; nsec = nsec + 1; remapped = remapped + 1; total = total + (1 + tkeep*3) * 8 } 337 if tag == nxa_tag4("SKIN" as *u8) { handled = 1; nsec = nsec + 1; remapped = remapped + 1; total = total + (1 + nout*TR_SKIN_W) * 8 } 338 if tag == nxa_tag4("TEXC" as *u8) { handled = 1; nsec = nsec + 1; remapped = remapped + 1; total = total + (TR_TEXC_HDR + nout*xstride) * 8 } 339 if handled == 0 { if tr_copyable(tag) == 1 { handled = 1; nsec = nsec + 1; copied = copied + 1; total = total + wl * 8 } } 340 if handled == 0 { 341 dropped = dropped + 1 342 tr_out("NXA-TIER-DROPPED tag=" as *u8) 343 tr_tagout(tag) 344 tr_out(" (a per-vertex or per-triangle section this rung does not carry; a later rung remaps it)\n" as *u8) 345 } 346 s0 = s0 + 1 347 } 348 if nsec < 1 { tr_err("NXA-TIER-REFUSE nothing to emit\n" as *u8); return TR_EXIT_REFUSE } 349 let toclen: i64 = TR_HDR + nsec * TR_TOCE 350 total = total + toclen 351 let nb: *u8 = sys_mmap(total + TR_PAD) 352 if (nb as i64) == 0 { tr_err("NXA-TIER-REFUSE cannot allocate output\n" as *u8); return TR_EXIT_REFUSE } 353 tr_wr64(nb, 0, nxa_magic()) 354 tr_wr64(nb, 8, NXA_VER) 355 tr_wr64(nb, 16, nsec) 356 var wo: i64 = toclen 357 var ti: i64 = 0 358 var s1: i64 = 0 359 while s1 < ns { 360 let e: i64 = TR_HDR + s1 * TR_TOCE 361 let tag: i64 = tr_rd64(b, e) 362 let oldoff: i64 = tr_rd64(b, e + 8) 363 let wl: i64 = tr_rd64(b, e + 16) 364 var emit: i64 = 0 365 var nw: i64 = 0 366 let te: i64 = TR_HDR + ti * TR_TOCE 367 if tag == nxa_tag4("VERT" as *u8) { 368 emit = 1 369 nw = 1 + nout * 3 370 tr_wr64(nb, wo, nout) 371 var r: i64 = 0 372 while r < nout { 373 tr_wr64(nb, wo + (1 + r*3)*8, cxv[r]) 374 tr_wr64(nb, wo + (2 + r*3)*8, cyv[r]) 375 tr_wr64(nb, wo + (3 + r*3)*8, czv[r]) 376 r = r + 1 377 } 378 } 379 if tag == nxa_tag4("TRIS" as *u8) { 380 emit = 1 381 nw = 1 + tkeep * 3 382 tr_wr64(nb, wo, tkeep) 383 var k: i64 = 0 384 var t2: i64 = 0 385 while t2 < nt { 386 let a: i64 = vrep[tw[t2*3]] 387 let bb: i64 = vrep[tw[t2*3 + 1]] 388 let c: i64 = vrep[tw[t2*3 + 2]] 389 if a != bb { if bb != c { if a != c { 390 tr_wr64(nb, wo + (1 + k*3)*8, a) 391 tr_wr64(nb, wo + (2 + k*3)*8, bb) 392 tr_wr64(nb, wo + (3 + k*3)*8, c) 393 k = k + 1 394 } } } 395 t2 = t2 + 1 396 } 397 } 398 if tag == nxa_tag4("SKIN" as *u8) { 399 emit = 1 400 nw = 1 + nout * TR_SKIN_W 401 tr_wr64(nb, wo, nout) 402 var r: i64 = 0 403 while r < nout { 404 let src: i64 = bestv[r] 405 var f: i64 = 0 406 while f < TR_SKIN_W { tr_wr64(nb, wo + (1 + r*TR_SKIN_W + f)*8, w[kwo + 1 + src*TR_SKIN_W + f]); f = f + 1 } 407 r = r + 1 408 } 409 } 410 if tag == nxa_tag4("TEXC" as *u8) { 411 emit = 1 412 nw = TR_TEXC_HDR + nout * xstride 413 tr_wr64(nb, wo, nout) 414 tr_wr64(nb, wo + 8, xstride) 415 tr_wr64(nb, wo + 16, w[xwo + 2]) 416 tr_wr64(nb, wo + 24, w[xwo + 3]) 417 var r: i64 = 0 418 while r < nout { 419 let src: i64 = bestv[r] 420 var f: i64 = 0 421 while f < xstride { tr_wr64(nb, wo + (TR_TEXC_HDR + r*xstride + f)*8, w[xwo + TR_TEXC_HDR + src*xstride + f]); f = f + 1 } 422 r = r + 1 423 } 424 } 425 if emit == 0 { if tr_copyable(tag) == 1 { 426 emit = 1 427 nw = wl 428 var k2: i64 = 0 429 while k2 < wl * 8 { nb[wo + k2] = b[oldoff + k2]; k2 = k2 + 1 } 430 } } 431 if emit == 1 { 432 tr_wr64(nb, te, tag) 433 tr_wr64(nb, te + 8, wo) 434 tr_wr64(nb, te + 16, nw) 435 let pw: *i64 = ((nb as i64) + wo) as *i64 436 tr_wr64(nb, te + 24, nxa_check2(1, pw, nw)) 437 wo = wo + nw * 8 438 ti = ti + 1 439 } 440 s1 = s1 + 1 441 } 442 let tb: *i64 = ((nb as i64) + TR_HDR) as *i64 443 tr_wr64(nb, 24, nxa_check2(1, tb, nsec * TR_TOC_W)) 444 let fd: i64 = sys_openat_wr(outp, TR_MODE) 445 if fd < 0 { tr_err("NXA-TIER-REFUSE cannot open output\n" as *u8); return TR_EXIT_REFUSE } 446 sys_write(fd, nb, wo) 447 sys_close(fd) 448 tr_out("NXA-TIER-OK in_verts=" as *u8); tr_num(nv) 449 tr_out(" out_verts=" as *u8); tr_num(nout) 450 tr_out(" in_tris=" as *u8); tr_num(nt) 451 tr_out(" out_tris=" as *u8); tr_num(tkeep) 452 tr_out(" collapsed_tris=" as *u8); tr_num(nt - tkeep) 453 tr_out(" region_ownership=" as *u8); if xstride == 3 { tr_num(1) } else { tr_num(0) } 454 tr_out(" region_floor=" as *u8); tr_num(coarse) 455 tr_out(" budget=" as *u8); tr_num(target) 456 tr_out(" cell_umm=" as *u8); tr_num(cell) 457 tr_out(" search_probes=" as *u8); tr_num(probes) 458 tr_out(" sections_in=" as *u8); tr_num(ns) 459 tr_out(" remapped=" as *u8); tr_num(remapped) 460 tr_out(" copied=" as *u8); tr_num(copied) 461 tr_out(" dropped=" as *u8); tr_num(dropped) 462 tr_out(" sum=" as *u8); tr_num(remapped + copied + dropped) 463 tr_out(" bytes=" as *u8); tr_num(wo) 464 tr_out("\n" as *u8) 465 return 0 466} 467 468// ---- the ladder verb: one output per conf tier under the source, the partition printed ---- 469func tr_ladder(inp: *u8, prefix: *u8, conf: *u8) -> i64 { 470 let lp: *i64 = sys_mmap(64) as *i64 471 let cb: *u8 = sys_read_file(conf, lp) 472 if (cb as i64) == 0 { tr_err("NXA-TIER-REFUSE cannot read the ladder conf\n" as *u8); return TR_EXIT_REFUSE } 473 let cn: i64 = lp[0] 474 let lp2: *i64 = sys_mmap(64) as *i64 475 let b: *u8 = sys_read_file(inp, lp2) 476 if (b as i64) == 0 { tr_err("NXA-TIER-REFUSE cannot read input\n" as *u8); return TR_EXIT_REFUSE } 477 let flen: i64 = lp2[0] 478 let vwo: i64 = nxa_find(b, flen, nxa_tag4("VERT" as *u8)) 479 if vwo < 0 { tr_err("NXA-TIER-REFUSE no valid VERT section\n" as *u8); return TR_EXIT_NOSEC } 480 let w: *i64 = b as *i64 481 let nv: i64 = w[vwo] 482 var emitted: i64 = 0 483 var skipped: i64 = 0 484 var failed: i64 = 0 485 var rows: i64 = 0 486 let idb: *u8 = sys_mmap(TR_PATH_CAP) 487 let outb: *u8 = sys_mmap(TR_PATH_CAP) 488 var p: i64 = 0 489 while p < cn { 490 var le: i64 = p 491 while le < cn { if cb[le] == (TR_ASCII_NL as u8) { break } le = le + 1 } 492 if le > p { if cb[p] != (TR_ASCII_HASH as u8) { 493 var f0: i64 = p 494 var fi: i64 = 0 495 var idlen: i64 = 0 496 var maxv: i64 = 0 497 var istier: i64 = 0 498 var q: i64 = p 499 while q <= le { 500 var atend: i64 = 0 501 if q == le { atend = 1 } else { if cb[q] == (TR_ASCII_PIPE as u8) { atend = 1 } } 502 if atend == 1 { 503 if fi == 0 { if q - f0 == TR_TAG_BYTES { if cb[f0] == (TR_ASCII_T as u8) { if cb[f0+1] == (TR_ASCII_I as u8) { if cb[f0+2] == (TR_ASCII_E as u8) { if cb[f0+3] == (TR_ASCII_R as u8) { istier = 1 } } } } } } 504 if fi == 1 { 505 idlen = q - f0 506 var c2: i64 = 0 507 while c2 < idlen { if c2 < TR_PATH_CAP - 1 { idb[c2] = cb[f0 + c2] } c2 = c2 + 1 } 508 if idlen > TR_PATH_CAP - 1 { idlen = TR_PATH_CAP - 1 } 509 idb[idlen] = 0 as u8 510 } 511 if fi == 2 { 512 var vv: i64 = 0 513 var c3: i64 = f0 514 while c3 < q { 515 let ch: i64 = cb[c3] as i64 516 if ch >= TR_ASCII_ZERO { if ch <= TR_ASCII_NINE { vv = vv * 10 + (ch - TR_ASCII_ZERO) } } 517 c3 = c3 + 1 518 } 519 maxv = vv 520 } 521 fi = fi + 1 522 f0 = q + 1 523 } 524 q = q + 1 525 } 526 if istier == 1 { if fi >= TR_LADDER_F { 527 rows = rows + 1 528 if maxv >= nv { 529 skipped = skipped + 1 530 tr_out("NXA-TIER-SKIP tier=" as *u8); tr_out(idb); tr_out(" max_verts=" as *u8); tr_num(maxv); tr_out(" is not under the source " as *u8); tr_num(nv); tr_out(" (a tier is never an upsample)\n" as *u8) 531 } else { 532 var o: i64 = 0 533 var c4: i64 = 0 534 while prefix[c4] != (0 as u8) { if o < TR_PATH_CAP - 8 { outb[o] = prefix[c4]; o = o + 1 } c4 = c4 + 1 } 535 outb[o] = TR_ASCII_US as u8 536 o = o + 1 537 c4 = 0 538 while idb[c4] != (0 as u8) { if o < TR_PATH_CAP - 8 { outb[o] = idb[c4]; o = o + 1 } c4 = c4 + 1 } 539 outb[o] = TR_ASCII_DOT as u8 540 outb[o+1] = TR_ASCII_N as u8 541 outb[o+2] = TR_ASCII_X as u8 542 outb[o+3] = TR_ASCII_A as u8 543 outb[o+4] = 0 as u8 544 tr_out("NXA-TIER-LADDER tier=" as *u8); tr_out(idb); tr_out(" out=" as *u8); tr_out(outb); tr_out("\n" as *u8) 545 let rc: i64 = tr_tier(inp, outb, maxv) 546 if rc == 0 { emitted = emitted + 1 } else { failed = failed + 1 } 547 } 548 } } 549 } } 550 p = le + 1 551 } 552 tr_out("NXA-TIER-LADDER-DONE tiers=" as *u8); tr_num(rows) 553 tr_out(" emitted=" as *u8); tr_num(emitted) 554 tr_out(" skipped=" as *u8); tr_num(skipped) 555 tr_out(" failed=" as *u8); tr_num(failed) 556 tr_out(" sum=" as *u8); tr_num(emitted + skipped + failed) 557 tr_out(" source_verts=" as *u8); tr_num(nv) 558 tr_out("\n" as *u8) 559 if rows < 1 { tr_err("NXA-TIER-REFUSE the ladder conf declares no tier rows\n" as *u8); return TR_EXIT_REFUSE } 560 if failed > 0 { return TR_EXIT_REFUSE } 561 return 0 562} 563 564func tr_is_ladder(a: *u8) -> i64 { 565 if a[0] != (TR_ASCII_L as u8) { return 0 } 566 if a[1] != (TR_ASCII_A as u8) { return 0 } 567 if a[2] != (TR_ASCII_D as u8) { return 0 } 568 if a[3] != (TR_ASCII_D as u8) { return 0 } 569 if a[4] != (TR_ASCII_E as u8) { return 0 } 570 if a[5] != (TR_ASCII_R as u8) { return 0 } 571 if a[6] != (0 as u8) { return 0 } 572 return 1 573} 574 575func main(argc: i64, argv: *i64) -> i64 { 576 if argc < 4 { 577 tr_err("usage: nx_nxa_tier <in.nxa> <out.nxa> <max_verts> | nx_nxa_tier ladder <in.nxa> <out_prefix> [ladder.conf]\n" as *u8) 578 return TR_EXIT_USAGE 579 } 580 let a1: *u8 = argv[1] as *u8 581 if tr_is_ladder(a1) == 1 { 582 var conf: *u8 = TR_LADDER_DEFAULT 583 if argc >= 5 { conf = argv[4] as *u8 } 584 return tr_ladder(argv[2] as *u8, argv[3] as *u8, conf) 585 } 586 let target: i64 = tr_atoi(argv[3] as *u8) 587 return tr_tier(a1, argv[2] as *u8, target) 588}