00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00044
00045 static int glVersion;
00046
00047 static int glXVersion;
00048
00049 static QStringList glExtensions;
00050 static QStringList glxExtensions;
00051
00052 int glTextureUnitsCount;
00053
00054
00055
00056 void initGLX()
00057 {
00058
00059 int major, minor;
00060 glXQueryVersion( display(), &major, &minor );
00061 glXVersion = MAKE_GL_VERSION( major, minor, 0 );
00062
00063 glxExtensions = QString((const char*)glXQueryExtensionsString(
00064 display(), DefaultScreen( display()))).split(" ");
00065
00066 glxResolveFunctions();
00067 }
00068
00069 void initGL()
00070 {
00071
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
00077 glExtensions = QString((const char*)glGetString(GL_EXTENSIONS)).split(" ");
00078
00079
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
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
00139
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
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
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
00184 void ( *glVertexFunc )( const float* ) = glVertex2fv;
00185 if( dim == 3 )
00186 glVertexFunc = glVertex3fv;
00187 else if( dim == 4 )
00188 glVertexFunc = glVertex4fv;
00189
00190
00191 int vsize, tsize, csize;
00192 vsize = tsize = csize = stride / sizeof(float);
00193 if( !stride )
00194 {
00195
00196
00197 vsize = dim;
00198 tsize = 2;
00199 csize = 4;
00200 }
00201
00202 glBegin( GL_QUADS );
00203
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
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
00271
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
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
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
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
00284
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
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
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
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
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
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 {
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,
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
00510 glMatrixMode( GL_TEXTURE );
00511 glPushMatrix();
00512 glLoadIdentity();
00513 glScalef( mScale.width(), mScale.height(), 1 );
00514 if( !y_inverted )
00515 {
00516
00517
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
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
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
00547
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
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 {
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 {
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 {
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
00653 QImage res = img.convertToFormat(QImage::Format_ARGB32);
00654 res = res.mirrored();
00655
00656 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
00657
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
00669 res = res.rgbSwapped();
00670 }
00671 return res;
00672 }
00673
00674
00675
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
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
00751 mProgram = glCreateProgram();
00752 if(!vertexsource.isEmpty())
00753 {
00754
00755 vertexshader = glCreateShader(GL_VERTEX_SHADER);
00756
00757 const QByteArray& srcba = vertexsource.toLatin1();
00758 const char* src = srcba.data();
00759 glShaderSource(vertexshader, 1, &src, NULL);
00760
00761 glCompileShader(vertexshader);
00762
00763 int compiled;
00764 glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &compiled);
00765
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
00778 glAttachShader(mProgram, vertexshader);
00779
00780 glDeleteShader(vertexshader);
00781 delete[] log;
00782 }
00783
00784
00785 if(!fragmentsource.isEmpty())
00786 {
00787 fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
00788
00789 const QByteArray& srcba = fragmentsource.toLatin1();
00790 const char* src = srcba.data();
00791 glShaderSource(fragmentshader, 1, &src, NULL);
00792
00793
00794 glCompileShader(fragmentshader);
00795
00796 int compiled;
00797 glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &compiled);
00798
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
00811 glAttachShader(mProgram, fragmentshader);
00812
00813 glDeleteShader(fragmentshader);
00814 delete[] log;
00815 }
00816
00817
00818
00819 glLinkProgram(mProgram);
00820
00821 int linked;
00822 glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
00823
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
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
00924 mValid = false;
00925
00926 mTexture = color;
00927
00928
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 }
00993
00994 #endif