From ad070909a3b21b0a5b374d539421bbace725ffa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Sun, 19 Dec 2010 14:41:26 +0100 Subject: [PATCH] Reflection plane in Coverswitch and GLES CoverSwitch uses new concept of combining a custom fragment shader with the built-in generic vertex shader. This shader is used to render the reflection plane on top of the reflected windows. The fragment shader uses two uniform colors for front and back and interpolates between them based on the texcoords (which are not used for texture lookup). The reflection plane vertices could be buffered. --- effects/coverswitch/CMakeLists.txt | 5 + .../coverswitch/coverswitch-reflection.glsl | 9 ++ effects/coverswitch/coverswitch.cpp | 95 ++++++++++++++----- effects/coverswitch/coverswitch.h | 2 + 4 files changed, 88 insertions(+), 23 deletions(-) create mode 100644 effects/coverswitch/coverswitch-reflection.glsl diff --git a/effects/coverswitch/CMakeLists.txt b/effects/coverswitch/CMakeLists.txt index cc08dcbe12..9a264915f6 100644 --- a/effects/coverswitch/CMakeLists.txt +++ b/effects/coverswitch/CMakeLists.txt @@ -11,6 +11,11 @@ install( FILES coverswitch/coverswitch.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kwin ) +install( FILES + coverswitch/coverswitch-reflection.glsl + DESTINATION ${DATA_INSTALL_DIR}/kwin ) + + ####################################### # Config diff --git a/effects/coverswitch/coverswitch-reflection.glsl b/effects/coverswitch/coverswitch-reflection.glsl new file mode 100644 index 0000000000..bce5b7557d --- /dev/null +++ b/effects/coverswitch/coverswitch-reflection.glsl @@ -0,0 +1,9 @@ +uniform vec4 u_frontColor; +uniform vec4 u_backColor; + +varying vec2 varyingTexCoords; + +void main() +{ + gl_FragColor = u_frontColor*(1.0-varyingTexCoords.s) + u_backColor*varyingTexCoords.s; +} diff --git a/effects/coverswitch/coverswitch.cpp b/effects/coverswitch/coverswitch.cpp index 23fd297c7e..6784cd192b 100644 --- a/effects/coverswitch/coverswitch.cpp +++ b/effects/coverswitch/coverswitch.cpp @@ -26,6 +26,8 @@ along with this program. If not, see . #include #include #include +#include +#include #include @@ -65,11 +67,15 @@ CoverSwitchEffect::CoverSwitchEffect() captionFont.setPointSize( captionFont.pointSize() * 2 ); captionFrame->setFont( captionFont ); captionFrame->enableCrossFade( true ); + + const QString fragmentshader = KGlobal::dirs()->findResource("data", "kwin/coverswitch-reflection.glsl"); + m_reflectionShader = ShaderManager::instance()->loadFragmentShader(ShaderManager::GenericShader, fragmentshader); } CoverSwitchEffect::~CoverSwitchEffect() { delete captionFrame; + delete m_reflectionShader; } bool CoverSwitchEffect::supported() @@ -257,33 +263,28 @@ void CoverSwitchEffect::paintScreen( int mask, QRegion region, ScreenPaintData& if( (!start && !stop) || ShaderManager::instance()->isValid() ) paintScene( frontWindow, leftWindows, rightWindows, true ); PaintClipper::pop( clip ); -#ifndef KWIN_HAVE_OPENGLES glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA ); +#ifndef KWIN_HAVE_OPENGLES glPolygonMode( GL_FRONT, GL_FILL ); - glPushMatrix(); +#endif QRect fullRect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() ); // we can use a huge scale factor (needed to calculate the rearground vertices) // as we restrict with a PaintClipper painting on the current screen float reflectionScaleFactor = 100000 * tan( 60.0 * M_PI / 360.0f )/area.width(); - if( effects->numScreens() > 1 && area.x() != fullRect.x() ) - { - // have to change the reflection area in horizontal layout and right screen - glTranslatef( -area.x(), 0.0, 0.0 ); - } - glTranslatef( area.x() + area.width()*0.5f, 0.0, 0.0 ); float vertices[] = { -area.width()*0.5f, area.height(), 0.0, area.width()*0.5f, area.height(), 0.0, (float)area.width()*reflectionScaleFactor, area.height(), -5000, -(float)area.width()*reflectionScaleFactor, area.height(), -5000 }; // foreground - if( start ) + if (start) { mirrorColor[0][3] = timeLine.value(); - else if( stop ) + } else if (stop) { mirrorColor[0][3] = 1.0 - timeLine.value(); - glColor4fv( mirrorColor[0] ); - mirrorColor[0][3] = 1.0; + } else { + mirrorColor[0][3] = 1.0; + } int y = 0; // have to adjust the y values to fit OpenGL @@ -302,20 +303,68 @@ void CoverSwitchEffect::paintScreen( int mask, QRegion region, ScreenPaintData& // use scissor to restrict painting of the reflection plane to current screen glScissor( area.x(), y, area.width(), area.height() ); glEnable( GL_SCISSOR_TEST ); - glBegin( GL_POLYGON ); - glVertex3f( vertices[0], vertices[1], vertices[2] ); - glVertex3f( vertices[3], vertices[4], vertices[5] ); - // rearground - glColor4fv( mirrorColor[1] ); - glVertex3f( vertices[6], vertices[7], vertices[8] ); - glVertex3f( vertices[9], vertices[10], vertices[11] ); - glEnd(); - glDisable( GL_SCISSOR_TEST ); - glPopMatrix(); - glDisable( GL_BLEND ); + ShaderManager *shaderManager = ShaderManager::instance(); + if (shaderManager->isValid() && m_reflectionShader->isValid()) { + shaderManager->pushShader(m_reflectionShader); + QMatrix4x4 windowTransformation; + if (effects->numScreens() > 1 && area.x() != fullRect.x()) { + // have to change the reflection area in horizontal layout and right screen + windowTransformation.translate(-area.x(), 0.0, 0.0); + } + windowTransformation.translate(area.x() + area.width()*0.5f, 0.0, 0.0); + m_reflectionShader->setUniform("windowTransformation", windowTransformation); + m_reflectionShader->setUniform("u_frontColor", QVector4D(mirrorColor[0][0], mirrorColor[0][1], mirrorColor[0][2], mirrorColor[0][3])); + m_reflectionShader->setUniform("u_backColor", QVector4D(mirrorColor[1][0], mirrorColor[1][1], mirrorColor[1][2], mirrorColor[1][3])); + // TODO: make this one properly + QVector verts; + QVector texcoords; + verts.reserve(18); + texcoords.reserve(12); + texcoords << 1.0 << 0.0; + verts << vertices[6] << vertices[7] << vertices[8]; + texcoords << 1.0 << 0.0; + verts << vertices[9] << vertices[10] << vertices[11]; + texcoords << 0.0 << 0.0; + verts << vertices[0] << vertices[1] << vertices[2]; + texcoords << 0.0 << 0.0; + verts << vertices[0] << vertices[1] << vertices[2]; + texcoords << 0.0 << 0.0; + verts << vertices[3] << vertices[4] << vertices[5]; + texcoords << 1.0 << 0.0; + verts << vertices[6] << vertices[7] << vertices[8]; + GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer(); + vbo->reset(); + vbo->setUseShader(true); + vbo->setData(6, 3, verts.data(), texcoords.data()); + vbo->render(GL_TRIANGLES); + + shaderManager->popShader(); + } else { +#ifndef KWIN_HAVE_OPENGLES + glPushMatrix(); + if( effects->numScreens() > 1 && area.x() != fullRect.x() ) + { + // have to change the reflection area in horizontal layout and right screen + glTranslatef( -area.x(), 0.0, 0.0 ); + } + glTranslatef( area.x() + area.width()*0.5f, 0.0, 0.0 ); + glColor4fv( mirrorColor[0] ); + glBegin( GL_POLYGON ); + glVertex3f( vertices[0], vertices[1], vertices[2] ); + glVertex3f( vertices[3], vertices[4], vertices[5] ); + // rearground + glColor4fv( mirrorColor[1] ); + glVertex3f( vertices[6], vertices[7], vertices[8] ); + glVertex3f( vertices[9], vertices[10], vertices[11] ); + glEnd(); + + glPopMatrix(); #endif } + glDisable( GL_SCISSOR_TEST ); + glDisable( GL_BLEND ); + } paintScene( frontWindow, leftWindows, rightWindows ); if( effects->numScreens() > 1 ) diff --git a/effects/coverswitch/coverswitch.h b/effects/coverswitch/coverswitch.h index a4a8d33cb7..e6311af07c 100644 --- a/effects/coverswitch/coverswitch.h +++ b/effects/coverswitch/coverswitch.h @@ -102,6 +102,8 @@ class CoverSwitchEffect bool primaryTabBox; bool secondaryTabBox; + + GLShader *m_reflectionShader; }; } // namespace