Skip to main content

mirage_engine/animation/
progress.rs

1use core::fmt::{self, Debug, Formatter};
2
3/// The whole of one cycle.
4const WHOLE: f32 = 1.0;
5
6/// How far along what it plays a machine is, which a state reads to decide
7/// where to go next.
8///
9/// A cycle is one run of the clip, from its first key to its last. A
10/// looping motion and a blend count cycles without end; one that holds at
11/// its last key stops at the first. No read of it changes anything, so the
12/// machine may read a state again over a tick's own span to reach the
13/// instant inside it a transition started at.
14#[derive(Clone, Copy)]
15pub struct Progress {
16    /// The cycles run, counted on past the end of a motion that holds
17    /// there.
18    run: f32,
19    /// Whether the motion holds at the end of one cycle.
20    ends: bool,
21}
22
23impl Progress {
24    /// The progress `run` cycles into a motion, which holds at the end of
25    /// the first where `ends`.
26    pub(crate) fn new(run: f32, ends: bool) -> Self {
27        Self {
28            run: match run.is_finite() {
29                true => run.max(0.0),
30                false => 0.0,
31            },
32            ends,
33        }
34    }
35
36    /// Whether the motion has run its whole cycle and holds there, which a
37    /// looping motion and a blend never do.
38    pub fn ended(&self) -> bool {
39        self.ends && self.run >= WHOLE
40    }
41
42    /// Whether it has gone past `fraction` of the cycle it is in.
43    pub fn past(&self, fraction: f32) -> bool {
44        self.fraction() >= fraction
45    }
46
47    /// The cycles of it that have run whole.
48    pub fn cycle(&self) -> u32 {
49        self.counted().floor().max(0.0) as u32
50    }
51
52    /// How far into the cycle it is in it lies, a fraction in `0.0..=1.0`.
53    pub fn fraction(&self) -> f32 {
54        match self.ended() {
55            true => WHOLE,
56            false => self.counted().fract().clamp(0.0, WHOLE),
57        }
58    }
59
60    /// The cycles run, held to the one a motion that holds at its last key
61    /// stops in.
62    fn counted(&self) -> f32 {
63        match self.ends {
64            true => self.run.min(WHOLE),
65            false => self.run,
66        }
67    }
68}
69
70impl Debug for Progress {
71    /// The cycles run and how far into the one it is in, which is what a
72    /// state reads it for.
73    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
74        formatter
75            .debug_struct("Progress")
76            .field("cycle", &self.cycle())
77            .field("fraction", &self.fraction())
78            .field("ended", &self.ended())
79            .finish()
80    }
81}