code wiki / (root) / nx_obj_export.nx

nx_obj_export.nx source

↩ module page · 76 lines · 4245 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" 6import "nx_vecmath.nx" 7import "nx_vnormals_lib.nx" 8 9// (oe_isqrt removed 2026-08-25: it was a one-line wrapper over vm_isqrt whose ONLY caller was the 10// duplicated normalise pass now retired onto nx_vnormals_lib. Leaving it would have added a row to the 11// defined-and-never-called census as a side effect of a consolidation.) 12func 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 } 13func oe_num(d: *u8, o: i64, v: i64) -> i64 { 14 var x: i64 = v 15 if x < 0 { d[o]=45 as u8; o=o+1; x=0-x } 16 if x == 0 { d[o]=48 as u8; return o+1 } 17 let t: *u8 = sys_mmap(24); var k: i64 = 0 18 while x > 0 { t[k]=(48+(x%10)) as u8; x=x/10; k=k+1 } 19 var i: i64 = 0 20 while i < k { d[o+i]=t[k-1-i]; i=i+1 } 21 return o + k 22} 23 24// returns bytes written, or -1. cap of buf handled by caller (size >= nv*70 + nf*48 + 64). 25func write_obj(vbuf: *i64, fbuf: *i64, nv: i64, nf: i64, path: *u8) -> i64 { 26 // RETIRED ONTO nx_vnormals_lib.vn_smooth_area, 2026-08-25. This block WAS a third copy of the 27 // area-weighted per-vertex normal computation -- character for character the same arithmetic as the 28 // former body of nx_gltf_export.gl_vnormals, but INLINE, which is why the estate's nx_retire_onto 29 // organ could not take it: that organ retires a named private FUNCTION onto an owner, and there was 30 // no function here to name. The owner also does the normalise-and-default pass that used to sit in 31 // the emit loop below, so the values written out are final. 32 let nrm: *i64 = sys_mmap(nv * VN_V3 * 8) as *i64 33 vn_smooth_area(vbuf, fbuf, nv, nf, nrm) 34 let cap: i64 = nv * 80 + nf * 52 + 128 35 let buf: *u8 = sys_mmap(cap) 36 var o: i64 = oe_cat(buf, 0, "# nishi_variant OBJ (sovereign nx_cc)\n" as *u8) 37 // vertices 38 var i: i64 = 0 39 while i < nv { 40 o = oe_cat(buf, o, "v " as *u8) 41 o = oe_num(buf, o, vbuf[i*3]); buf[o]=32 as u8; o=o+1 42 o = oe_num(buf, o, vbuf[i*3+1]); buf[o]=32 as u8; o=o+1 43 o = oe_num(buf, o, vbuf[i*3+2]); buf[o]=10 as u8; o=o+1 44 i = i + 1 45 } 46 // normals: smoothed, normalised to VN_SCALE and defaulted to +Y up by vn_smooth_area above. The 47 // normalise-and-default arithmetic that used to sit HERE was the second half of the duplicated copy; 48 // it moved to the owner with the first half, so this loop now only emits. 49 i = 0 50 while i < nv { 51 o = oe_cat(buf, o, "vn " as *u8) 52 o = oe_num(buf, o, nrm[i*VN_V3+VN_X]); buf[o]=32 as u8; o=o+1 53 o = oe_num(buf, o, nrm[i*VN_V3+VN_Y]); buf[o]=32 as u8; o=o+1 54 o = oe_num(buf, o, nrm[i*VN_V3+VN_Z]); buf[o]=10 as u8; o=o+1 55 i = i + 1 56 } 57 // faces (1-indexed; vertex index == normal index) 58 // `t` is DECLARED here now. It used to be declared by the normal-accumulation loop at the top of this 59 // function and merely reassigned here -- so retiring that loop onto vn_smooth_area took this loop's 60 // declaration with it. The compiler caught it; it is recorded because it is the ordinary hazard of 61 // removing code that shared a cursor with code that stays. 62 var t: i64 = 0 63 while t < nf { 64 let a: i64 = fbuf[t*3]+1; let b: i64 = fbuf[t*3+1]+1; let c: i64 = fbuf[t*3+2]+1 65 o = oe_cat(buf, o, "f " as *u8) 66 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 67 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 68 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 69 t = t + 1 70 } 71 let fd: i64 = sys_openat_wr(path, 0x1a4) 72 if fd < 0 { return 0 - 1 } 73 sys_write(fd, buf, o) 74 sys_close(fd) 75 return o 76}