aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/animation/bezier.rs60
-rw-r--r--src/animation/mod.rs8
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))
+ }
}
}
}