diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 20aedbf23..2ea9125b5 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -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) diff --git a/examples/osgviewerQtContext/CMakeLists.txt b/examples/osgviewerQtContext/CMakeLists.txt new file mode 100644 index 000000000..80aba84e4 --- /dev/null +++ b/examples/osgviewerQtContext/CMakeLists.txt @@ -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 ) diff --git a/examples/osgviewerQtContext/GraphicsWindowQt b/examples/osgviewerQtContext/GraphicsWindowQt new file mode 100644 index 000000000..951dfd9af --- /dev/null +++ b/examples/osgviewerQtContext/GraphicsWindowQt @@ -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 +#include +#include +#include + +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 diff --git a/examples/osgviewerQtContext/GraphicsWindowQt.cpp b/examples/osgviewerQtContext/GraphicsWindowQt.cpp new file mode 100644 index 000000000..1aa96d3c3 --- /dev/null +++ b/examples/osgviewerQtContext/GraphicsWindowQt.cpp @@ -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(_traits->inheritedWindowData.get()) : 0; + _widget = windowData ? windowData->_widget : 0; + if ( !_widget ) + { + GraphicsWindowQt* sharedContextQt = dynamic_cast(_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)) ); +} diff --git a/examples/osgviewerQtContext/osgviewerQtContext.cpp b/examples/osgviewerQtContext/osgviewerQtContext.cpp new file mode 100644 index 000000000..2cca33f41 --- /dev/null +++ b/examples/osgviewerQtContext/osgviewerQtContext.cpp @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#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( 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 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 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(traits->width)/static_cast(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(); +}