Skip to main content

ranim_anims/
lagged.rs

1use ranim_core::animation::Eval;
2
3// MARK: LaggedAnim
4/// The methods to create animations for `Group<T>`
5///
6/// # Example
7/// ```rust,ignore
8/// let item_group: Group::<VItem> = ...;
9/// let anim_lagged = item_group.lagged(0.5, |x| x.fade_in()); # lagged with ratio of 0.5
10/// let anim_not_lagged = item_group.lagged(0.0, |x| x.fade_in()); # not lagged (anim at the same time)
11/// ```
12pub trait LaggedAnim<T: Clone>: Sized + 'static {
13    /// Create a [`Lagged`] anim.
14    fn lagged<E>(&mut self, lag_ratio: f64, anim_func: impl FnMut(&mut T) -> E) -> Lagged<T, E>
15    where
16        E: Eval<Output = T> + 'static;
17}
18
19impl<T: Clone + 'static, I> LaggedAnim<T> for I
20where
21    for<'a> &'a mut I: IntoIterator<Item = &'a mut T>,
22    I: 'static,
23{
24    fn lagged<E>(&mut self, lag_ratio: f64, anim_func: impl FnMut(&mut T) -> E) -> Lagged<T, E>
25    where
26        E: Eval<Output = T> + 'static,
27    {
28        Lagged::new(lag_ratio, self.into_iter().map(anim_func).collect())
29    }
30}
31
32// pub fn lagged<T, I>(
33//     lag_ratio: f64,
34//     mut anim_func: impl FnMut(T) -> E,
35// ) -> impl FnMut(I) -> Lagged<T>
36// where
37//     I: IntoIterator<Item = T>,
38// {
39//     move |target| Lagged::new(target, lag_ratio, &mut anim_func)
40// }
41
42/// The lagged anim.
43///
44/// This is applyable to `IntoIterator<Item = T>`, and this will apply
45/// the anims in the order of the elements with the lag ratio.
46pub struct Lagged<T: Clone, E: Eval<Output = T>> {
47    anims: Vec<E>,
48    lag_ratio: f64,
49    _output: std::marker::PhantomData<fn() -> T>,
50}
51
52impl<T: Clone, E: Eval<Output = T>> Lagged<T, E> {
53    /// Constructor
54    pub fn new(lag_ratio: f64, anims: Vec<E>) -> Self {
55        Self {
56            anims,
57            lag_ratio,
58            _output: std::marker::PhantomData,
59        }
60    }
61}
62
63impl<T: Clone, E: Eval<Output = T>> Eval for Lagged<T, E> {
64    type Output = Vec<T>;
65
66    fn eval_alpha(&self, alpha: f64) -> Self::Output {
67        // -|--
68        //  -|--
69        //   -|--
70        // total_time - unit_time * (1.0 - lag_ratio)  = unit_time * lag_ratio * n
71        // total_time = unit_time * (1.0 + (n - 1) lag_ratio)
72        let unit_time = 1.0 / (1.0 + (self.anims.len() - 1) as f64 * self.lag_ratio);
73        let unit_lagged_time = unit_time * self.lag_ratio;
74        self.anims
75            .iter()
76            .enumerate()
77            .map(|(i, anim)| {
78                let start = unit_lagged_time * i as f64;
79
80                let alpha = (alpha - start) / unit_time;
81                let alpha = alpha.clamp(0.0, 1.0);
82                anim.eval_alpha(alpha)
83            })
84            .collect()
85    }
86}