nx_nxa_tier_pre_region_t143.nx source
↩ module page · 557 lines · 24911 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 the finest 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) -> 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 { 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) -> 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)
145 if hu[s] == 0 { hu[s] = 1; hx[s] = cx; hy[s] = cy; hz[s] = cz; occ = occ + 1 }
146 v = v + 1
147 }
148 return occ
149}
150
151// ---- ONE tier: read, cluster, remap, write. Returns the exit code; prints its own receipt. ----
152func tr_tier(inp: *u8, outp: *u8, target: i64) -> i64 {
153 if target < TR_MIN_VERTS { tr_err("NXA-TIER-REFUSE budget under 3 vertices\n" as *u8); return TR_EXIT_REFUSE }
154 let lp: *i64 = sys_mmap(64) as *i64
155 let b: *u8 = sys_read_file(inp, lp)
156 if (b as i64) == 0 { tr_err("NXA-TIER-REFUSE cannot read input\n" as *u8); return TR_EXIT_REFUSE }
157 let flen: i64 = lp[0]
158 let w: *i64 = b as *i64
159 let vwo: i64 = nxa_find(b, flen, nxa_tag4("VERT" as *u8))
160 if vwo == 0 - 2 { tr_err("NXA-TIER-REFUSE future NXA version\n" as *u8); return TR_EXIT_REFUSE }
161 if vwo == 0 - 3 { tr_err("NXA-TIER-REFUSE corrupt NXA (TOC or VERT checksum failed)\n" as *u8); return TR_EXIT_REFUSE }
162 if vwo < 0 { tr_err("NXA-TIER-REFUSE no VERT section\n" as *u8); return TR_EXIT_NOSEC }
163 let two: i64 = nxa_find(b, flen, nxa_tag4("TRIS" as *u8))
164 if two == 0 - 3 { tr_err("NXA-TIER-REFUSE corrupt NXA (TRIS checksum failed)\n" as *u8); return TR_EXIT_REFUSE }
165 if two < 0 { tr_err("NXA-TIER-REFUSE no TRIS section\n" as *u8); return TR_EXIT_NOSEC }
166 let kwo: i64 = nxa_find(b, flen, nxa_tag4("SKIN" as *u8))
167 if kwo == 0 - 3 { tr_err("NXA-TIER-REFUSE corrupt NXA (SKIN checksum failed)\n" as *u8); return TR_EXIT_REFUSE }
168 let xwo: i64 = nxa_find(b, flen, nxa_tag4("TEXC" as *u8))
169 if xwo == 0 - 3 { tr_err("NXA-TIER-REFUSE corrupt NXA (TEXC checksum failed)\n" as *u8); return TR_EXIT_REFUSE }
170 let nv: i64 = w[vwo]
171 let nt: i64 = w[two]
172 if nv < TR_MIN_VERTS { tr_err("NXA-TIER-REFUSE source has fewer than 3 vertices\n" as *u8); return TR_EXIT_REFUSE }
173 if nt < 1 { tr_err("NXA-TIER-REFUSE source has no triangles\n" as *u8); return TR_EXIT_REFUSE }
174 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 }
175 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 } }
176 var xstride: i64 = 0
177 if xwo >= 0 {
178 if w[xwo] != nv { tr_err("NXA-TIER-REFUSE TEXC vertex count does not match VERT\n" as *u8); return TR_EXIT_REFUSE }
179 xstride = w[xwo + 1]
180 if xstride < 1 { tr_err("NXA-TIER-REFUSE TEXC stride invalid\n" as *u8); return TR_EXIT_REFUSE }
181 }
182 let vw: *i64 = ((w as i64) + (vwo + 1) * 8) as *i64
183 let tw: *i64 = ((w as i64) + (two + 1) * 8) as *i64
184 var minx: i64 = vw[0]
185 var maxx: i64 = vw[0]
186 var miny: i64 = vw[1]
187 var maxy: i64 = vw[1]
188 var minz: i64 = vw[2]
189 var maxz: i64 = vw[2]
190 var v: i64 = 1
191 while v < nv {
192 let x: i64 = vw[v*3]
193 let y: i64 = vw[v*3 + 1]
194 let z: i64 = vw[v*3 + 2]
195 if x < minx { minx = x }
196 if x > maxx { maxx = x }
197 if y < miny { miny = y }
198 if y > maxy { maxy = y }
199 if z < minz { minz = z }
200 if z > maxz { maxz = z }
201 v = v + 1
202 }
203 var ext: i64 = maxx - minx
204 if maxy - miny > ext { ext = maxy - miny }
205 if maxz - minz > ext { ext = maxz - minz }
206 if ext < 1 { tr_err("NXA-TIER-REFUSE degenerate bbox (every vertex at one point)\n" as *u8); return TR_EXIT_REFUSE }
207 let tsize: i64 = tr_pow2_at_least(nv * 2)
208 let hx: *i64 = sys_mmap(tsize * 8) as *i64
209 let hy: *i64 = sys_mmap(tsize * 8) as *i64
210 let hz: *i64 = sys_mmap(tsize * 8) as *i64
211 let hu: *i64 = sys_mmap(tsize * 8) as *i64
212 let hrep: *i64 = sys_mmap(tsize * 8) as *i64
213 // binary search: the SMALLEST cell whose occupied-cell count fits the budget (occupied is monotone
214 // non-increasing in cell size, and the whole bbox in one cell always fits since target >= 3)
215 var lo: i64 = 1
216 var hi: i64 = ext
217 var probes: i64 = 0
218 while lo < hi {
219 let mid: i64 = (lo + hi) / 2
220 let occ: i64 = tr_occupied(vw, nv, minx, miny, minz, mid, hx, hy, hz, hu, tsize)
221 probes = probes + 1
222 if occ <= target { hi = mid } else { lo = mid + 1 }
223 }
224 let cell: i64 = lo
225 var i: i64 = 0
226 while i < tsize { hu[i] = 0; i = i + 1 }
227 let mask: i64 = tsize - 1
228 let cap: i64 = target + 1
229 let sx: *i64 = sys_mmap(cap * 8) as *i64
230 let sy: *i64 = sys_mmap(cap * 8) as *i64
231 let sz: *i64 = sys_mmap(cap * 8) as *i64
232 let cnt: *i64 = sys_mmap(cap * 8) as *i64
233 let vrep: *i64 = sys_mmap(nv * 8) as *i64
234 var nout: i64 = 0
235 v = 0
236 while v < nv {
237 let cx: i64 = (vw[v*3] - minx) / cell
238 let cy: i64 = (vw[v*3 + 1] - miny) / cell
239 let cz: i64 = (vw[v*3 + 2] - minz) / cell
240 let s: i64 = tr_hslot(hx, hy, hz, hu, mask, cx, cy, cz)
241 if hu[s] == 0 {
242 if nout >= cap { tr_err("NXA-TIER-REFUSE occupied cells exceeded the searched budget (internal)\n" as *u8); return TR_EXIT_REFUSE }
243 hu[s] = 1
244 hx[s] = cx
245 hy[s] = cy
246 hz[s] = cz
247 hrep[s] = nout
248 nout = nout + 1
249 }
250 let r: i64 = hrep[s]
251 vrep[v] = r
252 sx[r] = sx[r] + vw[v*3]
253 sy[r] = sy[r] + vw[v*3 + 1]
254 sz[r] = sz[r] + vw[v*3 + 2]
255 cnt[r] = cnt[r] + 1
256 v = v + 1
257 }
258 let cxv: *i64 = sys_mmap(cap * 8) as *i64
259 let cyv: *i64 = sys_mmap(cap * 8) as *i64
260 let czv: *i64 = sys_mmap(cap * 8) as *i64
261 let bestd: *i64 = sys_mmap(cap * 8) as *i64
262 let bestv: *i64 = sys_mmap(cap * 8) as *i64
263 var r2: i64 = 0
264 while r2 < nout {
265 cxv[r2] = sx[r2] / cnt[r2]
266 cyv[r2] = sy[r2] / cnt[r2]
267 czv[r2] = sz[r2] / cnt[r2]
268 bestd[r2] = 0 - 1
269 bestv[r2] = 0 - 1
270 r2 = r2 + 1
271 }
272 v = 0
273 while v < nv {
274 let r: i64 = vrep[v]
275 let dx: i64 = vw[v*3] - cxv[r]
276 let dy: i64 = vw[v*3 + 1] - cyv[r]
277 let dz: i64 = vw[v*3 + 2] - czv[r]
278 let d2: i64 = dx*dx + dy*dy + dz*dz
279 if bestd[r] < 0 { bestd[r] = d2; bestv[r] = v }
280 if d2 < bestd[r] { bestd[r] = d2; bestv[r] = v }
281 v = v + 1
282 }
283 var tkeep: i64 = 0
284 var t: i64 = 0
285 while t < nt {
286 let a: i64 = vrep[tw[t*3]]
287 let bb: i64 = vrep[tw[t*3 + 1]]
288 let c: i64 = vrep[tw[t*3 + 2]]
289 if a != bb { if bb != c { if a != c { tkeep = tkeep + 1 } } }
290 t = t + 1
291 }
292 if tkeep < 1 { tr_err("NXA-TIER-REFUSE every triangle collapsed at this budget\n" as *u8); return TR_EXIT_REFUSE }
293 // ---- output layout: walk the input TOC in order; remap VERT TRIS SKIN TEXC, copy the copyable, drop the rest ----
294 let ns: i64 = w[2]
295 var nsec: i64 = 0
296 var dropped: i64 = 0
297 var copied: i64 = 0
298 var remapped: i64 = 0
299 var total: i64 = 0
300 var s0: i64 = 0
301 while s0 < ns {
302 let e: i64 = TR_HDR + s0 * TR_TOCE
303 let tag: i64 = tr_rd64(b, e)
304 let wl: i64 = tr_rd64(b, e + 16)
305 var handled: i64 = 0
306 if tag == nxa_tag4("VERT" as *u8) { handled = 1; nsec = nsec + 1; remapped = remapped + 1; total = total + (1 + nout*3) * 8 }
307 if tag == nxa_tag4("TRIS" as *u8) { handled = 1; nsec = nsec + 1; remapped = remapped + 1; total = total + (1 + tkeep*3) * 8 }
308 if tag == nxa_tag4("SKIN" as *u8) { handled = 1; nsec = nsec + 1; remapped = remapped + 1; total = total + (1 + nout*TR_SKIN_W) * 8 }
309 if tag == nxa_tag4("TEXC" as *u8) { handled = 1; nsec = nsec + 1; remapped = remapped + 1; total = total + (TR_TEXC_HDR + nout*xstride) * 8 }
310 if handled == 0 { if tr_copyable(tag) == 1 { handled = 1; nsec = nsec + 1; copied = copied + 1; total = total + wl * 8 } }
311 if handled == 0 {
312 dropped = dropped + 1
313 tr_out("NXA-TIER-DROPPED tag=" as *u8)
314 tr_tagout(tag)
315 tr_out(" (a per-vertex or per-triangle section this rung does not carry; a later rung remaps it)\n" as *u8)
316 }
317 s0 = s0 + 1
318 }
319 if nsec < 1 { tr_err("NXA-TIER-REFUSE nothing to emit\n" as *u8); return TR_EXIT_REFUSE }
320 let toclen: i64 = TR_HDR + nsec * TR_TOCE
321 total = total + toclen
322 let nb: *u8 = sys_mmap(total + TR_PAD)
323 if (nb as i64) == 0 { tr_err("NXA-TIER-REFUSE cannot allocate output\n" as *u8); return TR_EXIT_REFUSE }
324 tr_wr64(nb, 0, nxa_magic())
325 tr_wr64(nb, 8, NXA_VER)
326 tr_wr64(nb, 16, nsec)
327 var wo: i64 = toclen
328 var ti: i64 = 0
329 var s1: i64 = 0
330 while s1 < ns {
331 let e: i64 = TR_HDR + s1 * TR_TOCE
332 let tag: i64 = tr_rd64(b, e)
333 let oldoff: i64 = tr_rd64(b, e + 8)
334 let wl: i64 = tr_rd64(b, e + 16)
335 var emit: i64 = 0
336 var nw: i64 = 0
337 let te: i64 = TR_HDR + ti * TR_TOCE
338 if tag == nxa_tag4("VERT" as *u8) {
339 emit = 1
340 nw = 1 + nout * 3
341 tr_wr64(nb, wo, nout)
342 var r: i64 = 0
343 while r < nout {
344 tr_wr64(nb, wo + (1 + r*3)*8, cxv[r])
345 tr_wr64(nb, wo + (2 + r*3)*8, cyv[r])
346 tr_wr64(nb, wo + (3 + r*3)*8, czv[r])
347 r = r + 1
348 }
349 }
350 if tag == nxa_tag4("TRIS" as *u8) {
351 emit = 1
352 nw = 1 + tkeep * 3
353 tr_wr64(nb, wo, tkeep)
354 var k: i64 = 0
355 var t2: i64 = 0
356 while t2 < nt {
357 let a: i64 = vrep[tw[t2*3]]
358 let bb: i64 = vrep[tw[t2*3 + 1]]
359 let c: i64 = vrep[tw[t2*3 + 2]]
360 if a != bb { if bb != c { if a != c {
361 tr_wr64(nb, wo + (1 + k*3)*8, a)
362 tr_wr64(nb, wo + (2 + k*3)*8, bb)
363 tr_wr64(nb, wo + (3 + k*3)*8, c)
364 k = k + 1
365 } } }
366 t2 = t2 + 1
367 }
368 }
369 if tag == nxa_tag4("SKIN" as *u8) {
370 emit = 1
371 nw = 1 + nout * TR_SKIN_W
372 tr_wr64(nb, wo, nout)
373 var r: i64 = 0
374 while r < nout {
375 let src: i64 = bestv[r]
376 var f: i64 = 0
377 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 }
378 r = r + 1
379 }
380 }
381 if tag == nxa_tag4("TEXC" as *u8) {
382 emit = 1
383 nw = TR_TEXC_HDR + nout * xstride
384 tr_wr64(nb, wo, nout)
385 tr_wr64(nb, wo + 8, xstride)
386 tr_wr64(nb, wo + 16, w[xwo + 2])
387 tr_wr64(nb, wo + 24, w[xwo + 3])
388 var r: i64 = 0
389 while r < nout {
390 let src: i64 = bestv[r]
391 var f: i64 = 0
392 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 }
393 r = r + 1
394 }
395 }
396 if emit == 0 { if tr_copyable(tag) == 1 {
397 emit = 1
398 nw = wl
399 var k2: i64 = 0
400 while k2 < wl * 8 { nb[wo + k2] = b[oldoff + k2]; k2 = k2 + 1 }
401 } }
402 if emit == 1 {
403 tr_wr64(nb, te, tag)
404 tr_wr64(nb, te + 8, wo)
405 tr_wr64(nb, te + 16, nw)
406 let pw: *i64 = ((nb as i64) + wo) as *i64
407 tr_wr64(nb, te + 24, nxa_check2(1, pw, nw))
408 wo = wo + nw * 8
409 ti = ti + 1
410 }
411 s1 = s1 + 1
412 }
413 let tb: *i64 = ((nb as i64) + TR_HDR) as *i64
414 tr_wr64(nb, 24, nxa_check2(1, tb, nsec * TR_TOC_W))
415 let fd: i64 = sys_openat_wr(outp, TR_MODE)
416 if fd < 0 { tr_err("NXA-TIER-REFUSE cannot open output\n" as *u8); return TR_EXIT_REFUSE }
417 sys_write(fd, nb, wo)
418 sys_close(fd)
419 tr_out("NXA-TIER-OK in_verts=" as *u8); tr_num(nv)
420 tr_out(" out_verts=" as *u8); tr_num(nout)
421 tr_out(" in_tris=" as *u8); tr_num(nt)
422 tr_out(" out_tris=" as *u8); tr_num(tkeep)
423 tr_out(" collapsed_tris=" as *u8); tr_num(nt - tkeep)
424 tr_out(" budget=" as *u8); tr_num(target)
425 tr_out(" cell_umm=" as *u8); tr_num(cell)
426 tr_out(" search_probes=" as *u8); tr_num(probes)
427 tr_out(" sections_in=" as *u8); tr_num(ns)
428 tr_out(" remapped=" as *u8); tr_num(remapped)
429 tr_out(" copied=" as *u8); tr_num(copied)
430 tr_out(" dropped=" as *u8); tr_num(dropped)
431 tr_out(" sum=" as *u8); tr_num(remapped + copied + dropped)
432 tr_out(" bytes=" as *u8); tr_num(wo)
433 tr_out("\n" as *u8)
434 return 0
435}
436
437// ---- the ladder verb: one output per conf tier under the source, the partition printed ----
438func tr_ladder(inp: *u8, prefix: *u8, conf: *u8) -> i64 {
439 let lp: *i64 = sys_mmap(64) as *i64
440 let cb: *u8 = sys_read_file(conf, lp)
441 if (cb as i64) == 0 { tr_err("NXA-TIER-REFUSE cannot read the ladder conf\n" as *u8); return TR_EXIT_REFUSE }
442 let cn: i64 = lp[0]
443 let lp2: *i64 = sys_mmap(64) as *i64
444 let b: *u8 = sys_read_file(inp, lp2)
445 if (b as i64) == 0 { tr_err("NXA-TIER-REFUSE cannot read input\n" as *u8); return TR_EXIT_REFUSE }
446 let flen: i64 = lp2[0]
447 let vwo: i64 = nxa_find(b, flen, nxa_tag4("VERT" as *u8))
448 if vwo < 0 { tr_err("NXA-TIER-REFUSE no valid VERT section\n" as *u8); return TR_EXIT_NOSEC }
449 let w: *i64 = b as *i64
450 let nv: i64 = w[vwo]
451 var emitted: i64 = 0
452 var skipped: i64 = 0
453 var failed: i64 = 0
454 var rows: i64 = 0
455 let idb: *u8 = sys_mmap(TR_PATH_CAP)
456 let outb: *u8 = sys_mmap(TR_PATH_CAP)
457 var p: i64 = 0
458 while p < cn {
459 var le: i64 = p
460 while le < cn { if cb[le] == (TR_ASCII_NL as u8) { break } le = le + 1 }
461 if le > p { if cb[p] != (TR_ASCII_HASH as u8) {
462 var f0: i64 = p
463 var fi: i64 = 0
464 var idlen: i64 = 0
465 var maxv: i64 = 0
466 var istier: i64 = 0
467 var q: i64 = p
468 while q <= le {
469 var atend: i64 = 0
470 if q == le { atend = 1 } else { if cb[q] == (TR_ASCII_PIPE as u8) { atend = 1 } }
471 if atend == 1 {
472 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 } } } } } }
473 if fi == 1 {
474 idlen = q - f0
475 var c2: i64 = 0
476 while c2 < idlen { if c2 < TR_PATH_CAP - 1 { idb[c2] = cb[f0 + c2] } c2 = c2 + 1 }
477 if idlen > TR_PATH_CAP - 1 { idlen = TR_PATH_CAP - 1 }
478 idb[idlen] = 0 as u8
479 }
480 if fi == 2 {
481 var vv: i64 = 0
482 var c3: i64 = f0
483 while c3 < q {
484 let ch: i64 = cb[c3] as i64
485 if ch >= TR_ASCII_ZERO { if ch <= TR_ASCII_NINE { vv = vv * 10 + (ch - TR_ASCII_ZERO) } }
486 c3 = c3 + 1
487 }
488 maxv = vv
489 }
490 fi = fi + 1
491 f0 = q + 1
492 }
493 q = q + 1
494 }
495 if istier == 1 { if fi >= TR_LADDER_F {
496 rows = rows + 1
497 if maxv >= nv {
498 skipped = skipped + 1
499 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)
500 } else {
501 var o: i64 = 0
502 var c4: i64 = 0
503 while prefix[c4] != (0 as u8) { if o < TR_PATH_CAP - 8 { outb[o] = prefix[c4]; o = o + 1 } c4 = c4 + 1 }
504 outb[o] = TR_ASCII_US as u8
505 o = o + 1
506 c4 = 0
507 while idb[c4] != (0 as u8) { if o < TR_PATH_CAP - 8 { outb[o] = idb[c4]; o = o + 1 } c4 = c4 + 1 }
508 outb[o] = TR_ASCII_DOT as u8
509 outb[o+1] = TR_ASCII_N as u8
510 outb[o+2] = TR_ASCII_X as u8
511 outb[o+3] = TR_ASCII_A as u8
512 outb[o+4] = 0 as u8
513 tr_out("NXA-TIER-LADDER tier=" as *u8); tr_out(idb); tr_out(" out=" as *u8); tr_out(outb); tr_out("\n" as *u8)
514 let rc: i64 = tr_tier(inp, outb, maxv)
515 if rc == 0 { emitted = emitted + 1 } else { failed = failed + 1 }
516 }
517 } }
518 } }
519 p = le + 1
520 }
521 tr_out("NXA-TIER-LADDER-DONE tiers=" as *u8); tr_num(rows)
522 tr_out(" emitted=" as *u8); tr_num(emitted)
523 tr_out(" skipped=" as *u8); tr_num(skipped)
524 tr_out(" failed=" as *u8); tr_num(failed)
525 tr_out(" sum=" as *u8); tr_num(emitted + skipped + failed)
526 tr_out(" source_verts=" as *u8); tr_num(nv)
527 tr_out("\n" as *u8)
528 if rows < 1 { tr_err("NXA-TIER-REFUSE the ladder conf declares no tier rows\n" as *u8); return TR_EXIT_REFUSE }
529 if failed > 0 { return TR_EXIT_REFUSE }
530 return 0
531}
532
533func tr_is_ladder(a: *u8) -> i64 {
534 if a[0] != (TR_ASCII_L as u8) { return 0 }
535 if a[1] != (TR_ASCII_A as u8) { return 0 }
536 if a[2] != (TR_ASCII_D as u8) { return 0 }
537 if a[3] != (TR_ASCII_D as u8) { return 0 }
538 if a[4] != (TR_ASCII_E as u8) { return 0 }
539 if a[5] != (TR_ASCII_R as u8) { return 0 }
540 if a[6] != (0 as u8) { return 0 }
541 return 1
542}
543
544func main(argc: i64, argv: *i64) -> i64 {
545 if argc < 4 {
546 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)
547 return TR_EXIT_USAGE
548 }
549 let a1: *u8 = argv[1] as *u8
550 if tr_is_ladder(a1) == 1 {
551 var conf: *u8 = TR_LADDER_DEFAULT
552 if argc >= 5 { conf = argv[4] as *u8 }
553 return tr_ladder(argv[2] as *u8, argv[3] as *u8, conf)
554 }
555 let target: i64 = tr_atoi(argv[3] as *u8)
556 return tr_tier(a1, argv[2] as *u8, target)
557}