Skip to main content

aura_anim_iced/timing/
normalized.rs

1use super::FillMode;
2
3/// The broad phase produced by elapsed-time normalization.
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum TimingPhase {
6    /// Elapsed time is still before the active interval.
7    BeforeStart,
8    /// Elapsed time is inside the active interval.
9    Active,
10    /// Elapsed time is after a finite active interval.
11    AfterEnd,
12}
13
14/// The sampling state produced by fill-mode-aware timing normalization.
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum TimingSampleState {
17    /// Elapsed time is before the active interval and no sample should be emitted.
18    BeforeStart,
19    /// Elapsed time is inside the active interval.
20    Active,
21    /// Elapsed time is after the active interval and no sample should be emitted.
22    AfterEnd,
23    /// Elapsed time is before the active interval and should emit the first sample.
24    BackwardsFill,
25    /// Elapsed time is after the active interval and should emit the final sample.
26    ForwardsFill,
27}
28
29impl TimingSampleState {
30    /// Returns whether this state should emit a sample.
31    #[must_use]
32    pub const fn has_sample(self) -> bool {
33        matches!(
34            self,
35            Self::Active | Self::BackwardsFill | Self::ForwardsFill
36        )
37    }
38
39    /// Returns whether this state is produced by fill behavior.
40    #[must_use]
41    pub const fn is_filled(self) -> bool {
42        matches!(self, Self::BackwardsFill | Self::ForwardsFill)
43    }
44}
45
46/// Normalized timing coordinates for sampling.
47#[derive(Debug, Clone, Copy, PartialEq)]
48pub struct NormalizedTiming {
49    /// Current timing phase.
50    pub phase: TimingPhase,
51    /// Fill-mode-aware sampling state.
52    pub sample_state: TimingSampleState,
53    /// Current zero-based iteration index while active.
54    pub current_iteration_index: Option<u32>,
55    /// Number of completed iterations.
56    pub completed_iterations: u32,
57    /// Normalized progress inside the current iteration.
58    pub iteration_progress: f64,
59    /// Unclamped progress across active iterations.
60    pub active_progress: f64,
61}
62
63impl NormalizedTiming {
64    pub(crate) fn before_start(fill_mode: FillMode, iteration_progress: f64) -> Self {
65        let sample_state = if fill_mode.fills_before_start() {
66            TimingSampleState::BackwardsFill
67        } else {
68            TimingSampleState::BeforeStart
69        };
70
71        Self {
72            phase: TimingPhase::BeforeStart,
73            sample_state,
74            current_iteration_index: None,
75            completed_iterations: 0,
76            iteration_progress,
77            active_progress: 0.0,
78        }
79    }
80
81    pub(crate) fn active(
82        current_iteration_index: u32,
83        iteration_progress: f64,
84        active_progress: f64,
85    ) -> Self {
86        Self {
87            phase: TimingPhase::Active,
88            sample_state: TimingSampleState::Active,
89            current_iteration_index: Some(current_iteration_index),
90            completed_iterations: current_iteration_index,
91            iteration_progress,
92            active_progress,
93        }
94    }
95
96    pub(crate) fn after_end(
97        iteration_count: u32,
98        fill_mode: FillMode,
99        iteration_progress: f64,
100    ) -> Self {
101        let sample_state = if fill_mode.fills_after_end() {
102            TimingSampleState::ForwardsFill
103        } else {
104            TimingSampleState::AfterEnd
105        };
106
107        Self {
108            phase: TimingPhase::AfterEnd,
109            sample_state,
110            current_iteration_index: None,
111            completed_iterations: iteration_count,
112            iteration_progress,
113            active_progress: f64::from(iteration_count),
114        }
115    }
116
117    /// Returns whether this normalized timing state should emit a sample.
118    #[must_use]
119    pub const fn has_sample(self) -> bool {
120        self.sample_state.has_sample()
121    }
122
123    /// Returns whether this normalized timing state is produced by fill behavior.
124    #[must_use]
125    pub const fn is_filled(self) -> bool {
126        self.sample_state.is_filled()
127    }
128}