Skip to content

Commit

Permalink
transition: interpolate with time instead of steps
Browse files Browse the repository at this point in the history
It's much more flexible this way.

Signed-off-by: Yuxuan Shui <[email protected]>
  • Loading branch information
yshui committed Apr 18, 2024
1 parent f54e89b commit 6e77ea0
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 47 deletions.
26 changes: 10 additions & 16 deletions src/picom.c
Original file line number Diff line number Diff line change
Expand Up @@ -478,10 +478,10 @@ static double fade_timeout(session_t *ps) {
* @param steps steps of fading
* @return whether we are still in fading mode
*/
static bool run_fade(struct managed_win **_w, unsigned int steps) {
static bool run_fade(struct managed_win **_w, double delta_sec) {
auto w = *_w;
log_trace("Process fading for window %s (%#010x), steps: %u", w->name, w->base.id,
steps);
log_trace("Process fading for window %s (%#010x), ΔT: %fs", w->name, w->base.id,
delta_sec);
if (w->number_of_animations == 0) {
// We have reached target opacity.
// We don't call win_check_fade_finished here because that could destroy
Expand All @@ -491,9 +491,9 @@ static bool run_fade(struct managed_win **_w, unsigned int steps) {
}

log_trace("|- fading, opacity: %lf", animatable_get(&w->opacity));
animatable_step(&w->opacity, steps);
animatable_step(&w->blur_opacity, steps);
log_trace("|- opacity updated: %lf (%u steps)", animatable_get(&w->opacity), steps);
animatable_advance(&w->opacity, delta_sec);
animatable_advance(&w->blur_opacity, delta_sec);
log_trace("|- opacity updated: %lf", animatable_get(&w->opacity));

// Note even if the animatable is not animating anymore at this point, we still
// want to run preprocess one last time to finish state transition. So return true
Expand Down Expand Up @@ -888,19 +888,13 @@ static bool paint_preprocess(session_t *ps, bool *fade_running, bool *animation,
*out_bottom = NULL;

// Fading step calculation
unsigned int steps = 0L;
int64_t delta_ms = 0L;
auto now = get_time_ms();
if (ps->fade_time) {
assert(now >= ps->fade_time);
auto raw_steps = (now - ps->fade_time) / ps->o.fade_delta;
assert(raw_steps <= UINT_MAX);
steps = (unsigned int)raw_steps;
ps->fade_time += raw_steps * ps->o.fade_delta;
} else {
// Reset fade_time if unset
ps->fade_time = get_time_ms();
steps = 0L;
delta_ms = now - ps->fade_time;
}
ps->fade_time = now;

// First, let's process fading, and animated shaders
// TODO(yshui) check if a window is fully obscured, and if we don't need to
Expand Down Expand Up @@ -928,7 +922,7 @@ static bool paint_preprocess(session_t *ps, bool *fade_running, bool *animation,
}

// Run fading
if (run_fade(&w, steps)) {
if (run_fade(&w, (double)delta_ms / 1000.0)) {
*fade_running = true;
}

Expand Down
45 changes: 23 additions & 22 deletions src/transition.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,39 @@
#include "utils.h"

double animatable_get_progress(const struct animatable *a) {
if (a->duration) {
return (double)a->progress / a->duration;
if (a->duration > 0) {
return a->elapsed / a->duration;
}
return 1;
}

/// Get the current value of an `animatable`.
double animatable_get(const struct animatable *a) {
if (a->duration) {
assert(a->progress < a->duration);
if (a->duration > 0) {
assert(a->elapsed < a->duration);
double t = a->curve->sample(a->curve, animatable_get_progress(a));
return (1 - t) * a->start + t * a->target;
}
return a->target;
}

/// Advance the animation by a given number of steps.
void animatable_step(struct animatable *a, unsigned int steps) {
if (!a->duration || !steps) {
void animatable_advance(struct animatable *a, double elapsed) {
if (a->duration == 0 || elapsed <= 0) {
return;
}

assert(a->progress < a->duration);
if (steps > a->duration - a->progress) {
steps = a->duration - a->progress;
assert(a->elapsed < a->duration);
if (elapsed >= a->duration - a->elapsed) {
a->elapsed = a->duration;
} else {
a->elapsed += elapsed;
}
a->progress += steps;

if (a->progress == a->duration) {
if (a->elapsed == a->duration) {
a->start = a->target;
a->duration = 0;
a->progress = 0;
a->elapsed = 0;
a->curve->free(a->curve);
a->curve = NULL;
if (a->callback) {
Expand All @@ -54,23 +55,23 @@ void animatable_step(struct animatable *a, unsigned int steps) {

/// Returns whether an `animatable` is currently animating.
bool animatable_is_animating(const struct animatable *a) {
assert(!a->duration || a->progress < a->duration);
return a->duration;
assert(a->duration == 0 || a->elapsed < a->duration);
return a->duration != 0;
}

/// Cancel the current animation of an `animatable`. This stops the animation and
/// the `animatable` will retain its current value.
///
/// Returns true if the `animatable` was animated before this function is called.
bool animatable_interrupt(struct animatable *a) {
if (!a->duration) {
if (a->duration == 0) {
return false;
}

a->start = animatable_get(a);
a->target = a->start;
a->duration = 0;
a->progress = 0;
a->elapsed = 0;
a->curve->free(a->curve);
a->curve = NULL;
if (a->callback) {
Expand All @@ -85,13 +86,13 @@ bool animatable_interrupt(struct animatable *a) {
///
/// Returns true if the `animatable` was animated before this function is called.
bool animatable_skip(struct animatable *a) {
if (!a->duration) {
if (a->duration == 0) {
return false;
}

a->start = a->target;
a->duration = 0;
a->progress = 0;
a->elapsed = 0;
a->curve->free(a->curve);
a->curve = NULL;
if (a->callback) {
Expand All @@ -104,10 +105,10 @@ bool animatable_skip(struct animatable *a) {

/// Change the target value of an `animatable`.
/// If the `animatable` is already animating, the animation will be canceled first.
bool animatable_set_target(struct animatable *a, double target, unsigned int duration,
bool animatable_set_target(struct animatable *a, double target, double duration,
const struct curve *curve, transition_callback_fn cb, void *data) {
animatable_interrupt(a);
if (!duration || a->start == target) {
if (duration == 0 || a->start == target) {
a->start = target;
a->target = target;
curve->free(curve);
Expand All @@ -116,7 +117,7 @@ bool animatable_set_target(struct animatable *a, double target, unsigned int dur

a->target = target;
a->duration = duration;
a->progress = 0;
a->elapsed = 0;
a->callback = cb;
a->callback_data = data;
a->curve = curve;
Expand All @@ -129,7 +130,7 @@ struct animatable animatable_new(double value) {
.start = value,
.target = value,
.duration = 0,
.progress = 0,
.elapsed = 0,
};
return ret;
}
Expand Down
14 changes: 7 additions & 7 deletions src/transition.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ struct animatable {
/// The target value.
/// If the `animatable` is not animated, this equals to `start`.
double target;
/// The animation duration in number of steps.
/// The animation duration in unspecified units.
/// If the `animatable` is not animated, this is 0.
unsigned int duration;
/// The current progress of the animation. From 0 to `duration - 1`.
double duration;
/// The current progress of the animation in the same units as `duration`.
/// If the `animatable` is not animated, this is 0.
unsigned int progress;
double elapsed;

transition_callback_fn callback;
void *callback_data;
Expand All @@ -71,8 +71,8 @@ struct animatable {
double animatable_get(const struct animatable *a);
/// Get the animation progress as a percentage of the total duration.
double animatable_get_progress(const struct animatable *a);
/// Advance the animation by a given number of steps.
void animatable_step(struct animatable *a, unsigned int steps);
/// Advance the animation by a given amount. `elapsed` cannot be negative.
void animatable_advance(struct animatable *a, double elapsed);
/// Returns whether an `animatable` is currently animating.
bool animatable_is_animating(const struct animatable *a);
/// Interrupt the current animation of an `animatable`. This stops the animation and
Expand All @@ -95,7 +95,7 @@ bool animatable_skip(struct animatable *a);
/// animatable's current animation, if it has one, will be canceled regardless.
///
/// Returns if the animatable is now animated.
bool animatable_set_target(struct animatable *a, double target, unsigned int duration,
bool animatable_set_target(struct animatable *a, double target, double duration,
const struct curve *curve,
transition_callback_fn cb, void *data);
/// Create a new animatable.
Expand Down
4 changes: 2 additions & 2 deletions src/win.c
Original file line number Diff line number Diff line change
Expand Up @@ -939,8 +939,8 @@ win_start_fade(session_t *ps, struct managed_win *w, double target_blur_opacity)
target_opacity = win_calc_opacity_target(ps, w);
double step_size =
target_opacity > current_opacity ? ps->o.fade_in_step : ps->o.fade_out_step;
unsigned int duration =
(unsigned int)(fabs(target_opacity - current_opacity) / step_size);
double duration = (fabs(target_opacity - current_opacity) / step_size) *
(double)ps->o.fade_delta / 1000.0;
if (!win_should_fade(ps, w)) {
duration = 0;
}
Expand Down

0 comments on commit 6e77ea0

Please sign in to comment.