ranim_core/
timeline.rs

1use std::any::Any;
2
3use crate::{
4    Extract,
5    animation::{AnimationCell, CoreItemAnimation, Eval, Static},
6    core_item::{AnyExtractCoreItem, CoreItem, DynItem},
7};
8
9// ANCHOR: Timeline
10/// A timeline for a animations.
11#[derive(Default)]
12pub struct Timeline {
13    anims: Vec<Box<dyn CoreItemAnimation>>,
14    // Followings are states use while constructing
15    cur_sec: f64,
16    /// The start time of the planning static anim.
17    /// When it is some, it means that it is showing and has a planning static anim.
18    planning_static_start_sec: Option<f64>,
19}
20// ANCHOR_END: Timeline
21
22impl Timeline {
23    /// Create a new timeline.
24    pub fn new() -> Self {
25        Self::default()
26    }
27    /// Show the item.
28    ///
29    /// This will start planning an static anim if there isn't an planning static anim.
30    pub fn show(&mut self) -> &mut Self {
31        if self.planning_static_start_sec.is_none() {
32            self.planning_static_start_sec = Some(self.cur_sec)
33        }
34        self
35    }
36    /// Hide the item.
37    ///
38    /// This will submit a static anim if there is an planning static anim.
39    pub fn hide(&mut self) -> &mut Self {
40        // println!("hide");
41        self._submit_planning_static_anim();
42        self
43    }
44    /// Forward the timeline by `secs`
45    pub fn forward(&mut self, secs: f64) -> &mut Self {
46        self.cur_sec += secs;
47        self
48    }
49    /// Forward the timeline to `target_sec` if the current sec is smaller than it.
50    pub fn forward_to(&mut self, target_sec: f64) -> &mut Self {
51        if target_sec > self.cur_sec {
52            self.forward(target_sec - self.cur_sec);
53        }
54        self
55    }
56    fn _submit_planning_static_anim(&mut self) -> bool {
57        // println!("{:?}", self.planning_static_start_sec);
58        if let (Some(start), Some(last_anim)) =
59            (self.planning_static_start_sec.take(), self.anims.last())
60        {
61            let state = last_anim.eval_alpha_dyn(1.0);
62            self.anims.push(Box::new(
63                Static(state)
64                    .into_animation_cell()
65                    .at(start)
66                    .with_duration(self.cur_sec - start)
67                    .with_enabled(last_anim.anim_info().enabled),
68            ));
69            return true;
70        }
71        false
72    }
73    // /// Plays an anim with `anim_func`.
74    // pub fn play_with(&mut self, anim_func: impl FnOnce(T) -> AnimationCell<T>) -> &mut Self {
75    //     self.play(anim_func(self.state.clone()))
76    // }
77    /// Plays an anim.
78    pub fn play<T: AnyExtractCoreItem>(&mut self, anim: AnimationCell<T>) -> &mut Self {
79        self._submit_planning_static_anim();
80        // let res = anim.eval_alpha(1.0);
81        let duration = anim.info.duration_secs;
82        self.anims
83            .push(Box::new(anim.at(self.cur_sec).with_duration(duration)));
84        self.cur_sec += duration;
85        // self.update(res);
86        self.show();
87        self
88    }
89    /// Evaluate the state at `alpha`
90    pub fn eval_at_alpha(&self, alpha: f64) -> Option<(usize, DynItem)> {
91        let (Some(start), Some(end)) = (self.start_sec(), self.end_sec()) else {
92            return None;
93        };
94        self.eval_at_sec(alpha * (end - start) + start)
95    }
96    /// Evaluate the state at `target_sec`
97    pub fn eval_at_sec(&self, target_sec: f64) -> Option<(usize, DynItem)> {
98        let (Some(start), Some(end)) = (self.start_sec(), self.end_sec()) else {
99            return None;
100        };
101
102        if !(start..=end).contains(&target_sec) {
103            return None;
104        }
105
106        self.anims
107            .iter()
108            .enumerate()
109            .filter(|(_, a)| a.anim_info().enabled)
110            .find_map(|(idx, anim)| {
111                // here we use an exclusive range, because we want to use the latest applied anim as the true state
112                let range = anim.anim_info().range();
113                // for the last anim, we use an exclusive range, because we want it take effect in the last frame.
114                if range.contains(&target_sec)
115                    || (idx == self.anims.len() - 1 && target_sec == range.end)
116                {
117                    anim.eval_global_sec_dyn(target_sec)
118                        .map(|dyn_item| (idx, dyn_item))
119                } else {
120                    None
121                }
122            })
123    }
124}
125
126impl TimelineFunc for Timeline {
127    fn start_sec(&self) -> Option<f64> {
128        self.anims.first().map(|a| a.anim_info().range().start)
129    }
130    fn end_sec(&self) -> Option<f64> {
131        self.anims.last().map(|a| a.anim_info().range().end)
132    }
133    fn seal(&mut self) {
134        self._submit_planning_static_anim();
135    }
136    fn cur_sec(&self) -> f64 {
137        self.cur_sec
138    }
139    fn forward(&mut self, duration_secs: f64) {
140        self.cur_sec += duration_secs;
141    }
142    fn show(&mut self) {
143        self.show();
144    }
145    fn hide(&mut self) {
146        self.hide();
147    }
148    fn get_animation_infos(&self) -> Vec<AnimationInfo> {
149        self.anims
150            .iter()
151            .map(|a| AnimationInfo {
152                anim_name: a.anim_name().to_string(),
153                range: a.anim_info().range(),
154            })
155            .collect()
156    }
157    fn type_name(&self) -> &str {
158        ""
159        // self.get_dyn().type_name()
160    }
161    fn eval_primitives_at_sec(&self, target_sec: f64) -> Option<(usize, Vec<CoreItem>)> {
162        self.eval_at_sec(target_sec).map(|(idx, dyn_item)| {
163            let mut items = Vec::new();
164            dyn_item.extract_into(&mut items);
165            (idx, items)
166        })
167    }
168}
169
170// MARK: TimelineFunc
171/// Functions for a timeline
172pub trait TimelineFunc: Any {
173    /// The start sec of the timeline(the start sec of the first animation.)
174    fn start_sec(&self) -> Option<f64>;
175    /// The end sec of the timeline(the end sec of the last animation.)
176    fn end_sec(&self) -> Option<f64>;
177    /// The range of the timeline.
178    fn range_sec(&self) -> Option<std::ops::Range<f64>> {
179        let (Some(start), Some(end)) = (self.start_sec(), self.end_sec()) else {
180            return None;
181        };
182        Some(start..end)
183    }
184    /// Seal the timeline func(submit the planning static anim)
185    fn seal(&mut self);
186    /// The current sec of the timeline.
187    fn cur_sec(&self) -> f64;
188    /// Forward the timeline by `secs`
189    fn forward(&mut self, secs: f64);
190    /// Forward the timeline to `target_sec`
191    fn forward_to(&mut self, target_sec: f64) {
192        let duration = target_sec - self.cur_sec();
193        if duration > 0.0 {
194            self.forward(duration);
195        }
196    }
197    /// Show the item
198    fn show(&mut self);
199    /// Hide the item
200    fn hide(&mut self);
201    /// Get the animation infos
202    fn get_animation_infos(&self) -> Vec<AnimationInfo>;
203    /// The type name of the timeline
204    fn type_name(&self) -> &str;
205
206    // fn eval_sec_any(&self, target_sec: f64) -> Option<(EvalResult<dyn Any>, usize)>;
207    /// Evaluate timeline's primitives at target sec
208    fn eval_primitives_at_sec(&self, target_sec: f64) -> Option<(usize, Vec<CoreItem>)>;
209}
210
211// MARK: TimelinesFunc
212/// Functions for timelines
213pub trait TimelinesFunc {
214    /// Seal timelines
215    fn seal(&mut self);
216    /// Get the max end_sec of the timelines
217    fn max_total_secs(&self) -> f64;
218    /// Sync the timelines
219    fn sync(&mut self);
220    /// Forward all timelines by `sec`
221    fn forward(&mut self, secs: f64);
222    /// Forward all timelines to `target_sec`
223    fn forward_to(&mut self, target_sec: f64);
224}
225
226impl<I: ?Sized, T: TimelineFunc> TimelinesFunc for I
227where
228    for<'a> &'a mut I: IntoIterator<Item = &'a mut T>,
229    for<'a> &'a I: IntoIterator<Item = &'a T>,
230{
231    fn seal(&mut self) {
232        self.into_iter().for_each(|timeline: &mut T| {
233            timeline.seal();
234        });
235    }
236    fn max_total_secs(&self) -> f64 {
237        self.into_iter()
238            .map(|timeline: &T| timeline.cur_sec())
239            .max_by(|a, b| a.partial_cmp(b).unwrap())
240            .unwrap()
241    }
242    fn sync(&mut self) {
243        let max_elapsed_secs = self.max_total_secs();
244        self.into_iter().for_each(|timeline: &mut T| {
245            timeline.forward_to(max_elapsed_secs);
246        });
247    }
248    fn forward(&mut self, secs: f64) {
249        self.into_iter()
250            .for_each(|timeline: &mut T| timeline.forward(secs));
251    }
252    fn forward_to(&mut self, target_sec: f64) {
253        self.into_iter().for_each(|timeline: &mut T| {
254            timeline.forward_to(target_sec);
255        });
256    }
257}
258
259/// Info of an animation
260pub struct AnimationInfo {
261    /// The name of the animation
262    pub anim_name: String,
263    /// The time range of the animation
264    pub range: std::ops::Range<f64>,
265}