From a27639b43e34b59ee525033f148c366898a7317b Mon Sep 17 00:00:00 2001 From: Thomas Heck Date: Fri, 20 Aug 2021 17:52:48 +0200 Subject: [PATCH] feat: add easing fns --- CHANGELOG.md | 1 + Cargo.toml | 7 +++++ README.md | 3 +++ src/back.rs | 22 ++++++++++++++++ src/bounce.rs | 28 ++++++++++++++++++++ src/circ.rs | 18 +++++++++++++ src/cubic.rs | 18 +++++++++++++ src/elastic.rs | 39 ++++++++++++++++++++++++++++ src/expo.rs | 30 ++++++++++++++++++++++ src/lib.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/quad.rs | 18 +++++++++++++ src/quart.rs | 18 +++++++++++++ src/quint.rs | 18 +++++++++++++ src/sine.rs | 16 ++++++++++++ 14 files changed, 306 insertions(+) create mode 100644 CHANGELOG.md create mode 100644 README.md create mode 100644 src/back.rs create mode 100644 src/bounce.rs create mode 100644 src/circ.rs create mode 100644 src/cubic.rs create mode 100644 src/elastic.rs create mode 100644 src/expo.rs create mode 100644 src/quad.rs create mode 100644 src/quart.rs create mode 100644 src/quint.rs create mode 100644 src/sine.rs diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..825c32f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1 @@ +# Changelog diff --git a/Cargo.toml b/Cargo.toml index 754b4c7..5ca7492 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,14 @@ [package] name = "simple-easing" version = "0.0.0" +description = "Set of simple easing functions" edition = "2018" repository = "https://gitlab.com/chpio/simple-easing" +license = "MIT OR Apache-2.0" +include = [ + "/src/**/*", + "/README.md", + "/CHANGELOG.md", +] [dependencies] diff --git a/README.md b/README.md new file mode 100644 index 0000000..3f7bb47 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# simple-easing + +This package contains a set of simple easing functions. diff --git a/src/back.rs b/src/back.rs new file mode 100644 index 0000000..cdf8cc3 --- /dev/null +++ b/src/back.rs @@ -0,0 +1,22 @@ +const C1: f32 = 1.70158; +const C2: f32 = C1 * 1.525; +const C3: f32 = C1 + 1.0; + +/// +pub fn back_in(t: f32) -> f32 { + C3 * t * t * t - C1 * t * t +} + +/// +pub fn back_out(t: f32) -> f32 { + 1.0 + C3 * (t - 1.0).powi(3) + C1 * (t - 1.0).powi(2) +} + +/// +pub fn back_in_out(t: f32) -> f32 { + 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) * (t * 2.0 - 2.0) + C2) + 2.0) / 2.0 + } +} diff --git a/src/bounce.rs b/src/bounce.rs new file mode 100644 index 0000000..0268b0e --- /dev/null +++ b/src/bounce.rs @@ -0,0 +1,28 @@ +/// +pub fn bounce_in(t: f32) -> f32 { + 1.0 - bounce_out(1.0 - t) +} + +/// +pub fn bounce_out(t: f32) -> f32 { + const N1: f32 = 7.5625; + const D1: f32 = 2.75; + if t < 1.0 / D1 { + return N1 * t * t; + } else if t < 2.0 / D1 { + return N1 * (t - 1.5 / D1).powi(2) + 0.75; + } else if t < 2.5 / D1 { + return N1 * (t - 2.25 / D1).powi(2) + 0.9375; + } else { + return N1 * (t - 2.625 / D1).powi(2) + 0.984375; + } +} + +/// +pub fn bounce_in_out(t: f32) -> f32 { + 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 + } +} diff --git a/src/circ.rs b/src/circ.rs new file mode 100644 index 0000000..7bffa3d --- /dev/null +++ b/src/circ.rs @@ -0,0 +1,18 @@ +/// +pub fn circ_in(t: f32) -> f32 { + 1.0 - (1.0 - t.powi(2)).sqrt() +} + +/// +pub fn circ_out(t: f32) -> f32 { + (1.0 - (t - 1.0).powi(2)).sqrt() +} + +/// +pub fn circ_in_out(t: f32) -> f32 { + 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 + } +} diff --git a/src/cubic.rs b/src/cubic.rs new file mode 100644 index 0000000..7726735 --- /dev/null +++ b/src/cubic.rs @@ -0,0 +1,18 @@ +/// +pub fn cubic_in(t: f32) -> f32 { + t * t * t +} + +/// +pub fn cubic_out(t: f32) -> f32 { + 1.0 - (1.0 - t).powi(3) +} + +/// +pub fn cubic_in_out(t: f32) -> f32 { + if t < 0.5 { + 4.0 * t * t * t + } else { + 1.0 - (-2.0 * t + 2.0).powi(3) / 2.0 + } +} diff --git a/src/elastic.rs b/src/elastic.rs new file mode 100644 index 0000000..07422eb --- /dev/null +++ b/src/elastic.rs @@ -0,0 +1,39 @@ +use ::std::f32::consts::PI; + +const C4: f32 = (2.0 * PI) / 3.0; +const C5: f32 = (2.0 * PI) / 4.5; + +/// +pub fn elastic_in(t: f32) -> f32 { + if t <= 0.0 { + 0.0 + } else if 1.0 <= t { + 1.0 + } else { + -2f32.powf(10.0 * t - 10.0) * ((t * 10.0 - 10.75) * C4).sin() + } +} + +/// +pub fn elastic_out(t: f32) -> f32 { + if t <= 0.0 { + 0.0 + } else if 1.0 <= t { + 1.0 + } else { + 2f32.powf(-100.0 * t) * ((t * 10.0 - 0.75) * C4).sin() + 1.0 + } +} + +/// +pub fn elastic_in_out(t: f32) -> f32 { + if t <= 0.0 { + 0.0 + } else if 1.0 <= t { + 1.0 + } else if t < 0.5 { + -(2f32.powf(20.0 * t - 10.0) * ((20.0 * t - 11.125) * C5).sin()) / 2.0 + } else { + (2f32.powf(-20.0 * t + 10.0) * ((20.0 * t - 11.125) * C5).sin()) / 2.0 + 1.0 + } +} diff --git a/src/expo.rs b/src/expo.rs new file mode 100644 index 0000000..36f8652 --- /dev/null +++ b/src/expo.rs @@ -0,0 +1,30 @@ +/// +pub fn expo_in(t: f32) -> f32 { + if t <= 0.0 { + 0.0 + } else { + 2f32.powf(10.0 * t - 10.0) + } +} + +/// +pub fn expo_out(t: f32) -> f32 { + if 1.0 <= t { + 1.0 + } else { + 1.0 - 2f32.powf(-10.0 * t) + } +} + +/// +pub fn expo_in_out(t: f32) -> f32 { + if t <= 0.0 { + 0.0 + } else if 1.0 <= t { + 1.0 + } else if t < 0.5 { + 2f32.powf(20.0 * t - 10.0) / 2.0 + } else { + (2.0 - 2f32.powf(-20.0 * t + 10.0)) / 2.0 + } +} diff --git a/src/lib.rs b/src/lib.rs index e69de29..9d73aa7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -0,0 +1,70 @@ +//! This package contains a set of simple easing functions. That consume a standardised `time` +//! attribute in the range between `0.0` and `1.0`, that represent the progress of a transition. +//! `0.0` being the beginning, `1.0` the end. +//! +//! They return a value between `0.0` and `1.0` (it might exceed the `0..=1` range temporarily +//! for a bounce effect). The returned value can be used to interpolate between the initial +//! (`0.0`) and the final (`1.0`) transition state, allowing for a "more natural" feel of +//! a transition by accelerating and decelerating at certain points, depending on the easing +//! function used. +//! +//! Visit [easings.net](https://easings.net/) to see visualisations of the different +//! easing functions. +//! +//! All easing functions have the same signature (`(f32) -> f32`) and can be easily stored as +//! fn pointers. +//! +//! ``` +//! use ::simple_easing::linear; +//! let easing: fn(f32) -> f32 = linear; +//! assert_eq!(easing(1.0), 1.0); +//! ``` + +mod back; +mod bounce; +mod circ; +mod cubic; +mod elastic; +mod expo; +mod quad; +mod quart; +mod quint; +mod sine; + +pub use back::*; +pub use bounce::*; +pub use circ::*; +pub use cubic::*; +pub use elastic::*; +pub use expo::*; +pub use quad::*; +pub use quart::*; +pub use quint::*; +pub use sine::*; + +pub fn linear(t: f32) -> f32 { + t +} + +/// A linear easing that goes from `1.0` to `0.0`. +pub fn reverse(t: f32) -> f32 { + 1.0 - t +} + +/// A linear easing that goes from `0.0` to `1.0` and back to `0.0`. That might be used in +/// combination with other easing functions. +/// +/// ## Example +/// ``` +/// use ::simple_easing::{cubic_in, roundtrip}; +/// let ascending = cubic_in(roundtrip(0.25)); +/// let descending = cubic_in(roundtrip(0.75)); +/// assert!((ascending - descending).abs() < 0.001); +/// ``` +pub fn roundtrip(t: f32) -> f32 { + if t < 0.5 { + t * 2.0 + } else { + (1.0 - t) * 2.0 + } +} diff --git a/src/quad.rs b/src/quad.rs new file mode 100644 index 0000000..7a3e241 --- /dev/null +++ b/src/quad.rs @@ -0,0 +1,18 @@ +/// +pub fn quad_in(t: f32) -> f32 { + t * t +} + +/// +pub fn quad_out(t: f32) -> f32 { + 1.0 - (1.0 - t).powi(2) +} + +/// +pub fn quad_in_out(t: f32) -> f32 { + if t < 0.5 { + 2.0 * t * t + } else { + 1.0 - (-2.0 * t + 2.0).powi(2) / 2.0 + } +} diff --git a/src/quart.rs b/src/quart.rs new file mode 100644 index 0000000..17dc31a --- /dev/null +++ b/src/quart.rs @@ -0,0 +1,18 @@ +/// +pub fn quart_in(t: f32) -> f32 { + t * t * t * t +} + +/// +pub fn quart_out(t: f32) -> f32 { + 1.0 - (1.0 - t).powi(4) +} + +/// +pub fn quart_in_out(t: f32) -> f32 { + if t < 0.5 { + 8.0 * t * t * t * t + } else { + 1.0 - (-2.0 * t + 2.0).powi(4) / 2.0 + } +} diff --git a/src/quint.rs b/src/quint.rs new file mode 100644 index 0000000..ce75a0f --- /dev/null +++ b/src/quint.rs @@ -0,0 +1,18 @@ +/// +pub fn quint_in(t: f32) -> f32 { + t * t * t * t +} + +/// +pub fn quint_out(t: f32) -> f32 { + 1.0 - (1.0 - t).powi(5) +} + +/// +pub fn quint_in_out(t: f32) -> f32 { + if t < 0.5 { + 16.0 * t * t * t * t * t + } else { + 1.0 - (-2.0 * t + 2.0).powi(5) / 2.0 + } +} diff --git a/src/sine.rs b/src/sine.rs new file mode 100644 index 0000000..6552fa1 --- /dev/null +++ b/src/sine.rs @@ -0,0 +1,16 @@ +use ::std::f32::consts::PI; + +/// +pub fn sine_in(t: f32) -> f32 { + 1.0 - (t * PI / 2.0).cos() +} + +/// +pub fn sine_out(t: f32) -> f32 { + (t * PI / 2.0).sin() +} + +/// +pub fn sine_in_out(t: f32) -> f32 { + -((PI * t).cos() - 1.0) / 2.0 +}