From 837af421a69e4122ca3e3f0a93a3a8c9744b51ba Mon Sep 17 00:00:00 2001 From: Scott Moreau Date: Wed, 31 Jul 2024 08:16:25 -0600 Subject: [PATCH 1/4] Add blinds animation --- metadata/animate.xml | 13 ++ plugins/animate/animate.cpp | 9 + plugins/animate/blinds.hpp | 369 ++++++++++++++++++++++++++++++++++++ 3 files changed, 391 insertions(+) create mode 100644 plugins/animate/blinds.hpp diff --git a/metadata/animate.xml b/metadata/animate.xml index 31da5891e..619f9c5fc 100644 --- a/metadata/animate.xml +++ b/metadata/animate.xml @@ -25,6 +25,10 @@ fire <_name>Fire + + blinds + <_name>Blinds + + diff --git a/plugins/animate/animate.cpp b/plugins/animate/animate.cpp index 8b7fb7805..19350df58 100644 --- a/plugins/animate/animate.cpp +++ b/plugins/animate/animate.cpp @@ -8,6 +8,7 @@ #include "animate.hpp" #include "system_fade.hpp" #include "basic_animations.hpp" +#include "blinds.hpp" #include "fire/fire.hpp" #include "unmapped-view-node.hpp" #include "wayfire/plugin.hpp" @@ -416,6 +417,10 @@ class wayfire_animation : public wf::plugin_interface_t, private wf::per_output_ { set_animation(ev->view, ANIMATION_TYPE_MAP, animation.duration, animation.animation_name); + } else if (animation.animation_name == "blinds") + { + set_animation(ev->view, ANIMATION_TYPE_MAP, + animation.duration, animation.animation_name); } }; @@ -436,6 +441,10 @@ class wayfire_animation : public wf::plugin_interface_t, private wf::per_output_ { set_animation(ev->view, ANIMATION_TYPE_UNMAP, animation.duration, animation.animation_name); + } else if (animation.animation_name == "blinds") + { + set_animation(ev->view, ANIMATION_TYPE_UNMAP, + animation.duration, animation.animation_name); } }; diff --git a/plugins/animate/blinds.hpp b/plugins/animate/blinds.hpp new file mode 100644 index 000000000..b4a599fc9 --- /dev/null +++ b/plugins/animate/blinds.hpp @@ -0,0 +1,369 @@ +/* + * 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 "animate.hpp" + + +static std::string blinds_transformer_name = "animation-blinds"; + +wf::option_wrapper_t blinds_duration{"animate/blinds_duration"}; + +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::animation; +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) + { + 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 = 20; + std::vector uv; + std::vector vertices; + 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); + 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); + 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::translate(m, + glm::vec3(0.0f, (src_box.height / 2.0f - i - (y2 - y1) / 2.0f) * (2.0f / og.height), + 0.0f)); + 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 / og.width, 2.0f / og.height, 1.0)); + 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)); + glm::mat4 p = glm::perspective(float(M_PI / 4.0), 1.0f, 0.1f, 100.0f); + 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.)); + + auto 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(); + } + }; + + 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 = bbox; + 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 +{ + wayfire_view view; + + public: + void init(wayfire_view view, wf::animation_description_t dur, wf_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 & 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(); + } + } +}; +} +} From eedf27fc662cb9a631332cf4f2fd599d22506892 Mon Sep 17 00:00:00 2001 From: Scott Moreau Date: Wed, 31 Jul 2024 11:31:29 -0600 Subject: [PATCH 2/4] blinds: Fix perspective projection --- plugins/animate/blinds.hpp | 59 ++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/plugins/animate/blinds.hpp b/plugins/animate/blinds.hpp index b4a599fc9..e25aec83b 100644 --- a/plugins/animate/blinds.hpp +++ b/plugins/animate/blinds.hpp @@ -150,10 +150,10 @@ class blinds_transformer : public wf::scene::view_2d_transformer_t self->animation_geometry = og; int line_height = 20; - std::vector uv; - std::vector vertices; 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(0.0); @@ -170,23 +170,17 @@ class blinds_transformer : public wf::scene::view_2d_transformer_t uv.push_back(std::max(0, y - line_height) * inv_h); 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); 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::translate(m, - glm::vec3(0.0f, (src_box.height / 2.0f - i - (y2 - y1) / 2.0f) * (2.0f / og.height), - 0.0f)); 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 / og.width, 2.0f / og.height, 1.0)); + m = glm::scale(m, glm::vec3(2.0f / (src_box.width + line_height * 2), 2.0f / (y2 - y1), 1.0)); v = glm::vec4(x2, y2, 0.0, 1.0); r = m * v; vertices.push_back(r.x); @@ -217,35 +211,38 @@ class blinds_transformer : public wf::scene::view_2d_transformer_t 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)); - glm::mat4 p = glm::perspective(float(M_PI / 4.0), 1.0f, 0.1f, 100.0f); - 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.)); - - auto transform = t * p * l; - OpenGL::render_begin(target); - for (auto box : region) - { - target.logic_scissor(wlr_box_from_pixman_box(box)); + 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_TRIANGLES, 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{src_box.x - line_height, + src_box.y + i, + (src_box.x - line_height) + src_box.width + line_height * 2.0, + (src_box.y + i) + (y2 - y1)}, {}, + target.get_orthographic_projection(), glm::vec4(1.0), 0); + } + + OpenGL::render_end(); } - - OpenGL::render_end(); } }; @@ -258,7 +255,7 @@ class blinds_transformer : public wf::scene::view_2d_transformer_t output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE); } - animation_geometry = bbox; + animation_geometry = output->get_relative_geometry(); OpenGL::render_begin(); program.compile(blinds_vert_source, blinds_frag_source); OpenGL::render_end(); From 04403c07517abf1abbc3b04fbd033f2dd483042f Mon Sep 17 00:00:00 2001 From: Scott Moreau Date: Wed, 31 Jul 2024 12:19:16 -0600 Subject: [PATCH 3/4] blinds: Fix compiler warnings --- plugins/animate/blinds.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/animate/blinds.hpp b/plugins/animate/blinds.hpp index e25aec83b..e00793caf 100644 --- a/plugins/animate/blinds.hpp +++ b/plugins/animate/blinds.hpp @@ -125,7 +125,7 @@ class blinds_transformer : public wf::scene::view_2d_transformer_t void schedule_instructions( std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) + const wf::render_target_t& target, wf::region_t& damage) override { instructions.push_back(render_instruction_t{ .instance = this, @@ -140,7 +140,7 @@ class blinds_transformer : public wf::scene::view_2d_transformer_t } void render(const wf::render_target_t& target, - const wf::region_t& region) + 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( @@ -234,10 +234,10 @@ class blinds_transformer : public wf::scene::view_2d_transformer_t for (auto box : region) { target.logic_scissor(wlr_box_from_pixman_box(box)); - OpenGL::render_transformed_texture(slice.tex, gl_geometry{src_box.x - line_height, - src_box.y + i, - (src_box.x - line_height) + src_box.width + line_height * 2.0, - (src_box.y + i) + (y2 - y1)}, {}, + 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); } From 129a5cfe0a8709d6af31f6650d9116023cd9c118 Mon Sep 17 00:00:00 2001 From: Scott Moreau Date: Fri, 2 Aug 2024 02:47:01 -0600 Subject: [PATCH 4/4] blinds: Release resources from intermediate textures --- plugins/animate/blinds.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/animate/blinds.hpp b/plugins/animate/blinds.hpp index e00793caf..c9ffe1943 100644 --- a/plugins/animate/blinds.hpp +++ b/plugins/animate/blinds.hpp @@ -241,6 +241,7 @@ class blinds_transformer : public wf::scene::view_2d_transformer_t target.get_orthographic_projection(), glm::vec4(1.0), 0); } + slice.release(); OpenGL::render_end(); } }