ferroui_base/rendering/composition/animations/
key_frame_animation_instance.rs1use super::animation_controller::{AnimationControllerClock, ProgressSpan};
2use super::{
3 AnimationDelayBehavior, AnimationInstanceBase, AnimationIterationBehavior, AnimationStopBehavior,
4 IAnimationInstance, IInterpolator, PropertySetSnapshot, ServerKeyFrame,
5};
6use crate::animation::PlaybackDirection;
7use crate::rendering::composition::expressions::{
8 BuiltInExpressionFfi, Expression, ExpressionEvaluationContext, ExpressionVariant, ExpressionVariantValue,
9};
10use crate::rendering::composition::server::{CompositionProperty, IServerClockItem, ServerCompositor, ServerObjectId};
11use crate::rendering::composition::AnimationCompletion;
12use std::cell::{Cell, RefCell};
13use std::collections::HashSet;
14use std::rc::{Rc, Weak};
15use std::time::Duration;
16
17fn ticks(d: Duration) -> i64 {
19 (d.as_nanos() / 100) as i64
20}
21
22fn total_seconds(ticks: i64) -> f64 {
24 ticks as f64 / 10_000_000.0
25}
26
27fn net_min(a: f64, b: f64) -> f64 {
30 if a.is_nan() || b.is_nan() {
31 f64::NAN
32 } else {
33 a.min(b)
34 }
35}
36
37fn net_max(a: f64, b: f64) -> f64 {
38 if a.is_nan() || b.is_nan() {
39 f64::NAN
40 } else {
41 a.max(b)
42 }
43}
44
45pub struct KeyFrameAnimationInstance<T: ExpressionVariantValue> {
51 base: AnimationInstanceBase,
52 interpolator: &'static dyn IInterpolator<T>,
53 key_frames: Vec<ServerKeyFrame<T>>,
54 final_value: Option<ExpressionVariant>,
55 delay_behavior: AnimationDelayBehavior,
56 delay_time: i64,
57 direction: PlaybackDirection,
58 duration: i64,
59 iteration_behavior: AnimationIterationBehavior,
60 iteration_count: i32,
61 stop_behavior: AnimationStopBehavior,
65 started_at: Cell<i64>,
66 starting_value: Cell<T>,
67 total_duration: i64,
68 finished: Cell<bool>,
69 completion: RefCell<AnimationCompletion>,
72 initial_values: RefCell<Vec<(String, Expression)>>,
75 clock: AnimationControllerClock,
77}
78
79impl<T: ExpressionVariantValue> KeyFrameAnimationInstance<T> {
80 #[allow(clippy::too_many_arguments)]
83 pub fn new(
84 interpolator: &'static dyn IInterpolator<T>,
85 key_frames: Vec<ServerKeyFrame<T>>,
86 snapshot: Rc<PropertySetSnapshot>,
87 final_value: Option<ExpressionVariant>,
88 target: ServerObjectId,
89 delay_behavior: AnimationDelayBehavior,
90 delay_time: Duration,
91 direction: PlaybackDirection,
92 duration: Duration,
93 iteration_behavior: AnimationIterationBehavior,
94 iteration_count: i32,
95 stop_behavior: AnimationStopBehavior,
96 ) -> Rc<KeyFrameAnimationInstance<T>> {
97 let duration = ticks(duration);
98 let delay_time = ticks(delay_time);
99 let mut total_duration = 0;
100 if iteration_behavior == AnimationIterationBehavior::Count {
101 total_duration = delay_time + iteration_count as i64 * duration;
102 }
103 if key_frames.is_empty() {
104 panic!("Animation has no key frames");
105 }
106 if duration <= 0 {
107 panic!("Invalid animation duration");
108 }
109 Rc::new_cyclic(|this: &Weak<KeyFrameAnimationInstance<T>>| KeyFrameAnimationInstance {
110 base: AnimationInstanceBase::new(this.clone(), target, snapshot),
111 interpolator,
112 key_frames,
113 final_value,
114 delay_behavior,
115 delay_time,
116 direction,
117 duration,
118 iteration_behavior,
119 iteration_count,
120 stop_behavior,
121 started_at: Cell::new(0),
122 starting_value: Cell::new(T::default()),
123 total_duration,
124 finished: Cell::new(false),
125 completion: RefCell::new(AnimationCompletion::none()),
126 initial_values: RefCell::new(Vec::new()),
127 clock: AnimationControllerClock::default(),
128 })
129 }
130
131 pub fn set_initial_value_expressions(&self, expressions: Vec<(String, Expression)>) {
135 *self.initial_values.borrow_mut() = expressions;
136 }
137
138 fn progress_span(&self) -> ProgressSpan {
141 let active = match self.iteration_behavior {
142 AnimationIterationBehavior::Count => self.iteration_count.max(0) as i64 * self.duration,
143 AnimationIterationBehavior::Forever => self.duration,
144 };
145 ProgressSpan { delay: self.delay_time, active }
146 }
147
148 pub fn set_completion(&self, completion: AnimationCompletion) {
151 *self.completion.borrow_mut() = completion;
152 }
153
154 fn release_completion_now(&self) {
155 let mut completion = std::mem::take(&mut *self.completion.borrow_mut());
158 completion.release();
159 }
160
161 fn final_key_frame_value(&self, current_value: ExpressionVariant) -> T {
164 let starting = ExpressionVariant::create(self.starting_value.get());
165 self.base.with_target_expression_object(|target| {
166 let ctx = ExpressionEvaluationContext {
167 parameters: Some(&**self.base.parameters()),
168 target,
169 current_value,
170 final_value: self.final_value.unwrap_or(starting),
171 starting_value: starting,
172 foreign_function_interface: Some(BuiltInExpressionFfi::instance()),
173 };
174 Self::get_key_frame(&ctx, &self.key_frames[self.key_frames.len() - 1])
175 })
176 }
177
178 fn evaluate_core(&self, now: Duration, current_value: ExpressionVariant) -> ExpressionVariant {
179 let starting = ExpressionVariant::create(self.starting_value.get());
180 let elapsed = self.clock.elapsed(
181 self.base.compositor().as_ref(),
182 ticks(now),
183 self.started_at.get(),
184 Some(self.progress_span()),
185 );
186 let res = self.base.with_target_expression_object(|target| {
187 let ctx = ExpressionEvaluationContext {
188 parameters: Some(&**self.base.parameters()),
189 target,
190 current_value,
191 final_value: self.final_value.unwrap_or(starting),
192 starting_value: starting,
193 foreign_function_interface: Some(BuiltInExpressionFfi::instance()),
194 };
195 self.evaluate_impl(elapsed, current_value, &ctx)
196 });
197
198 if self.iteration_behavior == AnimationIterationBehavior::Count
200 && !self.finished.get()
201 && elapsed > self.total_duration
202 && !self.clock.is_paused()
203 {
204 if let (Some(compositor), Some(this)) = (self.base.compositor(), self.base.this_clock_item()) {
206 compositor.animations().remove_from_clock(&this);
207 }
208 self.finished.set(true);
209 self.release_completion_now();
211 }
212 res
213 }
214
215 fn evaluate_impl(
216 &self,
217 mut elapsed: i64,
218 current_value: ExpressionVariant,
219 ctx: &ExpressionEvaluationContext<'_>,
220 ) -> ExpressionVariant {
221 if elapsed < self.delay_time {
222 if self.delay_behavior == AnimationDelayBehavior::SetInitialValueBeforeDelay {
223 return ExpressionVariant::create(Self::get_key_frame(ctx, &self.key_frames[0]));
224 }
225 return current_value;
226 }
227
228 elapsed -= self.delay_time;
229 let iteration_number = elapsed / self.duration;
230 if self.iteration_behavior == AnimationIterationBehavior::Count
231 && iteration_number >= self.iteration_count as i64
232 {
233 return ExpressionVariant::create(Self::get_key_frame(ctx, &self.key_frames[self.key_frames.len() - 1]));
234 }
235
236 let even_iteration_number = iteration_number % 2 == 0;
237 elapsed %= self.duration;
238
239 let reverse = match self.direction {
240 PlaybackDirection::Alternate => !even_iteration_number,
241 PlaybackDirection::AlternateReverse => even_iteration_number,
242 direction => direction == PlaybackDirection::Reverse,
243 };
244
245 let mut iteration_progress = total_seconds(elapsed) / total_seconds(self.duration);
246 if reverse {
247 iteration_progress = 1.0 - iteration_progress;
248 }
249
250 let starting_frame = ServerKeyFrame { value: self.starting_value.get(), ..ServerKeyFrame::default() };
251 let mut left = &starting_frame;
252 let mut right = &self.key_frames[self.key_frames.len() - 1];
253 for c in 0..self.key_frames.len() {
254 let kf = &self.key_frames[c];
255 if (kf.key as f64) < iteration_progress {
256 if c == self.key_frames.len() - 1 {
258 return ExpressionVariant::create(Self::get_key_frame(ctx, kf));
259 }
260
261 left = kf;
262 right = &self.key_frames[c + 1];
263 } else if c == 0 {
264 right = &self.key_frames[c];
267 break;
268 } else {
269 break;
270 }
271 }
272
273 let key_progress = net_max(
274 0.0,
275 net_min(1.0, (iteration_progress - left.key as f64) / (right.key as f64 - left.key as f64)),
276 );
277
278 let eased = right.easing_function.as_ref().map_or(key_progress, |easing| easing.ease(key_progress));
279 let eased_key_progress = eased as f32;
280 if eased_key_progress.is_nan() || eased_key_progress.is_infinite() {
281 return current_value;
282 }
283
284 ExpressionVariant::create(self.interpolator.interpolate(
285 Self::get_key_frame(ctx, left),
286 Self::get_key_frame(ctx, right),
287 eased_key_progress,
288 ))
289 }
290
291 fn get_key_frame(ctx: &ExpressionEvaluationContext<'_>, f: &ServerKeyFrame<T>) -> T {
292 match &f.expression {
293 Some(expression) => expression.evaluate(ctx).cast_or_default::<T>(),
294 None => f.value,
295 }
296 }
297}
298
299impl<T: ExpressionVariantValue> IServerClockItem for KeyFrameAnimationInstance<T> {
300 fn on_tick(&self) {
301 if self.base.target().is_none() {
305 if let (Some(compositor), Some(this)) = (self.base.compositor(), self.base.this_clock_item()) {
306 compositor.animations().remove_from_clock(&this);
307 }
308 self.release_completion_now();
309 return;
310 }
311 self.base.on_tick()
312 }
313}
314
315impl<T: ExpressionVariantValue> IAnimationInstance for KeyFrameAnimationInstance<T> {
316 fn target_object(&self) -> ServerObjectId {
317 self.base.target_object()
318 }
319
320 fn resolve(&self, compositor: &Rc<ServerCompositor>) {
321 self.base.resolve(compositor)
322 }
323
324 fn evaluate(&self, now: Duration, current_value: ExpressionVariant) -> ExpressionVariant {
325 self.base.begin_evaluate();
326 self.evaluate_core(now, current_value)
327 }
328
329 fn initialize(&self, started_at: Duration, starting_value: ExpressionVariant, property: &'static CompositionProperty) {
330 let initial_values = std::mem::take(&mut *self.initial_values.borrow_mut());
331 let starting_value = self.base.apply_initial_values(&initial_values, property, starting_value);
332 self.started_at.set(ticks(started_at));
333 self.starting_value.set(starting_value.cast_or_default::<T>());
334 let mut hs = HashSet::new();
335
336 for frame in &self.key_frames {
339 if let Some(expression) = &frame.expression {
340 expression.collect_references(&mut hs);
341 }
342 }
343 self.base.initialize(property, &hs);
344 }
345
346 fn activate(&self) {
347 if self.finished.get() {
348 return;
349 }
350 if let (Some(compositor), Some(this)) = (self.base.compositor(), self.base.this_clock_item()) {
351 compositor.animations().add_to_clock(this);
352 }
353 self.base.activate();
354 }
355
356 fn deactivate(&self) {
357 if let (Some(compositor), Some(this)) = (self.base.compositor(), self.base.this_clock_item()) {
358 compositor.animations().remove_from_clock(&this);
359 }
360 self.base.deactivate();
361 }
362
363 fn invalidate(&self) {
364 self.base.invalidate()
365 }
366
367 fn value_on_stop(&self, current_value: ExpressionVariant) -> Option<ExpressionVariant> {
368 match self.stop_behavior {
369 AnimationStopBehavior::LeaveCurrentValue => None,
370 AnimationStopBehavior::SetToInitialValue => Some(ExpressionVariant::create(self.starting_value.get())),
371 AnimationStopBehavior::SetToFinalValue => {
372 Some(ExpressionVariant::create(self.final_key_frame_value(current_value)))
373 }
374 }
375 }
376
377 fn release_completion(&self) {
378 self.release_completion_now()
379 }
380
381 fn attach_controller(&self, controller: ServerObjectId) {
382 self.clock.attach(controller)
383 }
384}