nx_autorig_mesh.nx source
↩ module page · 79 lines · 3877 B
1// nx_autorig_mesh.nx -- ONE-CALL SOVEREIGN AUTO-RIG OF A BARE MESH: skeleton then skin weights in a SINGLE
2// invocation, composing nx_curveskel_lib (cs_run) and nx_boneheat_lib (bh_run). This is the DC16 "arbitrary
3// topology" entry point: "run two tools in order" is not a delivered capability, one call is. Blender's Rigify
4// only assembles a control rig from a meta-rig a human PLACES, and UniRig/RigNet predict with a learned model;
5// this is the classical deterministic route, no checkpoint and no data, bare mesh in and a skinned rigged NXA out.
6// It emits the skeleton and the skinned rig as TWO EXPLICIT artifacts -- no hidden sibling writes -- geodesic
7// weights by default. Its neutrality is provable and its gate proves it: the one-call output is BYTE-IDENTICAL
8// to cs_run then bh_run run separately, so this organ adds an entry point and changes no arithmetic.
9// UNITS/format inherited from the composed libs (NXA v1, 0.01 mm). license_tier: ORIGINAL expect_exit: 0
10import "nx_syscalls.nx"
11import "nx_curveskel_lib.nx"
12
13const AM_CELLS_DEFAULT: i64 = 64 // bone-heat grid resolution default; overridable, derived from the asset otherwise
14const AM_EXIT_OK: i64 = 0
15const AM_EXIT_USAGE: i64 = 2
16const AM_EXIT_SKEL: i64 = 3 // the skeleton stage refused (a volumeless sheet, an unreadable mesh)
17const AM_EXIT_SKIN: i64 = 4 // the weight stage refused (no skeleton to weight against)
18
19func amw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
20func amn(v: i64) -> i64 {
21 let b: *u8 = sys_mmap(32)
22 var x: i64 = v
23 if x < 0 { b[0] = 45 as u8; sys_write(1, b, 1); x = 0 - x }
24 if x == 0 { b[0] = 48 as u8; sys_write(1, b, 1); return 0 }
25 var d: i64 = 0
26 var y: i64 = x
27 while y > 0 { d = d + 1; y = y / 10 }
28 var i: i64 = d
29 while i > 0 { i = i - 1; b[i] = ((x % 10) + 48) as u8; x = x / 10 }
30 sys_write(1, b, d)
31 return 0
32}
33func am_atoi(s: *u8) -> i64 {
34 var v: i64 = 0
35 var i: i64 = 0
36 while s[i] != (0 as u8) {
37 let c: i64 = s[i] as i64
38 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } }
39 i = i + 1
40 }
41 return v
42}
43// compose: bare -> skeleton (cs_run) -> skinned (bh_run geodesic). crep/brep are the composed libs' own reports,
44// zeroed here so a caller reads them straight. Returns AM_EXIT_OK, or the stage code of the first refusal.
45func amesh_run(bare: *u8, skel: *u8, skinned: *u8, cells: i64, crep: *i64, brep: *i64) -> i64 {
46 var k: i64 = 0
47 while k < CR_WORDS { crep[k] = 0; k = k + 1 }
48 let rcS: i64 = cs_run(bare, skel, crep)
49 if rcS != CS_EXIT_OK { return AM_EXIT_SKEL }
50 k = 0
51 while k < BR_WORDS { brep[k] = 0; k = k + 1 }
52 let rcB: i64 = bh_run(skel, skinned, BH_MODE_GEODESIC, cells, brep)
53 if rcB != BH_EXIT_OK { return AM_EXIT_SKIN }
54 return AM_EXIT_OK
55}
56func main(argc: i64, argv: *i64) -> i64 {
57 if argc < 4 {
58 amw("usage: nx_autorig_mesh <bare.nxa> <skel_out.nxa> <skinned_out.nxa> [cells]\n" as *u8)
59 return AM_EXIT_USAGE
60 }
61 let bare: *u8 = argv[1] as *u8
62 let skel: *u8 = argv[2] as *u8
63 let skinned: *u8 = argv[3] as *u8
64 var cells: i64 = AM_CELLS_DEFAULT
65 if argc >= 5 { cells = am_atoi(argv[4] as *u8) }
66 if cells < 1 { cells = AM_CELLS_DEFAULT }
67 let crep: *i64 = sys_mmap(CR_WORDS * 8) as *i64
68 let brep: *i64 = sys_mmap(BR_WORDS * 8) as *i64
69 let rc: i64 = amesh_run(bare, skel, skinned, cells, crep, brep)
70 cs_report(crep, bare, skel)
71 if rc == AM_EXIT_OK { bh_report(BH_MODE_GEODESIC, brep, skel, skinned) }
72 amw("NXAUTORIG-MESH rc=" as *u8); amn(rc)
73 amw(" limbs=" as *u8); amn(crep[CR_LIMBS])
74 amw(" joints=" as *u8); amn(crep[CR_JOINTS])
75 amw(" branches=" as *u8); amn(crep[CR_BRANCHES])
76 amw(" mixed_verts=" as *u8); amn(brep[BR_MIXED])
77 amw("\n" as *u8)
78 return rc
79}