• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KWinLibraries

kwinglutils.cpp

Go to the documentation of this file.
00001 /********************************************************************
00002  KWin - the KDE window manager
00003  This file is part of the KDE project.
00004 
00005 Copyright (C) 2006-2007 Rivo Laks <rivolaks@hot.ee>
00006 
00007 This program is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 This program is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with this program.  If not, see <http://www.gnu.org/licenses/>.
00019 *********************************************************************/
00020 
00021 #include "kwinglutils.h"
00022 
00023 #ifdef KWIN_HAVE_OPENGL
00024 
00025 #include "kwinglobals.h"
00026 #include "kwineffects.h"
00027 
00028 #include "kdebug.h"
00029 #include <kstandarddirs.h>
00030 
00031 #include <QPixmap>
00032 #include <QImage>
00033 #include <QHash>
00034 #include <QFile>
00035 
00036 
00037 
00038 #define MAKE_GL_VERSION(major, minor, release)  ( ((major) << 16) | ((minor) << 8) | (release) )
00039 
00040 
00041 namespace KWin
00042 {
00043 // Variables
00044 // GL version, use MAKE_GL_VERSION() macro for comparing with a specific version
00045 static int glVersion;
00046 // GLX version, use MAKE_GL_VERSION() macro for comparing with a specific version
00047 static int glXVersion;
00048 // List of all supported GL and GLX extensions
00049 static QStringList glExtensions;
00050 static QStringList glxExtensions;
00051 
00052 int glTextureUnitsCount;
00053 
00054 
00055 // Functions
00056 void initGLX()
00057     {
00058     // Get GLX version
00059     int major, minor;
00060     glXQueryVersion( display(), &major, &minor );
00061     glXVersion = MAKE_GL_VERSION( major, minor, 0 );
00062     // Get list of supported GLX extensions
00063     glxExtensions = QString((const char*)glXQueryExtensionsString(
00064         display(), DefaultScreen( display()))).split(" ");
00065 
00066     glxResolveFunctions();
00067     }
00068 
00069 void initGL()
00070     {
00071     // Get OpenGL version
00072     QString glversionstring = QString((const char*)glGetString(GL_VERSION));
00073     QStringList glversioninfo = glversionstring.left(glversionstring.indexOf(' ')).split('.');
00074     glVersion = MAKE_GL_VERSION(glversioninfo[0].toInt(), glversioninfo[1].toInt(),
00075                                     glversioninfo.count() > 2 ? glversioninfo[2].toInt() : 0);
00076     // Get list of supported OpenGL extensions
00077     glExtensions = QString((const char*)glGetString(GL_EXTENSIONS)).split(" ");
00078 
00079     // handle OpenGL extensions functions
00080     glResolveFunctions();
00081 
00082     GLTexture::initStatic();
00083     GLShader::initStatic();
00084     GLRenderTarget::initStatic();
00085     }
00086 
00087 bool hasGLVersion(int major, int minor, int release)
00088     {
00089     return glVersion >= MAKE_GL_VERSION(major, minor, release);
00090     }
00091 
00092 bool hasGLXVersion(int major, int minor, int release)
00093     {
00094     return glXVersion >= MAKE_GL_VERSION(major, minor, release);
00095     }
00096 
00097 bool hasGLExtension(const QString& extension)
00098     {
00099     return glExtensions.contains(extension) || glxExtensions.contains(extension);
00100     }
00101 
00102 bool checkGLError( const char* txt )
00103     {
00104     GLenum err = glGetError();
00105     if( err != GL_NO_ERROR )
00106         {
00107         kWarning(1212) << "GL error (" << txt << "): 0x" << QString::number( err, 16 ) ;
00108         return true;
00109         }
00110     return false;
00111     }
00112 
00113 int nearestPowerOfTwo( int x )
00114     {
00115     // This method had been copied from Qt's nearest_gl_texture_size()
00116     int n = 0, last = 0;
00117     for (int s = 0; s < 32; ++s) {
00118         if (((x>>s) & 1) == 1) {
00119             ++n;
00120             last = s;
00121         }
00122     }
00123     if (n > 1)
00124         return 1 << (last+1);
00125     return 1 << last;
00126     }
00127 
00128 void renderGLGeometry( int count, const float* vertices, const float* texture, const float* color,
00129     int dim, int stride )
00130     {
00131     return renderGLGeometry( infiniteRegion(), count, vertices, texture, color, dim, stride );
00132     }
00133 
00134 void renderGLGeometry( const QRegion& region, int count,
00135     const float* vertices, const float* texture, const float* color,
00136     int dim, int stride )
00137     {
00138     // Using arrays only makes sense if we have larger number of vertices.
00139     //  Otherwise overhead of enabling/disabling them is too big.
00140     bool use_arrays = (count > 5);
00141 
00142     if( use_arrays )
00143         {
00144         glPushAttrib( GL_ENABLE_BIT );
00145         glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
00146         // Enable arrays
00147         glEnableClientState( GL_VERTEX_ARRAY );
00148         glVertexPointer( dim, GL_FLOAT, stride, vertices );
00149         if( texture != NULL )
00150             {
00151             glEnableClientState( GL_TEXTURE_COORD_ARRAY );
00152             glTexCoordPointer( 2, GL_FLOAT, stride, texture );
00153             }
00154         if( color != NULL )
00155             {
00156             glEnableClientState( GL_COLOR_ARRAY );
00157             glColorPointer( 4, GL_FLOAT, stride, color );
00158             }
00159         }
00160 
00161     // Clip using scissoring
00162     PaintClipper pc( region );
00163     for( PaintClipper::Iterator iterator;
00164          !iterator.isDone();
00165          iterator.next())
00166         {
00167         if( use_arrays )
00168             glDrawArrays( GL_QUADS, 0, count );
00169         else
00170             renderGLGeometryImmediate( count, vertices, texture, color, dim, stride );
00171         }
00172 
00173     if( use_arrays )
00174         {
00175         glPopClientAttrib();
00176         glPopAttrib();
00177         }
00178     }
00179 
00180 void renderGLGeometryImmediate( int count, const float* vertices, const float* texture, const float* color,
00181       int dim, int stride )
00182 {
00183     // Find out correct glVertex*fv function according to dim parameter.
00184     void ( *glVertexFunc )( const float* ) = glVertex2fv;
00185     if( dim == 3 )
00186         glVertexFunc = glVertex3fv;
00187     else if( dim == 4 )
00188         glVertexFunc = glVertex4fv;
00189 
00190     // These are number of _floats_ per item, not _bytes_ per item as opengl uses.
00191     int vsize, tsize, csize;
00192     vsize = tsize = csize = stride / sizeof(float);
00193     if( !stride )
00194         {
00195         // 0 means that arrays are tightly packed. This gives us different
00196         //  strides for different arrays
00197         vsize = dim;
00198         tsize = 2;
00199         csize = 4;
00200         }
00201 
00202     glBegin( GL_QUADS );
00203     // This sucks. But makes it faster.
00204     if( texture && color )
00205         {
00206         for( int i = 0; i < count; i++ )
00207             {
00208             glTexCoord2fv( texture + i*tsize );
00209             glColor4fv( color + i*csize );
00210             glVertexFunc( vertices + i*vsize );
00211             }
00212         }
00213     else if( texture )
00214         {
00215         for( int i = 0; i < count; i++ )
00216             {
00217             glTexCoord2fv( texture + i*tsize );
00218             glVertexFunc( vertices + i*vsize );
00219             }
00220         }
00221     else if( color )
00222         {
00223         for( int i = 0; i < count; i++ )
00224             {
00225             glColor4fv( color + i*csize );
00226             glVertexFunc( vertices + i*vsize );
00227             }
00228         }
00229     else
00230         {
00231         for( int i = 0; i < count; i++ )
00232             glVertexFunc( vertices + i*vsize );
00233         }
00234     glEnd();
00235 }
00236 
00237 void addQuadVertices(QVector<float>& verts, float x1, float y1, float x2, float y2)
00238 {
00239     verts << x1 << y1;
00240     verts << x1 << y2;
00241     verts << x2 << y2;
00242     verts << x2 << y1;
00243 }
00244 
00245 void renderRoundBox( const QRect& area, float roundness, GLTexture* texture )
00246 {
00247     static GLTexture* circleTexture = 0;
00248     if( !texture && !circleTexture )
00249         {
00250         QString texturefile =  KGlobal::dirs()->findResource("data", "kwin/circle.png");
00251         circleTexture = new GLTexture(texturefile);
00252         }
00253     if( !texture )
00254         {
00255         texture = circleTexture;
00256         }
00257 
00258     glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT );
00259     glEnable( GL_BLEND );
00260     glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00261 
00262     glPushMatrix();
00263 
00264     QVector<float> verts, texcoords;
00265     verts.reserve(80);
00266     texcoords.reserve(80);
00267     // center
00268     addQuadVertices(verts, area.left() + roundness, area.top() + roundness, area.right() - roundness, area.bottom() - roundness);
00269     addQuadVertices(texcoords, 0.5, 0.5, 0.5, 0.5);
00270     // sides
00271     // left
00272     addQuadVertices(verts, area.left(), area.top() + roundness, area.left() + roundness, area.bottom() - roundness);
00273     addQuadVertices(texcoords, 0.0, 0.5, 0.5, 0.5);
00274     // top
00275     addQuadVertices(verts, area.left() + roundness, area.top(), area.right() - roundness, area.top() + roundness);
00276     addQuadVertices(texcoords, 0.5, 0.0, 0.5, 0.5);
00277     // right
00278     addQuadVertices(verts, area.right() - roundness, area.top() + roundness, area.right(), area.bottom() - roundness);
00279     addQuadVertices(texcoords, 0.5, 0.5, 1.0, 0.5);
00280     // bottom
00281     addQuadVertices(verts, area.left() + roundness, area.bottom() - roundness, area.right() - roundness, area.bottom());
00282     addQuadVertices(texcoords, 0.5, 0.5, 0.5, 1.0);
00283     // corners
00284     // top-left
00285     addQuadVertices(verts, area.left(), area.top(), area.left() + roundness, area.top() + roundness);
00286     addQuadVertices(texcoords, 0.0, 0.0, 0.5, 0.5);
00287     // top-right
00288     addQuadVertices(verts, area.right() - roundness, area.top(), area.right(), area.top() + roundness);
00289     addQuadVertices(texcoords, 0.5, 0.0, 1.0, 0.5);
00290     // bottom-left
00291     addQuadVertices(verts, area.left(), area.bottom() - roundness, area.left() + roundness, area.bottom());
00292     addQuadVertices(texcoords, 0.0, 0.5, 0.5, 1.0);
00293     // bottom-right
00294     addQuadVertices(verts, area.right() - roundness, area.bottom() - roundness, area.right(), area.bottom());
00295     addQuadVertices(texcoords, 0.5, 0.5, 1.0, 1.0);
00296 
00297     texture->bind();
00298     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00299     // We have two elements per vertex in the verts array
00300     int verticesCount = verts.count() / 2;
00301     texture->enableNormalizedTexCoords();
00302     renderGLGeometry( verticesCount, verts.data(), texcoords.data() );
00303     texture->disableNormalizedTexCoords();
00304     texture->unbind();
00305 
00306     glPopMatrix();
00307     glPopAttrib();
00308 }
00309 
00310 void renderRoundBoxWithEdge( const QRect& area, float roundness )
00311 {
00312     static GLTexture* texture = 0;
00313     if( !texture )
00314     {
00315         QString texturefile =  KGlobal::dirs()->findResource("data", "kwin/circle-edgy.png");
00316         texture = new GLTexture(texturefile);
00317     }
00318     renderRoundBox( area, roundness, texture );
00319 }
00320 
00321 //****************************************
00322 // GLTexture
00323 //****************************************
00324 
00325 bool GLTexture::mNPOTTextureSupported = false;
00326 bool GLTexture::mFramebufferObjectSupported = false;
00327 bool GLTexture::mSaturationSupported = false;
00328 
00329 GLTexture::GLTexture()
00330     {
00331     init();
00332     }
00333 
00334 GLTexture::GLTexture( const QImage& image, GLenum target )
00335     {
00336     init();
00337     load( image, target );
00338     }
00339 
00340 GLTexture::GLTexture( const QPixmap& pixmap, GLenum target )
00341     {
00342     init();
00343     load( pixmap, target );
00344     }
00345 
00346 GLTexture::GLTexture( const QString& fileName )
00347     {
00348     init();
00349     load( fileName );
00350     }
00351 
00352 GLTexture::GLTexture( int width, int height )
00353     {
00354     init();
00355 
00356     if( NPOTTextureSupported() || ( isPowerOfTwo( width ) && isPowerOfTwo( height )))
00357         {
00358         mTarget = GL_TEXTURE_2D;
00359         mScale.setWidth( 1.0 / width);
00360         mScale.setHeight( 1.0 / height);
00361         can_use_mipmaps = true;
00362 
00363         glGenTextures( 1, &mTexture );
00364         bind();
00365         glTexImage2D( mTarget, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
00366         unbind();
00367         }
00368     }
00369 
00370 GLTexture::~GLTexture()
00371     {
00372     discard();
00373     assert( mUnnormalizeActive == 0 );
00374     assert( mNormalizeActive == 0 );
00375     }
00376 
00377 void GLTexture::init()
00378     {
00379     mTexture = None;
00380     mTarget = 0;
00381     mFilter = 0;
00382     y_inverted = false;
00383     can_use_mipmaps = false;
00384     has_valid_mipmaps = false;
00385     mUnnormalizeActive = 0;
00386     mNormalizeActive = 0;
00387     }
00388 
00389 void GLTexture::initStatic()
00390     {
00391     mNPOTTextureSupported = hasGLExtension( "GL_ARB_texture_non_power_of_two" );
00392     mFramebufferObjectSupported = hasGLExtension( "GL_EXT_framebuffer_object" );
00393     mSaturationSupported = ((hasGLExtension("GL_ARB_texture_env_crossbar")
00394         && hasGLExtension("GL_ARB_texture_env_dot3")) || hasGLVersion(1, 4))
00395         && (glTextureUnitsCount >= 4) && glActiveTexture != NULL;
00396     }
00397 
00398 bool GLTexture::isNull() const
00399     {
00400     return mTexture == None;
00401     }
00402 
00403 QSize GLTexture::size() const
00404     {
00405     return mSize;
00406     }
00407 
00408 bool GLTexture::load( const QImage& image, GLenum target )
00409     {
00410     if( image.isNull())
00411         return false;
00412     QImage img = image;
00413     mTarget = target;
00414     if( mTarget != GL_TEXTURE_RECTANGLE_ARB )
00415         {
00416         if( !NPOTTextureSupported()
00417             && ( !isPowerOfTwo( image.width()) || !isPowerOfTwo( image.height())))
00418             { // non-rectangular target requires POT texture
00419             img = img.scaled( nearestPowerOfTwo( image.width()),
00420                     nearestPowerOfTwo( image.height()));
00421             }
00422         mScale.setWidth( 1.0 / img.width());
00423         mScale.setHeight( 1.0 / img.height());
00424         can_use_mipmaps = true;
00425         }
00426     else
00427         {
00428         mScale.setWidth( 1.0 );
00429         mScale.setHeight( 1.0 );
00430         can_use_mipmaps = false;
00431         }
00432     setFilter( GL_LINEAR );
00433     mSize = img.size();
00434     y_inverted = false;
00435 
00436     img = convertToGLFormat( img );
00437 
00438     setDirty();
00439     if( isNull())
00440         glGenTextures( 1, &mTexture );
00441     bind();
00442     glTexImage2D( mTarget, 0, GL_RGBA, img.width(), img.height(), 0,
00443         GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
00444     unbind();
00445     return true;
00446     }
00447 
00448 bool GLTexture::load( const QPixmap& pixmap, GLenum target )
00449     {
00450     if( pixmap.isNull())
00451         return false;
00452     return load( pixmap.toImage(), target );
00453     }
00454 
00455 bool GLTexture::load( const QString& fileName )
00456     {
00457     if( fileName.isEmpty())
00458         return false;
00459     return load( QImage( fileName ));
00460     }
00461 
00462 void GLTexture::discard()
00463     {
00464     setDirty();
00465     if( mTexture != None )
00466         glDeleteTextures( 1, &mTexture );
00467     mTexture = None;
00468     }
00469 
00470 void GLTexture::bind()
00471     {
00472     glEnable( mTarget );
00473     glBindTexture( mTarget, mTexture );
00474     enableFilter();
00475     }
00476 
00477 void GLTexture::unbind()
00478     {
00479     glBindTexture( mTarget, 0 );
00480     glDisable( mTarget );
00481     }
00482 
00483 void GLTexture::render( QRegion region, const QRect& rect )
00484     {
00485     const float verts[ 4 * 2 ] =
00486         {
00487         rect.x(), rect.y(),
00488         rect.x(), rect.y() + rect.height(),
00489         rect.x() + rect.width(), rect.y() + rect.height(),
00490         rect.x() + rect.width(), rect.y()
00491         };
00492     const float texcoords[ 4 * 2 ] =
00493         {
00494         0, 1, // y needs to be swapped (normalized coords)
00495         0, 0,
00496         1, 0,
00497         1, 1
00498         };
00499     enableNormalizedTexCoords();
00500     renderGLGeometry( region, 4, verts, texcoords );
00501     disableNormalizedTexCoords();
00502     }
00503 
00504 void GLTexture::enableUnnormalizedTexCoords()
00505     {
00506     assert( mNormalizeActive == 0 );
00507     if( mUnnormalizeActive++ != 0 )
00508         return;
00509     // update texture matrix to handle GL_TEXTURE_2D and GL_TEXTURE_RECTANGLE
00510     glMatrixMode( GL_TEXTURE );
00511     glPushMatrix();
00512     glLoadIdentity();
00513     glScalef( mScale.width(), mScale.height(), 1 );
00514     if( !y_inverted )
00515         {
00516         // Modify texture matrix so that we could always use non-opengl
00517         //  coordinates for textures
00518         glScalef( 1, -1, 1 );
00519         glTranslatef( 0, -mSize.height(), 0 );
00520         }
00521     glMatrixMode( GL_MODELVIEW );
00522     }
00523 
00524 void GLTexture::disableUnnormalizedTexCoords()
00525     {
00526     if( --mUnnormalizeActive != 0 )
00527         return;
00528     // Restore texture matrix
00529     glMatrixMode( GL_TEXTURE );
00530     glPopMatrix();
00531     glMatrixMode( GL_MODELVIEW );
00532     }
00533 
00534 void GLTexture::enableNormalizedTexCoords()
00535     {
00536     assert( mUnnormalizeActive == 0 );
00537     if( mNormalizeActive++ != 0 )
00538         return;
00539     // update texture matrix to handle GL_TEXTURE_2D and GL_TEXTURE_RECTANGLE
00540     glMatrixMode( GL_TEXTURE );
00541     glPushMatrix();
00542     glLoadIdentity();
00543     glScalef( mSize.width() * mScale.width(), mSize.height() * mScale.height(), 1 );
00544     if( y_inverted )
00545         {
00546         // Modify texture matrix so that we could always use non-opengl
00547         //  coordinates for textures
00548         glScalef( 1, -1, 1 );
00549         glTranslatef( 0, -1, 0 );
00550         }
00551     glMatrixMode( GL_MODELVIEW );
00552     }
00553 
00554 void GLTexture::disableNormalizedTexCoords()
00555     {
00556     if( --mNormalizeActive != 0 )
00557         return;
00558     // Restore texture matrix
00559     glMatrixMode( GL_TEXTURE );
00560     glPopMatrix();
00561     glMatrixMode( GL_MODELVIEW );
00562     }
00563 
00564 GLuint GLTexture::texture() const
00565     {
00566     return mTexture;
00567     }
00568 
00569 GLenum GLTexture::target() const
00570     {
00571     return mTarget;
00572     }
00573 
00574 GLenum GLTexture::filter() const
00575     {
00576     return mFilter;
00577     }
00578 
00579 bool GLTexture::isDirty() const
00580     {
00581     return has_valid_mipmaps;
00582     }
00583 
00584 void GLTexture::setTexture( GLuint texture )
00585     {
00586     discard();
00587     mTexture = texture;
00588     }
00589 
00590 void GLTexture::setTarget( GLenum target )
00591     {
00592     mTarget = target;
00593     }
00594 
00595 void GLTexture::setFilter( GLenum filter )
00596     {
00597     mFilter = filter;
00598     }
00599 
00600 void GLTexture::setWrapMode( GLenum mode )
00601     {
00602     bind();
00603     glTexParameteri( mTarget, GL_TEXTURE_WRAP_S, mode );
00604     glTexParameteri( mTarget, GL_TEXTURE_WRAP_T, mode );
00605     unbind();
00606     }
00607 
00608 void GLTexture::setDirty()
00609     {
00610     has_valid_mipmaps = false;
00611     }
00612 
00613 
00614 void GLTexture::enableFilter()
00615     {
00616     if( mFilter == GL_LINEAR_MIPMAP_LINEAR )
00617         { // trilinear filtering requested, but is it possible?
00618         if( NPOTTextureSupported()
00619             && framebufferObjectSupported()
00620             && can_use_mipmaps )
00621             {
00622             glTexParameteri( mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
00623             glTexParameteri( mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00624             if( !has_valid_mipmaps )
00625                 {
00626                 glGenerateMipmap( mTarget );
00627                 has_valid_mipmaps = true;
00628                 }
00629             }
00630         else
00631             { // can't use trilinear, so use bilinear
00632             setFilter( GL_LINEAR );
00633             glTexParameteri( mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
00634             glTexParameteri( mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00635             }
00636         }
00637     else if( mFilter == GL_LINEAR )
00638         {
00639         glTexParameteri( mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
00640         glTexParameteri( mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00641         }
00642     else
00643         { // if neither trilinear nor bilinear, default to fast filtering
00644         setFilter( GL_NEAREST );
00645         glTexParameteri( mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
00646         glTexParameteri( mTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
00647         }
00648     }
00649 
00650 QImage GLTexture::convertToGLFormat( const QImage& img ) const
00651     {
00652     // This method has been copied from Qt's QGLWidget::convertToGLFormat()
00653     QImage res = img.convertToFormat(QImage::Format_ARGB32);
00654     res = res.mirrored();
00655 
00656     if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
00657         // Qt has ARGB; OpenGL wants RGBA
00658         for (int i=0; i < res.height(); i++) {
00659             uint *p = (uint*)res.scanLine(i);
00660             uint *end = p + res.width();
00661             while (p < end) {
00662                 *p = (*p << 8) | ((*p >> 24) & 0xFF);
00663                 p++;
00664             }
00665         }
00666     }
00667     else {
00668         // Qt has ARGB; OpenGL wants ABGR (i.e. RGBA backwards)
00669         res = res.rgbSwapped();
00670     }
00671     return res;
00672     }
00673 
00674 //****************************************
00675 // GLShader
00676 //****************************************
00677 
00678 bool GLShader::mFragmentShaderSupported = false;
00679 bool GLShader::mVertexShaderSupported = false;
00680 
00681 void GLShader::initStatic()
00682 {
00683     mFragmentShaderSupported = mVertexShaderSupported =
00684             hasGLExtension("GL_ARB_shader_objects") && hasGLExtension("GL_ARB_shading_language_100");
00685     mVertexShaderSupported &= hasGLExtension("GL_ARB_vertex_shader");
00686     mFragmentShaderSupported &= hasGLExtension("GL_ARB_fragment_shader");
00687 }
00688 
00689 
00690 GLShader::GLShader(const QString& vertexfile, const QString& fragmentfile)
00691     {
00692     mValid = false;
00693     mVariableLocations = 0;
00694     mProgram = 0;
00695 
00696     loadFromFiles(vertexfile, fragmentfile);
00697     }
00698 
00699 GLShader::~GLShader()
00700 {
00701     if(mVariableLocations)
00702     {
00703         mVariableLocations->clear();
00704         delete mVariableLocations;
00705     }
00706 
00707     if(mProgram)
00708     {
00709         glDeleteProgram(mProgram);
00710     }
00711 }
00712 
00713 bool GLShader::loadFromFiles(const QString& vertexfile, const QString& fragmentfile)
00714     {
00715     QFile vf(vertexfile);
00716     if(!vf.open(QIODevice::ReadOnly))
00717         {
00718         kError(1212) << "Couldn't open '" << vertexfile << "' for reading!" << endl;
00719         return false;
00720         }
00721     QString vertexsource(vf.readAll());
00722 
00723     QFile ff(fragmentfile);
00724     if(!ff.open(QIODevice::ReadOnly))
00725         {
00726         kError(1212) << "Couldn't open '" << fragmentfile << "' for reading!" << endl;
00727         return false;
00728         }
00729     QString fragsource(ff.readAll());
00730 
00731     return load(vertexsource, fragsource);
00732     }
00733 
00734 bool GLShader::load(const QString& vertexsource, const QString& fragmentsource)
00735     {
00736     // Make sure shaders are actually supported
00737     if(( !vertexsource.isEmpty() && !vertexShaderSupported() ) ||
00738           ( !fragmentsource.isEmpty() && !fragmentShaderSupported() ))
00739         {
00740         kDebug(1212) << "Shaders not supported";
00741         return false;
00742         }
00743 
00744     GLuint vertexshader;
00745     GLuint fragmentshader;
00746 
00747     GLsizei logsize, logarraysize;
00748     char* log = 0;
00749 
00750     // Create program object
00751     mProgram = glCreateProgram();
00752     if(!vertexsource.isEmpty())
00753         {
00754         // Create shader object
00755         vertexshader = glCreateShader(GL_VERTEX_SHADER);
00756         // Load it
00757         const QByteArray& srcba = vertexsource.toLatin1();
00758         const char* src = srcba.data();
00759         glShaderSource(vertexshader, 1, &src, NULL);
00760         // Compile the shader
00761         glCompileShader(vertexshader);
00762         // Make sure it compiled correctly
00763         int compiled;
00764         glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &compiled);
00765         // Get info log
00766         glGetShaderiv(vertexshader, GL_INFO_LOG_LENGTH, &logarraysize);
00767         log = new char[logarraysize];
00768         glGetShaderInfoLog(vertexshader, logarraysize, &logsize, log);
00769         if(!compiled)
00770             {
00771             kError(1212) << "Couldn't compile vertex shader! Log:" << endl << log << endl;
00772             delete[] log;
00773             return false;
00774             }
00775         else if(logsize > 0)
00776             kDebug(1212) << "Vertex shader compilation log:"<< log;
00777         // Attach the shader to the program
00778         glAttachShader(mProgram, vertexshader);
00779         // Delete shader
00780         glDeleteShader(vertexshader);
00781         delete[] log;
00782         }
00783 
00784 
00785     if(!fragmentsource.isEmpty())
00786         {
00787         fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
00788         // Load it
00789         const QByteArray& srcba = fragmentsource.toLatin1();
00790         const char* src = srcba.data();
00791         glShaderSource(fragmentshader, 1, &src, NULL);
00792         //glShaderSource(fragmentshader, 1, &fragmentsrc.latin1(), NULL);
00793         // Compile the shader
00794         glCompileShader(fragmentshader);
00795         // Make sure it compiled correctly
00796         int compiled;
00797         glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &compiled);
00798         // Get info log
00799         glGetShaderiv(fragmentshader, GL_INFO_LOG_LENGTH, &logarraysize);
00800         log = new char[logarraysize];
00801         glGetShaderInfoLog(fragmentshader, logarraysize, &logsize, log);
00802         if(!compiled)
00803             {
00804             kError(1212) << "Couldn't compile fragment shader! Log:" << endl << log << endl;
00805             delete[] log;
00806             return false;
00807             }
00808         else if(logsize > 0)
00809             kDebug(1212) << "Fragment shader compilation log:"<< log;
00810         // Attach the shader to the program
00811         glAttachShader(mProgram, fragmentshader);
00812         // Delete shader
00813         glDeleteShader(fragmentshader);
00814         delete[] log;
00815         }
00816 
00817 
00818     // Link the program
00819     glLinkProgram(mProgram);
00820     // Make sure it linked correctly
00821     int linked;
00822     glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
00823     // Get info log
00824     glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &logarraysize);
00825     log = new char[logarraysize];
00826     glGetProgramInfoLog(mProgram, logarraysize, &logsize, log);
00827     if(!linked)
00828         {
00829         kError(1212) << "Couldn't link the program! Log" << endl << log << endl;
00830         delete[] log;
00831         return false;
00832         }
00833     else if(logsize > 0)
00834         kDebug(1212) << "Shader linking log:"<< log;
00835     delete[] log;
00836 
00837     mVariableLocations = new QHash<QString, int>;
00838 
00839     mValid = true;
00840     return true;
00841     }
00842 
00843 void GLShader::bind()
00844     {
00845     glUseProgram(mProgram);
00846     }
00847 
00848 void GLShader::unbind()
00849     {
00850     glUseProgram(0);
00851     }
00852 
00853 int GLShader::uniformLocation(const QString& name)
00854     {
00855     if(!mVariableLocations)
00856         {
00857         return -1;
00858         }
00859     if(!mVariableLocations->contains(name))
00860         {
00861         int location = glGetUniformLocation(mProgram, name.toLatin1().data());
00862         mVariableLocations->insert(name, location);
00863         }
00864     return mVariableLocations->value(name);
00865     }
00866 
00867 bool GLShader::setUniform(const QString& name, float value)
00868     {
00869     int location = uniformLocation(name);
00870     if(location >= 0)
00871         {
00872         glUniform1f(location, value);
00873         }
00874     return (location >= 0);
00875     }
00876 
00877 bool GLShader::setUniform(const QString& name, int value)
00878     {
00879     int location = uniformLocation(name);
00880     if(location >= 0)
00881         {
00882         glUniform1i(location, value);
00883         }
00884     return (location >= 0);
00885     }
00886 
00887 int GLShader::attributeLocation(const QString& name)
00888     {
00889     if(!mVariableLocations)
00890         {
00891         return -1;
00892         }
00893     if(!mVariableLocations->contains(name))
00894         {
00895         int location = glGetAttribLocation(mProgram, name.toLatin1().data());
00896         mVariableLocations->insert(name, location);
00897         }
00898     return mVariableLocations->value(name);
00899     }
00900 
00901 bool GLShader::setAttribute(const QString& name, float value)
00902     {
00903     int location = attributeLocation(name);
00904     if(location >= 0)
00905         {
00906         glVertexAttrib1f(location, value);
00907         }
00908     return (location >= 0);
00909     }
00910 
00911 
00912 
00913 /***  GLRenderTarget  ***/
00914 bool GLRenderTarget::mSupported = false;
00915 
00916 void GLRenderTarget::initStatic()
00917     {
00918     mSupported = hasGLExtension("GL_EXT_framebuffer_object") && glFramebufferTexture2D;
00919     }
00920 
00921 GLRenderTarget::GLRenderTarget(GLTexture* color)
00922     {
00923     // Reset variables
00924     mValid = false;
00925 
00926     mTexture = color;
00927 
00928     // Make sure FBO is supported
00929     if(mSupported && mTexture && !mTexture->isNull())
00930         {
00931         initFBO();
00932         }
00933     else
00934         kError(1212) << "Render targets aren't supported!" << endl;
00935     }
00936 
00937 GLRenderTarget::~GLRenderTarget()
00938     {
00939     if(mValid)
00940         {
00941         glDeleteFramebuffers(1, &mFramebuffer);
00942         }
00943     }
00944 
00945 bool GLRenderTarget::enable()
00946     {
00947     if(!valid())
00948         {
00949         kError(1212) << "Can't enable invalid render target!" << endl;
00950         return false;
00951         }
00952 
00953     glBindFramebuffer(GL_FRAMEBUFFER_EXT, mFramebuffer);
00954     mTexture->setDirty();
00955 
00956     return true;
00957     }
00958 
00959 bool GLRenderTarget::disable()
00960     {
00961     if(!valid())
00962         {
00963         kError(1212) << "Can't disable invalid render target!" << endl;
00964         return false;
00965         }
00966 
00967     glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
00968     mTexture->setDirty();
00969 
00970     return true;
00971     }
00972 
00973 void GLRenderTarget::initFBO()
00974     {
00975     glGenFramebuffers(1, &mFramebuffer);
00976     glBindFramebuffer(GL_FRAMEBUFFER_EXT, mFramebuffer);
00977 
00978     glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
00979                            mTexture->target(), mTexture->texture(), 0);
00980 
00981     GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
00982     if(status != GL_FRAMEBUFFER_COMPLETE_EXT)
00983         {
00984         kError(1212) << "Invalid fb status: " << status << endl;
00985         }
00986 
00987     glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
00988 
00989     mValid = true;
00990     }
00991 
00992 } // namespace
00993 
00994 #endif

KWinLibraries

Skip menu "KWinLibraries"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal