From Don Liech, Qt/OSG integration example

This commit is contained in:
Robert Osfield 2009-06-19 11:31:15 +00:00
parent d0916e63c6
commit 9d792c279b
15 changed files with 1377 additions and 1 deletions

View File

@ -168,7 +168,10 @@ IF(DYNAMIC_OPENSCENEGRAPH)
IF (QT_FOUND AND QT_QTOPENGL_LIBRARY)
ADD_SUBDIRECTORY(osgviewerQT)
ENDIF(QT_FOUND AND QT_QTOPENGL_LIBRARY)
IF (QT4_FOUND)
ADD_SUBDIRECTORY(osgviewerQtWidget)
ENDIF()
ENDIF()
IF (FLTK_FOUND)
ADD_SUBDIRECTORY(osgviewerFLTK)

View File

@ -0,0 +1,42 @@
#user interface compilation
SET(SOURCES_UI testMainWin.ui testOutboardWin.ui)
QT4_WRAP_UI( SOURCES_UI_H ${SOURCES_UI})
#ressources
#SET(QtApp_RCCS ressources/images/icons.qrc)
#QT4_ADD_RESOURCES(QtApp_RCC_SRCS ${QtApp_RCCS})
# for the macro Q_OBJECT..
SET(SOURCES_H
CompositeViewerQOSG.h
testMainWin.h
testOutboardWin.h
)
QT4_WRAP_CPP( SOURCES_H_MOC ${SOURCES_H} )
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} "./")
SET(TARGET_SRC
${SOURCES_H_MOC}
${SOURCES_UI_H}
QOSGWidget.h
testOutboardWin.cpp
CompositeViewerQOSG.cpp
QOSGWidget.cpp
testMainWin.cpp
main.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} )
#### end var setup ###
SETUP_EXAMPLE(osgviewerQtWidget)

View File

@ -0,0 +1,22 @@
// CompositeViewerQOSG.cpp
// #include <QCore/QDebug>
#include "CompositeViewerQOSG.h"
////////////////////////////////////////////////////////////////////////////////
CompositeViewerQOSG::CompositeViewerQOSG( QWidget * parent, Qt::WindowFlags f)
: QWidget( parent, f ), osgViewer::CompositeViewer()
{
setThreadingModel(osgViewer::CompositeViewer::SingleThreaded);
connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
_timer.start(10); // Don't know why 10, but 1 was no faster.
}
void CompositeViewerQOSG::paintEvent( QPaintEvent * /* event */ )
{
frame();
}

View File

@ -0,0 +1,28 @@
#ifndef _COMPOSITE_VIEWER_QOSG_HPP_
#define _COMPOSITE_VIEWER_QOSG_HPP_
#include <QtCore/QTimer>
#include <QtGui/QWidget>
#include <osgViewer/CompositeViewer>
class QPaintEvent;
//------------------------------------------------------------------------------
class CompositeViewerQOSG : public QWidget, public osgViewer::CompositeViewer
{
Q_OBJECT
public:
CompositeViewerQOSG( QWidget * parent = 0, Qt::WindowFlags f = 0 );
virtual ~CompositeViewerQOSG() {}
void paintEvent( QPaintEvent * /* event */ );
protected:
QTimer _timer;
}; // CompositeViewerQOSG
#endif // _COMPOSITE_VIEWER_QOSG_HPP_

View File

