This mod to QOSGWidget enables multithreaded rendering using QOSGWidget using
CompositeViewer. It demonstrates as well the embedding of QOSGWidget into other
QTWidgets. Performance is very good (70 fps) on AMD 3Ghz, FedoraCore8 using
NVidia 8600GTS.


usage:
~~~~~~

    osgviewerQT --QOSGWidget --MTCompositeViewer cow.osg


There are some issues with this mod:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1. Other multithreading modes fail.

2. Correct Widget inheritance is crucial to functionality.

3. Written for QT4 only

4. Using 'ClickToFocus'. Select the widget first before manipulating.

5. though working fine we get a BadWindow error message see thread

   [osg-users] Multiple Contexts in QT Applications

6. Although the problem (point 5) is related to deranged traits values
   which are set by failing a call to XGetWindowAttributes in
   GraphicsWindowX11::setWindow the following fix (to set traits only if
   XGetWindowAttributes returns with no error) does not solve the problem
   properly:

    @ line 750, GraphicsWindowX11.cpp

    Status s = XGetWindowAttributes( _display, _window, &watt );
        if (s = True)
        {
            _traits->x = watt.x;
            _traits->y = watt.y;
            _traits->width = watt.width;
            _traits->height = watt.height;
        }

        The context can be embedded and displayed but somehow the
        perspective is distored in this case. That's why we set the traits
        in QOSGWidget::createContext after initializing the graphicsContext.


Regards,
Lukas
/* OpenSceneGraph example, osganimate.
*
*  Permission is hereby granted, free of charge, to any person obtaining a copy
*  of this software and associated documentation files (the "Software"), to deal
*  in the Software without restriction, including without limitation the rights
*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*  copies of the Software, and to permit persons to whom the Software is
*  furnished to do so, subject to the following conditions:
*
*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
*  THE SOFTWARE.
*/

#if USE_QT4

    #include <QtCore/QString>
    #include <QtCore/QTimer>
    #include <QtGui/QKeyEvent>
    #include <QtGui/QApplication>
    #include <QtOpenGL/QGLWidget>
    #include <QtGui/QtGui>
    #include <QtGui/QWidget>
    using Qt::WindowFlags;

#else

    class QWidget;
    #include <qtimer.h>
    #include <qgl.h>
    #include <qapplication.h>

    #define WindowFlags WFlags

#endif


#include <osgViewer/Viewer>
#include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/GraphicsWindow>

#include <osgViewer/ViewerEventHandlers>

#if defined(WIN32) && !defined(__CYGWIN__)
#include <osgViewer/api/Win32/GraphicsWindowWin32>
typedef HWND WindowHandle;
typedef osgViewer::GraphicsWindowWin32::WindowData WindowData;
#elif defined(__APPLE__) && defined(APPLE_PRE_10_3)
#include <osgViewer/api/Carbon/GraphicsWindowCarbon>
typedef WindowRef WindowHandle;
typedef osgViewer::GraphicsWindowCarbon::WindowData WindowData;
#else // all other unix
#include <osgViewer/api/X11/GraphicsWindowX11>
typedef Window WindowHandle;
typedef osgViewer::GraphicsWindowX11::WindowData WindowData;
#endif


#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgGA/StateSetManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/TerrainManipulator>

#include <osgDB/ReadFile>

#include <iostream>
#include <sstream>

class QOSGWidget : public QWidget
{
    public:

        QOSGWidget( QWidget * parent = 0, const char * name = 0, WindowFlags f 
= 0, bool overrideTraits = false);

        virtual ~QOSGWidget() {}

        osgViewer::GraphicsWindow* getGraphicsWindow() { return _gw.get(); }
        const osgViewer::GraphicsWindow* getGraphicsWindow() const { return 
_gw.get(); }

    protected:

        void init();
        void createContext();

        virtual void mouseDoubleClickEvent ( QMouseEvent * event );
        virtual void closeEvent( QCloseEvent * event );
        virtual void destroyEvent( bool destroyWindow = true, bool 
destroySubWindows = true);
        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 mouseMoveEvent( QMouseEvent* event );

