ranim_core/animation/compose/
sequence.rs1use std::any::type_name;
4
5use crate::animation::eval::DynOutput;
6
7use crate::animation::build::{IntoAnimNode, Unplaced};
8use crate::animation::node::{AnimNode, NodeContent, constant_node};
9
10#[derive(Default)]
15pub struct AnimSequence {
16 pub(super) animations: Vec<AnimNode>,
17 pub(super) cursor_sec: f64,
18}
19
20impl AnimSequence {
21 pub fn new() -> Self {
23 Self::default()
24 }
25
26 fn eval_at_content_sec(&self, target_sec: f64, output: &mut Vec<DynOutput>) {
27 if let Some(animation) = self
28 .animations
29 .iter()
30 .rev()
31 .find(|animation| animation.contains_sec(target_sec, self.cursor_sec))
32 {
33 animation.capture_at(target_sec, output);
34 }
35 }
36
37 pub fn push<A: Unplaced + 'static>(&mut self, animation: A) -> &mut Self {
39 let mut animation = animation.into_anim_node();
40 let duration_secs = animation.duration_secs();
41 animation.shift_by(self.cursor_sec);
42 self.animations.push(animation);
43 self.cursor_sec += duration_secs;
44 self
45 }
46
47 pub fn extend(&mut self, mut sequence: AnimSequence) -> &mut Self {
49 for animation in &mut sequence.animations {
50 animation.shift_by(self.cursor_sec);
51 }
52 self.animations.extend(sequence.animations);
53 self.cursor_sec += sequence.cursor_sec;
54 self
55 }
56
57 pub fn forward(&mut self, secs: f64) -> &mut Self {
59 assert!(
60 secs.is_finite() && secs >= 0.0,
61 "forward duration must be finite and non-negative"
62 );
63 self.cursor_sec += secs;
64 self
65 }
66
67 pub fn forward_to(&mut self, target_sec: f64) -> &mut Self {
69 assert!(
70 target_sec.is_finite() && target_sec >= 0.0,
71 "forward target must be finite and non-negative"
72 );
73 if target_sec > self.cursor_sec {
74 self.forward(target_sec - self.cursor_sec);
75 }
76 self
77 }
78
79 pub fn hold(&mut self, secs: f64) -> &mut Self {
81 assert!(
82 secs.is_finite() && secs >= 0.0,
83 "hold duration must be finite and non-negative"
84 );
85 if secs == 0.0 {
86 return self;
87 }
88
89 let mut state = Vec::new();
90 self.eval_at_content_sec(self.cursor_sec, &mut state);
91
92 if !state.is_empty() {
93 self.animations.push(constant_node(
94 state,
95 self.cursor_sec..self.cursor_sec + secs,
96 ));
97 }
98 self.cursor_sec += secs;
99 self
100 }
101
102 pub fn hold_to(&mut self, target_sec: f64) -> &mut Self {
104 assert!(
105 target_sec.is_finite() && target_sec >= 0.0,
106 "hold target must be finite and non-negative"
107 );
108 if target_sec > self.cursor_sec {
109 self.hold(target_sec - self.cursor_sec);
110 }
111 self
112 }
113
114 pub fn cursor_sec(&self) -> f64 {
116 self.cursor_sec
117 }
118
119 pub fn duration_secs(&self) -> f64 {
121 self.cursor_sec
122 }
123
124 pub fn built_animations(&self) -> &[AnimNode] {
126 &self.animations
127 }
128
129 pub fn into_built_animations(self) -> Vec<AnimNode> {
131 self.animations
132 }
133}
134
135impl Unplaced for AnimSequence {}
136impl IntoAnimNode for AnimSequence {
137 fn into_anim_node(self) -> AnimNode {
140 let duration_secs = self.cursor_sec;
141 let last_at_end = self
145 .animations
146 .iter()
147 .rposition(|animation| animation.contains_sec(duration_secs, duration_secs));
148 let children = self
149 .animations
150 .into_iter()
151 .enumerate()
152 .filter_map(|(index, mut animation)| {
153 if animation.duration_secs() == 0.0 && Some(index) != last_at_end {
154 None
155 } else {
156 if animation.time_range.end == duration_secs && Some(index) != last_at_end {
157 animation.end_inclusive = false;
158 }
159 Some(animation)
160 }
161 })
162 .collect();
163 AnimNode {
164 content: NodeContent::Children(children),
165 internal_time_secs: duration_secs,
166 rate_func: None,
167 time_range: 0.0..duration_secs,
168 end_inclusive: true,
169 enabled: true,
170 anim_name: type_name::<Self>(),
171 }
172 }
173}
174
175#[macro_export]
177macro_rules! seq {
178 ($($animation:expr),* $(,)?) => {
179 {
180 #[allow(unused_mut)]
181 let mut sequence = $crate::animation::compose::sequence::AnimSequence::new();
182 $(sequence.push($animation);)*
183 sequence
184 }
185 };
186}
187
188impl<A: Unplaced + 'static> FromIterator<A> for AnimSequence {
189 fn from_iter<I: IntoIterator<Item = A>>(iter: I) -> Self {
190 let mut sequence = AnimSequence::new();
191 for animation in iter {
192 sequence.push(animation);
193 }
194 sequence
195 }
196}