1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 2008 Martin Gräßlin <ubuntu@martin-graesslin.com>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
24 #include <KStandardDirs>
33 KWIN_EFFECT( cylinder
, CylinderEffect
)
34 KWIN_EFFECT_SUPPORTED( cylinder
, CylinderEffect::supported() )
36 CylinderEffect::CylinderEffect()
44 reconfigure( ReconfigureAll
);
47 CylinderEffect::~CylinderEffect()
52 void CylinderEffect::reconfigure( ReconfigureFlags
)
54 loadConfig( "Cylinder" );
55 animateDesktopChange
= false;
59 bool CylinderEffect::supported()
61 return GLShader::fragmentShaderSupported() &&
62 (effects
->compositingType() == OpenGLCompositing
);
65 bool CylinderEffect::loadData()
68 QString fragmentshader
= KGlobal::dirs()->findResource("data", "kwin/cylinder.frag");
69 QString vertexshader
= KGlobal::dirs()->findResource("data", "kwin/cylinder.vert");
70 if(fragmentshader
.isEmpty() || vertexshader
.isEmpty())
72 kError(1212) << "Couldn't locate shader files" << endl
;
76 mShader
= new GLShader(vertexshader
, fragmentshader
);
77 if(!mShader
->isValid())
79 kError(1212) << "The shader failed to load!" << endl
;
85 mShader
->setUniform( "winTexture", 0 );
86 mShader
->setUniform( "opacity", cubeOpacity
);
87 QRect rect
= effects
->clientArea( FullScreenArea
, activeScreen
, effects
->currentDesktop());
88 if( effects
->numScreens() > 1 && (slide
|| bigCube
) )
89 rect
= effects
->clientArea( FullArea
, activeScreen
, effects
->currentDesktop() );
90 mShader
->setUniform( "width", (float)rect
.width() );
96 void CylinderEffect::paintScene( int mask
, QRegion region
, ScreenPaintData
& data
)
99 QRect rect
= effects
->clientArea( FullArea
, activeScreen
, effects
->currentDesktop());
101 float cubeAngle
= (effects
->numberOfDesktops() - 2 )/(float)effects
->numberOfDesktops() * 180.0f
;
102 float radian
= (cubeAngle
*0.5)*M_PI
/180;
103 // height of the triangle compound of one side of the cube and the two bisecting lines
104 float midpoint
= rect
.width()*0.5*tan(radian
);
105 // radius of the circle
106 float radius
= (rect
.width()*0.5)/cos(radian
);
107 glTranslatef( 0.0, 0.0, midpoint
- radius
);
108 CubeEffect::paintScene( mask
, region
, data
);
112 void CylinderEffect::prePaintWindow( EffectWindow
* w
, WindowPrePaintData
& data
, int time
)
118 if( w
->isOnDesktop( painting_desktop
))
120 data
.quads
= data
.quads
.makeGrid( 40 );
121 QRect rect
= effects
->clientArea( FullArea
, activeScreen
, painting_desktop
);
122 if( w
->x() < rect
.width()/2 && w
->x() + w
->width() > rect
.width()/ 2 )
123 data
.quads
= data
.quads
.splitAtX( rect
.width()/2 - w
->x() );
124 w
->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP
);
128 w
->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP
);
132 effects
->prePaintWindow( w
, data
, time
);
135 void CylinderEffect::paintWindow( EffectWindow
* w
, int mask
, QRegion region
, WindowPaintData
& data
)
137 if( activated
&& cube_painting
)
139 if( mValid
&& !mInited
)
141 bool useShader
= mValid
;
145 mShader
->setUniform( "windowWidth", (float)w
->width() );
146 mShader
->setUniform( "windowHeight", (float)w
->height() );
147 mShader
->setUniform( "xCoord", (float)w
->x() );
148 mShader
->setUniform( "cubeAngle", (effects
->numberOfDesktops() - 2 )/(float)effects
->numberOfDesktops() * 180.0f
);
149 data
.shader
= mShader
;
151 CubeEffect::paintWindow( w
, mask
, region
, data
);
158 effects
->paintWindow( w
, mask
, region
, data
);
161 void CylinderEffect::desktopChanged( int old
)
163 // cylinder effect is not useful to slide
166 void CylinderEffect::paintCap( float z
, float zTexture
)
168 if( ( !paintCaps
) || effects
->numberOfDesktops() <= 2 )
170 CubeEffect::paintCap( z
, zTexture
);
171 QRect rect
= effects
->clientArea( FullArea
, activeScreen
, painting_desktop
);
173 float cubeAngle
= (effects
->numberOfDesktops() - 2 )/(float)effects
->numberOfDesktops() * 180.0f
;
174 float radian
= (cubeAngle
*0.5)*M_PI
/180;
175 // height of the triangle compound of one side of the cube and the two bisecting lines
176 float midpoint
= rect
.width()*0.5*tan(radian
);
177 // radius of the circle
178 float radius
= (rect
.width()*0.5)/cos(radian
);
180 // paint round part of the cap
182 float zTranslate
= zPosition
+ zoom
;
184 zTranslate
*= timeLine
.value();
186 zTranslate
*= ( 1.0 - timeLine
.value() );
187 glTranslatef( 0.0, 0.0, -zTranslate
);
188 float triangleWidth
= 40.0;
190 for( int i
=0; i
<effects
->numberOfDesktops(); i
++ )
193 glTranslatef( rect
.width()/2, 0.0, -z
);
194 glRotatef( i
*(360.0f
/effects
->numberOfDesktops()), 0.0, 1.0, 0.0 );
195 glTranslatef( -rect
.width()/2, 0.0, z
);
196 glBegin( GL_TRIANGLE_STRIP
);
197 for( int j
=0; j
<rect
.width()/triangleWidth
; j
++ )
200 // distance from midpoint of desktop to x coord
201 // calculation is same as in shader -> see comments
202 float distance
= rect
.width()*0.5 - (j
*triangleWidth
);
203 if( (j
*triangleWidth
) > rect
.width()*0.5 )
205 distance
= (j
*triangleWidth
) - rect
.width()*0.5;
207 // distance in correct format
208 float angle
= acos( distance
/radius
);
210 // if distance == 0 -> angle=90 -> tan(90) singularity
211 if( distance
!= 0.0 )
212 h
= tan( angle
) * distance
;
213 zValue
= h
- midpoint
;
214 glVertex3f( j
*triangleWidth
, 0.0, zValue
);
215 glVertex3f( (j
+1)*triangleWidth
, 0.0, 0.0 );