@ -0,0 +1,606 @@
/* 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.
*/
#include <QtCore/QDebug>
#include <CompositeViewerQOSG.h>
#include <QOSGWidget.h>
#if defined(WIN32) && !defined(__CYGWIN__)
#include <osgViewer/api/Win32/GraphicsWindowWin32>
typedef HWND WindowHandle;
typedef osgViewer::GraphicsWindowWin32::WindowData WindowData;
#elif defined(__APPLE__) // Assume using Carbon on Mac.
// #include <Carbon/Carbon.h>
#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;
// 10/17/08 LM -- osgViewer/api/X11/GraphicsWindowX11 includes X.h.
// X.h defines KeyPress and KeyRelease.
// By doing so, using QEvent::KeyPress resolves into QEvent::2,
// causing a compile error.
#undef KeyPress
#undef KeyRelease
#endif
QOSGWidget::QOSGWidget( QWidget * parent, WindowFlags f)
: QWidget(parent, f),
_gw(0)
{
#if 0
// This was a win on Linux. Same as WA_PaintOnScreen?
extern void qt_x11_set_global_double_buffer(bool);
qt_x11_set_global_double_buffer(false);
#endif
createContext(parent);
// Date: Tue, 16 Jun 2009 10:07:16 +0000
// From: "Eric Pouliquen" <epouliquen@silicon-worlds.fr>
// Subject: Re: [osg-submissions] New QOSGWidget demo with a 4-way split
// window and bonus outboard window.
// Suggested replacing the two setAttribute calls with this...
// setAttribute(Qt::WA_OpaquePaintEvent);
// This solverd a flickering problem on Windows
// 8600 GT (185.85) and a Quadro FX1400 (182.65)
// but causes a visible black border to be visible in the rendering
// windows on Linux. This problem gone when WA_PaintOnScreen
// is used in combination.
// Hmmm...
// According to Qt doc, WA_PaintOnScreen is X11 only and disables
// double-buffering. I think this just means it disables a
// buffer swap under Qt control. We want OSG to have full control.
//
// Equivalent to qt_x11_set_global_double_buffer(false)?
//
// Tried turning it off and got severe flashing on Linux.
// Looks like without this we get an extraneous clear and
// buffer swap form Qt.
setAttribute(Qt::WA_PaintOnScreen);
// This flags that something other than Qt is responsible for
// all rendering in the window under the widget's control.
setAttribute(Qt::WA_OpaquePaintEvent);
// This seems superfluous now.
// setAttribute(Qt::WA_NoSystemBackground);
// Here or in ViewQOSG?
// Either way is OK; but since this class is also the one implementing
// eventFilter(), I thought it might be wiser here.
// Qt
// If you want to see how TAB and SHIFT-TAB work wrt focus,
// uncomment the following line.
// NOTE: If focusPolicy was set in the .ui file, that setting will
// override this. So don't set focusPolicy in the .ui file!
if (parent)
{
// The desire is to allow tabbing among the views of the
// composite viewer. On Linux, I could get that to work in many
// different ways, including setting StrongFocus on the QOSGWidget and
// re-implementing focusInEvent() in ViewQOSG. But the only thing
// that worked on Windows was to set StrongFocus on the *parent*, NOT
// on this QOSGWidget, AND to have ViewQOSG::keyReleaseEvent() do
// something special on the release of a Tab or Shift-Tab key. (The
// release is seen by the ViewQOSG that is getting the focus.)
parent->setFocusPolicy( Qt::StrongFocus );
// This instance of the QOSGWidget becomes the filter object on its
// 'parent'. Ie, the child is now filtering events for the parent
// QWidget.
parent->installEventFilter( this );
qDebug() << "parent->width() is " << parent->width();
qDebug() << "parent->height() is " << parent->height();
qDebug() << "parent->x() is " << parent->x();
qDebug() << "parent->y() is " << parent->y();
qDebug() << "width() is " << width();
qDebug() << "height() is " << height();
qDebug() << "x() is " << x();
qDebug() << "y() is " << y();
}
else
setFocusPolicy( Qt::StrongFocus );
}
void QOSGWidget::createContext(QWidget * parent)
{
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 = "qosgwidget";
traits->screenNum = 0;
// original location:
// 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();
#if defined(__APPLE__)
// Extract a WindowPtr from the HIViewRef that QWidget::winId() returns.
// Without this change, the peer tries to call GetWindowPort on the HIViewRef
// which returns 0 and we only render white.
traits->inheritedWindowData = new WindowData(HIViewGetWindow((HIViewRef)winId()));
#else // all others
traits->inheritedWindowData = new WindowData(winId());
#endif
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());
// A person named Lukas on the OSG group posted that to support embedding
// in another window, the following traits had to be set after the
// graphics context was created. And he's right, if embedding, you
// definitely have to do this AFTER creating the context.... Since it
// also works when creating a top-level window, do it here for all cases
// We may have just gotten some Bad Window errors from X11 calling
// XGetWindowAttributes before the Window has been realized.
// We'll also have garbage in the traits which get fixed up next.
// _overrideTraits is superfluous now.
if (parent)
{
traits->x = parent->x();
traits->y = parent->y();
traits->width = parent->width();
traits->height = parent->height();
}
else
{
traits->x = x();
traits->y = y();
traits->width = width();
traits->height = height();
}
}
//------------------------------------------------------------------------------
// From the Qt Doc:
// "eventFilter() can accept or reject the event, and allow or deny further
// processing of the event.
//
// If all event filters allow further processing of an event (by each
// returning false), the event is sent to the target object, in this case, the
// parent of this QOSGWidget instance.
//
// If one of them stops processing (by returning true), the target (ie the
// parent widget) and any later event filters do not get to see the event at
// all. "
//
// Effectively, this filter takes all the events it's interested in, most
// notably keyboard events, and passes them along to OSG and *prevents* them
// from reaching their intended target, this widget's parent.
//
// Since QOSGWidget sets Qt focusPolicy to StrongFocus, eventFilter() isn't
// needed for the keyboard events...at least this what I've observed on Linux;
// however it is essential to support resizing in embedded Qt windows that
// aren't a top-level window.
//
// Addendum: I think the above statement is true only if the parent has the
// NoFocus policy? If the parent also has StrongFocus, then
// eventFilter() has to return false for key events or tabbing
// breaks.
//------------------------------------------------------------------------------
// Return false to allow event to go to the intended target, the parent of
// this QOSGWidget. The only events we really want to go to the parent are
// TAB or shift-TAB presses and releases.
bool QOSGWidget::eventFilter(QObject *obj, QEvent *event)
{
if (obj != parent())
{
return false;
}
else if (event->type() == QEvent::KeyPress)
{
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab)
{
qDebug() << "QOSGWidget::eventFilter: TAB Press on "
<< qPrintable(objectName());
// Empirically have found that it's not necessary to call
// keyPressEvent on tab press ... my guess is that OSG ignores it.
keyPressEvent( ke );
// Return false so that the parent QWidget will process the tab.
return false;
}
else
{
qDebug() << "QOSGWidget::eventFilter: KeyPress on "
<< qPrintable(objectName());
keyPressEvent( ke );
// event handled, return true because parent does not have to see
// this event
return true;
}
}
else if (event->type() == QEvent::KeyRelease)
{
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab)
{
qDebug() << "QOSGWidget::eventFilter: TAB Release on "
<< qPrintable(objectName());
keyReleaseEvent( ke );
// Return false so that the parent QWidget will process the tab..
return false;
}
else
{
qDebug() << "QOSGWidget::eventFilter: KeyRelease on "
<< qPrintable(objectName());
keyReleaseEvent( ke );
// event handled, return true because parent does not have to see
// this event
return true;
}
}
else if (event->type() == QEvent::Resize)
{
QResizeEvent *re = static_cast<QResizeEvent *>(event);
qDebug() << "QOSGWidget::eventFilter: width is "
<< re->size().width()
<< "; height is " << re->size().height()
<< " on " << qPrintable(objectName())
;
// Call setGeometry on 'this', which will trigger
// QOSGWidget::resizeEvent
setGeometry(0, 0, re->size().width(), re->size().height());
// event handled, return true because parent does not have to see
// this event
return true;
}
else if (event->type() == QEvent::Close)
{
QCloseEvent *ce = static_cast<QCloseEvent *>(event);
closeEvent( ce );
}
return false;
}
// Skip all of the event queue reimplementations on WIN32.
// On second thought, all but the key events.
#ifndef WIN32
void QOSGWidget::destroyEvent(bool /* destroyWindow */, bool /* destroySubWindows */ )
{
qDebug() << "QOSGWidget::destroyEvent";
_gw->getEventQueue()->closeWindow();
}
void QOSGWidget::closeEvent( QCloseEvent * /* event */ )
{
qDebug() << "QOSGWidget::closeEvent";
_gw->getEventQueue()->closeWindow();
}
void QOSGWidget::resizeEvent( QResizeEvent * event )
{
const QSize & size = event->size();
qDebug() << "QOSGWidget::resizeEvent on " << qPrintable(objectName())
<< " - width is " << size.width()
<< "; height is " << size.height();
_gw->getEventQueue()->windowResize(0, 0, size.width(), size.height() );
_gw->resized(0, 0, size.width(), size.height());
}
void QOSGWidget::mousePressEvent( QMouseEvent* event )
{
qDebug() << "QOSGWidget::mousePressEvent on "
<< qPrintable(objectName()) << " at X, Y = "
<< event->x() << ", " << event->y();
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 )
{
qDebug() << "QOSGWidget::mouseDoubleClickEvent on "
<< qPrintable(objectName());
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 )
{
qDebug() << "QOSGWidget::mouseReleaseEvent on "
<< qPrintable(objectName()) << " at X, Y = "
<< event->x() << ", " << event->y();
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 )
{
qDebug() << "QOSGWidget::mouseMoveEvent";
_gw->getEventQueue()->mouseMotion(event->x(), event->y());
}
#endif // ndef WIN32
void QOSGWidget::keyPressEvent( QKeyEvent* event )
{
qDebug() << "QOSGWidget::keyPressEvent on " << qPrintable(objectName());
_gw->getEventQueue()->keyPress(
(osgGA::GUIEventAdapter::KeySymbol) *(event->text().toAscii().data() ) );
}
void QOSGWidget::keyReleaseEvent( QKeyEvent* event )
{
qDebug() << "QOSGWidget::keyReleaseEvent on " << qPrintable(objectName());
if (event->key() == Qt::Key_Tab || event->key() == Qt::Key_Backtab)
{
qDebug() << "---- It's a TAB Release" ;
}
else
{
int c = *event->text().toAscii().data();
_gw->getEventQueue()->keyRelease( (osgGA::GUIEventAdapter::KeySymbol) (c) );
}
}
//---------------------------------------------------------------------------
// ViewQOSG creates the traits...
ViewQOSG::ViewQOSG( QWidget *parent )
: osgViewer::View(),
QOSGWidget( parent ),
_daw(parent)
{
// OSG
setGeometry( 0, 0, parent->width(), parent->height() );
getCamera()->setGraphicsContext( getGraphicsWindow() );
getCamera()->setProjectionMatrixAsPerspective(
30.0f,
static_cast<double>(parent->width()) /
static_cast<double>(parent->height()), 1.0, 1000.0);
getCamera()->setViewport(
new osg::Viewport( 0, 0, parent->width(), parent->height()));
setupManipulatorAndHandler( *this );
} // ViewQOSG::ViewQOSG
//---------------------------------------------------------------------------
// note: since ViewQOSG has focusPolicy of Qt::NoFocus, this won't be called,
// but leaving it here anyway.
// See keyReleaseEvent()
void ViewQOSG::focusInEvent( QFocusEvent * /* event */)
{
qDebug() << "ViewQOSG::focusInEvent on " << qPrintable(objectName());
CompositeViewerQOSG *cv =
dynamic_cast<CompositeViewerQOSG *>(getViewerBase());
if (cv)
// Tell the viewer that this view's camera should now have focus
cv->setCameraWithFocus( getCamera() );
}
#ifndef WIN32
//---------------------------------------------------------------------------
void ViewQOSG::resizeEvent( QResizeEvent * event )
{
const QSize & size = event->size();
qDebug() << "ViewQOSG::resizeEvent: width is "
<< size.width() << "; height is " << size.height();
QOSGWidget::resizeEvent( event );
// This call seems to be essential to getting a picture after view's
// parent QWidget has been collapsed due to QSplitter activity.
getCamera()->setProjectionMatrixAsPerspective(
30.0f,
static_cast<double>(size.width()) /
static_cast<double>(size.height()), 1.0, 1000.0);
////
// This is an attempt to prevent Qt from giving tab focus to a ViewQOSG that
// has been collapsed; in our example, this can happen by using the QSplitters
// in the QMainWindow.
//
// However, while testing this, discovered the bigger problem:
// On *any* resize, osgViewer::CompositeViewer::eventTraversal() calls
// setCameraWithFocus(0) (ie, to the first view).
// Meanwhile, Qt's focus widget may or may not be the correpsonding ViewQOSG.
// Possibly worse, the ViewQOSG corresponding to the first view in the
// composite viewer may not even be visible.
// Doesn't seem to matter in this sense: regardless of which VIEWQOSG gets a
// keyboard event, the compositeViewer applies the key's corresponding action
// to the current camera/view.
//
// All of which suggests that trying to support TAB focus on the ViewQOSG
// widgets just isn't worth it.
// if (size.width() == 0 || size.height() == 0)
// setFocusPolicy( Qt::NoFocus );
// else
// setFocusPolicy( Qt::StrongFocus );
////
} // ViewQOSG::resizeEvent
#endif // WIN32
//---------------------------------------------------------------------------
// Reimplementing keyReleaseEvent from QOSGWidget.
// When tabbing in Qt, the current widget sees the TAB Press and the widget
// that gets the focus sees the TAB Release.
// On that TAB Release, we need to tell the CompositeViewer the camera that
// should now have the focus.
//
// SEE COMMENTS IN ViewQOSG::resizeEvent re how resizing screws this all up...
void ViewQOSG::keyReleaseEvent( QKeyEvent* event )
{
qDebug() << "ViewQOSG::keyReleaseEvent on " << qPrintable(objectName());
if (event->key() == Qt::Key_Tab || event->key() == Qt::Key_Backtab)
{
if (event->key() == Qt::Key_Tab)
qDebug() << "... and it's a TAB";
else
qDebug() << "... and it's a SHIFT-TAB";
CompositeViewerQOSG *cv =
dynamic_cast<CompositeViewerQOSG *>(getViewerBase());
if (cv)
{
// Tell the viewer that this view's camera should now have focus
cv->setCameraWithFocus( getCamera() );
// Note that the Stats come up wherever; having little success in
// getting them to come up in a specific osgView.
// cv->setEventQueue( _gw->getEventQueue() );
}
// and otherwise ignore the event
}
else
{
QOSGWidget::keyReleaseEvent( event );
}
} // ViewQOSG::keyReleaseEvent
//---------------------------------------------------------------------------
void ViewQOSG::setData( osg::ref_ptr<osg::Node> loadedModel )
{
setSceneData(loadedModel.get());
}
//---------------------------------------------------------------------------
float ViewQOSG::aspectRatio( int width, int height )
{
return static_cast<float>(width) / static_cast<float>(height);
}
//---------------------------------------------------------------------------
void setupManipulatorAndHandler(osgViewer::View & view
/*, 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() );
view.setCameraManipulator( keyswitchManipulator.get() );
}
// add the state manipulator
view.addEventHandler( new osgGA::StateSetManipulator(
view.getCamera()->getOrCreateStateSet()) );
// add the thread model handler
view.addEventHandler(new osgViewer::ThreadingHandler);
// add the window size toggle handler
view.addEventHandler(new osgViewer::WindowSizeHandler);
// add the stats handler
view.addEventHandler(new osgViewer::StatsHandler);
// add the help handler
view.addEventHandler(new osgViewer::HelpHandler(/*arguments.getApplicationUsage()*/));
}

