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.
This commit is contained in:
Martin Gräßlin 2010-12-19 14:41:26 +01:00
parent a4e4752109
commit ad070909a3
4 changed files with 88 additions and 23 deletions

View file

@ -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

View file

@ -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;
}

View file

@ -26,6 +26,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kapplication.h>
#include <kcolorscheme.h>
#include <kconfiggroup.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <kwinglutils.h>
@ -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<float> verts;
QVector<float> 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 )

View file

@ -102,6 +102,8 @@ class CoverSwitchEffect
bool primaryTabBox;
bool secondaryTabBox;
GLShader *m_reflectionShader;
};
} // namespace