00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 #include "scene_opengl.h"
00069
00070 #include <kxerrorhandler.h>
00071
00072 #include "utils.h"
00073 #include "client.h"
00074 #include "deleted.h"
00075 #include "effects.h"
00076
00077 #include <sys/ipc.h>
00078 #include <sys/shm.h>
00079 #include <math.h>
00080
00081
00082
00083
00084
00085 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00086
00087 namespace KWin
00088 {
00089
00090
00091
00092
00093
00094
00095 GLXFBConfig SceneOpenGL::fbcbuffer_db;
00096 GLXFBConfig SceneOpenGL::fbcbuffer_nondb;
00097
00098 SceneOpenGL::FBConfigInfo SceneOpenGL::fbcdrawableinfo[ 32 + 1 ];
00099
00100 GLXContext SceneOpenGL::ctxbuffer;
00101 GLXContext SceneOpenGL::ctxdrawable;
00102
00103 GLXDrawable SceneOpenGL::glxbuffer = None;
00104 GLXDrawable SceneOpenGL::last_pixmap = None;
00105 bool SceneOpenGL::tfp_mode;
00106 bool SceneOpenGL::db;
00107 bool SceneOpenGL::shm_mode;
00108 #ifdef HAVE_XSHM
00109 XShmSegmentInfo SceneOpenGL::shm;
00110 #endif
00111
00112
00113 SceneOpenGL::SceneOpenGL( Workspace* ws )
00114 : Scene( ws )
00115 , init_ok( false )
00116 {
00117 if( !Extensions::glxAvailable())
00118 {
00119 kDebug( 1212 ) << "No glx extensions available";
00120 return;
00121 }
00122 initGLX();
00123
00124 if( !hasGLExtension( "GLX_SGIX_fbconfig" ) || !glXGetFBConfigAttrib || !glXGetFBConfigs ||
00125 !glXGetVisualFromFBConfig || !glXCreatePixmap || !glXDestroyPixmap ||
00126 !glXCreateWindow || !glXDestroyWindow )
00127 {
00128 kError( 1212 ) << "GLX_SGIX_fbconfig or required GLX functions missing";
00129 return;
00130 }
00131 if( !selectMode())
00132 return;
00133 if( !initBuffer())
00134 return;
00135 if( !initRenderingContext())
00136 return;
00137
00138 initGL();
00139 if( !hasGLExtension( "GL_ARB_texture_non_power_of_two" )
00140 && !hasGLExtension( "GL_ARB_texture_rectangle" ))
00141 {
00142 kError( 1212 ) << "GL_ARB_texture_non_power_of_two and GL_ARB_texture_rectangle missing";
00143 return;
00144 }
00145 if( db )
00146 glDrawBuffer( GL_BACK );
00147
00148 has_waitSync = false;
00149 if( glXGetVideoSync && glXIsDirect( display(), ctxbuffer ) && options->glVSync )
00150 {
00151 unsigned int sync;
00152 if( glXGetVideoSync( &sync ) == 0 )
00153 {
00154 if( glXWaitVideoSync( 1, 0, &sync ) == 0 )
00155 has_waitSync = true;
00156 }
00157 }
00158
00159
00160 glMatrixMode( GL_PROJECTION );
00161 glLoadIdentity();
00162
00163 glOrtho( 0, displayWidth(), displayHeight(), 0, 0, 65535 );
00164 glMatrixMode( GL_MODELVIEW );
00165 glLoadIdentity();
00166 if( checkGLError( "Init" ))
00167 {
00168 kError( 1212 ) << "OpenGL compositing setup failed";
00169 return;
00170 }
00171 kDebug( 1212 ) << "DB:" << db << ", TFP:" << tfp_mode << ", SHM:" << shm_mode
00172 << ", Direct:" << bool( glXIsDirect( display(), ctxbuffer )) << endl;
00173 init_ok = true;
00174 }
00175
00176 SceneOpenGL::~SceneOpenGL()
00177 {
00178 if( !init_ok )
00179 {
00180
00181 wspace->destroyOverlay();
00182 return;
00183 }
00184 foreach( Window* w, windows )
00185 delete w;
00186
00187 if( wspace->overlayWindow())
00188 {
00189 if( hasGLXVersion( 1, 3 ))
00190 glXDestroyWindow( display(), glxbuffer );
00191 XDestroyWindow( display(), buffer );
00192 wspace->destroyOverlay();
00193 }
00194 else
00195 {
00196 glXDestroyPixmap( display(), glxbuffer );
00197 XFreeGC( display(), gcroot );
00198 XFreePixmap( display(), buffer );
00199 }
00200 if( shm_mode )
00201 cleanupShm();
00202 if( !tfp_mode && !shm_mode )
00203 {
00204 if( last_pixmap != None )
00205 glXDestroyPixmap( display(), last_pixmap );
00206 glXDestroyContext( display(), ctxdrawable );
00207 }
00208 glXMakeCurrent( display(), None, NULL );
00209 glXDestroyContext( display(), ctxbuffer );
00210 checkGLError( "Cleanup" );
00211 }
00212
00213 bool SceneOpenGL::initFailed() const
00214 {
00215 return !init_ok;
00216 }
00217
00218 bool SceneOpenGL::selectMode()
00219 {
00220
00221 shm_mode = false;
00222 tfp_mode = false;
00223 if( options->glMode == Options::GLTFP )
00224 {
00225 if( initTfp())
00226 tfp_mode = true;
00227 else if( initShm())
00228 shm_mode = true;
00229 }
00230 else if( options->glMode == Options::GLSHM )
00231 {
00232 if( initShm())
00233 shm_mode = true;
00234 else if( initTfp())
00235 tfp_mode = true;
00236 }
00237 if( !initDrawableConfigs())
00238 return false;
00239 return true;
00240 }
00241
00242 bool SceneOpenGL::initTfp()
00243 {
00244 if( glXBindTexImageEXT == NULL || glXReleaseTexImageEXT == NULL )
00245 return false;
00246 return true;
00247 }
00248
00249 bool SceneOpenGL::initShm()
00250 {
00251 #ifdef HAVE_XSHM
00252 int major, minor;
00253 Bool pixmaps;
00254 if( !XShmQueryVersion( display(), &major, &minor, &pixmaps ) || !pixmaps )
00255 return false;
00256 if( XShmPixmapFormat( display()) != ZPixmap )
00257 return false;
00258 const int MAXSIZE = 4096 * 2048 * 4;
00259
00260 shm.readOnly = False;
00261 shm.shmid = shmget( IPC_PRIVATE, MAXSIZE, IPC_CREAT | 0600 );
00262 if( shm.shmid < 0 )
00263 return false;
00264 shm.shmaddr = ( char* ) shmat( shm.shmid, NULL, 0 );
00265 if( shm.shmaddr == ( void * ) -1 )
00266 {
00267 shmctl( shm.shmid, IPC_RMID, 0 );
00268 return false;
00269 }
00270 #ifdef __linux__
00271
00272
00273 shmctl( shm.shmid, IPC_RMID, 0 );
00274 #endif
00275 KXErrorHandler errs;
00276 XShmAttach( display(), &shm );
00277 if( errs.error( true ))
00278 {
00279 #ifndef __linux__
00280 shmctl( shm.shmid, IPC_RMID, 0 );
00281 #endif
00282 shmdt( shm.shmaddr );
00283 return false;
00284 }
00285 return true;
00286 #else
00287 return false;
00288 #endif
00289 }
00290
00291 void SceneOpenGL::cleanupShm()
00292 {
00293 #ifdef HAVE_XSHM
00294 shmdt( shm.shmaddr );
00295 #ifndef __linux__
00296 shmctl( shm.shmid, IPC_RMID, 0 );
00297 #endif
00298 #endif
00299 }
00300
00301 bool SceneOpenGL::initRenderingContext()
00302 {
00303 bool direct_rendering = options->glDirect;
00304 if( !tfp_mode && !shm_mode )
00305 direct_rendering = false;
00306 KXErrorHandler errs1;
00307 ctxbuffer = glXCreateNewContext( display(), fbcbuffer, GLX_RGBA_TYPE, NULL,
00308 direct_rendering ? GL_TRUE : GL_FALSE );
00309 bool failed = ( ctxbuffer == NULL || !glXMakeCurrent( display(), glxbuffer, ctxbuffer ));
00310 if( errs1.error( true ))
00311 failed = true;
00312 if( failed )
00313 {
00314 if( !direct_rendering )
00315 {
00316 kDebug( 1212 ).nospace() << "Couldn't initialize rendering context ("
00317 << KXErrorHandler::errorMessage( errs1.errorEvent()) << ")";
00318 return false;
00319 }
00320 glXMakeCurrent( display(), None, NULL );
00321 if( ctxbuffer != NULL )
00322 glXDestroyContext( display(), ctxbuffer );
00323 direct_rendering = false;
00324 KXErrorHandler errs2;
00325 ctxbuffer = glXCreateNewContext( display(), fbcbuffer, GLX_RGBA_TYPE, NULL, GL_FALSE );
00326 bool failed = ( ctxbuffer == NULL || !glXMakeCurrent( display(), glxbuffer, ctxbuffer ));
00327 if( errs2.error( true ))
00328 failed = true;
00329 if( failed )
00330 {
00331 kDebug( 1212 ).nospace() << "Couldn't initialize rendering context ("
00332 << KXErrorHandler::errorMessage( errs2.errorEvent()) << ")";
00333 return false;
00334 }
00335 }
00336 if( !tfp_mode && !shm_mode )
00337 {
00338 ctxdrawable = glXCreateNewContext( display(), fbcdrawableinfo[ QX11Info::appDepth() ].fbconfig, GLX_RGBA_TYPE, ctxbuffer,
00339 direct_rendering ? GL_TRUE : GL_FALSE );
00340 }
00341 return true;
00342 }
00343
00344
00345 bool SceneOpenGL::initBuffer()
00346 {
00347 if( !initBufferConfigs())
00348 return false;
00349 if( fbcbuffer_db != NULL && wspace->createOverlay())
00350 {
00351 fbcbuffer = fbcbuffer_db;
00352 XVisualInfo* visual = glXGetVisualFromFBConfig( display(), fbcbuffer );
00353 XSetWindowAttributes attrs;
00354 attrs.colormap = XCreateColormap( display(), rootWindow(), visual->visual, AllocNone );
00355 buffer = XCreateWindow( display(), wspace->overlayWindow(), 0, 0, displayWidth(), displayHeight(),
00356 0, visual->depth, InputOutput, visual->visual, CWColormap, &attrs );
00357 if( hasGLXVersion( 1, 3 ))
00358 glxbuffer = glXCreateWindow( display(), fbcbuffer, buffer, NULL );
00359 else
00360 glxbuffer = buffer;
00361 wspace->setupOverlay( buffer );
00362 db = true;
00363 XFree( visual );
00364 }
00365 else if( fbcbuffer_nondb != NULL )
00366 {
00367 fbcbuffer = fbcbuffer_nondb;
00368 XVisualInfo* visual = glXGetVisualFromFBConfig( display(), fbcbuffer );
00369 XGCValues gcattr;
00370 gcattr.subwindow_mode = IncludeInferiors;
00371 gcroot = XCreateGC( display(), rootWindow(), GCSubwindowMode, &gcattr );
00372 buffer = XCreatePixmap( display(), rootWindow(), displayWidth(), displayHeight(),
00373 visual->depth );
00374 glxbuffer = glXCreatePixmap( display(), fbcbuffer, buffer, NULL );
00375 db = false;
00376 XFree( visual );
00377 }
00378 else
00379 {
00380 kError( 1212 ) << "Couldn't create output buffer (failed to create overlay window?) !";
00381 return false;
00382 }
00383 int vis_buffer;
00384 glXGetFBConfigAttrib( display(), fbcbuffer, GLX_VISUAL_ID, &vis_buffer );
00385 XVisualInfo* visinfo_buffer = glXGetVisualFromFBConfig( display(), fbcbuffer );
00386 kDebug( 1212 ) << "Buffer visual (depth " << visinfo_buffer->depth << "): 0x" << QString::number( vis_buffer, 16 );
00387 XFree( visinfo_buffer );
00388 return true;
00389 }
00390
00391
00392 bool SceneOpenGL::initBufferConfigs()
00393 {
00394 int cnt;
00395 GLXFBConfig *fbconfigs = glXGetFBConfigs( display(), DefaultScreen( display() ), &cnt );
00396 fbcbuffer_db = NULL;
00397 fbcbuffer_nondb = NULL;
00398
00399 for( int i = 0; i < 2; i++ )
00400 {
00401 int back, stencil, depth, caveat, alpha;
00402 back = i > 0 ? INT_MAX : 1;
00403 stencil = INT_MAX;
00404 depth = INT_MAX;
00405 caveat = INT_MAX;
00406 alpha = 0;
00407 for( int j = 0; j < cnt; j++ )
00408 {
00409 XVisualInfo *vi;
00410 int visual_depth;
00411 vi = glXGetVisualFromFBConfig( display(), fbconfigs[ j ] );
00412 if( vi == NULL )
00413 continue;
00414 visual_depth = vi->depth;
00415 XFree( vi );
00416 if( visual_depth != DefaultDepth( display(), DefaultScreen( display())))
00417 continue;
00418 int value;
00419 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00420 GLX_ALPHA_SIZE, &alpha );
00421 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00422 GLX_BUFFER_SIZE, &value );
00423 if( value != visual_depth && ( value - alpha ) != visual_depth )
00424 continue;
00425 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00426 GLX_RENDER_TYPE, &value );
00427 if( !( value & GLX_RGBA_BIT ))
00428 continue;
00429 int back_value;
00430 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00431 GLX_DOUBLEBUFFER, &back_value );
00432 if( i > 0 )
00433 {
00434 if( back_value > back )
00435 continue;
00436 }
00437 else
00438 {
00439 if( back_value < back )
00440 continue;
00441 }
00442 int stencil_value;
00443 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00444 GLX_STENCIL_SIZE, &stencil_value );
00445 if( stencil_value > stencil )
00446 continue;
00447 int depth_value;
00448 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00449 GLX_DEPTH_SIZE, &depth_value );
00450 if( depth_value > depth )
00451 continue;
00452 int caveat_value;
00453 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00454 GLX_CONFIG_CAVEAT, &caveat_value );
00455 if( caveat_value > caveat )
00456 continue;
00457 back = back_value;
00458 stencil = stencil_value;
00459 depth = depth_value;
00460 caveat = caveat_value;
00461 if( i > 0 )
00462 fbcbuffer_nondb = fbconfigs[ j ];
00463 else
00464 fbcbuffer_db = fbconfigs[ j ];
00465 }
00466 }
00467 if( cnt )
00468 XFree( fbconfigs );
00469 if( fbcbuffer_db == NULL && fbcbuffer_nondb == NULL )
00470 {
00471 kError( 1212 ) << "Couldn't find framebuffer configuration for buffer!";
00472 return false;
00473 }
00474 for( int i = 0; i <= 32; i++ )
00475 {
00476 if( fbcdrawableinfo[ i ].fbconfig == NULL )
00477 continue;
00478 int vis_drawable = 0;
00479 glXGetFBConfigAttrib( display(), fbcdrawableinfo[ i ].fbconfig, GLX_VISUAL_ID, &vis_drawable );
00480 kDebug( 1212 ) << "Drawable visual (depth " << i << "): 0x" << QString::number( vis_drawable, 16 );
00481 }
00482 return true;
00483 }
00484
00485
00486 bool SceneOpenGL::initDrawableConfigs()
00487 {
00488 int cnt;
00489 GLXFBConfig *fbconfigs = glXGetFBConfigs( display(), DefaultScreen( display() ), &cnt );
00490
00491 for( int i = 0; i <= 32; i++ )
00492 {
00493 int back, stencil, depth, caveat, alpha, mipmap, rgba;
00494 back = INT_MAX;
00495 stencil = INT_MAX;
00496 depth = INT_MAX;
00497 caveat = INT_MAX;
00498 mipmap = 0;
00499 rgba = 0;
00500 fbcdrawableinfo[ i ].fbconfig = NULL;
00501 fbcdrawableinfo[ i ].bind_texture_format = 0;
00502 fbcdrawableinfo[ i ].y_inverted = 0;
00503 fbcdrawableinfo[ i ].mipmap = 0;
00504 for( int j = 0; j < cnt; j++ )
00505 {
00506 XVisualInfo *vi;
00507 int visual_depth;
00508 vi = glXGetVisualFromFBConfig( display(), fbconfigs[ j ] );
00509 if( vi == NULL )
00510 continue;
00511 visual_depth = vi->depth;
00512 XFree( vi );
00513 if( visual_depth != i )
00514 continue;
00515 int value;
00516 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00517 GLX_ALPHA_SIZE, &alpha );
00518 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00519 GLX_BUFFER_SIZE, &value );
00520 if( value != i && ( value - alpha ) != i )
00521 continue;
00522 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00523 GLX_RENDER_TYPE, &value );
00524 if( !( value & GLX_RGBA_BIT ))
00525 continue;
00526 if( tfp_mode )
00527 {
00528 value = 0;
00529 if( i == 32 )
00530 {
00531 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00532 GLX_BIND_TO_TEXTURE_RGBA_EXT, &value );
00533 if( value )
00534 {
00535
00536 rgba = 1;
00537 fbcdrawableinfo[ i ].bind_texture_format = GLX_TEXTURE_FORMAT_RGBA_EXT;
00538 }
00539 }
00540 if( !value )
00541 {
00542 if( rgba )
00543 continue;
00544 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00545 GLX_BIND_TO_TEXTURE_RGB_EXT, &value );
00546 if( !value )
00547 continue;
00548 fbcdrawableinfo[ i ].bind_texture_format = GLX_TEXTURE_FORMAT_RGB_EXT;
00549 }
00550 }
00551 int back_value;
00552 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00553 GLX_DOUBLEBUFFER, &back_value );
00554 if( back_value > back )
00555 continue;
00556 int stencil_value;
00557 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00558 GLX_STENCIL_SIZE, &stencil_value );
00559 if( stencil_value > stencil )
00560 continue;
00561 int depth_value;
00562 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00563 GLX_DEPTH_SIZE, &depth_value );
00564 if( depth_value > depth )
00565 continue;
00566 int mipmap_value = -1;
00567 if( tfp_mode && GLTexture::framebufferObjectSupported())
00568 {
00569 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00570 GLX_BIND_TO_MIPMAP_TEXTURE_EXT, &mipmap_value );
00571 if( mipmap_value < mipmap )
00572 continue;
00573 }
00574 int caveat_value;
00575 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00576 GLX_CONFIG_CAVEAT, &caveat_value );
00577 if( caveat_value > caveat )
00578 continue;
00579
00580 fbcdrawableinfo[ i ].fbconfig = fbconfigs[ j ];
00581 caveat = caveat_value;
00582 back = back_value;
00583 stencil = stencil_value;
00584 depth = depth_value;
00585 mipmap = mipmap_value;
00586 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00587 GLX_Y_INVERTED_EXT, &value );
00588 fbcdrawableinfo[ i ].y_inverted = value;
00589 fbcdrawableinfo[ i ].mipmap = mipmap;
00590 }
00591 }
00592 if( cnt )
00593 XFree( fbconfigs );
00594 if( fbcdrawableinfo[ DefaultDepth( display(), DefaultScreen( display())) ].fbconfig == NULL )
00595 {
00596 kError( 1212 ) << "Couldn't find framebuffer configuration for default depth!";
00597 return false;
00598 }
00599 if( fbcdrawableinfo[ 32 ].fbconfig == NULL )
00600 {
00601 kError( 1212 ) << "Couldn't find framebuffer configuration for depth 32 (no ARGB GLX visual)!";
00602 return false;
00603 }
00604 return true;
00605 }
00606
00607
00608 void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels )
00609 {
00610 foreach( Toplevel* c, toplevels )
00611 {
00612 assert( windows.contains( c ));
00613 stacking_order.append( windows[ c ] );
00614 }
00615 grabXServer();
00616 glXWaitX();
00617 glPushMatrix();
00618 int mask = 0;
00619 #ifdef CHECK_GL_ERROR
00620 checkGLError( "Paint1" );
00621 #endif
00622 paintScreen( &mask, &damage );
00623 #ifdef CHECK_GL_ERROR
00624 checkGLError( "Paint2" );
00625 #endif
00626 glPopMatrix();
00627 ungrabXServer();
00628 flushBuffer( mask, damage );
00629
00630 stacking_order.clear();
00631 checkGLError( "PostPaint" );
00632 }
00633
00634
00635 void SceneOpenGL::waitSync()
00636 {
00637 if( waitSyncAvailable())
00638 {
00639 unsigned int sync;
00640
00641 glFlush();
00642 glXGetVideoSync( &sync );
00643 glXWaitVideoSync( 2, ( sync + 1 ) % 2, &sync );
00644 }
00645 }
00646
00647
00648 void SceneOpenGL::flushBuffer( int mask, QRegion damage )
00649 {
00650 if( wspace->overlayWindow())
00651 wspace->showOverlay();
00652 if( db )
00653 {
00654 if( mask & PAINT_SCREEN_REGION )
00655 {
00656 waitSync();
00657 if( glXCopySubBuffer )
00658 {
00659 foreach( const QRect &r, damage.rects())
00660 {
00661
00662 int y = displayHeight() - r.y() - r.height();
00663 glXCopySubBuffer( display(), glxbuffer, r.x(), y, r.width(), r.height());
00664 }
00665 }
00666 else
00667 {
00668 glEnable( GL_SCISSOR_TEST );
00669 glDrawBuffer( GL_FRONT );
00670 int xpos = 0;
00671 int ypos = 0;
00672 foreach( const QRect &r, damage.rects())
00673 {
00674
00675 int y = displayHeight() - r.y() - r.height();
00676
00677
00678
00679
00680 glBitmap( 0, 0, 0, 0, r.x() - xpos, y - ypos, NULL );
00681 xpos = r.x();
00682 ypos = y;
00683 glScissor( r.x(), y, r.width(), r.height());
00684 glCopyPixels( r.x(), y, r.width(), r.height(), GL_COLOR );
00685 }
00686 glBitmap( 0, 0, 0, 0, -xpos, -ypos, NULL );
00687 glDrawBuffer( GL_BACK );
00688 glDisable( GL_SCISSOR_TEST );
00689 }
00690 }
00691 else
00692 {
00693 waitSync();
00694 glXSwapBuffers( display(), glxbuffer );
00695 }
00696 glXWaitGL();
00697 XFlush( display());
00698 }
00699 else
00700 {
00701 glFlush();
00702 glXWaitGL();
00703 waitSync();
00704 if( mask & PAINT_SCREEN_REGION )
00705 foreach( const QRect &r, damage.rects())
00706 XCopyArea( display(), buffer, rootWindow(), gcroot, r.x(), r.y(), r.width(), r.height(), r.x(), r.y());
00707 else
00708 XCopyArea( display(), buffer, rootWindow(), gcroot, 0, 0, displayWidth(), displayHeight(), 0, 0 );
00709 XFlush( display());
00710 }
00711 }
00712
00713 void SceneOpenGL::paintGenericScreen( int mask, ScreenPaintData data )
00714 {
00715 if( mask & PAINT_SCREEN_TRANSFORMED )
00716 {
00717 glPushMatrix();
00718 glTranslatef( data.xTranslate, data.yTranslate, 0 );
00719 glScalef( data.xScale, data.yScale, 1 );
00720 }
00721 Scene::paintGenericScreen( mask, data );
00722 if( mask & PAINT_SCREEN_TRANSFORMED )
00723 glPopMatrix();
00724 }
00725
00726 void SceneOpenGL::paintBackground( QRegion region )
00727 {
00728 PaintClipper pc( region );
00729 if( !PaintClipper::clip())
00730 {
00731 glPushAttrib( GL_COLOR_BUFFER_BIT );
00732 glClearColor( 0, 0, 0, 1 );
00733 glClear( GL_COLOR_BUFFER_BIT );
00734 glPopAttrib();
00735 return;
00736 }
00737 if( pc.clip() && pc.paintArea().isEmpty())
00738 return;
00739 glPushAttrib( GL_CURRENT_BIT );
00740 glColor4f( 0, 0, 0, 1 );
00741 for( PaintClipper::Iterator iterator;
00742 !iterator.isDone();
00743 iterator.next())
00744 {
00745 glBegin( GL_QUADS );
00746 QRect r = iterator.boundingRect();
00747 glVertex2i( r.x(), r.y());
00748 glVertex2i( r.x() + r.width(), r.y());
00749 glVertex2i( r.x() + r.width(), r.y() + r.height());
00750 glVertex2i( r.x(), r.y() + r.height());
00751 glEnd();
00752 }
00753 glPopAttrib();
00754 }
00755
00756 void SceneOpenGL::windowAdded( Toplevel* c )
00757 {
00758 assert( !windows.contains( c ));
00759 windows[ c ] = new Window( c );
00760 c->effectWindow()->setSceneWindow( windows[ c ]);
00761 }
00762
00763 void SceneOpenGL::windowClosed( Toplevel* c, Deleted* deleted )
00764 {
00765 assert( windows.contains( c ));
00766 if( deleted != NULL )
00767 {
00768 Window* w = windows.take( c );
00769 w->updateToplevel( deleted );
00770 windows[ deleted ] = w;
00771 }
00772 else
00773 {
00774 delete windows.take( c );
00775 c->effectWindow()->setSceneWindow( NULL );
00776 }
00777 }
00778
00779 void SceneOpenGL::windowDeleted( Deleted* c )
00780 {
00781 assert( windows.contains( c ));
00782 delete windows.take( c );
00783 c->effectWindow()->setSceneWindow( NULL );
00784 }
00785
00786 void SceneOpenGL::windowGeometryShapeChanged( Toplevel* c )
00787 {
00788 if( !windows.contains( c ))
00789 return;
00790 Window* w = windows[ c ];
00791 w->discardShape();
00792 w->checkTextureSize();
00793 }
00794
00795 void SceneOpenGL::windowOpacityChanged( Toplevel* )
00796 {
00797 #if 0 // not really needed, windows are painted on every repaint
00798
00799
00800 if( !windows.contains( c ))
00801 return;
00802 Window* w = windows[ c ];
00803 w->discardTexture();
00804 #endif
00805 }
00806
00807
00808
00809
00810
00811 SceneOpenGL::Texture::Texture() : GLTexture()
00812 {
00813 init();
00814 }
00815
00816 SceneOpenGL::Texture::Texture( const Pixmap& pix, const QSize& size, int depth ) : GLTexture()
00817 {
00818 init();
00819 load( pix, size, depth );
00820 }
00821
00822 SceneOpenGL::Texture::~Texture()
00823 {
00824 }
00825
00826 void SceneOpenGL::Texture::init()
00827 {
00828 bound_glxpixmap = None;
00829 }
00830
00831 void SceneOpenGL::Texture::createTexture()
00832 {
00833 glGenTextures( 1, &mTexture );
00834 }
00835
00836 void SceneOpenGL::Texture::discard()
00837 {
00838 if( mTexture != None )
00839 release();
00840 GLTexture::discard();
00841 }
00842
00843 void SceneOpenGL::Texture::release()
00844 {
00845 if( tfp_mode && bound_glxpixmap != None )
00846 {
00847 if( !options->glStrictBinding )
00848 glXReleaseTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT );
00849 glXDestroyGLXPixmap( display(), bound_glxpixmap );
00850 bound_glxpixmap = None;
00851 }
00852 }
00853
00854 void SceneOpenGL::Texture::findTarget()
00855 {
00856 unsigned int new_target = 0;
00857 if( tfp_mode && glXQueryDrawable && bound_glxpixmap != None )
00858 glXQueryDrawable( display(), bound_glxpixmap, GLX_TEXTURE_TARGET_EXT, &new_target );
00859
00860
00861
00862
00863 if( new_target == 0 )
00864 {
00865 if( NPOTTextureSupported() ||
00866 ( isPowerOfTwo( mSize.width()) && isPowerOfTwo( mSize.height())))
00867 new_target = GLX_TEXTURE_2D_EXT;
00868 else
00869 new_target = GLX_TEXTURE_RECTANGLE_EXT;
00870 }
00871 switch( new_target )
00872 {
00873 case GLX_TEXTURE_2D_EXT:
00874 mTarget = GL_TEXTURE_2D;
00875 mScale.setWidth( 1.0f / mSize.width());
00876 mScale.setHeight( 1.0f / mSize.height());
00877 break;
00878 case GLX_TEXTURE_RECTANGLE_EXT:
00879 mTarget = GL_TEXTURE_RECTANGLE_ARB;
00880 mScale.setWidth( 1.0f );
00881 mScale.setHeight( 1.0f );
00882 break;
00883 default:
00884 assert( false );
00885 }
00886 }
00887
00888 QRegion SceneOpenGL::Texture::optimizeBindDamage( const QRegion& reg, int limit )
00889 {
00890 if( reg.rects().count() <= 1 )
00891 return reg;
00892
00893
00894
00895
00896 int size = 0;
00897 foreach( const QRect &r, reg.rects())
00898 size += r.width() * r.height();
00899 if( reg.boundingRect().width() * reg.boundingRect().height() - size < limit )
00900 return reg.boundingRect();
00901 return reg;
00902 }
00903
00904 bool SceneOpenGL::Texture::load( const Pixmap& pix, const QSize& size,
00905 int depth, QRegion region )
00906 {
00907 #ifdef CHECK_GL_ERROR
00908 checkGLError( "TextureLoad1" );
00909 #endif
00910 if( pix == None || size.isEmpty() || depth < 1 )
00911 return false;
00912 if( tfp_mode )
00913 {
00914 if( fbcdrawableinfo[ depth ].fbconfig == NULL )
00915 {
00916 kDebug( 1212 ) << "No framebuffer configuration for depth " << depth
00917 << "; not binding pixmap" << endl;
00918 return false;
00919 }
00920 }
00921
00922 mSize = size;
00923 if( mTexture == None || !region.isEmpty())
00924 {
00925 setDirty();
00926 }
00927
00928 #ifdef CHECK_GL_ERROR
00929 checkGLError( "TextureLoad2" );
00930 #endif
00931 if( tfp_mode )
00932 {
00933 if( mTexture == None )
00934 createTexture();
00935
00936
00937 if( bound_glxpixmap != None )
00938 glBindTexture( mTarget, mTexture );
00939 else
00940 {
00941 int attrs[] =
00942 {
00943 GLX_TEXTURE_FORMAT_EXT, fbcdrawableinfo[ depth ].bind_texture_format,
00944 GLX_MIPMAP_TEXTURE_EXT, fbcdrawableinfo[ depth ].mipmap,
00945 None
00946 };
00947
00948
00949 bound_glxpixmap = glXCreatePixmap( display(), fbcdrawableinfo[ depth ].fbconfig, pix, attrs );
00950 #ifdef CHECK_GL_ERROR
00951 checkGLError( "TextureLoadTFP1" );
00952 #endif
00953 findTarget();
00954 y_inverted = fbcdrawableinfo[ depth ].y_inverted ? true : false;
00955 can_use_mipmaps = fbcdrawableinfo[ depth ].mipmap ? true : false;
00956 glBindTexture( mTarget, mTexture );
00957 #ifdef CHECK_GL_ERROR
00958 checkGLError( "TextureLoadTFP2" );
00959 #endif
00960 if( !options->glStrictBinding )
00961 glXBindTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT, NULL );
00962 }
00963 }
00964 else if( shm_mode )
00965 {
00966 #ifdef HAVE_XSHM
00967 GLenum pixfmt, type;
00968 if( depth >= 24 )
00969 {
00970 pixfmt = GL_BGRA;
00971 type = GL_UNSIGNED_BYTE;
00972 }
00973 else
00974 {
00975 pixfmt = GL_RGB;
00976 type = GL_UNSIGNED_SHORT_5_6_5;
00977 }
00978 findTarget();
00979 #ifdef CHECK_GL_ERROR
00980 checkGLError( "TextureLoadSHM1" );
00981 #endif
00982 if( mTexture == None )
00983 {
00984 createTexture();
00985 glBindTexture( mTarget, mTexture );
00986 y_inverted = false;
00987 glTexImage2D( mTarget, 0, depth == 32 ? GL_RGBA : GL_RGB,
00988 mSize.width(), mSize.height(), 0,
00989 pixfmt, type, NULL );
00990 }
00991 else
00992 glBindTexture( mTarget, mTexture );
00993 if( !region.isEmpty())
00994 {
00995 XGCValues xgcv;
00996 xgcv.graphics_exposures = False;
00997 xgcv.subwindow_mode = IncludeInferiors;
00998 GC gc = XCreateGC( display(), pix, GCGraphicsExposures | GCSubwindowMode, &xgcv );
00999 Pixmap p = XShmCreatePixmap( display(), rootWindow(), shm.shmaddr, &shm,
01000 mSize.width(), mSize.height(), depth );
01001 QRegion damage = optimizeBindDamage( region, 100 * 100 );
01002 glPixelStorei( GL_UNPACK_ROW_LENGTH, mSize.width());
01003 foreach( const QRect &r, damage.rects())
01004 {
01005 XCopyArea( display(), pix, p, gc, r.x(), r.y(), r.width(), r.height(), 0, 0 );
01006 glXWaitX();
01007 glTexSubImage2D( mTarget, 0,
01008 r.x(), r.y(), r.width(), r.height(),
01009 pixfmt, type, shm.shmaddr );
01010 glXWaitGL();
01011 }
01012 glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
01013 XFreePixmap( display(), p );
01014 XFreeGC( display(), gc );
01015 }
01016 #ifdef CHECK_GL_ERROR
01017 checkGLError( "TextureLoadSHM2" );
01018 #endif
01019 y_inverted = true;
01020 can_use_mipmaps = true;
01021 #endif
01022 }
01023 else
01024 {
01025
01026
01027 findTarget();
01028 GLXDrawable pixmap = glXCreatePixmap( display(), fbcdrawableinfo[ QX11Info::appDepth() ].fbconfig, pix, NULL );
01029 glXMakeCurrent( display(), pixmap, ctxdrawable );
01030 if( last_pixmap != None )
01031 glXDestroyPixmap( display(), last_pixmap );
01032
01033
01034 last_pixmap = pixmap;
01035 glReadBuffer( GL_FRONT );
01036 glDrawBuffer( GL_FRONT );
01037 if( mTexture == None )
01038 {
01039 createTexture();
01040 glBindTexture( mTarget, mTexture );
01041 y_inverted = false;
01042 glCopyTexImage2D( mTarget, 0,
01043 depth == 32 ? GL_RGBA : GL_RGB,
01044 0, 0, mSize.width(), mSize.height(), 0 );
01045 }
01046 else
01047 {
01048 glBindTexture( mTarget, mTexture );
01049 QRegion damage = optimizeBindDamage( region, 30 * 30 );
01050 foreach( const QRect &r, damage.rects())
01051 {
01052
01053
01054
01055 int gly = mSize.height() - r.y() - r.height();
01056 glCopyTexSubImage2D( mTarget, 0,
01057 r.x(), gly, r.x(), gly, r.width(), r.height());
01058 }
01059 }
01060 glXWaitGL();
01061 if( db )
01062 glDrawBuffer( GL_BACK );
01063 glXMakeCurrent( display(), glxbuffer, ctxbuffer );
01064 glBindTexture( mTarget, mTexture );
01065 y_inverted = false;
01066 can_use_mipmaps = true;
01067 }
01068 #ifdef CHECK_GL_ERROR
01069 checkGLError( "TextureLoad0" );
01070 #endif
01071 return true;
01072 }
01073
01074 bool SceneOpenGL::Texture::load( const Pixmap& pix, const QSize& size,
01075 int depth )
01076 {
01077 return load( pix, size, depth,
01078 QRegion( 0, 0, size.width(), size.height()));
01079 }
01080
01081 bool SceneOpenGL::Texture::load( const QImage& image, GLenum target )
01082 {
01083 if( image.isNull())
01084 return false;
01085 return load( QPixmap::fromImage( image ), target );
01086 }
01087
01088 bool SceneOpenGL::Texture::load( const QPixmap& pixmap, GLenum target )
01089 {
01090 Q_UNUSED( target );
01091 if( pixmap.isNull())
01092 return false;
01093 return load( pixmap.handle(), pixmap.size(), pixmap.depth());
01094 }
01095
01096 void SceneOpenGL::Texture::bind()
01097 {
01098 glEnable( mTarget );
01099 glBindTexture( mTarget, mTexture );
01100 if( tfp_mode && options->glStrictBinding )
01101 {
01102 assert( bound_glxpixmap != None );
01103 glXBindTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT, NULL );
01104 }
01105 enableFilter();
01106 if( hasGLVersion( 1, 4, 0 ))
01107 {
01108
01109 glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -1.0f );
01110 }
01111 }
01112
01113 void SceneOpenGL::Texture::unbind()
01114 {
01115 if( hasGLVersion( 1, 4, 0 ))
01116 {
01117 glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, 0.0f );
01118 }
01119 if( tfp_mode && options->glStrictBinding )
01120 {
01121 assert( bound_glxpixmap != None );
01122 glBindTexture( mTarget, mTexture );
01123 glXReleaseTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT );
01124 }
01125 GLTexture::unbind();
01126 }
01127
01128
01129
01130
01131
01132 SceneOpenGL::Window::Window( Toplevel* c )
01133 : Scene::Window( c )
01134 , texture()
01135 {
01136 }
01137
01138 SceneOpenGL::Window::~Window()
01139 {
01140 discardTexture();
01141 }
01142
01143
01144 bool SceneOpenGL::Window::bindTexture()
01145 {
01146 if( texture.texture() != None && toplevel->damage().isEmpty())
01147 {
01148
01149 glBindTexture( texture.target(), texture.texture());
01150 return true;
01151 }
01152
01153 Pixmap pix = toplevel->windowPixmap();
01154 if( pix == None )
01155 return false;
01156 bool success = texture.load( pix, toplevel->size(), toplevel->depth(),
01157 toplevel->damage());
01158 if( success )
01159 toplevel->resetDamage( toplevel->rect());
01160 else
01161 kDebug( 1212 ) << "Failed to bind window";
01162 return success;
01163 }
01164
01165 void SceneOpenGL::Window::discardTexture()
01166 {
01167 texture.discard();
01168 }
01169
01170
01171
01172
01173
01174
01175
01176 void SceneOpenGL::Window::checkTextureSize()
01177 {
01178 if( texture.size() != size())
01179 discardTexture();
01180 }
01181
01182
01183 void SceneOpenGL::Window::pixmapDiscarded()
01184 {
01185 texture.release();
01186 }
01187
01188
01189 void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintData data )
01190 {
01191
01192
01193 bool opaque = isOpaque() && data.opacity == 1.0;
01194 if( mask & ( PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSLUCENT ))
01195 {}
01196 else if( mask & PAINT_WINDOW_OPAQUE )
01197 {
01198 if( !opaque )
01199 return;
01200 }
01201 else if( mask & PAINT_WINDOW_TRANSLUCENT )
01202 {
01203 if( opaque )
01204 return;
01205 }
01206
01207 if( region != infiniteRegion())
01208 region.translate( -x(), -y());
01209 if(( mask & ( PAINT_SCREEN_TRANSFORMED | PAINT_WINDOW_TRANSFORMED )) == 0 )
01210 region &= shape();
01211 if( region.isEmpty())
01212 return;
01213 if( !bindTexture())
01214 return;
01215 glPushMatrix();
01216
01217 if( options->smoothScale != 0 )
01218 {
01219 if( mask & PAINT_WINDOW_TRANSFORMED )
01220 filter = ImageFilterGood;
01221 else if( mask & PAINT_SCREEN_TRANSFORMED )
01222 filter = ImageFilterGood;
01223 else
01224 filter = ImageFilterFast;
01225 }
01226 else
01227 filter = ImageFilterFast;
01228 if( filter == ImageFilterGood )
01229 {
01230
01231
01232
01233 if( options->smoothScale == 2
01234 && ( data.quads.smoothNeeded() || data.xScale < 1 || data.yScale < 1 ))
01235 {
01236 texture.setFilter( GL_LINEAR_MIPMAP_LINEAR );
01237 }
01238 else
01239 texture.setFilter( GL_LINEAR );
01240 }
01241 else
01242 texture.setFilter( GL_NEAREST );
01243
01244 int x = toplevel->x();
01245 int y = toplevel->y();
01246 if( mask & PAINT_WINDOW_TRANSFORMED )
01247 {
01248 x += data.xTranslate;
01249 y += data.yTranslate;
01250 }
01251 glTranslatef( x, y, 0 );
01252 if(( mask & PAINT_WINDOW_TRANSFORMED ) && ( data.xScale != 1 || data.yScale != 1 ))
01253 glScalef( data.xScale, data.yScale, 1 );
01254 region.translate( toplevel->x(), toplevel->y() );
01255
01256 texture.bind();
01257 texture.enableUnnormalizedTexCoords();
01258
01259 WindowQuadList decoration = data.quads.select( WindowQuadDecoration );
01260 if( data.contents_opacity != data.decoration_opacity && !decoration.isEmpty())
01261 {
01262 prepareStates( data.opacity * data.contents_opacity, data.brightness, data.saturation, data.shader );
01263 renderQuads( mask, region, data.quads.select( WindowQuadContents ));
01264 restoreStates( data.opacity * data.contents_opacity, data.brightness, data.saturation, data.shader );
01265 prepareStates( data.opacity * data.decoration_opacity, data.brightness, data.saturation, data.shader );
01266 renderQuads( mask, region, decoration );
01267 restoreStates( data.opacity * data.decoration_opacity, data.brightness, data.saturation, data.shader );
01268 }
01269 else
01270 {
01271 prepareStates( data.opacity * data.contents_opacity, data.brightness, data.saturation, data.shader );
01272 renderQuads( mask, region, data.quads.select( WindowQuadContents ));
01273 renderQuads( mask, region, data.quads.select( WindowQuadDecoration ));
01274 restoreStates( data.opacity * data.contents_opacity, data.brightness, data.saturation, data.shader );
01275 }
01276
01277 texture.disableUnnormalizedTexCoords();
01278 texture.unbind();
01279 glPopMatrix();
01280 }
01281
01282 void SceneOpenGL::Window::renderQuads( int, const QRegion& region, const WindowQuadList& quads )
01283 {
01284 if( quads.isEmpty())
01285 return;
01286
01287 float* vertices;
01288 float* texcoords;
01289 quads.makeArrays( &vertices, &texcoords );
01290 renderGLGeometry( region, quads.count() * 4,
01291 vertices, texcoords, NULL, 2, 0 );
01292 delete[] vertices;
01293 delete[] texcoords;
01294 }
01295
01296 void SceneOpenGL::Window::prepareStates( double opacity, double brightness, double saturation, GLShader* shader )
01297 {
01298 if(shader)
01299 prepareShaderRenderStates( opacity, brightness, saturation, shader );
01300 else
01301 prepareRenderStates( opacity, brightness, saturation );
01302 }
01303
01304 void SceneOpenGL::Window::prepareShaderRenderStates( double opacity, double brightness, double saturation, GLShader* shader )
01305 {
01306
01307 glPushAttrib( GL_ENABLE_BIT );
01308 bool opaque = isOpaque() && opacity == 1.0;
01309 if( !opaque )
01310 {
01311 glEnable( GL_BLEND );
01312 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
01313 }
01314 shader->setUniform("opacity", (float)opacity);
01315 shader->setUniform("saturation", (float)saturation);
01316 shader->setUniform("brightness", (float)brightness);
01317 }
01318
01319 void SceneOpenGL::Window::prepareRenderStates( double opacity, double brightness, double saturation )
01320 {
01321
01322 glPushAttrib( GL_ENABLE_BIT );
01323 bool opaque = isOpaque() && opacity == 1.0;
01324 if( !opaque )
01325 {
01326 glEnable( GL_BLEND );
01327 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
01328 }
01329 if( saturation != 1.0 && texture.saturationSupported())
01330 {
01331
01332 glActiveTexture( GL_TEXTURE0 );
01333 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
01334 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
01335 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE );
01336 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
01337 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT );
01338 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
01339 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT );
01340 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA );
01341 const float scale_constant[] = { 1.0, 1.0, 1.0, 0.5};
01342 glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, scale_constant );
01343 texture.bind();
01344
01345
01346
01347
01348
01349
01350 glActiveTexture( GL_TEXTURE1 );
01351 float saturation_constant[] = { 0.5 + 0.5*0.30, 0.5 + 0.5*0.59, 0.5 + 0.5*0.11, saturation };
01352 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
01353 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB );
01354 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS );
01355 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
01356 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT );
01357 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
01358 glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, saturation_constant );
01359 texture.bind();
01360
01361
01362
01363 glActiveTexture( GL_TEXTURE2 );
01364 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
01365 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
01366 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0 );
01367 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
01368 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS );
01369 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
01370 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT );
01371 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA );
01372 glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, saturation_constant );
01373
01374 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE );
01375 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR );
01376 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
01377
01378 glColor4f( opacity, opacity, opacity, opacity );
01379 texture.bind();
01380
01381 if( toplevel->hasAlpha() || brightness != 1.0f )
01382 {
01383 glActiveTexture( GL_TEXTURE3 );
01384 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
01385 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE );
01386 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS );
01387 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
01388 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR );
01389 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
01390 if( toplevel->hasAlpha() )
01391 {
01392
01393 float opacityByBrightness = opacity * brightness;
01394 glColor4f( opacityByBrightness, opacityByBrightness, opacityByBrightness, opacity );
01395
01396 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE );
01397 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0 );
01398 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
01399 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR );
01400 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA );
01401 }
01402 else
01403 {
01404
01405 glColor4f( brightness, brightness, brightness, opacity );
01406
01407 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE );
01408 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS );
01409 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
01410 }
01411 texture.bind();
01412 }
01413
01414 glActiveTexture(GL_TEXTURE0 );
01415 }
01416 else if( opacity != 1.0 || brightness != 1.0 )
01417 {
01418
01419
01420 if( toplevel->hasAlpha())
01421 {
01422 float opacityByBrightness = opacity * brightness;
01423 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
01424 glColor4f( opacityByBrightness, opacityByBrightness, opacityByBrightness,
01425 opacity);
01426 }
01427 else
01428 {
01429
01430 float constant[] = { brightness, brightness, brightness, opacity };
01431 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
01432 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE );
01433 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE );
01434 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
01435 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT );
01436 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
01437 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE );
01438 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT );
01439 glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant );
01440 }
01441 }
01442 }
01443
01444 void SceneOpenGL::Window::restoreStates( double opacity, double brightness, double saturation, GLShader* shader )
01445 {
01446 if(shader)
01447 restoreShaderRenderStates( opacity, brightness, saturation, shader );
01448 else
01449 restoreRenderStates( opacity, brightness, saturation );
01450 }
01451
01452 void SceneOpenGL::Window::restoreShaderRenderStates( double opacity, double brightness, double saturation, GLShader* shader )
01453 {
01454 Q_UNUSED( opacity );
01455 Q_UNUSED( brightness );
01456 Q_UNUSED( saturation );
01457 Q_UNUSED( shader );
01458 glPopAttrib();
01459 }
01460
01461 void SceneOpenGL::Window::restoreRenderStates( double opacity, double brightness, double saturation )
01462 {
01463 if( opacity != 1.0 || saturation != 1.0 || brightness != 1.0f )
01464 {
01465 if( saturation != 1.0 && texture.saturationSupported())
01466 {
01467 glActiveTexture(GL_TEXTURE3);
01468 glDisable( texture.target());
01469 glActiveTexture(GL_TEXTURE2);
01470 glDisable( texture.target());
01471 glActiveTexture(GL_TEXTURE1);
01472 glDisable( texture.target());
01473 glActiveTexture(GL_TEXTURE0);
01474 }
01475 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
01476 glColor4f( 0, 0, 0, 0 );
01477 }
01478
01479 glPopAttrib();
01480 }
01481
01482 }
01483
01484 #endif