code wiki / (root) / nx_obj_export.nx

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}