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}