code wiki / (root) / nx_mesh3.nx

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}