Hi Robert,

still no clue what causes the bad window but most probably this is due
to the sequence of windowing toolkit initialization between qt,osg and
x11, so looking at GraphicsWindowX11 might be a good idea. 

Please ignore the header definition message from my last email, i've
mistook different file versions. The file was actually ok.

I have updated QOSGWindow due to your recommendations. Playing around
with it i've found some bugs so changed the widget which contains the
timer doing calls to CompositeViewer::frame () too. 

Unfortunately the mod does not behave as stable as my personal
applications in terms of number of independent widgets and resizing. The
reason for this is the workaround due to the timer, which is best
implemented standalone if using osg's CompositeViewer (no subclassing
with QWidget) like in the mod. I had bad performance using subclassing
in this case since we need to use qt's window inheritance. Maybe someone
can find a better solution to this...

I could see however you guys did quite a job working around to avoid
usage of the moc (because of cmake ?, usually qmake would call it for
you). 

Please note that if any subclasses of QObject want to implement custom
slots, which are not built using the moc, the user will get a runtime
error that slots are not present..  something like this:

Object::connect: No such slot QWidget::update()

In order to use these, the Q_OBJECT macro must be used at the beginning
of the class declaration.  Doing this, but compiling without moc
however, will lead to another error message looking something like this:

QOSGWidget.cpp:(.text+0x2028): undefined reference to `vtable for
QViewerTimer'

I just wanted to mention this because i know (my private apps work quite
fine) that there is way more performance and stability potential in
using osg with qt. Unfortunately this cannot be implemented in the
current example. Maybe you guys can fix this issue by finding a way to
call the moc from within cmake and implement signals and slots the
recommended 'QT way'.

I've attached the new version.

Best regards,
Lukas

On Mon, Oct 27, 2008 at 11:30:24AM +0000, Robert Osfield wrote:
> Hi Lukas,
> 
> I have do a test applying your patch and get the errors X11 your
> mention, I haven't dug into the example QT implementation or
> osgViewer::GraphicsWIndowX11 yet, but it does sound like we might need
> to refactor either the example or GraphicsWindowX11 to avoid the
> issue.  I would like to see these fixed as end users wouldn't be able
> to deploy an app that produces these warnings.
> 
> In your follow up post you write:
> 
> "Sorry, forgot to mention that i've remove the header definitions for mac
> and windows. Please add the original header definitions from the
> example."
> 
> I couldn't spot any code related this this.  Could be specific about
> what you mean here.
> 
> On a final note, the placement of the:
> 
> #if USE_QT4
>     if (arugments.read("--MTCompositeViewer"))
>    {
> ..
>    }
> ...
> 
> Makes the CompositeViewer code a bit more awkward, with the code
> indendent when it needn't be and there is an extra #if def's around
> the close } bracket that is at first look confusing.
> 
> A better structuring of your MTCompositeViewer code would be to put it
> after the --CompositeViewer block, then you could just put the #if
> USE_QT4 around one single block, and indentation could remain more
> consistent between the blocks.
> 
> As there a couple of issues outstanding that need resolving I'm going
> to hold off from merging right now.  Could you restructure the code as
> per the suggestion above and explain/resolve the header definitions.
> 
> Cheers,
> Robert.
> 
> 
> On Wed, Oct 15, 2008 at 9:07 PM, Lukas Diduch <[EMAIL PROTECTED]> wrote:
> >
> > 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
> >
> > _______________________________________________
> > osg-submissions mailing list
> > [email protected]
> > http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
> >
> >
> _______________________________________________
> osg-submissions mailing list
> [email protected]
> http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

-- 
Lukas L. Diduch
Smartspace Laboratory
Information Access Division (IAD) 
National Institute of Standards and Technology (NIST)

web    : http://www.nist.gov/smartspace
email  : [EMAIL PROTECTED]
office : +1 (301) 975 6399
fax    : +1 (301) 975 5287 
mobile : +1 (240) 899 6536
/* 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
// NOTE: this is a workaround because we're not using QT's moc precompiler here.
//
class QViewerTimer : public QWidget
{

    public:

        QViewerTimer (QWidget * parent = 0, WindowFlags f = 0):
            QWidget (parent, f)
    {
        _viewer = new osgViewer::CompositeViewer ();
        
_viewer->setThreadingModel(osgViewer::CompositeViewer::DrawThreadPerContext);
        connect(&_timer, SIGNAL(timeout()), this, SLOT(repaint()));
        _timer.start(10);
    }

    ~QViewerTimer ()
    {
        _timer.stop ();
    }

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

        osg::ref_ptr <osgViewer::CompositeViewer> _viewer;
        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 (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();
    }
#if USE_QT4
    else if (arguments.read("--MTCompositeViewer"))
    {

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

        int nbCowsX = 3;
        int nbCowsY = 2;
        int size = 300;
        unsigned int width = nbCowsX * size;
        unsigned int height = nbCowsY * size;

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

        // the timer holds an instance of osgViewer::CompositeViewer
        // NOTE: this is a workaround since we're not using QT's moc 
precompiler here..
        QViewerTimer *ctimer = new QViewerTimer ();

        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>(width*2)/static_cast<double>(height), 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 ());
                ctimer->_viewer->addView(view);
            }

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

        // we need the timer to be visible for repaints
        // NOTE: this is a workaround since we're not using QT's moc 
precompiler here..
        ctimer->resize (1,1);
        ctimer->show ();

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

        return a.exec();
    }
#endif
    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();
    }
}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to