diff --git a/.gitignore b/.gitignore index 35b6e162..e9136ce2 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,7 @@ target .vscode *.conf !/tests/configs/*.conf +!/data/*.conf perf.data perf.data.old core.* diff --git a/data/animation_presets.conf b/data/animation_presets.conf new file mode 100644 index 00000000..d5168344 --- /dev/null +++ b/data/animation_presets.conf @@ -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); + }; +}; diff --git a/src/config_libconfig.c b/src/config_libconfig.c index e69f3477..b90f8c0d 100644 --- a/src/config_libconfig.c +++ b/src/config_libconfig.c @@ -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.", diff --git a/src/transition/generated/script_templates.c b/src/transition/generated/script_templates.c new file mode 100644 index 00000000..61f21c79 --- /dev/null +++ b/src/transition/generated/script_templates.c @@ -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 +#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}, +}; diff --git a/src/transition/meson.build b/src/transition/meson.build index 17a618d6..c7a13819 100644 --- a/src/transition/meson.build +++ b/src/transition/meson.build @@ -1 +1 @@ -srcs += [ files('curve.c', 'script.c') ] +srcs += [files('generated/script_templates.c', 'curve.c', 'preset.c', 'script.c')] diff --git a/src/transition/preset.c b/src/transition/preset.c new file mode 100644 index 00000000..8b5cadde --- /dev/null +++ b/src/transition/preset.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright (c) Yuxuan Shui + +#include +#include + +#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; +} diff --git a/src/transition/preset.h b/src/transition/preset.h new file mode 100644 index 00000000..f6d1a45b --- /dev/null +++ b/src/transition/preset.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright (c) Yuxuan Shui + +#pragma once + +#include + +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); diff --git a/src/transition/script.c b/src/transition/script.c index 24edd8a0..29cd9f9a 100644 --- a/src/transition/script.c +++ b/src/transition/script.c @@ -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); diff --git a/src/transition/script.h b/src/transition/script.h index fd2bc415..d191eb32 100644 --- a/src/transition/script.h +++ b/src/transition/script.h @@ -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) {