nx_meshgap.nx source
↩ module page · 193 lines · 8068 B
1// nx_meshgap.nx -- SPATIAL COHERENCE OF A MESH: does the figure hold together, or have parts
2// flown off into empty space?
3//
4// WHY THIS EXISTS (measured 2026-08-23, by eye on a live page). The models page card FEMALE DARK
5// KNIGHT renders as FRAGMENTED GEOMETRY -- the hair/helmet floats detached far above the body and
6// stray blobs hang below it -- while EVERY NUMBER ON ITS CARD IS GREEN: 33 geometry nodes merged,
7// rig 113 joints, 3729 clusters = 33 x 113, albedo carried, 6-chart atlas. The arithmetic closes
8// perfectly and the picture is broken. That is the third time in one day the eye beat the teeth
9// (a donor rendering lying flat; a 30-pixel dark blob at the horizon; now this), and the reason is
10// always the same: every existing tooth measured a COUNT or a SUM, and no tooth measured whether
11// the thing HOLDS TOGETHER IN SPACE.
12//
13// WHY MESH SPACE AND NOT PIXELS. The obvious instrument is connected-component analysis on the
14// render. It cannot be built cheaply here -- the estate has PNG WRITERS but no decoder with an
15// unfilter stage -- and it would be the weaker measurement anyway: a pixel silhouette depends on
16// the camera, the renderer tier and the auto-framing, so a coherent mesh photographed badly and a
17// fragmented mesh photographed well are indistinguishable. The mesh is the SUBJECT; the render is
18// a projection of it. Measuring the subject is exact, load-independent, camera-independent, and
19// catches the defect AT INGEST rather than after it reaches a page.
20//
21// THE MEASURE IS PARAMETER-FREE, WHICH IS THE WHOLE POINT ON A DAY WHEN AN ESTATE CENSUS MEASURED
22// ONLY 2.56 PERCENT OF CAPACITY BOUNDS AS DERIVED. A coherent figure is spatially CONTIGUOUS: walk
23// along any axis and you never cross a large empty void before reaching the far side. A fragmented
24// figure has a VOID between the body and whatever flew off. So the measurement is the LARGEST
25// INTERIOR EMPTY GAP along each axis, expressed in permil of that axis's own span -- a ratio of the
26// mesh to itself, with no constant to pick and no units to get wrong.
27//
28// The bin width is DERIVED FROM THE DATA, not chosen: one bin per vertex (binwidth = span/nv, at
29// least 1 unit), so resolution follows the mesh's own density. A void spanning thousands of bins
30// cannot be confused with the one- or two-bin holes that ordinary sampling produces.
31//
32// ALL THREE AXES ARE REPORTED AND THE VERDICT TAKES THE WORST. Deliberately NOT stature-only: this
33// organ must not inherit the axis-identification problem that has bitten three lanes today, and a
34// part can fly off along any axis. Largest-extent-is-stature is ALSO wrong for these donors -- a
35// T-posed rig's arm span can exceed its height -- so no axis is privileged here at all.
36//
37// THE BOUND IS NOT BAKED IN. With no second argument this organ MEASURES ONLY and exits 0. The
38// caller supplies the bound, so it can be derived from a measured population (coherent donors vs
39// fragmented ones) and live in a conf with its derivation beside it, rather than being frozen into
40// a binary where nobody can see it.
41//
42// usage: nx_meshgap <asset.nxa> [max_gap_permil]
43// exit: 0 COHERENT or measure-only . 1 FRAGMENTED . 2 usage . 3 unreadable
44
45import "nx_syscalls.nx"
46import "nx_nxa.nx"
47
48const MG_EXIT_FRAG: i64 = 1
49const MG_EXIT_USAGE: i64 = 2
50const MG_EXIT_UNREADABLE: i64 = 3
51const MG_PERMIL: i64 = 1000
52const MG_AXES: i64 = 3
53const MG_WV: i64 = 3 // words per vertex in a VERT section (x,y,z), per the NXA v1 spec
54
55func mgw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
56func mgerr(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(2, s, n); return 0 }
57
58func mgn(v: i64) -> i64 {
59 let b: *u8 = sys_mmap(64) as *u8
60 var x: i64 = v
61 var neg: i64 = 0
62 if x < 0 { neg = 1; x = 0 - x }
63 var i: i64 = 40
64 b[i] = 0 as u8
65 if x == 0 { i = i - 1; b[i] = 48 as u8 }
66 while x > 0 {
67 i = i - 1
68 b[i] = ((x % 10) + 48) as u8
69 x = x / 10
70 }
71 if neg == 1 { i = i - 1; b[i] = 45 as u8 }
72 var n: i64 = 0
73 while b[i+n] != (0 as u8) { n = n + 1 }
74 sys_write(1, ((b as i64) + i) as *u8, n)
75 return 0
76}
77
78func mg_atoi(s: *u8) -> i64 {
79 var v: i64 = 0
80 var i: i64 = 0
81 while s[i] != (0 as u8) {
82 let c: i64 = s[i] as i64
83 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } }
84 i = i + 1
85 }
86 return v
87}
88
89// Largest INTERIOR empty gap along one axis, in permil of that axis's span.
90// Interior only: leading and trailing empty bins are not gaps, they are the ends of the object.
91func mg_axis_gap(vb: *i64, nv: i64, k: i64, out: *i64) -> i64 {
92 var mn: i64 = vb[k]
93 var mx: i64 = mn
94 var i: i64 = 1
95 while i < nv {
96 let v: i64 = vb[i*MG_WV+k]
97 if v < mn { mn = v }
98 if v > mx { mx = v }
99 i = i + 1
100 }
101 let span: i64 = mx - mn
102 out[0] = span
103 out[1] = 0
104 out[2] = 0
105 if span < 1 { return 0 }
106 // one bin per vertex: resolution follows the mesh's own density, nothing is picked
107 var bw: i64 = span / nv
108 if bw < 1 { bw = 1 }
109 let nb: i64 = span / bw + 1
110 let bins: *u8 = sys_mmap(nb) as *u8
111 i = 0
112 while i < nv {
113 var idx: i64 = (vb[i*MG_WV+k] - mn) / bw
114 if idx < 0 { idx = 0 }
115 if idx >= nb { idx = nb - 1 }
116 bins[idx] = 1 as u8
117 i = i + 1
118 }
119 var occ: i64 = 0
120 var run: i64 = 0
121 var best: i64 = 0
122 var seen: i64 = 0
123 i = 0
124 while i < nb {
125 if bins[i] == (1 as u8) {
126 occ = occ + 1
127 seen = 1
128 if run > best { best = run }
129 run = 0
130 }
131 if bins[i] == (0 as u8) { if seen == 1 { run = run + 1 } }
132 i = i + 1
133 }
134 // a trailing run is beyond the last vertex -- an end, not a gap -- so it is deliberately dropped
135 out[1] = best * bw
136 out[2] = occ
137 return best * bw * MG_PERMIL / span
138}
139
140func main(argc: i64, argv: *i64) -> i64 {
141 if argc < 2 {
142 mgerr("usage: nx_meshgap <asset.nxa> [max_gap_permil]\n" as *u8)
143 return MG_EXIT_USAGE
144 }
145 let path: *u8 = argv[1] as *u8
146 var bound: i64 = 0 - 1
147 if argc >= 3 { bound = mg_atoi(argv[2] as *u8) }
148
149 let lp: *i64 = sys_mmap(64)
150 let b: *u8 = sys_read_file(path, lp)
151 if b as i64 == 0 { mgerr("MESHGAP-REFUSE cannot read asset\n" as *u8); return MG_EXIT_UNREADABLE }
152 let flen: i64 = lp[0]
153 let w: *i64 = b as *i64
154 let vwo: i64 = nxa_find(b, flen, nxa_tag4("VERT" as *u8))
155 if vwo < 0 { mgerr("MESHGAP-REFUSE no VERT section\n" as *u8); return MG_EXIT_UNREADABLE }
156 let nv: i64 = w[vwo]
157 if nv < 2 { mgerr("MESHGAP-REFUSE VERT holds fewer than two vertices\n" as *u8); return MG_EXIT_UNREADABLE }
158 let vb: *i64 = ((w as i64) + (vwo + 1) * 8) as *i64
159
160 mgw("NX-MESHGAP " as *u8); mgw(path); mgw("\n" as *u8)
161 mgw(" verts=" as *u8); mgn(nv); mgw("\n" as *u8)
162
163 let out: *i64 = sys_mmap(64)
164 var worst: i64 = 0
165 var worst_ax: i64 = 0
166 var k: i64 = 0
167 while k < MG_AXES {
168 let g: i64 = mg_axis_gap(vb, nv, k, out)
169 mgw(" axis=" as *u8); mgn(k)
170 mgw(" span=" as *u8); mgn(out[0])
171 mgw(" occupied_bins=" as *u8); mgn(out[2])
172 mgw(" largest_interior_gap=" as *u8); mgn(out[1])
173 mgw(" gap_permil=" as *u8); mgn(g)
174 mgw("\n" as *u8)
175 if g > worst { worst = g; worst_ax = k }
176 k = k + 1
177 }
178 mgw(" max_gap_permil=" as *u8); mgn(worst)
179 mgw(" on_axis=" as *u8); mgn(worst_ax)
180 mgw("\n" as *u8)
181
182 if bound < 0 {
183 mgw("NX-MESHGAP verdict=MEASURED (no bound supplied -- the caller owns the bound so it can be derived from a population and kept where it is visible)\n" as *u8)
184 return 0
185 }
186 mgw(" bound_max_gap_permil=" as *u8); mgn(bound); mgw("\n" as *u8)
187 if worst > bound {
188 mgw("NX-MESHGAP verdict=FRAGMENTED (a part of this mesh sits across an empty void from the rest)\n" as *u8)
189 return MG_EXIT_FRAG
190 }
191 mgw("NX-MESHGAP verdict=COHERENT\n" as *u8)
192 return 0
193}