nx_mesh3.nx source
↩ module page · 205 lines · 8143 B
1// nx_mesh3.nx -- the SHARED triangle mesh + STL interchange (real3d census's connective-tissue gap: "CAD,
2// print, games cannot hand geometry to each other today"; operator 2026-07-03: "make sure all of these things
3// across the environment are reusable in other areas for robotics, manufacturing, video, vr, etc").
4// ONE mesh format, MANY consumers: CAD exports it, the printer slices it, games/video render it, robotics
5// collides against it, VR scenes carry it. Vertices are fx256 integers (the ecosystem fixed-point law);
6// STL IO is BINARY STL (the industry lingua franca: 80B header, u32 count, 50B/tri) with EXACT round-trip --
7// fx256 -> IEEE-754 f32 is exact for |v| < 2^24 because /256 is a pure exponent shift, so write->read is
8// bit-identical (gated). Base-relative, no allocations beyond the caller's arena. license_tier: ORIGINAL
9import "nx_syscalls.nx"
10import "nx_f32_hw.nx"
11const M3_MAGIC_1048575: i64 = 1048575
12
13const M3_MAXV: i64 = 4096
14const M3_MAXT: i64 = 8192
15
16func m3_hdr(base: i64) -> *i64 { return base as *i64 } // [0]=nverts [1]=ntris
17func m3_vert(base: i64, i: i64) -> *i64 { return (base + 64 + i * 24) as *i64 }
18func m3_tri(base: i64, i: i64) -> *i64 { return (base + 64 + M3_MAXV * 24 + i * 24) as *i64 }
19func m3_bytes() -> i64 { return 64 + M3_MAXV * 24 + M3_MAXT * 24 }
20
21func m3_init(base: i64) -> i64 {
22 let h: *i64 = m3_hdr(base)
23 h[0] = 0
24 h[1] = 0
25 return 0
26}
27func m3_add_vert(base: i64, x: i64, y: i64, z: i64) -> i64 {
28 let h: *i64 = m3_hdr(base)
29 if h[0] >= M3_MAXV { return 0 - 1 }
30 let v: *i64 = m3_vert(base, h[0])
31 v[0] = x; v[1] = y; v[2] = z
32 h[0] = h[0] + 1
33 return h[0] - 1
34}
35func m3_add_tri(base: i64, a: i64, b: i64, c: i64) -> i64 {
36 let h: *i64 = m3_hdr(base)
37 if h[1] >= M3_MAXT { return 0 - 1 }
38 let t: *i64 = m3_tri(base, h[1])
39 t[0] = a; t[1] = b; t[2] = c
40 h[1] = h[1] + 1
41 return h[1] - 1
42}
43
44// AABB into out[6] = minx,miny,minz,maxx,maxy,maxz
45func m3_aabb(base: i64, out: *i64) -> i64 {
46 let h: *i64 = m3_hdr(base)
47 if h[0] == 0 { return 0 - 1 }
48 let v0: *i64 = m3_vert(base, 0)
49 out[0] = v0[0]; out[1] = v0[1]; out[2] = v0[2]
50 out[3] = v0[0]; out[4] = v0[1]; out[5] = v0[2]
51 var i: i64 = 1
52 while i < h[0] {
53 let v: *i64 = m3_vert(base, i)
54 if v[0] < out[0] { out[0] = v[0] }
55 if v[1] < out[1] { out[1] = v[1] }
56 if v[2] < out[2] { out[2] = v[2] }
57 if v[0] > out[3] { out[3] = v[0] }
58 if v[1] > out[4] { out[4] = v[1] }
59 if v[2] > out[5] { out[5] = v[2] }
60 i = i + 1
61 }
62 return 0
63}
64
65// fx256 -> IEEE-754 f32 bits (exact: /256 is an exponent shift)
66func m3_fx_to_f32(v: i64) -> i64 { return f32_div(f32_of(v), f32_of(256)) }
67// f32 bits -> fx256 (exact for interchange values)
68func m3_f32_to_fx(bits: i64) -> i64 { return f32_int(f32_mul(bits, f32_of(256))) }
69
70func m3_w32(buf: *u8, off: i64, v: i64) -> i64 {
71 buf[off] = (v & 255) as u8
72 buf[off + 1] = ((v >> 8) & 255) as u8
73 buf[off + 2] = ((v >> 16) & 255) as u8
74 buf[off + 3] = ((v >> 24) & 255) as u8
75 return 0
76}
77func m3_r32(buf: *u8, off: i64) -> i64 {
78 return (buf[off] as i64) | ((buf[off + 1] as i64) << 8) | ((buf[off + 2] as i64) << 16) | ((buf[off + 3] as i64) << 24)
79}
80
81// write BINARY STL: 80B header + u32 ntris + per-tri (normal f32x3 = zeros [readers recompute], 3 verts, u16 attr)
82func m3_write_stl(base: i64, path: *u8) -> i64 {
83 let h: *i64 = m3_hdr(base)
84 let nt: i64 = h[1]
85 let bytes: i64 = 84 + nt * 50
86 let buf: *u8 = sys_mmap(bytes + 64) as *u8
87 var i: i64 = 0
88 while i < 80 { buf[i] = 0 as u8; i = i + 1 }
89 buf[0] = 110 as u8; buf[1] = 120 as u8; buf[2] = 51 as u8 // "nx3" brand in the header
90 m3_w32(buf, 80, nt)
91 var ti: i64 = 0
92 while ti < nt {
93 let t: *i64 = m3_tri(base, ti)
94 let rec: i64 = 84 + ti * 50
95 m3_w32(buf, rec, 0)
96 m3_w32(buf, rec + 4, 0)
97 m3_w32(buf, rec + 8, 0)
98 var k: i64 = 0
99 while k < 3 {
100 let v: *i64 = m3_vert(base, t[k])
101 m3_w32(buf, rec + 12 + k * 12, m3_fx_to_f32(v[0]))
102 m3_w32(buf, rec + 16 + k * 12, m3_fx_to_f32(v[1]))
103 m3_w32(buf, rec + 20 + k * 12, m3_fx_to_f32(v[2]))
104 k = k + 1
105 }
106 buf[rec + 48] = 0 as u8
107 buf[rec + 49] = 0 as u8
108 ti = ti + 1
109 }
110 let fd: i64 = sys_openat_wr(path, 420)
111 if fd < 0 { return 0 - 1 }
112 sys_write(fd, buf, bytes)
113 sys_close(fd)
114 return bytes
115}
116
117// read BINARY STL -> verts DEDUPLICATED exactly (bit-equal f32 triples share a vertex)
118func m3_read_stl(base: i64, path: *u8) -> i64 {
119 m3_init(base)
120 let fd: i64 = sys_openat_rd(path)
121 if fd < 0 { return 0 - 1 }
122 let cap: i64 = 84 + M3_MAXT * 50 + 64
123 let buf: *u8 = sys_mmap(cap) as *u8
124 var got: i64 = 0
125 var r: i64 = 1
126 while r > 0 {
127 r = sys_read(fd, (buf as i64 + got) as *u8, cap - got)
128 if r > 0 { got = got + r }
129 }
130 sys_close(fd)
131 if got < 84 { return 0 - 1 }
132 let nt: i64 = m3_r32(buf, 80)
133 if got < 84 + nt * 50 { return 0 - 1 }
134 var ti: i64 = 0
135 while ti < nt {
136 let rec: i64 = 84 + ti * 50
137 var ids: i64 = 0
138 var k: i64 = 0
139 while k < 3 {
140 let x: i64 = m3_f32_to_fx(m3_r32(buf, rec + 12 + k * 12))
141 let y: i64 = m3_f32_to_fx(m3_r32(buf, rec + 16 + k * 12))
142 let z: i64 = m3_f32_to_fx(m3_r32(buf, rec + 20 + k * 12))
143 // exact-dedup scan (O(n^2) -- fine at interchange sizes; spatial hash = a later rung)
144 let h: *i64 = m3_hdr(base)
145 var found: i64 = 0 - 1
146 var vi: i64 = 0
147 while vi < h[0] {
148 let v: *i64 = m3_vert(base, vi)
149 if v[0] == x { if v[1] == y { if v[2] == z { found = vi; vi = h[0] } } }
150 vi = vi + 1
151 }
152 if found < 0 { found = m3_add_vert(base, x, y, z) }
153 if k == 0 { ids = found }
154 if k == 1 { ids = ids | (found << 20) }
155 if k == 2 { ids = ids | (found << 40) }
156 k = k + 1
157 }
158 m3_add_tri(base, ids & M3_MAGIC_1048575, (ids >> 20) & M3_MAGIC_1048575, (ids >> 40) & M3_MAGIC_1048575)
159 ti = ti + 1
160 }
161 return nt
162}
163
164// slice at plane z=zc: count crossing segments (the print-pipeline primitive; polygon chaining = vessel-side)
165func m3_slice_z_count(base: i64, zc: i64) -> i64 {
166 let h: *i64 = m3_hdr(base)
167 var segs: i64 = 0
168 var ti: i64 = 0
169 while ti < h[1] {
170 let t: *i64 = m3_tri(base, ti)
171 var cross: i64 = 0
172 var e: i64 = 0
173 while e < 3 {
174 let a: *i64 = m3_vert(base, t[e])
175 let b: *i64 = m3_vert(base, t[(e + 1) % 3])
176 var lo: i64 = a[2]
177 var hi: i64 = b[2]
178 if lo > hi { lo = b[2]; hi = a[2] }
179 if lo < zc { if hi > zc { cross = cross + 1 } }
180 e = e + 1
181 }
182 if cross == 2 { segs = segs + 1 }
183 ti = ti + 1
184 }
185 return segs
186}
187
188// convenience: an axis-aligned box (12 tris) -- the canonical test solid + a CAD primitive
189func m3_box(base: i64, cx: i64, cy: i64, cz: i64, hx: i64, hy: i64, hz: i64) -> i64 {
190 let v0: i64 = m3_add_vert(base, cx - hx, cy - hy, cz - hz)
191 let v1: i64 = m3_add_vert(base, cx + hx, cy - hy, cz - hz)
192 let v2: i64 = m3_add_vert(base, cx + hx, cy + hy, cz - hz)
193 let v3: i64 = m3_add_vert(base, cx - hx, cy + hy, cz - hz)
194 let v4: i64 = m3_add_vert(base, cx - hx, cy - hy, cz + hz)
195 let v5: i64 = m3_add_vert(base, cx + hx, cy - hy, cz + hz)
196 let v6: i64 = m3_add_vert(base, cx + hx, cy + hy, cz + hz)
197 let v7: i64 = m3_add_vert(base, cx - hx, cy + hy, cz + hz)
198 m3_add_tri(base, v0, v2, v1); m3_add_tri(base, v0, v3, v2) // bottom
199 m3_add_tri(base, v4, v5, v6); m3_add_tri(base, v4, v6, v7) // top
200 m3_add_tri(base, v0, v1, v5); m3_add_tri(base, v0, v5, v4) // -y
201 m3_add_tri(base, v2, v3, v7); m3_add_tri(base, v2, v7, v6) // +y
202 m3_add_tri(base, v1, v2, v6); m3_add_tri(base, v1, v6, v5) // +x
203 m3_add_tri(base, v3, v0, v4); m3_add_tri(base, v3, v4, v7) // -x
204 return 12
205}