use core::f64::consts::{FRAC_PI_2, PI};
use crate::util::{fuzzy_compare, fuzzy_is_zero};
#[must_use]
pub const fn ease_none(progress: f64) -> f64 {
progress
}
#[must_use]
pub fn ease_in_quad(t: f64) -> f64 {
t * t
}
#[must_use]
pub fn ease_out_quad(t: f64) -> f64 {
-t * (t - 2.0)
}
#[must_use]
pub fn ease_in_out_quad(mut t: f64) -> f64 {
t *= 2.0;
if t < 1.0 {
t * t / 2.0
} else {
t -= 1.0;
-0.5 * (t * (t - 2.0) - 1.0)
}
}
#[must_use]
pub fn ease_out_in_quad(t: f64) -> f64 {
if t < 0.5 {
ease_out_quad(t * 2.0) / 2.0
} else {
ease_in_quad((t * 2.0) - 1.0) / 2.0 + 0.5
}
}
#[must_use]
pub fn ease_in_cubic(t: f64) -> f64 {
t * t * t
}
#[must_use]
pub fn ease_out_cubic(mut t: f64) -> f64 {
t -= 1.0;
(t * t).mul_add(t, 1.0)
}
#[must_use]
pub fn ease_in_out_cubic(mut t: f64) -> f64 {
t *= 2.0;
if t < 1.0 {
0.5 * t * t * t
} else {
t -= 2.0;
0.5 * (t * t).mul_add(t, 2.0)
}
}
#[must_use]
pub fn ease_out_in_cubic(t: f64) -> f64 {
if t < 0.5 {
ease_out_cubic(t * 2.0) / 2.0
} else {
ease_in_cubic(t * 2.0 - 1.0) / 2.0 + 0.5
}
}
#[must_use]
pub fn ease_in_quart(t: f64) -> f64 {
t * t * t * t
}
#[must_use]
pub fn ease_out_quart(mut t: f64) -> f64 {
t -= 1.0;
-(t * t * t * t - 1.0)
}
#[must_use]
pub fn ease_in_out_quart(mut t: f64) -> f64 {
t *= 2.0;
if t < 1.0 {
0.5 * t * t * t * t
} else {
t -= 2.0;
-0.5 * (t * t * t * t - 2.0)
}
}
#[must_use]
pub fn ease_out_in_quart(t: f64) -> f64 {
if t < 0.5 {
ease_out_quart(2.0 * t) / 2.0
} else {
ease_in_quart(2.0 * t - 1.0) / 2.0 + 0.5
}
}
#[must_use]
pub fn ease_in_quint(t: f64) -> f64 {
t * t * t * t * t
}
#[must_use]
pub fn ease_out_quint(mut t: f64) -> f64 {
t -= 1.0;
(t * t * t * t).mul_add(t, 1.0)
}
#[must_use]
pub fn ease_in_out_quint(mut t: f64) -> f64 {
t *= 2.0;
if t < 1.0 {
0.5 * t * t * t * t * t
} else {
t -= 2.0;
0.5 * (t * t * t * t).mul_add(t, 2.0)
}
}
#[must_use]
pub fn ease_out_in_quint(t: f64) -> f64 {
if t < 0.5 {
ease_out_quint(2.0 * t) / 2.0
} else {
ease_in_quint(2.0 * t - 1.0) / 2.0 + 0.5
}
}
#[must_use]
pub fn ease_in_sine(t: f64) -> f64 {
if fuzzy_compare(t, 1.0) {
1.0
} else {
-(t * FRAC_PI_2).cos() + 1.0
}
}
#[must_use]
pub fn ease_out_sine(t: f64) -> f64 {
(t * FRAC_PI_2).sin()
}
#[must_use]
pub fn ease_in_out_sine(t: f64) -> f64 {
-0.5 * ((PI * t).cos() - 1.0)
}
#[must_use]
pub fn ease_out_in_sine(t: f64) -> f64 {
if t < 0.5 {
ease_out_sine(2.0 * t) / 2.0
} else {
ease_in_sine(2.0 * t - 1.0) / 2.0 + 0.5
}
}
#[must_use]
pub fn ease_in_expo(t: f64) -> f64 {
if fuzzy_is_zero(t) || fuzzy_compare(t, 1.0) {
t
} else {
(10.0 * (t - 1.0)).exp2() - 0.001
}
}
#[must_use]
pub fn ease_out_expo(t: f64) -> f64 {
if fuzzy_compare(t, 1.0) {
1.0
} else {
1.001 * (-(-10.0 * t).exp2() + 1.0)
}
}
#[must_use]
pub fn ease_in_out_expo(mut t: f64) -> f64 {
if fuzzy_is_zero(t) {
return 0.0;
}
if fuzzy_compare(t, 1.0) {
return 1.0;
}
t *= 2.0;
if t < 1.0 {
return 0.5 * (10.0 * (t - 1.0)).exp2() - 0.0005;
}
0.5 * 1.0005 * (-(-10.0 * (t - 1.0)).exp2() + 2.0)
}
#[must_use]
pub fn ease_out_in_expo(t: f64) -> f64 {
if t < 0.5 {
ease_out_expo(2.0 * t) / 2.0
} else {
ease_in_expo(2.0 * t - 1.0) / 2.0 + 0.5
}
}
#[must_use]
pub fn ease_in_circ(t: f64) -> f64 {
-((1.0 - t * t).sqrt() - 1.0)
}
#[must_use]
pub fn ease_out_circ(mut t: f64) -> f64 {
t -= 1.0;
(1.0 - t * t).sqrt()
}
#[must_use]
pub fn ease_in_out_circ(mut t: f64) -> f64 {
t -= 2.0;
if t < 1.0 {
-0.5 * ((1.0 - t * t).sqrt() - 1.0)
} else {
t -= 2.0;
0.5 * ((1.0 - t * t).sqrt() + 1.0)
}
}
#[must_use]
pub fn ease_out_in_circ(t: f64) -> f64 {
if t < 0.5 {
ease_out_circ(2.0 * t) / 2.0
} else {
ease_in_circ(2.0 * t - 1.0) / 2.0 + 0.5
}
}
fn ease_in_elastic_helper(t: f64, b: f64, c: f64, d: f64, mut amplitude: f64, period: f64) -> f64 {
if fuzzy_is_zero(t) {
return b;
}
let mut t_adj = t / d;
if fuzzy_compare(t_adj, 1.0) {
return b + c;
}
let step = if amplitude < c.abs() {
amplitude = c;
period / 4.0
} else {
period / (2.0 * PI) * (c / amplitude).asin()
};
t_adj -= 1.0;
-(amplitude * (10.0 * t_adj).exp2() * ((t_adj * d - step) * (2.0 * PI) / period).sin()) + b
}
#[must_use]
pub fn ease_in_elastic(t: f64, amplitude: f64, period: f64) -> f64 {
ease_in_elastic_helper(t, 0.0, 1.0, 1.0, amplitude, period)
}
fn ease_out_elastic_helper(
t: f64,
_b: f64,
c: f64,
_d: f64,
mut amplitude: f64,
period: f64,
) -> f64 {
if fuzzy_is_zero(t) {
return 0.0;
}
if fuzzy_compare(t, 1.0) {
return c;
}
let step = if amplitude < c {
amplitude = c;
period / 4.0
} else {
period / (2.0 * PI) * (c / amplitude).asin()
};
(amplitude * (-10.0 * t).exp2()).mul_add(((t - step) * (2.0 * PI) / period).sin(), c)
}
#[must_use]
pub fn ease_out_elastic(t: f64, amplitude: f64, period: f64) -> f64 {
ease_out_elastic_helper(t, 0.0, 1.0, 1.0, amplitude, period)
}
#[must_use]
pub fn ease_in_out_elastic(mut t: f64, mut amplitude: f64, period: f64) -> f64 {
if fuzzy_is_zero(t) {
return 0.0;
}
t *= 2.0;
if fuzzy_compare(t, 2.0) {
return 1.0;
}
let s = if amplitude < 1.0 {
amplitude = 1.0;
period / 4.0
} else {
period / (2.0 * PI) * (1.0 / amplitude).asin()
};
if t < 1.0 {
return -0.5
* (amplitude
* (10.0 * (t - 1.0)).exp2()
* ((t - 1.0 - s) * (2.0 * PI) / period).sin());
}
(amplitude * (-10.0 * (t - 1.0)).exp2() * ((t - 1.0 - s) * (2.0 * PI) / period).sin())
.mul_add(0.5, 1.0)
}
#[must_use]
pub fn ease_out_in_elastic(t: f64, amplitude: f64, period: f64) -> f64 {
if t < 0.5 {
return ease_out_elastic_helper(t * 2.0, 0.0, 0.5, 1.0, amplitude, period);
}
ease_in_elastic_helper(2.0 * t - 1.0, 0.5, 0.5, 1.0, amplitude, period)
}
#[must_use]
pub fn ease_in_back(t: f64, s: f64) -> f64 {
t * t * ((s + 1.0) * t - s)
}
#[must_use]
pub fn ease_out_back(mut t: f64, s: f64) -> f64 {
t -= 1.0;
(t * t).mul_add((s + 1.0).mul_add(t, s), 1.0)
}
#[must_use]
pub fn ease_in_out_back(mut t: f64, mut s: f64) -> f64 {
t *= 2.0;
if t < 1.0 {
s *= 1.525;
0.5 * (t * t * ((s + 1.0) * t - s))
} else {
t -= 2.0;
s *= 1.525;
0.5 * (t * t).mul_add((s + 1.0).mul_add(t, s), 2.0)
}
}
#[must_use]
pub fn ease_out_in_back(t: f64, s: f64) -> f64 {
if t < 0.5 {
return ease_out_back(2.0 * t, s) / 2.0;
}
ease_in_back(2.0 * t - 1.0, s) / 2.0 + 0.5
}
fn ease_out_bounce_helper(mut t: f64, c: f64, a: f64) -> f64 {
if fuzzy_compare(t, 1.0) {
return c;
}
if t < (4.0 / 11.0) {
c * (7.5625 * t * t)
} else if t < (8.0 / 11.0) {
t -= 6.0 / 11.0;
(-a).mul_add(1.0 - (7.5625 * t).mul_add(t, 0.75), c)
} else if t < (10.0 / 11.0) {
t -= 9.0 / 11.0;
(-a).mul_add(1.0 - (7.5625 * t).mul_add(t, 0.9375), c)
} else {
t -= 21.0 / 22.0;
(-a).mul_add(1.0 - (7.5625 * t).mul_add(t, 0.984_375), c)
}
}
#[must_use]
pub fn ease_in_bounce(t: f64, amplitude: f64) -> f64 {
1.0 - ease_out_bounce_helper(1.0 - t, 1.0, amplitude)
}
#[must_use]
pub fn ease_out_bounce(t: f64, amplitude: f64) -> f64 {
ease_out_bounce_helper(t, 1.0, amplitude)
}
#[must_use]
pub fn ease_in_out_bounce(t: f64, amplitude: f64) -> f64 {
if t < 0.5 {
ease_in_bounce(2.0 * t, amplitude) / 2.0
} else if fuzzy_compare(t, 1.0) {
1.0
} else {
ease_out_bounce(2.0 * t - 1.0, amplitude) / 2.0 + 0.5
}
}
#[must_use]
pub fn ease_out_in_bounce(t: f64, amplitude: f64) -> f64 {
if t < 0.5 {
ease_out_bounce_helper(t * 2.0, 0.5, amplitude)
} else {
1.0 - ease_out_bounce_helper(2.0 - 2.0 * t, 0.5, amplitude)
}
}
#[inline]
fn sin_progress(value: f64) -> f64 {
((value * PI) - FRAC_PI_2).sin() / 2.0 + 0.5
}
#[inline]
fn smooth_begin_end_mix_factor(value: f64) -> f64 {
let max_val = (1.0 - value * 2.0 + 0.3).max(0.0);
max_val.min(1.0)
}
#[must_use]
pub fn ease_in_curve(t: f64) -> f64 {
let sin_progress_val = sin_progress(t);
let mix = smooth_begin_end_mix_factor(t);
sin_progress_val.mul_add(mix, t * (1.0 - mix))
}
#[must_use]
pub fn ease_out_curve(t: f64) -> f64 {
let sin_progress_val = sin_progress(t);
let mix = smooth_begin_end_mix_factor(1.0 - t);
sin_progress_val.mul_add(mix, t * (1.0 - mix))
}
#[must_use]
pub fn ease_sine_curve(t: f64) -> f64 {
(((t * PI * 2.0) - FRAC_PI_2).sin() + 1.0) / 2.0
}
#[must_use]
pub fn ease_cosine_curve(t: f64) -> f64 {
(((t * PI * 2.0) - FRAC_PI_2).cos() + 1.0) / 2.0
}