kira/tween.rs
1//! Smooth interpolation between values.
2
3mod tweenable;
4
5pub use tweenable::*;
6
7use std::time::Duration;
8
9use crate::start_time::StartTime;
10
11/// Curves the motion of a [`Tween`].
12#[derive(Debug, Clone, Copy, PartialEq)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub enum Easing {
15 /// Maintains a constant speed for the duration of the [`Tween`].
16 Linear,
17 /// Causes the [`Tween`] to start slow and speed up. A higher
18 /// value causes the [`Tween`] to speed up more dramatically.
19 InPowi(i32),
20 /// Causes the [`Tween`] to start fast and slow down. A higher
21 /// value causes the [`Tween`] to slow down more dramatically.
22 OutPowi(i32),
23 /// Causes the [`Tween`] to start slow, speed up, and then slow
24 /// back down. A higher values causes the [`Tween`] to have more
25 /// dramatic speed changes.
26 InOutPowi(i32),
27 /// Causes the [`Tween`] to start slow and speed up. A higher
28 /// value causes the [`Tween`] to speed up more dramatically.
29 ///
30 /// This is similar to [`InPowi`](Easing::InPowi), but allows
31 /// for float intensity values at the cost of being more
32 /// CPU intensive.
33 InPowf(f64),
34 /// Causes the [`Tween`] to start fast and slow down. A higher
35 /// value causes the [`Tween`] to slow down more dramatically.
36 ///
37 /// This is similar to [`OutPowi`](Easing::InPowi), but allows
38 /// for float intensity values at the cost of being more
39 /// CPU intensive.
40 OutPowf(f64),
41 /// Causes the [`Tween`] to start slow, speed up, and then slow
42 /// back down. A higher values causes the [`Tween`] to have more
43 /// dramatic speed changes.
44 ///
45 /// This is similar to [`InOutPowi`](Easing::InPowi), but allows
46 /// for float intensity values at the cost of being more
47 /// CPU intensive.
48 InOutPowf(f64),
49}
50
51impl Easing {
52 pub(crate) fn apply(&self, mut x: f64) -> f64 {
53 match self {
54 Easing::Linear => x,
55 Easing::InPowi(power) => x.powi(*power),
56 Easing::OutPowi(power) => 1.0 - Self::InPowi(*power).apply(1.0 - x),
57 Easing::InOutPowi(power) => {
58 x *= 2.0;
59 if x < 1.0 {
60 0.5 * Self::InPowi(*power).apply(x)
61 } else {
62 x = 2.0 - x;
63 0.5 * (1.0 - Self::InPowi(*power).apply(x)) + 0.5
64 }
65 }
66 Easing::InPowf(power) => x.powf(*power),
67 Easing::OutPowf(power) => 1.0 - Self::InPowf(*power).apply(1.0 - x),
68 Easing::InOutPowf(power) => {
69 x *= 2.0;
70 if x < 1.0 {
71 0.5 * Self::InPowf(*power).apply(x)
72 } else {
73 x = 2.0 - x;
74 0.5 * (1.0 - Self::InPowf(*power).apply(x)) + 0.5
75 }
76 }
77 }
78 }
79}
80
81impl Default for Easing {
82 fn default() -> Self {
83 Self::Linear
84 }
85}
86
87/// Describes a smooth transition between values.
88#[derive(Debug, Clone, Copy, PartialEq)]
89pub struct Tween {
90 /// When the motion starts.
91 pub start_time: StartTime,
92 /// The duration of the motion.
93 pub duration: Duration,
94 /// The curve of the motion.
95 pub easing: Easing,
96}
97
98impl Tween {
99 pub(super) fn value(&self, time: f64) -> f64 {
100 self.easing.apply(time / self.duration.as_secs_f64())
101 }
102}
103
104impl Default for Tween {
105 fn default() -> Self {
106 Self {
107 start_time: StartTime::default(),
108 duration: Duration::from_millis(10),
109 easing: Easing::Linear,
110 }
111 }
112}