freya_core/
animation_clock.rs1use std::{
2 sync::{
3 Arc,
4 atomic::{
5 AtomicU32,
6 Ordering,
7 },
8 },
9 time::Duration,
10};
11
12use tracing::info;
13
14use crate::prelude::consume_root_context;
15
16#[derive(Clone)]
18pub struct AnimationClock(Arc<AtomicU32>);
19
20#[doc(hidden)]
21pub trait New: sealed::Sealed {
22 fn new() -> Self;
23}
24
25impl New for AnimationClock {
26 fn new() -> Self {
27 Self(Arc::new(AtomicU32::new(Self::DEFAULT_SPEED.to_bits())))
28 }
29}
30
31mod sealed {
32 pub trait Sealed {}
33 impl Sealed for crate::animation_clock::AnimationClock {}
34}
35
36impl AnimationClock {
37 pub const DEFAULT_SPEED: f32 = 1.0;
39 pub const MIN_SPEED: f32 = 0.05;
41 pub const MAX_SPEED: f32 = 5.0;
43 pub const DISABLED_SPEED: f32 = 999_999_999.0;
45
46 #[track_caller]
48 pub fn get() -> Self {
49 consume_root_context()
50 }
51
52 pub fn speed(&self) -> f32 {
54 let bits = self.0.load(Ordering::Relaxed);
55 (f32::from_bits(bits) * 100.0).round() / 100.0
56 }
57
58 pub fn enable(&self) {
60 self.0
61 .store(Self::DEFAULT_SPEED.to_bits(), Ordering::Relaxed);
62 info!("Animation clock speed enabled");
63 }
64
65 pub fn disable(&self) {
67 self.0
68 .store(Self::DISABLED_SPEED.to_bits(), Ordering::Relaxed);
69 info!("Animation clock speed disabled");
70 }
71
72 pub fn set_speed(&self, speed: f32) {
74 let speed = speed.clamp(Self::MIN_SPEED, Self::MAX_SPEED);
75 self.0.store(speed.to_bits(), Ordering::Relaxed);
76 info!("Animation clock speed changed to {:.2}x", speed);
77 }
78
79 pub fn correct_elapsed_duration(&self, elapsed: Duration) -> Duration {
81 let scaled_secs = elapsed.as_secs_f32() * self.speed();
82 Duration::from_secs_f32(scaled_secs)
83 }
84}