1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
use crate::prelude::{
    chainable_curves::ChainableCurve,
    chainable_curves::{LinearPiecewiseCurve, SmoothCurve},
    Curve, Point,
};
use dyn_clone::{clone_trait_object, DynClone};
use num_traits::Float;
use std::{fmt::Display, time::Duration};

/// Trait for defining keyframes structs. Is defined for chainable and non-chainable curves, but is only really useful for non-chainable and only serves as a bloated abstraction when used with chainable.
pub trait KeyFrames: DynClone {
    type Value: Clone + Display + Send + Sync;
    fn get_value(&self, time: Duration) -> Self::Value;
}

clone_trait_object!(KeyFrames<Value = f32>);
clone_trait_object!(KeyFrames<Value = f64>);
clone_trait_object!(KeyFrames<Value = Point<f32>>);
clone_trait_object!(KeyFrames<Value = Point<f64>>);

#[derive(Clone)]
pub struct ScalarKeyFrames<
    T: Clone + Display + Float + Send + Sync + From<f64>,
    C: Curve<Value = T>,
> {
    pub curve: C,
}

impl<
        T: Clone + Display + Float + Send + Sync + From<f64>,
        C: ChainableCurve<Value = T> + Curve<Value = T> + Clone,
    > KeyFrames for ScalarKeyFrames<T, C>
{
    type Value = T;
    fn get_value(&self, time: Duration) -> Self::Value
    where
        <C as Curve>::Value: From<f64>,
    {
        From::<T>::from(self.curve.get_value(From::<f64>::from(time.as_secs_f64())))
    }
}

impl<
        T: Clone + Display + Float + Send + Sync + From<f64>,
        C: ChainableCurve<Value = T> + Curve<Value = T> + Clone,
    > ScalarKeyFrames<T, C>
{
    pub fn new(data: Vec<(f64, T)>) -> Self {
        Self {
            curve: C::new(
                data.iter()
                    .map(|(t, v)| (From::<f64>::from(*t), *v))
                    .collect::<Vec<_>>(),
            ),
        }
    }
}

pub type SmoothKeyframes<T> = ScalarKeyFrames<T, SmoothCurve<T>>;
pub type LinearKeyframes<T> = ScalarKeyFrames<T, LinearPiecewiseCurve<T>>;