        osg::ref_ptr<osgViewer::GraphicsWindow> _gw;
        bool _overrideTraits;
};

QOSGWidget::QOSGWidget( QWidget * parent, const char * name, WindowFlags f, 
bool overrideTraits):
#if USE_QT4
    QWidget(parent, f), _overrideTraits (overrideTraits)
#else
    QWidget(parent, name, f), _overrideTraits (overrideTraits)
#endif
{
    createContext();
    

#if USE_QT4
    setAttribute(Qt::WA_PaintOnScreen);
    setAttribute(Qt::WA_NoSystemBackground);
    setFocusPolicy(Qt::ClickFocus);
#else
    setBackgroundMode(Qt::NoBackground);
#endif    
}

void QOSGWidget::createContext()
{
    osg::DisplaySettings* ds = osg::DisplaySettings::instance();

    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new 
osg::GraphicsContext::Traits;

    traits->readDISPLAY();
    if (traits->displayNum<0) traits->displayNum = 0;

    traits->windowName = "osgViewerQt";
    traits->screenNum = 0;
    traits->x = x();
    traits->y = y();
    traits->width = width();
    traits->height = height();
    traits->alpha = ds->getMinimumNumAlphaBits();
    traits->stencil = ds->getMinimumNumStencilBits();
    traits->windowDecoration = false;
    traits->doubleBuffer = true;
    traits->sharedContext = 0;
    traits->sampleBuffers = ds->getMultiSamples();
    traits->samples = ds->getNumMultiSamples();

    traits->inheritedWindowData = new WindowData(winId());

    if (ds->getStereo())
    {
        switch(ds->getStereoMode())
        {
            case(osg::DisplaySettings::QUAD_BUFFER): traits->quadBufferStereo = 
true; break;
            case(osg::DisplaySettings::VERTICAL_INTERLACE):
            case(osg::DisplaySettings::CHECKERBOARD):
            case(osg::DisplaySettings::HORIZONTAL_INTERLACE): traits->stencil = 
8; break;
            default: break;
        }
    }

    osg::ref_ptr<osg::GraphicsContext> gc = 
osg::GraphicsContext::createGraphicsContext(traits.get());
    _gw = dynamic_cast<osgViewer::GraphicsWindow*>(gc.get());

    // get around dearanged traits on X11 (MTCompositeViewer only)
    if (_overrideTraits)
    {
        traits->x = x();
        traits->y = y();
        traits->width = width();
        traits->height = height();
    }

}
void QOSGWidget::destroyEvent(bool destroyWindow, bool destroySubWindows)
{   
    _gw->getEventQueue()->closeWindow();
}


void QOSGWidget::closeEvent( QCloseEvent * event )
{
#ifndef USE_QT4
    event->accept();
#endif

    _gw->getEventQueue()->closeWindow();
}


void QOSGWidget::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 QOSGWidget::keyPressEvent( QKeyEvent* event )
{
#if USE_QT4
    _gw->getEventQueue()->keyPress( (osgGA::GUIEventAdapter::KeySymbol) 
*(event->text().toAscii().data() ) );
#else
    _gw->getEventQueue()->keyPress( (osgGA::GUIEventAdapter::KeySymbol) 
event->ascii() );
#endif
}

void QOSGWidget::keyReleaseEvent( QKeyEvent* event )
{
#if USE_QT4
    int c = *event->text().toAscii().data();
#else
    int c = event->ascii();
#endif

    _gw->getEventQueue()->keyRelease( (osgGA::GUIEventAdapter::KeySymbol) (c) );
}

void QOSGWidget::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;
    }
    _gw->getEventQueue()->mouseButtonPress(event->x(), event->y(), button);
}
void QOSGWidget::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;
    }
    _gw->getEventQueue()->mouseDoubleButtonPress(event->x(), event->y(), 
button);
}
void QOSGWidget::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;
    }
    _gw->getEventQueue()->mouseButtonRelease(event->x(), event->y(), button);
}

