code wiki / _hdl_build / nx_motion_video_gate.nx

nx_motion_video_gate.nx source

↩ module page · 142 lines · 6591 B

1// nx_motion_video_gate.nx -- prove the S3 loop end-to-end: BUILD a move (data) -> pose the rig via FK per frame 2// -> render the articulated figure -> encode a sovereign ANIMATED PNG = "show the move in a VIDEO". Asserts: 3// T1 the .png is a real APNG (signature + acTL/fcTL/fdAT/IEND + acTL num_frames == N) 4// T2 MOTION happened (frame 0 checksum != mid-frame checksum -- the figure actually moved, not a static loop) 5// T3 a driven JOINT moved (right wrist world-Y spans a real range across the clip = true FK articulation) 6// T4 two DIFFERENT moves (wave vs kick) produce DIFFERENT poses at the same time (the library varies, like t2mesh) 7// Writes knowledge/nx_motion_wave.png (APNG, browser-playable) + knowledge/nx_motion_frame0.png (still, eyeball). 8// license_tier: ORIGINAL expect_exit: 0 9import "nx_syscalls.nx" 10import "nx_skeleton.nx" 11import "nx_figure_render.nx" 12import "nx_movelib.nx" 13import "nx_apng.nx" 14import "nx_png.nx" 15 16func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 17func pn(v: i64) -> i64 { 18 let b: *u8 = sys_mmap(32) as *u8 19 var x: i64 = v; var neg: i64 = 0 20 if x < 0 { neg = 1; x = 0 - x } 21 var i: i64 = 31 22 if x == 0 { b[i] = 48 as u8; i = i - 1 } 23 while x > 0 { b[i] = (48 + x % 10) as u8; x = x / 10; i = i - 1 } 24 if neg == 1 { b[i] = 45 as u8; i = i - 1 } 25 sys_write(1, (b as i64 + i + 1) as *u8, 31 - i) 26 return 0 27} 28func cksum(fb: *i64, n: i64) -> i64 { 29 var s: i64 = 1469598103 30 var i: i64 = 0 31 while i < n { s = (s * 31 + (fb[i] & 0xffffff)) & 0x0fffffffffffffff; i = i + 1 } 32 return s 33} 34func find4(buf: *u8, n: i64, a: i64, b: i64, c: i64, d: i64) -> i64 { 35 var i: i64 = 0 36 while i + 4 <= n { 37 if (buf[i]&0xff)==a { if (buf[i+1]&0xff)==b { if (buf[i+2]&0xff)==c { if (buf[i+3]&0xff)==d { return i } } } } 38 i = i + 1 39 } 40 return 0 - 1 41} 42 43const GW: i64 = 384 44const GH: i64 = 288 45 46func main() -> i64 { 47 hw("=== nx_motion_video_gate -- build a move -> FK -> render -> sovereign APNG (show it in a video) ===\n" as *u8) 48 let sk: i64 = sys_mmap(sk_bytes()) as i64 49 rig_build(sk) 50 let move: i64 = sys_mmap(move_bytes()) as i64 51 move_gen(move, 1) // WAVE 52 let period: i64 = (mv_hdr(move))[1] 53 54 let fb: *i64 = sys_mmap(GW * GH * 8) as *i64 55 let zb: *i64 = sys_mmap(GW * GH * 8) as *i64 56 let apbuf: *u8 = sys_mmap(16 * 1024 * 1024) 57 let seq: *i64 = sys_mmap(8) as *i64; seq[0] = 0 58 let nframes: i64 = 16 59 var delay_cs: i64 = period / nframes / 10 60 if delay_cs < 3 { delay_cs = 3 } 61 let scale: i64 = 86 62 let camyaw: i64 = md_deg(15) 63 64 var o: i64 = apng_open(apbuf, GW, GH, nframes) 65 var sum0: i64 = 0 66 var summid: i64 = 0 67 var wr_min: i64 = 2000000000 68 var wr_max: i64 = 0 - 2000000000 69 var f: i64 = 0 70 while f < nframes { 71 let t: i64 = f * period / nframes 72 move_pose_at(move, sk, t) 73 sk_update(sk) 74 let bwrr: *i64 = sk_bone(sk, RG_WRR) // right wrist world-Y (swings as the raised arm bobs) 75 var wr: i64 = bwrr[16] 76 if wr > 6000 { wr = 6000 } 77 if wr < 0 - 6000 { wr = 0 - 6000 } 78 if wr < wr_min { wr_min = wr } 79 if wr > wr_max { wr_max = wr } 80 rig_draw(sk, fb, zb, GW, GH, camyaw, scale) 81 if f == 0 { 82 write_png(fb, GW, GH, "knowledge/nx_motion_frame0.png" as *u8) 83 sum0 = cksum(fb, GW * GH) 84 } 85 if f == nframes / 2 { summid = cksum(fb, GW * GH) } 86 var first: i64 = 0 87 if f == 0 { first = 1 } 88 o = apng_frame(apbuf, o, seq, fb, GW, GH, delay_cs, first) 89 f = f + 1 90 } 91 o = apng_close(apbuf, o) 92 let fd: i64 = sys_openat_wr("knowledge/nx_motion_wave.png" as *u8, 0x1a4) 93 if fd >= 0 { sys_write(fd, apbuf, o); sys_close(fd) } 94 hw(" wrote knowledge/nx_motion_wave.png bytes="); pn(o); hw(" frames="); pn(nframes); hw("\n" as *u8) 95 96 var fails: i64 = 0 97 // T1 valid APNG 98 var t1: i64 = 1 99 if (apbuf[0]&0xff) != 137 { t1 = 0 } 100 if find4(apbuf, o, 97, 99, 84, 76) < 0 { t1 = 0 } // acTL 101 if find4(apbuf, o, 102, 99, 84, 76) < 0 { t1 = 0 } // fcTL 102 if find4(apbuf, o, 102, 100, 65, 84) < 0 { t1 = 0 } // fdAT 103 if find4(apbuf, o, 73, 69, 78, 68) < 0 { t1 = 0 } // IEND 104 let actl: i64 = find4(apbuf, o, 97, 99, 84, 76) 105 var nf_field: i64 = 0 106 if actl >= 0 { nf_field = ((apbuf[actl+4]&0xff)<<24)|((apbuf[actl+5]&0xff)<<16)|((apbuf[actl+6]&0xff)<<8)|(apbuf[actl+7]&0xff) } 107 if nf_field != nframes { t1 = 0 } 108 if t1 == 1 { hw("T1 PASS valid APNG (sig+acTL+fcTL+fdAT+IEND; acTL num_frames="); pn(nf_field); hw(")\n" as *u8) } 109 else { fails = fails + 1; hw("T1 FAIL not a valid APNG (nf_field="); pn(nf_field); hw(")\n" as *u8) } 110 // T2 motion present 111 if sum0 != summid { hw("T2 PASS motion present (frame0 checksum != mid-frame checksum)\n" as *u8) } 112 else { fails = fails + 1; hw("T2 FAIL frames identical -> no motion\n" as *u8) } 113 // T3 joint articulated 114 let wr_span: i64 = wr_max - wr_min 115 if wr_span > 200 { hw("T3 PASS right-wrist FK span="); pn(wr_span); hw(" units (true articulation)\n" as *u8) } 116 else { fails = fails + 1; hw("T3 FAIL wrist span too small="); pn(wr_span); hw("\n" as *u8) } 117 // T4 distinct moves 118 let move2: i64 = sys_mmap(move_bytes()) as i64 119 move_gen(move2, 4) // KICK 120 let tq: i64 = period / 4 121 move_pose_at(move, sk, tq); sk_update(sk) 122 let barm: *i64 = sk_bone(sk, RG_ANR) 123 let wave_ankleR: i64 = barm[16] 124 let bwr: *i64 = sk_bone(sk, RG_WRR) 125 let wave_wristR: i64 = bwr[16] 126 let m2p: *i64 = mv_hdr(move2) 127 let m2t: i64 = m2p[1] / 4 128 move_pose_at(move2, sk, m2t); sk_update(sk) 129 let barm2: *i64 = sk_bone(sk, RG_ANR) 130 let kick_ankleR: i64 = barm2[16] 131 let bwr2: *i64 = sk_bone(sk, RG_WRR) 132 let kick_wristR: i64 = bwr2[16] 133 var t4: i64 = 0 134 if wave_ankleR != kick_ankleR { t4 = 1 } 135 if wave_wristR != kick_wristR { t4 = 1 } 136 if t4 == 1 { hw("T4 PASS wave vs kick pose DIFFERENT (wave wristY="); pn(wave_wristR); hw(" ankleY="); pn(wave_ankleR); hw(" | kick wristY="); pn(kick_wristR); hw(" ankleY="); pn(kick_ankleR); hw(")\n" as *u8) } 137 else { fails = fails + 1; hw("T4 FAIL moves identical\n" as *u8) } 138 139 if fails == 0 { hw("MOTION-VIDEO-GATE 4/4 GREEN -- move-as-data -> FK -> render -> sovereign APNG; motion + articulation + distinct moves proven\n" as *u8); sys_exit(0); return 0 } 140 hw("MOTION-VIDEO-GATE RED fails="); pn(fails); hw("\n" as *u8) 141 sys_exit(1); return 1 142}