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}