From 9a52d3c70918c82c7e5dc83a033436a45ea871f9 Mon Sep 17 00:00:00 2001 From: Lucas Murray Date: Wed, 27 Aug 2008 12:20:34 +0000 Subject: [PATCH] Added feature to only invert the colours of selected windows Fixed shader alpha blending CCMAIL: kwin@kde.org svn path=/trunk/KDE/kdebase/workspace/; revision=853224 --- effects/data/invert.frag | 23 ++++++--- effects/data/invert.vert | 2 +- effects/invert.cpp | 106 +++++++++++++++++++++++++++++++++++--- effects/invert.desktop | 6 +-- effects/invert.h | 23 ++++++++- effects/invert_config.cpp | 6 +++ scene_opengl.cpp | 2 +- 7 files changed, 147 insertions(+), 21 deletions(-) diff --git a/effects/data/invert.frag b/effects/data/invert.frag index 4e124fd31c..456c5414ff 100644 --- a/effects/data/invert.frag +++ b/effects/data/invert.frag @@ -1,18 +1,27 @@ -uniform sampler2D sceneTex; +uniform sampler2D winTexture; uniform float textureWidth; uniform float textureHeight; - +uniform float opacity; +uniform float brightness; +uniform float saturation; // Converts pixel coordinates to texture coordinates -vec2 pix2tex(vec2 pix) +vec2 pix2tex( vec2 pix ) { - return vec2(pix.x / textureWidth, 1.0 - pix.y / textureHeight); + return vec2( pix.s / textureWidth, pix.t / textureHeight ); } void main() { - vec3 tex = texture2D(sceneTex, pix2tex(gl_TexCoord[0].xy)).rgb; + vec4 tex = texture2D( winTexture, pix2tex( gl_TexCoord[0].st )); + tex = vec4( vec3( 1.0 ) - tex.rgb, tex.a * opacity ); + if( saturation != 1.0 ) + { + vec3 desaturated = tex.rgb * vec3( 0.30, 0.59, 0.11 ); + desaturated = vec3( dot( desaturated, tex.rgb )); + tex.rgb = tex.rgb * vec3( saturation ) + desaturated * vec3( 1.0 - saturation ); + } + tex.rgb = tex.rgb * vec3( brightness ); - gl_FragColor = vec4(vec3(1.0) - tex, 1.0); + gl_FragColor = tex; } - diff --git a/effects/data/invert.vert b/effects/data/invert.vert index 066ac6c2aa..5ebf5d174b 100644 --- a/effects/data/invert.vert +++ b/effects/data/invert.vert @@ -1,6 +1,6 @@ void main() { - gl_TexCoord[0].xy = gl_Vertex.xy; + gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = ftransform(); } diff --git a/effects/invert.cpp b/effects/invert.cpp index a19a4246a5..5ffc8ccbf3 100644 --- a/effects/invert.cpp +++ b/effects/invert.cpp @@ -3,6 +3,7 @@ This file is part of the KDE project. Copyright (C) 2007 Rivo Laks +Copyright (C) 2008 Lucas Murray This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,10 +21,13 @@ along with this program. If not, see . #include "invert.h" +#include #include #include #include - +#include +#include +#include namespace KWin { @@ -31,19 +35,107 @@ namespace KWin KWIN_EFFECT( invert, InvertEffect ) KWIN_EFFECT_SUPPORTED( invert, ShaderEffect::supported() ) - -InvertEffect::InvertEffect() : QObject(), ShaderEffect("invert") +InvertEffect::InvertEffect() + : m_inited( false ), + m_valid( true ), + m_shader( NULL ), + m_allWindows( false ) { KActionCollection* actionCollection = new KActionCollection( this ); + KAction* a = (KAction*)actionCollection->addAction( "Invert" ); - a->setText( i18n("Toggle Invert Effect" )); - a->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::META + Qt::Key_I)); - connect(a, SIGNAL(triggered(bool)), this, SLOT(toggle())); + a->setText( i18n( "Toggle Invert Effect" )); + a->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::META + Qt::Key_I )); + connect(a, SIGNAL( triggered(bool) ), this, SLOT( toggle() )); + + KAction* b = (KAction*)actionCollection->addAction( "InvertWindow" ); + b->setText( i18n( "Toggle Invert Effect On Window" )); + b->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::META + Qt::Key_U )); + connect(b, SIGNAL( triggered(bool) ), this, SLOT( toggleWindow() )); + } + +InvertEffect::~InvertEffect() + { + delete m_shader; + } + +bool InvertEffect::loadData() +{ + m_inited = true; + + QString fragmentshader = KGlobal::dirs()->findResource("data", "kwin/invert.frag"); + QString vertexshader = KGlobal::dirs()->findResource("data", "kwin/invert.vert"); + if(fragmentshader.isEmpty() || vertexshader.isEmpty()) + { + kError(1212) << "Couldn't locate shader files" << endl; + return false; + } + + m_shader = new GLShader(vertexshader, fragmentshader); + if( !m_shader->isValid() ) + { + kError(1212) << "The shader failed to load!" << endl; + return false; + } + else + { + m_shader->bind(); + m_shader->setUniform("winTexture", 0); + m_shader->unbind(); + } + + return true; + } + +void InvertEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) + { + // Load if we haven't already + if( m_valid && !m_inited ) + m_valid = loadData(); + + bool useShader = m_valid && ( m_allWindows != m_windows.contains( w )); + if( useShader ) + { + m_shader->bind(); + + int texw = w->width(); + int texh = w->height(); + if( !GLTexture::NPOTTextureSupported() ) + { + kWarning( 1212 ) << "NPOT textures not supported, wasting some memory" ; + texw = nearestPowerOfTwo(texw); + texh = nearestPowerOfTwo(texh); + } + m_shader->setUniform("textureWidth", (float)texw); + m_shader->setUniform("textureHeight", (float)texh); + + data.shader = m_shader; + } + + effects->paintWindow( w, mask, region, data ); + + if( useShader ) + m_shader->unbind(); + } + +void InvertEffect::windowClosed( EffectWindow* w ) + { + m_windows.removeOne( w ); } void InvertEffect::toggle() { - setEnabled( !isEnabled()); + m_allWindows = !m_allWindows; + effects->addRepaintFull(); + } + +void InvertEffect::toggleWindow() + { + if( !m_windows.contains( effects->activeWindow() )) + m_windows.append( effects->activeWindow() ); + else + m_windows.removeOne( effects->activeWindow() ); + effects->activeWindow()->addRepaintFull(); } } // namespace diff --git a/effects/invert.desktop b/effects/invert.desktop index fcf4cfb795..ad57322095 100644 --- a/effects/invert.desktop +++ b/effects/invert.desktop @@ -116,10 +116,10 @@ Icon=preferences-system-windows-effect-invert Type=Service X-KDE-ServiceTypes=KWin/Effect -X-KDE-PluginInfo-Author=Rivo Laks -X-KDE-PluginInfo-Email=rivolaks@hot.ee +X-KDE-PluginInfo-Author=Rivo Laks & Lucas Murray +X-KDE-PluginInfo-Email=rivolaks@hot.ee & lmurray@undefinedfire.com X-KDE-PluginInfo-Name=kwin4_effect_invert -X-KDE-PluginInfo-Version=0.1.0 +X-KDE-PluginInfo-Version=0.2.0 X-KDE-PluginInfo-Category=Accessibility X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL diff --git a/effects/invert.h b/effects/invert.h index 2c5504ba2a..3d89540215 100644 --- a/effects/invert.h +++ b/effects/invert.h @@ -3,6 +3,7 @@ This file is part of the KDE project. Copyright (C) 2007 Rivo Laks +Copyright (C) 2008 Lucas Murray This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,22 +22,40 @@ along with this program. If not, see . #ifndef KWIN_INVERT_H #define KWIN_INVERT_H -#include +#include namespace KWin { +class GLShader; + /** * Inverts desktop's colors **/ -class InvertEffect : public QObject, public ShaderEffect +class InvertEffect + : public QObject, public Effect { Q_OBJECT public: InvertEffect(); + ~InvertEffect(); + + virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); + virtual void windowClosed( EffectWindow* w ); public slots: void toggle(); + void toggleWindow(); + + protected: + bool loadData(); + + private: + bool m_inited; + bool m_valid; + GLShader* m_shader; + bool m_allWindows; + QList m_windows; }; } // namespace diff --git a/effects/invert_config.cpp b/effects/invert_config.cpp index b2110983e6..21c755dd58 100644 --- a/effects/invert_config.cpp +++ b/effects/invert_config.cpp @@ -42,11 +42,17 @@ InvertEffectConfig::InvertEffectConfig(QWidget* parent, const QVariantList& args QVBoxLayout* layout = new QVBoxLayout(this); KActionCollection* actionCollection = new KActionCollection( this, componentData() ); + KAction* a = static_cast(actionCollection->addAction( "Invert" )); a->setText( i18n("Toggle Invert Effect" )); a->setProperty("isConfigurationAction", true); a->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::META + Qt::Key_I)); + KAction* b = static_cast(actionCollection->addAction( "InvertWindow" )); + b->setText( i18n("Toggle Invert Effect On Window" )); + b->setProperty("isConfigurationAction", true); + b->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::META + Qt::Key_U)); + mShortcutEditor = new KShortcutsEditor(actionCollection, this, KShortcutsEditor::GlobalAction, KShortcutsEditor::LetterShortcutsDisallowed); connect(mShortcutEditor, SIGNAL(keyChange()), this, SLOT(changed())); diff --git a/scene_opengl.cpp b/scene_opengl.cpp index e9424fd34c..aa31b1bd31 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -1365,7 +1365,7 @@ void SceneOpenGL::Window::prepareShaderRenderStates( double opacity, double brig if( !opaque ) { glEnable( GL_BLEND ); - glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); // TODO: GL_ONE like below? + glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA ); } shader->setUniform("opacity", (float)opacity); shader->setUniform("saturation", (float)saturation);