|
@@ -0,0 +1,496 @@
|
|
|
+#include "OSGWidget.hpp"
|
|
|
+#include "PickHandler.hpp"
|
|
|
+
|
|
|
+#include <osg/Camera>
|
|
|
+
|
|
|
+#include <osg/DisplaySettings>
|
|
|
+#include <osg/Geode>
|
|
|
+#include <osg/Material>
|
|
|
+#include <osg/Shape>
|
|
|
+#include <osg/ShapeDrawable>
|
|
|
+#include <osg/StateSet>
|
|
|
+
|
|
|
+#include <osgDB/WriteFile>
|
|
|
+
|
|
|
+#include <osgGA/EventQueue>
|
|
|
+#include <osgGA/TrackballManipulator>
|
|
|
+
|
|
|
+#include <osgUtil/IntersectionVisitor>
|
|
|
+#include <osgUtil/PolytopeIntersector>
|
|
|
+
|
|
|
+#include <osgViewer/View>
|
|
|
+#include <osgViewer/ViewerEventHandlers>
|
|
|
+
|
|
|
+#include <cassert>
|
|
|
+
|
|
|
+#include <stdexcept>
|
|
|
+#include <vector>
|
|
|
+
|
|
|
+#include <QDebug>
|
|
|
+#include <QKeyEvent>
|
|
|
+#include <QPainter>
|
|
|
+#include <QWheelEvent>
|
|
|
+
|
|
|
+namespace
|
|
|
+{
|
|
|
+
|
|
|
+#ifdef WITH_SELECTION_PROCESSING
|
|
|
+QRect makeRectangle( const QPoint& first, const QPoint& second )
|
|
|
+{
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if( second.x() >= first.x() && second.y() >= first.y() )
|
|
|
+ return QRect( first, second );
|
|
|
+ else if( second.x() < first.x() && second.y() >= first.y() )
|
|
|
+ return QRect( QPoint( second.x(), first.y() ), QPoint( first.x(), second.y() ) );
|
|
|
+ else if( second.x() < first.x() && second.y() < first.y() )
|
|
|
+ return QRect( second, first );
|
|
|
+ else if( second.x() >= first.x() && second.y() < first.y() )
|
|
|
+ return QRect( QPoint( first.x(), second.y() ), QPoint( second.x(), first.y() ) );
|
|
|
+
|
|
|
+
|
|
|
+ return QRect();
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+namespace osgWidget
|
|
|
+{
|
|
|
+ void Viewer::setupThreading()
|
|
|
+ {
|
|
|
+ if( _threadingModel == SingleThreaded )
|
|
|
+ {
|
|
|
+ if(_threadsRunning)
|
|
|
+ stopThreading();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if(!_threadsRunning)
|
|
|
+ startThreading();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+OSGWidget::OSGWidget( QWidget* parent,
|
|
|
+ Qt::WindowFlags f )
|
|
|
+ : QOpenGLWidget( parent,
|
|
|
+ f )
|
|
|
+ , graphicsWindow_( new osgViewer::GraphicsWindowEmbedded( this->x(),
|
|
|
+ this->y(),
|
|
|
+ this->width(),
|
|
|
+ this->height() ) )
|
|
|
+ , viewer_( new osgWidget::Viewer )
|
|
|
+ , selectionActive_( false )
|
|
|
+ , selectionFinished_( true )
|
|
|
+{
|
|
|
+ osg::Sphere* sphere = new osg::Sphere( osg::Vec3( 0.f, 0.f, 0.f ), 0.25f );
|
|
|
+ osg::ShapeDrawable* sd = new osg::ShapeDrawable( sphere );
|
|
|
+ sd->setColor( osg::Vec4( 1.f, 0.f, 0.f, 1.f ) );
|
|
|
+ sd->setName( "A nice sphere" );
|
|
|
+
|
|
|
+ osg::Geode* geode = new osg::Geode;
|
|
|
+ geode->addDrawable( sd );
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ {
|
|
|
+ osg::StateSet* stateSet = geode->getOrCreateStateSet();
|
|
|
+ osg::Material* material = new osg::Material;
|
|
|
+
|
|
|
+ material->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE );
|
|
|
+
|
|
|
+ stateSet->setAttributeAndModes( material, osg::StateAttribute::ON );
|
|
|
+ stateSet->setMode( GL_DEPTH_TEST, osg::StateAttribute::ON );
|
|
|
+ }
|
|
|
+
|
|
|
+ float aspectRatio = static_cast<float>( this->width() / 2 ) / static_cast<float>( this->height() );
|
|
|
+ auto pixelRatio = this->devicePixelRatio();
|
|
|
+
|
|
|
+ osg::Camera* camera = new osg::Camera;
|
|
|
+ camera->setViewport( 0, 0, this->width() / 2 * pixelRatio, this->height() * pixelRatio );
|
|
|
+ camera->setClearColor( osg::Vec4( 0.f, 0.f, 1.f, 1.f ) );
|
|
|
+ camera->setProjectionMatrixAsPerspective( 30.f, aspectRatio, 1.f, 1000.f );
|
|
|
+ camera->setGraphicsContext( graphicsWindow_ );
|
|
|
+
|
|
|
+ osgViewer::View* view = new osgViewer::View;
|
|
|
+ view->setCamera( camera );
|
|
|
+ view->setSceneData( geode );
|
|
|
+ view->addEventHandler( new osgViewer::StatsHandler );
|
|
|
+#ifdef WITH_PICK_HANDLER
|
|
|
+ view->addEventHandler( new PickHandler( this->devicePixelRatio() ) );
|
|
|
+#endif
|
|
|
+
|
|
|
+ osgGA::TrackballManipulator* manipulator = new osgGA::TrackballManipulator;
|
|
|
+ manipulator->setAllowThrow( false );
|
|
|
+
|
|
|
+ view->setCameraManipulator( manipulator );
|
|
|
+
|
|
|
+ osg::Camera* sideCamera = new osg::Camera;
|
|
|
+ sideCamera->setViewport( this->width() /2 * pixelRatio, 0,
|
|
|
+ this->width() /2 * pixelRatio, this->height() * pixelRatio );
|
|
|
+
|
|
|
+ sideCamera->setClearColor( osg::Vec4( 0.f, 0.f, 1.f, 1.f ) );
|
|
|
+ sideCamera->setProjectionMatrixAsPerspective( 30.f, aspectRatio, 1.f, 1000.f );
|
|
|
+ sideCamera->setGraphicsContext( graphicsWindow_ );
|
|
|
+
|
|
|
+ osgViewer::View* sideView = new osgViewer::View;
|
|
|
+ sideView->setCamera( sideCamera );
|
|
|
+ sideView->setSceneData( geode );
|
|
|
+ sideView->addEventHandler( new osgViewer::StatsHandler );
|
|
|
+ sideView->setCameraManipulator( new osgGA::TrackballManipulator );
|
|
|
+
|
|
|
+ viewer_->addView( view );
|
|
|
+ viewer_->addView( sideView );
|
|
|
+ viewer_->setThreadingModel( osgViewer::CompositeViewer::SingleThreaded );
|
|
|
+ viewer_->realize();
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ this->setFocusPolicy( Qt::StrongFocus );
|
|
|
+ this->setMinimumSize( 100, 100 );
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ this->setMouseTracking( true );
|
|
|
+}
|
|
|
+
|
|
|
+OSGWidget::~OSGWidget()
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+void OSGWidget::paintEvent( QPaintEvent* )
|
|
|
+{
|
|
|
+ this->makeCurrent();
|
|
|
+
|
|
|
+ QPainter painter( this );
|
|
|
+ painter.setRenderHint( QPainter::Antialiasing );
|
|
|
+
|
|
|
+ this->paintGL();
|
|
|
+
|
|
|
+#ifdef WITH_SELECTION_PROCESSING
|
|
|
+ if( selectionActive_ && !selectionFinished_ )
|
|
|
+ {
|
|
|
+ painter.setPen( Qt::black );
|
|
|
+ painter.setBrush( Qt::transparent );
|
|
|
+ painter.drawRect( makeRectangle( selectionStart_, selectionEnd_ ) );
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ painter.end();
|
|
|
+
|
|
|
+ this->doneCurrent();
|
|
|
+}
|
|
|
+
|
|
|
+void OSGWidget::paintGL()
|
|
|
+{
|
|
|
+ viewer_->frame();
|
|
|
+}
|
|
|
+
|
|
|
+void OSGWidget::resizeGL( int width, int height )
|
|
|
+{
|
|
|
+ this->getEventQueue()->windowResize( this->x(), this->y(), width, height );
|
|
|
+ graphicsWindow_->resized( this->x(), this->y(), width, height );
|
|
|
+
|
|
|
+ this->onResize( width, height );
|
|
|
+}
|
|
|
+
|
|
|
+void OSGWidget::keyPressEvent( QKeyEvent* event )
|
|
|
+{
|
|
|
+ QString keyString = event->text();
|
|
|
+ const char* keyData = keyString.toLocal8Bit().data();
|
|
|
+
|
|
|
+ if( event->key() == Qt::Key_S )
|
|
|
+ {
|
|
|
+#ifdef WITH_SELECTION_PROCESSING
|
|
|
+ selectionActive_ = !selectionActive_;
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ else if( event->key() == Qt::Key_D )
|
|
|
+ {
|
|
|
+ osgDB::writeNodeFile( *viewer_->getView(0)->getSceneData(),
|
|
|
+ "/tmp/sceneGraph.osg" );
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ else if( event->key() == Qt::Key_H )
|
|
|
+ {
|
|
|
+ this->onHome();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this->getEventQueue()->keyPress( osgGA::GUIEventAdapter::KeySymbol( *keyData ) );
|
|
|
+}
|
|
|
+
|
|
|
+void OSGWidget::keyReleaseEvent( QKeyEvent* event )
|
|
|
+{
|
|
|
+ QString keyString = event->text();
|
|
|
+ const char* keyData = keyString.toLocal8Bit().data();
|
|
|
+
|
|
|
+ this->getEventQueue()->keyRelease( osgGA::GUIEventAdapter::KeySymbol( *keyData ) );
|
|
|
+}
|
|
|
+
|
|
|
+void OSGWidget::mouseMoveEvent( QMouseEvent* event )
|
|
|
+{
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if( selectionActive_ && event->buttons() & Qt::LeftButton )
|
|
|
+ {
|
|
|
+ selectionEnd_ = event->pos();
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ this->update();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ auto pixelRatio = this->devicePixelRatio();
|
|
|
+
|
|
|
+ this->getEventQueue()->mouseMotion( static_cast<float>( event->x() * pixelRatio ),
|
|
|
+ static_cast<float>( event->y() * pixelRatio ) );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void OSGWidget::mousePressEvent( QMouseEvent* event )
|
|
|
+{
|
|
|
+
|
|
|
+ if( selectionActive_ && event->button() == Qt::LeftButton )
|
|
|
+ {
|
|
|
+ selectionStart_ = event->pos();
|
|
|
+ selectionEnd_ = selectionStart_;
|
|
|
+ selectionFinished_ = false;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ else
|
|
|
+ {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ unsigned int button = 0;
|
|
|
+
|
|
|
+ switch( event->button() )
|
|
|
+ {
|
|
|
+ case Qt::LeftButton:
|
|
|
+ button = 1;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case Qt::MiddleButton:
|
|
|
+ button = 2;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case Qt::RightButton:
|
|
|
+ button = 3;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ auto pixelRatio = this->devicePixelRatio();
|
|
|
+
|
|
|
+ this->getEventQueue()->mouseButtonPress( static_cast<float>( event->x() * pixelRatio ),
|
|
|
+ static_cast<float>( event->y() * pixelRatio ),
|
|
|
+ button );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void OSGWidget::mouseReleaseEvent(QMouseEvent* event)
|
|
|
+{
|
|
|
+
|
|
|
+
|
|
|
+ if( selectionActive_ && event->button() == Qt::LeftButton )
|
|
|
+ {
|
|
|
+ selectionEnd_ = event->pos();
|
|
|
+ selectionFinished_ = true;
|
|
|
+
|
|
|
+
|
|
|
+ this->processSelection();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ else
|
|
|
+ {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ unsigned int button = 0;
|
|
|
+
|
|
|
+ switch( event->button() )
|
|
|
+ {
|
|
|
+ case Qt::LeftButton:
|
|
|
+ button = 1;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case Qt::MiddleButton:
|
|
|
+ button = 2;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case Qt::RightButton:
|
|
|
+ button = 3;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ auto pixelRatio = this->devicePixelRatio();
|
|
|
+
|
|
|
+ this->getEventQueue()->mouseButtonRelease( static_cast<float>( pixelRatio * event->x() ),
|
|
|
+ static_cast<float>( pixelRatio * event->y() ),
|
|
|
+ button );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void OSGWidget::wheelEvent( QWheelEvent* event )
|
|
|
+{
|
|
|
+
|
|
|
+ if( selectionActive_ )
|
|
|
+ return;
|
|
|
+
|
|
|
+ event->accept();
|
|
|
+ int delta = event->angleDelta().y();
|
|
|
+
|
|
|
+ osgGA::GUIEventAdapter::ScrollingMotion motion = delta > 0 ? osgGA::GUIEventAdapter::SCROLL_UP
|
|
|
+ : osgGA::GUIEventAdapter::SCROLL_DOWN;
|
|
|
+
|
|
|
+ this->getEventQueue()->mouseScroll( motion );
|
|
|
+}
|
|
|
+
|
|
|
+bool OSGWidget::event( QEvent* event )
|
|
|
+{
|
|
|
+ bool handled = QOpenGLWidget::event( event );
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ switch( event->type() )
|
|
|
+ {
|
|
|
+ case QEvent::KeyPress:
|
|
|
+ case QEvent::KeyRelease:
|
|
|
+ case QEvent::MouseButtonDblClick:
|
|
|
+ case QEvent::MouseButtonPress:
|
|
|
+ case QEvent::MouseButtonRelease:
|
|
|
+ case QEvent::MouseMove:
|
|
|
+ case QEvent::Wheel:
|
|
|
+ this->update();
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return handled;
|
|
|
+}
|
|
|
+
|
|
|
+void OSGWidget::onHome()
|
|
|
+{
|
|
|
+ osgViewer::ViewerBase::Views views;
|
|
|
+ viewer_->getViews( views );
|
|
|
+
|
|
|
+ for( std::size_t i = 0; i < views.size(); i++ )
|
|
|
+ {
|
|
|
+ osgViewer::View* view = views.at(i);
|
|
|
+ view->home();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void OSGWidget::onResize( int width, int height )
|
|
|
+{
|
|
|
+ std::vector<osg::Camera*> cameras;
|
|
|
+ viewer_->getCameras( cameras );
|
|
|
+
|
|
|
+ assert( cameras.size() == 2 );
|
|
|
+
|
|
|
+ auto pixelRatio = this->devicePixelRatio();
|
|
|
+
|
|
|
+ cameras[0]->setViewport( 0, 0, width / 2 * pixelRatio, height * pixelRatio );
|
|
|
+ cameras[1]->setViewport( width / 2 * pixelRatio, 0, width / 2 * pixelRatio, height * pixelRatio );
|
|
|
+}
|
|
|
+
|
|
|
+osgGA::EventQueue* OSGWidget::getEventQueue() const
|
|
|
+{
|
|
|
+ osgGA::EventQueue* eventQueue = graphicsWindow_->getEventQueue();
|
|
|
+
|
|
|
+ if( eventQueue )
|
|
|
+ return eventQueue;
|
|
|
+ else
|
|
|
+ throw std::runtime_error( "Unable to obtain valid event queue");
|
|
|
+}
|
|
|
+
|
|
|
+void OSGWidget::processSelection()
|
|
|
+{
|
|
|
+#ifdef WITH_SELECTION_PROCESSING
|
|
|
+ QRect selectionRectangle = makeRectangle( selectionStart_, selectionEnd_ );
|
|
|
+ auto widgetHeight = this->height();
|
|
|
+ auto pixelRatio = this->devicePixelRatio();
|
|
|
+
|
|
|
+ double xMin = selectionRectangle.left();
|
|
|
+ double xMax = selectionRectangle.right();
|
|
|
+ double yMin = widgetHeight - selectionRectangle.bottom();
|
|
|
+ double yMax = widgetHeight - selectionRectangle.top();
|
|
|
+
|
|
|
+ xMin *= pixelRatio;
|
|
|
+ yMin *= pixelRatio;
|
|
|
+ xMax *= pixelRatio;
|
|
|
+ yMax *= pixelRatio;
|
|
|
+
|
|
|
+ osgUtil::PolytopeIntersector* polytopeIntersector
|
|
|
+ = new osgUtil::PolytopeIntersector( osgUtil::PolytopeIntersector::WINDOW,
|
|
|
+ xMin, yMin,
|
|
|
+ xMax, yMax );
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ polytopeIntersector->setIntersectionLimit( osgUtil::Intersector::LIMIT_ONE_PER_DRAWABLE );
|
|
|
+
|
|
|
+ osgUtil::IntersectionVisitor iv( polytopeIntersector );
|
|
|
+
|
|
|
+ for( unsigned int viewIndex = 0; viewIndex < viewer_->getNumViews(); viewIndex++ )
|
|
|
+ {
|
|
|
+ qDebug() << "View index:" << viewIndex;
|
|
|
+
|
|
|
+ osgViewer::View* view = viewer_->getView( viewIndex );
|
|
|
+
|
|
|
+ if( !view )
|
|
|
+ throw std::runtime_error( "Unable to obtain valid view for selection processing" );
|
|
|
+
|
|
|
+ osg::Camera* camera = view->getCamera();
|
|
|
+
|
|
|
+ if( !camera )
|
|
|
+ throw std::runtime_error( "Unable to obtain valid camera for selection processing" );
|
|
|
+
|
|
|
+ camera->accept( iv );
|
|
|
+
|
|
|
+ if( !polytopeIntersector->containsIntersections() )
|
|
|
+ continue;
|
|
|
+
|
|
|
+ auto intersections = polytopeIntersector->getIntersections();
|
|
|
+
|
|
|
+ for( auto&& intersection : intersections )
|
|
|
+ qDebug() << "Selected a drawable:" << QString::fromStdString( intersection.drawable->getName() );
|
|
|
+ }
|
|
|
+#endif
|
|
|
+}
|