nx_obj_export.nx source
↩ module page · 77 lines · 3899 B
1// nx_obj_export.nx -- sovereign Wavefront OBJ writer for the bestiary meshes (game/DCC reuse: engines + Blender
2// import OBJ+normals far cleaner than the print-only STL). Takes the nx_meshgen verts+tris, computes SMOOTH
3// per-vertex normals (accumulate face normals -> normalize), and emits v / vn / f (with //vn indices), 1-indexed.
4// Buffered (one write). Verts stay in the mesh's fx1024 units (importers rescale). license_tier: ORIGINAL
5import "nx_syscalls.nx"
6
7func oe_isqrt(v: i64) -> i64 { if v <= 0 { return 0 } var x: i64 = v; var y: i64 = (x + 1) / 2; while y < x { x = y; y = (x + v / x) / 2 } return x }
8func oe_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){d[o+i]=s[i]; i=i+1} return o+i }
9func oe_num(d: *u8, o: i64, v: i64) -> i64 {
10 var x: i64 = v
11 if x < 0 { d[o]=45 as u8; o=o+1; x=0-x }
12 if x == 0 { d[o]=48 as u8; return o+1 }
13 let t: *u8 = sys_mmap(24); var k: i64 = 0
14 while x > 0 { t[k]=(48+(x%10)) as u8; x=x/10; k=k+1 }
15 var i: i64 = 0
16 while i < k { d[o+i]=t[k-1-i]; i=i+1 }
17 return o + k
18}
19
20// returns bytes written, or -1. cap of buf handled by caller (size >= nv*70 + nf*48 + 64).
21func write_obj(vbuf: *i64, fbuf: *i64, nv: i64, nf: i64, path: *u8) -> i64 {
22 // per-vertex normal accumulation (nv*3 i64, zeroed by mmap)
23 let nrm: *i64 = sys_mmap(nv * 3 * 8) as *i64
24 var t: i64 = 0
25 while t < nf {
26 let a: i64 = fbuf[t*3]; let b: i64 = fbuf[t*3+1]; let c: i64 = fbuf[t*3+2]
27 let ax: i64 = vbuf[a*3]; let ay: i64 = vbuf[a*3+1]; let az: i64 = vbuf[a*3+2]
28 let e1x: i64 = vbuf[b*3]-ax; let e1y: i64 = vbuf[b*3+1]-ay; let e1z: i64 = vbuf[b*3+2]-az
29 let e2x: i64 = vbuf[c*3]-ax; let e2y: i64 = vbuf[c*3+1]-ay; let e2z: i64 = vbuf[c*3+2]-az
30 let fnx: i64 = e1y*e2z - e1z*e2y
31 let fny: i64 = e1z*e2x - e1x*e2z
32 let fnz: i64 = e1x*e2y - e1y*e2x
33 nrm[a*3]=nrm[a*3]+fnx; nrm[a*3+1]=nrm[a*3+1]+fny; nrm[a*3+2]=nrm[a*3+2]+fnz
34 nrm[b*3]=nrm[b*3]+fnx; nrm[b*3+1]=nrm[b*3+1]+fny; nrm[b*3+2]=nrm[b*3+2]+fnz
35 nrm[c*3]=nrm[c*3]+fnx; nrm[c*3+1]=nrm[c*3+1]+fny; nrm[c*3+2]=nrm[c*3+2]+fnz
36 t = t + 1
37 }
38 let cap: i64 = nv * 80 + nf * 52 + 128
39 let buf: *u8 = sys_mmap(cap)
40 var o: i64 = oe_cat(buf, 0, "# nishi_variant OBJ (sovereign nx_cc)\n" as *u8)
41 // vertices
42 var i: i64 = 0
43 while i < nv {
44 o = oe_cat(buf, o, "v " as *u8)
45 o = oe_num(buf, o, vbuf[i*3]); buf[o]=32 as u8; o=o+1
46 o = oe_num(buf, o, vbuf[i*3+1]); buf[o]=32 as u8; o=o+1
47 o = oe_num(buf, o, vbuf[i*3+2]); buf[o]=10 as u8; o=o+1
48 i = i + 1
49 }
50 // normals (smooth per-vertex; normalize to ~1000; degenerate -> +Y up)
51 i = 0
52 while i < nv {
53 var nx: i64 = nrm[i*3]; var ny: i64 = nrm[i*3+1]; var nz: i64 = nrm[i*3+2]
54 let l: i64 = oe_isqrt(nx*nx + ny*ny + nz*nz)
55 if l < 1 { nx = 0; ny = 1000; nz = 0 } else { nx = nx*1000/l; ny = ny*1000/l; nz = nz*1000/l }
56 o = oe_cat(buf, o, "vn " as *u8)
57 o = oe_num(buf, o, nx); buf[o]=32 as u8; o=o+1
58 o = oe_num(buf, o, ny); buf[o]=32 as u8; o=o+1
59 o = oe_num(buf, o, nz); buf[o]=10 as u8; o=o+1
60 i = i + 1
61 }
62 // faces (1-indexed; vertex index == normal index)
63 t = 0
64 while t < nf {
65 let a: i64 = fbuf[t*3]+1; let b: i64 = fbuf[t*3+1]+1; let c: i64 = fbuf[t*3+2]+1
66 o = oe_cat(buf, o, "f " as *u8)
67 o = oe_num(buf, o, a); o = oe_cat(buf, o, "//" as *u8); o = oe_num(buf, o, a); buf[o]=32 as u8; o=o+1
68 o = oe_num(buf, o, b); o = oe_cat(buf, o, "//" as *u8); o = oe_num(buf, o, b); buf[o]=32 as u8; o=o+1
69 o = oe_num(buf, o, c); o = oe_cat(buf, o, "//" as *u8); o = oe_num(buf, o, c); buf[o]=10 as u8; o=o+1
70 t = t + 1
71 }
72 let fd: i64 = sys_openat_wr(path, 0x1a4)
73 if fd < 0 { return 0 - 1 }
74 sys_write(fd, buf, o)
75 sys_close(fd)
76 return o
77}