diff options
Diffstat (limited to 'examples/opengl/overlay_x11')
-rw-r--r-- | examples/opengl/overlay_x11/README | 74 | ||||
-rw-r--r-- | examples/opengl/overlay_x11/README.X11-OVERLAYS | 92 | ||||
-rw-r--r-- | examples/opengl/overlay_x11/gearwidget.cpp | 268 | ||||
-rw-r--r-- | examples/opengl/overlay_x11/gearwidget.h | 29 | ||||
-rw-r--r-- | examples/opengl/overlay_x11/main.cpp | 125 | ||||
-rw-r--r-- | examples/opengl/overlay_x11/overlay_x11.doc | 82 | ||||
-rw-r--r-- | examples/opengl/overlay_x11/overlayrubber.pro | 14 | ||||
-rw-r--r-- | examples/opengl/overlay_x11/rubberbandwidget.cpp | 59 | ||||
-rw-r--r-- | examples/opengl/overlay_x11/rubberbandwidget.h | 37 | ||||
-rw-r--r-- | examples/opengl/overlay_x11/utilities/NOTICE | 11 | ||||
-rw-r--r-- | examples/opengl/overlay_x11/utilities/README | 22 | ||||
-rw-r--r-- | examples/opengl/overlay_x11/utilities/glxvisuals/glxvisuals.c | 147 | ||||
-rw-r--r-- | examples/opengl/overlay_x11/utilities/sovinfo/sovLayerUtil.h | 54 | ||||
-rw-r--r-- | examples/opengl/overlay_x11/utilities/sovinfo/sovinfo.c | 95 | ||||
-rw-r--r-- | examples/opengl/overlay_x11/utilities/sovinfo/sovlayerutil.c | 150 |
15 files changed, 1259 insertions, 0 deletions
diff --git a/examples/opengl/overlay_x11/README b/examples/opengl/overlay_x11/README new file mode 100644 index 000000000..eba728e67 --- /dev/null +++ b/examples/opengl/overlay_x11/README @@ -0,0 +1,74 @@ + +----------------------------------------------------------------------- +UPDATE: From version 5.0 onwards, the Qt OpenGL Extension includes +direct support for use of OpenGL overlays. For many uses of overlays, +this makes the technique described below redundant. See the 'overlay' +example program. The following is a discussion on how to use non-QGL +widgets in overlay planes. +----------------------------------------------------------------------- + +Overlayrubber: An example program showing how to use Qt and Qt OpenGL +Extension with X11 overlay visuals. + +(Background information for this example can be found in the file + README.X11-OVERLAYS) + +The example program has three main parts: + +GearWidget: A simple QGLWidget that renders the usual gears. Modified +so that it will print a debug message every time it redraws (renders) +itself. Thus, you can eaily confirm that drawing in the overlay plane +does not cause redrawings in the main plane where the QGLWidget +resides. + +RubberbandWidget: Very simple standard (non-GL) Qt widget that +implements rubberband drawing. Designed for use in an overlay +plane. It takes the planes' transparent color as a constructor +argument and uses that for its background color. Thus, the widget +itself will be invisible, only the rubberbands it draws will be +visible. + +main.cpp: Creates a GearWidget and a Rubberbandwidget and puts the +latter on top of the former. Contains a routine that checks that the +default visual is in an overlay plane, and returns the transparent +color of that plane. + + +Running it: +----------- + +Start the overlayrubber executable. Click and drag with the left mouse +button to see rubberband drawing. Observe that the QGLWidget does +not redraw itself (no redraw debug messages are output), and yet the +image is not destroyed. Marvel at the coolness of X11 overlays! + + +Using this technique in a real application +------------------------------------------ + +For clarity, this example program has been kept very simple. Here are +some hints for real application use: + +All normal widgets can go in the overlay plane: This means that you +can put all kinds of Qt widgets (your own or those provided with Qt) +on top of the OpenGL image (widget), e.g. pushbuttons etc., and they +can be moved, resized, or removed without destroying the OpenGL image. + +Using with geometry management: The QLayout classes will not allow you +to put one widget (the overlay) on top of another (the OpenGL widget); +that would defy the whole purpose of the automatic layout. The +solution is to add just one of them to the QLayout object. Have it +keep a pointer to the other (i.e. the QGLWidget knows about its +overlay widget or vice versa). Implement the resizeEvent() method of +the widget you put in the layout, and make it call setGeometry() on +the other widget with its own geometry as parameters, thus keeping the +two widgets' geometries synchronized. + +Using with QPalette and QColorGroup: Instead of the somewhat +simplistic setBackgroundColor( transparentColor ), you can use Qt's +QPalette system for having your overlay widgets use transparent color +for what you want. This way, the normal Qt widgets can be used as +overlays for fancy effects: just create a palette for them with the +transparent color for the wanted color roles, e.g. Background and +Base, in the Normal and/or Active modes. This way, you can create +see-through QPushButtons etc. diff --git a/examples/opengl/overlay_x11/README.X11-OVERLAYS b/examples/opengl/overlay_x11/README.X11-OVERLAYS new file mode 100644 index 000000000..6029ca3eb --- /dev/null +++ b/examples/opengl/overlay_x11/README.X11-OVERLAYS @@ -0,0 +1,92 @@ + + HOW TO USE X11 OVERLAYS WITH THE QT OPENGL EXTENSION + +X11 overlays is a powerful mechanism that allows one to draw +annotations etc. on top of an image without destroying it, thus saving +significant image rendering time. For more information, consult the +highly recommended book "OpenGL Programming for the X Window System" +(Mark Kilgard, Addison Wesley Developers Press 1996). + +----------------------------------------------------------------------- +UPDATE: From version 5.0 onwards, the Qt OpenGL Extension includes +direct support for use of OpenGL overlays. For many uses of overlays, +this makes the technique described below redundant. See the 'overlay' +example program. The following is a discussion on how to use non-QGL +widgets in overlay planes. +----------------------------------------------------------------------- + +In the typical case, X11 overlays can easily be used together with the +current version of Qt and the Qt OpenGL Extension. The following +retquirements apply: + +1) Your X server and graphics card/hardware must support overlays (of + course). For many X servers, overlay support can be turned on with + a configuration option; consult your X server installation + documentation. + +2) Your X server must (be configured to) use an overlay visual as the + default visual. Most modern X servers do this, since this has the + added advantage that pop-up menus, overlapping windows etc. will + not destroy underlying images in the main plane, saving expensive + redraws. + +3) The best (deepest) visual for OpenGL rendering is in the main + plane. This is the normal case. Typically, X servers that support + overlays provide a 24 bit deep TrueColor visuals in the main plane, + and an 8 bit PseudoColor (default) visual in the overlay plane. + +The provided example program "overlayrubber" will check for all this +and tell you what is wrong, if anything. See "About X11 Visuals" below +for more information. + + +How it works: +------------- + +Given the above, a QGLWidget will by default use the main plane +visual, while all other widgets will use the overlay visual. Thus, one +can place a normal widget on top of the QGLWidget, and do drawing in +it, without destroying the image in the OpenGL window. In other words, +one can use all the drawing capabilities of QPainter to draw the +annotations, rubberbands, whatever. For the typical use of overlays, +this is much easier than using OpenGL for rendering the annotations. + +An overlay plane has a specific color called the transparent +color. Pixels drawn in this color will not be visible, instead the +underlying OpenGL image will show through. In the example program +"overlayrubber", the file main.cpp contains a routine that returns a +QColor containing the transparent color. For the overlay widget, one +will typically want to set the background color to the transparent +color, so that the OpenGL image shows through except where explicitly +overpainted. + +Note: To use this technique, you must not use the "ManyColor" or +"TrueColor" ColorSpec for the QApplication, because this will force +the normal Qt widgets to use a TrueColor visual, which will typically +be in the main plane, not in the overlay plane as desired. + + + +About X11 visuals: +------------------ + +The utilities directory contains two small programs that can help you +determine the capabilities of your X server. These programs are from +the OpenGL book mentioned above, see utilities/NOTICE for copyright +information. The full set of example programs from this book is +available at ftp://ftp.sgi.com/pub/opengl/opengl_for_x/ + +"glxvisuals" will list all the GL-capable visuals the X server provides, +together with the depth and other GL-specific information for +each. Note especially the column "lvl"; a number in this column means +the visual is in an overlay plane. + +"sovinfo" will list all available visuals, and provides special +transparency information for overlay visuals. + +The overlayrubber example program will output what visual is used for +the normal Qt widgets, and what visual is used by the QGLWidget. + + + +Comments are welcome at info@trolltech.com. diff --git a/examples/opengl/overlay_x11/gearwidget.cpp b/examples/opengl/overlay_x11/gearwidget.cpp new file mode 100644 index 000000000..4d717f27e --- /dev/null +++ b/examples/opengl/overlay_x11/gearwidget.cpp @@ -0,0 +1,268 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of an example program for TQt. This example +** program may be used, distributed and modified without limitation. +** +*****************************************************************************/ +// +// A TQt OpenGL widget that draws a gear. +// +// Portions of this code has been borrowed from Brian Paul's Mesa +// distribution. +// + +#include "gearwidget.h" +#include <math.h> +#if defined(Q_WS_X11) +#include <X11/Xlib.h> +#endif + +#if defined(Q_CC_MSVC) +#pragma warning(disable:4305) // init: truncation from const double to float +#endif + +/* + * Draw a gear wheel. You'll probably want to call this function when + * building a display list since we do a lot of trig here. + * + * Input: inner_radius - radius of hole at center + * outer_radius - radius at center of teeth + * width - width of gear + * teeth - number of teeth + * tooth_depth - depth of tooth + */ +static void gear( GLfloat inner_radius, GLfloat outer_radius, GLfloat width, + GLint teeth, GLfloat tooth_depth ) +{ + GLint i; + GLfloat r0, r1, r2; + GLfloat angle, da; + GLfloat u, v, len; + + r0 = inner_radius; + r1 = outer_radius - tooth_depth/2.0; + r2 = outer_radius + tooth_depth/2.0; + + const double pi = 3.14159264; + da = 2.0*pi / teeth / 4.0; + + glShadeModel( GL_FLAT ); + + glNormal3f( 0.0, 0.0, 1.0 ); + + /* draw front face */ + glBegin( GL_QUAD_STRIP ); + for (i=0;i<=teeth;i++) { + angle = i * 2.0*pi / teeth; + glVertex3f( r0*cos(angle), r0*sin(angle), width*0.5 ); + glVertex3f( r1*cos(angle), r1*sin(angle), width*0.5 ); + glVertex3f( r0*cos(angle), r0*sin(angle), width*0.5 ); + glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5 ); + } + glEnd(); + + /* draw front sides of teeth */ + glBegin( GL_QUADS ); + da = 2.0*pi / teeth / 4.0; + for (i=0;i<teeth;i++) { + angle = i * 2.0*pi / teeth; + + glVertex3f( r1*cos(angle), r1*sin(angle), width*0.5 ); + glVertex3f( r2*cos(angle+da), r2*sin(angle+da), width*0.5 ); + glVertex3f( r2*cos(angle+2*da), r2*sin(angle+2*da), width*0.5 ); + glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5 ); + } + glEnd(); + + + glNormal3f( 0.0, 0.0, -1.0 ); + + /* draw back face */ + glBegin( GL_QUAD_STRIP ); + for (i=0;i<=teeth;i++) { + angle = i * 2.0*pi / teeth; + glVertex3f( r1*cos(angle), r1*sin(angle), -width*0.5 ); + glVertex3f( r0*cos(angle), r0*sin(angle), -width*0.5 ); + glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), -width*0.5 ); + glVertex3f( r0*cos(angle), r0*sin(angle), -width*0.5 ); + } + glEnd(); + + /* draw back sides of teeth */ + glBegin( GL_QUADS ); + da = 2.0*pi / teeth / 4.0; + for (i=0;i<teeth;i++) { + angle = i * 2.0*pi / teeth; + + glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), -width*0.5 ); + glVertex3f( r2*cos(angle+2*da), r2*sin(angle+2*da), -width*0.5 ); + glVertex3f( r2*cos(angle+da), r2*sin(angle+da), -width*0.5 ); + glVertex3f( r1*cos(angle), r1*sin(angle), -width*0.5 ); + } + glEnd(); + + + /* draw outward faces of teeth */ + glBegin( GL_QUAD_STRIP ); + for (i=0;i<teeth;i++) { + angle = i * 2.0*pi / teeth; + + glVertex3f( r1*cos(angle), r1*sin(angle), width*0.5 ); + glVertex3f( r1*cos(angle), r1*sin(angle), -width*0.5 ); + u = r2*cos(angle+da) - r1*cos(angle); + v = r2*sin(angle+da) - r1*sin(angle); + len = sqrt( u*u + v*v ); + u /= len; + v /= len; + glNormal3f( v, -u, 0.0 ); + glVertex3f( r2*cos(angle+da), r2*sin(angle+da), width*0.5 ); + glVertex3f( r2*cos(angle+da), r2*sin(angle+da), -width*0.5 ); + glNormal3f( cos(angle), sin(angle), 0.0 ); + glVertex3f( r2*cos(angle+2*da), r2*sin(angle+2*da), width*0.5 ); + glVertex3f( r2*cos(angle+2*da), r2*sin(angle+2*da), -width*0.5 ); + u = r1*cos(angle+3*da) - r2*cos(angle+2*da); + v = r1*sin(angle+3*da) - r2*sin(angle+2*da); + glNormal3f( v, -u, 0.0 ); + glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5 ); + glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), -width*0.5 ); + glNormal3f( cos(angle), sin(angle), 0.0 ); + } + + glVertex3f( r1*cos(0.0), r1*sin(0.0), width*0.5 ); + glVertex3f( r1*cos(0.0), r1*sin(0.0), -width*0.5 ); + + glEnd(); + + + glShadeModel( GL_SMOOTH ); + + /* draw inside radius cylinder */ + glBegin( GL_QUAD_STRIP ); + for (i=0;i<=teeth;i++) { + angle = i * 2.0*pi / teeth; + glNormal3f( -cos(angle), -sin(angle), 0.0 ); + glVertex3f( r0*cos(angle), r0*sin(angle), -width*0.5 ); + glVertex3f( r0*cos(angle), r0*sin(angle), width*0.5 ); + } + glEnd(); + +} + + +static GLfloat view_rotx=20.0, view_roty=30.0, view_rotz=0.0; +static GLint gear1, gear2, gear3; +static GLfloat angle = 0.0; + + +static void draw() +{ + angle += 2.0; + view_roty += 1.0; + + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + glPushMatrix(); + glRotatef( view_rotx, 1.0, 0.0, 0.0 ); + glRotatef( view_roty, 0.0, 1.0, 0.0 ); + glRotatef( view_rotz, 0.0, 0.0, 1.0 ); + + glPushMatrix(); + glTranslatef( -3.0, -2.0, 0.0 ); + glRotatef( angle, 0.0, 0.0, 1.0 ); + glCallList(gear1); + glPopMatrix(); + + glPushMatrix(); + glTranslatef( 3.1, -2.0, 0.0 ); + glRotatef( -2.0*angle-9.0, 0.0, 0.0, 1.0 ); + glCallList(gear2); + glPopMatrix(); + + glPushMatrix(); + glTranslatef( -3.1, 2.2, -1.8 ); + glRotatef( 90.0, 1.0, 0.0, 0.0 ); + glRotatef( 2.0*angle-2.0, 0.0, 0.0, 1.0 ); + glCallList(gear3); + glPopMatrix(); + + glPopMatrix(); +} + + + +GearWidget::GearWidget( TQWidget *parent, const char *name ) + : TQGLWidget( parent, name ) +{ +} + +void GearWidget::initializeGL() +{ + static GLfloat pos[4] = {5.0, 5.0, 10.0, 1.0 }; + static GLfloat redgear[4] = {0.8, 0.1, 0.0, 1.0 }; + static GLfloat greengear[4] = {0.0, 0.8, 0.2, 1.0 }; + static GLfloat bluegear[4] = {0.2, 0.2, 1.0, 1.0 }; + + glLightfv( GL_LIGHT0, GL_POSITION, pos ); + glEnable( GL_CULL_FACE ); + glEnable( GL_LIGHTING ); + glEnable( GL_LIGHT0 ); + glEnable( GL_DEPTH_TEST ); + + /* make the gears */ + gear1 = glGenLists(1); + glNewList(gear1, GL_COMPILE); + glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, redgear ); + gear( 1.0, 4.0, 1.0, 20, 0.7 ); + glEndList(); + + gear2 = glGenLists(1); + glNewList(gear2, GL_COMPILE); + glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, greengear ); + gear( 0.5, 2.0, 2.0, 10, 0.7 ); + glEndList(); + + gear3 = glGenLists(1); + glNewList(gear3, GL_COMPILE); + glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, bluegear ); + gear( 1.3, 2.0, 0.5, 10, 0.7 ); + glEndList(); + + glEnable( GL_NORMALIZE ); +} + + +void GearWidget::resizeGL( int width, int height ) +{ + GLfloat w = (float) width / (float) height; + GLfloat h = 1.0; + + glViewport( 0, 0, width, height ); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum( -w, w, -h, h, 5.0, 60.0 ); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef( 0.0, 0.0, -40.0 ); +} + + +void GearWidget::paintGL() +{ + qDebug( "GearWidget: Doing GL rendering." ); +#if defined (Q_GLX) + static bool doneIt = FALSE; + if ( !doneIt ) { + doneIt = TRUE; + // Print out the Visual ID. Access to this will be made + // simpler in future versions of TQt! + XWindowAttributes a; + XGetWindowAttributes( x11Display(), winId(), &a ); + qDebug( "TQGLWidget: using Visual ID: 0x%x.", + (int)XVisualIDFromVisual( a.visual ) ); + } +#endif + draw(); +} + diff --git a/examples/opengl/overlay_x11/gearwidget.h b/examples/opengl/overlay_x11/gearwidget.h new file mode 100644 index 000000000..6154e36da --- /dev/null +++ b/examples/opengl/overlay_x11/gearwidget.h @@ -0,0 +1,29 @@ +/**************************************************************************** +** +** Definition of a simple TQt OpenGL widget +** +** Copyright (C) 1999-2008 Trolltech ASA. All rights reserved. +** +** This file is part of an example program for TQt. This example +** program may be used, distributed and modified without limitation. +** +*****************************************************************************/ + +#ifndef GEAR_H +#define GEAR_H + +#include <qgl.h> + +class GearWidget : public TQGLWidget +{ +public: + GearWidget( TQWidget *parent=0, const char *name=0 ); + +protected: + void initializeGL(); + void resizeGL( int, int ); + void paintGL(); +}; + + +#endif diff --git a/examples/opengl/overlay_x11/main.cpp b/examples/opengl/overlay_x11/main.cpp new file mode 100644 index 000000000..70a6f4362 --- /dev/null +++ b/examples/opengl/overlay_x11/main.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Example application showing how to use TQt and TQt OpenGL Extension on an +** X11 overlay visual +** +** Copyright (C) 1999-2008 Trolltech ASA. All rights reserved. +** +** This file is part of an example program for TQt. This example +** program may be used, distributed and modified without limitation. +** +*****************************************************************************/ + +#include <qapplication.h> +#include "gearwidget.h" +#include "rubberbandwidget.h" + +#if defined(Q_WS_X11) +#include <X11/Xlib.h> +#endif + +TQColor findOverlayTransparentColor() +{ + TQColor invalidColor; + +#if defined(Q_WS_X11) + + Display* appDisplay; + Visual* appVisual; + + // The static methods are called 'App' in TQt 2.x +#if QT_VERSION < 200 + appDisplay = TQPaintDevice::x__Display(); + appVisual = (Visual*)TQPaintDevice::x11Visual(); +#else + appDisplay = TQPaintDevice::x11AppDisplay(); + appVisual = (Visual*)TQPaintDevice::x11AppVisual(); +#endif + + qDebug( "Default Visual ID: 0x%x", (int)XVisualIDFromVisual(appVisual) ); + + typedef struct OverlayProp { + long visual; + long type; + long value; + long layer; + } OverlayProp; + + TQWidget* rootWin = TQApplication::desktop(); + if ( !rootWin ) + return invalidColor; // Should not happen + + Atom overlayVisualsAtom = XInternAtom( appDisplay, + "SERVER_OVERLAY_VISUALS", True ); + if ( overlayVisualsAtom == None ) { + warning( "Server has no overlay visuals" ); + return invalidColor; + } + + Atom actualType; + int actualFormat; + ulong nItems; + ulong bytesAfter; + OverlayProp* overlayProp; + int res = XGetWindowProperty( appDisplay, TQApplication::desktop()->winId(), + overlayVisualsAtom, 0, 10000, False, + overlayVisualsAtom, &actualType, + &actualFormat, &nItems, &bytesAfter, + (uchar**)&overlayProp ); + + if ( res != Success || actualType != overlayVisualsAtom + || actualFormat != 32 || nItems < 4 ) { + warning( "Failed to get overlay visual property from server" ); + return invalidColor; + } + + + for ( uint i = 0; i < nItems/4; i++ ) { + if ( (VisualID)overlayProp[i].visual == XVisualIDFromVisual(appVisual) + && overlayProp[i].type == 1 ) + return TQColor( qRgb( 1, 2, 3 ), overlayProp[i].value ); + } + + qWarning( "Default visual is not in overlay plane" ); + return invalidColor; + +#else // defined(Q_WS_X11) + qWarning( "Wrong window system - Only X11 has overlay support." ); + return invalidColor; +#endif +} + + +int main( int argc, char **argv ) +{ + TQApplication::setColorSpec( TQApplication::CustomColor ); + TQApplication a( argc, argv ); + + if ( !TQGLFormat::hasOpenGL() ) { + qWarning( "This system has no OpenGL support. Exiting." ); + return -1; + } + + TQColor transparentColor = findOverlayTransparentColor(); + if ( !transparentColor.isValid() ) { + qWarning( "Failed to get transparent color for overlay. Exiting." ); + return -1; + } + + TQWidget top; + a.setMainWidget( &top ); + top.setGeometry( 50, 50, 600, 400 ); + + // Make an OpenGL widget. It will use the deepest visual available + // (typically a TrueColor visual), which typically is in the normal layer. + GearWidget g( &top ); + g.setGeometry( 20, 20, 560, 360 ); + + // Put the rubberband widget (which uses the default, i.e. overlay visual) + // on top of the OpenGL widget: + RubberbandWidget r( transparentColor, &top ); + r.setGeometry( 20, 20, 560, 360 ); + + top.show(); + return a.exec(); +} diff --git a/examples/opengl/overlay_x11/overlay_x11.doc b/examples/opengl/overlay_x11/overlay_x11.doc new file mode 100644 index 000000000..6dddc9b9b --- /dev/null +++ b/examples/opengl/overlay_x11/overlay_x11.doc @@ -0,0 +1,82 @@ +/*! \page opengl-overlay-x11-example.html + + \ingroup opengl-examples + \title OpenGL Overlay X11 Example + +\warning From version 5.0 onwards, the Qt OpenGL Extension includes +direct support for use of OpenGL overlays. For many uses of overlays, +this makes the technique described below redundant. See the \link +opengl-overlay-example.html overlay\endlink example program. The +following is a discussion on how to use non-QGL widgets in overlay +planes. + +Overlayrubber: An example program showing how to use Qt and Qt OpenGL +Extension with X11 overlay visuals. + +See \c{$QTDIR/examples/opengl/overlay_x11} for the source code. + +Background information for this example can be found in the +information on \link opengl-x11-overlays.html overlays\endlink. + +The example program has three main parts: + +\list 1 +\i \e GearWidget - a normal, simple QGLWidget. This renders the usual +gears. It has been modified to print a debug message every time it +redraws (renders) itself. Thus, you can easily confirm that drawing in +the overlay plane does not cause redrawings in the main plane where +the QGLWidget resides. + +\i \e RubberbandWidget - Very simple standard (non-GL) Qt widget that +implements rubberband drawing. Designed for use in an overlay plane. +It takes the plane's transparent color as a constructor argument and +uses that for its background color. Thus, the widget itself will be +invisible, only the rubberbands it draws will be visible. + +\i \e{main.cpp} Creates a GearWidget and a Rubberbandwidget and puts the +latter on top of the former. Contains a routine that checks that the +default visual is in an overlay plane, and returns the transparent +color of that plane. +\endlist + +\section1 Running the Example + +Start the \c overlayrubber executable. Click and drag with the left +mouse button to see rubberband drawing. Observe that the QGLWidget +does not redraw itself (no redraw debug messages are output), and yet +the image is not destroyed. Marvel at the coolness of X11 overlays! + + +\section1 Using this technique in a real application + +For clarity, this example program has been kept very simple. Here are +some hints for real application usage: + +\list + +\i \e{All normal widgets are in the overlay plane.} This means that you +can put all kinds of Qt widgets (your own or standard Qt widgets) on +top of the OpenGL image (widget), e.g. pushbuttons etc., and they can +be moved, resized, or removed without destroying the OpenGL image. + +\i \e{Using with geometry management.} The QLayout classes don't permit +putting one widget (the overlay) on top of another (the OpenGL +widget); that would defy the whole purpose of the automatic layout. +The solution is to add just one of them to the QLayout object. Have it +keep a pointer to the other (i.e. the QGLWidget knows about its +overlay widget or vice versa). Implement the resizeEvent() method of +the widget you put in the layout, and make it call setGeometry() on +the other widget with its own geometry as parameters, thus keeping the +two widgets' geometries synchronized. + +\i \e{Using together with QPalette and QColorGroup.} Instead of the +simplistic setBackgroundColor( transparentColor ), you can +use Qt's QPalette system to make your overlay widgets use +transparent color for what you want. This way, the normal Qt widgets +can be used as overlays for fancy effects. Just create a palette for +them with the transparent color for the relevant color roles, e.g. +Background and Base, in the Normal and/or Active modes. This way, you +can create see-through QPushButtons etc. +\endlist + +*/ diff --git a/examples/opengl/overlay_x11/overlayrubber.pro b/examples/opengl/overlay_x11/overlayrubber.pro new file mode 100644 index 000000000..5381ebb2e --- /dev/null +++ b/examples/opengl/overlay_x11/overlayrubber.pro @@ -0,0 +1,14 @@ +TEMPLATE = app +TARGET = overlayrubber + +CONFIG += qt opengl warn_on release +CONFIG -= dlopen_opengl +DEPENDPATH = ../include + +REQUIRES = opengl full-config + +HEADERS = gearwidget.h \ + rubberbandwidget.h +SOURCES = gearwidget.cpp \ + main.cpp \ + rubberbandwidget.cpp diff --git a/examples/opengl/overlay_x11/rubberbandwidget.cpp b/examples/opengl/overlay_x11/rubberbandwidget.cpp new file mode 100644 index 000000000..5cd5c5654 --- /dev/null +++ b/examples/opengl/overlay_x11/rubberbandwidget.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Implementation of a widget that draws a rubberband. Designed to be used +** in an X11 overlay visual +** +** Copyright (C) 1999-2008 Trolltech ASA. All rights reserved. +** +** This file is part of an example program for TQt. This example +** program may be used, distributed and modified without limitation. +** +*****************************************************************************/ + +#include "rubberbandwidget.h" +#include <qpainter.h> + + +RubberbandWidget::RubberbandWidget( TQColor transparentColor, TQWidget *parent, + const char *name, WFlags f ) + : TQWidget( parent, name, f ) +{ + setBackgroundColor( transparentColor ); + on = FALSE; +} + + +void RubberbandWidget::mousePressEvent( TQMouseEvent* e ) +{ + p1 = e->pos(); + p2 = p1; + p3 = p1; + on = TRUE; + setMouseTracking( TRUE ); +} + + +void RubberbandWidget::mouseMoveEvent( TQMouseEvent* e ) +{ + if ( on ) { + p2 = e->pos(); + TQPainter p( this ); + // Erase last drawn rubberband: + p.setPen( TQPen( backgroundColor(), 3 ) ); + p.drawRect( TQRect( p1, p3 ) ); + // Draw the new one: + p.setPen( TQPen( white, 3 ) ); + p.drawRect( TQRect(p1, p2) ); + p3 = p2; + } +} + +void RubberbandWidget::mouseReleaseEvent( TQMouseEvent* ) +{ + if ( on ) { + TQPainter p ( this ); + p.eraseRect( rect() ); + } + on = FALSE; + setMouseTracking( FALSE ); +} diff --git a/examples/opengl/overlay_x11/rubberbandwidget.h b/examples/opengl/overlay_x11/rubberbandwidget.h new file mode 100644 index 000000000..10513a6d6 --- /dev/null +++ b/examples/opengl/overlay_x11/rubberbandwidget.h @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Definition of a widget that draws a rubberband. Designed to be used +** in an X11 overlay visual +** +** Copyright (C) 1999-2008 Trolltech ASA. All rights reserved. +** +** This file is part of an example program for TQt. This example +** program may be used, distributed and modified without limitation. +** +*****************************************************************************/ + +#ifndef RUBBERBANDWIDGET_H +#define RUBBERBANDWIDGET_H + +#include <qwidget.h> + + +class RubberbandWidget : public TQWidget +{ +public: + RubberbandWidget( TQColor transparentColor, TQWidget *parent=0, + const char *name=0, WFlags f=0 ); + +protected: + void mousePressEvent( TQMouseEvent* e ); + void mouseMoveEvent( TQMouseEvent* e ); + void mouseReleaseEvent( TQMouseEvent* e ); + + TQColor c; + TQPoint p1; + TQPoint p2; + TQPoint p3; + bool on; +}; + +#endif diff --git a/examples/opengl/overlay_x11/utilities/NOTICE b/examples/opengl/overlay_x11/utilities/NOTICE new file mode 100644 index 000000000..4157392b3 --- /dev/null +++ b/examples/opengl/overlay_x11/utilities/NOTICE @@ -0,0 +1,11 @@ + +NOTICE: This source code distribution contains source code contained +in the book "Programming OpenGL for the X Window System" (ISBN: +0-201-48359-9) published by Addison-Wesley. The programs and +associated files contained in the distribution were developed by Mark +J. Kilgard and are Copyright 1994, 1995, 1996 by Mark J. Kilgard +(unless otherwise noted). The programs are not in the public domain, +but they are freely distributable without licensing fees. These +programs are provided without guarantee or warranty expressed or +implied. + diff --git a/examples/opengl/overlay_x11/utilities/README b/examples/opengl/overlay_x11/utilities/README new file mode 100644 index 000000000..d96f3437b --- /dev/null +++ b/examples/opengl/overlay_x11/utilities/README @@ -0,0 +1,22 @@ + +Welcome to the "Programming OpenGL for the X Window System" Xlib-based +example source code. The following table names each example program +directory and what section of the book discusses the example. + +Section Example directory +---------- ------------------ + 1.5 glxsimple + 2.1 glxdino + 2.2.2 glxvisuals + 2.6.1 pixmap2eps + 6.2.3.1 xdevices + 6.2.7 dials + 6.3.4 sovinfo + 6.3.5 layerdemo + +I've tried to make the Makefiles as simple and as portable as +possible. If you find problems with these examples, please report bugs +to mjk@sgi.com + +- Mark Kilgard + diff --git a/examples/opengl/overlay_x11/utilities/glxvisuals/glxvisuals.c b/examples/opengl/overlay_x11/utilities/glxvisuals/glxvisuals.c new file mode 100644 index 000000000..3c1a21e68 --- /dev/null +++ b/examples/opengl/overlay_x11/utilities/glxvisuals/glxvisuals.c @@ -0,0 +1,147 @@ + +/* Copyright (c) Mark J. Kilgard, 1996. */ + +/* This program is freely distributable without licensing fees + and is provided without guarantee or warrantee expressed or + implied. This program is -not- in the public domain. */ + +#include <stdlib.h> +#include <stdio.h> +#include <X11/Xlib.h> +#include <GL/glx.h> + +static char *ClassOf(int c); +static char *Format(int n, int w); + +void +main(int argc, char *argv[]) +{ + Display *dpy; + XVisualInfo match, *visualList, *vi, *visualToTry; + int errorBase, eventBase, major, minor, found; + int glxCapable, bufferSize, level, renderType, doubleBuffer, stereo, + auxBuffers, redSize, greenSize, blueSize, alphaSize, depthSize, + stencilSize, acRedSize, acGreenSize, acBlueSize, acAlphaSize; + + dpy = XOpenDisplay(NULL); + if (!dpy) { + fprintf(stderr, "Could not connect to %s.\n", XDisplayName(NULL)); + exit(1); + } + if (glXQueryExtension(dpy, &errorBase, &eventBase) == False) { + fprintf(stderr, "OpenGL not supported by X server.\n"); + exit(1); + } + + glXQueryVersion(dpy, &major, &minor); + printf("display: %s\n", XDisplayName(NULL)); + printf("using GLX version: %d.%d\n\n", major, minor); + + match.screen = DefaultScreen(dpy); + visualList = XGetVisualInfo(dpy, VisualScreenMask, &match, &found); + + printf(" visual bf lv rg d st r g b a ax dp st accum buffs\n"); + printf(" id dep cl sz l ci b ro sz sz sz sz bf th cl r g b a\n"); + printf("-------------------------------------------------------------\n"); + + visualToTry = NULL; + for(vi = visualList; found > 0; found--, vi++) { + glXGetConfig(dpy, vi, GLX_USE_GL, &glxCapable); + if (glxCapable) { + printf("0x%x %2d %s", vi->visualid, vi->depth, ClassOf(vi->class)); + glXGetConfig(dpy, vi, GLX_BUFFER_SIZE, &bufferSize); + glXGetConfig(dpy, vi, GLX_LEVEL, &level); + glXGetConfig(dpy, vi, GLX_RGBA, &renderType); + glXGetConfig(dpy, vi, GLX_DOUBLEBUFFER, &doubleBuffer); + glXGetConfig(dpy, vi, GLX_STEREO, &stereo); + glXGetConfig(dpy, vi, GLX_AUX_BUFFERS, &auxBuffers); + glXGetConfig(dpy, vi, GLX_RED_SIZE, &redSize); + glXGetConfig(dpy, vi, GLX_GREEN_SIZE, &greenSize); + glXGetConfig(dpy, vi, GLX_BLUE_SIZE, &blueSize); + glXGetConfig(dpy, vi, GLX_ALPHA_SIZE, &alphaSize); + glXGetConfig(dpy, vi, GLX_DEPTH_SIZE, &depthSize); + glXGetConfig(dpy, vi, GLX_STENCIL_SIZE, &stencilSize); + glXGetConfig(dpy, vi, GLX_ACCUM_RED_SIZE, &acRedSize); + glXGetConfig(dpy, vi, GLX_ACCUM_GREEN_SIZE, &acGreenSize); + glXGetConfig(dpy, vi, GLX_ACCUM_BLUE_SIZE, &acBlueSize); + glXGetConfig(dpy, vi, GLX_ACCUM_ALPHA_SIZE, &acAlphaSize); + printf(" %2s %2s %1s %1s %1s ", + Format(bufferSize, 2), Format(level, 2), + renderType ? "r" : "c", + doubleBuffer ? "y" : ".", + stereo ? "y" : "."); + printf("%2s %2s %2s %2s ", + Format(redSize, 2), Format(greenSize, 2), + Format(blueSize, 2), Format(alphaSize, 2)); + printf("%2s %2s %2s %2s %2s %2s %2s", + Format(auxBuffers, 2), Format(depthSize, 2), Format(stencilSize, 2), + Format(acRedSize, 2), Format(acGreenSize, 2), + Format(acBlueSize, 2), Format(acAlphaSize, 2)); + printf("\n"); + visualToTry = vi; + } + } + + if (visualToTry) { + GLXContext context; + Window window; + Colormap colormap; + XSetWindowAttributes swa; + + context = glXCreateContext(dpy, visualToTry, 0, GL_TRUE); + colormap = XCreateColormap(dpy, + RootWindow(dpy, visualToTry->screen), + visualToTry->visual, AllocNone); + swa.colormap = colormap; + swa.border_pixel = 0; + window = XCreateWindow(dpy, RootWindow(dpy, visualToTry->screen), 0, 0, 100, 100, + 0, visualToTry->depth, InputOutput, visualToTry->visual, + CWBorderPixel | CWColormap, &swa); + glXMakeCurrent(dpy, window, context); + printf("\n"); + printf("OpenGL vendor string: %s\n", glGetString(GL_VENDOR)); + printf("OpenGL renderer string: %s\n", glGetString(GL_RENDERER)); + printf("OpenGL version string: %s\n", glGetString(GL_VERSION)); + if (glXIsDirect(dpy, context)) + printf("direct rendering: supported\n"); + printf( "GL extensions: '%s'\n\n", glGetString(GL_EXTENSIONS) ); +#if defined(GLX_VERSION_1_1) + printf( "GLX extensions: '%s'\n\n", glXQueryExtensionsString( dpy, visualToTry->screen ) ); +#endif + + } else + printf("No GLX-capable visuals!\n"); + XFree(visualList); +} + +static char * +ClassOf(int c) +{ + switch (c) { + case StaticGray: return "sg"; + case GrayScale: return "gs"; + case StaticColor: return "sc"; + case PseudoColor: return "pc"; + case TrueColor: return "tc"; + case DirectColor: return "dc"; + default: return "??"; + } +} + +static char * +Format(int n, int w) +{ + static char buffer[256]; + static int bufptr; + char *buf; + + if (bufptr >= sizeof(buffer) - w) + bufptr = 0; + buf = buffer + bufptr; + if (n == 0) + sprintf(buf, "%*s", w, "."); + else + sprintf(buf, "%*d", w, n); + bufptr += w + 1; + return buf; +} diff --git a/examples/opengl/overlay_x11/utilities/sovinfo/sovLayerUtil.h b/examples/opengl/overlay_x11/utilities/sovinfo/sovLayerUtil.h new file mode 100644 index 000000000..f45423a8d --- /dev/null +++ b/examples/opengl/overlay_x11/utilities/sovinfo/sovLayerUtil.h @@ -0,0 +1,54 @@ +#ifndef __sovLayerUtil_h__ +#define __sovLayerUtil_h__ + +/* Copyright (c) Mark J. Kilgard, 1996. */ + +/* This program is freely distributable without licensing fees + and is provided without guarantee or warrantee expressed or + implied. This program is -not- in the public domain. */ + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xmd.h> + +/* Transparent type values */ +/* None 0 */ +#define TransparentPixel 1 +#define TransparentMask 2 + +/* layered visual info template flags */ +#define VisualLayerMask 0x200 +#define VisualTransparentType 0x400 +#define VisualTransparentValue 0x800 +#define VisualAllLayerMask 0xFFF + +/* layered visual info structure */ +typedef struct _sovVisualInfo { + XVisualInfo vinfo; + int layer; + int type; + unsigned long value; +} sovVisualInfo; + +/* SERVER_OVERLAY_VISUALS property element */ +typedef struct _sovOverlayInfo { + long overlay_visual; + long transparent_type; + long value; + long layer; +} sovOverlayInfo; + +extern sovVisualInfo *sovGetVisualInfo( + Display *display, + long lvinfo_mask, + sovVisualInfo *lvinfo_template, + int *nitems_return); +extern Status sovMatchVisualInfo( + Display *display, + int screen, + int depth, + int class, + int layer, + sovVisualInfo *lvinfo_return); + +#endif /* __sovLayerUtil_h__ */ diff --git a/examples/opengl/overlay_x11/utilities/sovinfo/sovinfo.c b/examples/opengl/overlay_x11/utilities/sovinfo/sovinfo.c new file mode 100644 index 000000000..059050c2f --- /dev/null +++ b/examples/opengl/overlay_x11/utilities/sovinfo/sovinfo.c @@ -0,0 +1,95 @@ + +/* Copyright (c) Mark J. Kilgard, 1996. */ + +/* This program is freely distributable without licensing fees + and is provided without guarantee or warrantee expressed or + implied. This program is -not- in the public domain. */ + +/* compile: cc -o sovinfo sovinfo.c sovLayerUtil.c -lX11 */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "sovLayerUtil.h" + +int +main(int argc, char *argv[]) +{ + Display *dpy; + char *display_name, *arg, *class; + sovVisualInfo template, *lvinfo; + int nVisuals, i, overlaysOnly = 0; + + display_name = NULL; + for (i = 1; i < argc; i++) { + arg = argv[i]; + if (!strcmp(arg, "-display")) { + if (++i >= argc) { + fprintf(stderr, "sovinfo: missing argument to -display\n"); + exit(1); + } + display_name = argv[i]; + } else if (!strcmp(arg, "-overlays_only")) { + overlaysOnly = 1; + } else { + fprintf(stderr, + "usage: sovinfo [-display dpy] [-overlays_only]\n"); + exit(1); + } + } + dpy = XOpenDisplay(display_name); + if (dpy == NULL) { + fprintf(stderr, "sovinfo: cannot open display %s\n", + XDisplayName(NULL)); + exit(1); + } + lvinfo = sovGetVisualInfo(dpy, 0L, &template, &nVisuals); + for (i = 0; i < nVisuals; i++) { + if (!overlaysOnly || lvinfo[i].layer > 0) { + printf(" Visual ID: 0x%x\n", lvinfo[i].vinfo.visualid); + printf(" screen: %d\n", lvinfo[i].vinfo.screen); + printf(" depth: %d\n", lvinfo[i].vinfo.depth); + switch (lvinfo[i].vinfo.class) { + case StaticGray: + class = "StaticGray"; + break; + case GrayScale: + class = "GrayScale"; + break; + case StaticColor: + class = "StaticColor"; + break; + case PseudoColor: + class = "PseudoColor"; + break; + case TrueColor: + class = "TrueColor"; + break; + case DirectColor: + class = "DirectColor"; + break; + default: + class = "Unknown"; + break; + } + printf(" class: %s\n", class); + switch (lvinfo[i].type) { + case None: + printf(" transparent type: None\n"); + break; + case TransparentPixel: + printf(" transparent type: TransparentPixel\n"); + printf(" pixel value: %d\n", lvinfo[i].value); + break; + case TransparentMask: + printf(" transparent type: TransparentMask\n"); + printf(" transparency mask: %0x%x\n", lvinfo[i].value); + break; + default: + printf(" transparent type: Unknown or invalid\n"); + break; + } + printf(" layer: %d\n", lvinfo[i].layer); + } + } + return 0; +} diff --git a/examples/opengl/overlay_x11/utilities/sovinfo/sovlayerutil.c b/examples/opengl/overlay_x11/utilities/sovinfo/sovlayerutil.c new file mode 100644 index 000000000..8837d06cf --- /dev/null +++ b/examples/opengl/overlay_x11/utilities/sovinfo/sovlayerutil.c @@ -0,0 +1,150 @@ + +/* Copyright (c) Mark J. Kilgard, 1996. */ + +/* This program is freely distributable without licensing fees + and is provided without guarantee or warrantee expressed or + implied. This program is -not- in the public domain. */ + +#include <stdlib.h> +#include "sovLayerUtil.h" + +static Bool layersRead; +static Atom overlayVisualsAtom; +static sovOverlayInfo **overlayInfoPerScreen; +static int *numOverlaysPerScreen; + +sovVisualInfo * +sovGetVisualInfo(Display *display, long lvinfo_mask, + sovVisualInfo *lvinfo_template, int *nitems_return) +{ + XVisualInfo *vinfo; + sovVisualInfo *layerInfo; + Window root; + Status status; + Atom actualType; + unsigned long sizeData, bytesLeft; + int actualFormat, numVisuals, numScreens, count, i, j; + + vinfo = XGetVisualInfo(display, lvinfo_mask & VisualAllMask, + &lvinfo_template->vinfo, nitems_return); + if (vinfo == NULL) + return NULL; + numVisuals = *nitems_return; + if (layersRead == False) { + overlayVisualsAtom = XInternAtom(display, + "SERVER_OVERLAY_VISUALS", True); + if (overlayVisualsAtom != None) { + numScreens = ScreenCount(display); + overlayInfoPerScreen = (sovOverlayInfo **) + malloc(numScreens * sizeof(sovOverlayInfo *)); + numOverlaysPerScreen = (int *) malloc(numScreens * sizeof(int)); + if (overlayInfoPerScreen != NULL && + numOverlaysPerScreen != NULL) { + for (i = 0; i < numScreens; i++) { + root = RootWindow(display, i); + status = XGetWindowProperty(display, root, overlayVisualsAtom, + 0L, (long) 10000, False, overlayVisualsAtom, + &actualType, &actualFormat, + &sizeData, &bytesLeft, + (unsigned char **) &overlayInfoPerScreen[i]); + if (status != Success || + actualType != overlayVisualsAtom || + actualFormat != 32 || sizeData < 4) + numOverlaysPerScreen[i] = 0; + else + numOverlaysPerScreen[i] = sizeData / 4; + } + layersRead = True; + } else { + if (overlayInfoPerScreen != NULL) + free(overlayInfoPerScreen); + if (numOverlaysPerScreen != NULL) + free(numOverlaysPerScreen); + } + } + } + layerInfo = (sovVisualInfo *) + malloc(numVisuals * sizeof(sovVisualInfo)); + if (layerInfo == NULL) { + XFree(vinfo); + return NULL; + } + count = 0; + for (i = 0; i < numVisuals; i++) { + XVisualInfo *pVinfo; + int screen; + sovOverlayInfo *overlayInfo; + + pVinfo = &vinfo[i]; + screen = pVinfo->screen; + overlayInfo = NULL; + if (layersRead) { + for (j = 0; j < numOverlaysPerScreen[screen]; j++) + if (pVinfo->visualid == + overlayInfoPerScreen[screen][j].overlay_visual) { + overlayInfo = &overlayInfoPerScreen[screen][j]; + break; + } + } + if (lvinfo_mask & VisualLayerMask) + if (overlayInfo == NULL) { + if (lvinfo_template->layer != 0) + continue; + } else if (lvinfo_template->layer != overlayInfo->layer) + continue; + if (lvinfo_mask & VisualTransparentType) + if (overlayInfo == NULL) { + if (lvinfo_template->type != None) + continue; + } else if (lvinfo_template->type != + overlayInfo->transparent_type) + continue; + if (lvinfo_mask & VisualTransparentValue) + if (overlayInfo == NULL) + /* non-overlay visuals have no sense of + TransparentValue */ + continue; + else if (lvinfo_template->value != overlayInfo->value) + continue; + layerInfo[count].vinfo = *pVinfo; + if (overlayInfo == NULL) { + layerInfo[count].layer = 0; + layerInfo[count].type = None; + layerInfo[count].value = 0; /* meaningless */ + } else { + layerInfo[count].layer = overlayInfo->layer; + layerInfo[count].type = overlayInfo->transparent_type; + layerInfo[count].value = overlayInfo->value; + } + count++; + } + XFree(vinfo); + *nitems_return = count; + if (count == 0) { + XFree(layerInfo); + return NULL; + } else + return layerInfo; +} + +Status +sovMatchVisualInfo(Display *display, int screen, + int depth, int class, int layer, sovVisualInfo *lvinfo_return) +{ + sovVisualInfo *lvinfo; + sovVisualInfo lvinfoTemplate; + int nitems; + + lvinfoTemplate.vinfo.screen = screen; + lvinfoTemplate.vinfo.depth = depth; + lvinfoTemplate.vinfo.class = class; + lvinfoTemplate.layer = layer; + lvinfo = sovGetVisualInfo(display, + VisualScreenMask|VisualDepthMask|VisualClassMask|VisualLayerMask, + &lvinfoTemplate, &nitems); + if (lvinfo != NULL && nitems > 0) { + *lvinfo_return = *lvinfo; + return 1; + } else + return 0; +} |