Some additional info: The actual rendering DOES work (including user
interaction), but it's full-screen and I can't resize it since I don't have a
graphicscontext to resize.
Job
Hi,
I have created a OSG-Qt Widget (based on the QOSGWidget example) that uses
threaded rendering so the rendering doesn't block Qt's main thread. This works
fine on my own achine, which has an ATI card (and never seems to use the GPU
according to the StasHandler). However, one of my co-developers has an NVIDIA
card and for some reason the osg::GraphicsContext::createGraphicsContext call
we use returns NULL on his machine.
I have added the class below. The line that seems to cause the problem is at
the bottom of the cpp file (at the end of this mail)
Is there anything I missed there? I hope someone has encountered and solved
this problem before...
Regards, Job Mulder
//////////////////////////// h file ///////////////////////////
#ifndef OSGVIEWERWIDGET_H
#define OSGVIEWERWIDGET_H
class QPaintEvent;
class QResizeEvent;
class QCloseEvent;
class QShowEvent;
class QHideEvent;
#include <osgViewer/Viewer>
#include <osgViewer/GraphicsWindow>
#include <QtOpenGL/QGLWidget>
#include <QThread>
#include <QSize>
class OsgViewerWidget : public osgViewer::Viewer, public QGLWidget
{
private:
class OsgWidgetThread : public QThread
{
public:
OsgWidgetThread(OsgViewerWidget* parent);
protected:
virtual void run();
OsgViewerWidget* m_osgWidget;
};
public:
OsgViewerWidget(QWidget* parent = 0, Qt::WindowFlags f = 0);
virtual ~OsgViewerWidget();
virtual void updateCamera();
virtual void paintEvent(QPaintEvent*);
virtual void resizeEvent(QResizeEvent*);
virtual void closeEvent(QCloseEvent*);
virtual void showEvent(QShowEvent*);
// virtual void hideEvent(QHideEvent*);
void threadMain();
protected:
virtual void handleStateUpdatesThreaded(void);
virtual void initializeThreaded(void);
bool isThreadInitComplete() const;
void createContext();
osgViewer::GraphicsWindow* getGraphicsWindow() const;
OsgWidgetThread m_thread;
volatile bool m_terminating;
volatile bool m_resize;
volatile bool m_threadStarted;
QSize m_size;
osg::ref_ptr<osgViewer::GraphicsWindow> m_graphicsWindow;
};
#endif // OSGVIEWERWIDGET_H
//////////////////////////// cpp file ///////////////////////////
#include "osgviewerwidget.h"
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/api/Win32/GraphicsWindowWin32>
typedef osgViewer::GraphicsWindowWin32::WindowData WindowData;
#include <osgGA/TrackballManipulator>
#include <QResizeEvent>
#include <QCloseEvent>
#include <QShowEvent>
/*! \class OsgViewerWidget::OsgWidgetThread
\brief A simple thread handler for the OsgViewerWidget. It starts the
thread function of OsgViewerWidget.
*/
/*! \brief Constructor, does not start anything, just initializes
The thread is started by OsgViewerWidget.
*/
OsgViewerWidget::OsgWidgetThread::OsgWidgetThread(OsgViewerWidget* parent)
: QThread(parent)
, m_osgWidget(parent)
{
}
/*! \brief The main function of the OsgWidgetThread.
\details The function is just a wrapper for the OsgViewerWidget main
thread function
*/
void OsgViewerWidget::OsgWidgetThread::run()
{
m_osgWidget->threadMain();
}
/*! \class OsgViewerWidget
\brief An OSG viewer contained in a Qt Widget.
The class handles the actual drawing of the scenegraph in a separate
thread.
Any inheriting classes should make sure to do the same by overloading the
\a handleStateUpdatesThreaded function and calling the base function for
the
standard state updates such as resizing and closing
*/
/*! \brief Constructor, initializes the widget and starts the render thread
*/
OsgViewerWidget::OsgViewerWidget(QWidget* parent, Qt::WindowFlags f)
: QGLWidget( parent, 0, f )
, m_thread(this)
, m_terminating(false)
, m_resize(false)
, m_threadStarted(false)
{
setAttribute(Qt::WA_PaintOnScreen);
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_OpaquePaintEvent);
setAttribute(Qt::WA_PaintUnclipped);
setAttribute(Qt::WA_TranslucentBackground);
setFocusPolicy(Qt::ClickFocus);
setAutoFillBackground(false);
setThreadingModel(osgViewer::Viewer::SingleThreaded); // we already
handle the multi-threading ourselves
}
/*! \brief Destructor, stops the render thread if it was still running
*/
OsgViewerWidget::~OsgViewerWidget()
{
m_terminating = true;
m_thread.wait();
}
/*! \brief Start the render thread when showing the window
*/
void OsgViewerWidget::showEvent(QShowEvent*)
{
m_thread.start();
}
/*! \brief Wait for thread initialization to complete
*/
bool OsgViewerWidget::isThreadInitComplete() const
{
return m_threadStarted;
}
/*! \brief Update the camera, usually to match a new window size
*/
void OsgViewerWidget::updateCamera()
{
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(m_graphicsWindow.get());
}
/*! \brief The paint event is deliberately empty so Qt does not corrupt the
display
All actual painting is done in the render thread
*/
void OsgViewerWidget::paintEvent(QPaintEvent* event)
{
}
/*! \brief Handle the resize event by scheduling a threaded resize
*/
void OsgViewerWidget::resizeEvent(QResizeEvent* event)
{
m_size = event->size();
m_resize = true;
}
/*! \brief Handle the close event by ending the render thread and waiting for it
*/
void OsgViewerWidget::closeEvent(QCloseEvent* event)
{
m_terminating = true;
m_thread.wait();
event->accept();
}
/*! \brief Update state change messages coming from other threads in the render
thread
This function handles things like resize events in the render thread so
they're thread-safe
and don't interfere with the actual drawing.
Subclasses should overload this function and call it if they want to
define their own
thread-safe handling. If the events handled by the base function need to
be handled by
the subclass, make sure to handle them before calling the function and
make sure to
update the relevant boolean.
Currently only \a m_resize is checked by this function
*/
void OsgViewerWidget::handleStateUpdatesThreaded(void)
{
if (m_resize)
{
osgViewer::GraphicsWindow* gw = m_graphicsWindow.get();
if (gw)
{
gw->getEventQueue()->windowResize(0, 0, m_size.width(),
m_size.height() );
gw->resized(0, 0, m_size.width(), m_size.height());
}
updateCamera();
m_resize = false;
}
}
/*! \brief This function performs the user-specific initialization of the widget
Typically this means setting up a statshandler and camera manipulator,
which is
what the default implementation does.
*/
void OsgViewerWidget::initializeThreaded(void)
{
setCameraManipulator(new osgGA::TrackballManipulator);
addEventHandler(new osgViewer::StatsHandler);
}
/*! \brief The main render thread of the widget.
\todo Maybe bundle these for multiple widgets to reduce thread-count?
*/
void OsgViewerWidget::threadMain()
{
createContext();
initializeThreaded();
m_threadStarted = true;
while(!m_terminating)
{
handleStateUpdatesThreaded();
frame();
QThread::yieldCurrentThread();
}
}
/*! \brief Return the graphics window of the OSG part
*/
osgViewer::GraphicsWindow* OsgViewerWidget::getGraphicsWindow() const
{
return m_graphicsWindow.get();
}
/*! \brief Create the display context for the OSG viewer
This is based on the QOSGWidget example code and may include some
redundant code.
*/
void OsgViewerWidget::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());
m_graphicsWindow = dynamic_cast<osgViewer::GraphicsWindow*>(gc.get());
}
_______________________________________________
osg-users mailing list
[email protected]<mailto:[email protected]>
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org