diff --git a/effects/CMakeLists.txt b/effects/CMakeLists.txt index d76b5a4ef6..583bce8234 100644 --- a/effects/CMakeLists.txt +++ b/effects/CMakeLists.txt @@ -166,6 +166,8 @@ if(KWIN_HAVE_OPENGL_COMPOSITING) data/lookingglass.frag data/lookingglass.vert data/shadow-texture.png + data/snow.frag + data/snow.vert data/snowflake.png data/circle.png data/circle-edgy.png diff --git a/effects/data/snow.frag b/effects/data/snow.frag new file mode 100644 index 0000000000..d7b23ddc5e --- /dev/null +++ b/effects/data/snow.frag @@ -0,0 +1,25 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + + Copyright (C) 2008 Martin Gräßlin + +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 +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +uniform sampler2D snowTexture; + +void main() +{ + gl_FragColor = texture2D( snowTexture, gl_TexCoord[0].st ); +} diff --git a/effects/data/snow.vert b/effects/data/snow.vert new file mode 100644 index 0000000000..a2b0551960 --- /dev/null +++ b/effects/data/snow.vert @@ -0,0 +1,31 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + + Copyright (C) 2008 Martin Gräßlin + +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 +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +attribute float angle; +attribute float x; +attribute float y; + +void main() +{ + float radian = radians(angle); + mat2 rotation = mat2( cos(radian), sin(radian), -sin(radian), cos(radian) ); + vec2 vertex = (gl_Vertex.xy-vec2(x, y))*rotation+vec2(x, y); + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = gl_ModelViewProjectionMatrix * vec4(vertex, gl_Vertex.zw); +} diff --git a/effects/snow.cpp b/effects/snow.cpp index fe9b01f8a2..68455b5083 100644 --- a/effects/snow.cpp +++ b/effects/snow.cpp @@ -50,6 +50,9 @@ SnowEffect::SnowEffect() , flakes( NULL ) , active( false) , snowBehindWindows( false ) + , mShader( 0 ) + , mInited( false ) + , mUseShader( true ) { srandom( std::time( NULL ) ); lastFlakeTime = QTime::currentTime(); @@ -66,6 +69,7 @@ SnowEffect::~SnowEffect() { delete texture; delete flakes; + delete mShader; } void SnowEffect::reconfigure( ReconfigureFlags ) @@ -145,35 +149,73 @@ void SnowEffect::snowing( QRegion& region ) if(! texture ) loadTexture(); if( texture ) { - glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT ); + glActiveTexture(GL_TEXTURE0); texture->bind(); + if( mUseShader && !mInited ) + mUseShader = loadShader(); + glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - glNewList( list, GL_COMPILE_AND_EXECUTE ); + if( mUseShader ) + { + mShader->bind(); + glNewList( list, GL_COMPILE_AND_EXECUTE ); + glBegin( GL_QUADS ); + } + else + glNewList( list, GL_COMPILE_AND_EXECUTE ); for (int i=0; icount(); i++) { SnowFlake flake = flakes->at(i); - - // save the matrix - glPushMatrix(); - - // translate to the center of the flake - glTranslatef(flake.getWidth()/2 + flake.getX(), flake.getHeight()/2 + flake.getY(), 0); - - // rotate around the Z-axis - glRotatef(flake.getRotationAngle(), 0.0, 0.0, 1.0); - - // translate back to the starting point - glTranslatef(-flake.getWidth()/2 - flake.getX(), -flake.getHeight()/2 - flake.getY(), 0); - - // paint the snowflake - texture->render( region, flake.getRect()); - - // restore the matrix - glPopMatrix(); + if( snowBehindWindows && !region.contains( flake.getRect() ) ) + continue; + + if( mUseShader ) + { + // use shader + mShader->setAttribute( "angle", flake.getRotationAngle() ); + mShader->setAttribute( "x", flake.getWidth()/2 + flake.getX() ); + mShader->setAttribute( "y", flake.getHeight()/2 + flake.getY() ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex2i( flake.getRect().x(), flake.getRect().y() ); + glTexCoord2f( 1.0f, 0.0f ); + glVertex2i( flake.getRect().x()+flake.getRect().width(), flake.getRect().y() ); + glTexCoord2f( 1.0f, 1.0f ); + glVertex2i( flake.getRect().x()+flake.getRect().width(), flake.getRect().y()+flake.getRect().height() ); + glTexCoord2f( 0.0f, 1.0f ); + glVertex2i( flake.getRect().x(), flake.getRect().y()+flake.getRect().height() ); + } + else + { + // no shader + // save the matrix + glPushMatrix(); + + // translate to the center of the flake + glTranslatef(flake.getWidth()/2 + flake.getX(), flake.getHeight()/2 + flake.getY(), 0); + + // rotate around the Z-axis + glRotatef(flake.getRotationAngle(), 0.0, 0.0, 1.0); + + // translate back to the starting point + glTranslatef(-flake.getWidth()/2 - flake.getX(), -flake.getHeight()/2 - flake.getY(), 0); + + // paint the snowflake + texture->render( region, flake.getRect()); + + // restore the matrix + glPopMatrix(); + } } - glEndList(); + if( mUseShader ) + { + glEnd(); + glEndList(); + mShader->unbind(); + } + else + glEndList(); glDisable( GL_BLEND ); texture->unbind(); glPopAttrib(); @@ -212,6 +254,39 @@ void SnowEffect::toggle() effects->addRepaintFull(); } +bool SnowEffect::loadShader() + { + mInited = true; + if( !(GLShader::fragmentShaderSupported() && + (effects->compositingType() == OpenGLCompositing)) ) + { + kDebug() << "Shaders not supported - waisting CPU cycles" << endl; + return false; + } + QString fragmentshader = KGlobal::dirs()->findResource("data", "kwin/snow.frag"); + QString vertexshader = KGlobal::dirs()->findResource("data", "kwin/snow.vert"); + if(fragmentshader.isEmpty() || vertexshader.isEmpty()) + { + kDebug() << "Couldn't locate shader files" << endl; + return false; + } + + mShader = new GLShader(vertexshader, fragmentshader); + if(!mShader->isValid()) + { + kDebug() << "The shader failed to load!" << endl; + return false; + } + else + { + mShader->bind(); + mShader->setUniform( "snowTexture", 0 ); + mShader->unbind(); + } + kDebug() << "using shader"; + return true; + } + void SnowEffect::loadTexture() { #ifdef KWIN_HAVE_OPENGL_COMPOSITING diff --git a/effects/snow.h b/effects/snow.h index 2331e819c8..f8ecbc7216 100644 --- a/effects/snow.h +++ b/effects/snow.h @@ -78,6 +78,7 @@ class SnowEffect private: void loadTexture(); void snowing( QRegion& region ); + bool loadShader(); GLTexture* texture; QList* flakes; QTime lastFlakeTime; @@ -90,6 +91,9 @@ class SnowEffect bool active; GLuint list; bool snowBehindWindows; + GLShader* mShader; + bool mInited; + bool mUseShader; }; } // namespace