Skip to main content

tween/tweens/
elastic.rs

1use core::f32::consts::TAU;
2
3const SIGMA: f32 = 0.075;
4const SIGMA_IN_OUT: f32 = 0.1125;
5const THREE_DOT_THREE_REPEATING: f32 = 10.0 / 3.0;
6const FORTY_FIVE: f32 = 2.222222;
7
8declare_tween!(
9    /// An elastic tween in. Go [here](https://easings.net/#easeInElastic) for a visual demonstration.
10    pub struct ElasticIn;
11
12    /// Creates a new [ElasticIn] Tweener.
13    pub fn elastic_in;
14
15    /// Creates a new [ElasticIn] Tweener at the given time.
16    pub fn elastic_in_at;
17
18    pub fn tween<Value: crate::TweenValue>(&mut self, value_delta: Value, mut percent: f32) -> Value {
19        if percent == 0.0 {
20            return value_delta.scale(0.0);
21        }
22
23        if percent == 1.0 {
24            return value_delta;
25        }
26
27        percent -= 1.0;
28
29        #[cfg(feature = "libm")]
30        let scalar = libm::powf(2.0, percent * 10.0);
31
32        #[cfg(feature = "std")]
33        let scalar = 2f32.powf(percent * 10.0);
34
35        let post_fix = value_delta.scale(scalar);
36        let temp = (percent - SIGMA) * TAU * THREE_DOT_THREE_REPEATING;
37
38        #[cfg(feature = "libm")]
39        let scalar = -libm::sinf(temp);
40
41        #[cfg(feature = "std")]
42        let scalar = -temp.sin();
43
44        post_fix.scale(scalar)
45    }
46);
47
48declare_tween!(
49    /// An elastic tween out. Go [here](https://easings.net/#easeOutElastic) for a visual demonstration.
50    pub struct ElasticOut;
51
52    /// Creates a new [ElasticOut] Tweener.
53    pub fn elastic_out;
54
55    /// Creates a new [ElasticOut] Tweener at the given time.
56    pub fn elastic_out_at;
57
58    pub fn tween<Value: crate::TweenValue>(&mut self, value_delta: Value,  percent: f32) -> Value {
59        if percent == 0.0 {
60            return value_delta.scale(0.0);
61        }
62
63        if percent == 1.0 {
64            return value_delta;
65        }
66
67        let temp = (percent - SIGMA) * TAU * THREE_DOT_THREE_REPEATING;
68
69        #[cfg(feature = "libm")]
70        let scalar = libm::powf(2.0, -10.0 * percent) * libm::sinf(temp);
71
72        #[cfg(feature = "std")]
73        let scalar = 2f32.powf(-10.0 * percent) * temp.sin();
74
75        value_delta.scale(scalar) + value_delta
76    }
77);
78
79declare_tween!(
80    /// An elastic tween in and out. Go [here](https://easings.net/#easeInOutElastic) for a visual demonstration.
81    pub struct ElasticInOut;
82
83    /// Creates a new [ElasticInOut] Tweener.
84    pub fn elastic_in_out;
85
86    /// Creates a new [ElasticInOut] Tweener at the given time.
87    pub fn elastic_in_out_at;
88
89    pub fn tween<Value: crate::TweenValue>(&mut self, value_delta: Value, mut percent: f32) -> Value {
90        if percent == 0.0 {
91            return value_delta.scale(0.0);
92        }
93
94        if percent == 1.0 {
95            return value_delta;
96        }
97
98        percent = (percent * 2.0) - 1.0;
99
100        if percent < 0.0 {
101            #[cfg(feature = "libm")]
102            let scalar = libm::powf(2.0, percent * 10.0);
103
104            #[cfg(feature = "std")]
105            let scalar = 2f32.powf(percent * 10.0);
106
107            let post_fix = value_delta.scale(scalar);
108            let temp = (percent - SIGMA_IN_OUT) * TAU * FORTY_FIVE;
109
110            #[cfg(feature = "libm")]
111            let temp_sin = libm::sinf(temp);
112
113            #[cfg(feature = "std")]
114            let temp_sin = temp.sin();
115
116            post_fix.scale(-0.5 * temp_sin)
117        } else {
118            #[cfg(feature = "libm")]
119            let scalar = libm::powf(2.0, percent * -10.0);
120
121            #[cfg(feature = "std")]
122            let scalar = 2f32.powf(-10.0 * percent);
123
124            let post_fix = value_delta.scale(scalar);
125            let temp = (percent - SIGMA_IN_OUT) * TAU * FORTY_FIVE;
126
127            #[cfg(feature = "libm")]
128            let temp_sin = libm::sinf(temp);
129
130            #[cfg(feature = "std")]
131            let temp_sin = temp.sin();
132
133            post_fix.scale(temp_sin * 0.5) + value_delta
134        }
135
136    }
137);
138
139test_tween!(Elastic);