diff options
| author | Horu <73709188+HigherOrderLogic@users.noreply.github.com> | 2025-08-29 15:31:50 +1000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-29 05:31:50 +0000 |
| commit | 1ffda91e0cc3938af1a9d4f1f1b6a87afa3c210f (patch) | |
| tree | 60aa82866d4f3fa0105447419d154c69fba521f1 /src | |
| parent | d9833fc1c3de306f500662471ae001094813dbd5 (diff) | |
| download | niri-1ffda91e0cc3938af1a9d4f1f1b6a87afa3c210f.tar.gz niri-1ffda91e0cc3938af1a9d4f1f1b6a87afa3c210f.tar.bz2 niri-1ffda91e0cc3938af1a9d4f1f1b6a87afa3c210f.zip | |
feat: cubic-bezier curve for animation (#2059)
* feat: bezier curve for animation
* fixes
---------
Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/animation/bezier.rs | 60 | ||||
| -rw-r--r-- | src/animation/mod.rs | 8 |
2 files changed, 68 insertions, 0 deletions
diff --git a/src/animation/bezier.rs b/src/animation/bezier.rs new file mode 100644 index 00000000..17facfda --- /dev/null +++ b/src/animation/bezier.rs @@ -0,0 +1,60 @@ +use keyframe::EasingFunction; + +#[derive(Debug, Clone, Copy)] +pub struct CubicBezier { + x1: f64, + y1: f64, + x2: f64, + y2: f64, +} + +impl CubicBezier { + pub fn new(x1: f64, y1: f64, x2: f64, y2: f64) -> Self { + Self { x1, y1, x2, y2 } + } + + // Based on libadwaita (LGPL-2.1-or-later): + // https://gitlab.gnome.org/GNOME/libadwaita/-/blob/1.7.6/src/adw-easing.c?ref_type=tags#L469-531 + + fn x_for_t(&self, t: f64) -> f64 { + let omt = 1. - t; + 3. * omt * omt * t * self.x1 + 3. * omt * t * t * self.x2 + t * t * t + } + + fn y_for_t(&self, t: f64) -> f64 { + let omt = 1. - t; + 3. * omt * omt * t * self.y1 + 3. * omt * t * t * self.y2 + t * t * t + } + + fn t_for_x(&self, x: f64) -> f64 { + let mut min_t = 0.; + let mut max_t = 1.; + + for _ in 0..=30 { + let guess_t = (min_t + max_t) / 2.; + let guess_x = self.x_for_t(guess_t); + + if x < guess_x { + max_t = guess_t; + } else { + min_t = guess_t; + } + } + + (min_t + max_t) / 2. + } +} + +impl EasingFunction for CubicBezier { + fn y(&self, x: f64) -> f64 { + if x <= f64::EPSILON { + return 0.; + } + + if 1. - f64::EPSILON <= x { + return 1.; + } + + self.y_for_t(self.t_for_x(x)) + } +} diff --git a/src/animation/mod.rs b/src/animation/mod.rs index a8de3275..73a79c5e 100644 --- a/src/animation/mod.rs +++ b/src/animation/mod.rs @@ -3,6 +3,9 @@ use std::time::Duration; use keyframe::functions::{EaseOutCubic, EaseOutQuad}; use keyframe::EasingFunction; +mod bezier; +use bezier::CubicBezier; + mod spring; pub use spring::{Spring, SpringParams}; @@ -43,6 +46,7 @@ pub enum Curve { EaseOutQuad, EaseOutCubic, EaseOutExpo, + CubicBezier(CubicBezier), } impl Animation { @@ -342,6 +346,7 @@ impl Curve { Curve::EaseOutQuad => EaseOutQuad.y(x), Curve::EaseOutCubic => EaseOutCubic.y(x), Curve::EaseOutExpo => 1. - 2f64.powf(-10. * x), + Curve::CubicBezier(b) => b.y(x), } } } @@ -353,6 +358,9 @@ impl From<niri_config::animations::Curve> for Curve { niri_config::animations::Curve::EaseOutQuad => Curve::EaseOutQuad, niri_config::animations::Curve::EaseOutCubic => Curve::EaseOutCubic, niri_config::animations::Curve::EaseOutExpo => Curve::EaseOutExpo, + niri_config::animations::Curve::CubicBezier(x1, y1, x2, y2) => { + Curve::CubicBezier(CubicBezier::new(x1, y1, x2, y2)) + } } } } |
