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