Hi,

Thanks for Don's modification. I would like to contribute a newer
osgviewerQtContext example again. Usages of inheritedWindowData and
sharedContext are included. But no idea to set window decoration in
real-time (which breaks the QGLContext) and avoid the ugly stuff when pop-up
in front of main window.

Wang Rui


2009/6/24 Wang Rui <[email protected]>

> Hi all,
>
> 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.
>
> Cheers,
>
> Wang Rui
>
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 )
/* -*-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
/* -*-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)) );
}
#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()
    {
        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();
}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to