1use core::borrow::Borrow;
2use core::mem::MaybeUninit;
3
4pub(crate) use crate::*;
5
6#[cfg(feature = "mint_types")]
7pub use mint_type_impls::*;
8
9pub trait EasingFunction {
11 fn y(&self, x: f64) -> f64;
22}
23
24pub trait CanTween {
26 fn ease(from: Self, to: Self, time: impl Float) -> Self;
31}
32
33impl CanTween for f32 {
34 #[inline]
35 fn ease(from: Self, to: Self, time: impl Float) -> Self {
36 as_t(as_f64(from) + as_f64(to - from) * as_f64(time))
37 }
38}
39
40impl CanTween for f64 {
41 #[inline]
42 fn ease(from: Self, to: Self, time: impl Float) -> Self {
43 as_t(as_f64(from) + as_f64(to - from) * as_f64(time))
44 }
45}
46
47impl<T: CanTween, const N: usize> CanTween for [T; N] {
48 fn ease(from: Self, to: Self, time: impl Float) -> Self {
49 let mut result_uninit: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
51
52 for (i, (f, t)) in IntoIterator::into_iter(from)
53 .zip(IntoIterator::into_iter(to))
54 .enumerate()
55 {
56 result_uninit[i].write(T::ease(f, t, time));
58 }
59
60 unsafe {
61 let ptr = result_uninit.as_mut_ptr() as *mut [T; N];
63 let result = ptr.read();
64 core::mem::forget(result_uninit);
65
66 result
67 }
68 }
69}
70
71#[inline]
74pub fn ease_with_unbounded_time<V: CanTween, F: EasingFunction>(
75 function: impl Borrow<F>,
76 from: V,
77 to: V,
78 time: impl Float,
79) -> V {
80 V::ease(from, to, function.borrow().y(as_f64(time)))
81}
82
83#[inline]
86pub fn ease<V: CanTween, T: Float, F: EasingFunction>(function: impl Borrow<F>, from: V, to: V, time: T) -> V {
87 ease_with_unbounded_time(
88 function,
89 from,
90 to,
91 match time {
92 _ if time < T::zero() => T::zero(),
93 _ if time > T::one() => T::one(),
94 _ => time,
95 },
96 )
97}
98
99#[inline]
102pub fn ease_with_scaled_time<V: CanTween, T: Float, F: EasingFunction>(
103 function: impl Borrow<F>,
104 from: V,
105 to: V,
106 time: T,
107 max_time: T,
108) -> V {
109 ease(
110 function,
111 from,
112 to,
113 match time {
114 _ if time < T::zero() => T::zero(),
115 _ if time > max_time => T::one(),
116 _ => time / max_time,
117 },
118 )
119}
120
121#[cfg(feature = "mint_types")]
122mod mint_type_impls {
123 use crate::easing::*;
124
125 impl<V: CanTween> CanTween for Vector2<V> {
126 #[inline]
127 fn ease(from: Self, to: Self, time: impl Float) -> Self {
128 Self {
129 x: V::ease(from.x, to.x, time),
130 y: V::ease(from.y, to.y, time),
131 }
132 }
133 }
134
135 impl<V: CanTween> CanTween for Vector3<V> {
136 #[inline]
137 fn ease(from: Self, to: Self, time: impl Float) -> Self {
138 Self {
139 x: V::ease(from.x, to.x, time),
140 y: V::ease(from.y, to.y, time),
141 z: V::ease(from.z, to.z, time),
142 }
143 }
144 }
145
146 impl<V: CanTween> CanTween for Vector4<V> {
147 #[inline]
148 fn ease(from: Self, to: Self, time: impl Float) -> Self {
149 Self {
150 x: V::ease(from.x, to.x, time),
151 y: V::ease(from.y, to.y, time),
152 z: V::ease(from.z, to.z, time),
153 w: V::ease(from.w, to.w, time),
154 }
155 }
156 }
157
158 impl<V: CanTween> CanTween for Point2<V> {
159 #[inline]
160 fn ease(from: Self, to: Self, time: impl Float) -> Self {
161 Self {
162 x: V::ease(from.x, to.x, time),
163 y: V::ease(from.y, to.y, time),
164 }
165 }
166 }
167
168 impl<V: CanTween> CanTween for Point3<V> {
169 #[inline]
170 fn ease(from: Self, to: Self, time: impl Float) -> Self {
171 Self {
172 x: V::ease(from.x, to.x, time),
173 y: V::ease(from.y, to.y, time),
174 z: V::ease(from.z, to.z, time),
175 }
176 }
177 }
178}