1use egui::{Color32, Pos2, Rect, Vec2};
6
7pub trait Interpolate: Clone {
19 #[must_use]
21 fn interpolate(&self, other: &Self, t: f32) -> Self;
22}
23
24impl Interpolate for f32 {
26 fn interpolate(&self, other: &Self, t: f32) -> Self {
27 self + (other - self) * t
28 }
29}
30
31impl Interpolate for f64 {
33 fn interpolate(&self, other: &Self, t: f32) -> Self {
34 self + (other - self) * Self::from(t)
35 }
36}
37
38impl Interpolate for Vec2 {
40 fn interpolate(&self, other: &Self, t: f32) -> Self {
41 Self::new(
42 self.x.interpolate(&other.x, t),
43 self.y.interpolate(&other.y, t),
44 )
45 }
46}
47
48impl Interpolate for Pos2 {
50 fn interpolate(&self, other: &Self, t: f32) -> Self {
51 Self::new(
52 self.x.interpolate(&other.x, t),
53 self.y.interpolate(&other.y, t),
54 )
55 }
56}
57
58impl Interpolate for Rect {
60 fn interpolate(&self, other: &Self, t: f32) -> Self {
61 Self {
62 min: self.min.interpolate(&other.min, t),
63 max: self.max.interpolate(&other.max, t),
64 }
65 }
66}
67
68impl Interpolate for Color32 {
70 #[allow(clippy::many_single_char_names)]
71 fn interpolate(&self, other: &Self, t: f32) -> Self {
72 let r = interpolate_u8(self.r(), other.r(), t);
73 let g = interpolate_u8(self.g(), other.g(), t);
74 let b = interpolate_u8(self.b(), other.b(), t);
75 let a = interpolate_u8(self.a(), other.a(), t);
76 Self::from_rgba_premultiplied(r, g, b, a)
77 }
78}
79
80fn interpolate_u8(a: u8, b: u8, t: f32) -> u8 {
82 let a = f32::from(a);
83 let b = f32::from(b);
84 (a + (b - a) * t).round().clamp(0.0, 255.0) as u8
85}
86
87impl<A: Interpolate, B: Interpolate> Interpolate for (A, B) {
89 fn interpolate(&self, other: &Self, t: f32) -> Self {
90 (
91 self.0.interpolate(&other.0, t),
92 self.1.interpolate(&other.1, t),
93 )
94 }
95}
96
97impl<A: Interpolate, B: Interpolate, C: Interpolate> Interpolate for (A, B, C) {
98 fn interpolate(&self, other: &Self, t: f32) -> Self {
99 (
100 self.0.interpolate(&other.0, t),
101 self.1.interpolate(&other.1, t),
102 self.2.interpolate(&other.2, t),
103 )
104 }
105}
106
107impl<T: Interpolate> Interpolate for Option<T> {
109 fn interpolate(&self, other: &Self, t: f32) -> Self {
110 match (self, other) {
111 (Some(a), Some(b)) => Some(a.interpolate(b, t)),
112 (Some(_), None) if t < 0.5 => self.clone(),
113 (None, Some(_)) if t >= 0.5 => other.clone(),
114 _ => None,
115 }
116 }
117}
118
119pub fn lerp<T: Interpolate>(a: &T, b: &T, t: f32) -> T {
121 a.interpolate(b, t)
122}
123
124#[must_use]
126pub fn smooth_step(t: f32) -> f32 {
127 let t = t.clamp(0.0, 1.0);
128 t * t * (3.0 - 2.0 * t)
129}
130
131#[must_use]
133pub fn smoother_step(t: f32) -> f32 {
134 let t = t.clamp(0.0, 1.0);
135 t * t * t * (t * (t * 6.0 - 15.0) + 10.0)
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[test]
143 fn test_f32_interpolate() {
144 assert_eq!(0.0f32.interpolate(&10.0, 0.0), 0.0);
145 assert_eq!(0.0f32.interpolate(&10.0, 0.5), 5.0);
146 assert_eq!(0.0f32.interpolate(&10.0, 1.0), 10.0);
147 }
148
149 #[test]
150 fn test_vec2_interpolate() {
151 let a = Vec2::new(0.0, 0.0);
152 let b = Vec2::new(10.0, 20.0);
153
154 let mid = a.interpolate(&b, 0.5);
155 assert_eq!(mid.x, 5.0);
156 assert_eq!(mid.y, 10.0);
157 }
158
159 #[test]
160 fn test_color_interpolate() {
161 let black = Color32::BLACK;
162 let white = Color32::WHITE;
163
164 let gray = black.interpolate(&white, 0.5);
165 assert!(gray.r() > 100 && gray.r() < 155);
166 }
167
168 #[test]
169 fn test_smooth_step() {
170 assert_eq!(smooth_step(0.0), 0.0);
171 assert_eq!(smooth_step(1.0), 1.0);
172 assert!(smooth_step(0.5) > 0.4 && smooth_step(0.5) < 0.6);
173 }
174
175 #[test]
176 fn test_tuple_interpolate() {
177 let a = (0.0f32, 0.0f32);
178 let b = (10.0f32, 20.0f32);
179
180 let mid = a.interpolate(&b, 0.5);
181 assert_eq!(mid, (5.0, 10.0));
182 }
183}