void QOSGWidget::mouseMoveEvent( QMouseEvent* event )
{
    _gw->getEventQueue()->mouseMotion(event->x(), event->y());
}








class ViewerQOSG : public osgViewer::Viewer, public QOSGWidget
{
    public:

        ViewerQOSG(QWidget * parent = 0, const char * name = 0, WindowFlags f = 
0):
            QOSGWidget( parent, name, f )
        {
            getCamera()->setViewport(new osg::Viewport(0,0,width(),height()));
            getCamera()->setProjectionMatrixAsPerspective(30.0f, 
static_cast<double>(width())/static_cast<double>(height()), 1.0f, 10000.0f);
            getCamera()->setGraphicsContext(getGraphicsWindow());

            setThreadingModel(osgViewer::Viewer::SingleThreaded);

        connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
            _timer.start(10);
    }

        virtual void paintEvent( QPaintEvent * event ) { frame(); }

    protected:

        QTimer _timer;
};



class CompositeViewerQOSG : public osgViewer::CompositeViewer, public QOSGWidget
{
    public:

        CompositeViewerQOSG(QWidget * parent = 0, const char * name = 0, 
WindowFlags f = 0):
            QOSGWidget( parent, name, f )
        {
            setThreadingModel(osgViewer::CompositeViewer::SingleThreaded);

            connect(&_timer, SIGNAL(timeout()), this, SLOT(repaint()));
            _timer.start(1);
        }

        virtual void paintEvent( QPaintEvent * event ) { frame(); }

    protected:

        QTimer _timer;
};



#if USE_QT4
// we use this wrapper for CompositeViewer ONLY because of the timer
//
class MTCompositeViewer : public osgViewer::CompositeViewer, public QWidget
{
    public:

        MTCompositeViewer (QWidget * parent = 0, WindowFlags f = 0):
            QWidget (parent, f)
        {
            setThreadingModel(osgViewer::CompositeViewer::DrawThreadPerContext);
            connect(&_timer, SIGNAL(timeout()), this, SLOT(repaint()));
            _timer.start(1);
        }

        virtual void paintEvent( QPaintEvent * event ) { frame(); }

    protected:

        QTimer _timer;
};
#endif

void setupManipulatorAndHandler(osgViewer::View & viewer, osg::ArgumentParser & 
arguments)
{
    // set up the camera manipulators.
    {
        osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = 
new osgGA::KeySwitchMatrixManipulator;

        keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new 
osgGA::TrackballManipulator() );
        keyswitchManipulator->addMatrixManipulator( '2', "Flight", new 
osgGA::FlightManipulator() );
        keyswitchManipulator->addMatrixManipulator( '3', "Drive", new 
osgGA::DriveManipulator() );
        keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new 
osgGA::TerrainManipulator() );

        viewer.setCameraManipulator( keyswitchManipulator.get() );
    }

    // add the state manipulator
    viewer.addEventHandler( new 
osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
    
    // add the thread model handler
    viewer.addEventHandler(new osgViewer::ThreadingHandler);

    // add the window size toggle handler
    viewer.addEventHandler(new osgViewer::WindowSizeHandler);
        
    // add the stats handler
    viewer.addEventHandler(new osgViewer::StatsHandler);

    // add the help handler
    viewer.addEventHandler(new 
osgViewer::HelpHandler(arguments.getApplicationUsage()));
}

