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}