1#![feature(clamp)]
2
3use std::f32::consts::PI;
4
5const C1: f32 = 1.70158;
6const C2: f32 = C1 * 1.525;
7const C3: f32 = C1 + 1.0;
8const C4: f32 = (2.0 * PI) / 3.0;
9const C5: f32 = (2.0 * PI) / 4.5;
10const N1: f32 = 7.5625;
11const D1: f32 = 2.75;
12
13#[derive(Clone, Copy, Debug)]
14pub enum Easing {
15 Linear,
16 SineIn,
17 SineOut,
18 SineInOut,
19 QuadIn,
20 QuadOut,
21 QuadInOut,
22 CubicIn,
23 CubicOut,
24 CubicInOut,
25 QuartIn,
26 QuartOut,
27 QuartInOut,
28 QuintIn,
29 QuintOut,
30 QuintInOut,
31 ExpoIn,
32 ExpoOut,
33 ExpoInOut,
34 CircIn,
35 CircOut,
36 CircInOut,
37 BackIn,
38 BackOut,
39 BackInOut,
40 ElasticIn,
41 ElasticOut,
42 ElasticInOut,
43 BounceIn,
44 BounceOut,
45 BounceInOut,
46}
47
48pub fn ease(easing: Easing, x: f32) -> f32 {
49 let x = x.clamp(0.0, 1.0);
50 match easing {
51 Easing::Linear => x,
52
53 Easing::SineIn => 1.0 - (x * PI / 2.0).cos(),
55 Easing::SineOut => (x * PI / 2.0).sin(),
56 Easing::SineInOut => -((x * PI).cos() - 1.0) / 2.0,
57
58 Easing::QuadIn => x.powf(2.0),
60 Easing::QuadOut => 1.0 - (1.0 - x).powf(2.0),
61 Easing::QuadInOut => {
62 if x < 0.5 {
63 2.0 * x.powf(2.0)
64 } else {
65 1.0 - (-2.0 * x + 2.0).powf(2.0) / 2.0
66 }
67 }
68
69 Easing::CubicIn => x.powf(3.0),
71 Easing::CubicOut => 1.0 - (1.0 - x).powf(3.0),
72 Easing::CubicInOut => {
73 if x < 0.5 {
74 4.0 * x.powf(3.0)
75 } else {
76 1.0 - (-2.0 * x + 2.0).powf(3.0) / 2.0
77 }
78 }
79
80 Easing::QuartIn => x.powf(4.0),
82 Easing::QuartOut => 1.0 - (1.0 - x).powf(4.0),
83 Easing::QuartInOut => {
84 if x < 0.5 {
85 8.0 * x.powf(4.0)
86 } else {
87 1.0 - (-2.0 * x + 2.0).powf(4.0) / 2.0
88 }
89 }
90
91 Easing::QuintIn => x.powf(5.0),
93 Easing::QuintOut => 1.0 - (1.0 - x).powf(5.0),
94 Easing::QuintInOut => {
95 if x < 0.5 {
96 16.0 * x.powf(5.0)
97 } else {
98 1.0 - (-2.0 * x + 2.0).powf(5.0) / 2.0
99 }
100 }
101
102 Easing::ExpoIn => {
104 if x <= 0.0 {
105 0.0
106 } else {
107 2.0_f32.powf(10.0 * x - 10.0)
108 }
109 }
110 Easing::ExpoOut => {
111 if x >= 1.0 {
112 1.0
113 } else {
114 1.0 - 2.0_f32.powf(-10.0 * x)
115 }
116 }
117 Easing::ExpoInOut => {
118 if x <= 0.0 {
119 0.0
120 } else if x >= 1.0 {
121 1.0
122 } else if x < 0.5 {
123 2.0_f32.powf(20.0 * x - 10.0) / 2.0
124 } else {
125 (2.0 - 2.0_f32.powf(-20.0 * x + 10.0)) / 2.0
126 }
127 }
128
129 Easing::CircIn => 1.0 - (1.0 - x.powf(2.0)).sqrt(),
131 Easing::CircOut => (1.0 - (x - 1.0).powf(2.0)).sqrt(),
132 Easing::CircInOut => {
133 if x < 0.5 {
134 (1.0 - (1.0 - (2.0 * x).powf(2.0)).sqrt()) / 2.0
135 } else {
136 ((1.0 - (-2.0 * x + 2.0).powf(2.0)).sqrt() + 1.0) / 2.0
137 }
138 }
139
140 Easing::BackIn => C3 * x.powf(3.0) - C1 * x.powf(2.0),
142 Easing::BackOut => 1.0 + C3 * (x - 1.0).powf(3.0) + C1 * (x - 1.0).powf(2.0),
143 Easing::BackInOut => {
144 if x < 0.5 {
145 (2.0 * x).powf(2.0) * ((C2 + 1.0) * 2.0 * x - 2.0) / 2.0
146 } else {
147 ((2.0 * x - 2.0).powf(2.0) * ((C2 + 1.0) * (x * 2.0 - 2.0) + C2) + 2.0) / 2.0
148 }
149 }
150
151 Easing::ElasticIn => {
153 if x <= 0.0 {
154 0.0
155 } else if x >= 1.0 {
156 1.0
157 } else {
158 -(2.0_f32.powf(10.0 * x - 10.0)) * (C4 * (x * 10.0 - 10.75)).sin()
159 }
160 }
161 Easing::ElasticOut => {
162 if x <= 0.0 {
163 0.0
164 } else if x >= 1.0 {
165 1.0
166 } else {
167 2.0_f32.powf(-10.0 * x) * (C4 * (x * 10.0 - 0.75)).sin() + 1.0
168 }
169 }
170 Easing::ElasticInOut => {
171 if x <= 0.0 {
172 0.0
173 } else if x >= 1.0 {
174 1.0
175 } else if x < 0.5 {
176 -(2.0_f32.powf(20.0 * x - 10.0) * (C5 * (20.0 * x - 11.125)).sin()) / 2.0
177 } else {
178 2.0_f32.powf(-20.0 * x + 10.0) * (C5 * (20.0 * x - 11.125)).sin() / 2.0 + 1.0
179 }
180 }
181
182 Easing::BounceIn => 1.0 - bounce_out(1.0 - x),
184 Easing::BounceOut => bounce_out(x),
185 Easing::BounceInOut => {
186 if x < 0.5 {
187 (1.0 - bounce_out(1.0 - 2.0 * x)) / 2.0
188 } else {
189 (1.0 + bounce_out(2.0 * x - 1.0)) / 2.0
190 }
191 }
192 }
193}
194
195fn bounce_out(x: f32) -> f32 {
196 if x < 1.0 / D1 {
197 N1 * x.powf(2.0)
198 } else if x < 2.0 / D1 {
199 let x = x - 1.5 / D1;
200 N1 * x.powf(2.0) + 0.75
201 } else if x < 2.5 / D1 {
202 let x = x - 2.25 / D1;
203 N1 * x.powf(2.0) + 0.9375
204 } else {
205 let x = x - 2.625 / D1;
206 N1 * x.powf(2.0) + 0.984_375
207 }
208}