View File

@ -0,0 +1,163 @@
/* 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.
*/
#ifndef _QOSG_WIDGET_HPP_
#define _QOSG_WIDGET_HPP_
#include <QtCore/QString>
//#include <QtCore/QTimer>
#include <QtGui/QKeyEvent>
#include <QtGui/QApplication>
#include <QtGui/QWidget>
#include <QtGui/QMouseEvent>
#include <QtGui/QFocusEvent>
using Qt::WindowFlags;
// Port Note 10/14/08 LM -- I tried putting some of these headers into the
// source file, but ran into compile problems. Very order dependent?
#include <osgViewer/View>
#include <osgViewer/Viewer>
#include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/GraphicsWindow>
#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>
class QOSGWidget : public QWidget
{
public:
QOSGWidget( QWidget * parent = 0, WindowFlags f = 0 );
virtual ~QOSGWidget() {}
osgViewer::GraphicsWindow* getGraphicsWindow() {
return _gw.get();
}
const osgViewer::GraphicsWindow* getGraphicsWindow() const {
return _gw.get();
}
protected:
void init();
void createContext( QWidget *qwindow = 0 );
bool eventFilter(QObject *obj, QEvent *event);
// Looking at the doc for Qt::WA_PaintOnScreen this may be appropriate.
// Didn't seem to help or hurt.
virtual QPaintEngine *paintEngine() { return 0; }
// Grabbed this from Martin Beckett:
// The GraphincsWindowWin32 implementation already takes care of message handling.
// We don't want to relay these on Windows, it will just cause duplicate messages
// with further problems downstream (i.e. not being able to throw the trackball
#ifndef WIN32
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 mousePressEvent( QMouseEvent* event );
virtual void mouseReleaseEvent( QMouseEvent* event );
virtual void mouseMoveEvent( QMouseEvent* event );
#endif // ndef WIN32
virtual void keyPressEvent( QKeyEvent* event );
virtual void keyReleaseEvent( QKeyEvent* event );
osg::ref_ptr<osgViewer::GraphicsWindow> _gw;
bool _overrideTraits;
}; // QOSGWidget
//------------------------------------------------------------------------------
// I could get Linux to work in so many different ways.
//
// But I could get Windows to work in only one way:
// 1. If QOSGWidget is constructed with a parent QWidget, the parent's
// focusPolicy is set to StrongFocus. The QOSGWidget widget
// will have NoFocus, the default for QWidget.
//
// 2. If ViewQOSG is part of a osgViewer::CompositeViewer,
// ViewQOSG::keyReleaseEvent(), on a TAB or Shift-TAB key release,
// sets the Viewer's cameraWithFocus to the ViewQOSG's camera.
// All other key releases are passed up to QOSGWidget::keyReleaseEvent.
//
// 3. Since the QOSGWidget's focusPolicy is noFocus, and hence ViewQOSG's
// is as well, ViewQOSG::focusInEvent() will never be called.
//
// This was the only way I could get Windows to allow tabbing to change
// which View of the CompositeViewer should have focus.
//
// Using StrongFocus on the QOSGWidget (and hence ViewQOSG) instead of its
// parent caused all sorts of behavioral problems on Windows. For example,
// tabbing didn't work as expected. Or it did, but it didn't matter
// because the CompositeViewer considered the "current ViewQOSG" to be the
// one under the mouse.
//
// The code we based this on created a class that inherited from
// QOSGWidget and osgViewer::Viewer. We instead inherit from
// QOSGWidget and osgViewer::View. This allows us to post a different
// scene graph in each view that the viewer manages.
class ViewQOSG : public osgViewer::View, public QOSGWidget
{
public:
ViewQOSG( QWidget *parent /*, osg::GraphicsContext::Traits* traits*/ );
virtual ~ViewQOSG() {}
// Reimplement from QWidget
#ifndef WIN32
virtual void resizeEvent( QResizeEvent * event );
#endif // ndef WIN32
virtual void keyReleaseEvent( QKeyEvent* event );
void setData( osg::ref_ptr<osg::Node> loadedModel );
QWidget * getDrawingAreaWidget() { return _daw; }
float aspectRatio( int width, int height );
protected:
void focusInEvent( QFocusEvent *event );
QWidget *_daw; // drawing area widget
int _x, _y, _width, _height;
};
extern void setupManipulatorAndHandler(osgViewer::View & viewer
/*, osg::ArgumentParser & arguments*/);
#endif // _QOSG_WIDGET_HPP_

