Commit 3e8c9a65 authored by Martin Flöser's avatar Martin Flöser

Removing Snow Effect.

The usefulness of the snow effect is doubtable and it is rather
difficult to port the effect to the new rendering architecture
introduced with GLES. It is probably easier to rewrite the complete
effect from scratch, therefore it is removed for now.

I might consider readding it for 4.7.

This kind of "fixes" snow related bug reports.
BUG: 259362
BUG: 254498
FIXED-IN: 4.7.0
parent d0d15c4c
......@@ -106,9 +106,6 @@ if( KWIN_HAVE_OPENGL_COMPOSITING )
include( trackmouse/CMakeLists.txt )
include( wobblywindows/CMakeLists.txt )
endif( KWIN_HAVE_OPENGL_COMPOSITING )
if( KWIN_HAVE_OPENGL_COMPOSITING AND NOT KWIN_HAVE_OPENGLES_COMPOSITING )
include( snow/CMakeLists.txt )
endif( KWIN_HAVE_OPENGL_COMPOSITING AND NOT KWIN_HAVE_OPENGLES_COMPOSITING )
###############################################################################
......
......@@ -51,9 +51,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "mousemark/mousemark_config.h"
#include "trackmouse/trackmouse_config.h"
#include "wobblywindows/wobblywindows_config.h"
#ifndef KWIN_HAVE_OPENGLES
#include "snow/snow_config.h"
#endif
#endif
#include <kwineffects.h>
......@@ -92,9 +89,6 @@ KWIN_EFFECT_CONFIG_MULTIPLE( builtins,
KWIN_EFFECT_CONFIG_SINGLE( mousemark, MouseMarkEffectConfig )
KWIN_EFFECT_CONFIG_SINGLE( trackmouse, TrackMouseEffectConfig )
KWIN_EFFECT_CONFIG_SINGLE( wobblywindows, WobblyWindowsEffectConfig )
#ifndef KWIN_HAVE_OPENGLES
KWIN_EFFECT_CONFIG_SINGLE( snow, SnowEffectConfig )
#endif
#endif
)
......
#######################################
# Effect
# Source files
set( kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources}
snow/snow.cpp
)
# .desktop files
install( FILES
snow/snow.desktop
DESTINATION ${SERVICES_INSTALL_DIR}/kwin )
# Data files
install( FILES
snow/data/snow.frag
snow/data/snow.vert
snow/data/snowflake.png
DESTINATION ${DATA_INSTALL_DIR}/kwin )
#######################################
# Config
# Source files
set( kwin4_effect_builtins_config_sources ${kwin4_effect_builtins_config_sources}
snow/snow_config.cpp
snow/snow_config.ui
)
# .desktop files
install( FILES
snow/snow_config.desktop
DESTINATION ${SERVICES_INSTALL_DIR}/kwin )
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2008 Martin Gräßlin <ubuntu@martin-graesslin.com>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
uniform sampler2D snowTexture;
uniform int left;
uniform int right;
uniform int top;
uniform int bottom;
void main()
{
gl_FragColor = texture2D( snowTexture, gl_TexCoord[0].st );
// manual clipping
if( gl_FragCoord.x < float( left ) || gl_FragCoord.x > float( right )
|| gl_FragCoord.y < float( top ) || gl_FragCoord.y > float( bottom ) )
discard;
}
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2008 Martin Gräßlin <ubuntu@martin-graesslin.com>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
uniform float angle;
uniform int x;
uniform int width;
uniform int height;
varying float discarding;
uniform int hSpeed;
uniform int vSpeed;
uniform int frames;
void main()
{
gl_TexCoord[0] = gl_MultiTexCoord0;
float radian = radians( angle*float(frames) );
mat2 rotation = mat2( cos(radian), sin(radian), -sin(radian), cos(radian) );
float xCoord;
float yCoord;
if( gl_MultiTexCoord0.s == 0.0 )
xCoord = -float(width)*0.5;
else
xCoord = float(width)*0.5;
if( gl_MultiTexCoord0.t == 0.0 )
yCoord = -float(height)*0.5;
else
yCoord = float(height)*0.5;
vec2 vertex = vec2( xCoord, yCoord );
vertex = (vertex)*rotation + vec2( float(x), float(-height) ) + vec2(hSpeed, vSpeed)*float(frames);
gl_Position = gl_ModelViewProjectionMatrix * vec4(vertex, gl_Vertex.zw);
}
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2007 Martin Gräßlin <ubuntu@martin-graesslin.com>
Copyright (C) 2008 Torgny Johansson <torgny.johansson@gmail.com>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "snow.h"
#include <kwinconfig.h>
#include <kaction.h>
#include <kactioncollection.h>
#include <kconfiggroup.h>
#include <kglobal.h>
#include <klocale.h>
#include <kstandarddirs.h>
#include <kdebug.h>
#include <ctime>
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
#include <GL/gl.h>
#endif
namespace KWin
{
KWIN_EFFECT( snow, SnowEffect )
KWIN_EFFECT_SUPPORTED( snow, SnowEffect::supported() )
SnowEffect::SnowEffect()
: texture( NULL )
, active( false)
, snowBehindWindows( false )
, mShader( 0 )
, mInited( false )
, mUseShader( true )
, hasSnown( false )
{
srandom( std::time( NULL ) );
nextFlakeMillis = 0;
KActionCollection* actionCollection = new KActionCollection( this );
KAction* a = static_cast< KAction* >( actionCollection->addAction( "Snow" ));
a->setText( i18n("Snow" ));
a->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::META + Qt::Key_F12 ));
connect( a, SIGNAL( triggered( bool )), this, SLOT( toggle()));
reconfigure( ReconfigureAll );
}
SnowEffect::~SnowEffect()
{
delete texture;
if( active )
delete mShader;
}
bool SnowEffect::supported()
{
return effects->compositingType() == OpenGLCompositing;
}
void SnowEffect::reconfigure( ReconfigureFlags )
{
KConfigGroup conf = effects->effectConfig("Snow");
mNumberFlakes = conf.readEntry("Number", 200);
mMinFlakeSize = conf.readEntry("MinFlakes", 10);
mMaxFlakeSize = conf.readEntry("MaxFlakes", 50);
mMaxVSpeed = conf.readEntry("MaxVSpeed", 2);
mMaxHSpeed = conf.readEntry("MaxHSpeed", 1);
snowBehindWindows = conf.readEntry("BehindWindows", true);
}
void SnowEffect::prePaintScreen( ScreenPrePaintData& data, int time )
{
if ( active )
{
// if number of active snowflakes is smaller than maximum number
// create a random new snowflake
nextFlakeMillis -= time;
if ( ( nextFlakeMillis <= 0 ) && flakes.count() < mNumberFlakes)
{
int size = 0;
while ( size < mMinFlakeSize )
size = random() % mMaxFlakeSize;
SnowFlake flake = SnowFlake( random() % (displayWidth() - size), -size, size, size, mMaxVSpeed, mMaxHSpeed );
flakes.append( flake );
// calculation of next time of snowflake
// depends on the time the flow needs to get to the bottom (screen size)
// and the fps
long next = ((500/(time+5))*(Effect::displayHeight()/flake.getVSpeed()))/mNumberFlakes;
nextFlakeMillis = next;
}
data.mask |= PAINT_SCREEN_TRANSFORMED;
hasSnown = false;
}
effects->prePaintScreen( data, time );
}
void SnowEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
{
if( active && snowBehindWindows )
repaintRegion = QRegion( 0, 0, displayWidth(), displayHeight() );
effects->paintScreen( mask, region, data ); // paint normal screen
if( active && !snowBehindWindows )
snowing( region );
}
void SnowEffect::snowing( QRegion& region )
{
if(! texture ) loadTexture();
if( texture )
{
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 );
if( mUseShader )
{
mShader->bind();
QRect rect = region.boundingRect();
mShader->setUniform( "left", rect.x() );
mShader->setUniform( "right", rect.x() + rect.width() );
mShader->setUniform( "top", rect.y() );
mShader->setUniform( "bottom", rect.y() + rect.height() );
}
for (int i=0; i<flakes.count(); i++)
{
SnowFlake& flake = flakes[i];
if( !hasSnown )
{
// only update during first paint in one frame
if( flake.addFrame() == 0 )
{
flakes.removeAt( i-- );
continue;
}
}
if( mUseShader )
{
// use shader
mShader->setUniform( "angle", flake.getRotationSpeed() );
mShader->setUniform( "x", flake.getX() );
mShader->setUniform( "hSpeed", flake.getHSpeed() );
mShader->setUniform( "vSpeed", flake.getVSpeed() );
mShader->setUniform( "frames", flake.getFrames() );
mShader->setUniform( "width", flake.getWidth() );
mShader->setUniform( "height", flake.getHeight() );
glCallList( list );
}
else
{
if( !hasSnown )
{
// only update during first paint in one frame
flake.updateSpeedAndRotation();
}
// 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();
}
}
if( mUseShader )
{
mShader->unbind();
}
glDisable( GL_BLEND );
texture->unbind();
glPopAttrib();
hasSnown = true;
}
}
void SnowEffect::postPaintScreen()
{
if( active )
{
if( snowBehindWindows )
effects->addRepaint( repaintRegion );
else
effects->addRepaintFull();
}
effects->postPaintScreen();
}
void SnowEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
{
if( active && snowBehindWindows && !w->isDesktop() && !w->isDock() && !w->hasAlpha() && data.opacity == 1.0 )
{
repaintRegion -= QRegion( w->geometry() );
}
effects->paintWindow( w, mask, region, data );
if( active && w->isDesktop() && snowBehindWindows )
{
QRect rect = effects->clientArea( FullScreenArea, w->screen(), effects->currentDesktop());
QRegion snowRegion( rect.x() + data.xTranslate, rect.y() + data.yTranslate,
(double)rect.width()*data.xScale, (double)rect.height()*data.yScale);
if( mUseShader )
{
// have to adjust the y values to fit OpenGL
// in OpenGL y==0 is at bottom, in Qt at top
int y = 0;
if( effects->numScreens() > 1 )
{
QRect fullArea = effects->clientArea( FullArea, 0, 1 );
if( fullArea.height() != rect.height() )
{
if( rect.y() == 0 )
y = fullArea.height() - rect.height();
else
y = fullArea.height() - rect.y() - rect.height();
}
}
snowRegion = QRegion( rect.x() + data.xTranslate,
y + rect.height() - data.yTranslate - (double)rect.height()*data.yScale,
(double)rect.width()*data.xScale, (double)rect.height()*data.yScale);
}
glPushMatrix();
glTranslatef( rect.x() + data.xTranslate, rect.y() + data.yTranslate, 0.0 );
glScalef( data.xScale, data.yScale, 1.0 );
snowing( snowRegion );
glPopMatrix();
}
}
void SnowEffect::toggle()
{
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
active = !active;
if( active )
{
list = glGenLists(1);
}
else
{
glDeleteLists( list, 1 );
flakes.clear();
if( mUseShader )
{
delete mShader;
mShader = NULL;
mInited = false;
mUseShader = true;
}
}
effects->addRepaintFull();
#endif
}
bool SnowEffect::loadShader()
{
mInited = true;
if( !(GLShader::fragmentShaderSupported() &&
(effects->compositingType() == OpenGLCompositing)) )
{
kDebug(1212) << "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(1212) << "Couldn't locate shader files" << endl;
return false;
}
mShader = new GLShader(vertexshader, fragmentshader);
if(!mShader->isValid())
{
kDebug(1212) << "The shader failed to load!" << endl;
return false;
}
else
{
mShader->bind();
mShader->setUniform( "snowTexture", 0 );
mShader->unbind();
}
kDebug(1212) << "using shader";
glNewList( list, GL_COMPILE );
glBegin( GL_QUADS );
glTexCoord2f( 0.0f, 0.0f );
glVertex2i( 0, 0 );
glTexCoord2f( 1.0f, 0.0f );
glVertex2i( 0, 0 );
glTexCoord2f( 1.0f, 1.0f );
glVertex2i( 0, 0 );
glTexCoord2f( 0.0f, 1.0f );
glVertex2i( 0, 0 );
glEnd();
glEndList();
return true;
}
void SnowEffect::loadTexture()
{
QString file = KGlobal::dirs()->findResource( "appdata", "snowflake.png" );
if( file.isEmpty())
return;
texture = new GLTexture( file );
}
// the snowflake class
SnowFlake::SnowFlake(int x, int y, int width, int height, int maxVSpeed, int maxHSpeed)
{
int minVSpeed = maxVSpeed - 8; // 8 gives a nice difference in speed
if(minVSpeed < 1) minVSpeed = 1;
vSpeed = random()%maxVSpeed + minVSpeed;
hSpeed = random()%(maxHSpeed+1);
if(random()%2 < 1) hSpeed = -hSpeed; // to create negative hSpeeds at random
rotationAngle = 0;
rotationSpeed = random()%4 - 2;
if(rotationSpeed == 0) rotationSpeed = 0.5;
rect = QRect(x, y, width, height);
frameCounter = 0;
maxFrames = (displayHeight() + 2*height) / vSpeed;
if( hSpeed > 0 )
maxFrames = qMin( maxFrames, (displayWidth() + width - x)/hSpeed );
else if( hSpeed < 0 )
maxFrames = qMin( maxFrames, (x + width)/(-hSpeed) );
}
SnowFlake::~SnowFlake()
{
}
int SnowFlake::getHSpeed()
{
return hSpeed;
}
QRect SnowFlake::getRect()
{
return rect;
}
void SnowFlake::updateSpeedAndRotation()
{
rotationAngle = rotationAngle+rotationSpeed;
rect.translate(hSpeed, vSpeed);
}
float SnowFlake::getRotationAngle()
{
return rotationAngle;
}
float SnowFlake::getRotationSpeed()
{
return rotationSpeed;
}
int SnowFlake::getVSpeed()
{
return vSpeed;
}
int SnowFlake::getHeight()
{
return rect.height();
}
int SnowFlake::getWidth()
{
return rect.width();
}
int SnowFlake::getX()
{
return rect.x();
}
int SnowFlake::getY()
{
return rect.y();
}
void SnowFlake::setHeight(int height)
{
rect.setHeight(height);
}
void SnowFlake::setWidth(int width)
{
rect.setWidth(width);
}
void SnowFlake::setX(int x)
{
rect.setX(x);
}
void SnowFlake::setY(int y)
{
rect.setY(y);
}
int SnowFlake::addFrame()
{
return ( maxFrames - (++frameCounter) );
}
int SnowFlake::getFrames()
{
return frameCounter;
}
} // namespace
[Desktop Entry]
# Name of the effect
Name=Snow
Name[af]=Sneeu
Name[ar]=الثلج
Name[ast]=Ñeve
Name[be@latin]=Śnieh
Name[bg]=Сняг
Name[bn]=বরফ
Name[bn_IN]=Snow (তুষার)
Name[ca]=Neu
Name[ca@valencia]=Neu