code wiki / (root) / nx_xps.nx

nx_xps.nx source

↩ module page · 83 lines · 5490 B

1// nx_xps.nx -- XPS / XNALara MODEL TO THE SOVEREIGN ASSET (/compare/modding MD2 xps_to_nxa, 2026-09-06). Reads either 2// dialect through nx_xps_lib (the reference readers mirrored and read first) and writes NXANIM01 VERT, TRIS, SKEL and SKIN 3// through nx_nxa_write_lib, the ONE container writer. Scale is DATA: units_per_xps names how many 0.01 mm units one XPS unit 4// is (default 100000, i.e. one XPS unit read as one metre, announced on every run). Axes are carried as authored; the world 5// derives the up axis from the asset's own extents, as it does for every other donor. Normals, colours, uvs and tangents are 6// read and counted, not carried (TEXC is the texture rung). Every refusal is named and exits 3; nothing is written on refusal. 7// usage: nx_xps <in.xps|in.mesh.ascii> <out.nxa> [units_per_xps=<n>] 8// exits: 0 ok | 2 usage | 3 REFUSED (the reason is on the line) | 4 the container could not be written (the reason is on the line) 9// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 10import "nx_syscalls.nx" 11import "nx_xps_lib.nx" 12import "nx_nxa_write_lib.nx" 13 14const XPS_EXIT_USAGE: i64 = 2 15const XPS_EXIT_REFUSE: i64 = 3 16const XPS_EXIT_WRITE: i64 = 4 17const XPS_UNITS_KEY: *u8 = "units_per_xps=" 18const XPS_UNITS_KEY_LEN: i64 = 14 19 20func xps_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 21func xps_puts(s: *u8) -> i64 { sys_write(1, s, xps_len(s)); return 0 } 22func xps_putn(v: i64) -> i64 { 23 let t: *u8 = sys_mmap(32) 24 var m: i64 = v 25 var w: i64 = 0 26 if m < 0 { t[0] = 45 as u8; sys_write(1, t, 1); m = 0 - m } 27 if m == 0 { t[0] = 48 as u8; sys_write(1, t, 1); return 0 } 28 let d: *u8 = sys_mmap(32) 29 var k: i64 = 0 30 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 31 var j: i64 = 0 32 while j < k { t[w] = d[k - 1 - j]; w = w + 1; j = j + 1 } 33 sys_write(1, t, w) 34 return 0 35} 36func xps_kv(k: *u8, v: i64) -> i64 { xps_puts(k); xps_putn(v); return 0 } 37func xps_prefix(s: *u8, p: *u8, n: i64) -> i64 { var i: i64 = 0; while i < n { if s[i] != p[i] { return 0 } i = i + 1 } return 1 } 38func xps_atoi(s: *u8) -> i64 { var v: i64 = 0; var i: i64 = 0; while s[i] != (0 as u8) { let c: i64 = s[i] as i64; if c < 48 { return v } if c > 57 { return v } v = v * 10 + (c - 48); i = i + 1 } return v } 39// trailing units_per_xps=<n> is a SCAN so the positional contract stays fixed 40func xps_units_arg(argc: i64, argv: *i64) -> i64 { 41 var i: i64 = 3 42 while i < argc { let a: *u8 = argv[i] as *u8; if xps_prefix(a, XPS_UNITS_KEY, XPS_UNITS_KEY_LEN) == 1 { return xps_atoi(a + XPS_UNITS_KEY_LEN) } i = i + 1 } 43 return 0 44} 45func xps_dialect_name(d: i64) -> *u8 { if d == XP_DIALECT_BIN { return "binary" as *u8 } return "ascii" as *u8 } 46// THE CONTRACT SYMBOL the modding board watches: one XPS file in, one NXANIM01 out, the receipt printed, the counts in m. 47// returns 0, or a NEGATIVE xp error (refused, nothing written), or a POSITIVE nxw error code negated past -100 for the writer 48func xps_to_nxa(inpath: *u8, outpath: *u8, units_per_xps: i64, m: *i64, wrc: *i64) -> i64 { 49 let lp: *i64 = sys_mmap(16) as *i64 50 let b: *u8 = sys_read_file(inpath, lp) 51 if (b as i64) == 0 { xps_puts("XPS-REFUSE unreadable: " as *u8); xps_puts(inpath); xps_puts("\n" as *u8); return XP_ERR_TRUNCATED } 52 let rc: i64 = xp_read(b, lp[0], units_per_xps, m) 53 xps_puts("XPS dialect=" as *u8); xps_puts(xps_dialect_name(m[XP_M_DIALECT])) 54 xps_kv(" version=" as *u8, m[XP_M_VMAJ]); xps_puts("." as *u8); xps_putn(m[XP_M_VMIN]) 55 xps_kv(" tangent=" as *u8, m[XP_M_TANGENT]); xps_kv(" variable_weights=" as *u8, m[XP_M_VARW]) 56 xps_kv(" bones=" as *u8, m[XP_M_NJ]); xps_kv(" meshes=" as *u8, m[XP_M_NMESH]); xps_kv(" textures=" as *u8, m[XP_M_NTEX]) 57 xps_kv(" uv_layers_max=" as *u8, m[XP_M_UVMAX]); xps_kv(" verts=" as *u8, m[XP_M_NV]); xps_kv(" tris=" as *u8, m[XP_M_NT]) 58 xps_kv(" weights_fixed=" as *u8, m[XP_M_WFIX]); xps_kv(" weights_truncated_to_4=" as *u8, m[XP_M_WTRUNC]) 59 xps_kv(" units_per_xps=" as *u8, m[XP_M_MUL]); xps_puts(" axes=as-authored normals=read-not-carried uvs=read-not-carried\n" as *u8) 60 if rc < 0 { 61 xps_puts("XPS-REFUSE " as *u8); xps_puts(xp_err_name(rc)) 62 if m[XP_M_ERRPOS] >= 0 { xps_kv(" at_byte=" as *u8, m[XP_M_ERRPOS]) } 63 xps_kv(" bad_joint_refs=" as *u8, m[XP_M_BADJOINT]); xps_puts("\n" as *u8) 64 return rc 65 } 66 let w: i64 = nxw_write(outpath, m[XP_M_VX] as *i64, m[XP_M_NV], m[XP_M_TR] as *i64, m[XP_M_NT], m[XP_M_JPAR] as *i64, m[XP_M_JPOS] as *i64, m[XP_M_NJ], m[XP_M_SJ] as *i64, m[XP_M_SW] as *i64, wrc) 67 if w < 0 { 68 xps_puts("XPS-NXA-REFUSE " as *u8); xps_puts(nxw_err_name(w)); xps_kv(" first_bad_record=" as *u8, wrc[NXW_R_FIRSTBAD]); xps_puts("\n" as *u8) 69 return 0 - 100 + w 70 } 71 xps_kv("XPS-NXA wrote=" as *u8, w); xps_kv(" sections=" as *u8, wrc[NXW_R_SECTIONS]); xps_kv(" words=" as *u8, wrc[NXW_R_WORDS]) 72 xps_puts(" out=" as *u8); xps_puts(outpath); xps_puts("\n" as *u8) 73 return 0 74} 75func main(argc: i64, argv: *i64) -> i64 { 76 if argc < 3 { xps_puts("usage: nx_xps <in.xps|in.mesh.ascii> <out.nxa> [units_per_xps=<n>]\n" as *u8); return XPS_EXIT_USAGE } 77 let m: *i64 = sys_mmap(8 * XP_M_N) as *i64 78 let wrc: *i64 = sys_mmap(8 * NXW_R_N) as *i64 79 let rc: i64 = xps_to_nxa(argv[1] as *u8, argv[2] as *u8, xps_units_arg(argc, argv), m, wrc) 80 if rc == 0 { return 0 } 81 if rc <= 0 - 100 { return XPS_EXIT_WRITE } 82 return XPS_EXIT_REFUSE 83}