• Skip to content
  • Skip to link menu
KDE 4.1 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() << "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     renderGLGeometry( verticesCount, verts.data(), texcoords.data() );
00302     texture->unbind();
00303 
00304     glPopMatrix();
00305     glPopAttrib();
00306 }
00307 
00308 void renderRoundBoxWithEdge( const QRect& area, float roundness )
00309 {
00310     static GLTexture* texture = 0;
00311     if( !texture )
00312     {
00313         QString texturefile =  KGlobal::dirs()->findResource("data", "kwin/circle-edgy.png");
00314         texture = new GLTexture(texturefile);
00315     }
00316     renderRoundBox( area, roundness, texture );
00317 }
00318 
00319 //****************************************
00320 // GLTexture
00321 //****************************************
00322 
00323 bool GLTexture::mNPOTTextureSupported = false;
00324 bool GLTexture::mFramebufferObjectSupported = false;
00325 bool GLTexture::mSaturationSupported = false;
00326 
00327 GLTexture::GLTexture()
00328     {
00329     init();
00330     }
00331 
00332 GLTexture::GLTexture( const QImage& image, GLenum target )
00333     {
00334     init();
00335     load( image, target );
00336     }
00337 
00338 GLTexture::GLTexture( const QPixmap& pixmap, GLenum target )
00339     {
00340     init();
00341     load( pixmap, target );
00342     }
00343 
00344 GLTexture::GLTexture( const QString& fileName )
00345     {
00346     init();
00347     load( fileName );
00348     }
00349 
00350 GLTexture::GLTexture( int width, int height )
00351     {
00352     init();
00353 
00354     if( NPOTTextureSupported() || ( isPowerOfTwo( width ) && isPowerOfTwo( height )))
00355         {
00356         mTarget = GL_TEXTURE_2D;
00357         mScale.setWidth( 1.0 / width);
00358         mScale.setHeight( 1.0 / height);
00359         can_use_mipmaps = true;
00360 
00361         glGenTextures( 1, &mTexture );
00362         bind();
00363         glTexImage2D( mTarget, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
00364         unbind();
00365         }
00366     }
00367 
00368 GLTexture::~GLTexture()
00369     {
00370     discard();
00371     }
00372 
00373 void GLTexture::init()
00374     {
00375     mTexture = None;
00376     mTarget = 0;
00377     mFilter = 0;
00378     y_inverted = false;
00379     can_use_mipmaps = false;
00380     has_valid_mipmaps = false;
00381     }
00382 
00383 void GLTexture::initStatic()
00384     {
00385     mNPOTTextureSupported = hasGLExtension( "GL_ARB_texture_non_power_of_two" );
00386     mFramebufferObjectSupported = hasGLExtension( "GL_EXT_framebuffer_object" );
00387     mSaturationSupported = ((hasGLExtension("GL_ARB_texture_env_crossbar")
00388         && hasGLExtension("GL_ARB_texture_env_dot3")) || hasGLVersion(1, 4))
00389         && (glTextureUnitsCount >= 4) && glActiveTexture != NULL;
00390     }
00391 
00392 bool GLTexture::isNull() const
00393     {
00394     return mTexture == None;
00395     }
00396 
00397 QSize GLTexture::size() const
00398     {
00399     return mSize;
00400     }
00401 
00402 bool GLTexture::load( const QImage& image, GLenum target )
00403     {
00404     if( image.isNull())
00405         return false;
00406     QImage img = image;
00407     mTarget = target;
00408     if( mTarget != GL_TEXTURE_RECTANGLE_ARB )
00409         {
00410         if( !NPOTTextureSupported()
00411             && ( !isPowerOfTwo( image.width()) || !isPowerOfTwo( image.height())))
00412             { // non-rectangular target requires POT texture
00413             img = img.scaled( nearestPowerOfTwo( image.width()),
00414                     nearestPowerOfTwo( image.height()));
00415             }
00416         mScale.setWidth( 1.0 / img.width());
00417         mScale.setHeight( 1.0 / img.height());
00418         can_use_mipmaps = true;
00419         }
00420     else
00421         {
00422         mScale.setWidth( 1.0 );
00423         mScale.setHeight( 1.0 );
00424         can_use_mipmaps = false;
00425         }
00426     setFilter( GL_LINEAR );
00427     mSize = img.size();
00428     y_inverted = false;
00429 
00430     img = convertToGLFormat( img );
00431 
00432     setDirty();
00433     if( isNull())
00434         glGenTextures( 1, &mTexture );
00435     bind();
00436     glTexImage2D( mTarget, 0, GL_RGBA, img.width(), img.height(), 0,
00437         GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
00438     unbind();
00439     return true;
00440     }
00441 
00442 bool GLTexture::load( const QPixmap& pixmap, GLenum target )
00443     {
00444     if( pixmap.isNull())
00445         return false;
00446     return load( pixmap.toImage(), target );
00447     }
00448 
00449 bool GLTexture::load( const QString& fileName )
00450     {
00451     if( fileName.isEmpty())
00452         return false;
00453     return load( QImage( fileName ));
00454     }
00455 
00456 void GLTexture::discard()
00457     {
00458     setDirty();
00459     if( mTexture != None )
00460         glDeleteTextures( 1, &mTexture );
00461     mTexture = None;
00462     }
00463 
00464 void GLTexture::bind()
00465     {
00466     glEnable( mTarget );
00467     glBindTexture( mTarget, mTexture );
00468     enableFilter();
00469     }
00470 
00471 void GLTexture::unbind()
00472     {
00473     glBindTexture( mTarget, 0 );
00474     glDisable( mTarget );
00475     }
00476 
00477 void GLTexture::render( QRegion region, const QRect& rect )
00478     {
00479     const float verts[ 4 * 2 ] =
00480         {
00481         rect.x(), rect.y(),
00482         rect.x(), rect.y() + rect.height(),
00483         rect.x() + rect.width(), rect.y() + rect.height(),
00484         rect.x() + rect.width(), rect.y()
00485         };
00486     const float texcoords[ 4 * 2 ] =
00487         {
00488         0, 1,
00489         0, 0,
00490         1, 0,
00491         1, 1
00492         };
00493     renderGLGeometry( region, 4, verts, texcoords );
00494     }
00495 
00496 void GLTexture::enableUnnormalizedTexCoords()
00497     {
00498     // update texture matrix to handle GL_TEXTURE_2D and GL_TEXTURE_RECTANGLE
00499     glMatrixMode( GL_TEXTURE );
00500     glPushMatrix();
00501     glLoadIdentity();
00502     glScalef( mScale.width(), mScale.height(), 1 );
00503     if( !y_inverted )
00504         {
00505         // Modify texture matrix so that we could always use non-opengl
00506         //  coordinates for textures
00507         glScalef( 1, -1, 1 );
00508         glTranslatef( 0, -mSize.height(), 0 );
00509         }
00510     glMatrixMode( GL_MODELVIEW );
00511     }
00512 
00513 void GLTexture::disableUnnormalizedTexCoords()
00514     {
00515     // Restore texture matrix
00516     glMatrixMode( GL_TEXTURE );
00517     glPopMatrix();
00518     glMatrixMode( GL_MODELVIEW );
00519     }
00520 
00521 GLuint GLTexture::texture() const
00522     {
00523     return mTexture;
00524     }
00525 
00526 GLenum GLTexture::target() const
00527     {
00528     return mTarget;
00529     }
00530 
00531 GLenum GLTexture::filter() const
00532     {
00533     return mFilter;
00534     }
00535 
00536 bool GLTexture::isDirty() const
00537     {
00538     return has_valid_mipmaps;
00539     }
00540 
00541 void GLTexture::setTexture( GLuint texture )
00542     {
00543     discard();
00544     mTexture = texture;
00545     }
00546 
00547 void GLTexture::setTarget( GLenum target )
00548     {
00549     mTarget = target;
00550     }
00551 
00552 void GLTexture::setFilter( GLenum filter )
00553     {
00554     mFilter = filter;
00555     }
00556 
00557 void GLTexture::setWrapMode( GLenum mode )
00558     {
00559     bind();
00560     glTexParameteri( mTarget, GL_TEXTURE_WRAP_S, mode );
00561     glTexParameteri( mTarget, GL_TEXTURE_WRAP_T, mode );
00562     unbind();
00563     }
00564 
00565 void GLTexture::setDirty()
00566     {
00567     has_valid_mipmaps = false;
00568     }
00569 
00570 
00571 void GLTexture::enableFilter()
00572     {
00573     if( mFilter == GL_LINEAR_MIPMAP_LINEAR )
00574         { // trilinear filtering requested, but is it possible?
00575         if( NPOTTextureSupported()
00576             && framebufferObjectSupported()
00577             && can_use_mipmaps )
00578             {
00579             glTexParameteri( mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
00580             glTexParameteri( mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00581             if( !has_valid_mipmaps )
00582                 {
00583                 glGenerateMipmap( mTarget );
00584                 has_valid_mipmaps = true;
00585                 }
00586             }
00587         else
00588             { // can't use trilinear, so use bilinear
00589             setFilter( GL_LINEAR );
00590             glTexParameteri( mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
00591             glTexParameteri( mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00592             }
00593         }
00594     else if( mFilter == GL_LINEAR )
00595         {
00596         glTexParameteri( mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
00597         glTexParameteri( mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00598         }
00599     else
00600         { // if neither trilinear nor bilinear, default to fast filtering
00601         setFilter( GL_NEAREST );
00602         glTexParameteri( mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
00603         glTexParameteri( mTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
00604         }
00605     }
00606 
00607 QImage GLTexture::convertToGLFormat( const QImage& img ) const
00608     {
00609     // This method has been copied from Qt's QGLWidget::convertToGLFormat()
00610     QImage res = img.convertToFormat(QImage::Format_ARGB32);
00611     res = res.mirrored();
00612 
00613     if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
00614         // Qt has ARGB; OpenGL wants RGBA
00615         for (int i=0; i < res.height(); i++) {
00616             uint *p = (uint*)res.scanLine(i);
00617             uint *end = p + res.width();
00618             while (p < end) {
00619                 *p = (*p << 8) | ((*p >> 24) & 0xFF);
00620                 p++;
00621             }
00622         }
00623     }
00624     else {
00625         // Qt has ARGB; OpenGL wants ABGR (i.e. RGBA backwards)
00626         res = res.rgbSwapped();
00627     }
00628     return res;
00629     }
00630 
00631 //****************************************
00632 // GLShader
00633 //****************************************
00634 
00635 bool GLShader::mFragmentShaderSupported = false;
00636 bool GLShader::mVertexShaderSupported = false;
00637 
00638 void GLShader::initStatic()
00639 {
00640     mFragmentShaderSupported = mVertexShaderSupported =
00641             hasGLExtension("GL_ARB_shader_objects") && hasGLExtension("GL_ARB_shading_language_100");
00642     mVertexShaderSupported &= hasGLExtension("GL_ARB_vertex_shader");
00643     mFragmentShaderSupported &= hasGLExtension("GL_ARB_fragment_shader");
00644 }
00645 
00646 
00647 GLShader::GLShader(const QString& vertexfile, const QString& fragmentfile)
00648     {
00649     mValid = false;
00650     mVariableLocations = 0;
00651     mProgram = 0;
00652 
00653     loadFromFiles(vertexfile, fragmentfile);
00654     }
00655 
00656 GLShader::~GLShader()
00657 {
00658     if(mVariableLocations)
00659     {
00660         mVariableLocations->clear();
00661         delete mVariableLocations;
00662     }
00663 
00664     if(mProgram)
00665     {
00666         glDeleteProgram(mProgram);
00667     }
00668 }
00669 
00670 bool GLShader::loadFromFiles(const QString& vertexfile, const QString& fragmentfile)
00671     {
00672     QFile vf(vertexfile);
00673     if(!vf.open(QIODevice::ReadOnly))
00674         {
00675         kError(1212) << "Couldn't open '" << vertexfile << "' for reading!" << endl;
00676         return false;
00677         }
00678     QString vertexsource(vf.readAll());
00679 
00680     QFile ff(fragmentfile);
00681     if(!ff.open(QIODevice::ReadOnly))
00682         {
00683         kError(1212) << "Couldn't open '" << fragmentfile << "' for reading!" << endl;
00684         return false;
00685         }
00686     QString fragsource(ff.readAll());
00687 
00688     return load(vertexsource, fragsource);
00689     }
00690 
00691 bool GLShader::load(const QString& vertexsource, const QString& fragmentsource)
00692     {
00693     // Make sure shaders are actually supported
00694     if(( !vertexsource.isEmpty() && !vertexShaderSupported() ) ||
00695           ( !fragmentsource.isEmpty() && !fragmentShaderSupported() ))
00696         {
00697         kDebug(1212) << "Shaders not supported";
00698         return false;
00699         }
00700 
00701     GLuint vertexshader;
00702     GLuint fragmentshader;
00703 
00704     GLsizei logsize, logarraysize;
00705     char* log = 0;
00706 
00707     // Create program object
00708     mProgram = glCreateProgram();
00709     if(!vertexsource.isEmpty())
00710         {
00711         // Create shader object
00712         vertexshader = glCreateShader(GL_VERTEX_SHADER);
00713         // Load it
00714         const QByteArray& srcba = vertexsource.toLatin1();
00715         const char* src = srcba.data();
00716         glShaderSource(vertexshader, 1, &src, NULL);
00717         // Compile the shader
00718         glCompileShader(vertexshader);
00719         // Make sure it compiled correctly
00720         int compiled;
00721         glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &compiled);
00722         // Get info log
00723         glGetShaderiv(vertexshader, GL_INFO_LOG_LENGTH, &logarraysize);
00724         log = new char[logarraysize];
00725         glGetShaderInfoLog(vertexshader, logarraysize, &logsize, log);
00726         if(!compiled)
00727             {
00728             kError(1212) << "Couldn't compile vertex shader! Log:" << endl << log << endl;
00729             delete[] log;
00730             return false;
00731             }
00732         else if(logsize > 0)
00733             kDebug(1212) << "Vertex shader compilation log:"<< log;
00734         // Attach the shader to the program
00735         glAttachShader(mProgram, vertexshader);
00736         // Delete shader
00737         glDeleteShader(vertexshader);
00738         delete[] log;
00739         }
00740 
00741 
00742     if(!fragmentsource.isEmpty())
00743         {
00744         fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
00745         // Load it
00746         const QByteArray& srcba = fragmentsource.toLatin1();
00747         const char* src = srcba.data();
00748         glShaderSource(fragmentshader, 1, &src, NULL);
00749         //glShaderSource(fragmentshader, 1, &fragmentsrc.latin1(), NULL);
00750         // Compile the shader
00751         glCompileShader(fragmentshader);
00752         // Make sure it compiled correctly
00753         int compiled;
00754         glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &compiled);
00755         // Get info log
00756         glGetShaderiv(fragmentshader, GL_INFO_LOG_LENGTH, &logarraysize);
00757         log = new char[logarraysize];
00758         glGetShaderInfoLog(fragmentshader, logarraysize, &logsize, log);
00759         if(!compiled)
00760             {
00761             kError(1212) << "Couldn't compile fragment shader! Log:" << endl << log << endl;
00762             delete[] log;
00763             return false;
00764             }
00765         else if(logsize > 0)
00766             kDebug(1212) << "Fragment shader compilation log:"<< log;
00767         // Attach the shader to the program
00768         glAttachShader(mProgram, fragmentshader);
00769         // Delete shader
00770         glDeleteShader(fragmentshader);
00771         delete[] log;
00772         }
00773 
00774 
00775     // Link the program
00776     glLinkProgram(mProgram);
00777     // Make sure it linked correctly
00778     int linked;
00779     glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
00780     // Get info log
00781     glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &logarraysize);
00782     log = new char[logarraysize];
00783     glGetProgramInfoLog(mProgram, logarraysize, &logsize, log);
00784     if(!linked)
00785         {
00786         kError(1212) << "Couldn't link the program! Log" << endl << log << endl;
00787         delete[] log;
00788         return false;
00789         }
00790     else if(logsize > 0)
00791         kDebug(1212) << "Shader linking log:"<< log;
00792     delete[] log;
00793 
00794     mVariableLocations = new QHash<QString, int>;
00795 
00796     mValid = true;
00797     return true;
00798     }
00799 
00800 void GLShader::bind()
00801     {
00802     glUseProgram(mProgram);
00803     }
00804 
00805 void GLShader::unbind()
00806     {
00807     glUseProgram(0);
00808     }
00809 
00810 int GLShader::uniformLocation(const QString& name)
00811     {
00812     if(!mVariableLocations)
00813         {
00814         return -1;
00815         }
00816     if(!mVariableLocations->contains(name))
00817         {
00818         int location = glGetUniformLocation(mProgram, name.toLatin1().data());
00819         mVariableLocations->insert(name, location);
00820         }
00821     return mVariableLocations->value(name);
00822     }
00823 
00824 bool GLShader::setUniform(const QString& name, float value)
00825     {
00826     int location = uniformLocation(name);
00827     if(location >= 0)
00828         {
00829         glUniform1f(location, value);
00830         }
00831     return (location >= 0);
00832     }
00833 
00834 bool GLShader::setUniform(const QString& name, int value)
00835     {
00836     int location = uniformLocation(name);
00837     if(location >= 0)
00838         {
00839         glUniform1i(location, value);
00840         }
00841     return (location >= 0);
00842     }
00843 
00844 int GLShader::attributeLocation(const QString& name)
00845     {
00846     if(!mVariableLocations)
00847         {
00848         return -1;
00849         }
00850     if(!mVariableLocations->contains(name))
00851         {
00852         int location = glGetAttribLocation(mProgram, name.toLatin1().data());
00853         mVariableLocations->insert(name, location);
00854         }
00855     return mVariableLocations->value(name);
00856     }
00857 
00858 bool GLShader::setAttribute(const QString& name, float value)
00859     {
00860     int location = attributeLocation(name);
00861     if(location >= 0)
00862         {
00863         glVertexAttrib1f(location, value);
00864         }
00865     return (location >= 0);
00866     }
00867 
00868 
00869 
00870 /***  GLRenderTarget  ***/
00871 bool GLRenderTarget::mSupported = false;
00872 
00873 void GLRenderTarget::initStatic()
00874     {
00875     mSupported = hasGLExtension("GL_EXT_framebuffer_object") && glFramebufferTexture2D;
00876     }
00877 
00878 GLRenderTarget::GLRenderTarget(GLTexture* color)
00879     {
00880     // Reset variables
00881     mValid = false;
00882 
00883     mTexture = color;
00884 
00885     // Make sure FBO is supported
00886     if(mSupported && mTexture && !mTexture->isNull())
00887         {
00888         initFBO();
00889         }
00890     else
00891         kError(1212) << "Render targets aren't supported!" << endl;
00892     }
00893 
00894 GLRenderTarget::~GLRenderTarget()
00895     {
00896     if(mValid)
00897         {
00898         glDeleteFramebuffers(1, &mFramebuffer);
00899         }
00900     }
00901 
00902 bool GLRenderTarget::enable()
00903     {
00904     if(!valid())
00905         {
00906         kError(1212) << "Can't enable invalid render target!" << endl;
00907         return false;
00908         }
00909 
00910     glBindFramebuffer(GL_FRAMEBUFFER_EXT, mFramebuffer);
00911     mTexture->setDirty();
00912 
00913     return true;
00914     }
00915 
00916 bool GLRenderTarget::disable()
00917     {
00918     if(!valid())
00919         {
00920         kError(1212) << "Can't disable invalid render target!" << endl;
00921         return false;
00922         }
00923 
00924     glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
00925     mTexture->setDirty();
00926 
00927     return true;
00928     }
00929 
00930 void GLRenderTarget::initFBO()
00931     {
00932     glGenFramebuffers(1, &mFramebuffer);
00933     glBindFramebuffer(GL_FRAMEBUFFER_EXT, mFramebuffer);
00934 
00935     glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
00936                            mTexture->target(), mTexture->texture(), 0);
00937 
00938     GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
00939     if(status != GL_FRAMEBUFFER_COMPLETE_EXT)
00940         {
00941         kError(1212) << "Invalid fb status: " << status << endl;
00942         }
00943 
00944     glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
00945 
00946     mValid = true;
00947     }
00948 
00949 } // namespace
00950 
00951 #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
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
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