mirror of https://github.com/yshui/picom.git
transition: add a generic animated transition mechanism
This should replace the current fading animation implementation. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
5df19aed20
commit
dcab6fc868
|
@ -10,7 +10,7 @@ base_deps = [
|
||||||
srcs = [ files('picom.c', 'win.c', 'c2.c', 'x.c', 'config.c', 'vsync.c', 'utils.c',
|
srcs = [ files('picom.c', 'win.c', 'c2.c', 'x.c', 'config.c', 'vsync.c', 'utils.c',
|
||||||
'diagnostic.c', 'string_utils.c', 'render.c', 'kernel.c', 'log.c',
|
'diagnostic.c', 'string_utils.c', 'render.c', 'kernel.c', 'log.c',
|
||||||
'options.c', 'event.c', 'cache.c', 'atom.c', 'file_watch.c', 'statistics.c',
|
'options.c', 'event.c', 'cache.c', 'atom.c', 'file_watch.c', 'statistics.c',
|
||||||
'vblank.c') ]
|
'vblank.c', 'transition.c') ]
|
||||||
picom_inc = include_directories('.')
|
picom_inc = include_directories('.')
|
||||||
|
|
||||||
cflags = []
|
cflags = []
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "compiler.h"
|
||||||
|
#include "transition.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
/// Get the current value of an `animatable`.
|
||||||
|
double animatable_get(const struct animatable *a) {
|
||||||
|
if (a->step_state) {
|
||||||
|
return a->step_state->current;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a->duration) {
|
||||||
|
assert(a->progress < a->duration);
|
||||||
|
return a->interpolator(a);
|
||||||
|
}
|
||||||
|
return a->target;
|
||||||
|
}
|
||||||
|
|
||||||
|
double animatable_get_progress(const struct animatable *a) {
|
||||||
|
if (a->duration) {
|
||||||
|
return (double)a->progress / a->duration;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Advance the animation by a given number of steps.
|
||||||
|
void animatable_step(struct animatable *a, unsigned int steps) {
|
||||||
|
if (!a->duration || !steps) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(a->progress < a->duration);
|
||||||
|
if (steps > a->duration - a->progress) {
|
||||||
|
steps = a->duration - a->progress;
|
||||||
|
}
|
||||||
|
a->progress += steps;
|
||||||
|
if (a->step_state) {
|
||||||
|
a->step(a, steps);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a->progress == a->duration) {
|
||||||
|
a->start = a->target;
|
||||||
|
a->duration = 0;
|
||||||
|
a->progress = 0;
|
||||||
|
if (a->step_state) {
|
||||||
|
a->step_state->current = a->target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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_cancel(struct animatable *a) {
|
||||||
|
if (!a->duration) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
a->start = animatable_get(a);
|
||||||
|
a->target = a->start;
|
||||||
|
a->duration = 0;
|
||||||
|
a->progress = 0;
|
||||||
|
if (a->step_state) {
|
||||||
|
a->step_state->current = a->start;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancel the current animation of an `animatable` and set its value to its target.
|
||||||
|
///
|
||||||
|
/// Returns true if the `animatable` was animated before this function is called.
|
||||||
|
bool animatable_early_stop(struct animatable *a) {
|
||||||
|
if (!a->duration) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
a->start = a->target;
|
||||||
|
a->duration = 0;
|
||||||
|
a->progress = 0;
|
||||||
|
if (a->step_state) {
|
||||||
|
a->step_state->current = a->target;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Change the target value of an `animatable`.
|
||||||
|
/// If the `animatable` is already animating, the animation will be canceled first.
|
||||||
|
void animatable_set_target(struct animatable *a, double target, unsigned int duration) {
|
||||||
|
animatable_cancel(a);
|
||||||
|
if (!duration) {
|
||||||
|
a->start = target;
|
||||||
|
a->target = target;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a->target = target;
|
||||||
|
a->duration = duration;
|
||||||
|
a->progress = 0;
|
||||||
|
if (a->step_state) {
|
||||||
|
a->step(a, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new animatable.
|
||||||
|
struct animatable animatable_new(double value, interpolator_fn interpolator, step_fn step) {
|
||||||
|
assert(!interpolator || !step);
|
||||||
|
struct animatable ret = {
|
||||||
|
.start = value,
|
||||||
|
.target = value,
|
||||||
|
.duration = 0,
|
||||||
|
.progress = 0,
|
||||||
|
.step_state = NULL,
|
||||||
|
};
|
||||||
|
if (interpolator) {
|
||||||
|
ret.interpolator = interpolator;
|
||||||
|
} else if (step) {
|
||||||
|
ret.step = step;
|
||||||
|
step(&ret, 0);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
double linear_interpolator(const struct animatable *a) {
|
||||||
|
double t = (double)a->progress / a->duration;
|
||||||
|
return (1 - t) * a->start + t * a->target;
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
struct animatable;
|
||||||
|
/// The interpolator function for an animatable. This function should calculate the
|
||||||
|
/// current value of the `animatable` based on its `start`, `target`, `duration` and
|
||||||
|
/// `progress`.
|
||||||
|
typedef double (*interpolator_fn)(const struct animatable *);
|
||||||
|
/// The step function for an animatable. This function should advance the animation state
|
||||||
|
/// by one step. This function is called _after_ `progress` is incremented. If `progress`
|
||||||
|
/// is 0 when the function is called, it means an animation has just started, and this
|
||||||
|
/// function should initialize the state. If `step_state` is NULL when this function is
|
||||||
|
/// called, this function should allocate and initialize `step_state`.
|
||||||
|
/// `steps` is the number of steps to advance. This is always 1 or more, unless `progress`
|
||||||
|
/// is 0 or `step_state` is NULL, in which case `steps` is 0.
|
||||||
|
typedef void (*step_fn)(struct animatable *, unsigned int steps);
|
||||||
|
|
||||||
|
/// The base type for step_state.
|
||||||
|
struct step_state_base {
|
||||||
|
/// The current value of the `animatable`.
|
||||||
|
/// If the `animatable` is not animated, this equals to `animatable->target`.
|
||||||
|
double current;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// An animatable value
|
||||||
|
struct animatable {
|
||||||
|
/// The starting value.
|
||||||
|
/// When this `animatable` is not animated, this is the current value.
|
||||||
|
double start;
|
||||||
|
/// The target value.
|
||||||
|
/// If the `animatable` is not animated, this equals to `start`.
|
||||||
|
double target;
|
||||||
|
/// The animation duration in number of steps.
|
||||||
|
/// If the `animatable` is not animated, this is 0.
|
||||||
|
unsigned int duration;
|
||||||
|
/// The current progress of the animation. From 0 to `duration - 1`.
|
||||||
|
/// If the `animatable` is not animated, this is 0.
|
||||||
|
unsigned int progress;
|
||||||
|
|
||||||
|
/// Step function state.
|
||||||
|
struct step_state_base *step_state;
|
||||||
|
/// The function for calculating the current value. If
|
||||||
|
/// `step_state` is not NULL, the `step` function is used;
|
||||||
|
/// otherwise, the `interpolator` function is used.
|
||||||
|
union {
|
||||||
|
/// The interpolator function.
|
||||||
|
interpolator_fn interpolator;
|
||||||
|
/// The step function.
|
||||||
|
step_fn step;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================== API ===============================
|
||||||
|
|
||||||
|
/// Get the current value of an `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);
|
||||||
|
/// Returns whether an `animatable` is currently animating.
|
||||||
|
bool animatable_is_animating(const struct animatable *a);
|
||||||
|
/// 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_cancel(struct animatable *a);
|
||||||
|
/// Cancel the current animation of an `animatable` and set its value to its target.
|
||||||
|
///
|
||||||
|
/// Returns true if the `animatable` was animated before this function is called.
|
||||||
|
bool animatable_early_stop(struct animatable *a);
|
||||||
|
/// Change the target value of an `animatable`.
|
||||||
|
/// If the `animatable` is already animating, the animation will be canceled first.
|
||||||
|
void animatable_set_target(struct animatable *a, double target, unsigned int duration);
|
||||||
|
/// Create a new animatable.
|
||||||
|
struct animatable animatable_new(double value, interpolator_fn interpolator, step_fn step);
|
||||||
|
|
||||||
|
// ========================== Interpolators ==========================
|
||||||
|
|
||||||
|
double linear_interpolator(const struct animatable *a);
|
Loading…
Reference in New Issue