View File

@ -0,0 +1,107 @@
This now builds with cmake if added to the osg examples tree. A change to
examples/CMakeLists.txt is also required.
It is also possible to build this stand alone with qmake using the .pro file.
I think I've made the .pro sufficiently generic to build anywhere. The first
couple of lines in the file need to be adjusted for anyone's local environment.
This builds and runs on Linux and Win32 OK. See status section.
Mac has some problems. Qt was 4.4.2 and Mac OS X 10.5.2. 1) Had to adjust the
.pro file to hide QT_NO_DEBUG_OUTPUT or problems with a Frameworks header. 2)
Had to eliminate the outboard window to avoid a crash. 3) Only the lower-left
of the 4 views is OK. The other 3 views filled with frame buffer garbage. 4)
Maximize twice and we loose the lower-left too.
My colleague Liz Martin collaborated on the design and did the Qt work.
She is known for her copious comments. -- Don Leich, Intelligent Light
Linux/Win32 builds (on Mac substitute make for gmake):
gmake clean
qmake qosgwidget.pro
gmake
12/05/08 Status
---------------
o Implemented the skeleton of CompositeViewerQOSG and ViewQOSG (in
QOSGWidget.cpp)
o In testMainWin.ui, osgGraphicsArea is a "promoted" widget: It is promoted to
CompositeViewerQOSG
CompositeViewerQOSG inherits from both QWidget and osgViewer::CompositeViewer
o ViewQOSG inherits from QOSGWidget (which inherits from QWidget) and
osgViewer::View
o Bagged on allowing tab focus between the ViewQOSG widgets because:
o on resizing, OSG's CompositeViewer sets the camera (and view) focus to its
first osgViewer::View, which can create a disconnect between the Qt widget
(ie ViewQOSG) that has the focus and is receiving keyboard events, and the
actual ViewQOSG that the composite viewer acts on
o From empirical observation, it didn't seem to matter which ViewQOSG
received the keyboard event; the composite viewer applied the designated
action to the view the composite viewer consider current
o TAB focus would be given to a ViewQOSG even it had been completely
collapsed via QSplitter action in the QMainWindow. I was not successful
in my attempts to modify this behavior.
12/15/08 Status
---------------
o In this area, in testMainWin.ui, not only is osgGraphicsArea a promoted
widget (to CompositeViewerQOSG), but the 4 subviews are now also promoted
widgets, to ViewQOSG.
o I eliminated QOSGWidget::eventFilter().
o In QOSGWidget::QOSGWidget(), I no longer take x, y, width, and height from
the 'parent', I simply take it from itself.
Unfortunately, these changes don't help the Windows exe at all. Linux
continues to run just fine. But Windows doesn't see that TAB, and doesn't see
any *results* of the Key presses (Like 'l' to change lighting.)
5/15/09 Status
---------------
o Applied Martin Beckett's fix for WIN32 event queue handling.
5/19/09 Status
---------------
o Altered WIN32 event queue handling to not skip key events.
o Got Mac to build and sort of run. Qt is 4.4.2 and Mac OS X 10.5.2.
1) Had to adjust the .pro file to hide QT_NO_DEBUG_OUTPUT or problems with
a Frameworks header. 2) Had to eliminate the outboard window to
avoid a crash. 3) Only the lower-left of the 4 views is OK.
The other 3 views filled with frame buffer garbage. 4) Maximize
twice and we loose the lower-left too.
6/18/09 Status
---------------
o Simon Loic provided cmake infrastructure and help me debug some cmake
configuration problems. I needed to wipe my out-of-source object tree
and start over explicitly defining QT version 4, ala:
ccmake ../OpenSceneGraph-2.8.1 -DDESIRED_QT_VERSION=4
o Reimplemented QWidget::paintEngine to return 0 as recommended by doc.
This is purported to stop Qt from rendering anything in our windows.
o Eric Pouliquen recommended replacing setAttribute Qt::WA_PaintOnScreen
and Qt::WA_NoSystemBackground with Qt::WA_OpaquePaintEvent. Seems best
if we add Qt::WA_OpaquePaintEvent, get rid of Qt::WA_NoSystemBackground,
but keep Qt::WA_PaintOnScreen.

