1use crate::media::Color;
4use crate::numerics::{Quaternion, Vector2, Vector3, Vector4};
5use crate::{RelativePoint, RelativeScalar, Vector, Vector3D};
6
7pub trait IInterpolator<T> {
9 fn interpolate(&self, from: T, to: T, progress: f32) -> T;
10}
11
12macro_rules! instance {
13 ($ty:ident) => {
14 impl $ty {
15 pub fn instance() -> &'static $ty {
17 static INSTANCE: $ty = $ty;
18 &INSTANCE
19 }
20 }
21 };
22}
23
24#[derive(Clone, Copy, Debug, Default)]
26pub struct ScalarInterpolator;
27
28impl IInterpolator<f32> for ScalarInterpolator {
29 fn interpolate(&self, from: f32, to: f32, progress: f32) -> f32 {
30 from + (to - from) * progress
31 }
32}
33
34instance!(ScalarInterpolator);
35
36#[derive(Clone, Copy, Debug, Default)]
38pub struct DoubleInterpolator;
39
40impl IInterpolator<f64> for DoubleInterpolator {
41 fn interpolate(&self, from: f64, to: f64, progress: f32) -> f64 {
42 from + (to - from) * progress as f64
43 }
44}
45
46instance!(DoubleInterpolator);
47
48#[derive(Clone, Copy, Debug, Default)]
50pub struct Vector2Interpolator;
51
52impl IInterpolator<Vector2> for Vector2Interpolator {
53 fn interpolate(&self, from: Vector2, to: Vector2, progress: f32) -> Vector2 {
54 Vector2::lerp(from, to, progress)
55 }
56}
57
58instance!(Vector2Interpolator);
59
60#[derive(Clone, Copy, Debug, Default)]
62pub struct VectorInterpolator;
63
64impl IInterpolator<Vector> for VectorInterpolator {
65 fn interpolate(&self, from: Vector, to: Vector, progress: f32) -> Vector {
66 Vector::new(
67 DoubleInterpolator::instance().interpolate(from.x, to.x, progress),
68 DoubleInterpolator::instance().interpolate(from.y, to.y, progress),
69 )
70 }
71}
72
73instance!(VectorInterpolator);
74
75#[derive(Clone, Copy, Debug, Default)]
77pub struct Vector3Interpolator;
78
79impl IInterpolator<Vector3> for Vector3Interpolator {
80 fn interpolate(&self, from: Vector3, to: Vector3, progress: f32) -> Vector3 {
81 Vector3::lerp(from, to, progress)
82 }
83}
84
85instance!(Vector3Interpolator);
86
87#[derive(Clone, Copy, Debug, Default)]
89pub struct Vector3DInterpolator;
90
91impl IInterpolator<Vector3D> for Vector3DInterpolator {
92 fn interpolate(&self, from: Vector3D, to: Vector3D, progress: f32) -> Vector3D {
93 Vector3D::new(
94 DoubleInterpolator::instance().interpolate(from.x, to.x, progress),
95 DoubleInterpolator::instance().interpolate(from.y, to.y, progress),
96 DoubleInterpolator::instance().interpolate(from.z, to.z, progress),
97 )
98 }
99}
100
101instance!(Vector3DInterpolator);
102
103#[derive(Clone, Copy, Debug, Default)]
105pub struct Vector4Interpolator;
106
107impl IInterpolator<Vector4> for Vector4Interpolator {
108 fn interpolate(&self, from: Vector4, to: Vector4, progress: f32) -> Vector4 {
109 Vector4::lerp(from, to, progress)
110 }
111}
112
113instance!(Vector4Interpolator);
114
115#[derive(Clone, Copy, Debug, Default)]
117pub struct QuaternionInterpolator;
118
119impl IInterpolator<Quaternion> for QuaternionInterpolator {
120 fn interpolate(&self, from: Quaternion, to: Quaternion, progress: f32) -> Quaternion {
121 Quaternion::lerp(from, to, progress)
122 }
123}
124
125instance!(QuaternionInterpolator);
126
127#[derive(Clone, Copy, Debug, Default)]
129pub struct ColorInterpolator;
130
131impl ColorInterpolator {
132 fn lerp(a: f32, b: f32, p: f32) -> u8 {
133 ((a * (1.0 - p)) + (b * p)).clamp(0.0, 255.0) as u8
136 }
137
138 pub fn lerp_rgb(to: Color, from: Color, progress: f32) -> Color {
140 Color::new(
141 Self::lerp(to.a as f32, from.a as f32, progress),
142 Self::lerp(to.r as f32, from.r as f32, progress),
143 Self::lerp(to.g as f32, from.g as f32, progress),
144 Self::lerp(to.b as f32, from.b as f32, progress),
145 )
146 }
147}
148
149impl IInterpolator<Color> for ColorInterpolator {
150 fn interpolate(&self, from: Color, to: Color, progress: f32) -> Color {
151 Self::lerp_rgb(from, to, progress)
152 }
153}
154
155instance!(ColorInterpolator);
156
157#[derive(Clone, Copy, Debug, Default)]
159pub struct BooleanInterpolator;
160
161impl IInterpolator<bool> for BooleanInterpolator {
162 fn interpolate(&self, from: bool, to: bool, progress: f32) -> bool {
163 if progress >= 1.0 {
164 to
165 } else {
166 from
167 }
168 }
169}
170
171instance!(BooleanInterpolator);
172
173#[derive(Clone, Copy, Debug, Default)]
176pub struct RelativePointInterpolator;
177
178impl IInterpolator<RelativePoint> for RelativePointInterpolator {
179 fn interpolate(&self, from: RelativePoint, to: RelativePoint, progress: f32) -> RelativePoint {
180 if from.unit != to.unit {
181 return if progress >= 0.5 { to } else { from };
182 }
183
184 let x = DoubleInterpolator::instance().interpolate(from.point.x, to.point.x, progress);
185 let y = DoubleInterpolator::instance().interpolate(from.point.y, to.point.y, progress);
186 RelativePoint::new(x, y, from.unit)
187 }
188}
189
190instance!(RelativePointInterpolator);
191
192#[derive(Clone, Copy, Debug, Default)]
195pub struct RelativeScalarInterpolator;
196
197impl IInterpolator<RelativeScalar> for RelativeScalarInterpolator {
198 fn interpolate(&self, from: RelativeScalar, to: RelativeScalar, progress: f32) -> RelativeScalar {
199 if from.unit != to.unit {
200 return if progress >= 0.5 { to } else { from };
201 }
202 RelativeScalar::new(from.scalar + (to.scalar - from.scalar) * progress as f64, from.unit)
203 }
204}
205
206instance!(RelativeScalarInterpolator);
207
208#[cfg(test)]
209mod tests {
210 use super::*;
211 use crate::RelativeUnit;
212
213 #[test]
214 fn scalars() {
215 assert_eq!(ScalarInterpolator::instance().interpolate(2.0, 4.0, 0.25), 2.5);
216 assert_eq!(ScalarInterpolator::instance().interpolate(2.0, 4.0, 1.5), 5.0);
217 assert_eq!(DoubleInterpolator::instance().interpolate(2.0, 4.0, 0.25), 2.5);
218 assert_eq!(DoubleInterpolator::instance().interpolate(4.0, 2.0, 0.5), 3.0);
219 }
220
221 #[test]
222 fn vectors() {
223 assert_eq!(
224 Vector2Interpolator::instance().interpolate(Vector2::new(0.0, 2.0), Vector2::new(4.0, 4.0), 0.5),
225 Vector2::new(2.0, 3.0)
226 );
227 assert_eq!(
228 VectorInterpolator::instance().interpolate(Vector::new(0.0, 2.0), Vector::new(4.0, 4.0), 0.5),
229 Vector::new(2.0, 3.0)
230 );
231 assert_eq!(
232 Vector3Interpolator::instance().interpolate(
233 Vector3::new(0.0, 2.0, -2.0),
234 Vector3::new(4.0, 4.0, 2.0),
235 0.5
236 ),
237 Vector3::new(2.0, 3.0, 0.0)
238 );
239 assert_eq!(
240 Vector3DInterpolator::instance().interpolate(
241 Vector3D::new(0.0, 2.0, -2.0),
242 Vector3D::new(4.0, 4.0, 2.0),
243 0.5
244 ),
245 Vector3D::new(2.0, 3.0, 0.0)
246 );
247 assert_eq!(
248 Vector4Interpolator::instance().interpolate(
249 Vector4::new(0.0, 2.0, -2.0, 1.0),
250 Vector4::new(4.0, 4.0, 2.0, 1.0),
251 0.5
252 ),
253 Vector4::new(2.0, 3.0, 0.0, 1.0)
254 );
255 }
256
257 #[test]
258 fn quaternion_is_a_normalized_lerp() {
259 let from = Quaternion::create_from_axis_angle(Vector3::UNIT_Z, 0.0);
260 let to = Quaternion::create_from_axis_angle(Vector3::UNIT_Z, 1.0);
261 let actual = QuaternionInterpolator::instance().interpolate(from, to, 0.5);
262 assert_eq!(actual, Quaternion::lerp(from, to, 0.5));
263 assert!((actual.length() - 1.0).abs() < 1e-6);
264 }
265
266 #[test]
267 fn color_channels_are_interpolated_and_truncated() {
268 let from = Color::from_argb(255, 10, 0, 255);
269 let to = Color::from_argb(0, 200, 1, 255);
270 let i = ColorInterpolator::instance();
271 assert_eq!(i.interpolate(from, to, 0.5), Color::from_argb(127, 105, 0, 255));
273 assert_eq!(i.interpolate(from, to, 0.0), from);
274 assert_eq!(i.interpolate(from, to, 1.0), to);
275 assert_eq!(i.interpolate(from, to, 2.0), Color::from_argb(0, 255, 2, 255));
277 assert_eq!(i.interpolate(from, to, -1.0), Color::from_argb(255, 0, 0, 255));
278 assert_eq!(ColorInterpolator::lerp_rgb(from, to, 0.5), i.interpolate(from, to, 0.5));
279 }
280
281 #[test]
282 fn boolean_switches_at_the_end() {
283 let i = BooleanInterpolator::instance();
284 assert!(!i.interpolate(false, true, 0.0));
285 assert!(!i.interpolate(false, true, 0.999));
286 assert!(i.interpolate(false, true, 1.0));
287 assert!(i.interpolate(true, false, 0.5));
288 }
289
290 #[test]
291 fn relative_values() {
292 let p = RelativePointInterpolator::instance();
293 let from = RelativePoint::new(0.0, 1.0, RelativeUnit::Relative);
294 let to = RelativePoint::new(1.0, 0.0, RelativeUnit::Relative);
295 assert_eq!(
296 p.interpolate(from, to, 0.25),
297 RelativePoint::new(0.25, 0.75, RelativeUnit::Relative)
298 );
299 let absolute = RelativePoint::new(10.0, 20.0, RelativeUnit::Absolute);
300 assert_eq!(p.interpolate(from, absolute, 0.25), from);
301 assert_eq!(p.interpolate(from, absolute, 0.5), absolute);
302
303 let s = RelativeScalarInterpolator::instance();
304 let from = RelativeScalar::new(0.0, RelativeUnit::Relative);
305 let to = RelativeScalar::new(1.0, RelativeUnit::Relative);
306 assert_eq!(
307 s.interpolate(from, to, 0.25),
308 RelativeScalar::new(0.25, RelativeUnit::Relative)
309 );
310 let absolute = RelativeScalar::new(10.0, RelativeUnit::Absolute);
311 assert_eq!(s.interpolate(from, absolute, 0.25), from);
312 assert_eq!(s.interpolate(from, absolute, 0.75), absolute);
313 }
314}