code wiki / (root) / nx_stl_write.nx

nx_stl_write.nx source

↩ module page · 108 lines · 4742 B

1// nx_stl_write.nx -- SOVEREIGN DCC export: procedural mesh -> binary STL. 2// 3// The creator/writer half (nx_stl is the reader). Emits the exact 1980s binary 4// STL the existing slicer->gcode->klipper pipeline consumes: 80B header + u32 5// n_tris + per-tri 50B (12B normal + 9 f32 verts + 2B attr). Floats via the new 6// f32_from_i64 encoder; bytes via nx_le_write_u32. This is the model->print seam: 7// geometry authored here feeds nx_stl_load_binary -> nx_slice_* -> nx_gcode_* -> 8// nx_klipper_gcode_validator. No dup (nx_stl had no writer). license_tier: ORIGINAL. 9 10import "nx_syscalls.nx" 11import "nx_le.nx" 12import "nx_f32_encode.nx" 13import "nx_mesh.nx" 14 15// write one vertex (x,y,z mm) as 3 little-endian f32 at off; returns off+12 16func sw_put_vert(buf: *u8, off: i64, x: i64, y: i64, z: i64) -> i64 { 17 nx_le_write_u32(buf, off, f32_from_i64(x)) 18 nx_le_write_u32(buf, off + 4, f32_from_i64(y)) 19 nx_le_write_u32(buf, off + 8, f32_from_i64(z)) 20 return off + 12 21} 22 23// write a binary STL of a cube of side S (mm) into buf; returns total bytes (684) 24func nx_stl_write_cube(buf: *u8, S: i64) -> i64 { 25 let cx: *i64 = (sys_mmap(8 * 8)) as *i64 26 let cy: *i64 = (sys_mmap(8 * 8)) as *i64 27 let cz: *i64 = (sys_mmap(8 * 8)) as *i64 28 cx[0] = 0; cy[0] = 0; cz[0] = 0 29 cx[1] = S; cy[1] = 0; cz[1] = 0 30 cx[2] = S; cy[2] = S; cz[2] = 0 31 cx[3] = 0; cy[3] = S; cz[3] = 0 32 cx[4] = 0; cy[4] = 0; cz[4] = S 33 cx[5] = S; cy[5] = 0; cz[5] = S 34 cx[6] = S; cy[6] = S; cz[6] = S 35 cx[7] = 0; cy[7] = S; cz[7] = S 36 let ta: *i64 = (sys_mmap(12 * 8)) as *i64 37 let tb: *i64 = (sys_mmap(12 * 8)) as *i64 38 let tc: *i64 = (sys_mmap(12 * 8)) as *i64 39 ta[0]=0;tb[0]=1;tc[0]=2; ta[1]=0;tb[1]=2;tc[1]=3 40 ta[2]=5;tb[2]=4;tc[2]=7; ta[3]=5;tb[3]=7;tc[3]=6 41 ta[4]=4;tb[4]=0;tc[4]=3; ta[5]=4;tb[5]=3;tc[5]=7 42 ta[6]=1;tb[6]=5;tc[6]=6; ta[7]=1;tb[7]=6;tc[7]=2 43 ta[8]=4;tb[8]=5;tc[8]=1; ta[9]=4;tb[9]=1;tc[9]=0 44 ta[10]=3;tb[10]=2;tc[10]=6; ta[11]=3;tb[11]=6;tc[11]=7 45 46 var i: i64 = 0 47 while i < 80 { buf[i] = 0 as u8; i = i + 1 } // 80-byte header (ignored) 48 nx_le_write_u32(buf, 80, 12) // n_tris 49 var off: i64 = 84 50 var t: i64 = 0 51 while t < 12 { 52 nx_le_write_u32(buf, off, 0) // normal = (0,0,0) f32 (reader ignores) 53 nx_le_write_u32(buf, off + 4, 0) 54 nx_le_write_u32(buf, off + 8, 0) 55 off = off + 12 56 let a: i64 = ta[t]; let b: i64 = tb[t]; let c: i64 = tc[t] 57 off = sw_put_vert(buf, off, cx[a], cy[a], cz[a]) 58 off = sw_put_vert(buf, off, cx[b], cy[b], cz[b]) 59 off = sw_put_vert(buf, off, cx[c], cy[c], cz[c]) 60 nx_le_write_u16(buf, off, 0) // attribute byte count 61 off = off + 2 62 t = t + 1 63 } 64 return off 65} 66 67// ===== GENERAL mesh export: ANY NxMesh -> binary STL ================= 68// 69// The cube-only writer above proved the seam; this writes an ARBITRARY 70// authored mesh (the output of the DCC editor / CAD kernel) to the exact 71// binary STL the slicer consumes. Vertices are read from the mesh in its 72// native Q14-mm units and encoded with f32_from_q14 (exact), so sub-mm 73// geometry survives. Triangle corners are emitted unindexed (STL has no 74// shared-vertex table); the existing nx_stl_load_binary re-dedups them on 75// read. buf must hold >= 84 + 50*m.n_tris bytes. Returns bytes written. 76 77// write vertex `vidx` of mesh `m` (Q14 mm) as 3 little-endian f32; off+12 78func sw_put_mesh_vert(buf: *u8, off: i64, m: *NxMesh, vidx: i64) -> i64 { 79 nx_le_write_u32(buf, off, f32_from_q14(nx_mesh_get_vertex_x(m, vidx))) 80 nx_le_write_u32(buf, off + 4, f32_from_q14(nx_mesh_get_vertex_y(m, vidx))) 81 nx_le_write_u32(buf, off + 8, f32_from_q14(nx_mesh_get_vertex_z(m, vidx))) 82 return off + 12 83} 84 85func nx_stl_write_mesh(buf: *u8, m: *NxMesh) -> i64 { 86 var i: i64 = 0 87 while i < 80 { buf[i] = 0 as u8; i = i + 1 } // 80-byte header (ignored) 88 let nt: i64 = m.n_tris 89 nx_le_write_u32(buf, 80, nt) // n_tris 90 var off: i64 = 84 91 var t: i64 = 0 92 while t < nt { 93 nx_le_write_u32(buf, off, 0) // normal = (0,0,0) f32 (reader trusts winding) 94 nx_le_write_u32(buf, off + 4, 0) 95 nx_le_write_u32(buf, off + 8, 0) 96 off = off + 12 97 let a: i64 = m.indices[t * 3 + 0] 98 let b: i64 = m.indices[t * 3 + 1] 99 let c: i64 = m.indices[t * 3 + 2] 100 off = sw_put_mesh_vert(buf, off, m, a) 101 off = sw_put_mesh_vert(buf, off, m, b) 102 off = sw_put_mesh_vert(buf, off, m, c) 103 nx_le_write_u16(buf, off, 0) // attribute byte count 104 off = off + 2 105 t = t + 1 106 } 107 return off 108}