View File

@ -0,0 +1,118 @@
// Demo for a 4-way split window with a different scene graph in
// each of the 4 views. Also, an optional 5th view in it's own window.
// Qt 4.4.3 was used for this example.
//
#include <iostream>
#include <string>
#include <QtGui/QApplication>
#include <QtCore/QDebug>
#include <osgDB/ReadFile>
#include <osg/ArgumentParser>
#include "testMainWin.h"
#include "testOutboardWin.h"
#include <QtCore/QPointer>
#ifdef __APPLE__
#define DO_OUTBOARD_WINDOW 0 // won't go on Mac
#else
#define DO_OUTBOARD_WINDOW 1
#endif
using namespace std;
int main( int argc, char **argv )
{
QApplication app( argc, argv );
// load some standard files
osg::ref_ptr<osg::Node> Cow = osgDB::readNodeFile("cow.osg");
if (!Cow)
{
qDebug() << "No cow loaded.";
return 1;
}
osg::ref_ptr<osg::Node> Truck = osgDB::readNodeFile("dumptruck.osg");
if (!Truck)
{
qDebug() << "No truck loaded.";
return 1;
}
osg::ref_ptr<osg::Node> Spaceship = osgDB::readNodeFile("spaceship.osg");
if (!Spaceship)
{
qDebug() << "No spaceship loaded.";
return 1;
}
osg::ref_ptr<osg::Node> Cessna = osgDB::readNodeFile("cessna.osg");
if (!Cessna)
{
qDebug() << "No cessna loaded.";
return 1;
}
osg::ref_ptr<osg::Node> Fountain = osgDB::readNodeFile("fountain.osg");
if (!Fountain)
{
qDebug() << "No fountain loaded.";
return 1;
}
///////////////////////////////////////////////////////////////////////////
app.connect( &app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()) );
osg::ArgumentParser arguments(&argc, argv);
QPointer<testMainWin> myMainWindow = new testMainWin;
#if DO_OUTBOARD_WINDOW
QPointer<testOutboardWin> mySecondaryWindow = new testOutboardWin;
#endif
// The .ui file uses the "Promoted" widget, CompositeViewerQOSG
osg::ref_ptr<CompositeViewerQOSG> compositeViewer = myMainWindow->ui.osgGraphicsArea;
osg::ref_ptr<ViewQOSG> view1 = new ViewQOSG( myMainWindow->ui.graphicsView1 );
view1->setObjectName("ViewQOSG 1");
osg::ref_ptr<ViewQOSG> view2 = new ViewQOSG( myMainWindow->ui.graphicsView2 );
view2->setObjectName("ViewQOSG 2");
osg::ref_ptr<ViewQOSG> view3 = new ViewQOSG( myMainWindow->ui.graphicsView3 );
view3->setObjectName("ViewQOSG 3");
osg::ref_ptr<ViewQOSG> view4 = new ViewQOSG( myMainWindow->ui.graphicsView4 );
view4->setObjectName("ViewQOSG 4");
view1->setData( Cow );
view2->setData( Truck );
view3->setData( Spaceship );
view4->setData( Cessna );
compositeViewer->addView( view1.get() );
compositeViewer->addView( view2.get() );
compositeViewer->addView( view3.get() );
compositeViewer->addView( view4.get() );
myMainWindow->show();
#if DO_OUTBOARD_WINDOW
QWidget *outboardGfx = mySecondaryWindow->getDrawingAreaWidget();
osg::ref_ptr<ViewQOSG> outboardView = static_cast<ViewQOSG*>( outboardGfx );
outboardView->setObjectName("ViewQOSG Outboard");
outboardView->setData( Fountain );
// Note that outboardView, in a completely different window, is going to be
// managed by the compositeViewer in the QMainWindow.
compositeViewer->addView( outboardView.get() );
mySecondaryWindow->show();
#endif
return app.exec();
}

