use std::f32::consts::PI;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub enum EasingFunction {
Linear,
QuadIn,
QuadOut,
QuadInOut,
CubicIn,
CubicOut,
CubicInOut,
QuartIn,
QuartOut,
QuartInOut,
QuintIn,
QuintOut,
QuintInOut,
SineIn,
SineOut,
SineInOut,
ExpoIn,
ExpoOut,
ExpoInOut,
CircIn,
CircOut,
CircInOut,
BackIn,
BackOut,
BackInOut,
ElasticIn,
ElasticOut,
ElasticInOut,
BounceIn,
BounceOut,
BounceInOut,
}
impl Default for EasingFunction {
fn default() -> Self {
Self::Linear
}
}
impl EasingFunction {
pub fn evaluate(&self, t: f32) -> f32 {
let t = t.clamp(0.0, 1.0);
match self {
Self::Linear => t,
Self::QuadIn => t * t,
Self::QuadOut => 1.0 - (1.0 - t) * (1.0 - t),
Self::QuadInOut => {
if t < 0.5 {
2.0 * t * t
} else {
1.0 - (-2.0 * t + 2.0).powi(2) / 2.0
}
}
Self::CubicIn => t * t * t,
Self::CubicOut => 1.0 - (1.0 - t).powi(3),
Self::CubicInOut => {
if t < 0.5 {
4.0 * t * t * t
} else {
1.0 - (-2.0 * t + 2.0).powi(3) / 2.0
}
}
Self::QuartIn => t * t * t * t,
Self::QuartOut => 1.0 - (1.0 - t).powi(4),
Self::QuartInOut => {
if t < 0.5 {
8.0 * t * t * t * t
} else {
1.0 - (-2.0 * t + 2.0).powi(4) / 2.0
}
}
Self::QuintIn => t * t * t * t * t,
Self::QuintOut => 1.0 - (1.0 - t).powi(5),
Self::QuintInOut => {
if t < 0.5 {
16.0 * t * t * t * t * t
} else {
1.0 - (-2.0 * t + 2.0).powi(5) / 2.0
}
}
Self::SineIn => 1.0 - (t * PI / 2.0).cos(),
Self::SineOut => (t * PI / 2.0).sin(),
Self::SineInOut => -(PI * t).cos() / 2.0 + 0.5,
Self::ExpoIn => {
if t == 0.0 {
0.0
} else {
(2.0f32).powf(10.0 * t - 10.0)
}
}
Self::ExpoOut => {
if t == 1.0 {
1.0
} else {
1.0 - (2.0f32).powf(-10.0 * t)
}
}
Self::ExpoInOut => {
if t == 0.0 {
0.0
} else if t == 1.0 {
1.0
} else if t < 0.5 {
(2.0f32).powf(20.0 * t - 10.0) / 2.0
} else {
(2.0 - (2.0f32).powf(-20.0 * t + 10.0)) / 2.0
}
}
Self::CircIn => 1.0 - (1.0 - t * t).sqrt(),
Self::CircOut => (1.0 - (t - 1.0).powi(2)).sqrt(),
Self::CircInOut => {
if t < 0.5 {
(1.0 - (1.0 - (2.0 * t).powi(2)).sqrt()) / 2.0
} else {
((1.0 - (-2.0 * t + 2.0).powi(2)).sqrt() + 1.0) / 2.0
}
}
Self::BackIn => {
let c1 = 1.70158;
let c3 = c1 + 1.0;
c3 * t * t * t - c1 * t * t
}
Self::BackOut => {
let c1 = 1.70158;
let c3 = c1 + 1.0;
1.0 + c3 * (t - 1.0).powi(3) + c1 * (t - 1.0).powi(2)
}
Self::BackInOut => {
let c1 = 1.70158;
let c2 = c1 * 1.525;
if t < 0.5 {
((2.0 * t).powi(2) * ((c2 + 1.0) * 2.0 * t - c2)) / 2.0
} else {
((2.0 * t - 2.0).powi(2) * ((c2 + 1.0) * (2.0 * t - 2.0) + c2) + 2.0) / 2.0
}
}
Self::ElasticIn => {
if t == 0.0 {
0.0
} else if t == 1.0 {
1.0
} else {
let c4 = 2.0 * PI / 3.0;
-(2.0f32).powf(10.0 * t - 10.0) * ((10.0 * t - 10.75) * c4).sin()
}
}
Self::ElasticOut => {
if t == 0.0 {
0.0
} else if t == 1.0 {
1.0
} else {
let c4 = 2.0 * PI / 3.0;
(2.0f32).powf(-10.0 * t) * ((10.0 * t - 0.75) * c4).sin() + 1.0
}
}
Self::ElasticInOut => {
if t == 0.0 {
0.0
} else if t == 1.0 {
1.0
} else {
let c5 = 2.0 * PI / 4.5;
if t < 0.5 {
-(2.0f32).powf(20.0 * t - 10.0) * ((20.0 * t - 11.125) * c5).sin() / 2.0
} else {
(2.0f32).powf(-20.0 * t + 10.0) * ((20.0 * t - 11.125) * c5).sin() / 2.0
+ 1.0
}
}
}
Self::BounceIn => 1.0 - Self::BounceOut.evaluate(1.0 - t),
Self::BounceOut => bounce_out(t),
Self::BounceInOut => {
if t < 0.5 {
(1.0 - bounce_out(1.0 - 2.0 * t)) / 2.0
} else {
(1.0 + bounce_out(2.0 * t - 1.0)) / 2.0
}
}
}
}
}
fn bounce_out(t: f32) -> f32 {
let n1 = 7.5625;
let d1 = 2.75;
if t < 1.0 / d1 {
n1 * t * t
} else if t < 2.0 / d1 {
let t = t - 1.5 / d1;
n1 * t * t + 0.75
} else if t < 2.5 / d1 {
let t = t - 2.25 / d1;
n1 * t * t + 0.9375
} else {
let t = t - 2.625 / d1;
n1 * t * t + 0.984375
}
}