nx_boneheat_gate.nx source
↩ module page · 329 lines · 17639 B
1// nx_boneheat_gate.nx -- THE REFEREE FOR THE SOVEREIGN AUTO-WEIGHTS: a geodesic solve must BLEND at a joint, must NOT
2// bleed across air, must announce an unsealed mesh instead of refusing it, must refuse a mesh with no skeleton BY
3// NAME, and must be byte-deterministic -- while the nearest-joint control (modding MD4's own accept-rule control)
4// is shown to do exactly what the geodesic solve exists to stop.
5// Fixtures are BUILT AT RUN TIME under /tmp/nx_boneheat_gate (a detector that scans source must never meet its own
6// fixture) and are AXIS-ALIGNED SQUARE PRISMS on purpose: their four walls and two caps lie on coordinate planes,
7// so the voxeliser seals them without depending on the tilted-face dilation (that dilation stays in the lib for
8// real meshes; the fixture must isolate the WEIGHT solve, not the seam heuristic). A closed prism with a
9// three-joint chain; the same prism open at both ends; two prisms separated by 12 mm of air where one shell's
10// joint is Euclidean-nearer to the other shell's vertices than that shell's own joint. Every solve is IN-PROCESS
11// through nx_boneheat_lib, so a mutant of the lib is reached.
12// license_tier: ORIGINAL expect_exit: 0
13import "nx_syscalls.nx"
14import "nx_gate_verdict.nx"
15import "nx_nxa.nx"
16import "nx_boneheat_lib.nx"
17
18const BHG_DIR: *u8 = "/tmp/nx_boneheat_gate"
19const BHG_MODE_DIR: i64 = 493 // 0755
20const BHG_AROUND: i64 = 4 // square cross-section: 4 axis-aligned corners -> 4 axis-aligned faces
21const BHG_R: i64 = 400 // 4 mm half-width in 0.01 mm units
22const BHG_LEN: i64 = 4000 // 40 mm prism
23const BHG_RINGS: i64 = 41 // one ring per mm
24const BHG_MID: i64 = 2000
25const BHG_SHELL_LEN: i64 = 2000
26const BHG_SHELL_RINGS: i64 = 21
27const BHG_SHELL_DX: i64 = 2000 // second shell centre: 12 mm of air between the surfaces
28const BHG_CELLS: i64 = 64 // fixture grid, passed explicitly so the gate never depends on the conf file
29const BHG_VERT_CAP: i64 = 1024
30const BHG_TRI_CAP: i64 = 4096
31const BHG_JOINT_CAP: i64 = 8
32const BHG_RING_ROOT: i64 = 5 // z = 5 mm
33const BHG_RING_MID: i64 = 20 // z = 20 mm, the middle joint
34const BHG_RING_FAR: i64 = 35 // z = 35 mm
35const BHG_ROOT: i64 = 0 - 1
36
37func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
38// the four axis-aligned corners of the square cross-section, going around
39func bhg_ring_xy(k: i64, out: *i64) -> i64 {
40 if k == 0 { out[0] = BHG_R; out[1] = 0 - BHG_R }
41 if k == 1 { out[0] = BHG_R; out[1] = BHG_R }
42 if k == 2 { out[0] = 0 - BHG_R; out[1] = BHG_R }
43 if k == 3 { out[0] = 0 - BHG_R; out[1] = 0 - BHG_R }
44 return 0
45}
46func bhg_tri(tris: *i64, st: *i64, a: i64, b: i64, c: i64) -> i64 {
47 let t: i64 = st[1]
48 tris[1 + t * 3] = a; tris[1 + t * 3 + 1] = b; tris[1 + t * 3 + 2] = c
49 st[1] = t + 1
50 return 0
51}
52// append an axis-aligned square prism along z (centre cx) to the vert/tris arrays; st[0]=nv st[1]=nt advance
53func bhg_prism(vert: *i64, tris: *i64, st: *i64, cx: i64, z0: i64, z1: i64, rings: i64, caps: i64) -> i64 {
54 let v0: i64 = st[0]
55 let xy: *i64 = sys_mmap(16) as *i64
56 var r: i64 = 0
57 while r < rings {
58 var k: i64 = 0
59 while k < BHG_AROUND {
60 bhg_ring_xy(k, xy)
61 let idx: i64 = v0 + r * BHG_AROUND + k
62 vert[1 + idx * 3] = cx + xy[0]
63 vert[1 + idx * 3 + 1] = xy[1]
64 vert[1 + idx * 3 + 2] = z0 + (z1 - z0) * r / (rings - 1)
65 k = k + 1
66 }
67 r = r + 1
68 }
69 st[0] = v0 + rings * BHG_AROUND
70 r = 0
71 while r < rings - 1 {
72 var k: i64 = 0
73 while k < BHG_AROUND {
74 let a: i64 = v0 + r * BHG_AROUND + k
75 let b: i64 = v0 + r * BHG_AROUND + (k + 1) % BHG_AROUND
76 let c: i64 = v0 + (r + 1) * BHG_AROUND + (k + 1) % BHG_AROUND
77 let d: i64 = v0 + (r + 1) * BHG_AROUND + k
78 bhg_tri(tris, st, a, b, c)
79 bhg_tri(tris, st, a, c, d)
80 k = k + 1
81 }
82 r = r + 1
83 }
84 if caps == 1 {
85 let cb: i64 = st[0]
86 vert[1 + cb * 3] = cx; vert[1 + cb * 3 + 1] = 0; vert[1 + cb * 3 + 2] = z0
87 let ct: i64 = st[0] + 1
88 vert[1 + ct * 3] = cx; vert[1 + ct * 3 + 1] = 0; vert[1 + ct * 3 + 2] = z1
89 st[0] = st[0] + 2
90 var k: i64 = 0
91 while k < BHG_AROUND {
92 bhg_tri(tris, st, cb, v0 + (k + 1) % BHG_AROUND, v0 + k)
93 let top: i64 = v0 + (rings - 1) * BHG_AROUND
94 bhg_tri(tris, st, ct, top + k, top + (k + 1) % BHG_AROUND)
95 k = k + 1
96 }
97 }
98 return st[0] - v0
99}
100func bhg_joint(skel: *i64, j: i64, parent: i64, x: i64, y: i64, z: i64) -> i64 {
101 let o: i64 = 1 + j * BH_JOINT_WORDS
102 skel[o] = parent; skel[o + 1] = x; skel[o + 2] = y; skel[o + 3] = z
103 skel[o + 4] = 0; skel[o + 5] = 0; skel[o + 6] = 0; skel[o + 7] = BH_Q12
104 return 0
105}
106func bhg_write(path: *u8, vert: *i64, tris: *i64, st: *i64, skel: *i64, nj: i64) -> i64 {
107 vert[0] = st[0]; tris[0] = st[1]; skel[0] = nj
108 let tags: *i64 = sys_mmap(64) as *i64
109 let ptrs: *i64 = sys_mmap(64) as *i64
110 let wls: *i64 = sys_mmap(64) as *i64
111 tags[0] = nxa_tag4("VERT" as *u8); ptrs[0] = vert as i64; wls[0] = 1 + st[0] * 3
112 tags[1] = nxa_tag4("TRIS" as *u8); ptrs[1] = tris as i64; wls[1] = 1 + st[1] * 3
113 var ns: i64 = 2
114 if nj > 0 { tags[2] = nxa_tag4("SKEL" as *u8); ptrs[2] = skel as i64; wls[2] = 1 + nj * BH_JOINT_WORDS; ns = 3 }
115 return bh_nxa_write(path, ns, tags, ptrs, wls)
116}
117func bhg_open(path: *u8, lp: *i64) -> i64 {
118 let b: *u8 = sys_read_file(path, lp)
119 if (b as i64) == 0 { return 0 }
120 return b as i64
121}
122func bhg_w(b: *u8, flen: i64, v: i64, j: i64) -> i64 {
123 let kwo: i64 = nxa_find(b, flen, nxa_tag4("SKIN" as *u8))
124 if kwo < 0 { return 0 - 1 }
125 let w: *i64 = b as *i64
126 let row: i64 = kwo + 1 + v * BH_SKIN_WORDS
127 var s: i64 = 0
128 var k: i64 = 0
129 while k < BH_INF_SLOTS { if w[row + k] == j { s = s + w[row + BH_INF_SLOTS + k] } k = k + 1 }
130 return s
131}
132func bhg_wsum(b: *u8, flen: i64, v: i64) -> i64 {
133 let kwo: i64 = nxa_find(b, flen, nxa_tag4("SKIN" as *u8))
134 if kwo < 0 { return 0 - 1 }
135 let w: *i64 = b as *i64
136 let row: i64 = kwo + 1 + v * BH_SKIN_WORDS
137 var s: i64 = 0
138 var k: i64 = 0
139 while k < BH_INF_SLOTS { s = s + w[row + BH_INF_SLOTS + k]; k = k + 1 }
140 return s
141}
142func bhg_wmax(b: *u8, flen: i64, v: i64) -> i64 {
143 let kwo: i64 = nxa_find(b, flen, nxa_tag4("SKIN" as *u8))
144 if kwo < 0 { return 0 - 1 }
145 let w: *i64 = b as *i64
146 let row: i64 = kwo + 1 + v * BH_SKIN_WORDS
147 var m: i64 = 0
148 var k: i64 = 0
149 while k < BH_INF_SLOTS { if w[row + BH_INF_SLOTS + k] > m { m = w[row + BH_INF_SLOTS + k] } k = k + 1 }
150 return m
151}
152func bhg_files_equal(pa: *u8, pb: *u8) -> i64 {
153 let la: *i64 = sys_mmap(16) as *i64
154 let lb: *i64 = sys_mmap(16) as *i64
155 let a: *u8 = sys_read_file(pa, la)
156 let b: *u8 = sys_read_file(pb, lb)
157 if (a as i64) == 0 { return 0 }
158 if (b as i64) == 0 { return 0 }
159 if la[0] != lb[0] { return 0 }
160 var i: i64 = 0
161 while i < la[0] { if a[i] != b[i] { return 0 } i = i + 1 }
162 return 1
163}
164
165func main() -> i64 {
166 let ctr: *i64 = gv_ctr()
167 gv_head("nx_boneheat_gate -- the geodesic auto-weights are asked to blend at a joint, to refuse to cross air, to announce an open mesh and to refuse a missing skeleton by name" as *u8)
168 sys_mkdir(BHG_DIR, BHG_MODE_DIR)
169 let vert: *i64 = sys_mmap((1 + BHG_VERT_CAP * 3) * 8) as *i64
170 let tris: *i64 = sys_mmap((1 + BHG_TRI_CAP * 3) * 8) as *i64
171 let skel: *i64 = sys_mmap((1 + BHG_JOINT_CAP * BH_JOINT_WORDS) * 8) as *i64
172 let st: *i64 = sys_mmap(16) as *i64
173 let rep: *i64 = sys_mmap(BR_WORDS * 8) as *i64
174 let lp: *i64 = sys_mmap(16) as *i64
175
176 // ---- fixture A: one closed prism, three joints along its axis ----
177 st[0] = 0; st[1] = 0
178 bhg_prism(vert, tris, st, 0, 0, BHG_LEN, BHG_RINGS, 1)
179 bhg_joint(skel, 0, BHG_ROOT, 0, 0, 0)
180 bhg_joint(skel, 1, 0, 0, 0, BHG_MID)
181 bhg_joint(skel, 2, 1, 0, 0, BHG_LEN)
182 let pa: *u8 = "/tmp/nx_boneheat_gate/prism.nxa"
183 let pao: *u8 = "/tmp/nx_boneheat_gate/prism_geo.nxa"
184 let pao2: *u8 = "/tmp/nx_boneheat_gate/prism_geo2.nxa"
185 let pan: *u8 = "/tmp/nx_boneheat_gate/prism_near.nxa"
186 let wrote: i64 = bhg_write(pa, vert, tris, st, skel, 3)
187 let nvA: i64 = st[0]
188 gv_check("T1 fixture-reached-the-condition: the closed prism was written as an NXA with VERT TRIS and SKEL (166 vertices, 328 triangles, 3 joints)" as *u8, ((wrote > 0) as i64) * ((nvA == BHG_RINGS * BHG_AROUND + 2) as i64) * ((st[1] == (BHG_RINGS - 1) * BHG_AROUND * 2 + BHG_AROUND * 2) as i64), ctr)
189 var k: i64 = 0
190 while k < BR_WORDS { rep[k] = 0; k = k + 1 }
191 let rcA: i64 = bh_run(pa, pao, BH_MODE_GEODESIC, BHG_CELLS, rep)
192 bh_report(BH_MODE_GEODESIC, rep, pa, pao)
193 let sealedA: i64 = rep[BR_SEALED]
194 let cellsA: i64 = rep[BR_CELLS]
195 let surfA: i64 = rep[BR_SURF]
196 let extA: i64 = rep[BR_EXT]
197 let intA: i64 = rep[BR_INT]
198 let gnx: i64 = rep[BR_NX]
199 let gny: i64 = rep[BR_NY]
200 let gnz: i64 = rep[BR_NZ]
201 let gcell: i64 = rep[BR_CELL]
202 gv_check("T2 the geodesic solve on a sealed prism exits 0 and writes a SKIN section for every vertex" as *u8, ((rcA == BH_EXIT_OK) as i64) * ((rep[BR_BYTES] > wrote) as i64), ctr)
203 gv_check("T3 the voxel partition SUMS: exterior + surface + interior == cells, printed not assumed" as *u8, ((extA + surfA + intA == cellsA) as i64) * ((cellsA > 0) as i64), ctr)
204 gv_check("T4 a closed prism is SEALED: the exterior flood was stopped by the surface shell and interior cells exist" as *u8, ((sealedA == 1) as i64) * ((intA > 0) as i64), ctr)
205 let bA: i64 = bhg_open(pao, lp)
206 let fA: i64 = lp[0]
207 var bad_sum: i64 = 0
208 var v: i64 = 0
209 while v < nvA { if bhg_wsum(bA as *u8, fA, v) != BH_Q12 { bad_sum = bad_sum + 1 } v = v + 1 }
210 gv_check("T5 every vertex's four weights sum to EXACTLY 4096 (the NXA spec, residual folded into the largest) -- bound to the vertex count" as *u8, ((bad_sum == 0) as i64) * ((nvA > 0) as i64), ctr)
211 var mixed_mid: i64 = 0
212 var root_wins: i64 = 0
213 var far_wins: i64 = 0
214 k = 0
215 while k < BHG_AROUND {
216 let vm: i64 = BHG_RING_MID * BHG_AROUND + k
217 if bhg_w(bA as *u8, fA, vm, 0) > 0 { if bhg_w(bA as *u8, fA, vm, 1) > 0 { mixed_mid = mixed_mid + 1 } }
218 let vr: i64 = BHG_RING_ROOT * BHG_AROUND + k
219 if bhg_w(bA as *u8, fA, vr, 0) > bhg_w(bA as *u8, fA, vr, 1) { root_wins = root_wins + 1 }
220 let vf: i64 = BHG_RING_FAR * BHG_AROUND + k
221 if bhg_w(bA as *u8, fA, vf, 1) + bhg_w(bA as *u8, fA, vf, 2) > bhg_w(bA as *u8, fA, vf, 0) { far_wins = far_wins + 1 }
222 k = k + 1
223 }
224 gv_check("T6 anti-vacuity BLEND: all 4 corner vertices on the ring AT the middle joint carry weight from BOTH joint 0 and joint 1 -- a hard nearest boundary cannot produce this" as *u8, (mixed_mid == BHG_AROUND) as i64, ctr)
225 gv_check("T7 the falloff is monotone toward the root: all 4 corner vertices at 5 mm weigh joint 0 above joint 1" as *u8, (root_wins == BHG_AROUND) as i64, ctr)
226 gv_check("T8 the falloff is monotone toward the tip: all 4 corner vertices at 35 mm weigh joints 1 plus 2 above joint 0" as *u8, (far_wins == BHG_AROUND) as i64, ctr)
227 k = 0
228 while k < BR_WORDS { rep[k] = 0; k = k + 1 }
229 let rcN: i64 = bh_run(pa, pan, BH_MODE_NEAREST, BHG_CELLS, rep)
230 bh_report(BH_MODE_NEAREST, rep, pa, pan)
231 let bN: i64 = bhg_open(pan, lp)
232 let fN: i64 = lp[0]
233 var hard_mid: i64 = 0
234 k = 0
235 while k < BHG_AROUND { if bhg_wmax(bN as *u8, fN, BHG_RING_MID * BHG_AROUND + k) == BH_Q12 { hard_mid = hard_mid + 1 } k = k + 1 }
236 let nearMixed: i64 = rep[BR_MIXED]
237 gv_check("T9 neg-control-nearest-mode-cannot-blend: the control MD4 names gives every middle-ring vertex ONE joint at 4096 and reports mixed_verts=0 -- the discriminator between the two modes is real" as *u8, ((rcN == BH_EXIT_OK) as i64) * ((hard_mid == BHG_AROUND) as i64) * ((nearMixed == 0) as i64), ctr)
238
239 // ---- fixture B: the same prism with OPEN ends -- announced as unsealed, still solved over its shell ----
240 st[0] = 0; st[1] = 0
241 bhg_prism(vert, tris, st, 0, 0, BHG_LEN, BHG_RINGS, 0)
242 let pb: *u8 = "/tmp/nx_boneheat_gate/open.nxa"
243 let pbo: *u8 = "/tmp/nx_boneheat_gate/open_geo.nxa"
244 bhg_write(pb, vert, tris, st, skel, 3)
245 let nvB: i64 = st[0]
246 k = 0
247 while k < BR_WORDS { rep[k] = 0; k = k + 1 }
248 let rcB: i64 = bh_run(pb, pbo, BH_MODE_GEODESIC, BHG_CELLS, rep)
249 bh_report(BH_MODE_GEODESIC, rep, pb, pbo)
250 let sealedB: i64 = rep[BR_SEALED]
251 let intB: i64 = rep[BR_INT]
252 gv_check("T10 the seal detector DISCRIMINATES: the open-ended prism floods through (sealed=0, interior=0) while the closed one sealed (sealed=1, interior>0) -- one measurement is not the other" as *u8, ((sealedB == 0) as i64) * ((intB == 0) as i64) * ((sealedA == 1) as i64) * ((intA > 0) as i64), ctr)
253 let bB: i64 = bhg_open(pbo, lp)
254 let fB: i64 = lp[0]
255 var bad_sum_b: i64 = 0
256 v = 0
257 while v < nvB { if bhg_wsum(bB as *u8, fB, v) != BH_Q12 { bad_sum_b = bad_sum_b + 1 } v = v + 1 }
258 gv_check("T11 an UNSEALED mesh is announced and still weighted over its shell -- exit 0, every vertex sums to 4096 -- never refused (Blender bone heat needs a manifold; ours does not)" as *u8, ((rcB == BH_EXIT_OK) as i64) * ((bad_sum_b == 0) as i64) * ((nvB > 0) as i64), ctr)
259
260 // ---- fixture C: two shells, 12 mm of air; shell B's only joint sits at its far end ----
261 st[0] = 0; st[1] = 0
262 bhg_prism(vert, tris, st, 0, 0, BHG_SHELL_LEN, BHG_SHELL_RINGS, 1)
263 let nvShellA: i64 = st[0]
264 bhg_prism(vert, tris, st, BHG_SHELL_DX, 0, BHG_SHELL_LEN, BHG_SHELL_RINGS, 1)
265 let nvC: i64 = st[0]
266 bhg_joint(skel, 0, BHG_ROOT, 0, 0, 0)
267 bhg_joint(skel, 1, 0, 0, 0, BHG_SHELL_LEN)
268 bhg_joint(skel, 2, BHG_ROOT, BHG_SHELL_DX, 0, BHG_SHELL_LEN)
269 let pc: *u8 = "/tmp/nx_boneheat_gate/shells.nxa"
270 let pco: *u8 = "/tmp/nx_boneheat_gate/shells_geo.nxa"
271 let pcn: *u8 = "/tmp/nx_boneheat_gate/shells_near.nxa"
272 bhg_write(pc, vert, tris, st, skel, 3)
273 k = 0
274 while k < BR_WORDS { rep[k] = 0; k = k + 1 }
275 let rcC: i64 = bh_run(pc, pco, BH_MODE_GEODESIC, BHG_CELLS, rep)
276 bh_report(BH_MODE_GEODESIC, rep, pc, pco)
277 let unreachedC: i64 = rep[BR_UNREACH_V]
278 let bC: i64 = bhg_open(pco, lp)
279 let fC: i64 = lp[0]
280 var bleed_geo: i64 = 0
281 v = nvShellA
282 while v < nvC { if bhg_w(bC as *u8, fC, v, 0) + bhg_w(bC as *u8, fC, v, 1) > 0 { bleed_geo = bleed_geo + 1 } v = v + 1 }
283 gv_check("T12 anti-bleed EXCEED: across 12 mm of air NO vertex of shell B takes weight from shell A's joints (0 of 84), and every B vertex was reached through B's own volume (verts_unreached=0)" as *u8, ((rcC == BH_EXIT_OK) as i64) * ((bleed_geo == 0) as i64) * ((nvC - nvShellA > 0) as i64) * ((unreachedC == 0) as i64), ctr)
284 k = 0
285 while k < BR_WORDS { rep[k] = 0; k = k + 1 }
286 let rcCN: i64 = bh_run(pc, pcn, BH_MODE_NEAREST, BHG_CELLS, rep)
287 let bCN: i64 = bhg_open(pcn, lp)
288 let fCN: i64 = lp[0]
289 var bleed_near: i64 = 0
290 v = nvShellA
291 while v < nvC { if bhg_w(bCN as *u8, fCN, v, 0) + bhg_w(bCN as *u8, fCN, v, 1) > 0 { bleed_near = bleed_near + 1 } v = v + 1 }
292 gv_check("T13 neg-control-nearest-bleeds-across-air: the Euclidean control hands shell A's joints to shell B vertices (measured count above 0) -- the failure the geodesic solve exists to remove is real on this fixture" as *u8, ((rcCN == BH_EXIT_OK) as i64) * ((bleed_near > 0) as i64), ctr)
293
294 // ---- determinism and the named refusal ----
295 k = 0
296 while k < BR_WORDS { rep[k] = 0; k = k + 1 }
297 bh_run(pa, pao2, BH_MODE_GEODESIC, BHG_CELLS, rep)
298 gv_check("T14 two geodesic solves of the same asset are BYTE-IDENTICAL (integer Dial buckets, deterministic scan order)" as *u8, bhg_files_equal(pao, pao2), ctr)
299 st[0] = 0; st[1] = 0
300 bhg_prism(vert, tris, st, 0, 0, BHG_LEN, BHG_RINGS, 1)
301 let pd: *u8 = "/tmp/nx_boneheat_gate/noskel.nxa"
302 let pdo: *u8 = "/tmp/nx_boneheat_gate/noskel_geo.nxa"
303 bhg_write(pd, vert, tris, st, skel, 0)
304 k = 0
305 while k < BR_WORDS { rep[k] = 0; k = k + 1 }
306 let rcD: i64 = bh_run(pd, pdo, BH_MODE_GEODESIC, BHG_CELLS, rep)
307 gv_check("T15 neg-control-refuses-without-skeleton: an NXA carrying VERT and TRIS but no SKEL is refused BY NAME with exit 3, never weighted against nothing" as *u8, (rcD == BH_EXIT_REFUSE) as i64, ctr)
308
309 gv_values_head()
310 gv_kv("closed_cells" as *u8, cellsA)
311 gv_kv("closed_grid_nx" as *u8, gnx)
312 gv_kv("closed_grid_ny" as *u8, gny)
313 gv_kv("closed_grid_nz" as *u8, gnz)
314 gv_kv("closed_cell_units" as *u8, gcell)
315 gv_kv("closed_exterior" as *u8, extA)
316 gv_kv("closed_surface" as *u8, surfA)
317 gv_kv("closed_interior" as *u8, intA)
318 gv_kv("closed_sealed" as *u8, sealedA)
319 gv_kv("open_sealed" as *u8, sealedB)
320 gv_kv("open_interior" as *u8, intB)
321 gv_kv("mixed_ring_verts" as *u8, mixed_mid)
322 gv_kv("root_ring_wins" as *u8, root_wins)
323 gv_kv("far_ring_wins" as *u8, far_wins)
324 gv_kv("nearest_mixed_verts" as *u8, nearMixed)
325 gv_kv("shells_bleed_geodesic" as *u8, bleed_geo)
326 gv_kv("shells_bleed_nearest" as *u8, bleed_near)
327 gv_kv("shells_verts_unreached" as *u8, unreachedC)
328 return gv_verdict("nx_boneheat_gate" as *u8, ctr, "geodesic bone-heat auto-weights: blends at joints, never crosses air, announces an open mesh, refuses a missing skeleton by name" as *u8)
329}