View File

@ -0,0 +1,80 @@
# Adjust these for your build environment.
win32 {
OSGHOME=c:/Program Files/OpenSceneGraph
} else {
OSGHOME=/usr/osg/OpenSceneGraph-2.8.1
#OUT_OF_SOURCE_POSTFIX=
# OUT_OF_SOURCE_POSTFIX=.build_debug
OUT_OF_SOURCE_POSTFIX=.build_release
}
D=
# Uncomment to enable debug library linkinig
# CONFIG += debug
# D=d
#-----------------------------------------------------------------------------
# This is untested...
# Added for Qt-4.5.1 which now requires linking with Frameworks
# /usr/local/Trolltech/Qt-4.5.1/lib/QtGui.framework/QtGui
#
# QMAKE_FLAGS += -F/usr/local/Trolltech/Qt-4.5.1/lib/
# LIBS += -framework QtGui -framework QtCore
#-----------------------------------------------------------------------------
TEMPLATE = app
QMAKE_CXXFLAGS_THREAD += -pthread
CONFIG += thread
#-----------------------------------------------------------------------------
win32 {
cpu_type = win32_x86
} else {
cpu_type = $$system(uname -m)
OBJECTS_DIR = $${cpu_type}
TARGET = $${OBJECTS_DIR}/qosgwidget
}
#-----------------------------------------------------------------------------
win32 {
CONFIG += console
DEPENDPATH += .
INCLUDEPATH += . $$quote("\"$${OSGHOME}/include\"")
} else {
# Need the extra path to find OpenThreads/Config with out-of-source builds.
INCLUDEPATH += $${OSGHOME}$${OUT_OF_SOURCE_POSTFIX}/include $${OSGHOME}/include
}
macx {
CONFIG += x86
# Uncomment to turn off qDebug() messages:
# When uncommented there's a problem with a Frameworks header file??!!
# DEFINES += QT_NO_DEBUG_OUTPUT
} else {
# Comment out to turn on qDebug() messages:
DEFINES += QT_NO_DEBUG_OUTPUT
}
FORMS = testMainWin.ui testOutboardWin.ui
HEADERS = testMainWin.h testOutboardWin.h QOSGWidget.h CompositeViewerQOSG.h
SOURCES += main.cpp testMainWin.cpp testOutboardWin.cpp QOSGWidget.cpp \
CompositeViewerQOSG.cpp
OSG_LIBS= -losgText$${D} -losgGA$${D} -losgFX$${D} \
-losgDB$${D} -losgUtil$${D} -losg$${D} \
-lOpenThreads$${D} -losgViewer$${D} \
#-----------------------------------------------------------------------------
win32 {
OSG_LIB_DIR=$${OSGHOME}/lib
QMAKE_LFLAGS += /LIBPATH:$$quote("\"$${OSG_LIB_DIR}\"")
LIBS += $${OSG_LIBS}
} else {
LIBS += -L$${OSGHOME}$${OUT_OF_SOURCE_POSTFIX}/lib $${OSG_LIBS}
}

