1
0
Fork 0
mirror of https://github.com/yshui/picom.git synced 2024-11-25 14:06:08 -05:00

transition: add support for animation presets

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2024-08-05 17:39:11 +01:00
parent 23f44d7295
commit 5a69a26602
No known key found for this signature in database
GPG key ID: D3A4405BE6CC17F4
9 changed files with 645 additions and 66 deletions

1
.gitignore vendored
View file

@ -54,6 +54,7 @@ target
.vscode
*.conf
!/tests/configs/*.conf
!/data/*.conf
perf.data
perf.data.old
core.*

View file

@ -0,0 +1,61 @@
disappear = {
opacity = {
duration = "placeholder0";
start = "window-raw-opacity-before";
end = "window-raw-opacity";
};
blur-opacity = "opacity";
shadow-opacity = "opacity";
offset-x = "(1 - scale-x) / 2 * window-width";
offset-y = "(1 - scale-y) / 2 * window-height";
scale-x = {
curve = "cubic-bezier(0.21, 0.02, 0.76, 0.36)";
duration = "placeholder0";
start = 1;
end = "placeholder1";
};
scale-y = "scale-x";
shadow-scale-x = "scale-x";
shadow-scale-y = "scale-y";
shadow-offset-x = "offset-x";
shadow-offset-y = "offset-y";
# This section defines placeholders used in this script
# Each entry is a tuple of two numbers. The first one is
# the id of the placeholder (e.g. 0 for placeholder0), the
# second number is the default value, if it is not specified
# by the user.
#
# Currently up to 10 placeholders are supported, if more is
# needed, tools/animgen.c needs to be updated to include more.
placeholders = {
scale = (1, 0.95);
duration = (0, 0.2);
};
};
appear = {
opacity = {
duration = "placeholder0";
start = "window-raw-opacity-before";
end = "window-raw-opacity";
};
blur-opacity = "opacity";
shadow-opacity = "opacity";
offset-x = "(1 - scale-x) / 2 * window-width";
offset-y = "(1 - scale-y) / 2 * window-height";
scale-x = {
curve = "cubic-bezier(0.24, 0.64, 0.79, 0.98)";
duration = "placeholder0";
start = "placeholder1";
end = 1;
};
scale-y = "scale-x";
shadow-scale-x = "scale-x";
shadow-scale-y = "scale-y";
shadow-offset-x = "offset-x";
shadow-offset-y = "offset-y";
placeholders = {
scale = (1, 0.95);
duration = (0, 0.2);
};
};

View file

@ -16,6 +16,7 @@
#include "common.h"
#include "config.h"
#include "log.h"
#include "transition/preset.h"
#include "transition/script.h"
#include "utils/dynarr.h"
#include "utils/misc.h"
@ -233,8 +234,14 @@ static enum animation_trigger parse_animation_trigger(const char *trigger) {
return ANIMATION_TRIGGER_INVALID;
}
static struct script *
compile_win_script(config_setting_t *setting, int *output_indices, char **err) {
/// Compile a script from `setting` into `result`, return false on failure.
/// Only the `script` and `output_indices` fields of `result` will be modified.
static bool
compile_win_script(struct win_script *result, config_setting_t *setting, char **err) {
if (config_setting_lookup(setting, "preset")) {
return win_script_parse_preset(result, setting);
}
struct script_output_info outputs[ARR_SIZE(win_script_outputs)];
memcpy(outputs, win_script_outputs, sizeof(win_script_outputs));
@ -242,20 +249,19 @@ compile_win_script(config_setting_t *setting, int *output_indices, char **err) {
.context_info = win_script_context_info,
.output_info = outputs,
};
auto script = script_compile(setting, parse_config, err);
if (script == NULL) {
return script;
result->script = script_compile(setting, parse_config, err);
if (result->script == NULL) {
return false;
}
for (int i = 0; i < NUM_OF_WIN_SCRIPT_OUTPUTS; i++) {
output_indices[i] = outputs[i].slot;
result->output_indices[i] = outputs[i].slot;
}
return script;
return true;
}
static bool
set_animation(struct win_script *animations, const enum animation_trigger *triggers,
int number_of_triggers, struct script *script, const int *output_indices,
uint64_t suppressions, unsigned line, bool is_generated) {
int number_of_triggers, struct win_script animation, unsigned line) {
bool needed = false;
for (int i = 0; i < number_of_triggers; i++) {
if (triggers[i] == ANIMATION_TRIGGER_INVALID) {
@ -268,42 +274,39 @@ set_animation(struct win_script *animations, const enum animation_trigger *trigg
animation_trigger_names[triggers[i]], line);
continue;
}
memcpy(animations[triggers[i]].output_indices, output_indices,
sizeof(int[NUM_OF_WIN_SCRIPT_OUTPUTS]));
animations[triggers[i]].script = script;
animations[triggers[i]].suppressions = suppressions;
animations[triggers[i]].is_generated = is_generated;
animations[triggers[i]] = animation;
needed = true;
}
return needed;
}
static struct script *
parse_animation_one(struct win_script *animations, config_setting_t *setting) {
static bool parse_animation_one(struct win_script *animations,
struct script ***all_scripts, config_setting_t *setting) {
struct win_script result = {};
auto triggers = config_setting_lookup(setting, "triggers");
if (!triggers) {
log_error("Missing triggers in animation script, at line %d",
config_setting_source_line(setting));
return NULL;
return false;
}
if (!config_setting_is_list(triggers) && !config_setting_is_array(triggers) &&
config_setting_get_string(triggers) == NULL) {
log_error("The \"triggers\" option must either be a string, a list, or "
"an array, but is none of those at line %d",
config_setting_source_line(triggers));
return NULL;
return false;
}
auto number_of_triggers =
config_setting_get_string(triggers) == NULL ? config_setting_length(triggers) : 1;
if (number_of_triggers > ANIMATION_TRIGGER_LAST) {
log_error("Too many triggers in animation defined at line %d",
config_setting_source_line(triggers));
return NULL;
return false;
}
if (number_of_triggers == 0) {
log_error("Trigger list is empty in animation defined at line %d",
config_setting_source_line(triggers));
return NULL;
return false;
}
enum animation_trigger *trigger_types =
alloca(sizeof(enum animation_trigger[number_of_triggers]));
@ -322,7 +325,6 @@ parse_animation_one(struct win_script *animations, config_setting_t *setting) {
// script parser shouldn't see this.
config_setting_remove(setting, "triggers");
uint64_t suppressions = 0;
auto suppressions_setting = config_setting_lookup(setting, "suppressions");
if (suppressions_setting != NULL) {
auto single_suppression = config_setting_get_string(suppressions_setting);
@ -332,16 +334,16 @@ parse_animation_one(struct win_script *animations, config_setting_t *setting) {
log_error("The \"suppressions\" option must either be a string, "
"a list, or an array, but is none of those at line %d",
config_setting_source_line(suppressions_setting));
return NULL;
return false;
}
if (single_suppression != NULL) {
auto suppression = parse_animation_trigger(single_suppression);
if (suppression == ANIMATION_TRIGGER_INVALID) {
log_error("Invalid suppression defined at line %d",
config_setting_source_line(suppressions_setting));
return NULL;
return false;
}
suppressions = 1 << suppression;
result.suppressions = 1 << suppression;
} else {
auto len = config_setting_length(suppressions_setting);
for (int i = 0; i < len; i++) {
@ -353,39 +355,37 @@ parse_animation_one(struct win_script *animations, config_setting_t *setting) {
"contain strings, but one of them is not at "
"line %d",
config_setting_source_line(suppressions_setting));
return NULL;
return false;
}
auto suppression = parse_animation_trigger(suppression_str);
if (suppression == ANIMATION_TRIGGER_INVALID) {
log_error(
"Invalid suppression defined at line %d",
config_setting_source_line(suppressions_setting));
return NULL;
return false;
}
suppressions |= 1U << suppression;
result.suppressions |= 1U << suppression;
}
}
config_setting_remove(setting, "suppressions");
}
int output_indices[NUM_OF_WIN_SCRIPT_OUTPUTS];
char *err;
auto script = compile_win_script(setting, output_indices, &err);
if (!script) {
if (!compile_win_script(&result, setting, &err)) {
log_error("Failed to parse animation script at line %d: %s",
config_setting_source_line(setting), err);
free(err);
return NULL;
return false;
}
bool needed = set_animation(animations, trigger_types, number_of_triggers, script,
output_indices, suppressions,
config_setting_source_line(setting), false);
bool needed = set_animation(animations, trigger_types, number_of_triggers, result,
config_setting_source_line(setting));
if (!needed) {
script_free(script);
script = NULL;
script_free(result.script);
} else {
dynarr_push(*all_scripts, result.script);
}
return script;
return true;
}
/// `out_scripts`: all the script objects created, this is a dynarr.
@ -394,10 +394,7 @@ static void parse_animations(struct win_script *animations, config_setting_t *se
auto number_of_animations = (unsigned)config_setting_length(setting);
for (unsigned i = 0; i < number_of_animations; i++) {
auto sub = config_setting_get_elem(setting, (unsigned)i);
auto script = parse_animation_one(animations, sub);
if (script != NULL) {
dynarr_push(*out_scripts, script);
}
parse_animation_one(animations, out_scripts, sub);
}
}
@ -414,7 +411,7 @@ static void parse_animations(struct win_script *animations, config_setting_t *se
" start = %d; end = %d; " \
"};"
static struct script *compile_win_script_from_string(const char *input, int *output_indices) {
static bool compile_win_script_from_string(struct win_script *result, const char *input) {
config_t tmp_config;
config_setting_t *setting;
config_init(&tmp_config);
@ -424,11 +421,11 @@ static struct script *compile_win_script_from_string(const char *input, int *out
// Since we are compiling scripts we generated, it can't fail.
char *err = NULL;
auto script = compile_win_script(setting, output_indices, &err);
bool succeeded = compile_win_script(result, setting, &err);
config_destroy(&tmp_config);
BUG_ON(err != NULL);
return script;
return succeeded;
}
void generate_fading_config(struct options *opt) {
@ -441,7 +438,6 @@ void generate_fading_config(struct options *opt) {
unsigned number_of_scripts = 0;
int number_of_triggers = 0;
int output_indices[NUM_OF_WIN_SCRIPT_OUTPUTS];
double duration = 1.0 / opt->fade_in_step * opt->fade_delta / 1000.0;
if (!safe_isinf(duration) && !safe_isnan(duration) && duration > 0) {
scoped_charp duration_str = NULL;
@ -451,7 +447,8 @@ void generate_fading_config(struct options *opt) {
asnprintf(&str, &len, FADING_TEMPLATE_1 FADING_TEMPLATE_2, duration_str,
duration_str, 0, 1);
auto fade_in1 = compile_win_script_from_string(str, output_indices);
struct win_script fade_in1 = {.is_generated = true};
BUG_ON(!compile_win_script_from_string(&fade_in1, str));
if (opt->animations[ANIMATION_TRIGGER_OPEN].script == NULL &&
!opt->no_fading_openclose) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_OPEN;
@ -459,25 +456,24 @@ void generate_fading_config(struct options *opt) {
if (opt->animations[ANIMATION_TRIGGER_SHOW].script == NULL) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_SHOW;
}
if (set_animation(opt->animations, trigger, number_of_triggers, fade_in1,
output_indices, 0, 0, true)) {
scripts[number_of_scripts++] = fade_in1;
if (set_animation(opt->animations, trigger, number_of_triggers, fade_in1, 0)) {
scripts[number_of_scripts++] = fade_in1.script;
} else {
script_free(fade_in1);
script_free(fade_in1.script);
}
// Fading for opacity change, for these, the blur opacity doesn't change.
asnprintf(&str, &len, FADING_TEMPLATE_1, duration_str);
auto fade_in2 = compile_win_script_from_string(str, output_indices);
struct win_script fade_in2 = {.is_generated = true};
BUG_ON(!compile_win_script_from_string(&fade_in2, str));
number_of_triggers = 0;
if (opt->animations[ANIMATION_TRIGGER_INCREASE_OPACITY].script == NULL) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_INCREASE_OPACITY;
}
if (set_animation(opt->animations, trigger, number_of_triggers, fade_in2,
output_indices, 0, 0, true)) {
scripts[number_of_scripts++] = fade_in2;
if (set_animation(opt->animations, trigger, number_of_triggers, fade_in2, 0)) {
scripts[number_of_scripts++] = fade_in2.script;
} else {
script_free(fade_in2);
script_free(fade_in2.script);
}
} else {
log_error("Invalid fade-in setting (step: %f, delta: %d), ignoring.",
@ -492,7 +488,8 @@ void generate_fading_config(struct options *opt) {
// Fading out to nothing, i.e. `hide` and `close`
asnprintf(&str, &len, FADING_TEMPLATE_1 FADING_TEMPLATE_2, duration_str,
duration_str, 1, 0);
auto fade_out1 = compile_win_script_from_string(str, output_indices);
struct win_script fade_out1 = {.is_generated = true};
BUG_ON(!compile_win_script_from_string(&fade_out1, str));
number_of_triggers = 0;
if (opt->animations[ANIMATION_TRIGGER_CLOSE].script == NULL &&
!opt->no_fading_openclose) {
@ -501,25 +498,24 @@ void generate_fading_config(struct options *opt) {
if (opt->animations[ANIMATION_TRIGGER_HIDE].script == NULL) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_HIDE;
}
if (set_animation(opt->animations, trigger, number_of_triggers, fade_out1,
output_indices, 0, 0, true)) {
scripts[number_of_scripts++] = fade_out1;
if (set_animation(opt->animations, trigger, number_of_triggers, fade_out1, 0)) {
scripts[number_of_scripts++] = fade_out1.script;
} else {
script_free(fade_out1);
script_free(fade_out1.script);
}
// Fading for opacity change
asnprintf(&str, &len, FADING_TEMPLATE_1, duration_str);
auto fade_out2 = compile_win_script_from_string(str, output_indices);
struct win_script fade_out2 = {.is_generated = true};
BUG_ON(!compile_win_script_from_string(&fade_out2, str));
number_of_triggers = 0;
if (opt->animations[ANIMATION_TRIGGER_DECREASE_OPACITY].script == NULL) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_DECREASE_OPACITY;
}
if (set_animation(opt->animations, trigger, number_of_triggers, fade_out2,
output_indices, 0, 0, true)) {
scripts[number_of_scripts++] = fade_out2;
if (set_animation(opt->animations, trigger, number_of_triggers, fade_out2, 0)) {
scripts[number_of_scripts++] = fade_out2.script;
} else {
script_free(fade_out2);
script_free(fade_out2.script);
}
} else {
log_error("Invalid fade-out setting (step: %f, delta: %d), ignoring.",

View file

@ -0,0 +1,451 @@
// This file is generated by tools/animgen.c from data/animation_presets.conf
// This file is included in git repository for convenience only.
// DO NOT EDIT THIS FILE!
#include <libconfig.h>
#include "../curve.h"
#include "../script.h"
#include "../script_internal.h"
#include "config.h"
#include "utils/misc.h"
static struct script *script_template__disappear(int *output_slots) {
static const struct instruction instrs[] = {
{.type = INST_BRANCH_ONCE, .rel = 59},
{.type = INST_LOAD, .slot = 14},
{.type = INST_LOAD, .slot = 13},
{.type = INST_OP, .op = OP_SUB},
{.type = INST_LOAD, .slot = 11},
{.type = INST_IMM, .imm = 0.000000},
{.type = INST_OP, .op = OP_SUB},
{.type = INST_LOAD, .slot = 15},
{.type = INST_OP, .op = OP_DIV},
{
.type = INST_CURVE,
.curve = {.type = CURVE_LINEAR},
},
{.type = INST_OP, .op = OP_MUL},
{.type = INST_LOAD, .slot = 13},
{.type = INST_OP, .op = OP_ADD},
{.type = INST_STORE, .slot = 0},
{.type = INST_LOAD, .slot = 0},
{.type = INST_STORE, .slot = 1},
{.type = INST_LOAD, .slot = 0},
{.type = INST_STORE, .slot = 2},
{.type = INST_LOAD, .slot = 17},
{.type = INST_LOAD, .slot = 16},
{.type = INST_OP, .op = OP_SUB},
{.type = INST_LOAD, .slot = 11},
{.type = INST_IMM, .imm = 0.000000},
{.type = INST_OP, .op = OP_SUB},
{.type = INST_LOAD, .slot = 18},
{.type = INST_OP, .op = OP_DIV},
{
.type = INST_CURVE,
.curve = {.type = CURVE_CUBIC_BEZIER,
.bezier = {.ax = -0.650000,
.bx = 1.020000,
.cx = 0.630000,
.ay = -0.020000,
.by = 0.960000,
.cy = 0.060000}},
},
{.type = INST_OP, .op = OP_MUL},
{.type = INST_LOAD, .slot = 16},
{.type = INST_OP, .op = OP_ADD},
{.type = INST_STORE, .slot = 5},
{.type = INST_IMM, .imm = 1.000000},
{.type = INST_LOAD, .slot = 5},
{.type = INST_OP, .op = OP_SUB},
{.type = INST_IMM, .imm = 2.000000},
{.type = INST_OP, .op = OP_DIV},
{.type = INST_LOAD_CTX, .ctx = 16},
{.type = INST_OP, .op = OP_MUL},
{.type = INST_STORE, .slot = 3},
{.type = INST_LOAD, .slot = 5},
{.type = INST_STORE, .slot = 6},
{.type = INST_IMM, .imm = 1.000000},
{.type = INST_LOAD, .slot = 6},
{.type = INST_OP, .op = OP_SUB},
{.type = INST_IMM, .imm = 2.000000},
{.type = INST_OP, .op = OP_DIV},
{.type = INST_LOAD_CTX, .ctx = 24},
{.type = INST_OP, .op = OP_MUL},
{.type = INST_STORE, .slot = 4},
{.type = INST_LOAD, .slot = 5},
{.type = INST_STORE, .slot = 7},
{.type = INST_LOAD, .slot = 6},
{.type = INST_STORE, .slot = 8},
{.type = INST_LOAD, .slot = 3},
{.type = INST_STORE, .slot = 9},
{.type = INST_LOAD, .slot = 4},
{.type = INST_STORE, .slot = 10},
{.type = INST_BRANCH_ONCE, .rel = 15},
{.type = INST_HALT},
{.type = INST_LOAD_CTX, .ctx = 32},
{.type = INST_STORE_OVER_NAN, .slot = 13},
{.type = INST_LOAD_CTX, .ctx = 1073741824},
{.type = INST_STORE, .slot = 15},
{.type = INST_LOAD_CTX, .ctx = 40},
{.type = INST_STORE, .slot = 14},
{.type = INST_IMM, .imm = 1.000000},
{.type = INST_STORE_OVER_NAN, .slot = 16},
{.type = INST_LOAD_CTX, .ctx = 1073741824},
{.type = INST_STORE, .slot = 18},
{.type = INST_LOAD_CTX, .ctx = 1073741828},
{.type = INST_STORE, .slot = 17},
{.type = INST_BRANCH, .rel = -70},
{.type = INST_IMM, .imm = 0.000000},
{.type = INST_STORE, .slot = 12},
{.type = INST_LOAD, .slot = 15},
{.type = INST_IMM, .imm = 0.000000},
{.type = INST_OP, .op = OP_ADD},
{.type = INST_LOAD, .slot = 12},
{.type = INST_OP, .op = OP_MAX},
{.type = INST_STORE, .slot = 12},
{.type = INST_LOAD, .slot = 18},
{.type = INST_IMM, .imm = 0.000000},
{.type = INST_OP, .op = OP_ADD},
{.type = INST_LOAD, .slot = 12},
{.type = INST_OP, .op = OP_MAX},
{.type = INST_STORE, .slot = 12},
{.type = INST_HALT},
};
struct script *ret = malloc(offsetof(struct script, instrs) + sizeof(instrs));
ret->len = ARR_SIZE(instrs);
ret->elapsed_slot = 11;
ret->n_slots = 19;
ret->stack_size = 3;
ret->vars = NULL;
ret->overrides = NULL;
memcpy(ret->instrs, instrs, sizeof(instrs));
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("opacity"), .slot = 0, .index = 0};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("blur-opacity"), .slot = 1, .index = 1};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("shadow-opacity"), .slot = 2, .index = 2};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("offset-x"), .slot = 3, .index = 3};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("offset-y"), .slot = 4, .index = 4};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("scale-x"), .slot = 5, .index = 5};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("scale-y"), .slot = 6, .index = 6};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("shadow-scale-x"), .slot = 7, .index = 7};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("shadow-scale-y"), .slot = 8, .index = 8};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("shadow-offset-x"), .slot = 9, .index = 9};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("shadow-offset-y"), .slot = 10, .index = 10};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct overridable_slot *override = malloc(sizeof(*override));
*override = (struct overridable_slot){.name = strdup("opacity"), .slot = 13};
HASH_ADD_STR(ret->overrides, name, override);
}
{
struct overridable_slot *override = malloc(sizeof(*override));
*override = (struct overridable_slot){.name = strdup("scale-x"), .slot = 16};
HASH_ADD_STR(ret->overrides, name, override);
}
output_slots[0] = 3;
output_slots[1] = 4;
output_slots[2] = 9;
output_slots[3] = 10;
output_slots[4] = 0;
output_slots[5] = 1;
output_slots[6] = 2;
output_slots[7] = 5;
output_slots[8] = 6;
output_slots[9] = 7;
output_slots[10] = 8;
output_slots[11] = -1;
output_slots[12] = -1;
output_slots[13] = -1;
output_slots[14] = -1;
return ret;
}
static bool
win_script_preset__disappear(struct win_script *output, config_setting_t *setting) {
output->script = script_template__disappear(output->output_indices);
double placeholder_duration = 0.200000;
config_setting_lookup_float(setting, "duration", &placeholder_duration);
double placeholder_scale = 0.950000;
config_setting_lookup_float(setting, "scale", &placeholder_scale);
struct script_specialization_context spec[] = {
{.offset = SCRIPT_CTX_PLACEHOLDER_BASE + 0, .value = placeholder_duration},
{.offset = SCRIPT_CTX_PLACEHOLDER_BASE + 4, .value = placeholder_scale},
};
script_specialize(output->script, spec, ARR_SIZE(spec));
return true;
}
static struct script *script_template__appear(int *output_slots) {
static const struct instruction instrs[] = {
{.type = INST_BRANCH_ONCE, .rel = 59},
{.type = INST_LOAD, .slot = 14},
{.type = INST_LOAD, .slot = 13},
{.type = INST_OP, .op = OP_SUB},
{.type = INST_LOAD, .slot = 11},
{.type = INST_IMM, .imm = 0.000000},
{.type = INST_OP, .op = OP_SUB},
{.type = INST_LOAD, .slot = 15},
{.type = INST_OP, .op = OP_DIV},
{
.type = INST_CURVE,
.curve = {.type = CURVE_LINEAR},
},
{.type = INST_OP, .op = OP_MUL},
{.type = INST_LOAD, .slot = 13},
{.type = INST_OP, .op = OP_ADD},
{.type = INST_STORE, .slot = 0},
{.type = INST_LOAD, .slot = 0},
{.type = INST_STORE, .slot = 1},
{.type = INST_LOAD, .slot = 0},
{.type = INST_STORE, .slot = 2},
{.type = INST_IMM, .imm = 1.000000},
{.type = INST_LOAD, .slot = 16},
{.type = INST_OP, .op = OP_SUB},
{.type = INST_LOAD, .slot = 11},
{.type = INST_IMM, .imm = 0.000000},
{.type = INST_OP, .op = OP_SUB},
{.type = INST_LOAD, .slot = 17},
{.type = INST_OP, .op = OP_DIV},
{
.type = INST_CURVE,
.curve = {.type = CURVE_CUBIC_BEZIER,
.bezier = {.ax = -0.650000,
.bx = 0.930000,
.cx = 0.720000,
.ay = -0.020000,
.by = -0.900000,
.cy = 1.920000}},
},
{.type = INST_OP, .op = OP_MUL},
{.type = INST_LOAD, .slot = 16},
{.type = INST_OP, .op = OP_ADD},
{.type = INST_STORE, .slot = 5},
{.type = INST_IMM, .imm = 1.000000},
{.type = INST_LOAD, .slot = 5},
{.type = INST_OP, .op = OP_SUB},
{.type = INST_IMM, .imm = 2.000000},
{.type = INST_OP, .op = OP_DIV},
{.type = INST_LOAD_CTX, .ctx = 16},
{.type = INST_OP, .op = OP_MUL},
{.type = INST_STORE, .slot = 3},
{.type = INST_LOAD, .slot = 5},
{.type = INST_STORE, .slot = 6},
{.type = INST_IMM, .imm = 1.000000},
{.type = INST_LOAD, .slot = 6},
{.type = INST_OP, .op = OP_SUB},
{.type = INST_IMM, .imm = 2.000000},
{.type = INST_OP, .op = OP_DIV},
{.type = INST_LOAD_CTX, .ctx = 24},
{.type = INST_OP, .op = OP_MUL},
{.type = INST_STORE, .slot = 4},
{.type = INST_LOAD, .slot = 5},
{.type = INST_STORE, .slot = 7},
{.type = INST_LOAD, .slot = 6},
{.type = INST_STORE, .slot = 8},
{.type = INST_LOAD, .slot = 3},
{.type = INST_STORE, .slot = 9},
{.type = INST_LOAD, .slot = 4},
{.type = INST_STORE, .slot = 10},
{.type = INST_BRANCH_ONCE, .rel = 13},
{.type = INST_HALT},
{.type = INST_LOAD_CTX, .ctx = 32},
{.type = INST_STORE_OVER_NAN, .slot = 13},
{.type = INST_LOAD_CTX, .ctx = 1073741824},
{.type = INST_STORE, .slot = 15},
{.type = INST_LOAD_CTX, .ctx = 40},
{.type = INST_STORE, .slot = 14},
{.type = INST_LOAD_CTX, .ctx = 1073741828},
{.type = INST_STORE_OVER_NAN, .slot = 16},
{.type = INST_LOAD_CTX, .ctx = 1073741824},
{.type = INST_STORE, .slot = 17},
{.type = INST_BRANCH, .rel = -68},
{.type = INST_IMM, .imm = 0.000000},
{.type = INST_STORE, .slot = 12},
{.type = INST_LOAD, .slot = 15},
{.type = INST_IMM, .imm = 0.000000},
{.type = INST_OP, .op = OP_ADD},
{.type = INST_LOAD, .slot = 12},
{.type = INST_OP, .op = OP_MAX},
{.type = INST_STORE, .slot = 12},
{.type = INST_LOAD, .slot = 17},
{.type = INST_IMM, .imm = 0.000000},
{.type = INST_OP, .op = OP_ADD},
{.type = INST_LOAD, .slot = 12},
{.type = INST_OP, .op = OP_MAX},
{.type = INST_STORE, .slot = 12},
{.type = INST_HALT},
};
struct script *ret = malloc(offsetof(struct script, instrs) + sizeof(instrs));
ret->len = ARR_SIZE(instrs);
ret->elapsed_slot = 11;
ret->n_slots = 18;
ret->stack_size = 3;
ret->vars = NULL;
ret->overrides = NULL;
memcpy(ret->instrs, instrs, sizeof(instrs));
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("opacity"), .slot = 0, .index = 0};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("blur-opacity"), .slot = 1, .index = 1};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("shadow-opacity"), .slot = 2, .index = 2};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("offset-x"), .slot = 3, .index = 3};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("offset-y"), .slot = 4, .index = 4};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("scale-x"), .slot = 5, .index = 5};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("scale-y"), .slot = 6, .index = 6};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("shadow-scale-x"), .slot = 7, .index = 7};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("shadow-scale-y"), .slot = 8, .index = 8};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("shadow-offset-x"), .slot = 9, .index = 9};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct variable_allocation *var = malloc(sizeof(*var));
*var = (struct variable_allocation){
.name = strdup("shadow-offset-y"), .slot = 10, .index = 10};
HASH_ADD_STR(ret->vars, name, var);
}
{
struct overridable_slot *override = malloc(sizeof(*override));
*override = (struct overridable_slot){.name = strdup("opacity"), .slot = 13};
HASH_ADD_STR(ret->overrides, name, override);
}
{
struct overridable_slot *override = malloc(sizeof(*override));
*override = (struct overridable_slot){.name = strdup("scale-x"), .slot = 16};
HASH_ADD_STR(ret->overrides, name, override);
}
output_slots[0] = 3;
output_slots[1] = 4;
output_slots[2] = 9;
output_slots[3] = 10;
output_slots[4] = 0;
output_slots[5] = 1;
output_slots[6] = 2;
output_slots[7] = 5;
output_slots[8] = 6;
output_slots[9] = 7;
output_slots[10] = 8;
output_slots[11] = -1;
output_slots[12] = -1;
output_slots[13] = -1;
output_slots[14] = -1;
return ret;
}
static bool win_script_preset__appear(struct win_script *output, config_setting_t *setting) {
output->script = script_template__appear(output->output_indices);
double placeholder_duration = 0.200000;
config_setting_lookup_float(setting, "duration", &placeholder_duration);
double placeholder_scale = 0.950000;
config_setting_lookup_float(setting, "scale", &placeholder_scale);
struct script_specialization_context spec[] = {
{.offset = SCRIPT_CTX_PLACEHOLDER_BASE + 0, .value = placeholder_duration},
{.offset = SCRIPT_CTX_PLACEHOLDER_BASE + 4, .value = placeholder_scale},
};
script_specialize(output->script, spec, ARR_SIZE(spec));
return true;
}
struct {
const char *name;
bool (*func)(struct win_script *output, config_setting_t *setting);
} win_script_presets[] = {
{"disappear", win_script_preset__disappear},
{"appear", win_script_preset__appear},
{NULL, NULL},
};

View file

@ -1 +1 @@
srcs += [ files('curve.c', 'script.c') ]
srcs += [files('generated/script_templates.c', 'curve.c', 'preset.c', 'script.c')]

30
src/transition/preset.c Normal file
View file

@ -0,0 +1,30 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#include <libconfig.h>
#include <stdbool.h>
#include "config.h"
#include "preset.h"
#include "script.h"
extern struct {
const char *name;
bool (*func)(struct win_script *output, config_setting_t *setting);
} win_script_presets[];
bool win_script_parse_preset(struct win_script *output, config_setting_t *setting) {
const char *preset = NULL;
if (!config_setting_lookup_string(setting, "preset", &preset)) {
log_error("Missing preset name in script");
return false;
}
for (unsigned i = 0; win_script_presets[i].name; i++) {
if (strcmp(preset, win_script_presets[i].name) == 0) {
log_debug("Using animation preset: %s", preset);
return win_script_presets[i].func(output, setting);
}
}
log_error("Unknown preset: %s", preset);
return false;
}

12
src/transition/preset.h Normal file
View file

@ -0,0 +1,12 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#pragma once
#include <stdbool.h>
typedef struct config_setting_t config_setting_t;
struct win_script;
/// Parse a animation preset definition into a win_script.
bool win_script_parse_preset(struct win_script *output, config_setting_t *setting);

View file

@ -1127,6 +1127,22 @@ char *script_to_c(const struct script *script, const struct script_output_info *
return dynarr_join(buf, "");
}
void script_specialize(struct script *script,
const struct script_specialization_context *spec, unsigned n_context) {
for (unsigned i = 0; i < script->len; i++) {
if (script->instrs[i].type != INST_LOAD_CTX) {
continue;
}
for (unsigned j = 0; j < n_context; j++) {
if (script->instrs[i].ctx == spec[j].offset) {
script->instrs[i].type = INST_IMM;
script->instrs[i].imm = spec[j].value;
break;
}
}
}
}
struct script_instance *script_instance_new(const struct script *script) {
// allocate no space for the variable length array is UB.
unsigned memory_size = max2(1, script->n_slots + script->stack_size);

View file

@ -14,6 +14,11 @@ struct script_context_info {
ptrdiff_t offset;
};
struct script_specialization_context {
ptrdiff_t offset;
double value;
};
struct script_output_info {
const char *name;
/// Slot for this variable, -1 if this variable doesn't exist.
@ -66,6 +71,13 @@ struct script_instance *script_instance_new(const struct script *script);
unsigned script_total_duration_slot(const struct script *script);
unsigned script_elapsed_slot(const struct script *script);
/// Specialize a script instance with a context. During evaluation of the resulting
/// script, what would have been read from the context will be replaced with the hardcoded
/// value in the specialization context.
void script_specialize(struct script *instance,
const struct script_specialization_context *context,
unsigned n_context);
/// Check if a script instance has finished. The script instance must have been evaluated
/// at least once.
static inline bool script_instance_is_finished(const struct script_instance *instance) {