# pose.ludic - the sampled LOCAL transforms turned into the model-frame deltas `skin_pose` wants. # skin_pose folds a delta D in as local = (G_p^-1 . D . G_p) . R_rest, and a channel gives the # absolute local L, so D = G_p . (L . R_rest^-1) . G_p^-1 (a root: D = L . R_rest^-1) # eight quaternions of scratch, made with the state function pose_parts_new() -> []floats { let l = new []floats for k in 0 .. 8 { push(l, floats(4)) } return l } function pose_part(anim_st: AnimState, i: int) -> floats { return anim_st.parts[i] } export function anim_to_pose(anim_st: mut AnimState, sk: Skin, rot: floats, pos: floats, hit: words) -> void { let l = pose_part(anim_st, 0) let rinv = pose_part(anim_st, 1) let gp = pose_part(anim_st, 2) let gpi = pose_part(anim_st, 3) let tmp = pose_part(anim_st, 4) let d = pose_part(anim_st, 5) let v = pose_part(anim_st, 6) for i in 0 .. sk.n_nodes { let p = sk.par[i] if (hit[i] & 1) != 0 { q_load(l, rot, i) q_load(rinv, sk.rest_r, i) q_conj(rinv, rinv) q_mul(tmp, l, rinv) if p >= 0 { q_load(gp, sk.rest_g, p) q_conj(gpi, gp) q_mul(d, gp, tmp) q_mul(d, d, gpi) } else { q_copy(d, tmp) } q_normalize(d) skin_set_quat(sk, i, d) } if (hit[i] & 2) != 0 and anim_st.positions { let dx = pos[i * 3] - sk.rest_t[i * 3] let dy = pos[i * 3 + 1] - sk.rest_t[i * 3 + 1] let dz = pos[i * 3 + 2] - sk.rest_t[i * 3 + 2] if p >= 0 { q_load(gp, sk.rest_g, p) v3_set(v, dx, dy, dz) q_rotate(v, gp, v) skin_set_offset(sk, i, v[0], v[1], v[2]) } else { skin_set_offset(sk, i, dx, dy, dz) } } } } # The scratch is made ONCE and grown, never allocated per call: a call is per actor per frame. @alloc_ok("grown once to the largest skeleton posed, kept after") function scratch(anim_st: mut AnimState, n: int) -> void { if anim_st.cap >= n { return } anim_st.rot_s = floats(n * 4) anim_st.pos_s = floats(n * 3) anim_st.hit_s = words(n) anim_st.cap = n } # Play `a` at time `ta`, cross-faded toward `b` at `tb` by `blend` (0 is all a, 1 is all b), and # fold it into the joint matrices. `b` may be null. False when there is no skin or no clip. export function anim_play(anim_st: mut AnimState, sk: Skin, a: Clip, ta: float, b: Clip, tb: float, blend: float) -> bool { if sk == null or a == null { return false } let n = sk.n_nodes scratch(anim_st, n) for i in 0 .. n { anim_st.hit_s[i] = 0 } skin_reset(sk) anim_mix(anim_st, a, sk, ta, 1.0, anim_st.rot_s, anim_st.pos_s, anim_st.hit_s) if b != null and blend > 0.001 { anim_mix(anim_st, b, sk, tb, blend, anim_st.rot_s, anim_st.pos_s, anim_st.hit_s) } anim_to_pose(anim_st, sk, anim_st.rot_s, anim_st.pos_s, anim_st.hit_s) skin_pose(sk) return true }