From Wang Rui, "I've just made another OSG+Qt (GUI) examples to demonstrate how to create OSG views, add them to a CompositeViewer, and add corresponding widgets to Qt layouts or as popup windows. The example inherits a GraphicsWindowQt from the GraphicsWindow base class and implements most of the virtual methods. A QGLWidget is created at the same time to perform keyboards and mouse events, who is also added as the main widget's child.

The new example, named osgviewerQtContext (because of deriving from GraphicsContext), works fine on Windows XP SP3 and Qt 4.5.0, with 4 widgets in QGridLayout and a popup window and 60Hz frame rate. I haven't tested it on Unix/Linux and Mac OSX yet. So any feedback from these platforms is appreciated. I wish this example be a useful complement to current osgviewerQt and osgviewerQtWidgets ones. :)

Some unfinished functionalities: inheritedWindowData, sharedContext, and more tests needed."
This commit is contained in:
Robert Osfield 2010-04-30 12:22:31 +00:00
parent c2a59415ce
commit 6d046e9fa1
5 changed files with 540 additions and 0 deletions

View File

@ -189,6 +189,7 @@ IF(DYNAMIC_OPENSCENEGRAPH)
IF (BUILD_QT_EXAMPLES AND QT_QTOPENGL_LIBRARY)
ADD_SUBDIRECTORY(osgviewerQT)
ADD_SUBDIRECTORY(osgviewerQtContext)
ENDIF()
IF (BUILD_QT_EXAMPLES AND QT4_FOUND)

View File

@ -0,0 +1,15 @@
SET( TARGET_SRC
GraphicsWindowQt
GraphicsWindowQt.cpp
osgviewerQtContext.cpp
)
IF( QT4_FOUND )
SET(TARGET_EXTERNAL_LIBRARIES ${QT_QTCORE_LIBRARY_RELEASE} ${QT_QTGUI_LIBRARY_RELEASE} ${QT_QTOPENGL_LIBRARY_RELEASE} )
ADD_DEFINITIONS(-DUSE_QT4)
ELSE( QT4_FOUND )
SET(TARGET_EXTERNAL_LIBRARIES ${QT_LIBRARIES} )
ENDIF( QT4_FOUND )
INCLUDE_DIRECTORIES( ${QT_INCLUDE_DIR} )
SETUP_EXAMPLE( osgviewerQtContext )

View File

@ -0,0 +1,90 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 2009 Wang Rui
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGVIEWER_GRAPHICSWINDOWQT
#define OSGVIEWER_GRAPHICSWINDOWQT
#include <QtGui/QWidget>
#include <QtGui/QInputEvent>
#include <QtOpenGL/QGLWidget>
#include <osgViewer/GraphicsWindow>
class GraphWidget : public QGLWidget
{
public:
GraphWidget( const QGLFormat& format, QWidget* parent=0, const QGLWidget* shareWidget=0, Qt::WindowFlags f=0 );
inline void setGraphicsWindow( osgViewer::GraphicsWindow* gw ) { _gw = gw; }
void setKeyboardModifiers( QInputEvent* event );
virtual void resizeEvent( QResizeEvent* event );
virtual void keyPressEvent( QKeyEvent* event );
virtual void keyReleaseEvent( QKeyEvent* event );
virtual void mousePressEvent( QMouseEvent* event );
virtual void mouseReleaseEvent( QMouseEvent* event );
virtual void mouseDoubleClickEvent( QMouseEvent* event );
virtual void mouseMoveEvent( QMouseEvent* event );
virtual void wheelEvent( QWheelEvent* event );
protected:
osgViewer::GraphicsWindow* _gw;
};
class GraphicsWindowQt : public osgViewer::GraphicsWindow
{
public:
GraphicsWindowQt( osg::GraphicsContext::Traits* traits );
virtual ~GraphicsWindowQt();
inline GraphWidget* getGraphWidget() { return _widget; }
inline const GraphWidget* getGraphWidget() const { return _widget; }
struct WindowData : public osg::Referenced
{
WindowData( GraphWidget* widget ): _widget(widget) {}
GraphWidget* _widget;
};
bool init();
virtual bool setWindowRectangleImplementation( int x, int y, int width, int height );
virtual void getWindowRectangle( int& x, int& y, int& width, int& height );
virtual bool setWindowDecorationImplementation( bool windowDecoration );
virtual bool getWindowDecoration() const;
virtual void grabFocus();
virtual void grabFocusIfPointerInWindow();
virtual void raiseWindow();
virtual void setWindowName( const std::string& name );
virtual std::string getWindowName();
virtual void useCursor( bool cursorOn );
virtual void setCursor( MouseCursor cursor );
virtual bool valid() const;
virtual bool realizeImplementation();
virtual bool isRealizedImplementation() const;
virtual void closeImplementation();
virtual bool makeCurrentImplementation();
virtual bool releaseContextImplementation();
virtual void swapBuffersImplementation();
virtual void requestWarpPointer( float x, float y );
protected:
GraphWidget* _widget;
QCursor _currentCursor;
bool _initialized;
bool _realized;
};
#endif

