mirror of
https://github.com/danbulant/cushy
synced 2026-07-06 11:40:37 +00:00
Easings
This commit is contained in:
parent
126b324b55
commit
1bf1b082af
1 changed files with 333 additions and 1 deletions
334
src/animation.rs
334
src/animation.rs
|
|
@ -35,6 +35,7 @@
|
||||||
//! assert_eq!(reader.get(), 100);
|
//! assert_eq!(reader.get(), 100);
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
use std::f32::consts::PI;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::{ControlFlow, Deref};
|
use std::ops::{ControlFlow, Deref};
|
||||||
|
|
@ -769,10 +770,45 @@ impl LinearInterpolate for ZeroToOne {
|
||||||
|
|
||||||
/// Performs easing for value interpolation.
|
/// Performs easing for value interpolation.
|
||||||
pub trait Easing: Send + Sync + 'static {
|
pub trait Easing: Send + Sync + 'static {
|
||||||
/// Returns a ratio between 0.0 and 1.0 of
|
/// Eases a value ranging between zero and one. The resulting value does not
|
||||||
|
/// need to be bounded between zero and one.
|
||||||
fn ease(progress: ZeroToOne) -> f32;
|
fn ease(progress: ZeroToOne) -> f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /// An [`Easing`] function that produces a steady, linear transition.
|
||||||
|
// pub enum Linear {}
|
||||||
|
|
||||||
|
// impl Easing for Linear {
|
||||||
|
// fn ease(progress: ZeroToOne) -> f32 {
|
||||||
|
// *progress
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Think this macro has a long name? This is to ensure rustfmt wraps the closure
|
||||||
|
// onto its own line. Seriously, try shortening the name and see how it changes
|
||||||
|
// the formatting. If it keeps all closures on a single line, remove this
|
||||||
|
// comment and change this back to `declare_easing_function`.
|
||||||
|
macro_rules! declare_easing_function_implementation {
|
||||||
|
($name:ident, $anchor_name:ident, $description:literal, $closure:expr) => {
|
||||||
|
/// An [`Easing`] function that eases
|
||||||
|
#[doc = $description]
|
||||||
|
#[doc = concat!(".\n\nSee <https://easings.net/#", stringify!($anchor_name), "> for a visualization and more information.")]
|
||||||
|
pub enum $name {}
|
||||||
|
|
||||||
|
impl Easing for $name {
|
||||||
|
fn ease(progress: ZeroToOne) -> f32 {
|
||||||
|
let closure = force_closure_type($closure);
|
||||||
|
closure(*progress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// This prevents the closures from requiring the parameter to be type annotated.
|
||||||
|
fn force_closure_type(f: impl Fn(f32) -> f32) -> impl Fn(f32) -> f32 {
|
||||||
|
f
|
||||||
|
}
|
||||||
|
|
||||||
/// An [`Easing`] function that produces a steady, linear transition.
|
/// An [`Easing`] function that produces a steady, linear transition.
|
||||||
pub enum Linear {}
|
pub enum Linear {}
|
||||||
|
|
||||||
|
|
@ -781,3 +817,299 @@ impl Easing for Linear {
|
||||||
*progress
|
*progress
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInSine,
|
||||||
|
easeInSine,
|
||||||
|
"in using a sine wave",
|
||||||
|
|percent| 1. - (percent * PI).cos() / 2.
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseOutSine,
|
||||||
|
easeOutSine,
|
||||||
|
"out using a sine wave",
|
||||||
|
|percent| (percent * PI).sin() / 2.
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInOutSine,
|
||||||
|
easeInOutSine,
|
||||||
|
"in and out using a sine wave",
|
||||||
|
|percent| -((percent * PI).cos() - 1.) / 2.
|
||||||
|
);
|
||||||
|
|
||||||
|
fn squared(value: f32) -> f32 {
|
||||||
|
value * value
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInQuadradic,
|
||||||
|
easeInQuad,
|
||||||
|
"in using a quadradic (x^2) curve",
|
||||||
|
squared
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseOutQuadradic,
|
||||||
|
easeOutQuad,
|
||||||
|
"out using a quadradic (x^2) curve",
|
||||||
|
|percent| 1. - squared(1. - percent)
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInOutQuadradic,
|
||||||
|
easeInOutQuad,
|
||||||
|
"in and out using a quadradic (x^2) curve",
|
||||||
|
|percent| {
|
||||||
|
if percent < 0.5 {
|
||||||
|
2. * percent * percent
|
||||||
|
} else {
|
||||||
|
1. - squared(-2. * percent + 2.) / 2.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
fn cubed(value: f32) -> f32 {
|
||||||
|
value * value * value
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInCubic,
|
||||||
|
easeInCubic,
|
||||||
|
"in using a cubic (x^3) curve",
|
||||||
|
cubed
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseOutCubic,
|
||||||
|
easeOutCubic,
|
||||||
|
"out using a cubic (x^3) curve",
|
||||||
|
|percent| 1. - cubed(1. - percent)
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInOutCubic,
|
||||||
|
easeInOutCubic,
|
||||||
|
"in and out using a cubic (x^3) curve",
|
||||||
|
|percent| {
|
||||||
|
if percent < 0.5 {
|
||||||
|
4. * cubed(percent)
|
||||||
|
} else {
|
||||||
|
1. - cubed(-2. * percent + 2.) / 2.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
fn quarted(value: f32) -> f32 {
|
||||||
|
let sq = squared(value);
|
||||||
|
squared(sq)
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInQuartic,
|
||||||
|
easeInQuart,
|
||||||
|
"in using a quartic (x^4) curve",
|
||||||
|
quarted
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseOutQuartic,
|
||||||
|
easeOutQuart,
|
||||||
|
"out using a quartic (x^4) curve",
|
||||||
|
|percent| 1. - quarted(1. - percent)
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInOutQuartic,
|
||||||
|
easeInOutQuart,
|
||||||
|
"in and out using a quartic (x^4) curve",
|
||||||
|
|percent| {
|
||||||
|
if percent < 0.5 {
|
||||||
|
8. * quarted(percent)
|
||||||
|
} else {
|
||||||
|
1. - quarted(-2. * percent + 2.) / 2.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
fn quinted(value: f32) -> f32 {
|
||||||
|
let squared = squared(value);
|
||||||
|
let cubed = squared * value;
|
||||||
|
squared * cubed
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInQuintic,
|
||||||
|
easeInQuint,
|
||||||
|
"in using a quintic (x^5) curve",
|
||||||
|
quinted
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseOutQuintic,
|
||||||
|
easeOutQuint,
|
||||||
|
"out using a quintic (x^5) curve",
|
||||||
|
|percent| 1. - quinted(1. - percent)
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInOutQuintic,
|
||||||
|
easeInOutQuint,
|
||||||
|
"in and out using a quintic (x^5) curve",
|
||||||
|
|percent| {
|
||||||
|
if percent < 0.5 {
|
||||||
|
8. * quinted(percent)
|
||||||
|
} else {
|
||||||
|
1. - quinted(-2. * percent + 2.) / 2.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInExponential,
|
||||||
|
easeInExpo,
|
||||||
|
"in using an expenential curve",
|
||||||
|
|percent| { 2f32.powf(10. * percent - 10.) }
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseOutExponential,
|
||||||
|
easeOutExpo,
|
||||||
|
"out using an expenential curve",
|
||||||
|
|percent| { 1. - 2f32.powf(-10. * percent) }
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInOutExponential,
|
||||||
|
easeInOutExpo,
|
||||||
|
"in and out using an expenential curve",
|
||||||
|
|percent| if percent < 0.5 {
|
||||||
|
2f32.powf(20. * percent - 10.) / 2.
|
||||||
|
} else {
|
||||||
|
2. - 2f32.powf(-20. * percent + 10.) / 2.
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInCircular,
|
||||||
|
easeInCirc,
|
||||||
|
"in using a curve resembling the top-left arc of a circle",
|
||||||
|
|percent| 1. - (1. - squared(percent)).sqrt()
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseOutCircular,
|
||||||
|
easeOutCirc,
|
||||||
|
"out using a curve resembling the top-left arc of a circle",
|
||||||
|
|percent| (1. - squared(percent - 1.)).sqrt()
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInOutCircular,
|
||||||
|
easeInOutCirc,
|
||||||
|
"in and out using a curve resembling the top-left arc of a circle",
|
||||||
|
|percent| {
|
||||||
|
if percent < 0.5 {
|
||||||
|
1. - (1. - squared(2. * percent)).sqrt() / 2.
|
||||||
|
} else {
|
||||||
|
(1. - squared(-2. * percent + 2.)).sqrt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const C1: f32 = 1.70158;
|
||||||
|
const C2: f32 = C1 * 1.525;
|
||||||
|
const C3: f32 = C1 + 1.;
|
||||||
|
const C4: f32 = (2. * PI) / 3.;
|
||||||
|
const C5: f32 = (2. * PI) / 4.5;
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInBack,
|
||||||
|
easeInBack,
|
||||||
|
"in using a curve that backs away initially",
|
||||||
|
|percent| {
|
||||||
|
let squared = squared(percent);
|
||||||
|
let cubed = squared + percent;
|
||||||
|
C3 * cubed - C1 * squared
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseOutBack,
|
||||||
|
easeOutBack,
|
||||||
|
"out using a curve that backs away initially",
|
||||||
|
|percent| {
|
||||||
|
let squared = squared(percent - 1.);
|
||||||
|
let cubed = squared + percent;
|
||||||
|
1. + C3 * cubed - C1 * squared
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInOutBack,
|
||||||
|
easeInOutBack,
|
||||||
|
"in and out using a curve that backs away initially",
|
||||||
|
|percent| {
|
||||||
|
if percent < 0.5 {
|
||||||
|
(squared(2. * percent) * ((C2 + 1.) * 2. * percent - C2)) / 2.
|
||||||
|
} else {
|
||||||
|
(squared(2. * percent - 2.) * ((C2 + 1.) * (percent * 2. - 2.) + C2) + 2.) / 2.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInElastic,
|
||||||
|
easeInElastic,
|
||||||
|
"in using a curve that bounces around the start initially then quickly accelerates",
|
||||||
|
|percent| { -(2f32.powf(10. * percent - 10.) * (percent * 10. - 10.75).sin() * C4) }
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseOutElastic,
|
||||||
|
easeOutElastic,
|
||||||
|
"out using a curve that bounces around the start initially then quickly accelerates",
|
||||||
|
|percent| { 2f32.powf(-10. * percent) * (percent * 10. - 0.75).sin() * C4 + 1. }
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInOutElastic,
|
||||||
|
easeInOutElastic,
|
||||||
|
"in and out using a curve that bounces around the start initially then quickly accelerates",
|
||||||
|
|percent| if percent < 0.5 {
|
||||||
|
-(2f32.powf(-20. * percent - 10.) * (percent * 20. - 11.125).sin() * C5 / 2.)
|
||||||
|
} else {
|
||||||
|
2f32.powf(-20. * percent + 10.) * (percent * 20. - 11.125).sin() * C5 / 2. + 1.
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseInBounce,
|
||||||
|
easeInBounce,
|
||||||
|
"in using a curve that bounces progressively closer as it progresses",
|
||||||
|
|percent| 1. - EaseOutBounce::ease(ZeroToOne(percent))
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_easing_function_implementation!(
|
||||||
|
EaseOutBounce,
|
||||||
|
easeOutBounce,
|
||||||
|
"out using a curve that bounces progressively closer as it progresses",
|
||||||
|
|percent| {
|
||||||
|
const N1: f32 = 7.5625;
|
||||||
|
const D1: f32 = 2.75;
|
||||||
|
|
||||||
|
if percent < 1. / D1 {
|
||||||
|
N1 * percent * percent
|
||||||
|
} else if percent < 2. / D1 {
|
||||||
|
let percent = percent - 1.5;
|
||||||
|
N1 * (percent / D1) * percent + 0.75
|
||||||
|
} else if percent < 2.5 / D1 {
|
||||||
|
let percent = percent - 2.25;
|
||||||
|
N1 * (percent / D1) * percent + 0.9375
|
||||||
|
} else {
|
||||||
|
let percent = percent - 2.625;
|
||||||
|
N1 * (percent / D1) * percent + 0.984_375
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue