code wiki / (root) / nx_movelib.nx

nx_movelib.nx source

↩ module page · 228 lines · 13683 B

1// nx_movelib.nx -- MOTION AS DATA (swap+motion census SCOPE B, the operator's headline: a synthetic human wants 2// a move that isn't in the library -> BUILD it). A MOVE is DATA: keyframes over a loop period, each keyframe = a 3// per-bone {yaw,pitch} pose. move_gen is a PARAMETRIC generator (data-driven vocabulary, grows by adding a 4// recipe -- exactly like nx_t2mesh grows objects; NOT neural MDM, which is the S6 rung). move_pose_at interpolates 5// the keyframes and poses the skeleton via nx_skeleton FK. Both the synthetic human AND the game system draw from 6// the same library. Angles in rad*4096 (nx_itrig). license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_skeleton.nx" 9import "nx_itrig.nx" 10import "nx_figure_render.nx" // RIG_NB + RG_* bone-index consts (the rig moves target) 11const MOVE_MAGIC_12868: i64 = 12868 12const MOVE_MAGIC_1200: i64 = 1200 13const MOVE_MAGIC_1600: i64 = 1600 14const MOVE_MAGIC_1400: i64 = 1400 15const MOVE_MAGIC_1800: i64 = 1800 16const MOVE_MAGIC_1500: i64 = 1500 17const MOVE_MAGIC_2000: i64 = 2000 18const MOVE_MAGIC_4096: i64 = 4096 19 20const MOVE_MAXK: i64 = 8 // max keyframes 21 22func mv_hdr(base: i64) -> *i64 { return base as *i64 } // [0]=nk [1]=period_ms 23func mv_time(base: i64) -> *i64 { return (base + 64) as *i64 } // [k] = key time ms 24// pose slot for (key k, bone b): yaw at +0, pitch at +8 (2 i64) 25func mv_pose(base: i64, k: i64, b: i64) -> *i64 { return (base + 64 + MOVE_MAXK * 8 + (k * RIG_NB + b) * 16) as *i64 } 26func move_bytes() -> i64 { return 64 + MOVE_MAXK * 8 + MOVE_MAXK * RIG_NB * 16 + 64 } 27 28// deg -> rad*4096 (IT_PI 12868 == 180 deg) 29func md_deg(d: i64) -> i64 { return d * MOVE_MAGIC_12868 / 180 } 30 31func mv_zero(base: i64) -> i64 { 32 var k: i64 = 0 33 while k < MOVE_MAXK { 34 var b: i64 = 0 35 while b < RIG_NB { let p: *i64 = mv_pose(base, k, b); p[0] = 0; p[1] = 0; b = b + 1 } 36 k = k + 1 37 } 38 return 0 39} 40func mv_set(base: i64, k: i64, b: i64, yaw: i64, pitch: i64) -> i64 { let p: *i64 = mv_pose(base, k, b); p[0] = yaw; p[1] = pitch; return 0 } 41// author evenly-spaced key TIMES over [0, period] (nk keys; key nk-1 sits at period == a copy of key 0 for a seamless loop) 42func mv_times(base: i64, nk: i64, period: i64) -> i64 { 43 let h: *i64 = mv_hdr(base); h[0] = nk; h[1] = period 44 let t: *i64 = mv_time(base) 45 var k: i64 = 0 46 while k < nk { t[k] = k * period / (nk - 1); k = k + 1 } 47 return 0 48} 49 50// ---- the move vocabulary (parametric; grows as data) -------------------------------------------------- 51func move_name(id: i64) -> *u8 { 52 if id == 1 { return "wave" as *u8 } 53 if id == 2 { return "cheer" as *u8 } 54 if id == 3 { return "sway" as *u8 } 55 if id == 4 { return "kick" as *u8 } 56 if id == 5 { return "lookaround" as *u8 } 57 if id == 6 { return "armcircle" as *u8 } 58 if id == 7 { return "clap" as *u8 } 59 if id == 8 { return "punch" as *u8 } 60 if id == 9 { return "bow" as *u8 } 61 if id == 10 { return "jumpingjack" as *u8 } 62 return "idle" as *u8 63} 64func move_id_of(prompt: *u8) -> i64 { 65 if mv_has(prompt, "wave" as *u8) == 1 { return 1 } 66 if mv_has(prompt, "hello" as *u8) == 1 { return 1 } 67 if mv_has(prompt, "cheer" as *u8) == 1 { return 2 } 68 if mv_has(prompt, "celebrat" as *u8) == 1 { return 2 } 69 if mv_has(prompt, "victory" as *u8) == 1 { return 2 } 70 if mv_has(prompt, "sway" as *u8) == 1 { return 3 } 71 if mv_has(prompt, "dance" as *u8) == 1 { return 3 } 72 if mv_has(prompt, "kick" as *u8) == 1 { return 4 } 73 if mv_has(prompt, "march" as *u8) == 1 { return 4 } 74 if mv_has(prompt, "look" as *u8) == 1 { return 5 } 75 if mv_has(prompt, "circle" as *u8) == 1 { return 6 } 76 if mv_has(prompt, "stretch" as *u8) == 1 { return 6 } 77 if mv_has(prompt, "clap" as *u8) == 1 { return 7 } 78 if mv_has(prompt, "applau" as *u8) == 1 { return 7 } 79 if mv_has(prompt, "punch" as *u8) == 1 { return 8 } 80 if mv_has(prompt, "jab" as *u8) == 1 { return 8 } 81 if mv_has(prompt, "bow" as *u8) == 1 { return 9 } 82 if mv_has(prompt, "jump" as *u8) == 1 { return 10 } 83 if mv_has(prompt, "jack" as *u8) == 1 { return 10 } 84 return 0 85} 86func mv_has(s: *u8, kw: *u8) -> i64 { 87 var i: i64 = 0 88 while s[i] != (0 as u8) { 89 var k: i64 = 0 90 var stop: i64 = 0 91 while stop == 0 { 92 if kw[k] == (0 as u8) { stop = 1 } else { 93 let sc: *u8 = (s as i64 + i + k) as *u8 94 if sc[0] != kw[k] { stop = 2 } else { k = k + 1 } 95 } 96 } 97 if stop == 1 { return 1 } 98 i = i + 1 99 } 100 return 0 101} 102 103// build a move recipe into base for the given id (the parametric "generator"). Pitch(Rz) raises a limb in the 104// frontal plane; yaw(Ry) turns it. Right-side raises are +pitch, left-side raises are -pitch (mirror). 105func move_gen(base: i64, id: i64) -> i64 { 106 if id == 1 { // WAVE: right arm raised, swinging up/down (visible wave) 107 mv_times(base, 5, MOVE_MAGIC_1200); mv_zero(base) 108 mv_set(base, 0, RG_SHR, 0, md_deg(48)); mv_set(base, 0, RG_ELR, md_deg(16), 0) 109 mv_set(base, 1, RG_SHR, 0, md_deg(76)); mv_set(base, 1, RG_ELR, 0 - md_deg(14), 0) 110 mv_set(base, 2, RG_SHR, 0, md_deg(48)); mv_set(base, 2, RG_ELR, md_deg(16), 0) 111 mv_set(base, 3, RG_SHR, 0, md_deg(76)); mv_set(base, 3, RG_ELR, 0 - md_deg(14), 0) 112 mv_set(base, 4, RG_SHR, 0, md_deg(48)); mv_set(base, 4, RG_ELR, md_deg(16), 0) 113 return 0 114 } 115 if id == 2 { // CHEER: both arms up, small bounce 116 mv_times(base, 4, 1000); mv_zero(base) 117 mv_set(base, 0, RG_SHR, 0, md_deg(60)); mv_set(base, 0, RG_SHL, 0, 0 - md_deg(60)) 118 mv_set(base, 1, RG_SHR, 0, md_deg(72)); mv_set(base, 1, RG_SHL, 0, 0 - md_deg(72)) 119 mv_set(base, 2, RG_SHR, 0, md_deg(60)); mv_set(base, 2, RG_SHL, 0, 0 - md_deg(60)) 120 mv_set(base, 3, RG_SHR, 0, md_deg(60)); mv_set(base, 3, RG_SHL, 0, 0 - md_deg(60)) 121 return 0 122 } 123 if id == 3 { // SWAY / dance: spine + head sway, arms counter-swing 124 mv_times(base, 5, MOVE_MAGIC_1600); mv_zero(base) 125 mv_set(base, 0, RG_SPINE, md_deg(16), 0); mv_set(base, 0, RG_NECK, 0 - md_deg(12), 0); mv_set(base, 0, RG_SHR, 0, md_deg(28)); mv_set(base, 0, RG_SHL, 0, 0 - md_deg(14)) 126 mv_set(base, 1, RG_SPINE, 0 - md_deg(16), 0); mv_set(base, 1, RG_NECK, md_deg(12), 0); mv_set(base, 1, RG_SHR, 0, md_deg(14)); mv_set(base, 1, RG_SHL, 0, 0 - md_deg(28)) 127 mv_set(base, 2, RG_SPINE, md_deg(16), 0); mv_set(base, 2, RG_NECK, 0 - md_deg(12), 0); mv_set(base, 2, RG_SHR, 0, md_deg(28)); mv_set(base, 2, RG_SHL, 0, 0 - md_deg(14)) 128 mv_set(base, 3, RG_SPINE, 0 - md_deg(16), 0); mv_set(base, 3, RG_NECK, md_deg(12), 0); mv_set(base, 3, RG_SHR, 0, md_deg(14)); mv_set(base, 3, RG_SHL, 0, 0 - md_deg(28)) 129 mv_set(base, 4, RG_SPINE, md_deg(16), 0); mv_set(base, 4, RG_NECK, 0 - md_deg(12), 0); mv_set(base, 4, RG_SHR, 0, md_deg(28)); mv_set(base, 4, RG_SHL, 0, 0 - md_deg(14)) 130 return 0 131 } 132 if id == 4 { // KICK / march: legs alternate, arms counter 133 mv_times(base, 5, MOVE_MAGIC_1400); mv_zero(base) 134 mv_set(base, 0, RG_HIPR, 0, md_deg(40)); mv_set(base, 0, RG_SHL, 0, 0 - md_deg(30)) 135 mv_set(base, 1, RG_HIPL, 0, 0 - md_deg(40)); mv_set(base, 1, RG_SHR, 0, md_deg(30)) 136 mv_set(base, 2, RG_HIPR, 0, md_deg(40)); mv_set(base, 2, RG_SHL, 0, 0 - md_deg(30)) 137 mv_set(base, 3, RG_HIPL, 0, 0 - md_deg(40)); mv_set(base, 3, RG_SHR, 0, md_deg(30)) 138 mv_set(base, 4, RG_HIPR, 0, md_deg(40)); mv_set(base, 4, RG_SHL, 0, 0 - md_deg(30)) 139 return 0 140 } 141 if id == 5 { // LOOKAROUND: head + upper spine yaw sweep 142 mv_times(base, 5, MOVE_MAGIC_1800); mv_zero(base) 143 mv_set(base, 0, RG_NECK, md_deg(35), 0); mv_set(base, 0, RG_CHEST, md_deg(10), 0) 144 mv_set(base, 1, RG_NECK, 0, 0) 145 mv_set(base, 2, RG_NECK, 0 - md_deg(35), 0); mv_set(base, 2, RG_CHEST, 0 - md_deg(10), 0) 146 mv_set(base, 3, RG_NECK, 0, 0) 147 mv_set(base, 4, RG_NECK, md_deg(35), 0); mv_set(base, 4, RG_CHEST, md_deg(10), 0) 148 return 0 149 } 150 if id == 6 { // ARMCIRCLE / stretch: both arms sweep through pitch phases 151 mv_times(base, 5, MOVE_MAGIC_1500); mv_zero(base) 152 mv_set(base, 0, RG_SHR, 0, md_deg(18)); mv_set(base, 0, RG_SHL, 0, 0 - md_deg(18)) 153 mv_set(base, 1, RG_SHR, 0, md_deg(50)); mv_set(base, 1, RG_SHL, 0, 0 - md_deg(50)) 154 mv_set(base, 2, RG_SHR, 0, md_deg(78)); mv_set(base, 2, RG_SHL, 0, 0 - md_deg(78)) 155 mv_set(base, 3, RG_SHR, 0, md_deg(50)); mv_set(base, 3, RG_SHL, 0, 0 - md_deg(50)) 156 mv_set(base, 4, RG_SHR, 0, md_deg(18)); mv_set(base, 4, RG_SHL, 0, 0 - md_deg(18)) 157 return 0 158 } 159 if id == 7 { // CLAP: forearms swing IN together, then OUT apart (rhythmic) 160 mv_times(base, 5, 900); mv_zero(base) 161 mv_set(base, 0, RG_SHR, 0, md_deg(38)); mv_set(base, 0, RG_ELR, 0 - md_deg(28), 0); mv_set(base, 0, RG_SHL, 0, 0 - md_deg(38)); mv_set(base, 0, RG_ELL, md_deg(28), 0) 162 mv_set(base, 1, RG_SHR, 0, md_deg(42)); mv_set(base, 1, RG_ELR, md_deg(40), 0); mv_set(base, 1, RG_SHL, 0, 0 - md_deg(42)); mv_set(base, 1, RG_ELL, 0 - md_deg(40), 0) 163 mv_set(base, 2, RG_SHR, 0, md_deg(38)); mv_set(base, 2, RG_ELR, 0 - md_deg(28), 0); mv_set(base, 2, RG_SHL, 0, 0 - md_deg(38)); mv_set(base, 2, RG_ELL, md_deg(28), 0) 164 mv_set(base, 3, RG_SHR, 0, md_deg(42)); mv_set(base, 3, RG_ELR, md_deg(40), 0); mv_set(base, 3, RG_SHL, 0, 0 - md_deg(42)); mv_set(base, 3, RG_ELL, 0 - md_deg(40), 0) 165 mv_set(base, 4, RG_SHR, 0, md_deg(38)); mv_set(base, 4, RG_ELR, 0 - md_deg(28), 0); mv_set(base, 4, RG_SHL, 0, 0 - md_deg(38)); mv_set(base, 4, RG_ELL, md_deg(28), 0) 166 return 0 167 } 168 if id == 8 { // PUNCH: alternating forward jabs (one arm extends, other guards) 169 mv_times(base, 5, 1000); mv_zero(base) 170 mv_set(base, 0, RG_SHR, 0, md_deg(16)); mv_set(base, 0, RG_ELR, 0, 0); mv_set(base, 0, RG_SHL, 0, 0 - md_deg(20)); mv_set(base, 0, RG_ELL, md_deg(72), 0) 171 mv_set(base, 1, RG_SHR, 0, md_deg(16)); mv_set(base, 1, RG_ELR, md_deg(72), 0); mv_set(base, 1, RG_SHL, 0, 0 - md_deg(16)); mv_set(base, 1, RG_ELL, 0, 0) 172 mv_set(base, 2, RG_SHR, 0, md_deg(16)); mv_set(base, 2, RG_ELR, 0, 0); mv_set(base, 2, RG_SHL, 0, 0 - md_deg(20)); mv_set(base, 2, RG_ELL, md_deg(72), 0) 173 mv_set(base, 3, RG_SHR, 0, md_deg(16)); mv_set(base, 3, RG_ELR, md_deg(72), 0); mv_set(base, 3, RG_SHL, 0, 0 - md_deg(16)); mv_set(base, 3, RG_ELL, 0, 0) 174 mv_set(base, 4, RG_SHR, 0, md_deg(16)); mv_set(base, 4, RG_ELR, 0, 0); mv_set(base, 4, RG_SHL, 0, 0 - md_deg(20)); mv_set(base, 4, RG_ELL, md_deg(72), 0) 175 return 0 176 } 177 if id == 9 { // BOW: bend forward at the spine, head down, return 178 mv_times(base, 4, MOVE_MAGIC_1600); mv_zero(base) 179 mv_set(base, 1, RG_SPINE, 0, md_deg(44)); mv_set(base, 1, RG_NECK, 0, md_deg(22)); mv_set(base, 1, RG_SHR, 0, md_deg(14)); mv_set(base, 1, RG_SHL, 0, 0 - md_deg(14)) 180 mv_set(base, 2, RG_SPINE, 0, md_deg(44)); mv_set(base, 2, RG_NECK, 0, md_deg(22)); mv_set(base, 2, RG_SHR, 0, md_deg(14)); mv_set(base, 2, RG_SHL, 0, 0 - md_deg(14)) 181 return 0 182 } 183 if id == 10 { // JUMPING JACK: arms up + legs out, then down + together 184 mv_times(base, 5, 1000); mv_zero(base) 185 mv_set(base, 0, RG_SHR, 0, md_deg(8)); mv_set(base, 0, RG_SHL, 0, 0 - md_deg(8)) 186 mv_set(base, 1, RG_SHR, 0, md_deg(86)); mv_set(base, 1, RG_SHL, 0, 0 - md_deg(86)); mv_set(base, 1, RG_HIPR, md_deg(22), 0); mv_set(base, 1, RG_HIPL, 0 - md_deg(22), 0) 187 mv_set(base, 2, RG_SHR, 0, md_deg(8)); mv_set(base, 2, RG_SHL, 0, 0 - md_deg(8)) 188 mv_set(base, 3, RG_SHR, 0, md_deg(86)); mv_set(base, 3, RG_SHL, 0, 0 - md_deg(86)); mv_set(base, 3, RG_HIPR, md_deg(22), 0); mv_set(base, 3, RG_HIPL, 0 - md_deg(22), 0) 189 mv_set(base, 4, RG_SHR, 0, md_deg(8)); mv_set(base, 4, RG_SHL, 0, 0 - md_deg(8)) 190 return 0 191 } 192 // idle: gentle spine sway 193 mv_times(base, 3, MOVE_MAGIC_2000); mv_zero(base) 194 mv_set(base, 0, RG_SPINE, md_deg(6), 0) 195 mv_set(base, 1, RG_SPINE, 0 - md_deg(6), 0) 196 mv_set(base, 2, RG_SPINE, md_deg(6), 0) 197 return 0 198} 199 200// interpolate the move at time t (ms), pose EVERY rig bone on the skeleton (rest bones stay rest), then the 201// caller runs sk_update. Loops over the move period. 202func move_pose_at(moveBase: i64, sk: i64, t: i64) -> i64 { 203 let h: *i64 = mv_hdr(moveBase) 204 let nk: i64 = h[0] 205 let period: i64 = h[1] 206 let tm: *i64 = mv_time(moveBase) 207 var tt: i64 = t 208 if period > 0 { tt = t % period } 209 if tt < 0 { tt = 0 } 210 // find segment [k, k+1] with tm[k] <= tt < tm[k+1] 211 var k: i64 = 0 212 var seg: i64 = 0 213 while k < nk - 1 { if tt >= tm[k] { if tt < tm[k + 1] { seg = k } } k = k + 1 } 214 let t0: i64 = tm[seg] 215 let t1: i64 = tm[seg + 1] 216 var frac: i64 = 0 217 if t1 > t0 { frac = (tt - t0) * MOVE_MAGIC_4096 / (t1 - t0) } 218 var b: i64 = 0 219 while b < RIG_NB { 220 let p0: *i64 = mv_pose(moveBase, seg, b) 221 let p1: *i64 = mv_pose(moveBase, seg + 1, b) 222 let yaw: i64 = p0[0] + (p1[0] - p0[0]) * frac / MOVE_MAGIC_4096 223 let pitch: i64 = p0[1] + (p1[1] - p0[1]) * frac / MOVE_MAGIC_4096 224 sk_pose(sk, b, yaw, pitch) 225 b = b + 1 226 } 227 return 0 228}