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() << "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 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
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 {
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
00499 glMatrixMode( GL_TEXTURE );
00500 glPushMatrix();
00501 glLoadIdentity();
00502 glScalef( mScale.width(), mScale.height(), 1 );
00503 if( !y_inverted )
00504 {
00505
00506
00507 glScalef( 1, -1, 1 );
00508 glTranslatef( 0, -mSize.height(), 0 );
00509 }
00510 glMatrixMode( GL_MODELVIEW );
00511 }
00512
00513 void GLTexture::disableUnnormalizedTexCoords()
00514 {
00515
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 {
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 {
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 {
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
00610 QImage res = img.convertToFormat(QImage::Format_ARGB32);
00611 res = res.mirrored();
00612
00613 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
00614
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
00626 res = res.rgbSwapped();
00627 }
00628 return res;
00629 }
00630
00631
00632
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
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
00708 mProgram = glCreateProgram();
00709 if(!vertexsource.isEmpty())
00710 {
00711
00712 vertexshader = glCreateShader(GL_VERTEX_SHADER);
00713
00714 const QByteArray& srcba = vertexsource.toLatin1();
00715 const char* src = srcba.data();
00716 glShaderSource(vertexshader, 1, &src, NULL);
00717
00718 glCompileShader(vertexshader);
00719
00720 int compiled;
00721 glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &compiled);
00722
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
00735 glAttachShader(mProgram, vertexshader);
00736
00737 glDeleteShader(vertexshader);
00738 delete[] log;
00739 }
00740
00741
00742 if(!fragmentsource.isEmpty())
00743 {
00744 fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
00745
00746 const QByteArray& srcba = fragmentsource.toLatin1();
00747 const char* src = srcba.data();
00748 glShaderSource(fragmentshader, 1, &src, NULL);
00749
00750
00751 glCompileShader(fragmentshader);
00752
00753 int compiled;
00754 glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &compiled);
00755
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
00768 glAttachShader(mProgram, fragmentshader);
00769
00770 glDeleteShader(fragmentshader);
00771 delete[] log;
00772 }
00773
00774
00775
00776 glLinkProgram(mProgram);
00777
00778 int linked;
00779 glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
00780
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
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
00881 mValid = false;
00882
00883 mTexture = color;
00884
00885
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 }
00950
00951 #endif