ludic/packages/ludic.anim/clip.ludic

75 lines
2.7 KiB
Text

# clip.ludic - a clip: its channels flattened into one run of key times and one of values, and the
# table of every clip read so far, found by name
export const AC_ROT: int = 0
export const AC_POS: int = 1
export property Clip {
name: string = "",
dur: float = 0.0, # seconds: the last key of any channel
n: int = 0, # channels
cnode: words, # target node per channel (the FILE's node index)
cpath: words, # AC_ROT or AC_POS
ckeys: words, # keys per channel
coff: words, # where this channel starts in `times`
cvoff: words, # where it starts in `vals`
times: floats,
vals: floats
}
export state AnimState {
clips: []Clip = new []Clip
positions: bool = false
q_a: floats = floats(4)
q_b: floats = floats(4)
q_cur: floats = floats(4)
parts: []floats = pose_parts_new()
rot_s: floats = null
pos_s: floats = null
hit_s: words = null
cap: int = 0
}
# Keyed translations are off unless asked for: baking keys location on every bone, and a skeleton
# does not translate its joints, so applying them turns rounding into a pose.
function clips_init() -> void {
}
# the clip of that name, or null; names are per file (per body, per species), never shared
export function anim_find(anim_st: AnimState, name: string) -> Clip {
clips_init()
for i in 0 .. len(anim_st.clips) { if anim_st.clips[i].name == name { return anim_st.clips[i] } }
return null
}
export function anim_count(anim_st: AnimState) -> int {
clips_init()
return len(anim_st.clips)
}
# a clip made outside a glTF (a test, a generated clip); a name already held is refused
export function anim_add(anim_st: mut AnimState, c: Clip) -> bool {
if c == null or anim_find(anim_st, c.name) != null { return false }
push(anim_st.clips, c)
return true
}
export function anim_clear(anim_st: mut AnimState) -> void { anim_st.clips = new []Clip }
export function anim_set_positions(anim_st: mut AnimState, on: bool) -> void { anim_st.positions = on }
export function anim_positions(anim_st: AnimState) -> bool { return anim_st.positions }
# Which key pair straddles time t, by halving rather than walking: a grazing clip is three
# hundred keys long and a valley can have dozens of animals posed in a frame.
export function anim_key_at(c: Clip, ch: int, t: float) -> int {
let n = c.ckeys[ch]
let o = c.coff[ch]
if n <= 1 { return 0 }
if t < c.times[o] { return 0 }
if t > c.times[o + n - 1] { return n - 2 }
var lo = 0
var hi = n - 1
while hi - lo > 1 {
let mid = (lo + hi) / 2
if c.times[o + mid] > t { hi = mid } else { lo = mid }
}
return lo
}