int mainQOSGWidget(QApplication& a, osg::ArgumentParser& arguments)
{
    // load the scene.
    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
    if (!loadedModel)
    {
        std::cout << arguments[0] <<": No data loaded." << std::endl;
        return 1;
    }

    std::cout<<"Using QOSGWidget - QWidget + osgViewer creating the graphics 
context."<<std::endl;

#if USE_QT4
    if (arguments.read("--MTCompositeViewer"))
    {

        std::cout<<" + using standard CompositeViewer with seperate contexts 
(Multithreaded mode)."<<std::endl;

        int nbCowsX = 3;
        int nbCowsY = 3;
        int size = 200;
        unsigned int width = nbCowsX * size;
        unsigned int height = nbCowsY * size;

        QGridLayout *uiLayout = new QGridLayout ();
        QWidget *wy = new QWidget ();

        // we pass wy as a parent because want wy->show () to work on cViewer
        // too..
        //
        MTCompositeViewer *cViewer = new MTCompositeViewer (wy);

        for (int x=0;x<nbCowsX; x++)
            for (int y=0;y<nbCowsY; y++)
            {

                // embed the QOSGWidget into QGroupBox to demonstrate that we
                // really use QT's Widgets
                //
                std::stringstream widgetname; widgetname << "View (" << x << 
"," << y << ")";
                QGroupBox *w= new QGroupBox (QString (widgetname.str ().c_str 
()), wy);
                QGridLayout *tmpl = new QGridLayout ();
                QOSGWidget *gw = new QOSGWidget (w, 0, 0, true);
                tmpl->addWidget (gw);
                w->setLayout(tmpl);
                uiLayout->addWidget (w, y, x);

                // setup views as usual
                osgViewer::View* view = new osgViewer::View;
                view->getCamera()->setGraphicsContext(gw->getGraphicsWindow ());
                view->getCamera()->setProjectionMatrixAsPerspective
                    (30.0f, 
static_cast<double>(size)/static_cast<double>(size/nbCowsY), 1.0, 1000.0);
                view->getCamera()->setViewport(new 
osg::Viewport(0,0,size,size));
                view->addEventHandler(new osgViewer::StatsHandler);
                view->setCameraManipulator(new osgGA::TrackballManipulator);
                view->setSceneData(loadedModel.get ());
                cViewer->addView(view);
            }

        wy->setLayout (uiLayout);
        wy->resize (width, height);
        wy->show ();

        a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );

        return a.exec();
    }
    else
    {
#endif
        if (arguments.read("--CompositeViewer"))
        {
            osg::ref_ptr<CompositeViewerQOSG> viewerWindow(new 
CompositeViewerQOSG);
            viewerWindow->setGeometry(0,0,640,480);

            unsigned int width = viewerWindow->width();
            unsigned int height = viewerWindow->height();

            {
                osgViewer::View* view1 = new osgViewer::View;
                
view1->getCamera()->setGraphicsContext(viewerWindow->getGraphicsWindow());
                view1->getCamera()->setProjectionMatrixAsPerspective(30.0f, 
static_cast<double>(width)/static_cast<double>(height/2), 1.0, 1000.0);
                view1->getCamera()->setViewport(new 
osg::Viewport(0,0,width,height/2));
                view1->setSceneData(loadedModel.get());

                setupManipulatorAndHandler(*view1, arguments);

                viewerWindow->addView(view1);
            }

            {
                osgViewer::View* view2 = new osgViewer::View;
                
view2->getCamera()->setGraphicsContext(viewerWindow->getGraphicsWindow());
                view2->getCamera()->setProjectionMatrixAsPerspective(30.0f, 
static_cast<double>(width)/static_cast<double>(height/2), 1.0, 1000.0);
                view2->getCamera()->setViewport(new 
osg::Viewport(0,height/2,width,height/2));
                view2->setSceneData(loadedModel.get());

                setupManipulatorAndHandler(*view2, arguments);

                viewerWindow->addView(view2);
            }

            viewerWindow->show();

            a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );

            return a.exec();
        }
        else
        {
            osg::ref_ptr<ViewerQOSG> viewerWindow(new ViewerQOSG);
            viewerWindow->setGeometry(0,0,640,480);

            viewerWindow->setCameraManipulator(new osgGA::TrackballManipulator);
            viewerWindow->setSceneData(loadedModel.get());

            viewerWindow->show();

            setupManipulatorAndHandler(*viewerWindow.get(), arguments);

            a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );

            return a.exec();
        }
#if USE_QT4
    }
#endif
}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to