Skip to main content

wde_animation/
clip.rs

1use std::collections::HashMap;
2
3use bevy::prelude::*;
4
5/// How values are interpolated between two keyframes.
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub enum Interpolation {
8    /// Holds the value of the previous keyframe.
9    Step,
10    Linear
11}
12
13/// Values over time, sorted by time.
14#[derive(Clone, Debug)]
15pub struct Keyframes<T> {
16    pub times: Vec<f32>,
17    pub values: Vec<T>,
18    pub interpolation: Interpolation
19}
20
21/// Value type that can be interpolated between keyframes.
22pub trait Interpolate: Copy {
23    fn interpolate(from: Self, to: Self, t: f32) -> Self;
24}
25impl Interpolate for Vec3 {
26    fn interpolate(from: Self, to: Self, t: f32) -> Self {
27        from.lerp(to, t)
28    }
29}
30impl Interpolate for Quat {
31    fn interpolate(from: Self, to: Self, t: f32) -> Self {
32        from.slerp(to, t)
33    }
34}
35
36impl<T: Interpolate> Keyframes<T> {
37    /// Value at `time`, held constant before the first and after the last keyframe.
38    pub fn sample(&self, time: f32) -> Option<T> {
39        let count = self.times.len().min(self.values.len());
40        if count == 0 {
41            return None;
42        }
43        let next = self.times[..count].partition_point(|&t| t <= time);
44        if next == 0 {
45            return Some(self.values[0]);
46        }
47        if next == count {
48            return Some(self.values[count - 1]);
49        }
50        let (from, to) = (self.times[next - 1], self.times[next]);
51        Some(match self.interpolation {
52            Interpolation::Step => self.values[next - 1],
53            Interpolation::Linear => T::interpolate(
54                self.values[next - 1],
55                self.values[next],
56                (time - from) / (to - from).max(f32::EPSILON)
57            )
58        })
59    }
60}
61
62/// Animation of one bone. Missing channels keep the bone's rest value.
63#[derive(Clone, Debug, Default)]
64pub struct BoneTrack {
65    pub translation: Option<Keyframes<Vec3>>,
66    pub rotation: Option<Keyframes<Quat>>,
67    pub scale: Option<Keyframes<Vec3>>
68}
69impl BoneTrack {
70    /// Local transform of the bone at `time`.
71    pub fn sample(&self, time: f32, rest: &Transform) -> Transform {
72        let sample = |keys: &Option<Keyframes<Vec3>>, default| {
73            keys.as_ref()
74                .and_then(|k| k.sample(time))
75                .unwrap_or(default)
76        };
77        Transform {
78            translation: sample(&self.translation, rest.translation),
79            rotation: self
80                .rotation
81                .as_ref()
82                .and_then(|k| k.sample(time))
83                .unwrap_or(rest.rotation),
84            scale: sample(&self.scale, rest.scale)
85        }
86    }
87}
88
89/// Keyframed animation of a set of bones, identified by name.
90#[derive(Asset, TypePath, Clone, Debug, Default)]
91pub struct AnimationClip {
92    pub name: String,
93    /// Time of the last keyframe, in seconds.
94    pub duration: f32,
95    pub tracks: HashMap<String, BoneTrack>,
96    /// Ground speed the clip was authored for (glTF extras `ground_speed`), to match the playback
97    /// speed to the movement speed.
98    pub ground_speed: Option<f32>
99}