View File

@ -0,0 +1,11 @@
#include "testMainWin.h"
testMainWin::testMainWin()
: QMainWindow()
{
ui.setupUi( this );
connect ( ui.actionExit, SIGNAL(activated(void)), this, SLOT(close()) );
}

View File

@ -0,0 +1,18 @@
#ifndef TESTMAINWIN_HPP_
#define TESTMAINWIN_HPP_
#include "ui_testMainWin.h"
class testMainWin : public QMainWindow // QWidget
{
Q_OBJECT
public:
testMainWin();
public: // for now
Ui::testMainWin ui;
};
#endif // TESTMAINWIN_HPP_

View File

@ -0,0 +1,108 @@
<ui version="4.0" >
<class>testMainWin</class>
<widget class="QMainWindow" name="testMainWin" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>621</width>
<height>547</height>
</rect>
</property>
<property name="windowTitle" >
<string>MainWindow</string>
</property>
<widget class="QWidget" name="graphicsArea" >
<layout class="QVBoxLayout" name="graphicsAreaVLayout" >
<item>
<widget class="CompositeViewerQOSG" native="1" name="osgGraphicsArea" >
<layout class="QVBoxLayout" name="osgGraphicsAreaVLayout" >
<item>
<widget class="QSplitter" name="graphicsAreaVSplitter" >
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<widget class="QSplitter" name="graphicsAreaHSplitterTop" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" native="1" name="graphicsView1" />
<widget class="QWidget" native="1" name="graphicsView2" />
</widget>
<widget class="QSplitter" name="graphicsAreaHSplitterBottom" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" native="1" name="graphicsView3" />
<widget class="QWidget" native="1" name="graphicsView4" />
</widget>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>621</width>
<height>28</height>
</rect>
</property>
<widget class="QMenu" name="menuMain" >
<property name="title" >
<string>Main</string>
</property>
<addaction name="actionExit" />
</widget>
<addaction name="menuMain" />
</widget>
<widget class="QStatusBar" name="statusbar" />
<widget class="QToolBar" name="sideToolbar" >
<property name="windowTitle" >
<string>toolBar</string>
</property>
<attribute name="toolBarArea" >
<enum>LeftToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak" >
<bool>false</bool>
</attribute>
</widget>
<widget class="QToolBar" name="topToolbar" >
<property name="windowTitle" >
<string>toolBar_2</string>
</property>
<attribute name="toolBarArea" >
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak" >
<bool>false</bool>
</attribute>
</widget>
<action name="actionExit" >
<property name="text" >
<string>Exit</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>CompositeViewerQOSG</class>
<extends>QWidget</extends>
<header>CompositeViewerQOSG.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>graphicsView1</tabstop>
<tabstop>graphicsView2</tabstop>
<tabstop>graphicsView3</tabstop>
<tabstop>graphicsView4</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,12 @@
#include "testOutboardWin.h"
testOutboardWin::testOutboardWin(QWidget *parent)
: QDialog( parent )
{
ui.setupUi( this );
}
QWidget * testOutboardWin::getDrawingAreaWidget(void)
{
return ui.graphicsView;
}

View File

@ -0,0 +1,20 @@
#ifndef TESTPLOTWIN_HPP_
#define TESTPLOTWIN_HPP_
#include "ui_testOutboardWin.h"
class testOutboardWin : public QDialog
{
Q_OBJECT
public:
testOutboardWin( QWidget *parent = 0 );
QWidget *getDrawingAreaWidget();
private:
Ui::testOutboardWindow ui;
};
#endif // TESTOUTBOARDWIN_HPP_

View File

@ -0,0 +1,38 @@
<ui version="4.0" >
<class>testOutboardWindow</class>
<widget class="QDialog" name="testOutboardWindow" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>278</width>
<height>292</height>
</rect>
</property>
<property name="windowTitle" >
<string>The Outboard Window</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" >
<item>
<widget class="ViewQOSG" native="1" name="graphicsView" >
<property name="minimumSize" >
<size>
<width>100</width>
<height>100</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ViewQOSG</class>
<extends>QWidget</extends>
<header>QOSGWidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>