You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
635 lines
20 KiB
635 lines
20 KiB
/***************************************************************** |
|
KWin - the KDE window manager |
|
This file is part of the KDE project. |
|
|
|
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org> |
|
|
|
You can Freely distribute this program under the GNU General Public |
|
License. See the file "COPYING" for the exact licensing terms. |
|
|
|
Based on glcompmgr code by Felix Bellaby. |
|
******************************************************************/ |
|
|
|
|
|
|
|
#include "scene_opengl.h" |
|
|
|
#include "utils.h" |
|
#include "client.h" |
|
|
|
#include <dlfcn.h> |
|
|
|
#include <X11/extensions/shape.h> |
|
|
|
namespace KWinInternal |
|
{ |
|
|
|
//**************************************** |
|
// SceneOpenGL |
|
//**************************************** |
|
|
|
GLXFBConfig SceneOpenGL::fbcdrawable; |
|
GLXContext SceneOpenGL::context; |
|
GLXPixmap SceneOpenGL::glxroot; |
|
bool SceneOpenGL::tfp_mode; // using glXBindTexImageEXT (texture_from_pixmap) |
|
|
|
typedef void (*glXBindTexImageEXT_func)( Display* dpy, GLXDrawable drawable, |
|
int buffer, const int* attrib_list ); |
|
typedef void (*glXReleaseTexImageEXT_func)( Display* dpy, GLXDrawable drawable, int buffer ); |
|
typedef void (*glXFuncPtr)(); |
|
typedef glXFuncPtr (*glXGetProcAddress_func)( const GLubyte* ); |
|
glXBindTexImageEXT_func glXBindTexImageEXT; |
|
glXReleaseTexImageEXT_func glXReleaseTexImageEXT; |
|
glXGetProcAddress_func glXGetProcAddress; |
|
|
|
static void checkGLError( const char* txt ) |
|
{ |
|
GLenum err = glGetError(); |
|
if( err != GL_NO_ERROR ) |
|
kWarning() << "GL error (" << txt << "): 0x" << QString::number( err, 16 ) << endl; |
|
} |
|
|
|
const int root_db_attrs[] = |
|
{ |
|
GLX_DOUBLEBUFFER, True, |
|
GLX_RED_SIZE, 1, |
|
GLX_GREEN_SIZE, 1, |
|
GLX_BLUE_SIZE, 1, |
|
GLX_ALPHA_SIZE, 1, |
|
GLX_RENDER_TYPE, GLX_RGBA_BIT, |
|
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, |
|
None |
|
}; |
|
|
|
static const int root_buffer_attrs[] = |
|
{ |
|
GLX_DOUBLEBUFFER, False, |
|
GLX_RED_SIZE, 1, |
|
GLX_GREEN_SIZE, 1, |
|
GLX_BLUE_SIZE, 1, |
|
GLX_ALPHA_SIZE, 1, |
|
GLX_RENDER_TYPE, GLX_RGBA_BIT, |
|
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, |
|
None |
|
}; |
|
|
|
const int drawable_attrs[] = |
|
{ |
|
GLX_DOUBLEBUFFER, False, |
|
GLX_DEPTH_SIZE, 0, |
|
GLX_RED_SIZE, 1, |
|
GLX_GREEN_SIZE, 1, |
|
GLX_BLUE_SIZE, 1, |
|
GLX_ALPHA_SIZE, 1, |
|
GLX_RENDER_TYPE, GLX_RGBA_BIT, |
|
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, |
|
None |
|
}; |
|
|
|
const int drawable_tfp_attrs[] = |
|
{ |
|
GLX_DOUBLEBUFFER, False, |
|
GLX_DEPTH_SIZE, 0, |
|
GLX_RED_SIZE, 1, |
|
GLX_GREEN_SIZE, 1, |
|
GLX_BLUE_SIZE, 1, |
|
GLX_ALPHA_SIZE, 1, |
|
GLX_RENDER_TYPE, GLX_RGBA_BIT, |
|
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, |
|
GLX_BIND_TO_TEXTURE_RGBA_EXT, True, // additional for tfp |
|
None |
|
}; |
|
|
|
static glXFuncPtr getProcAddress( const char* name ) |
|
{ |
|
glXFuncPtr ret = NULL; |
|
if( glXGetProcAddress != NULL ) |
|
ret = glXGetProcAddress( ( const GLubyte* ) name ); |
|
if( ret == NULL ) |
|
ret = ( glXFuncPtr ) dlsym( RTLD_DEFAULT, name ); |
|
return ret; |
|
} |
|
|
|
SceneOpenGL::SceneOpenGL( Workspace* ws ) |
|
: Scene( ws ) |
|
{ |
|
// TODO add checks where needed |
|
int dummy; |
|
if( !glXQueryExtension( display(), &dummy, &dummy )) |
|
return; |
|
glXGetProcAddress = (glXGetProcAddress_func) getProcAddress( "glxGetProcAddress" ); |
|
if( glXGetProcAddress == NULL ) |
|
glXGetProcAddress = (glXGetProcAddress_func) getProcAddress( "glxGetProcAddressARB" ); |
|
glXBindTexImageEXT = (glXBindTexImageEXT_func) getProcAddress( "glXBindTexImageEXT" ); |
|
glXReleaseTexImageEXT = (glXReleaseTexImageEXT_func) getProcAddress( "glXReleaseTexImageEXT" ); |
|
tfp_mode = ( glXBindTexImageEXT != NULL && glXReleaseTexImageEXT != NULL ); |
|
initBuffer(); |
|
if( tfp_mode ) |
|
{ |
|
if( !findConfig( drawable_tfp_attrs, fbcdrawable )) |
|
{ |
|
tfp_mode = false; |
|
if( !findConfig( drawable_attrs, fbcdrawable )) |
|
assert( false ); |
|
} |
|
} |
|
else |
|
if( !findConfig( drawable_attrs, fbcdrawable )) |
|
assert( false ); |
|
context = glXCreateNewContext( display(), fbcroot, GLX_RGBA_TYPE, NULL, GL_FALSE ); |
|
glXMakeContextCurrent( display(), glxroot, glxroot, context ); |
|
glMatrixMode( GL_PROJECTION ); |
|
glLoadIdentity(); |
|
glOrtho( 0, displayWidth(), 0, displayHeight(), 0, 65535 ); |
|
checkGLError( "Init" ); |
|
kDebug() << "Root DB:" << root_db << ", TFP:" << tfp_mode << endl; |
|
} |
|
|
|
SceneOpenGL::~SceneOpenGL() |
|
{ |
|
for( QMap< Toplevel*, Window >::Iterator it = windows.begin(); |
|
it != windows.end(); |
|
++it ) |
|
(*it).free(); |
|
if( root_db ) |
|
glXDestroyWindow( display(), glxroot ); |
|
else |
|
{ |
|
glXDestroyPixmap( display(), glxroot ); |
|
XFreeGC( display(), gcroot ); |
|
XFreePixmap( display(), buffer ); |
|
} |
|
glXDestroyContext( display(), context ); |
|
checkGLError( "Cleanup" ); |
|
} |
|
|
|
void SceneOpenGL::initBuffer() |
|
{ |
|
XWindowAttributes attrs; |
|
XGetWindowAttributes( display(), rootWindow(), &attrs ); |
|
if( findConfig( root_db_attrs, fbcroot, XVisualIDFromVisual( attrs.visual ))) |
|
root_db = true; |
|
else |
|
{ |
|
if( findConfig( root_buffer_attrs, fbcroot )) |
|
root_db = false; |
|
else |
|
assert( false ); |
|
} |
|
if( root_db ) |
|
{ |
|
buffer = rootWindow(); |
|
glxroot = glXCreateWindow( display(), fbcroot, buffer, NULL ); |
|
} |
|
else |
|
{ |
|
XGCValues gcattr; |
|
gcattr.subwindow_mode = IncludeInferiors; |
|
gcroot = XCreateGC( display(), rootWindow(), GCSubwindowMode, &gcattr ); |
|
buffer = XCreatePixmap( display(), rootWindow(), displayWidth(), displayHeight(), |
|
QX11Info::appDepth()); |
|
glxroot = glXCreatePixmap( display(), fbcroot, buffer, NULL ); |
|
} |
|
} |
|
|
|
static void debugFBConfig( GLXFBConfig* fbconfigs, int i, const int* attrs ) |
|
{ |
|
int pos = 0; |
|
while( attrs[ pos ] != (int)None ) |
|
{ |
|
int value; |
|
if( glXGetFBConfigAttrib( display(), fbconfigs[ i ], attrs[ pos ], &value ) |
|
== Success ) |
|
kDebug() << "ATTR: 0x" << QString::number( attrs[ pos ], 16 ) |
|
<< ": 0x" << QString::number( attrs[ pos + 1 ], 16 ) |
|
<< ": 0x" << QString::number( value, 16 ) << endl; |
|
else |
|
kDebug() << "ATTR FAIL: 0x" << QString::number( attrs[ pos ], 16 ) << endl; |
|
pos += 2; |
|
} |
|
} |
|
|
|
bool SceneOpenGL::findConfig( const int* attrs, GLXFBConfig& config, VisualID visual ) |
|
{ |
|
int cnt; |
|
GLXFBConfig* fbconfigs = glXChooseFBConfig( display(), DefaultScreen( display()), |
|
attrs, &cnt ); |
|
if( fbconfigs != NULL ) |
|
{ |
|
if( visual == None ) |
|
{ |
|
config = fbconfigs[ 0 ]; |
|
kDebug() << "Found FBConfig" << endl; |
|
debugFBConfig( fbconfigs, 0, attrs ); |
|
XFree( fbconfigs ); |
|
return true; |
|
} |
|
else |
|
{ |
|
for( int i = 0; |
|
i < cnt; |
|
++i ) |
|
{ |
|
int value; |
|
glXGetFBConfigAttrib( display(), fbconfigs[ i ], GLX_VISUAL_ID, &value ); |
|
if( value == (int)visual ) |
|
{ |
|
kDebug() << "Found FBConfig" << endl; |
|
config = fbconfigs[ i ]; |
|
debugFBConfig( fbconfigs, i, attrs ); |
|
XFree( fbconfigs ); |
|
return true; |
|
} |
|
} |
|
} |
|
} |
|
#if 0 // for debug |
|
fbconfigs = glXGetFBConfigs( display(), DefaultScreen( display()), &cnt ); |
|
for( int i = 0; |
|
i < cnt; |
|
++i ) |
|
{ |
|
kDebug() << "Listing FBConfig:" << i << endl; |
|
debugFBConfig( fbconfigs, i, attrs ); |
|
} |
|
if( fbconfigs != NULL ) |
|
XFree( fbconfigs ); |
|
#endif |
|
return false; |
|
} |
|
|
|
void SceneOpenGL::paint( QRegion damage, ToplevelList windows ) |
|
{ |
|
grabXServer(); |
|
glXWaitX(); |
|
glPushMatrix(); |
|
glClearColor( 0, 0, 0, 1 ); |
|
glClear( GL_COLOR_BUFFER_BIT ); |
|
glScalef( 1, -1, 1 ); |
|
glTranslatef( 0, -displayHeight(), 0 ); |
|
if( /*generic case*/true ) |
|
paintGenericScreen( windows ); |
|
else |
|
paintSimpleScreen( damage, windows ); |
|
glPopMatrix(); |
|
if( root_db ) |
|
glXSwapBuffers( display(), glxroot ); |
|
else |
|
{ |
|
glFlush(); |
|
glXWaitGL(); |
|
XCopyArea( display(), buffer, rootWindow(), gcroot, 0, 0, displayWidth(), displayHeight(), 0, 0 ); |
|
XFlush( display()); |
|
} |
|
ungrabXServer(); |
|
checkGLError( "PostPaint" ); |
|
} |
|
|
|
// the generic drawing code that should eventually handle even |
|
// transformations |
|
void SceneOpenGL::paintGenericScreen( ToplevelList windows ) |
|
{ |
|
foreach( Toplevel* c, windows ) // bottom to top |
|
{ |
|
assert( this->windows.contains( c )); |
|
Window& w = this->windows[ c ]; |
|
if( !w.isVisible()) |
|
continue; |
|
w.bindTexture(); |
|
if( !w.isOpaque()) |
|
{ |
|
glEnable( GL_BLEND ); |
|
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); |
|
} |
|
w.draw(); |
|
glDisable( GL_BLEND ); |
|
} |
|
} |
|
|
|
// the optimized case without any transformations at all |
|
void SceneOpenGL::paintSimpleScreen( QRegion, ToplevelList windows ) |
|
{ |
|
QList< Window* > phase2; |
|
for( int i = windows.count() - 1; // top to bottom |
|
i >= 0; |
|
--i ) |
|
{ |
|
Toplevel* c = windows[ i ]; |
|
assert( this->windows.contains( c )); |
|
Window& w = this->windows[ c ]; |
|
if( !w.isVisible()) |
|
continue; |
|
if( !w.isOpaque()) |
|
{ |
|
phase2.prepend( &w ); |
|
continue; |
|
} |
|
w.bindTexture(); |
|
w.draw(); |
|
} |
|
foreach( Window* w2, phase2 ) |
|
{ |
|
Window& w = *w2; |
|
w.bindTexture(); |
|
glEnable( GL_BLEND ); |
|
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); |
|
w.draw(); |
|
glDisable( GL_BLEND ); |
|
} |
|
} |
|
|
|
void SceneOpenGL::windowAdded( Toplevel* c ) |
|
{ |
|
assert( !windows.contains( c )); |
|
windows[ c ] = Window( c ); |
|
} |
|
|
|
void SceneOpenGL::windowDeleted( Toplevel* c ) |
|
{ |
|
assert( windows.contains( c )); |
|
windows[ c ].free(); |
|
windows.remove( c ); |
|
} |
|
|
|
void SceneOpenGL::windowGeometryShapeChanged( Toplevel* c ) |
|
{ |
|
if( !windows.contains( c )) // this is ok, shape is not valid |
|
return; // by default |
|
Window& w = windows[ c ]; |
|
w.discardShape(); |
|
w.discardTexture(); |
|
} |
|
|
|
void SceneOpenGL::windowOpacityChanged( Toplevel* ) |
|
{ |
|
#if 0 // not really needed, windows are painted on every repaint |
|
// and opacity is used when applying texture, not when |
|
// creating it |
|
if( !windows.contains( c )) // this is ok, texture is created |
|
return; // on demand |
|
Window& w = windows[ c ]; |
|
w.discardTexture(); |
|
#endif |
|
} |
|
|
|
SceneOpenGL::Window::Window( Toplevel* c ) |
|
: toplevel( c ) |
|
, texture( 0 ) |
|
, texture_y_inverted( false ) |
|
, bound_pixmap( None ) |
|
, bound_glxpixmap( None ) |
|
, shape_valid( false ) |
|
{ |
|
} |
|
|
|
SceneOpenGL::Window::~Window() |
|
{ |
|
} |
|
|
|
void SceneOpenGL::Window::free() |
|
{ |
|
discardTexture(); |
|
} |
|
|
|
void SceneOpenGL::Window::bindTexture() |
|
{ |
|
if( texture != 0 && toplevel->damage().isEmpty() |
|
&& !tfp_mode ) // interestingly this makes tfp slower |
|
{ |
|
// texture doesn't need updating, just bind it |
|
glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture ); |
|
return; |
|
} |
|
// TODO cache pixmaps here if possible |
|
Pixmap window_pix = toplevel->createWindowPixmap(); |
|
Pixmap pix = window_pix; |
|
// HACK |
|
// When a window uses ARGB visual and has a decoration, the decoration |
|
// does use ARGB visual. When converting such window to a texture |
|
// the alpha for the decoration part is broken for some reason (undefined?). |
|
// I wasn't lucky converting KWin to use ARGB visuals for decorations, |
|
// so instead simply set alpha in those parts to opaque. |
|
// Without ALPHA_CLEAR_COPY the setting is done directly in the window |
|
// pixmap, which seems to be ok, but let's not risk trouble right now. |
|
// TODO check if this isn't a performance problem and how it can be done better |
|
Client* c = dynamic_cast< Client* >( toplevel ); |
|
bool alpha_clear = c != NULL && c->hasAlpha() && !c->noBorder(); |
|
#define ALPHA_CLEAR_COPY |
|
#ifdef ALPHA_CLEAR_COPY |
|
if( alpha_clear ) |
|
{ |
|
Pixmap p2 = XCreatePixmap( display(), pix, c->width(), c->height(), 32 ); |
|
GC gc = XCreateGC( display(), pix, 0, NULL ); |
|
XCopyArea( display(), pix, p2, gc, 0, 0, c->width(), c->height(), 0, 0 ); |
|
pix = p2; |
|
XFreeGC( display(), gc ); |
|
} |
|
#endif |
|
if( alpha_clear ) |
|
{ |
|
XGCValues gcv; |
|
gcv.foreground = 0xff000000; |
|
gcv.plane_mask = 0xff000000; |
|
GC gc = XCreateGC( display(), pix, GCPlaneMask | GCForeground, &gcv ); |
|
XFillRectangle( display(), pix, gc, 0, 0, c->width(), c->clientPos().y()); |
|
XFillRectangle( display(), pix, gc, 0, 0, c->clientPos().x(), c->height()); |
|
int tw = c->clientPos().x() + c->clientSize().width(); |
|
int th = c->clientPos().y() + c->clientSize().height(); |
|
XFillRectangle( display(), pix, gc, 0, th, c->width(), c->height() - th ); |
|
XFillRectangle( display(), pix, gc, tw, 0, c->width() - tw, c->height()); |
|
XFreeGC( display(), gc ); |
|
glXWaitX(); |
|
} |
|
if( tfp_mode ) |
|
{ |
|
if( texture == None ) |
|
glGenTextures( 1, &texture ); |
|
if( bound_pixmap != None ) |
|
{ |
|
glXReleaseTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT ); |
|
glXDestroyGLXPixmap( display(), bound_glxpixmap ); |
|
XFreePixmap( display(), bound_pixmap ); |
|
} |
|
static const int attrs[] = |
|
{ |
|
GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT, |
|
None |
|
}; |
|
bound_pixmap = pix; |
|
bound_glxpixmap = glXCreatePixmap( display(), fbcdrawable, pix, attrs ); |
|
int value; |
|
glXGetFBConfigAttrib( display(), fbcdrawable, GLX_Y_INVERTED_EXT, &value ); |
|
// this is swapped in order to get a conversion of OpenGL coordinates |
|
// (binding to a texture is not affected by transforming the OpenGL scene) |
|
texture_y_inverted = value ? false : true; |
|
glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture ); |
|
glXBindTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT, NULL ); |
|
} |
|
else |
|
{ |
|
GLXDrawable pixmap = glXCreatePixmap( display(), fbcdrawable, pix, NULL ); |
|
glXMakeContextCurrent( display(), pixmap, pixmap, context ); |
|
glReadBuffer( GL_FRONT ); |
|
glDrawBuffer( GL_FRONT ); |
|
if( texture == None ) |
|
{ |
|
glGenTextures( 1, &texture ); |
|
glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture ); |
|
texture_y_inverted = true; // conversion to OpenGL coordinates |
|
glCopyTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, |
|
toplevel->hasAlpha() ? GL_RGBA : GL_RGB, |
|
0, 0, toplevel->width(), toplevel->height(), 0 ); |
|
} |
|
else |
|
{ |
|
glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture ); |
|
if( !toplevel->damage().isEmpty()) |
|
{ |
|
foreach( QRect r, toplevel->damage().rects()) |
|
{ |
|
// convert to OpenGL coordinates (this is mapping |
|
// the pixmap to a texture, this is not affected |
|
// by transforming the OpenGL scene) |
|
int gly = toplevel->height() - r.y() - r.height(); |
|
texture_y_inverted = true; |
|
glCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, |
|
r.x(), gly, r.x(), gly, r.width(), r.height()); |
|
} |
|
} |
|
} |
|
// the pixmap is no longer needed, the texture will be updated |
|
// only when the window changes anyway, so no need to cache |
|
// the pixmap |
|
glXDestroyPixmap( display(), pixmap ); |
|
XFreePixmap( display(), pix ); |
|
} |
|
#ifdef ALPHA_CLEAR_COPY |
|
if( alpha_clear ) |
|
XFreePixmap( display(), window_pix ); |
|
#endif |
|
} |
|
|
|
void SceneOpenGL::Window::discardTexture() |
|
{ |
|
if( texture != 0 ) |
|
{ |
|
if( tfp_mode ) |
|
{ |
|
glXReleaseTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT ); |
|
glXDestroyGLXPixmap( display(), bound_glxpixmap ); |
|
XFreePixmap( display(), bound_pixmap ); |
|
bound_pixmap = None; |
|
bound_glxpixmap = None; |
|
} |
|
glDeleteTextures( 1, &texture ); |
|
} |
|
texture = 0; |
|
} |
|
|
|
|
|
void SceneOpenGL::Window::discardShape() |
|
{ |
|
shape_valid = false; |
|
} |
|
|
|
QRegion SceneOpenGL::Window::shape() const |
|
{ |
|
if( !shape_valid ) |
|
{ |
|
Client* c = dynamic_cast< Client* >( toplevel ); |
|
if( toplevel->shape() || ( c != NULL && !c->mask().isEmpty())) |
|
{ |
|
int count, order; |
|
XRectangle* rects = XShapeGetRectangles( display(), toplevel->handle(), |
|
ShapeBounding, &count, &order ); |
|
if(rects) |
|
{ |
|
shape_region = QRegion(); |
|
for( int i = 0; |
|
i < count; |
|
++i ) |
|
shape_region += QRegion( rects[ i ].x, rects[ i ].y, |
|
rects[ i ].width, rects[ i ].height ); |
|
XFree(rects); |
|
} |
|
else |
|
shape_region = QRegion( 0, 0, width(), height()); |
|
} |
|
else |
|
shape_region = QRegion( 0, 0, width(), height()); |
|
shape_valid = true; |
|
} |
|
return shape_region; |
|
} |
|
|
|
static void quadDraw( int x1, int y1, int x2, int y2, bool invert_y ) |
|
{ |
|
glTexCoord2i( x1, invert_y ? y2 : y1 ); |
|
glVertex2i( x1, y1 ); |
|
glTexCoord2i( x2, invert_y ? y2 : y1 ); |
|
glVertex2i( x2, y1 ); |
|
glTexCoord2i( x2, invert_y ? y1 : y2 ); |
|
glVertex2i( x2, y2 ); |
|
glTexCoord2i( x1, invert_y ? y1 : y2 ); |
|
glVertex2i( x1, y2 ); |
|
} |
|
|
|
void SceneOpenGL::Window::draw() |
|
{ |
|
// TODO for double-buffered root glDrawBuffer( GL_BACK ); |
|
glXMakeContextCurrent( display(), glxroot, glxroot, context ); |
|
glPushMatrix(); |
|
glTranslatef( x(), y(), 0 ); |
|
if( toplevel->opacity() != 1.0 ) |
|
{ |
|
if( toplevel->hasAlpha()) |
|
{ |
|
glEnable( GL_BLEND ); |
|
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); |
|
glColor4f( toplevel->opacity(), toplevel->opacity(), toplevel->opacity(), |
|
toplevel->opacity()); |
|
} |
|
else |
|
{ |
|
float constant_alpha[] = { 0, 0, 0, toplevel->opacity() }; |
|
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE ); |
|
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE ); |
|
glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE ); |
|
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE ); |
|
glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT ); |
|
glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_alpha ); |
|
} |
|
} |
|
glEnable( GL_TEXTURE_RECTANGLE_ARB ); |
|
glBegin( GL_QUADS ); |
|
foreach( QRect r, shape().rects()) |
|
{ |
|
quadDraw( r.x(), r.y(), r.x() + r.width(), r.y() + r.height(), |
|
texture_y_inverted ); |
|
} |
|
glEnd(); |
|
glPopMatrix(); |
|
if( toplevel->opacity() != 1.0 ) |
|
{ |
|
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); |
|
glColor4f( 0, 0, 0, 0 ); |
|
glDisable( GL_BLEND ); |
|
} |
|
glDisable( GL_TEXTURE_RECTANGLE_ARB ); |
|
glBindTexture( GL_TEXTURE_RECTANGLE_ARB, 0 ); |
|
} |
|
|
|
bool SceneOpenGL::Window::isVisible() const |
|
{ |
|
// TODO mapping state? |
|
return !toplevel->geometry() |
|
.intersect( QRect( 0, 0, displayWidth(), displayHeight())) |
|
.isEmpty(); |
|
} |
|
|
|
bool SceneOpenGL::Window::isOpaque() const |
|
{ |
|
return toplevel->opacity() == 1.0 && !toplevel->hasAlpha(); |
|
} |
|
|
|
} // namespace
|
|
|