1 //! A module contains implementation of ease functions.
2 
3 #[allow(missing_docs)]
4 #[derive(Copy, Clone, PartialEq)]
5 pub enum EaseFunction {
6     QuadraticIn,
7     QuadraticOut,
8     QuadraticInOut,
9 
10     CubicIn,
11     CubicOut,
12     CubicInOut,
13 
14     QuarticIn,
15     QuarticOut,
16     QuarticInOut,
17 
18     QuinticIn,
19     QuinticOut,
20     QuinticInOut,
21 
22     SineIn,
23     SineOut,
24     SineInOut,
25 
26     CircularIn,
27     CircularOut,
28     CircularInOut,
29 
30     ExponentialIn,
31     ExponentialOut,
32     ExponentialInOut,
33 
34     ElasticIn,
35     ElasticOut,
36     ElasticInOut,
37 
38     BackIn,
39     BackOut,
40     BackInOut,
41 
42     BounceIn,
43     BounceOut,
44     BounceInOut,
45 }
46 
47 #[allow(missing_docs)]
48 pub trait Ease {
49     /// Calculate the eased value, normalized
calc(self, f: EaseFunction) -> Self50     fn calc(self, f: EaseFunction) -> Self;
51 
quadratic_in(self) -> Self52     fn quadratic_in(self) -> Self;
quadratic_out(self) -> Self53     fn quadratic_out(self) -> Self;
quadratic_in_out(self) -> Self54     fn quadratic_in_out(self) -> Self;
55 
cubic_in(self) -> Self56     fn cubic_in(self) -> Self;
cubic_out(self) -> Self57     fn cubic_out(self) -> Self;
cubic_in_out(self) -> Self58     fn cubic_in_out(self) -> Self;
59 
quartic_in(self) -> Self60     fn quartic_in(self) -> Self;
quartic_out(self) -> Self61     fn quartic_out(self) -> Self;
quartic_in_out(self) -> Self62     fn quartic_in_out(self) -> Self;
63 
quintic_in(self) -> Self64     fn quintic_in(self) -> Self;
quintic_out(self) -> Self65     fn quintic_out(self) -> Self;
quintic_in_out(self) -> Self66     fn quintic_in_out(self) -> Self;
67 
sine_in(self) -> Self68     fn sine_in(self) -> Self;
sine_out(self) -> Self69     fn sine_out(self) -> Self;
sine_in_out(self) -> Self70     fn sine_in_out(self) -> Self;
71 
circular_in(self) -> Self72     fn circular_in(self) -> Self;
circular_out(self) -> Self73     fn circular_out(self) -> Self;
circular_in_out(self) -> Self74     fn circular_in_out(self) -> Self;
75 
exponential_in(self) -> Self76     fn exponential_in(self) -> Self;
exponential_out(self) -> Self77     fn exponential_out(self) -> Self;
exponential_in_out(self) -> Self78     fn exponential_in_out(self) -> Self;
79 
elastic_in(self) -> Self80     fn elastic_in(self) -> Self;
elastic_out(self) -> Self81     fn elastic_out(self) -> Self;
elastic_in_out(self) -> Self82     fn elastic_in_out(self) -> Self;
83 
back_in(self) -> Self84     fn back_in(self) -> Self;
back_out(self) -> Self85     fn back_out(self) -> Self;
back_in_out(self) -> Self86     fn back_in_out(self) -> Self;
87 
bounce_in(self) -> Self88     fn bounce_in(self) -> Self;
bounce_out(self) -> Self89     fn bounce_out(self) -> Self;
bounce_in_out(self) -> Self90     fn bounce_in_out(self) -> Self;
91 }
92 
93 macro_rules! impl_ease_trait_for {
94     ($T: ident) => (
95         mod $T {
96             pub const PI_2: $T = 6.28318530717958647692528676655900576;
97 
98             pub fn clamp(p: $T) -> $T {
99                 match () {
100                     _ if p > 1.0 => 1.0,
101                     _ if p < 0.0 => 0.0,
102                     _ => p
103                 }
104             }
105         }
106         impl Ease for $T {
107             fn calc(self, f: EaseFunction) -> Self {
108                 match f {
109                     EaseFunction::QuadraticIn => self.quadratic_in(),
110                     EaseFunction::QuadraticOut => self.quadratic_out(),
111                     EaseFunction::QuadraticInOut => self.quadratic_in_out(),
112 
113                     EaseFunction::CubicIn => self.cubic_in(),
114                     EaseFunction::CubicOut => self.cubic_out(),
115                     EaseFunction::CubicInOut => self.cubic_in_out(),
116 
117                     EaseFunction::QuarticIn => self.quartic_in(),
118                     EaseFunction::QuarticOut => self.quartic_out(),
119                     EaseFunction::QuarticInOut => self.quartic_in_out(),
120 
121                     EaseFunction::QuinticIn => self.quintic_in(),
122                     EaseFunction::QuinticOut => self.quintic_out(),
123                     EaseFunction::QuinticInOut => self.quintic_in_out(),
124 
125                     EaseFunction::SineIn => self.sine_in(),
126                     EaseFunction::SineOut => self.sine_out(),
127                     EaseFunction::SineInOut => self.sine_in_out(),
128 
129                     EaseFunction::CircularIn => self.circular_in(),
130                     EaseFunction::CircularOut => self.circular_out(),
131                     EaseFunction::CircularInOut => self.circular_in_out(),
132 
133                     EaseFunction::ExponentialIn => self.exponential_in(),
134                     EaseFunction::ExponentialOut => self.exponential_out(),
135                     EaseFunction::ExponentialInOut => self.exponential_in_out(),
136 
137                     EaseFunction::ElasticIn => self.elastic_in(),
138                     EaseFunction::ElasticOut => self.elastic_out(),
139                     EaseFunction::ElasticInOut => self.elastic_in_out(),
140 
141                     EaseFunction::BackIn => self.back_in(),
142                     EaseFunction::BackOut => self.back_out(),
143                     EaseFunction::BackInOut => self.back_in_out(),
144 
145                     EaseFunction::BounceIn => self.bounce_in(),
146                     EaseFunction::BounceOut => self.bounce_out(),
147                     EaseFunction::BounceInOut => self.bounce_in_out(),
148                 }
149             }
150 
151             fn quadratic_in(self) -> Self {
152                 let p = $T::clamp(self);
153                 p * p
154             }
155 
156             fn quadratic_out(self) -> Self {
157                 let p = $T::clamp(self);
158                 -(p * (p - 2.0))
159             }
160 
161             fn quadratic_in_out(self) -> Self {
162                 let p = $T::clamp(self);
163                 if p < 0.5 {
164                     2.0 * p * p
165                 } else {
166                     (-2.0 * p * p) + (4.0 * p) - 1.0
167                 }
168             }
169 
170 
171             fn cubic_in(self) -> Self {
172                 let p = $T::clamp(self);
173                 p * p * p
174             }
175 
176             fn cubic_out(self) -> Self {
177                 let p = $T::clamp(self);
178                 let f = p - 1.0;
179                 f * f * f + 1.0
180             }
181 
182             fn cubic_in_out(self) -> Self {
183                 let p = $T::clamp(self);
184                 if p < 0.5 {
185                     4.0 * p * p * p
186                 } else {
187                     let f = (2.0 * p) - 2.0;
188                     0.5 * f * f * f + 1.0
189                 }
190             }
191 
192 
193             fn quartic_in(self) -> Self {
194                 let p = $T::clamp(self);
195                 p * p * p * p
196             }
197 
198             fn quartic_out(self) -> Self {
199                 let p = $T::clamp(self);
200                 let f = p - 1.0;
201                 f * f * f * (1.0 - p) + 1.0
202             }
203 
204             fn quartic_in_out(self) -> Self {
205                 let p = $T::clamp(self);
206                 if p < 0.5 {
207                     8.0 * p * p * p * p
208                 } else {
209                     let f = p - 1.0;
210                     -8.0 * f * f * f * f + 1.0
211                 }
212             }
213 
214 
215             fn quintic_in(self) -> Self {
216                 let p = $T::clamp(self);
217                 p * p * p * p * p
218             }
219 
220             fn quintic_out(self) -> Self {
221                 let p = $T::clamp(self);
222                 let f = p - 1.0;
223                 f * f * f * f * f + 1.0
224             }
225 
226             fn quintic_in_out(self) -> Self {
227                 let p = $T::clamp(self);
228                 if p < 0.5  {
229                     16.0 * p * p * p * p * p
230                 } else {
231                     let f = (2.0 * p) - 2.0;
232                     0.5 * f * f * f * f * f + 1.0
233                 }
234             }
235 
236 
237             fn sine_in(self) -> Self {
238                 use self::$T::PI_2;
239                 let p = $T::clamp(self);
240                 ((p - 1.0) * PI_2).sin() + 1.0
241             }
242 
243             fn sine_out(self) -> Self {
244                 use self::$T::PI_2;
245                 let p = $T::clamp(self);
246                 (p * PI_2).sin()
247             }
248 
249             fn sine_in_out(self) -> Self {
250                 use std::$T::consts::PI;
251                 let p = $T::clamp(self);
252                 0.5 * (1.0 - (p * PI).cos())
253             }
254 
255 
256             fn circular_in(self) -> Self {
257                 let p = $T::clamp(self);
258                 1.0 - (1.0 - (p * p)).sqrt()
259             }
260 
261             fn circular_out(self) -> Self {
262                 let p = $T::clamp(self);
263                 ((2.0 - p) * p).sqrt()
264             }
265 
266             fn circular_in_out(self) -> Self {
267                 let p = $T::clamp(self);
268                 if p < 0.5 {
269                     0.5 * (1.0 - (1.0 - 4.0 * (p * p)).sqrt())
270                 } else {
271                     0.5 * ((-((2.0 * p) - 3.0) * ((2.0 * p) - 1.0)).sqrt() + 1.0)
272                 }
273             }
274 
275 
276             fn exponential_in(self) -> Self {
277                 if self <= 0.0 {
278                     0.0
279                 } else {
280                     (2.0 as $T).powf(10.0 * (self.min(1.0) - 1.0))
281                 }
282             }
283 
284             fn exponential_out(self) -> Self {
285                 if self >= 1.0 {
286                     1.0
287                 } else {
288                     1.0 - (2.0 as $T).powf(-10.0 * self.max(0.0))
289                 }
290             }
291 
292             fn exponential_in_out(self) -> Self {
293                 if self <= 0.0 {
294                     return 0.0;
295                 }
296                 if self >= 1.0 {
297                     return 1.0;
298                 }
299 
300                 if self < 0.5  {
301                     0.5 * (2.0 as $T).powf((20.0 * self) - 10.0)
302                 } else {
303                     -0.5 * (2.0 as $T).powf((-20.0 * self) + 10.0) + 1.0
304                 }
305             }
306 
307 
308             fn elastic_in(self) -> Self {
309                 use self::$T::PI_2;
310                 let p = $T::clamp(self);
311                 (13.0 * PI_2 * p).sin() * (2.0 as $T).powf(10.0 * (p - 1.0))
312             }
313 
314             fn elastic_out(self) -> Self {
315                 use self::$T::PI_2;
316                 let p = $T::clamp(self);
317                 (-13.0 * PI_2 * (p + 1.0)).sin() * (2.0 as $T).powf(-10.0 * p) + 1.0
318             }
319 
320             fn elastic_in_out(self) -> Self {
321                 use self::$T::PI_2;
322                 let p = $T::clamp(self);
323                 if p < 0.5 {
324                     0.5 * (13.0 * PI_2 * (2.0 * p)).sin() * (2.0 as $T).powf(10.0 * ((2.0 * p) - 1.0))
325                 } else {
326                     0.5 * ((-13.0 * PI_2 * ((2.0 * p - 1.0) + 1.0)).sin()
327                            * (2.0 as $T).powf(-10.0 * (2.0 * p - 1.0)) + 2.0)
328                 }
329             }
330 
331 
332             fn back_in(self) -> Self {
333                 use std::$T::consts::PI;
334                 let p = $T::clamp(self);
335                 p * p * p - p * (p * PI).sin()
336             }
337 
338             fn back_out(self) -> Self {
339                 use std::$T::consts::PI;
340                 let p = $T::clamp(self);
341                 let f = 1.0 - p;
342                 1.0 - (f * f * f - f * (f * PI).sin())
343             }
344 
345             fn back_in_out(self) -> Self {
346                 use std::$T::consts::PI;
347                 let p = $T::clamp(self);
348                 if p < 0.5 {
349                     let f = 2.0 * p;
350                     0.5 * (f * f * f - f * (f * PI).sin())
351                 } else {
352                     let f = 1.0 - (2.0 * p - 1.0);
353                     0.5 * (1.0 - (f * f * f - f * (f * PI).sin())) + 0.5
354                 }
355             }
356 
357 
358             fn bounce_in(self) -> Self {
359                 let p = $T::clamp(self);
360                 1.0 - Ease::bounce_out(1.0 - p)
361             }
362 
363             fn bounce_out(self) -> Self {
364                 let p = $T::clamp(self);
365                 if p < 4.0 / 11.0 {
366                     (121.0 * p * p) / 16.0
367                 } else if p < 8.0 / 11.0 {
368                     (363.0 / 40.0 * p * p) - (99.0 / 10.0 * p) + 17.0 / 5.0
369                 } else if p < 9.0 / 10.0 {
370                     (4356.0 / 361.0 * p * p) - (35442.0 / 1805.0 * p) + 16061.0 / 1805.0
371                 } else {
372                     (54.0 / 5.0 * p * p) - (513.0 / 25.0 * p) + 268.0 / 25.0
373                 }
374             }
375 
376             fn bounce_in_out(self) -> Self {
377                 let p = $T::clamp(self);
378                 if p < 0.5 {
379                     0.5 * Ease::bounce_in(p * 2.0)
380                 } else {
381                     0.5 * Ease::bounce_out(p * 2.0 - 1.0) + 0.5
382                 }
383             }
384         }
385     )
386 }
387 
388 impl_ease_trait_for!(f32);
389 impl_ease_trait_for!(f64);
390