cosmic/
anim.rs

1use std::time::{Duration, Instant};
2
3/// A simple linear interpolation calculation function.
4/// p = `percent_complete` in decimal form
5#[must_use]
6pub fn lerp(start: f32, end: f32, p: f32) -> f32 {
7    (1.0 - p) * start + p * end
8}
9
10/// A fast smooth interpolation calculation function.
11/// p = `percent_complete` in decimal form
12#[must_use]
13pub fn slerp(start: f32, end: f32, p: f32) -> f32 {
14    let t = smootherstep(p);
15    (1.0 - t) * start + t * end
16}
17
18/// utility function which maps a value [0, 1] -> [0, 1] using the smootherstep function
19pub fn smootherstep(t: f32) -> f32 {
20    (6.0 * t.powi(5) - 15.0 * t.powi(4) + 10.0 * t.powi(3)).clamp(0.0, 1.0)
21}
22
23#[derive(Default, Debug)]
24pub struct State {
25    pub last_change: Option<Instant>,
26}
27
28impl State {
29    pub fn changed(&mut self, dur: Duration) {
30        let t = self.t(dur, false);
31        let diff = dur.mul_f32(t.abs());
32        let now = Instant::now();
33        self.last_change = Some(now.checked_sub(diff).unwrap_or(now));
34    }
35
36    pub fn anim_done(&mut self, dur: Duration) {
37        if self
38            .last_change
39            .is_some_and(|t| Instant::now().duration_since(t) > dur)
40        {
41            self.last_change = None;
42        }
43    }
44
45    pub fn t(&self, dur: Duration, forward: bool) -> f32 {
46        let res = self.last_change.map_or(1., |t| {
47            Instant::now().duration_since(t).as_millis() as f32 / dur.as_millis() as f32
48        });
49        if forward { res } else { 1. - res }
50    }
51}