From 2eebfc8011ffbb6ee32419d4969c1f749a8bf729 Mon Sep 17 00:00:00 2001 From: Scott Moreau Date: Fri, 20 Dec 2024 11:06:08 -0700 Subject: [PATCH] Add extra-animations plugin The extra-animations plugin adds four new animations - blinds, helix, shatter and vortex. It requires animate and extra-animations plugins to be enabled. Currently, the new animations will not show up in wcm animate plugin, the config file must be edited manually. However, the options for the animations can be adjusted in wcm extra animations plugin. The animations are valid for open and close animation options. --- .github/workflows/ci.yaml | 4 +- metadata/extra-animations.xml | 58 +++++ metadata/meson.build | 1 + src/extra-animations/blinds.hpp | 360 ++++++++++++++++++++++++++ src/extra-animations/helix.hpp | 368 +++++++++++++++++++++++++++ src/extra-animations/meson.build | 5 + src/extra-animations/plugin.cpp | 69 +++++ src/extra-animations/shatter.hpp | 424 +++++++++++++++++++++++++++++++ src/extra-animations/vortex.hpp | 319 +++++++++++++++++++++++ src/meson.build | 2 + 10 files changed, 1608 insertions(+), 2 deletions(-) create mode 100644 metadata/extra-animations.xml create mode 100644 src/extra-animations/blinds.hpp create mode 100644 src/extra-animations/helix.hpp create mode 100644 src/extra-animations/meson.build create mode 100644 src/extra-animations/plugin.cpp create mode 100644 src/extra-animations/shatter.hpp create mode 100644 src/extra-animations/vortex.hpp diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d4a96f2..7e90090 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest container: alpine:edge steps: - - run: apk --no-cache add git gcc g++ binutils pkgconf meson ninja musl-dev wayland-dev wayland-protocols libinput-dev libevdev-dev libxkbcommon-dev pixman-dev glm-dev libdrm-dev mesa-dev cairo-dev pango-dev eudev-dev libxml2-dev glibmm-dev libseat-dev libdisplay-info-dev hwdata-dev nlohmann-json + - run: apk --no-cache add git gcc g++ binutils pkgconf meson ninja musl-dev wayland-dev wayland-protocols libinput-dev libevdev-dev libxkbcommon-dev pixman-dev glm-dev libdrm-dev mesa-dev cairo-dev pango-dev eudev-dev libxml2-dev glibmm-dev libseat-dev libdisplay-info-dev hwdata-dev nlohmann-json boost-dev - name: Wayfire uses: actions/checkout@v2 with: @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest container: alpine:edge steps: - - run: apk --no-cache add git gcc g++ binutils pkgconf meson ninja musl-dev wayland-dev wayland-protocols libinput-dev libevdev-dev libxkbcommon-dev pixman-dev glm-dev libdrm-dev mesa-dev cairo-dev pango-dev eudev-dev libxml2-dev glibmm-dev libseat-dev libxcb-dev xcb-util-wm-dev xwayland libdisplay-info-dev hwdata-dev nlohmann-json + - run: apk --no-cache add git gcc g++ binutils pkgconf meson ninja musl-dev wayland-dev wayland-protocols libinput-dev libevdev-dev libxkbcommon-dev pixman-dev glm-dev libdrm-dev mesa-dev cairo-dev pango-dev eudev-dev libxml2-dev glibmm-dev libseat-dev libxcb-dev xcb-util-wm-dev xwayland libdisplay-info-dev hwdata-dev nlohmann-json boost-dev - name: Wayfire uses: actions/checkout@v2 with: diff --git a/metadata/extra-animations.xml b/metadata/extra-animations.xml new file mode 100644 index 0000000..718645c --- /dev/null +++ b/metadata/extra-animations.xml @@ -0,0 +1,58 @@ + + + + <_short>Extra Animations + <_long>Extra animations to extend animate plugin + Effects + + <_short>Blinds Settings + + + + + <_short>Helix Settings + + + + + + <_short>Shatter Settings + + + + <_short>Vortex Settings + + + + diff --git a/metadata/meson.build b/metadata/meson.build index c6bf0cc..45ab60b 100644 --- a/metadata/meson.build +++ b/metadata/meson.build @@ -2,6 +2,7 @@ install_data('annotate.xml', install_dir: wayfire.get_variable(pkgconfig: 'metad install_data('autorotate-iio.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir')) install_data('bench.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir')) install_data('crosshair.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir')) +install_data('extra-animations.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir')) install_data('focus-change.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir')) install_data('focus-steal-prevent.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir')) install_data('follow-focus.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir')) diff --git a/src/extra-animations/blinds.hpp b/src/extra-animations/blinds.hpp new file mode 100644 index 0000000..7efee3d --- /dev/null +++ b/src/extra-animations/blinds.hpp @@ -0,0 +1,360 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Scott Moreau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static const char *blinds_vert_source = + R"( +#version 100 + +attribute mediump vec3 position; +attribute mediump vec2 uv_in; + +uniform mat4 matrix; + +varying highp vec2 uv; + +void main() { + uv = uv_in; + gl_Position = matrix * vec4(position, 1.0); +} +)"; + +static const char *blinds_frag_source = + R"( +#version 100 +@builtin_ext@ +@builtin@ + +precision mediump float; + +varying highp vec2 uv; + +void main() +{ + gl_FragColor = get_pixel(uv); +} +)"; + +namespace wf +{ +namespace blinds +{ +using namespace wf::scene; +using namespace wf::animate; +using namespace wf::animation; + +static std::string blinds_transformer_name = "animation-blinds"; + +wf::option_wrapper_t blinds_duration{"extra-animations/blinds_duration"}; +wf::option_wrapper_t blinds_strip_height{"extra-animations/blinds_strip_height"}; + +class blinds_animation_t : public duration_t +{ + public: + using duration_t::duration_t; +}; +class blinds_transformer : public wf::scene::view_2d_transformer_t +{ + public: + wayfire_view view; + OpenGL::program_t program; + wf::output_t *output; + wf::geometry_t animation_geometry; + blinds_animation_t progression{blinds_duration}; + + class simple_node_render_instance_t : public wf::scene::transformer_render_instance_t + { + wf::signal::connection_t on_node_damaged = + [=] (node_damage_signal *ev) + { + push_to_parent(ev->region); + }; + + blinds_transformer *self; + wayfire_view view; + damage_callback push_to_parent; + + public: + simple_node_render_instance_t(blinds_transformer *self, damage_callback push_damage, + wayfire_view view) : wf::scene::transformer_render_instance_t(self, + push_damage, + view->get_output()) + { + this->self = self; + this->view = view; + this->push_to_parent = push_damage; + self->connect(&on_node_damaged); + } + + ~simple_node_render_instance_t() + {} + + void schedule_instructions( + std::vector& instructions, + const wf::render_target_t& target, wf::region_t& damage) override + { + instructions.push_back(render_instruction_t{ + .instance = this, + .target = target, + .damage = damage & self->animation_geometry, + }); + } + + void transform_damage_region(wf::region_t& damage) override + { + damage |= wf::region_t{self->animation_geometry}; + } + + void render(const wf::render_target_t& target, + const wf::region_t& region) override + { + auto src_box = self->get_children_bounding_box(); + auto src_tex = wf::scene::transformer_render_instance_t::get_texture( + 1.0); + auto progress = self->progression.progress(); + self->animation_geometry = + wf::geometry_t{src_box.x - int(blinds_strip_height), src_box.y, + (src_box.x - int(blinds_strip_height)) + src_box.width + int(blinds_strip_height) * 2, + src_box.y + src_box.height}; + + int line_height = int(blinds_strip_height); + for (int i = 0; i < src_box.height; i += line_height) + { + std::vector uv; + std::vector vertices; + auto y = src_box.height - i; + auto inv_h = 1.0 / src_box.height; + uv.push_back(1.0); + uv.push_back(std::max(0, y - line_height) * inv_h); + uv.push_back(0.0); + uv.push_back(std::max(0, y - line_height) * inv_h); + uv.push_back(0.0); + uv.push_back(y * inv_h); + uv.push_back(1.0); + uv.push_back(y * inv_h); + auto x1 = src_box.width / 2.0; + auto x2 = -(src_box.width / 2.0); + auto y1 = -(std::min(src_box.height - i, line_height) / 2.0); + auto y2 = std::min(src_box.height - i, line_height) / 2.0; + glm::vec4 v, r; + glm::mat4 m(1.0); + m = + glm::rotate(m, + float(std::min(M_PI, + std::max(0.0, + (M_PI * (1.0 - progress)) - M_PI / 2.0 * (float(i) / src_box.height)) + + M_PI / 2.0)), glm::vec3(1.0, 0.0, 0.0)); + m = glm::scale(m, glm::vec3(2.0f / (src_box.width + line_height * 2), 2.0f / (y2 - y1), 1.0)); + v = glm::vec4(x1, y2, 0.0, 1.0); + r = m * v; + vertices.push_back(r.x); + vertices.push_back(r.y); + vertices.push_back(r.z); + v = glm::vec4(x2, y2, 0.0, 1.0); + r = m * v; + vertices.push_back(r.x); + vertices.push_back(r.y); + vertices.push_back(r.z); + v = glm::vec4(x2, y1, 0.0, 1.0); + r = m * v; + vertices.push_back(r.x); + vertices.push_back(r.y); + vertices.push_back(r.z); + v = glm::vec4(x1, y1, 0.0, 1.0); + r = m * v; + vertices.push_back(r.x); + vertices.push_back(r.y); + vertices.push_back(r.z); + + glm::mat4 p = glm::perspective(float(M_PI / 64.0), 1.0f, 0.1f, 100.0f); + glm::mat4 l = glm::lookAt( + glm::vec3(0., 0., 1.0 / std::tan(float(M_PI / 64.0) / 2)), + glm::vec3(0., 0., 0.), + glm::vec3(0., 1., 0.)); + + auto transform = p * l; + wf::render_target_t slice; + slice.allocate(src_box.width + line_height * 2, y2 - y1); + OpenGL::render_begin(slice); + OpenGL::clear(wf::color_t{0.0, 0.0, 0.0, 0.0}, GL_COLOR_BUFFER_BIT); + self->program.use(wf::TEXTURE_TYPE_RGBA); + self->program.uniformMatrix4f("matrix", transform); + self->program.attrib_pointer("position", 3, 0, vertices.data()); + self->program.attrib_pointer("uv_in", 2, 0, uv.data()); + self->program.set_active_texture(src_tex); + GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, vertices.size() / 3)); + OpenGL::render_end(); + OpenGL::render_begin(target); + for (auto box : region) + { + target.logic_scissor(wlr_box_from_pixman_box(box)); + OpenGL::render_transformed_texture(slice.tex, gl_geometry{float(src_box.x - line_height), + float(src_box.y + i), + float((src_box.x - line_height) + src_box.width + line_height * 2.0), + float((src_box.y + i) + (y2 - y1))}, {}, + target.get_orthographic_projection(), glm::vec4(1.0), 0); + } + + slice.release(); + OpenGL::render_end(); + } + } + }; + + blinds_transformer(wayfire_view view, wf::geometry_t bbox) : wf::scene::view_2d_transformer_t(view) + { + this->view = view; + if (view->get_output()) + { + output = view->get_output(); + output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE); + } + + animation_geometry = + wf::geometry_t{bbox.x - int(blinds_strip_height), bbox.y, + (bbox.x - int(blinds_strip_height)) + bbox.width + int(blinds_strip_height) * 2, + bbox.y + bbox.height}; + OpenGL::render_begin(); + program.compile(blinds_vert_source, blinds_frag_source); + OpenGL::render_end(); + } + + wf::geometry_t get_bounding_box() override + { + return this->animation_geometry; + } + + wf::effect_hook_t pre_hook = [=] () + { + output->render->damage(animation_geometry); + output->render->damage_whole(); + }; + + void gen_render_instances(std::vector& instances, + damage_callback push_damage, wf::output_t *shown_on) override + { + instances.push_back(std::make_unique( + this, push_damage, view)); + } + + void init_animation(bool blinds) + { + if (!blinds) + { + this->progression.reverse(); + } + + this->progression.start(); + } + + virtual ~blinds_transformer() + { + if (output) + { + output->render->rem_effect(&pre_hook); + } + + program.free_resources(); + } +}; + +class blinds_animation : public animation_base_t +{ + wayfire_view view; + + public: + void init(wayfire_view view, wf::animation_description_t dur, animation_type type) override + { + this->view = view; + pop_transformer(view); + auto bbox = view->get_transformed_node()->get_bounding_box(); + auto tmgr = view->get_transformed_node(); + auto node = std::make_shared(view, bbox); + tmgr->add_transformer(node, wf::TRANSFORMER_HIGHLEVEL + 1, blinds_transformer_name); + node->init_animation(type & WF_ANIMATE_HIDING_ANIMATION); + } + + void pop_transformer(wayfire_view view) + { + if (view->get_transformed_node()->get_transformer(blinds_transformer_name)) + { + view->get_transformed_node()->rem_transformer(blinds_transformer_name); + } + } + + bool step() override + { + if (!view) + { + return false; + } + + auto tmgr = view->get_transformed_node(); + if (!tmgr) + { + return false; + } + + if (auto tr = tmgr->get_transformer(blinds_transformer_name)) + { + auto running = tr->progression.running(); + if (!running) + { + pop_transformer(view); + return false; + } + + return running; + } + + return false; + } + + void reverse() override + { + if (auto tr = + view->get_transformed_node()->get_transformer( + blinds_transformer_name)) + { + tr->progression.reverse(); + } + } +}; +} +} diff --git a/src/extra-animations/helix.hpp b/src/extra-animations/helix.hpp new file mode 100644 index 0000000..900e16a --- /dev/null +++ b/src/extra-animations/helix.hpp @@ -0,0 +1,368 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Scott Moreau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static const char *helix_vert_source = + R"( +#version 100 + +attribute mediump vec3 position; +attribute mediump vec2 uv_in; + +uniform mat4 matrix; + +varying highp vec2 uv; + +void main() { + uv = uv_in; + gl_Position = matrix * vec4(position, 1.0); +} +)"; + +static const char *helix_frag_source = + R"( +#version 100 +@builtin_ext@ +@builtin@ + +precision mediump float; + +varying highp vec2 uv; + +void main() +{ + gl_FragColor = get_pixel(uv); +} +)"; + +namespace wf +{ +namespace helix +{ +using namespace wf::scene; +using namespace wf::animate; +using namespace wf::animation; + +static std::string transformer_name = "animation-helix"; + +wf::option_wrapper_t helix_duration{"extra-animations/helix_duration"}; +wf::option_wrapper_t helix_strip_height{"extra-animations/helix_strip_height"}; +wf::option_wrapper_t helix_rotations{"extra-animations/helix_rotations"}; + +class helix_animation_t : public duration_t +{ + public: + using duration_t::duration_t; +}; +class helix_transformer : public wf::scene::view_2d_transformer_t +{ + public: + wayfire_view view; + OpenGL::program_t program; + wf::output_t *output; + wf::geometry_t animation_geometry; + helix_animation_t progression{helix_duration}; + + class simple_node_render_instance_t : public wf::scene::transformer_render_instance_t + { + wf::signal::connection_t on_node_damaged = + [=] (node_damage_signal *ev) + { + push_to_parent(ev->region); + }; + + helix_transformer *self; + wayfire_view view; + damage_callback push_to_parent; + + public: + simple_node_render_instance_t(helix_transformer *self, damage_callback push_damage, + wayfire_view view) : wf::scene::transformer_render_instance_t(self, + push_damage, + view->get_output()) + { + this->self = self; + this->view = view; + this->push_to_parent = push_damage; + self->connect(&on_node_damaged); + } + + ~simple_node_render_instance_t() + {} + + void schedule_instructions( + std::vector& instructions, + const wf::render_target_t& target, wf::region_t& damage) + { + instructions.push_back(render_instruction_t{ + .instance = this, + .target = target, + .damage = damage & self->animation_geometry, + }); + } + + void transform_damage_region(wf::region_t& damage) override + { + damage |= wf::region_t{self->animation_geometry}; + } + + void render(const wf::render_target_t& target, + const wf::region_t& region) + { + auto src_box = self->get_children_bounding_box(); + auto src_tex = wf::scene::transformer_render_instance_t::get_texture( + 1.0); + auto progress = self->progression.progress(); + auto og = self->output->get_relative_geometry(); + self->animation_geometry = og; + + int line_height = int(helix_strip_height); + std::vector uv; + std::vector vertices; + glm::mat4 l = glm::lookAt( + glm::vec3(0., 0., 1.0 / std::tan(float(M_PI / 4.0) / 2)), + glm::vec3(0., 0., 0.), + glm::vec3(0., 1., 0.)); + glm::mat4 p = glm::perspective(float(M_PI / 4.0), 1.0f, 0.1f, 100.0f); + for (int i = 0; i < src_box.height; i += line_height) + { + auto y = src_box.height - i; + auto inv_h = 1.0 / src_box.height; + uv.push_back(0.0); + uv.push_back(std::max(0, y - line_height) * inv_h); + uv.push_back(1.0); + uv.push_back(std::max(0, y - line_height) * inv_h); + uv.push_back(0.0); + uv.push_back(y * inv_h); + uv.push_back(1.0); + uv.push_back(y * inv_h); + uv.push_back(0.0); + uv.push_back(y * inv_h); + uv.push_back(1.0); + uv.push_back(std::max(0, y - line_height) * inv_h); + glm::vec4 v, r; + glm::mat4 m(1.0); + m = glm::rotate(m, float(M_PI), glm::vec3(1.0, 0.0, 0.0)); + m = + glm::rotate(m, + float(std::min(M_PI * int(helix_rotations), + std::max(0.0, + ((M_PI * 1.5 + int(helix_rotations) * M_PI) * (1.0 - progress)) - M_PI * 2.0 * + (float(i) / src_box.height)) + + M_PI / 2.0) - int(helix_rotations) * M_PI), glm::vec3(0.0, 1.0, 0.0)); + m = glm::scale(m, glm::vec3(2.0f / og.width, 2.0f / og.height, 1.0)); + auto x1 = src_box.width / 2.0; + auto x2 = -(src_box.width / 2.0); + auto y1 = -(src_box.height / 2.0) + i; + auto y2 = std::min(src_box.height / 2.0, -(src_box.height / 2.0) + i + line_height); + v = glm::vec4(x2, y2, 0.0, 1.0); + r = m * v; + vertices.push_back(r.x); + vertices.push_back(r.y); + vertices.push_back(r.z); + v = glm::vec4(x1, y2, 0.0, 1.0); + r = m * v; + vertices.push_back(r.x); + vertices.push_back(r.y); + vertices.push_back(r.z); + v = glm::vec4(x2, y1, 0.0, 1.0); + r = m * v; + vertices.push_back(r.x); + vertices.push_back(r.y); + vertices.push_back(r.z); + v = glm::vec4(x1, y1, 0.0, 1.0); + r = m * v; + vertices.push_back(r.x); + vertices.push_back(r.y); + vertices.push_back(r.z); + v = glm::vec4(x2, y1, 0.0, 1.0); + r = m * v; + vertices.push_back(r.x); + vertices.push_back(r.y); + vertices.push_back(r.z); + v = glm::vec4(x1, y2, 0.0, 1.0); + r = m * v; + vertices.push_back(r.x); + vertices.push_back(r.y); + vertices.push_back(r.z); + } + + auto t = + glm::translate(glm::mat4(1.0), + glm::vec3((src_box.x - og.width / 2.0f + src_box.width / 2.0f) * + float(2.0f / float(og.width)), + -(src_box.y - og.height / 2.0f + src_box.height / 2.0f) * + float(2.0f / float(og.height)), + 0.0)); + + auto transform = target.transform * t * p * l; + OpenGL::render_begin(target); + for (auto box : region) + { + target.logic_scissor(wlr_box_from_pixman_box(box)); + self->program.use(wf::TEXTURE_TYPE_RGBA); + self->program.uniformMatrix4f("matrix", transform); + self->program.attrib_pointer("position", 3, 0, vertices.data()); + self->program.attrib_pointer("uv_in", 2, 0, uv.data()); + self->program.set_active_texture(src_tex); + GL_CALL(glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3)); + } + + OpenGL::render_end(); + } + }; + + helix_transformer(wayfire_view view, wf::geometry_t bbox) : wf::scene::view_2d_transformer_t(view) + { + this->view = view; + if (view->get_output()) + { + output = view->get_output(); + output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE); + } + + animation_geometry = bbox; + OpenGL::render_begin(); + program.compile(helix_vert_source, helix_frag_source); + OpenGL::render_end(); + } + + wf::geometry_t get_bounding_box() override + { + return this->animation_geometry; + } + + wf::effect_hook_t pre_hook = [=] () + { + output->render->damage(animation_geometry); + output->render->damage_whole(); + }; + + void gen_render_instances(std::vector& instances, + damage_callback push_damage, wf::output_t *shown_on) override + { + instances.push_back(std::make_unique( + this, push_damage, view)); + } + + void init_animation(bool helix) + { + if (!helix) + { + this->progression.reverse(); + } + + this->progression.start(); + } + + virtual ~helix_transformer() + { + if (output) + { + output->render->rem_effect(&pre_hook); + } + + program.free_resources(); + } +}; + +class helix_animation : public animation_base_t +{ + wayfire_view view; + + public: + void init(wayfire_view view, wf::animation_description_t dur, animation_type type) override + { + this->view = view; + pop_transformer(view); + auto bbox = view->get_transformed_node()->get_bounding_box(); + auto tmgr = view->get_transformed_node(); + auto node = std::make_shared(view, bbox); + tmgr->add_transformer(node, wf::TRANSFORMER_HIGHLEVEL + 1, transformer_name); + node->init_animation(type & WF_ANIMATE_HIDING_ANIMATION); + } + + void pop_transformer(wayfire_view view) + { + if (view->get_transformed_node()->get_transformer(transformer_name)) + { + view->get_transformed_node()->rem_transformer(transformer_name); + } + } + + bool step() override + { + if (!view) + { + return false; + } + + auto tmgr = view->get_transformed_node(); + if (!tmgr) + { + return false; + } + + if (auto tr = tmgr->get_transformer(transformer_name)) + { + auto running = tr->progression.running(); + if (!running) + { + pop_transformer(view); + return false; + } + + return running; + } + + return false; + } + + void reverse() override + { + if (auto tr = + view->get_transformed_node()->get_transformer( + transformer_name)) + { + tr->progression.reverse(); + } + } +}; +} +} diff --git a/src/extra-animations/meson.build b/src/extra-animations/meson.build new file mode 100644 index 0000000..0d14b19 --- /dev/null +++ b/src/extra-animations/meson.build @@ -0,0 +1,5 @@ +boost = dependency('boost') + +extra_animations = shared_module('extra-animations', 'plugin.cpp', + dependencies: [wayfire, boost], + install: true, install_dir: join_paths(get_option('libdir'), 'wayfire')) diff --git a/src/extra-animations/plugin.cpp b/src/extra-animations/plugin.cpp new file mode 100644 index 0000000..fcd29a2 --- /dev/null +++ b/src/extra-animations/plugin.cpp @@ -0,0 +1,69 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Scott Moreau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +#include "blinds.hpp" +#include "helix.hpp" +#include "shatter.hpp" +#include "vortex.hpp" + +class wayfire_extra_animations : public wf::plugin_interface_t +{ + wf::shared_data::ref_ptr_t effects_registry; + + public: + void init() override + { + effects_registry->register_effect("blinds", wf::animate::effect_description_t{ + .generator = [] { return std::make_unique(); }, + .default_duration = [=] { return wf::blinds::blinds_duration.value(); }, + }); + effects_registry->register_effect("helix", wf::animate::effect_description_t{ + .generator = [] { return std::make_unique(); }, + .default_duration = [=] { return wf::helix::helix_duration.value(); }, + }); + effects_registry->register_effect("shatter", wf::animate::effect_description_t{ + .generator = [] { return std::make_unique(); }, + .default_duration = [=] { return wf::shatter::shatter_duration.value(); }, + }); + effects_registry->register_effect("vortex", wf::animate::effect_description_t{ + .generator = [] { return std::make_unique(); }, + .default_duration = [=] { return wf::vortex::vortex_duration.value(); }, + }); + } + + void fini() override + { + effects_registry->unregister_effect("blinds"); + effects_registry->unregister_effect("helix"); + effects_registry->unregister_effect("shatter"); + effects_registry->unregister_effect("vortex"); + } +}; + +DECLARE_WAYFIRE_PLUGIN(wayfire_extra_animations); diff --git a/src/extra-animations/shatter.hpp b/src/extra-animations/shatter.hpp new file mode 100644 index 0000000..c68c13f --- /dev/null +++ b/src/extra-animations/shatter.hpp @@ -0,0 +1,424 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Scott Moreau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using boost::polygon::voronoi_builder; +using boost::polygon::voronoi_diagram; + +static const char *shatter_vert_source = + R"( +#version 100 + +attribute mediump vec2 position; +attribute mediump vec2 uv_in; + +uniform mat4 matrix; + +varying highp vec2 uv; + +void main() { + uv = uv_in; + gl_Position = matrix * vec4(position, 0.0, 1.0); +} +)"; + +static const char *shatter_frag_source = + R"( +#version 100 +@builtin_ext@ +@builtin@ + +precision mediump float; + +varying highp vec2 uv; +uniform mediump float alpha; + +void main() +{ + vec4 pixel = get_pixel(uv); + gl_FragColor = vec4(pixel * alpha); +} +)"; + +namespace wf +{ +namespace shatter +{ +using namespace wf::scene; +using namespace wf::animate; +using namespace wf::animation; + +static std::string shatter_transformer_name = "animation-shatter"; + +wf::option_wrapper_t shatter_duration{"extra-animations/shatter_duration"}; + +class shatter_animation_t : public duration_t +{ + public: + using duration_t::duration_t; + timed_transition_t shatter{*this}; +}; +class shatter_transformer : public wf::scene::view_2d_transformer_t +{ + public: + wayfire_view view; + OpenGL::program_t program; + wf::output_t *output; + wf::geometry_t animation_geometry; + shatter_animation_t progression{shatter_duration}; + voronoi_diagram vd; + std::vector rotations; + std::vector> points; + + class simple_node_render_instance_t : public wf::scene::transformer_render_instance_t + { + wf::signal::connection_t on_node_damaged = + [=] (node_damage_signal *ev) + { + push_to_parent(ev->region); + }; + + shatter_transformer *self; + wayfire_view view; + damage_callback push_to_parent; + + public: + simple_node_render_instance_t(shatter_transformer *self, damage_callback push_damage, + wayfire_view view) : wf::scene::transformer_render_instance_t(self, + push_damage, + view->get_output()) + { + this->self = self; + this->view = view; + this->push_to_parent = push_damage; + self->connect(&on_node_damaged); + } + + ~simple_node_render_instance_t() + {} + + void schedule_instructions( + std::vector& instructions, + const wf::render_target_t& target, wf::region_t& damage) override + { + instructions.push_back(render_instruction_t{ + .instance = this, + .target = target, + .damage = damage // & self->get_bounding_box(), + }); + } + + void transform_damage_region(wf::region_t& damage) override + { + damage |= wf::region_t{self->animation_geometry}; + } + + void render(const wf::render_target_t& target, + const wf::region_t& region) override + { + auto src_box = self->get_children_bounding_box(); + auto src_tex = wf::scene::transformer_render_instance_t::get_texture( + 1.0); + auto progress = self->progression.progress(); + auto progress_pt_one = (std::clamp(progress, 0.5, 1.0) - 0.5) * 2.0; + auto progress_pt_two = std::clamp(progress, 0.0, 0.5) * 2.0; + auto og = self->output->get_relative_geometry(); + + OpenGL::render_begin(target); + GL_CALL(glDisable(GL_CULL_FACE)); + GL_CALL(glEnable(GL_BLEND)); + GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); + self->program.use(wf::TEXTURE_TYPE_RGBA); + self->program.set_active_texture(src_tex); + int i = 0; + glm::mat4 l = glm::lookAt( + glm::vec3(0., 0., 1.0 / std::tan(float(M_PI / 4.0) / 2)), + glm::vec3(0., 0., 0.), + glm::vec3(0., 1., 0.)); + glm::mat4 p = glm::perspective(float(M_PI / 4.0), 1.0f, 0.1f, 100.0f); + for (voronoi_diagram::const_cell_iterator cell = self->vd.cells().begin(); + cell != self->vd.cells().end(); + cell++, i++) + { + const boost::polygon::voronoi_edge *edge = cell->incident_edge(); + std::vector uv; + std::vector vertices; + // bounding box of polygon + float x1 = std::numeric_limits::max(); + float y1 = std::numeric_limits::max(); + float x2 = std::numeric_limits::min(); + float y2 = std::numeric_limits::min(); + if (!edge) + { + continue; + } + + do { + if (!edge) + { + continue; + } + + edge = edge->next(); + if (edge && edge->vertex0() && !std::isnan(edge->vertex0()->x()) && + !std::isnan(edge->vertex0()->y())) + { + auto x = std::clamp(edge->vertex0()->x(), double(0.0), double(src_box.width)); + auto y = std::clamp(edge->vertex0()->y(), double(0.0), double(src_box.height)); + uv.push_back(x / src_box.width); + uv.push_back(y / src_box.height); + if (x1 > x) + { + x1 = x; + } + + if (y1 > y) + { + y1 = y; + } + + if (x2 < x) + { + x2 = x; + } + + if (y2 < y) + { + y2 = y; + } + } + } while (edge != cell->incident_edge()); + + auto center = glm::vec2(x1 + (x2 - x1) / 2.0f, y1 + (y2 - y1) / 2.0f); + do { + if (!edge) + { + continue; + } + + edge = edge->next(); + if (edge && edge->vertex0() && !std::isnan(edge->vertex0()->x()) && + !std::isnan(edge->vertex0()->y())) + { + auto x = std::clamp(edge->vertex0()->x(), double(0.0), double(src_box.width)); + auto y = std::clamp(edge->vertex0()->y(), double(0.0), double(src_box.height)); + glm::vec4 v, r; + glm::mat4 m(1.0); + m = + glm::rotate(m, + float(progress_pt_one * progress_pt_one * self->rotations.data()[i].z), glm::vec3( + 0.0, 0.0, + 1.0)); + m = glm::scale(m, glm::vec3(2.0f / og.width, 2.0f / og.height, 1.0)); + m = glm::translate(m, glm::vec3(-(center.x), -(center.y), 0.0)); + v = glm::vec4(x, y, 0.0, 1.0); + r = m * v; + vertices.push_back(r.x); + vertices.push_back(r.y); + } + } while (edge != cell->incident_edge()); + + glm::mat4 m(1.0); + m = glm::translate(m, glm::vec3( + ((progress_pt_one * progress_pt_one + progress_pt_two * 0.01) * + (center.x - src_box.width / 2.0f) * self->rotations.data()[i].x) * (2.0f / og.width), + ((progress_pt_one * progress_pt_one + progress_pt_two * 0.01) * + (center.y - src_box.height / 2.0f) * self->rotations.data()[i].y) * (2.0f / og.width), + (progress_pt_one * progress_pt_one * self->rotations.data()[i].z) * (2.0f / og.width))); + m = glm::translate(m, glm::vec3( + ((center.x - og.width / 2.0f) + src_box.x) * (2.0f / og.width), + ((center.y - og.height / 2.0f) + (og.height - src_box.y - src_box.height)) * + (2.0f / og.height), 0.0)); + auto alpha = std::clamp((1.0 - progress) * 2.0, 0.0, 1.0); + self->program.uniformMatrix4f("matrix", target.transform * m * p * l); + self->program.uniform1f("alpha", alpha); + self->program.attrib_pointer("position", 2, 0, vertices.data()); + self->program.attrib_pointer("uv_in", 2, 0, uv.data()); + if (vertices.size() / 2 >= 3) + { + GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, vertices.size() / 2)); + } + } + + self->program.deactivate(); + OpenGL::render_end(); + } + }; + + shatter_transformer(wayfire_view view, wf::geometry_t bbox) : wf::scene::view_2d_transformer_t(view) + { + this->view = view; + if (view->get_output()) + { + output = view->get_output(); + output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE); + } + + auto og = output->get_relative_geometry(); + animation_geometry = og; + OpenGL::render_begin(); + program.compile(shatter_vert_source, shatter_frag_source); + OpenGL::render_end(); + + std::srand(std::time(nullptr)); + auto offset_range = 100; + for (int y = -offset_range; + y < bbox.height + offset_range * 2; + y += int((std::rand() / float(RAND_MAX)) * offset_range)) + { + for (int x = -offset_range * 1.75f; + x < bbox.width + offset_range * 1.75f * 2; + x += int((std::rand() / float(RAND_MAX)) * offset_range * 1.75f)) + { + points.push_back(boost::polygon::point_data(x, y)); + rotations.push_back(glm::vec3( + ((std::rand() / float(RAND_MAX)) * 5.0f + 5.0f), + ((std::rand() / float(RAND_MAX)) * 5.0f + 5.0f), + M_PI * 2.0 * ((std::rand() / float(RAND_MAX)) * 10.0f - 5.0f))); + } + } + + construct_voronoi(points.begin(), points.end(), &vd); + } + + wf::geometry_t get_bounding_box() override + { + return this->animation_geometry; + } + + wf::effect_hook_t pre_hook = [=] () + { + output->render->damage(animation_geometry); + }; + + void gen_render_instances(std::vector& instances, + damage_callback push_damage, wf::output_t *shown_on) override + { + instances.push_back(std::make_unique( + this, push_damage, view)); + } + + void init_animation(bool shatter) + { + if (!shatter) + { + this->progression.reverse(); + } + + this->progression.start(); + } + + virtual ~shatter_transformer() + { + if (output) + { + output->render->rem_effect(&pre_hook); + } + + program.free_resources(); + } +}; + +class shatter_animation : public animation_base_t +{ + wayfire_view view; + + public: + void init(wayfire_view view, wf::animation_description_t dur, animation_type type) override + { + this->view = view; + pop_transformer(view); + auto bbox = view->get_transformed_node()->get_bounding_box(); + auto tmgr = view->get_transformed_node(); + auto node = std::make_shared(view, bbox); + tmgr->add_transformer(node, wf::TRANSFORMER_HIGHLEVEL + 1, shatter_transformer_name); + node->init_animation(type & WF_ANIMATE_HIDING_ANIMATION); + } + + void pop_transformer(wayfire_view view) + { + if (view->get_transformed_node()->get_transformer(shatter_transformer_name)) + { + view->get_transformed_node()->rem_transformer(shatter_transformer_name); + } + } + + bool step() override + { + if (!view) + { + return false; + } + + auto tmgr = view->get_transformed_node(); + if (!tmgr) + { + return false; + } + + if (auto tr = + tmgr->get_transformer(shatter_transformer_name)) + { + auto running = tr->progression.running(); + if (!running) + { + pop_transformer(view); + return false; + } + + return running; + } + + return false; + } + + void reverse() override + { + if (auto tr = + view->get_transformed_node()->get_transformer( + shatter_transformer_name)) + { + tr->progression.reverse(); + } + } +}; +} +} diff --git a/src/extra-animations/vortex.hpp b/src/extra-animations/vortex.hpp new file mode 100644 index 0000000..5da0deb --- /dev/null +++ b/src/extra-animations/vortex.hpp @@ -0,0 +1,319 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Scott Moreau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static const char *vortex_vert_source = + R"( +#version 100 + +attribute mediump vec2 position; +attribute mediump vec2 uv_in; + +uniform mat4 matrix; + +varying highp vec2 uv; + +void main() { + uv = uv_in; + gl_Position = matrix * vec4(position, 0.0, 1.0); +} +)"; + +static const char *vortex_frag_source = + R"( +#version 100 +@builtin_ext@ +@builtin@ + +precision mediump float; + +varying highp vec2 uv; +uniform mediump float progress; + +const float PI = 3.1415926535897932384626433832795; + +vec2 rotate(vec2 uv, float rotation, vec2 mid) +{ + return vec2( + cos(rotation) * (uv.x - mid.x) + sin(rotation) * (uv.y - mid.y) + mid.x, + cos(rotation) * (uv.y - mid.y) - sin(rotation) * (uv.x - mid.x) + mid.y + ); +} + +void main() +{ + vec2 uv_vortex; + float intensity = 50.0; + vec2 center = vec2(0.5, 0.5); + float d = distance(uv, center); + float progress_pt_one = clamp(progress, 0.0, 0.5) * 2.0; + float progress_pt_two = (clamp(progress, 0.5, 1.0) - 0.5) * 2.0; + float sigmoid = 1.0 / (1.0 + pow(2.718, -(d * 12.0))); + vec2 r = uv - (center - uv) * progress_pt_two * progress_pt_two * 5.0; + r -= (center - r) * progress_pt_one * progress_pt_one * (2.0 - (sigmoid - 0.5) * 4.0); + uv_vortex = rotate(r, (1.0 - (sigmoid - 0.5) * 2.0) * progress * progress * intensity, center); + + if (uv_vortex.x < 0.0 || uv_vortex.y < 0.0 || + uv_vortex.x > 1.0 || uv_vortex.y > 1.0) + { + discard; + } + + gl_FragColor = get_pixel(uv_vortex) * clamp(1.0 - progress, 0.0, 0.25) * 4.0; +} +)"; + +namespace wf +{ +namespace vortex +{ +using namespace wf::scene; +using namespace wf::animate; +using namespace wf::animation; + +static std::string vortex_transformer_name = "animation-vortex"; + +wf::option_wrapper_t vortex_duration{"extra-animations/vortex_duration"}; + +class vortex_animation_t : public duration_t +{ + public: + using duration_t::duration_t; +}; +class vortex_transformer : public wf::scene::view_2d_transformer_t +{ + public: + wayfire_view view; + OpenGL::program_t program; + wf::output_t *output; + wf::geometry_t animation_geometry; + vortex_animation_t progression{vortex_duration}; + + class simple_node_render_instance_t : public wf::scene::transformer_render_instance_t + { + wf::signal::connection_t on_node_damaged = + [=] (node_damage_signal *ev) + { + push_to_parent(ev->region); + }; + + vortex_transformer *self; + wayfire_view view; + damage_callback push_to_parent; + + public: + simple_node_render_instance_t(vortex_transformer *self, damage_callback push_damage, + wayfire_view view) : wf::scene::transformer_render_instance_t(self, + push_damage, + view->get_output()) + { + this->self = self; + this->view = view; + this->push_to_parent = push_damage; + self->connect(&on_node_damaged); + } + + ~simple_node_render_instance_t() + {} + + void schedule_instructions( + std::vector& instructions, + const wf::render_target_t& target, wf::region_t& damage) override + { + instructions.push_back(render_instruction_t{ + .instance = this, + .target = target, + .damage = damage & self->get_bounding_box(), + }); + } + + void transform_damage_region(wf::region_t& damage) override + { + damage |= wf::region_t{self->animation_geometry}; + } + + void render(const wf::render_target_t& target, + const wf::region_t& region) override + { + auto src_box = self->get_children_bounding_box(); + auto src_tex = wf::scene::transformer_render_instance_t::get_texture( + 1.0); + auto progress = self->progression.progress(); + static const float vertex_data_uv[] = { + 0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f, + 0.0f, 1.0f, + }; + + const float vertex_data_pos[] = { + 1.0f * src_box.x, + 1.0f * src_box.y + src_box.height, + 1.0f * src_box.x + src_box.width, + 1.0f * src_box.y + src_box.height, + 1.0f * src_box.x + src_box.width, + 1.0f * src_box.y, + 1.0f * src_box.x, 1.0f * src_box.y, + }; + + OpenGL::render_begin(target); + self->program.use(wf::TEXTURE_TYPE_RGBA); + self->program.uniformMatrix4f("matrix", target.get_orthographic_projection()); + self->program.attrib_pointer("position", 2, 0, vertex_data_pos); + self->program.attrib_pointer("uv_in", 2, 0, vertex_data_uv); + self->program.uniform1f("progress", progress); + self->program.set_active_texture(src_tex); + GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4)); + OpenGL::render_end(); + } + }; + + vortex_transformer(wayfire_view view, wf::geometry_t bbox) : wf::scene::view_2d_transformer_t(view) + { + this->view = view; + if (view->get_output()) + { + output = view->get_output(); + output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE); + } + + animation_geometry = bbox; + OpenGL::render_begin(); + program.compile(vortex_vert_source, vortex_frag_source); + OpenGL::render_end(); + } + + wf::effect_hook_t pre_hook = [=] () + { + output->render->damage(animation_geometry); + }; + + void gen_render_instances(std::vector& instances, + damage_callback push_damage, wf::output_t *shown_on) override + { + instances.push_back(std::make_unique( + this, push_damage, view)); + } + + void init_animation(bool vortex) + { + if (!vortex) + { + this->progression.reverse(); + } + + this->progression.start(); + } + + virtual ~vortex_transformer() + { + if (output) + { + output->render->rem_effect(&pre_hook); + } + + program.free_resources(); + } +}; + +class vortex_animation : public animation_base_t +{ + wayfire_view view; + + public: + void init(wayfire_view view, wf::animation_description_t dur, animation_type type) override + { + this->view = view; + pop_transformer(view); + auto bbox = view->get_transformed_node()->get_bounding_box(); + auto tmgr = view->get_transformed_node(); + auto node = std::make_shared(view, bbox); + tmgr->add_transformer(node, wf::TRANSFORMER_HIGHLEVEL + 1, vortex_transformer_name); + node->init_animation(type & WF_ANIMATE_HIDING_ANIMATION); + } + + void pop_transformer(wayfire_view view) + { + if (view->get_transformed_node()->get_transformer(vortex_transformer_name)) + { + view->get_transformed_node()->rem_transformer(vortex_transformer_name); + } + } + + bool step() override + { + if (!view) + { + return false; + } + + auto tmgr = view->get_transformed_node(); + if (!tmgr) + { + return false; + } + + if (auto tr = + tmgr->get_transformer(vortex_transformer_name)) + { + auto running = tr->progression.running(); + if (!running) + { + pop_transformer(view); + return false; + } + + return running; + } + + return false; + } + + void reverse() override + { + if (auto tr = + view->get_transformed_node()->get_transformer( + vortex_transformer_name)) + { + tr->progression.reverse(); + } + } +}; +} +} diff --git a/src/meson.build b/src/meson.build index dfdd44a..954323c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -90,3 +90,5 @@ window_zoom = shared_module('winzoom', 'window-zoom.cpp', workspace_names = shared_module('workspace-names', 'workspace-names.cpp', dependencies: [wayfire], install: true, install_dir: join_paths(get_option('libdir'), 'wayfire')) + +subdir('extra-animations')