code wiki / (root) / nx_bvhmotion.nx

nx_bvhmotion.nx source

↩ module page · 212 lines · 9841 B

1// nx_bvhmotion.nx -- BVH MOTION CAPTURE CENSUS (thin CLI over nx_bvh_lib). 2// 3// NAMING (deliberate, do not "fix" to nx_bvh): nx_bvh.nx is a BOUNDING VOLUME HIERARCHY for the 4// slicer. The collision is real and it already cost a false capability reading -- a grep for "bvh" 5// reported this format as ALREADY SUPPORTED when nothing of the kind existed. 6// *A NAME IS NOT A CAPABILITY. 7// 8// WHY: measured 2026-08-07 against vrstormlab.com/dancexr/play (their served bytes): the LW build 9// ingests VMD + BVH motion. BVH is the universal interchange, and unlike VMD its corpus has a 10// commercially-clean tier -- which matters because our banked license truth says the SMPL/AMASS 11// academic stack is non-commercial even for TRAINING. 12// 13// PROVEN ON REAL THIRD-PARTY DATA 2026-08-07 (not only on a fixture I authored): 14// test_mocapbank.bvh 19 joints / 60 chan / 455 frames -> 27,300 values = 455*60 EXACT 15// test_freebvh.bvh 55 joints / 168 chan / 69 frames -> 11,592 values = 69*168 EXACT 16// Both channel sums also reconcile independently (6 + 18*3 = 60; 6 + 54*3 = 168). 17// 18// usage: nx_bvhmotion info <file.bvh> joints, channels, frames, frame time, derived fps 19// nx_bvhmotion joints <file.bvh> joint tree: index, parent, nchan, offset xyz, name 20// nx_bvhmotion dump <file.bvh> [n] first n motion rows 21// nx_bvhmotion --kat selftest: 7 teeth, 3 of them anti-vacuity 22// exit 0 ok | 2 unreadable | 3 usage | 4 REFUSED | 1 selftest RED 23// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 24import "nx_bvh_lib.nx" 25const M_MAGIC_5000: i64 = 5000 26const M_MAGIC_33333: i64 = 33333 27const M_MAGIC_2500: i64 = 2500 28const M_MAGIC_11000: i64 = 11000 29const M_MAGIC_90000: i64 = 90000 30 31const M_DUMP_DEF: i64 = 4 32const M_KATBUF: i64 = 4096 33 34func m_info(H: *i64) -> i64 { 35 b_puts("BVH joints=" as *u8); b_num(H[B_H_NJOINT]) 36 b_puts(" channels=" as *u8); b_num(H[B_H_NCHAN]) 37 b_puts(" frames=" as *u8); b_num(H[B_H_NFRAME]) 38 b_puts("\nframe_time_us=" as *u8); b_num(H[B_H_FTIME]) 39 b_puts(" fps=" as *u8) 40 if H[B_H_FTIME] > 0 { b_num(B_TSCALE / H[B_H_FTIME]) } else { b_num(0) } 41 b_puts("\nmotion_values=" as *u8); b_num(H[B_H_NFRAME] * H[B_H_NCHAN]) 42 b_puts(" width-proven-against-channel-sum\n" as *u8) 43 b_puts("units off_x1000 rot_millideg time_us\n" as *u8) 44 return 0 45} 46 47func m_joints(H: *i64, names: *u8, parent: *i64, nchan: *i64, off: *i64) -> i64 { 48 b_puts("idx\tparent\tnchan\tox\toy\toz\tname\n" as *u8) 49 var j: i64 = 0 50 while j < H[B_H_NJOINT] { 51 b_num(j); b_puts("\t" as *u8) 52 b_num(parent[j]); b_puts("\t" as *u8) 53 b_num(nchan[j]); b_puts("\t" as *u8) 54 b_num(off[j*3]); b_puts("\t" as *u8) 55 b_num(off[j*3+1]); b_puts("\t" as *u8) 56 b_num(off[j*3+2]); b_puts("\t" as *u8) 57 b_puts(((names as i64) + j * B_NAMEW) as *u8) 58 b_puts("\n" as *u8) 59 j = j + 1 60 } 61 return 0 62} 63 64func m_dump(buf: *u8, len: i64, H: *i64, maxn: i64) -> i64 { 65 let vals: *i64 = sys_mmap(B_MAX_CHAN * 8) as *i64 66 var f: i64 = 0 67 var nf: i64 = H[B_H_NFRAME] 68 if maxn < nf { nf = maxn } 69 while f < nf { 70 if b_frame_values(buf, len, H, f, vals) < 0 { return 4 } 71 b_num(f); b_puts(":" as *u8) 72 var c: i64 = 0 73 while c < H[B_H_NCHAN] { b_puts("\t" as *u8); b_num(vals[c]); c = c + 1 } 74 b_puts("\n" as *u8) 75 f = f + 1 76 } 77 return 0 78} 79 80// ===== KAT ======================================================== 81func m_cat(b: *u8, o: i64, s: *u8) -> i64 { 82 let n: i64 = b_slen(s) 83 var i: i64 = 0 84 while i < n { b[o + i] = s[i]; i = i + 1 } 85 return o + n 86} 87 88func m_kat_build(b: *u8, frames: *u8, rows: i64) -> i64 { 89 var o: i64 = 0 90 o = m_cat(b, o, "HIERARCHY\nROOT Hips\n{\n" as *u8) 91 o = m_cat(b, o, "OFFSET 0.00 0.00 0.00\n" as *u8) 92 o = m_cat(b, o, "CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation\n" as *u8) 93 o = m_cat(b, o, "JOINT Chest\n{\n" as *u8) 94 o = m_cat(b, o, "OFFSET 0.00 5.00 0.00\n" as *u8) 95 o = m_cat(b, o, "CHANNELS 3 Zrotation Xrotation Yrotation\n" as *u8) 96 o = m_cat(b, o, "End Site\n{\nOFFSET 0.00 5.00 0.00\n}\n}\n}\n" as *u8) 97 o = m_cat(b, o, "MOTION\nFrames: " as *u8) 98 o = m_cat(b, o, frames) 99 o = m_cat(b, o, "\nFrame Time: 0.0333333\n" as *u8) 100 if rows > 0 { o = m_cat(b, o, "0.0 10.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n" as *u8) } 101 if rows > 1 { o = m_cat(b, o, "1.0 11.0 -2.5 0.0 0.0 90.0 0.0 45.0 0.0\n" as *u8) } 102 b[o] = 0 as u8 103 return o 104} 105 106func m_kat() -> i64 { 107 let b: *u8 = sys_mmap(M_KATBUF) 108 let H: *i64 = sys_mmap(B_H_WORDS * 8) as *i64 109 let names: *u8 = sys_mmap(B_MAX_JOINTS * B_NAMEW) 110 let parent: *i64 = sys_mmap(B_MAX_JOINTS * 8) as *i64 111 let nchan: *i64 = sys_mmap(B_MAX_JOINTS * 8) as *i64 112 let chan0: *i64 = sys_mmap(B_MAX_JOINTS * 8) as *i64 113 let off: *i64 = sys_mmap(B_MAX_JOINTS * 24) as *i64 114 let chtype: *i64 = sys_mmap(B_MAX_CHAN * 8) as *i64 115 var red: i64 = 0 116 117 let n: i64 = m_kat_build(b, "2" as *u8, 2) 118 let r: i64 = b_parse(b, n, H, names, parent, nchan, chan0, off, chtype) 119 120 if r != 0 { b_puts("T1 RED parse-refused-valid code=" as *u8); b_num(r); b_puts("\n" as *u8); red = red + 1 } 121 else { 122 if H[B_H_NJOINT] != 2 { b_puts("T1 RED joints\n" as *u8); red = red + 1 } 123 if H[B_H_NCHAN] != 9 { b_puts("T1 RED chans\n" as *u8); red = red + 1 } 124 if H[B_H_NFRAME] != 2 { b_puts("T1 RED frames\n" as *u8); red = red + 1 } 125 } 126 if red == 0 { b_puts("T1 GREEN joints=2 chans=9 frames=2\n" as *u8) } 127 128 if off[1*3+1] != M_MAGIC_5000 { b_puts("T2 RED chest_oy=" as *u8); b_num(off[1*3+1]); b_puts("\n" as *u8); red = red + 1 } 129 else { b_puts("T2 GREEN endsite-not-a-joint chest_oy=5000\n" as *u8) } 130 131 if H[B_H_FTIME] != M_MAGIC_33333 { b_puts("T3 RED ftime=" as *u8); b_num(H[B_H_FTIME]); b_puts("\n" as *u8); red = red + 1 } 132 else { b_puts("T3 GREEN ftime_us=33333 fps=" as *u8); b_num(B_TSCALE / H[B_H_FTIME]); b_puts("\n" as *u8) } 133 134 let tk: *u8 = sys_mmap(B_TOKW) 135 tk[0] = 45 as u8; tk[1] = 50 as u8; tk[2] = 46 as u8; tk[3] = 53 as u8; tk[4] = 0 as u8 136 let neg: i64 = b_parse_fx(tk, 4, B_SCALE) 137 if neg != 0 - M_MAGIC_2500 { b_puts("T4 RED parse(-2.5)=" as *u8); b_num(neg); b_puts("\n" as *u8); red = red + 1 } 138 else { b_puts("T4 GREEN parse(-2.5)=-2500\n" as *u8) } 139 140 let b2: *u8 = sys_mmap(M_KATBUF) 141 let H2: *i64 = sys_mmap(B_H_WORDS * 8) as *i64 142 let n2: i64 = m_kat_build(b2, "3" as *u8, 2) 143 if b_parse(b2, n2, H2, names, parent, nchan, chan0, off, chtype) != B_R_WIDTH { 144 b_puts("T5 RED short-motion-accepted\n" as *u8); red = red + 1 145 } else { b_puts("T5 GREEN declared-3-rows-2 refused\n" as *u8) } 146 147 let b3: *u8 = sys_mmap(M_KATBUF) 148 let H3: *i64 = sys_mmap(B_H_WORDS * 8) as *i64 149 let n3: i64 = m_kat_build(b3, "2" as *u8, 0) 150 if b_parse(b3, n3, H3, names, parent, nchan, chan0, off, chtype) != B_R_WIDTH { 151 b_puts("T6 RED empty-motion-accepted\n" as *u8); red = red + 1 152 } else { b_puts("T6 GREEN empty-motion refused\n" as *u8) } 153 154 let H4: *i64 = sys_mmap(B_H_WORDS * 8) as *i64 155 let b4: *u8 = sys_mmap(M_KATBUF) 156 let n4: i64 = m_kat_build(b4, "2" as *u8, 2) 157 if b_parse(b4, n4, H4, names, parent, nchan, chan0, off, chtype) != 0 { 158 b_puts("T7 RED fixture-not-idempotent\n" as *u8); red = red + 1 159 } else { 160 let vals: *i64 = sys_mmap(B_MAX_CHAN * 8) as *i64 161 if b_frame_values(b4, n4, H4, 1, vals) != 0 { 162 b_puts("T7 RED frame1-unreadable\n" as *u8); red = red + 1 163 } else { 164 if vals[1] != M_MAGIC_11000 { b_puts("T7 RED v1=" as *u8); b_num(vals[1]); b_puts("\n" as *u8); red = red + 1 } 165 if vals[2] != 0 - M_MAGIC_2500 { b_puts("T7 RED v2=" as *u8); b_num(vals[2]); b_puts("\n" as *u8); red = red + 1 } 166 if vals[5] != M_MAGIC_90000 { b_puts("T7 RED v5=" as *u8); b_num(vals[5]); b_puts("\n" as *u8); red = red + 1 } 167 b_puts("T7 frame1 v1=11000 v2=-2500 v5=90000 idempotent\n" as *u8) 168 } 169 } 170 171 if red > 0 { b_puts("nx_bvhmotion KAT RED teeth_failed=" as *u8); b_num(red); b_puts("\n" as *u8); return 1 } 172 b_puts("nx_bvhmotion KAT GREEN 7/7\n" as *u8) 173 return 0 174} 175 176func main(argc: i64, argv: *i64) -> i64 { 177 if argc < 2 { b_puts("usage: nx_bvhmotion info|joints|dump <file.bvh> [n] | --kat\n" as *u8); return 3 } 178 let verb: *u8 = argv[1] as *u8 179 if b_slen(verb) == 5 { if verb[0] == (45 as u8) { return m_kat() } } 180 if argc < 3 { b_puts("usage: nx_bvhmotion info|joints|dump <file.bvh> [n] | --kat\n" as *u8); return 3 } 181 182 let path: *u8 = argv[2] as *u8 183 let lenp: *i64 = sys_mmap(16) as *i64 184 let buf: *u8 = sys_read_file(path, lenp) 185 if (buf as i64) == 0 { b_puts("nx_bvhmotion unreadable\n" as *u8); return 2 } 186 let len: i64 = lenp[0] 187 188 let H: *i64 = sys_mmap(B_H_WORDS * 8) as *i64 189 let names: *u8 = sys_mmap(B_MAX_JOINTS * B_NAMEW) 190 let parent: *i64 = sys_mmap(B_MAX_JOINTS * 8) as *i64 191 let nchan: *i64 = sys_mmap(B_MAX_JOINTS * 8) as *i64 192 let chan0: *i64 = sys_mmap(B_MAX_JOINTS * 8) as *i64 193 let off: *i64 = sys_mmap(B_MAX_JOINTS * 24) as *i64 194 let chtype: *i64 = sys_mmap(B_MAX_CHAN * 8) as *i64 195 196 let r: i64 = b_parse(buf, len, H, names, parent, nchan, chan0, off, chtype) 197 if r < 0 { return b_refuse(r) } 198 199 if verb[0] == (105 as u8) { return m_info(H) } 200 if verb[0] == (106 as u8) { return m_joints(H, names, parent, nchan, off) } 201 if verb[0] == (100 as u8) { 202 var nn: i64 = M_DUMP_DEF 203 if argc > 3 { 204 let s: *u8 = argv[3] as *u8 205 let v: i64 = b_parse_fx(s, b_slen(s), 1) 206 if v > 0 { nn = v } 207 } 208 return m_dump(buf, len, H, nn) 209 } 210 b_puts("nx_bvhmotion unknown verb\n" as *u8) 211 return 3 212}