sycamore/
easing.rs
1#![allow(missing_docs)] use std::f32::consts::PI;
6
7const EXP_BASE: f32 = 2.0;
8const BOUNCE_GRAVITY: f32 = 2.75;
9const BOUNCE_AMPLITUDE: f32 = 7.5625;
10
11pub fn linear(t: f32) -> f32 {
14 t
15}
16
17pub fn quad_in(t: f32) -> f32 {
20 t * t
21}
22
23pub fn quad_out(t: f32) -> f32 {
24 -t * (t - 2.0)
25}
26
27pub fn quad_inout(t: f32) -> f32 {
28 if t < 0.5 {
29 2.0 * t * t
30 } else {
31 -2.0 * t * t + 4.0 * t - 1.0
32 }
33}
34
35pub fn cubic_in(t: f32) -> f32 {
38 t * t * t
39}
40
41pub fn cubic_out(t: f32) -> f32 {
42 let f = t - 1.0;
43 f * f * f + 1.0
44}
45
46pub fn cubic_inout(t: f32) -> f32 {
47 if t < 0.5 {
48 4.0 * t * t * t
49 } else {
50 let f = 2.0 * t - 2.0;
51 0.5 * f * f * f + 1.0
52 }
53}
54
55pub fn quart_in(t: f32) -> f32 {
58 t * t * t * t
59}
60
61pub fn quart_out(t: f32) -> f32 {
62 let f = t - 1.0;
63 f * f * f * (1.0 - t) + 1.0
64}
65
66pub fn quart_inout(t: f32) -> f32 {
67 if t < 0.5 {
68 8.0 * t * t * t * t
69 } else {
70 let f = t - 1.0;
71 -8.0 * f * f * f * f + 1.0
72 }
73}
74
75pub fn quint_in(t: f32) -> f32 {
78 t * t * t * t * t
79}
80
81pub fn quint_out(t: f32) -> f32 {
82 let f = t - 1.0;
83 f * f * f * f * f + 1.0
84}
85
86pub fn quint_inout(t: f32) -> f32 {
87 if t < 0.5 {
88 16.0 * t * t * t * t * t
89 } else {
90 let f = (2.0 * t) - 2.0;
91 0.5 * f * f * f * f * f + 1.0
92 }
93}
94
95pub fn circ_in(t: f32) -> f32 {
98 1.0 - f32::sqrt(1.0 - f32::powi(t, 2))
99}
100
101pub fn circ_out(t: f32) -> f32 {
102 f32::sqrt(1.0 - f32::powi(t - 1.0, 2).powi(2))
103}
104
105pub fn circ_inout(t: f32) -> f32 {
106 if t < 0.5 {
107 (1.0 - f32::sqrt(1.0 - f32::powi(2.0 * t, 2))) / 2.0
108 } else {
109 (f32::sqrt(1.0 - f32::powi(-2.0 * t + 2.0, 2)) + 1.0) / 2.0
110 }
111}
112
113pub fn expo_in(t: f32) -> f32 {
116 if t.abs() <= f32::EPSILON {
117 0.0
118 } else {
119 EXP_BASE.powf(10.0 * t - 10.0)
120 }
121}
122
123pub fn expo_out(t: f32) -> f32 {
124 if (t - 1.0).abs() <= f32::EPSILON {
125 1.0
126 } else {
127 1.0 - EXP_BASE.powf(-10.0 * t)
128 }
129}
130
131pub fn expo_inout(t: f32) -> f32 {
132 if t.abs() <= f32::EPSILON {
133 0.0
134 } else if (t - 1.0) <= f32::EPSILON {
135 1.0
136 } else if t <= 0.5 {
137 f32::powf(EXP_BASE, 20.0 * t - 10.0) / 2.0
138 } else {
139 1.0 + f32::powf(EXP_BASE, -20.0 * t + 10.0) / -2.0
140 }
141}
142
143pub fn sine_in(t: f32) -> f32 {
146 1.0 - f32::cos(t * PI / 2.0)
147}
148
149pub fn sine_out(t: f32) -> f32 {
150 f32::sin(t * PI / 2.0)
151}
152
153pub fn sine_inout(t: f32) -> f32 {
154 -(f32::cos(PI * t) - 1.0) / 2.0
155}
156
157pub fn bounce_in(t: f32) -> f32 {
160 1.0 - bounce_out(1.0 - t)
161}
162
163pub fn bounce_out(t: f32) -> f32 {
164 if t < 1.0 / BOUNCE_GRAVITY {
165 BOUNCE_AMPLITUDE * t * t
166 } else if t < 2.0 / BOUNCE_GRAVITY {
167 let t = t - 1.5 / BOUNCE_GRAVITY;
168 BOUNCE_AMPLITUDE * t * t + 0.75
169 } else if t < 2.5 / BOUNCE_GRAVITY {
170 let t = t - 2.25 / BOUNCE_GRAVITY;
171 BOUNCE_AMPLITUDE * t * t + 0.9375
172 } else {
173 let t = t - 2.625 / BOUNCE_GRAVITY;
174 BOUNCE_AMPLITUDE * t * t + 0.984375
175 }
176}
177
178pub fn bounce_inout(t: f32) -> f32 {
179 if t < 0.5 {
180 (1.0 - bounce_out(1.0 - 2.0 * t)) / 2.0
181 } else {
182 (1.0 + bounce_out(-1.0 + 2.0 * t)) / 2.0
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189
190 macro_rules! test_start_at_0 {
191 ($($ease_fn:ident),*) => {
192 paste::paste! {
193 $(
194 #[test]
195 fn [<test_ease_ $ease_fn _starts_at_0>]() {
196 assert!(f32::abs($ease_fn(0.0) - 0.0) < f32::EPSILON);
197 }
198 )*
199 }
200 }
201 }
202
203 macro_rules! test_end_at_1 {
204 ($($ease_fn:ident),*) => {
205 paste::paste! {
206 $(
207 #[test]
208 fn [<test_ease_ $ease_fn _ends_at_1>]() {
209 assert!(f32::abs($ease_fn(1.0) - 1.0) < f32::EPSILON);
210 }
211 )*
212 }
213 }
214 }
215
216 test_start_at_0![
217 linear,
218 quad_in,
219 quad_out,
220 quad_inout,
221 cubic_in,
222 cubic_out,
223 cubic_inout,
224 quart_in,
225 quart_out,
226 quart_inout,
227 quint_in,
228 quint_out,
229 quint_inout,
230 circ_in,
231 circ_out,
232 circ_inout,
233 expo_in,
234 expo_out,
235 expo_inout,
236 sine_in,
237 sine_out,
238 sine_inout,
239 bounce_in,
240 bounce_out,
241 bounce_inout
242 ];
243
244 test_end_at_1![
245 linear,
246 quad_in,
247 quad_out,
248 quad_inout,
249 cubic_in,
250 cubic_out,
251 cubic_inout,
252 quart_in,
253 quart_out,
254 quart_inout,
255 quint_in,
256 quint_out,
257 quint_inout,
258 circ_in,
259 circ_out,
260 circ_inout,
261 expo_in,
262 expo_out,
263 expo_inout,
264 sine_in,
265 sine_out,
266 sine_inout,
267 bounce_in,
268 bounce_out,
269 bounce_inout
270 ];
271}