1 #include <wayfire/plugin.hpp> 2 #include <wayfire/output.hpp> 3 #include <wayfire/opengl.hpp> 4 #include <wayfire/render-manager.hpp> 5 6 static const char *vertex_shader = 7 R"( 8 #version 100 9 10 attribute mediump vec2 position; 11 attribute highp vec2 uvPosition; 12 13 varying highp vec2 uvpos; 14 15 void main() { 16 17 gl_Position = vec4(position.xy, 0.0, 1.0); 18 uvpos = uvPosition; 19 } 20 )"; 21 22 static const char *fragment_shader = 23 R"( 24 #version 100 25 26 varying highp vec2 uvpos; 27 uniform sampler2D smp; 28 uniform bool preserve_hue; 29 30 void main() 31 { 32 mediump vec4 tex = texture2D(smp, uvpos); 33 34 if (preserve_hue) 35 { 36 mediump float hue = tex.a - min(tex.r, min(tex.g, tex.b)) - max(tex.r, max(tex.g, tex.b)); 37 gl_FragColor = hue + tex; 38 } else 39 { 40 gl_FragColor = vec4(1.0 - tex.r, 1.0 - tex.g, 1.0 - tex.b, 1.0); 41 } 42 } 43 )"; 44 45 class wayfire_invert_screen : public wf::plugin_interface_t 46 { 47 wf::post_hook_t hook; 48 wf::activator_callback toggle_cb; 49 wf::option_wrapper_t<bool> preserve_hue{"invert/preserve_hue"}; 50 51 bool active = false; 52 OpenGL::program_t program; 53 54 public: init()55 void init() override 56 { 57 wf::option_wrapper_t<wf::activatorbinding_t> toggle_key{"invert/toggle"}; 58 59 grab_interface->name = "invert"; 60 grab_interface->capabilities = 0; 61 62 hook = [=] (const wf::framebuffer_base_t& source, 63 const wf::framebuffer_base_t& destination) 64 { 65 render(source, destination); 66 }; 67 68 toggle_cb = [=] (auto) 69 { 70 if (!output->can_activate_plugin(grab_interface)) 71 { 72 return false; 73 } 74 75 if (active) 76 { 77 output->render->rem_post(&hook); 78 } else 79 { 80 output->render->add_post(&hook); 81 } 82 83 active = !active; 84 85 return true; 86 }; 87 88 OpenGL::render_begin(); 89 program.set_simple( 90 OpenGL::compile_program(vertex_shader, fragment_shader)); 91 OpenGL::render_end(); 92 93 output->add_activator(toggle_key, &toggle_cb); 94 } 95 render(const wf::framebuffer_base_t & source,const wf::framebuffer_base_t & destination)96 void render(const wf::framebuffer_base_t& source, 97 const wf::framebuffer_base_t& destination) 98 { 99 static const float vertexData[] = { 100 -1.0f, -1.0f, 101 1.0f, -1.0f, 102 1.0f, 1.0f, 103 -1.0f, 1.0f 104 }; 105 106 static const float coordData[] = { 107 0.0f, 0.0f, 108 1.0f, 0.0f, 109 1.0f, 1.0f, 110 0.0f, 1.0f 111 }; 112 113 OpenGL::render_begin(destination); 114 115 program.use(wf::TEXTURE_TYPE_RGBA); 116 GL_CALL(glBindTexture(GL_TEXTURE_2D, source.tex)); 117 GL_CALL(glActiveTexture(GL_TEXTURE0)); 118 119 program.attrib_pointer("position", 2, 0, vertexData); 120 program.attrib_pointer("uvPosition", 2, 0, coordData); 121 program.uniform1i("preserve_hue", preserve_hue); 122 123 GL_CALL(glDisable(GL_BLEND)); 124 GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4)); 125 GL_CALL(glEnable(GL_BLEND)); 126 GL_CALL(glBindTexture(GL_TEXTURE_2D, 0)); 127 128 program.deactivate(); 129 OpenGL::render_end(); 130 } 131 fini()132 void fini() override 133 { 134 if (active) 135 { 136 output->render->rem_post(&hook); 137 } 138 139 OpenGL::render_begin(); 140 program.free_resources(); 141 OpenGL::render_end(); 142 143 output->rem_binding(&toggle_cb); 144 } 145 }; 146 147 DECLARE_WAYFIRE_PLUGIN(wayfire_invert_screen); 148