View File

@ -0,0 +1,342 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 2009 Wang Rui
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#include "GraphicsWindowQt"
GraphWidget::GraphWidget( const QGLFormat& format, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f )
: QGLWidget(format, parent, shareWidget, f)
{
setAutoBufferSwap( false );
setMouseTracking( true );
}
void GraphWidget::setKeyboardModifiers( QInputEvent* event )
{
int modkey = event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier);
unsigned int mask = 0;
if ( modkey & Qt::ShiftModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_SHIFT;
if ( modkey & Qt::ControlModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_CTRL;
if ( modkey & Qt::AltModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_ALT;
_gw->getEventQueue()->getCurrentEventState()->setModKeyMask( mask );
}
void GraphWidget::resizeEvent( QResizeEvent* event )
{
const QSize& size = event->size();
_gw->getEventQueue()->windowResize( 0, 0, size.width(), size.height() );
_gw->resized( 0, 0, size.width(), size.height() );
}
void GraphWidget::keyPressEvent( QKeyEvent* event )
{
setKeyboardModifiers( event );
_gw->getEventQueue()->keyPress( (osgGA::GUIEventAdapter::KeySymbol) *(event->text().toAscii().data()) );
}
void GraphWidget::keyReleaseEvent( QKeyEvent* event )
{
setKeyboardModifiers( event );
_gw->getEventQueue()->keyRelease( (osgGA::GUIEventAdapter::KeySymbol) *(event->text().toAscii().data()) );
}
void GraphWidget::mousePressEvent( QMouseEvent* event )
{
int button = 0;
switch ( event->button() )
{
case Qt::LeftButton: button = 1; break;
case Qt::MidButton: button = 2; break;
case Qt::RightButton: button = 3; break;
case Qt::NoButton: button = 0; break;
default: button = 0; break;
}
setKeyboardModifiers( event );
_gw->getEventQueue()->mouseButtonPress( event->x(), event->y(), button );
}
void GraphWidget::mouseReleaseEvent( QMouseEvent* event )
{
int button = 0;
switch ( event->button() )
{
case Qt::LeftButton: button = 1; break;
case Qt::MidButton: button = 2; break;
case Qt::RightButton: button = 3; break;
case Qt::NoButton: button = 0; break;
default: button = 0; break;
}
setKeyboardModifiers( event );
_gw->getEventQueue()->mouseButtonRelease( event->x(), event->y(), button );
}
void GraphWidget::mouseDoubleClickEvent( QMouseEvent* event )
{
int button = 0;
switch ( event->button() )
{
case Qt::LeftButton: button = 1; break;
case Qt::MidButton: button = 2; break;
case Qt::RightButton: button = 3; break;
case Qt::NoButton: button = 0; break;
default: button = 0; break;
}
setKeyboardModifiers( event );
_gw->getEventQueue()->mouseDoubleButtonPress( event->x(), event->y(), button );
}
void GraphWidget::mouseMoveEvent( QMouseEvent* event )
{
setKeyboardModifiers( event );
_gw->getEventQueue()->mouseMotion( event->x(), event->y() );
}
void GraphWidget::wheelEvent( QWheelEvent* event )
{
setKeyboardModifiers( event );
_gw->getEventQueue()->mouseScroll(
event->delta()>0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN );
}
GraphicsWindowQt::GraphicsWindowQt( osg::GraphicsContext::Traits* traits )
: _widget(0),
_initialized(false),
_realized(false)
{
_traits = traits;
_initialized = init();
if ( valid() )
{
setState( new osg::State );
getState()->setGraphicsContext(this);
if ( _traits.valid() && _traits->sharedContext )
{
getState()->setContextID( _traits->sharedContext->getState()->getContextID() );
incrementContextIDUsageCount( getState()->getContextID() );
}
else
{
getState()->setContextID( osg::GraphicsContext::createNewContextID() );
}
}
}
GraphicsWindowQt::~GraphicsWindowQt()
{
close();
}
bool GraphicsWindowQt::init()
{
QGLFormat format( QGLFormat::defaultFormat() );
format.setAlphaBufferSize( _traits->alpha );
format.setRedBufferSize( _traits->red );
format.setGreenBufferSize( _traits->green );
format.setBlueBufferSize( _traits->blue );
format.setDepthBufferSize( _traits->depth );
format.setStencilBufferSize( _traits->stencil );
format.setSampleBuffers( _traits->sampleBuffers );
format.setSamples( _traits->samples );
format.setAlpha( _traits->alpha>0 );
format.setDepth( _traits->depth>0 );
format.setStencil( _traits->stencil>0 );
format.setDoubleBuffer( _traits->doubleBuffer );
format.setSwapInterval( _traits->vsync ? 1 : 0 );
WindowData* windowData = _traits.get() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;
_widget = windowData ? windowData->_widget : 0;
if ( !_widget )
{
GraphicsWindowQt* sharedContextQt = dynamic_cast<GraphicsWindowQt*>(_traits->sharedContext);
QGLWidget* shareWidget = sharedContextQt ? sharedContextQt->getGraphWidget() : 0;
Qt::WindowFlags flags = Qt::Window|Qt::CustomizeWindowHint;//|Qt::WindowStaysOnTopHint;
if ( _traits->windowDecoration )
flags |= Qt::WindowTitleHint|Qt::WindowMinMaxButtonsHint|Qt::WindowSystemMenuHint;
_widget = new GraphWidget( format, 0, shareWidget, flags );
}
_widget->setWindowTitle( _traits->windowName.c_str() );
_widget->move( _traits->x, _traits->y );
if ( !_traits->supportsResize ) _widget->setFixedSize( _traits->width, _traits->height );
else _widget->resize( _traits->width, _traits->height );
_widget->setFocusPolicy( Qt::WheelFocus );
_widget->setGraphicsWindow( this );
useCursor( _traits->useCursor );
return true;
}
bool GraphicsWindowQt::setWindowRectangleImplementation( int x, int y, int width, int height )
{
if ( _widget ) _widget->setGeometry( x, y, width, height );
return _widget!=NULL;
}
void GraphicsWindowQt::getWindowRectangle( int& x, int& y, int& width, int& height )
{
if ( _widget )
{
const QRect& geom = _widget->geometry();
x = geom.x();
y = geom.y();
width = geom.width();
height = geom.height();
}
}
bool GraphicsWindowQt::setWindowDecorationImplementation( bool windowDecoration )
{
Qt::WindowFlags flags = Qt::Window|Qt::CustomizeWindowHint;//|Qt::WindowStaysOnTopHint;
if ( windowDecoration )
flags |= Qt::WindowTitleHint|Qt::WindowMinMaxButtonsHint|Qt::WindowSystemMenuHint;
_traits->windowDecoration = windowDecoration;
// FIXME: Calling setWindowFlags or reparent widget will recreate the window handle,
// which makes QGLContext no longer work...How to deal with that?
//if ( _widget ) _widget->setWindowFlags( flags );
return false;
}
bool GraphicsWindowQt::getWindowDecoration() const
{
return _traits->windowDecoration;
}
void GraphicsWindowQt::grabFocus()
{
if ( _widget )
_widget->setFocus( Qt::ActiveWindowFocusReason );
}
void GraphicsWindowQt::grabFocusIfPointerInWindow()
{
if ( _widget->underMouse() )
_widget->setFocus( Qt::ActiveWindowFocusReason );
}
void GraphicsWindowQt::raiseWindow()
{
if ( _widget )
_widget->raise();
}
void GraphicsWindowQt::setWindowName( const std::string& name )
{
if ( _widget )
_widget->setWindowTitle( name.c_str() );
}
std::string GraphicsWindowQt::getWindowName()
{
return _widget ? _widget->windowTitle().toStdString() : "";
}
void GraphicsWindowQt::useCursor( bool cursorOn )
{
if ( _widget )
{
_traits->useCursor = cursorOn;
if ( !cursorOn ) _widget->setCursor( Qt::BlankCursor );
else _widget->setCursor( _currentCursor );
}
}
void GraphicsWindowQt::setCursor( MouseCursor cursor )
{
if ( cursor==InheritCursor && _widget )
{
_widget->unsetCursor();
}
switch ( cursor )
{
case NoCursor: _currentCursor = Qt::BlankCursor; break;
case RightArrowCursor: case LeftArrowCursor: _currentCursor = Qt::ArrowCursor; break;
case InfoCursor: _currentCursor = Qt::SizeAllCursor; break;
case DestroyCursor: _currentCursor = Qt::ForbiddenCursor; break;
case HelpCursor: _currentCursor = Qt::WhatsThisCursor; break;
case CycleCursor: _currentCursor = Qt::ForbiddenCursor; break;
case SprayCursor: _currentCursor = Qt::SizeAllCursor; break;
case WaitCursor: _currentCursor = Qt::WaitCursor; break;
case TextCursor: _currentCursor = Qt::IBeamCursor; break;
case CrosshairCursor: _currentCursor = Qt::CrossCursor; break;
case HandCursor: _currentCursor = Qt::OpenHandCursor; break;
case UpDownCursor: _currentCursor = Qt::SizeVerCursor; break;
case LeftRightCursor: _currentCursor = Qt::SizeHorCursor; break;
case TopSideCursor: case BottomSideCursor: _currentCursor = Qt::UpArrowCursor; break;
case LeftSideCursor: case RightSideCursor: _currentCursor = Qt::SizeHorCursor; break;
case TopLeftCorner: _currentCursor = Qt::SizeBDiagCursor; break;
case TopRightCorner: _currentCursor = Qt::SizeFDiagCursor; break;
case BottomRightCorner: _currentCursor = Qt::SizeBDiagCursor; break;
case BottomLeftCorner: _currentCursor = Qt::SizeFDiagCursor; break;
default: break;
};
if ( _widget ) _widget->setCursor( _currentCursor );
}
bool GraphicsWindowQt::valid() const
{
return _widget && _widget->isValid();
}
bool GraphicsWindowQt::realizeImplementation()
{
if ( !_initialized )
_initialized = init();
// A makeCurrent()/doneCurrent() seems to be required for
// realizing the context(?) before starting drawing
_widget->makeCurrent();
_widget->doneCurrent();
_realized = true;
return true;
}
bool GraphicsWindowQt::isRealizedImplementation() const
{
return _realized;
}
void GraphicsWindowQt::closeImplementation()
{
if ( _widget )
_widget->close();
}
bool GraphicsWindowQt::makeCurrentImplementation()
{
_widget->makeCurrent();
return true;
}
bool GraphicsWindowQt::releaseContextImplementation()
{
_widget->doneCurrent();
return true;
}
void GraphicsWindowQt::swapBuffersImplementation()
{
_widget->swapBuffers();
}
void GraphicsWindowQt::requestWarpPointer( float x, float y )
{
if ( _widget )
QCursor::setPos( _widget->mapToGlobal(QPoint((int)x,(int)y)) );
}

View File

@ -0,0 +1,92 @@
#include <QtCore/QTimer>
#include <QtGui/QApplication>
#include <QtGui/QGridLayout>
#include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osgDB/ReadFile>
#include <iostream>
#include "GraphicsWindowQt"
class ViewerWidget : public QWidget, public osgViewer::CompositeViewer
{
public:
ViewerWidget() : QWidget()
{
setThreadingModel(osgViewer::CompositeViewer::SingleThreaded);
QWidget* widget1 = addViewWidget( createCamera(0,0,100,100), osgDB::readNodeFile("cow.osg") );
QWidget* widget2 = addViewWidget( createCamera(0,0,100,100), osgDB::readNodeFile("glider.osg") );
QWidget* widget3 = addViewWidget( createCamera(0,0,100,100), osgDB::readNodeFile("axes.osg") );
QWidget* widget4 = addViewWidget( createCamera(0,0,100,100), osgDB::readNodeFile("fountain.osg") );
QWidget* popupWidget = addViewWidget( createCamera(900,100,320,240,"Popup window",true),
osgDB::readNodeFile("dumptruck.osg") );
popupWidget->show();
QGridLayout* grid = new QGridLayout;
grid->addWidget( widget1, 0, 0 );
grid->addWidget( widget2, 0, 1 );
grid->addWidget( widget3, 1, 0 );
grid->addWidget( widget4, 1, 1 );
setLayout( grid );
connect( &_timer, SIGNAL(timeout()), this, SLOT(update()) );
_timer.start( 10 );
}
QWidget* addViewWidget( osg::Camera* camera, osg::Node* scene )
{
osgViewer::View* view = new osgViewer::View;
view->setCamera( camera );
addView( view );
view->setSceneData( scene );
view->addEventHandler( new osgViewer::StatsHandler );
view->setCameraManipulator( new osgGA::TrackballManipulator );
GraphicsWindowQt* gw = dynamic_cast<GraphicsWindowQt*>( camera->getGraphicsContext() );
return gw ? gw->getGraphWidget() : NULL;
}
osg::Camera* createCamera( int x, int y, int w, int h, const std::string& name="", bool windowDecoration=false )
{
osg::DisplaySettings* ds = osg::DisplaySettings::instance();
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
traits->windowName = name;
traits->windowDecoration = windowDecoration;
traits->x = x;
traits->y = y;
traits->width = w;
traits->height = h;
traits->doubleBuffer = true;
traits->alpha = ds->getMinimumNumAlphaBits();
traits->stencil = ds->getMinimumNumStencilBits();
traits->sampleBuffers = ds->getMultiSamples();
traits->samples = ds->getNumMultiSamples();
osg::ref_ptr<osg::Camera> camera = new osg::Camera;
camera->setGraphicsContext( new GraphicsWindowQt(traits.get()) );
camera->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) );
camera->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );
camera->setProjectionMatrixAsPerspective(
30.0f, static_cast<double>(traits->width)/static_cast<double>(traits->height), 1.0f, 10000.0f );
return camera.release();
}
virtual void paintEvent( QPaintEvent* event )
{ frame(); }
protected:
QTimer _timer;
};
int main( int argc, char** argv )
{
QApplication app(argc, argv);
ViewerWidget* viewWidget = new ViewerWidget;
viewWidget->setGeometry( 100, 100, 800, 600 );
viewWidget->show();
return app.exec();
}