nx_mesh_sculpt_test.nx source
↩ module page · 82 lines · 4290 B
1// nx_mesh_sculpt_test.nx -- KAT gate for the ZBrush-class curved primitive +
2// sculpt brush. Closed-form invariants: octahedron axis verts sit exactly on
3// the sphere; subdivision counts follow the formula; projection keeps the poles
4// exact; a north-pole inflate brush raises max_z by EXACTLY the strength while
5// leaving the far (south) pole untouched and conserving topology. expect_exit: 0.
6
7import "nx_syscalls.nx"
8import "nx_mesh.nx"
9import "nx_mesh_edit.nx"
10import "nx_mesh_sculpt.nx"
11
12func w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
13func wn(v: i64) -> i64 {
14 let b: *u8 = sys_mmap(28); var m: i64 = v
15 if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) }
16 let t: *u8 = sys_mmap(28); var k: i64 = 0
17 if m == 0 { t[0] = 48 as u8; k = 1 }
18 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
19 var i: i64 = 0; while i < k { b[i] = t[k - 1 - i]; i = i + 1 }
20 sys_write(1, b, k); return 0
21}
22func chk(cond: i64, pass: *i64, fail: *i64, label: *u8) -> i64 {
23 if cond == 1 { pass[0] = pass[0] + 1; w(" ok " as *u8); w(label); w("\n" as *u8) }
24 else { fail[0] = fail[0] + 1; w(" XX " as *u8); w(label); w("\n" as *u8) }
25 return 0
26}
27func eqi(a: i64, b: i64) -> i64 { if a == b { return 1 } return 0 }
28// within +/- tol
29func near(a: i64, b: i64, tol: i64) -> i64 { var d: i64 = a - b; if d < 0 { d = 0 - d } if d <= tol { return 1 } return 0 }
30
31func main() -> i64 {
32 let pass: *i64 = (sys_mmap(8)) as *i64
33 let fail: *i64 = (sys_mmap(8)) as *i64
34 pass[0] = 0
35 fail[0] = 0
36 let bb: *i64 = (sys_mmap(48)) as *i64
37 let R: i64 = 163840 // 10mm radius
38 w("=== nx_mesh_sculpt KAT (icosphere + inflate brush) ===\n" as *u8)
39
40 // --- OCTAHEDRON: 6v/8t, axis verts exactly on sphere ---
41 let oct: *NxMesh = nx_mesh_make_octahedron(R, 0)
42 chk(eqi(oct.n_verts, 6), pass, fail, "octahedron 6 verts" as *u8)
43 chk(eqi(oct.n_tris, 8), pass, fail, "octahedron 8 tris" as *u8)
44 chk(eqi(nx_mesh_validate(oct), NX_MESH_OK), pass, fail, "octahedron valid" as *u8)
45 chk(eqi(nx_mesh_vert_radius(oct, 4), R), pass, fail, "north pole exactly at radius R" as *u8)
46
47 // --- ICOSPHERE subdiv=2: 126v/128t, valid, on the sphere ---
48 let sph: *NxMesh = nx_mesh_make_icosphere(R, 2, 0)
49 w(" icosphere(2): verts=" as *u8); wn(sph.n_verts); w(" tris=" as *u8); wn(sph.n_tris); w("\n" as *u8)
50 chk(eqi(sph.n_tris, 128), pass, fail, "icosphere subdiv=2: 8*4*4 = 128 tris" as *u8)
51 chk(eqi(sph.n_verts, 126), pass, fail, "icosphere subdiv=2: 126 verts" as *u8)
52 chk(eqi(nx_mesh_validate(sph), NX_MESH_OK), pass, fail, "icosphere valid (indices in range)" as *u8)
53 // every vertex within 2 Q14 ULP of radius R (isqrt floor rounding)
54 var allon: i64 = 1
55 var vi: i64 = 0
56 while vi < sph.n_verts {
57 if near(nx_mesh_vert_radius(sph, vi), R, 2) == 0 { allon = 0 }
58 vi = vi + 1
59 }
60 chk(eqi(allon, 1), pass, fail, "ALL 126 verts lie on the sphere (radius R +/-2 ULP)" as *u8)
61
62 // --- pre-sculpt bounding box: a clean sphere spanning +/-R in z ---
63 nx_mesh_aabb(sph, bb)
64 chk(eqi(bb[5], R), pass, fail, "pre-sculpt max_z = +R (north pole present)" as *u8)
65 chk(eqi(bb[2], 0 - R), pass, fail, "pre-sculpt min_z = -R (south pole present)" as *u8)
66
67 // --- SCULPT: inflate brush at the north pole ---
68 let strength: i64 = 32768 // 2mm bump
69 let brad: i64 = 81920 // 5mm brush radius
70 nx_mesh_sculpt_brush(sph, 0, 0, R, brad, strength)
71 chk(eqi(sph.n_verts, 126), pass, fail, "sculpt preserves vert count (126)" as *u8)
72 chk(eqi(sph.n_tris, 128), pass, fail, "sculpt preserves tri count (128)" as *u8)
73 nx_mesh_aabb(sph, bb)
74 w(" post-sculpt max_z=" as *u8); wn(bb[5]); w(" (expect R+strength=" as *u8); wn(R + strength); w(")\n" as *u8)
75 chk(eqi(bb[5], R + strength), pass, fail, "north-pole bump: max_z = R + strength EXACTLY" as *u8)
76 chk(eqi(bb[2], 0 - R), pass, fail, "far south pole untouched: min_z still -R" as *u8)
77 chk(eqi(nx_mesh_validate(sph), NX_MESH_OK), pass, fail, "sculpted mesh still valid" as *u8)
78
79 w("=== VERDICT pass=" as *u8); wn(pass[0]); w(" fail=" as *u8); wn(fail[0]); w(" ===\n" as *u8)
80 if fail[0] == 0 { return 0 }
81 return 1
82}