/******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2009 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 . Based on Compiz Fusion cube gear plugin by Dennis Kasprzyk: http://gitweb.compiz-fusion.org/?p=fusion/plugins/gears;a=blob;f=gears.c;hb=HEAD Which is based on glxgears.c by Brian Paul: http://cvsweb.xfree86.org/cvsweb/xc/programs/glxgears/glxgears.c *********************************************************************/ #include "gears.h" #include "../cube/cube_proxy.h" #include #include namespace KWin { KWIN_EFFECT( gears, GearsEffect ) KWIN_EFFECT_SUPPORTED( gears, GearsEffect::supported() ) GearsEffect::GearsEffect() : CubeInsideEffect() , m_active( false ) , m_contentRotation( 0.0f ) , m_angle( 0.0f ) { CubeEffectProxy* proxy = static_cast( effects->getProxy( "cube" ) ); if( proxy ) proxy->registerCubeInsideEffect( this ); } GearsEffect::~GearsEffect() { CubeEffectProxy* proxy = static_cast( effects->getProxy( "cube" ) ); if( proxy ) proxy->unregisterCubeInsideEffect( this ); } bool GearsEffect::supported() { return effects->compositingType() == OpenGLCompositing; } void GearsEffect::prePaintScreen( ScreenPrePaintData& data, int time ) { if( m_active ) { m_contentRotation += time * 360.0f / 20000.0f; if( m_contentRotation > 360.0f ) m_contentRotation -= 360.0f; m_angle += time * 360.0f / 8000.0f; if( m_angle > 360.0f ) m_angle -= 360.0f; } effects->prePaintScreen( data, time ); } void GearsEffect::postPaintScreen() { if( m_active ) { effects->addRepaintFull(); } effects->postPaintScreen(); } void GearsEffect::paint() { if( m_active ) { paintGears(); } } void GearsEffect::setActive( bool active ) { m_active = active; if( active ) initGears(); else endGears(); } void GearsEffect::gear( float inner_radius, float outer_radius, float width, int teeth, float tooth_depth ) { GLint i; GLfloat r0, r1, r2, maxr2, minr2; GLfloat angle, da; GLfloat u, v, len; r0 = inner_radius; r1 = outer_radius - tooth_depth / 2.0; maxr2 = r2 = outer_radius + tooth_depth / 2.0; minr2 = r2; da = 2.0 * M_PI / teeth / 4.0; glShadeModel( GL_FLAT ); glNormal3f( 0.0, 0.0, 1.0 ); /* draw front face */ glBegin( GL_QUAD_STRIP ); for( i = 0; i <= teeth; ++i ) { angle = i * 2.0 * M_PI / teeth; glVertex3f( r0 * cos( angle ), r0 * sin( angle ), width * 0.5 ); glVertex3f( r1 * cos( angle ), r1 * sin( angle ), width * 0.5 ); if( i < teeth ) { glVertex3f( r0 * cos( angle ), r0 * sin( angle ), width * 0.5 ); glVertex3f( r1 * cos( angle + 3 * da ), r1 * sin( angle + 3 * da ), width * 0.5 ); } } glEnd(); /* draw front sides of teeth */ glBegin( GL_QUADS ); for( i = 0; i < teeth; ++i ) { angle = i * 2.0 * M_PI / teeth; glVertex3f( r1 * cos( angle ), r1 * sin( angle ), width * 0.5 ); glVertex3f( r2 * cos( angle + da ), r2 * sin( angle + da ), width * 0.5 ); glVertex3f( r2 * cos( angle + 2 * da ), r2 * sin( angle + 2 * da ), width * 0.5 ); glVertex3f( r1 * cos( angle + 3 * da ), r1 * sin( angle + 3 * da ), width * 0.5 ); r2 = minr2; } r2 = maxr2; glEnd(); glNormal3f( 0.0, 0.0, -1.0 ); /* draw back face */ glBegin( GL_QUAD_STRIP ); for( i = 0; i <= teeth; ++i ) { angle = i * 2.0 * M_PI / teeth; glVertex3f( r1 * cos( angle ), r1 * sin( angle ), -width * 0.5 ); glVertex3f( r0 * cos( angle ), r0 * sin( angle ), -width * 0.5 ); if( i < teeth ) { glVertex3f( r1 * cos( angle + 3 * da ), r1 * sin( angle + 3 * da ), -width * 0.5 ); glVertex3f( r0 * cos( angle ), r0 * sin( angle ), -width * 0.5 ); } } glEnd(); /* draw back sides of teeth */ glBegin( GL_QUADS ); da = 2.0 * M_PI / teeth / 4.0; for( i = 0; i < teeth; ++i ) { angle = i * 2.0 * M_PI / teeth; glVertex3f( r1 * cos( angle + 3 * da ), r1 * sin( angle + 3 * da ), -width * 0.5 ); glVertex3f( r2 * cos( angle + 2 * da ), r2 * sin( angle + 2 * da ), -width * 0.5 ); glVertex3f( r2 * cos (angle + da), r2 * sin (angle + da), -width * 0.5 ); glVertex3f( r1 * cos (angle), r1 * sin (angle), -width * 0.5 ); r2 = minr2; } r2 = maxr2; glEnd(); /* draw outward faces of teeth */ glBegin( GL_QUAD_STRIP ); for( i = 0; i < teeth; ++i ) { angle = i * 2.0 * M_PI / teeth; glVertex3f( r1 * cos( angle ), r1 * sin( angle ), width * 0.5 ); glVertex3f( r1 * cos( angle ), r1 * sin( angle ), -width * 0.5 ); u = r2 * cos( angle + da ) - r1 * cos( angle ); v = r2 * sin( angle + da ) - r1 * sin( angle ); len = sqrt( u * u + v * v ); u /= len; v /= len; glNormal3f( v, -u, 0.0 ); glVertex3f( r2 * cos( angle + da ), r2 * sin( angle + da ), width * 0.5 ); glVertex3f( r2 * cos( angle + da ), r2 * sin( angle + da ), -width * 0.5 ); glNormal3f( cos( angle + 1.5 * da ), sin( angle + 1.5 * da ), 0.0 ); glVertex3f( r2 * cos( angle + 2 * da ), r2 * sin( angle + 2 * da ), width * 0.5 ); glVertex3f( r2 * cos( angle + 2 * da ), r2 * sin( angle + 2 * da ), -width * 0.5 ); u = r1 * cos( angle + 3 * da ) - r2 * cos( angle + 2 * da ); v = r1 * sin( angle + 3 * da ) - r2 * sin( angle + 2 * da ); glNormal3f( v, -u, 0.0 ); glVertex3f( r1 * cos( angle + 3 * da ), r1 * sin( angle + 3 * da ), width * 0.5 ); glVertex3f( r1 * cos( angle + 3 * da ), r1 * sin( angle + 3 * da ), -width * 0.5 ); glNormal3f( cos( angle + 3.5 * da ), sin( angle + 3.5 * da ), 0.0 ); r2 = minr2; } r2 = maxr2; glVertex3f( r1 * cos( 0 ), r1 * sin( 0 ), width * 0.5 ); glVertex3f( r1 * cos( 0 ), r1 * sin( 0 ), -width * 0.5 ); glEnd(); glShadeModel( GL_SMOOTH ); /* draw inside radius cylinder */ glBegin( GL_QUAD_STRIP ); for( i = 0; i <= teeth; ++i ) { angle = i * 2.0 * M_PI / teeth; glNormal3f( -cos( angle ), -sin( angle ), 0.0 ); glVertex3f( r0 * cos( angle ), r0 * sin( angle ), -width * 0.5 ); glVertex3f( r0 * cos( angle ), r0 * sin( angle ), width * 0.5 ); } glEnd(); } void GearsEffect::paintGears() { static GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 }; QRect rect = effects->clientArea( FullArea, effects->activeScreen(), effects->currentDesktop() ); glPushMatrix(); // invert scale float fovy = 60.0f; float zNear = 0.1f; float ymax = zNear * tan( fovy * M_PI / 360.0f ); float ymin = -ymax; float xmin = ymin; float xmax = ymax; float scaleFactor = 1.1 * tan( fovy * M_PI / 360.0f )/ymax; glScalef( 1.0f/((xmax-xmin)*scaleFactor/displayWidth()), 1.0f/(-(ymax-ymin)*scaleFactor/displayHeight()), 1000.0f ); glPushAttrib( GL_COLOR_BUFFER_BIT | GL_TEXTURE_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT ); glDisable( GL_BLEND ); glPushMatrix(); // content rotation requires depth test - so disabled // glRotatef( m_contentRotation, 0.0, 1.0, 0.0 ); glScalef( 0.05, 0.05, 0.05 ); glEnable( GL_NORMALIZE ); glEnable( GL_LIGHTING ); glEnable( GL_LIGHT1 ); glDisable( GL_COLOR_MATERIAL ); glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); glPushMatrix(); glTranslatef( -3.0, -2.0, 0.0 ); glRotatef( m_angle, 0.0, 0.0, 1.0 ); glCallList( m_gear1 ); glPopMatrix(); glPushMatrix(); glTranslatef( 3.1, -2.0, 0.0 ); glRotatef( -2.0 * m_angle - 9.0, 0.0, 0.0, 1.0 ); glCallList( m_gear2 ); glPopMatrix(); glPushMatrix(); glTranslatef( -3.1, 4.2, 0.0 ); glRotatef( -2.0 * m_angle - 25.0, 0.0, 0.0, 1.0 ); glCallList( m_gear3 ); glPopMatrix(); glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, white ); glPopMatrix(); glDisable( GL_LIGHT1 ); glDisable( GL_NORMALIZE ); glEnable( GL_COLOR_MATERIAL ); glDisable( GL_LIGHTING ); glPopMatrix(); glPopAttrib(); } void GearsEffect::initGears() { static GLfloat pos[4] = { 5.0f, 5.0f, 10.0f, 0.0f }; static GLfloat red[4] = { 0.8f, 0.1f, 0.0f, 1.0f }; static GLfloat green[4] = { 0.0f, 0.8f, 0.2f, 1.0f }; static GLfloat blue[4] = { 0.2f, 0.2f, 1.0f, 1.0f }; static GLfloat ambientLight[] = { 0.3f, 0.3f, 0.3f, 0.3f }; static GLfloat diffuseLight[] = { 0.5f, 0.5f, 0.5f, 0.5f }; glLightfv( GL_LIGHT1, GL_AMBIENT, ambientLight ); glLightfv( GL_LIGHT1, GL_DIFFUSE, diffuseLight ); glLightfv( GL_LIGHT1, GL_POSITION, pos ); m_gear1 = glGenLists( 1 ); glNewList( m_gear1, GL_COMPILE ); glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red ); gear( 1.0f, 4.0f, 1.0f, 20, 0.7f ); glEndList(); m_gear2 = glGenLists( 1 ); glNewList( m_gear2, GL_COMPILE ); glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green ); gear( 0.5f, 2.0f, 2.0f, 10, 0.7f ); glEndList(); m_gear3 = glGenLists( 1 ); glNewList( m_gear3, GL_COMPILE ); glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue ); gear( 1.3f, 2.0f, 0.5f, 10, 0.7f ); glEndList(); } void GearsEffect::endGears() { glDeleteLists( m_gear1, 1 ); glDeleteLists( m_gear2, 1 ); glDeleteLists( m_gear3, 1 ); } } // namespace