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"
29 #include <kstandarddirs.h>
38 #define MAKE_GL_VERSION(major, minor, release) ( ((major) << 16) | ((minor) << 8) | (release) )
44 // GL version, use MAKE_GL_VERSION() macro for comparing with a specific version
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
;
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();
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
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(1212) << "GL error (" << txt
<< "): 0x" << QString::number( err
, 16 ) ;
113 int nearestPowerOfTwo( int x
)
115 // This method had been copied from Qt's nearest_gl_texture_size()
117 for (int s
= 0; s
< 32; ++s
) {
118 if (((x
>>s
) & 1) == 1) {
124 return 1 << (last
+1);
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);
144 glPushAttrib( GL_ENABLE_BIT
);
145 glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT
);
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
);
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
;
168 glDrawArrays( GL_QUADS
, 0, count
);
170 renderGLGeometryImmediate( count
, vertices
, texture
, color
, dim
, stride
);
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
;
186 glVertexFunc
= glVertex3fv
;
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);
195 // 0 means that arrays are tightly packed. This gives us different
196 // strides for different arrays
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
);
215 for( int i
= 0; i
< count
; i
++ )
217 glTexCoord2fv( texture
+ i
*tsize
);
218 glVertexFunc( vertices
+ i
*vsize
);
223 for( int i
= 0; i
< count
; i
++ )
225 glColor4fv( color
+ i
*csize
);
226 glVertexFunc( vertices
+ i
*vsize
);
231 for( int i
= 0; i
< count
; i
++ )
232 glVertexFunc( vertices
+ i
*vsize
);
237 void addQuadVertices(QVector
<float>& verts
, float x1
, float y1
, float x2
, float y2
)
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
);
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
);
264 QVector
<float> verts
, texcoords
;
266 texcoords
.reserve(80);
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);
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);
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);
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);
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);
285 addQuadVertices(verts
, area
.left(), area
.top(), area
.left() + roundness
, area
.top() + roundness
);
286 addQuadVertices(texcoords
, 0.0, 0.0, 0.5, 0.5);
288 addQuadVertices(verts
, area
.right() - roundness
, area
.top(), area
.right(), area
.top() + roundness
);
289 addQuadVertices(texcoords
, 0.5, 0.0, 1.0, 0.5);
291 addQuadVertices(verts
, area
.left(), area
.bottom() - roundness
, area
.left() + roundness
, area
.bottom());
292 addQuadVertices(texcoords
, 0.0, 0.5, 0.5, 1.0);
294 addQuadVertices(verts
, area
.right() - roundness
, area
.bottom() - roundness
, area
.right(), area
.bottom());
295 addQuadVertices(texcoords
, 0.5, 0.5, 1.0, 1.0);
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 texture
->enableNormalizedTexCoords();
302 renderGLGeometry( verticesCount
, verts
.data(), texcoords
.data() );
303 texture
->disableNormalizedTexCoords();
310 void renderRoundBoxWithEdge( const QRect
& area
, float roundness
)
312 static GLTexture
* texture
= 0;
315 QString texturefile
= KGlobal::dirs()->findResource("data", "kwin/circle-edgy.png");
316 texture
= new GLTexture(texturefile
);
318 renderRoundBox( area
, roundness
, texture
);
321 //****************************************
323 //****************************************
325 bool GLTexture::mNPOTTextureSupported
= false;
326 bool GLTexture::mFramebufferObjectSupported
= false;
327 bool GLTexture::mSaturationSupported
= false;
329 GLTexture::GLTexture()
334 GLTexture::GLTexture( const QImage
& image
, GLenum target
)
337 load( image
, target
);
340 GLTexture::GLTexture( const QPixmap
& pixmap
, GLenum target
)
343 load( pixmap
, target
);
346 GLTexture::GLTexture( const QString
& fileName
)
352 GLTexture::GLTexture( int width
, int height
)
356 if( NPOTTextureSupported() || ( isPowerOfTwo( width
) && isPowerOfTwo( height
)))
358 mTarget
= GL_TEXTURE_2D
;
359 mScale
.setWidth( 1.0 / width
);
360 mScale
.setHeight( 1.0 / height
);
361 can_use_mipmaps
= true;
363 glGenTextures( 1, &mTexture
);
365 glTexImage2D( mTarget
, 0, GL_RGBA
, width
, height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, 0);
370 GLTexture::~GLTexture()
373 assert( mUnnormalizeActive
== 0 );
374 assert( mNormalizeActive
== 0 );
377 void GLTexture::init()
383 can_use_mipmaps
= false;
384 has_valid_mipmaps
= false;
385 mUnnormalizeActive
= 0;
386 mNormalizeActive
= 0;
389 void GLTexture::initStatic()
391 mNPOTTextureSupported
= hasGLExtension( "GL_ARB_texture_non_power_of_two" );
392 mFramebufferObjectSupported
= hasGLExtension( "GL_EXT_framebuffer_object" );
393 mSaturationSupported
= ((hasGLExtension("GL_ARB_texture_env_crossbar")
394 && hasGLExtension("GL_ARB_texture_env_dot3")) || hasGLVersion(1, 4))
395 && (glTextureUnitsCount
>= 4) && glActiveTexture
!= NULL
;
398 bool GLTexture::isNull() const
400 return mTexture
== None
;
403 QSize
GLTexture::size() const
408 bool GLTexture::load( const QImage
& image
, GLenum target
)
414 if( mTarget
!= GL_TEXTURE_RECTANGLE_ARB
)
416 if( !NPOTTextureSupported()
417 && ( !isPowerOfTwo( image
.width()) || !isPowerOfTwo( image
.height())))
418 { // non-rectangular target requires POT texture
419 img
= img
.scaled( nearestPowerOfTwo( image
.width()),
420 nearestPowerOfTwo( image
.height()));
422 mScale
.setWidth( 1.0 / img
.width());
423 mScale
.setHeight( 1.0 / img
.height());
424 can_use_mipmaps
= true;
428 mScale
.setWidth( 1.0 );
429 mScale
.setHeight( 1.0 );
430 can_use_mipmaps
= false;
432 setFilter( GL_LINEAR
);
436 img
= convertToGLFormat( img
);
440 glGenTextures( 1, &mTexture
);
442 glTexImage2D( mTarget
, 0, GL_RGBA
, img
.width(), img
.height(), 0,
443 GL_RGBA
, GL_UNSIGNED_BYTE
, img
.bits());
448 bool GLTexture::load( const QPixmap
& pixmap
, GLenum target
)
452 return load( pixmap
.toImage(), target
);
455 bool GLTexture::load( const QString
& fileName
)
457 if( fileName
.isEmpty())
459 return load( QImage( fileName
));
462 void GLTexture::discard()
465 if( mTexture
!= None
)
466 glDeleteTextures( 1, &mTexture
);
470 void GLTexture::bind()
473 glBindTexture( mTarget
, mTexture
);
477 void GLTexture::unbind()
479 glBindTexture( mTarget
, 0 );
480 glDisable( mTarget
);
483 void GLTexture::render( QRegion region
, const QRect
& rect
)
485 const float verts
[ 4 * 2 ] =
488 rect
.x(), rect
.y() + rect
.height(),
489 rect
.x() + rect
.width(), rect
.y() + rect
.height(),
490 rect
.x() + rect
.width(), rect
.y()
492 const float texcoords
[ 4 * 2 ] =
494 0, 1, // y needs to be swapped (normalized coords)
499 enableNormalizedTexCoords();
500 renderGLGeometry( region
, 4, verts
, texcoords
);
501 disableNormalizedTexCoords();
504 void GLTexture::enableUnnormalizedTexCoords()
506 assert( mNormalizeActive
== 0 );
507 if( mUnnormalizeActive
++ != 0 )
509 // update texture matrix to handle GL_TEXTURE_2D and GL_TEXTURE_RECTANGLE
510 glMatrixMode( GL_TEXTURE
);
513 glScalef( mScale
.width(), mScale
.height(), 1 );
516 // Modify texture matrix so that we could always use non-opengl
517 // coordinates for textures
518 glScalef( 1, -1, 1 );
519 glTranslatef( 0, -mSize
.height(), 0 );
521 glMatrixMode( GL_MODELVIEW
);
524 void GLTexture::disableUnnormalizedTexCoords()
526 if( --mUnnormalizeActive
!= 0 )
528 // Restore texture matrix
529 glMatrixMode( GL_TEXTURE
);
531 glMatrixMode( GL_MODELVIEW
);
534 void GLTexture::enableNormalizedTexCoords()
536 assert( mUnnormalizeActive
== 0 );
537 if( mNormalizeActive
++ != 0 )
539 // update texture matrix to handle GL_TEXTURE_2D and GL_TEXTURE_RECTANGLE
540 glMatrixMode( GL_TEXTURE
);
543 glScalef( mSize
.width() * mScale
.width(), mSize
.height() * mScale
.height(), 1 );
546 // Modify texture matrix so that we could always use non-opengl
547 // coordinates for textures
548 glScalef( 1, -1, 1 );
549 glTranslatef( 0, -1, 0 );
551 glMatrixMode( GL_MODELVIEW
);
554 void GLTexture::disableNormalizedTexCoords()
556 if( --mNormalizeActive
!= 0 )
558 // Restore texture matrix
559 glMatrixMode( GL_TEXTURE
);
561 glMatrixMode( GL_MODELVIEW
);
564 GLuint
GLTexture::texture() const
569 GLenum
GLTexture::target() const
574 GLenum
GLTexture::filter() const
579 bool GLTexture::isDirty() const
581 return has_valid_mipmaps
;
584 void GLTexture::setTexture( GLuint texture
)
590 void GLTexture::setTarget( GLenum target
)
595 void GLTexture::setFilter( GLenum filter
)
600 void GLTexture::setWrapMode( GLenum mode
)
603 glTexParameteri( mTarget
, GL_TEXTURE_WRAP_S
, mode
);
604 glTexParameteri( mTarget
, GL_TEXTURE_WRAP_T
, mode
);
608 void GLTexture::setDirty()
610 has_valid_mipmaps
= false;
614 void GLTexture::enableFilter()
616 if( mFilter
== GL_LINEAR_MIPMAP_LINEAR
)
617 { // trilinear filtering requested, but is it possible?
618 if( NPOTTextureSupported()
619 && framebufferObjectSupported()
622 glTexParameteri( mTarget
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR_MIPMAP_LINEAR
);
623 glTexParameteri( mTarget
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
624 if( !has_valid_mipmaps
)
626 glGenerateMipmap( mTarget
);
627 has_valid_mipmaps
= true;
631 { // can't use trilinear, so use bilinear
632 setFilter( GL_LINEAR
);
633 glTexParameteri( mTarget
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
634 glTexParameteri( mTarget
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
637 else if( mFilter
== GL_LINEAR
)
639 glTexParameteri( mTarget
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
640 glTexParameteri( mTarget
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
643 { // if neither trilinear nor bilinear, default to fast filtering
644 setFilter( GL_NEAREST
);
645 glTexParameteri( mTarget
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
646 glTexParameteri( mTarget
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
650 QImage
GLTexture::convertToGLFormat( const QImage
& img
) const
652 // This method has been copied from Qt's QGLWidget::convertToGLFormat()
653 QImage res
= img
.convertToFormat(QImage::Format_ARGB32
);
654 res
= res
.mirrored();
656 if (QSysInfo::ByteOrder
== QSysInfo::BigEndian
) {
657 // Qt has ARGB; OpenGL wants RGBA
658 for (int i
=0; i
< res
.height(); i
++) {
659 uint
*p
= (uint
*)res
.scanLine(i
);
660 uint
*end
= p
+ res
.width();
662 *p
= (*p
<< 8) | ((*p
>> 24) & 0xFF);
668 // Qt has ARGB; OpenGL wants ABGR (i.e. RGBA backwards)
669 res
= res
.rgbSwapped();
674 //****************************************
676 //****************************************
678 bool GLShader::mFragmentShaderSupported
= false;
679 bool GLShader::mVertexShaderSupported
= false;
681 void GLShader::initStatic()
683 mFragmentShaderSupported
= mVertexShaderSupported
=
684 hasGLExtension("GL_ARB_shader_objects") && hasGLExtension("GL_ARB_shading_language_100");
685 mVertexShaderSupported
&= hasGLExtension("GL_ARB_vertex_shader");
686 mFragmentShaderSupported
&= hasGLExtension("GL_ARB_fragment_shader");
690 GLShader::GLShader(const QString
& vertexfile
, const QString
& fragmentfile
)
693 mVariableLocations
= 0;
696 loadFromFiles(vertexfile
, fragmentfile
);
699 GLShader::~GLShader()
701 if(mVariableLocations
)
703 mVariableLocations
->clear();
704 delete mVariableLocations
;
709 glDeleteProgram(mProgram
);
713 bool GLShader::loadFromFiles(const QString
& vertexfile
, const QString
& fragmentfile
)
715 QFile
vf(vertexfile
);
716 if(!vf
.open(QIODevice::ReadOnly
))
718 kError(1212) << "Couldn't open '" << vertexfile
<< "' for reading!" << endl
;
721 QString
vertexsource(vf
.readAll());
723 QFile
ff(fragmentfile
);
724 if(!ff
.open(QIODevice::ReadOnly
))
726 kError(1212) << "Couldn't open '" << fragmentfile
<< "' for reading!" << endl
;
729 QString
fragsource(ff
.readAll());
731 return load(vertexsource
, fragsource
);
734 bool GLShader::load(const QString
& vertexsource
, const QString
& fragmentsource
)
736 // Make sure shaders are actually supported
737 if(( !vertexsource
.isEmpty() && !vertexShaderSupported() ) ||
738 ( !fragmentsource
.isEmpty() && !fragmentShaderSupported() ))
740 kDebug(1212) << "Shaders not supported";
745 GLuint fragmentshader
;
747 GLsizei logsize
, logarraysize
;
750 // Create program object
751 mProgram
= glCreateProgram();
752 if(!vertexsource
.isEmpty())
754 // Create shader object
755 vertexshader
= glCreateShader(GL_VERTEX_SHADER
);
757 const QByteArray
& srcba
= vertexsource
.toLatin1();
758 const char* src
= srcba
.data();
759 glShaderSource(vertexshader
, 1, &src
, NULL
);
760 // Compile the shader
761 glCompileShader(vertexshader
);
762 // Make sure it compiled correctly
764 glGetShaderiv(vertexshader
, GL_COMPILE_STATUS
, &compiled
);
766 glGetShaderiv(vertexshader
, GL_INFO_LOG_LENGTH
, &logarraysize
);
767 log
= new char[logarraysize
];
768 glGetShaderInfoLog(vertexshader
, logarraysize
, &logsize
, log
);
771 kError(1212) << "Couldn't compile vertex shader! Log:" << endl
<< log
<< endl
;
776 kDebug(1212) << "Vertex shader compilation log:"<< log
;
777 // Attach the shader to the program
778 glAttachShader(mProgram
, vertexshader
);
780 glDeleteShader(vertexshader
);
785 if(!fragmentsource
.isEmpty())
787 fragmentshader
= glCreateShader(GL_FRAGMENT_SHADER
);
789 const QByteArray
& srcba
= fragmentsource
.toLatin1();
790 const char* src
= srcba
.data();
791 glShaderSource(fragmentshader
, 1, &src
, NULL
);
792 //glShaderSource(fragmentshader, 1, &fragmentsrc.latin1(), NULL);
793 // Compile the shader
794 glCompileShader(fragmentshader
);
795 // Make sure it compiled correctly
797 glGetShaderiv(fragmentshader
, GL_COMPILE_STATUS
, &compiled
);
799 glGetShaderiv(fragmentshader
, GL_INFO_LOG_LENGTH
, &logarraysize
);
800 log
= new char[logarraysize
];
801 glGetShaderInfoLog(fragmentshader
, logarraysize
, &logsize
, log
);
804 kError(1212) << "Couldn't compile fragment shader! Log:" << endl
<< log
<< endl
;
809 kDebug(1212) << "Fragment shader compilation log:"<< log
;
810 // Attach the shader to the program
811 glAttachShader(mProgram
, fragmentshader
);
813 glDeleteShader(fragmentshader
);
819 glLinkProgram(mProgram
);
820 // Make sure it linked correctly
822 glGetProgramiv(mProgram
, GL_LINK_STATUS
, &linked
);
824 glGetProgramiv(mProgram
, GL_INFO_LOG_LENGTH
, &logarraysize
);
825 log
= new char[logarraysize
];
826 glGetProgramInfoLog(mProgram
, logarraysize
, &logsize
, log
);
829 kError(1212) << "Couldn't link the program! Log" << endl
<< log
<< endl
;
834 kDebug(1212) << "Shader linking log:"<< log
;
837 mVariableLocations
= new QHash
<QString
, int>;
843 void GLShader::bind()
845 glUseProgram(mProgram
);
848 void GLShader::unbind()
853 int GLShader::uniformLocation(const QString
& name
)
855 if(!mVariableLocations
)
859 if(!mVariableLocations
->contains(name
))
861 int location
= glGetUniformLocation(mProgram
, name
.toLatin1().data());
862 mVariableLocations
->insert(name
, location
);
864 return mVariableLocations
->value(name
);
867 bool GLShader::setUniform(const QString
& name
, float value
)
869 int location
= uniformLocation(name
);
872 glUniform1f(location
, value
);
874 return (location
>= 0);
877 bool GLShader::setUniform(const QString
& name
, int value
)
879 int location
= uniformLocation(name
);
882 glUniform1i(location
, value
);
884 return (location
>= 0);
887 int GLShader::attributeLocation(const QString
& name
)
889 if(!mVariableLocations
)
893 if(!mVariableLocations
->contains(name
))
895 int location
= glGetAttribLocation(mProgram
, name
.toLatin1().data());
896 mVariableLocations
->insert(name
, location
);
898 return mVariableLocations
->value(name
);
901 bool GLShader::setAttribute(const QString
& name
, float value
)
903 int location
= attributeLocation(name
);
906 glVertexAttrib1f(location
, value
);
908 return (location
>= 0);
913 /*** GLRenderTarget ***/
914 bool GLRenderTarget::mSupported
= false;
916 void GLRenderTarget::initStatic()
918 mSupported
= hasGLExtension("GL_EXT_framebuffer_object") && glFramebufferTexture2D
;
921 GLRenderTarget::GLRenderTarget(GLTexture
* color
)
928 // Make sure FBO is supported
929 if(mSupported
&& mTexture
&& !mTexture
->isNull())
934 kError(1212) << "Render targets aren't supported!" << endl
;
937 GLRenderTarget::~GLRenderTarget()
941 glDeleteFramebuffers(1, &mFramebuffer
);
945 bool GLRenderTarget::enable()
949 kError(1212) << "Can't enable invalid render target!" << endl
;
953 glBindFramebuffer(GL_FRAMEBUFFER_EXT
, mFramebuffer
);
954 mTexture
->setDirty();
959 bool GLRenderTarget::disable()
963 kError(1212) << "Can't disable invalid render target!" << endl
;
967 glBindFramebuffer(GL_FRAMEBUFFER_EXT
, 0);
968 mTexture
->setDirty();
973 void GLRenderTarget::initFBO()
975 glGenFramebuffers(1, &mFramebuffer
);
976 glBindFramebuffer(GL_FRAMEBUFFER_EXT
, mFramebuffer
);
978 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
,
979 mTexture
->target(), mTexture
->texture(), 0);
981 GLenum status
= glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT
);
982 if(status
!= GL_FRAMEBUFFER_COMPLETE_EXT
)
984 kError(1212) << "Invalid fb status: " << status
<< endl
;
987 glBindFramebuffer(GL_FRAMEBUFFER_EXT
, 0);