Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / kwin / lib / kwinglutils.cpp
blob0d047ce4fbbf496ae66691b1f8651bebd35ed065
1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 2006-2007 Rivo Laks <rivolaks@hot.ee>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
21 #include "kwinglutils.h"
23 #ifdef KWIN_HAVE_OPENGL
25 #include "kwinglobals.h"
26 #include "kwineffects.h"
28 #include "kdebug.h"
29 #include <kstandarddirs.h>
31 #include <QPixmap>
32 #include <QImage>
33 #include <QHash>
34 #include <QFile>
38 #define MAKE_GL_VERSION(major, minor, release) ( ((major) << 16) | ((minor) << 8) | (release) )
41 namespace KWin
43 // Variables
44 // GL version, use MAKE_GL_VERSION() macro for comparing with a specific version
45 static int glVersion;
46 // GLX version, use MAKE_GL_VERSION() macro for comparing with a specific version
47 static int glXVersion;
48 // List of all supported GL and GLX extensions
49 static QStringList glExtensions;
50 static QStringList glxExtensions;
52 int glTextureUnitsCount;
55 // Functions
56 void initGLX()
58 // Get GLX version
59 int major, minor;
60 glXQueryVersion( display(), &major, &minor );
61 glXVersion = MAKE_GL_VERSION( major, minor, 0 );
62 // Get list of supported GLX extensions
63 glxExtensions = QString((const char*)glXQueryExtensionsString(
64 display(), DefaultScreen( display()))).split(" ");
66 glxResolveFunctions();
69 void initGL()
71 // Get OpenGL version
72 QString glversionstring = QString((const char*)glGetString(GL_VERSION));
73 QStringList glversioninfo = glversionstring.left(glversionstring.indexOf(' ')).split('.');
74 glVersion = MAKE_GL_VERSION(glversioninfo[0].toInt(), glversioninfo[1].toInt(),
75 glversioninfo.count() > 2 ? glversioninfo[2].toInt() : 0);
76 // Get list of supported OpenGL extensions
77 glExtensions = QString((const char*)glGetString(GL_EXTENSIONS)).split(" ");
79 // handle OpenGL extensions functions
80 glResolveFunctions();
82 GLTexture::initStatic();
83 GLShader::initStatic();
84 GLRenderTarget::initStatic();
87 bool hasGLVersion(int major, int minor, int release)
89 return glVersion >= MAKE_GL_VERSION(major, minor, release);
92 bool hasGLXVersion(int major, int minor, int release)
94 return glXVersion >= MAKE_GL_VERSION(major, minor, release);
97 bool hasGLExtension(const QString& extension)
99 return glExtensions.contains(extension) || glxExtensions.contains(extension);
102 bool checkGLError( const char* txt )
104 GLenum err = glGetError();
105 if( err != GL_NO_ERROR )
107 kWarning() << "GL error (" << txt << "): 0x" << QString::number( err, 16 ) ;
108 return true;
110 return false;
113 int nearestPowerOfTwo( int x )
115 // This method had been copied from Qt's nearest_gl_texture_size()
116 int n = 0, last = 0;
117 for (int s = 0; s < 32; ++s) {
118 if (((x>>s) & 1) == 1) {
119 ++n;
120 last = s;
123 if (n > 1)
124 return 1 << (last+1);
125 return 1 << last;
128 void renderGLGeometry( int count, const float* vertices, const float* texture, const float* color,
129 int dim, int stride )
131 return renderGLGeometry( infiniteRegion(), count, vertices, texture, color, dim, stride );
134 void renderGLGeometry( const QRegion& region, int count,
135 const float* vertices, const float* texture, const float* color,
136 int dim, int stride )
138 // Using arrays only makes sense if we have larger number of vertices.
139 // Otherwise overhead of enabling/disabling them is too big.
140 bool use_arrays = (count > 5);
142 if( use_arrays )
144 glPushAttrib( GL_ENABLE_BIT );
145 glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
146 // Enable arrays
147 glEnableClientState( GL_VERTEX_ARRAY );
148 glVertexPointer( dim, GL_FLOAT, stride, vertices );
149 if( texture != NULL )
151 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
152 glTexCoordPointer( 2, GL_FLOAT, stride, texture );
154 if( color != NULL )
156 glEnableClientState( GL_COLOR_ARRAY );
157 glColorPointer( 4, GL_FLOAT, stride, color );
161 // Clip using scissoring
162 PaintClipper pc( region );
163 for( PaintClipper::Iterator iterator;
164 !iterator.isDone();
165 iterator.next())
167 if( use_arrays )
168 glDrawArrays( GL_QUADS, 0, count );
169 else
170 renderGLGeometryImmediate( count, vertices, texture, color, dim, stride );
173 if( use_arrays )
175 glPopClientAttrib();
176 glPopAttrib();
180 void renderGLGeometryImmediate( int count, const float* vertices, const float* texture, const float* color,
181 int dim, int stride )
183 // Find out correct glVertex*fv function according to dim parameter.
184 void ( *glVertexFunc )( const float* ) = glVertex2fv;
185 if( dim == 3 )
186 glVertexFunc = glVertex3fv;
187 else if( dim == 4 )
188 glVertexFunc = glVertex4fv;
190 // These are number of _floats_ per item, not _bytes_ per item as opengl uses.
191 int vsize, tsize, csize;
192 vsize = tsize = csize = stride / sizeof(float);
193 if( !stride )
195 // 0 means that arrays are tightly packed. This gives us different
196 // strides for different arrays
197 vsize = dim;
198 tsize = 2;
199 csize = 4;
202 glBegin( GL_QUADS );
203 // This sucks. But makes it faster.
204 if( texture && color )
206 for( int i = 0; i < count; i++ )
208 glTexCoord2fv( texture + i*tsize );
209 glColor4fv( color + i*csize );
210 glVertexFunc( vertices + i*vsize );
213 else if( texture )
215 for( int i = 0; i < count; i++ )
217 glTexCoord2fv( texture + i*tsize );
218 glVertexFunc( vertices + i*vsize );
221 else if( color )
223 for( int i = 0; i < count; i++ )
225 glColor4fv( color + i*csize );
226 glVertexFunc( vertices + i*vsize );
229 else
231 for( int i = 0; i < count; i++ )
232 glVertexFunc( vertices + i*vsize );
234 glEnd();
237 void addQuadVertices(QVector<float>& verts, float x1, float y1, float x2, float y2)
239 verts << x1 << y1;
240 verts << x1 << y2;
241 verts << x2 << y2;
242 verts << x2 << y1;
245 void renderRoundBox( const QRect& area, float roundness, GLTexture* texture )
247 static GLTexture* circleTexture = 0;
248 if( !texture && !circleTexture )
250 QString texturefile = KGlobal::dirs()->findResource("data", "kwin/circle.png");
251 circleTexture = new GLTexture(texturefile);
253 if( !texture )
255 texture = circleTexture;
258 glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT );
259 glEnable( GL_BLEND );
260 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
262 glPushMatrix();
264 QVector<float> verts, texcoords;
265 verts.reserve(80);
266 texcoords.reserve(80);
267 // center
268 addQuadVertices(verts, area.left() + roundness, area.top() + roundness, area.right() - roundness, area.bottom() - roundness);
269 addQuadVertices(texcoords, 0.5, 0.5, 0.5, 0.5);
270 // sides
271 // left
272 addQuadVertices(verts, area.left(), area.top() + roundness, area.left() + roundness, area.bottom() - roundness);
273 addQuadVertices(texcoords, 0.0, 0.5, 0.5, 0.5);
274 // top
275 addQuadVertices(verts, area.left() + roundness, area.top(), area.right() - roundness, area.top() + roundness);
276 addQuadVertices(texcoords, 0.5, 0.0, 0.5, 0.5);
277 // right
278 addQuadVertices(verts, area.right() - roundness, area.top() + roundness, area.right(), area.bottom() - roundness);
279 addQuadVertices(texcoords, 0.5, 0.5, 1.0, 0.5);
280 // bottom
281 addQuadVertices(verts, area.left() + roundness, area.bottom() - roundness, area.right() - roundness, area.bottom());
282 addQuadVertices(texcoords, 0.5, 0.5, 0.5, 1.0);
283 // corners
284 // top-left
285 addQuadVertices(verts, area.left(), area.top(), area.left() + roundness, area.top() + roundness);
286 addQuadVertices(texcoords, 0.0, 0.0, 0.5, 0.5);
287 // top-right
288 addQuadVertices(verts, area.right() - roundness, area.top(), area.right(), area.top() + roundness);
289 addQuadVertices(texcoords, 0.5, 0.0, 1.0, 0.5);
290 // bottom-left
291 addQuadVertices(verts, area.left(), area.bottom() - roundness, area.left() + roundness, area.bottom());
292 addQuadVertices(texcoords, 0.0, 0.5, 0.5, 1.0);
293 // bottom-right
294 addQuadVertices(verts, area.right() - roundness, area.bottom() - roundness, area.right(), area.bottom());
295 addQuadVertices(texcoords, 0.5, 0.5, 1.0, 1.0);
297 texture->bind();
298 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
299 // We have two elements per vertex in the verts array
300 int verticesCount = verts.count() / 2;
301 renderGLGeometry( verticesCount, verts.data(), texcoords.data() );
302 texture->unbind();
304 glPopMatrix();
305 glPopAttrib();
308 void renderRoundBoxWithEdge( const QRect& area, float roundness )
310 static GLTexture* texture = 0;
311 if( !texture )
313 QString texturefile = KGlobal::dirs()->findResource("data", "kwin/circle-edgy.png");
314 texture = new GLTexture(texturefile);
316 renderRoundBox( area, roundness, texture );
319 //****************************************
320 // GLTexture
321 //****************************************
323 bool GLTexture::mNPOTTextureSupported = false;
324 bool GLTexture::mFramebufferObjectSupported = false;
325 bool GLTexture::mSaturationSupported = false;
327 GLTexture::GLTexture()
329 init();
332 GLTexture::GLTexture( const QImage& image, GLenum target )
334 init();
335 load( image, target );
338 GLTexture::GLTexture( const QPixmap& pixmap, GLenum target )
340 init();
341 load( pixmap, target );
344 GLTexture::GLTexture( const QString& fileName )
346 init();
347 load( fileName );
350 GLTexture::GLTexture( int width, int height )
352 init();
354 if( NPOTTextureSupported() || ( isPowerOfTwo( width ) && isPowerOfTwo( height )))
356 mTarget = GL_TEXTURE_2D;
357 mScale.setWidth( 1.0 / width);
358 mScale.setHeight( 1.0 / height);
359 can_use_mipmaps = true;
361 glGenTextures( 1, &mTexture );
362 bind();
363 glTexImage2D( mTarget, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
364 unbind();
368 GLTexture::~GLTexture()
370 discard();
373 void GLTexture::init()
375 mTexture = None;
376 mTarget = 0;
377 mFilter = 0;
378 y_inverted = false;
379 can_use_mipmaps = false;
380 has_valid_mipmaps = false;
383 void GLTexture::initStatic()
385 mNPOTTextureSupported = hasGLExtension( "GL_ARB_texture_non_power_of_two" );
386 mFramebufferObjectSupported = hasGLExtension( "GL_EXT_framebuffer_object" );
387 mSaturationSupported = ((hasGLExtension("GL_ARB_texture_env_crossbar")
388 && hasGLExtension("GL_ARB_texture_env_dot3")) || hasGLVersion(1, 4))
389 && (glTextureUnitsCount >= 4) && glActiveTexture != NULL;
392 bool GLTexture::isNull() const
394 return mTexture == None;
397 bool GLTexture::load( const QImage& image, GLenum target )
399 if( image.isNull())
400 return false;
401 QImage img = image;
402 mTarget = target;
403 if( mTarget != GL_TEXTURE_RECTANGLE_ARB )
405 if( !NPOTTextureSupported()
406 && ( !isPowerOfTwo( image.width()) || !isPowerOfTwo( image.height())))
407 { // non-rectangular target requires POT texture
408 img = img.scaled( nearestPowerOfTwo( image.width()),
409 nearestPowerOfTwo( image.height()));
411 mScale.setWidth( 1.0 / img.width());
412 mScale.setHeight( 1.0 / img.height());
413 can_use_mipmaps = true;
415 else
417 mScale.setWidth( 1.0 );
418 mScale.setHeight( 1.0 );
419 can_use_mipmaps = false;
421 setFilter( GL_LINEAR );
422 mSize = img.size();
423 y_inverted = false;
425 img = convertToGLFormat( img );
427 setDirty();
428 if( isNull())
429 glGenTextures( 1, &mTexture );
430 bind();
431 glTexImage2D( mTarget, 0, GL_RGBA, img.width(), img.height(), 0,
432 GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
433 unbind();
434 return true;
437 bool GLTexture::load( const QPixmap& pixmap, GLenum target )
439 if( pixmap.isNull())
440 return false;
441 return load( pixmap.toImage(), target );
444 bool GLTexture::load( const QString& fileName )
446 if( fileName.isEmpty())
447 return false;
448 return load( QImage( fileName ));
451 void GLTexture::discard()
453 setDirty();
454 if( mTexture != None )
455 glDeleteTextures( 1, &mTexture );
456 mTexture = None;
459 void GLTexture::bind()
461 glEnable( mTarget );
462 glBindTexture( mTarget, mTexture );
463 enableFilter();
466 void GLTexture::unbind()
468 glBindTexture( mTarget, 0 );
469 glDisable( mTarget );
472 void GLTexture::render( QRegion region, const QRect& rect )
474 const float verts[ 4 * 2 ] =
476 rect.x(), rect.y(),
477 rect.x(), rect.y() + rect.height(),
478 rect.x() + rect.width(), rect.y() + rect.height(),
479 rect.x() + rect.width(), rect.y()
481 const float texcoords[ 4 * 2 ] =
483 0, 1,
484 0, 0,
485 1, 0,
486 1, 1
488 renderGLGeometry( region, 4, verts, texcoords );
491 void GLTexture::enableUnnormalizedTexCoords()
493 // update texture matrix to handle GL_TEXTURE_2D and GL_TEXTURE_RECTANGLE
494 glMatrixMode( GL_TEXTURE );
495 glPushMatrix();
496 glLoadIdentity();
497 glScalef( mScale.width(), mScale.height(), 1 );
498 if( !y_inverted )
500 // Modify texture matrix so that we could always use non-opengl
501 // coordinates for textures
502 glScalef( 1, -1, 1 );
503 glTranslatef( 0, -mSize.height(), 0 );
505 glMatrixMode( GL_MODELVIEW );
508 void GLTexture::disableUnnormalizedTexCoords()
510 // Restore texture matrix
511 glMatrixMode( GL_TEXTURE );
512 glPopMatrix();
513 glMatrixMode( GL_MODELVIEW );
516 GLuint GLTexture::texture() const
518 return mTexture;
521 GLenum GLTexture::target() const
523 return mTarget;
526 GLenum GLTexture::filter() const
528 return mFilter;
531 bool GLTexture::isDirty() const
533 return has_valid_mipmaps;
536 void GLTexture::setTexture( GLuint texture )
538 discard();
539 mTexture = texture;
542 void GLTexture::setTarget( GLenum target )
544 mTarget = target;
547 void GLTexture::setFilter( GLenum filter )
549 mFilter = filter;
552 void GLTexture::setWrapMode( GLenum mode )
554 bind();
555 glTexParameteri( mTarget, GL_TEXTURE_WRAP_S, mode );
556 glTexParameteri( mTarget, GL_TEXTURE_WRAP_T, mode );
557 unbind();
560 void GLTexture::setDirty()
562 has_valid_mipmaps = false;
566 void GLTexture::enableFilter()
568 if( mFilter == GL_LINEAR_MIPMAP_LINEAR )
569 { // trilinear filtering requested, but is it possible?
570 if( NPOTTextureSupported()
571 && framebufferObjectSupported()
572 && can_use_mipmaps )
574 glTexParameteri( mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
575 glTexParameteri( mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
576 if( !has_valid_mipmaps )
578 glGenerateMipmap( mTarget );
579 has_valid_mipmaps = true;
582 else
583 { // can't use trilinear, so use bilinear
584 setFilter( GL_LINEAR );
585 glTexParameteri( mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
586 glTexParameteri( mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
589 else if( mFilter == GL_LINEAR )
591 glTexParameteri( mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
592 glTexParameteri( mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
594 else
595 { // if neither trilinear nor bilinear, default to fast filtering
596 setFilter( GL_NEAREST );
597 glTexParameteri( mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
598 glTexParameteri( mTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
602 QImage GLTexture::convertToGLFormat( const QImage& img ) const
604 // This method has been copied from Qt's QGLWidget::convertToGLFormat()
605 QImage res = img.convertToFormat(QImage::Format_ARGB32);
606 res = res.mirrored();
608 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
609 // Qt has ARGB; OpenGL wants RGBA
610 for (int i=0; i < res.height(); i++) {
611 uint *p = (uint*)res.scanLine(i);
612 uint *end = p + res.width();
613 while (p < end) {
614 *p = (*p << 8) | ((*p >> 24) & 0xFF);
615 p++;
619 else {
620 // Qt has ARGB; OpenGL wants ABGR (i.e. RGBA backwards)
621 res = res.rgbSwapped();
623 return res;
626 //****************************************
627 // GLShader
628 //****************************************
630 bool GLShader::mFragmentShaderSupported = false;
631 bool GLShader::mVertexShaderSupported = false;
633 void GLShader::initStatic()
635 mFragmentShaderSupported = mVertexShaderSupported =
636 hasGLExtension("GL_ARB_shader_objects") && hasGLExtension("GL_ARB_shading_language_100");
637 mVertexShaderSupported &= hasGLExtension("GL_ARB_vertex_shader");
638 mFragmentShaderSupported &= hasGLExtension("GL_ARB_fragment_shader");
642 GLShader::GLShader(const QString& vertexfile, const QString& fragmentfile)
644 mValid = false;
645 mVariableLocations = 0;
646 mProgram = 0;
648 loadFromFiles(vertexfile, fragmentfile);
651 GLShader::~GLShader()
653 if(mVariableLocations)
655 mVariableLocations->clear();
656 delete mVariableLocations;
659 if(mProgram)
661 glDeleteProgram(mProgram);
665 bool GLShader::loadFromFiles(const QString& vertexfile, const QString& fragmentfile)
667 QFile vf(vertexfile);
668 if(!vf.open(QIODevice::ReadOnly))
670 kError(1212) << "Couldn't open '" << vertexfile << "' for reading!" << endl;
671 return false;
673 QString vertexsource(vf.readAll());
675 QFile ff(fragmentfile);
676 if(!ff.open(QIODevice::ReadOnly))
678 kError(1212) << "Couldn't open '" << fragmentfile << "' for reading!" << endl;
679 return false;
681 QString fragsource(ff.readAll());
683 return load(vertexsource, fragsource);
686 bool GLShader::load(const QString& vertexsource, const QString& fragmentsource)
688 // Make sure shaders are actually supported
689 if(( !vertexsource.isEmpty() && !vertexShaderSupported() ) ||
690 ( !fragmentsource.isEmpty() && !fragmentShaderSupported() ))
692 kDebug(1212) << "Shaders not supported";
693 return false;
696 GLuint vertexshader;
697 GLuint fragmentshader;
699 GLsizei logsize, logarraysize;
700 char* log = 0;
702 // Create program object
703 mProgram = glCreateProgram();
704 if(!vertexsource.isEmpty())
706 // Create shader object
707 vertexshader = glCreateShader(GL_VERTEX_SHADER);
708 // Load it
709 const QByteArray& srcba = vertexsource.toLatin1();
710 const char* src = srcba.data();
711 glShaderSource(vertexshader, 1, &src, NULL);
712 // Compile the shader
713 glCompileShader(vertexshader);
714 // Make sure it compiled correctly
715 int compiled;
716 glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &compiled);
717 // Get info log
718 glGetShaderiv(vertexshader, GL_INFO_LOG_LENGTH, &logarraysize);
719 log = new char[logarraysize];
720 glGetShaderInfoLog(vertexshader, logarraysize, &logsize, log);
721 if(!compiled)
723 kError(1212) << "Couldn't compile vertex shader! Log:" << endl << log << endl;
724 delete[] log;
725 return false;
727 else if(logsize > 0)
728 kDebug(1212) << "Vertex shader compilation log:"<< log;
729 // Attach the shader to the program
730 glAttachShader(mProgram, vertexshader);
731 // Delete shader
732 glDeleteShader(vertexshader);
733 delete[] log;
737 if(!fragmentsource.isEmpty())
739 fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
740 // Load it
741 const QByteArray& srcba = fragmentsource.toLatin1();
742 const char* src = srcba.data();
743 glShaderSource(fragmentshader, 1, &src, NULL);
744 //glShaderSource(fragmentshader, 1, &fragmentsrc.latin1(), NULL);
745 // Compile the shader
746 glCompileShader(fragmentshader);
747 // Make sure it compiled correctly
748 int compiled;
749 glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &compiled);
750 // Get info log
751 glGetShaderiv(fragmentshader, GL_INFO_LOG_LENGTH, &logarraysize);
752 log = new char[logarraysize];
753 glGetShaderInfoLog(fragmentshader, logarraysize, &logsize, log);
754 if(!compiled)
756 kError(1212) << "Couldn't compile fragment shader! Log:" << endl << log << endl;
757 delete[] log;
758 return false;
760 else if(logsize > 0)
761 kDebug(1212) << "Fragment shader compilation log:"<< log;
762 // Attach the shader to the program
763 glAttachShader(mProgram, fragmentshader);
764 // Delete shader
765 glDeleteShader(fragmentshader);
766 delete[] log;
770 // Link the program
771 glLinkProgram(mProgram);
772 // Make sure it linked correctly
773 int linked;
774 glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
775 // Get info log
776 glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &logarraysize);
777 log = new char[logarraysize];
778 glGetProgramInfoLog(mProgram, logarraysize, &logsize, log);
779 if(!linked)
781 kError(1212) << "Couldn't link the program! Log" << endl << log << endl;
782 delete[] log;
783 return false;
785 else if(logsize > 0)
786 kDebug(1212) << "Shader linking log:"<< log;
787 delete[] log;
789 mVariableLocations = new QHash<QString, int>;
791 mValid = true;
792 return true;
795 void GLShader::bind()
797 glUseProgram(mProgram);
800 void GLShader::unbind()
802 glUseProgram(0);
805 int GLShader::uniformLocation(const QString& name)
807 if(!mVariableLocations)
809 return -1;
811 if(!mVariableLocations->contains(name))
813 int location = glGetUniformLocation(mProgram, name.toLatin1().data());
814 mVariableLocations->insert(name, location);
816 return mVariableLocations->value(name);
819 bool GLShader::setUniform(const QString& name, float value)
821 int location = uniformLocation(name);
822 if(location >= 0)
824 glUniform1f(location, value);
826 return (location >= 0);
829 bool GLShader::setUniform(const QString& name, int value)
831 int location = uniformLocation(name);
832 if(location >= 0)
834 glUniform1i(location, value);
836 return (location >= 0);
839 int GLShader::attributeLocation(const QString& name)
841 if(!mVariableLocations)
843 return -1;
845 if(!mVariableLocations->contains(name))
847 int location = glGetAttribLocation(mProgram, name.toLatin1().data());
848 mVariableLocations->insert(name, location);
850 return mVariableLocations->value(name);
853 bool GLShader::setAttribute(const QString& name, float value)
855 int location = attributeLocation(name);
856 if(location >= 0)
858 glVertexAttrib1f(location, value);
860 return (location >= 0);
865 /*** GLRenderTarget ***/
866 bool GLRenderTarget::mSupported = false;
868 void GLRenderTarget::initStatic()
870 mSupported = hasGLExtension("GL_EXT_framebuffer_object") && glFramebufferTexture2D;
873 GLRenderTarget::GLRenderTarget(GLTexture* color)
875 // Reset variables
876 mValid = false;
878 mTexture = color;
880 // Make sure FBO is supported
881 if(mSupported && mTexture && !mTexture->isNull())
883 initFBO();
885 else
886 kError(1212) << "Render targets aren't supported!" << endl;
889 GLRenderTarget::~GLRenderTarget()
891 if(mValid)
893 glDeleteFramebuffers(1, &mFramebuffer);
897 bool GLRenderTarget::enable()
899 if(!valid())
901 kError(1212) << "Can't enable invalid render target!" << endl;
902 return false;
905 glBindFramebuffer(GL_FRAMEBUFFER_EXT, mFramebuffer);
906 mTexture->setDirty();
908 return true;
911 bool GLRenderTarget::disable()
913 if(!valid())
915 kError(1212) << "Can't disable invalid render target!" << endl;
916 return false;
919 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
920 mTexture->setDirty();
922 return true;
925 void GLRenderTarget::initFBO()
927 glGenFramebuffers(1, &mFramebuffer);
928 glBindFramebuffer(GL_FRAMEBUFFER_EXT, mFramebuffer);
930 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
931 mTexture->target(), mTexture->texture(), 0);
933 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
934 if(status != GL_FRAMEBUFFER_COMPLETE_EXT)
936 kError(1212) << "Invalid fb status: " << status << endl;
939 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
941 mValid = true;
944 } // namespace
946 #endif