From b19898ac5d73722810a3ad9a85c12ff5f46fb14a Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sun, 20 Mar 2016 18:23:10 +0100 Subject: [PATCH] LP-29 extract CameraManipulator out of OSGCamera - clean up Camera/Viewport - clean up SkyNode - replace attach/detach with use of QQmlParserStatus --- .../osgearth/osgQtQuick/OSGBackgroundNode.cpp | 37 +- .../osgearth/osgQtQuick/OSGBackgroundNode.hpp | 3 - .../libs/osgearth/osgQtQuick/OSGCamera.cpp | 459 ++++-------------- .../libs/osgearth/osgQtQuick/OSGCamera.hpp | 89 +--- .../libs/osgearth/osgQtQuick/OSGFileNode.cpp | 39 +- .../libs/osgearth/osgQtQuick/OSGFileNode.hpp | 3 - .../osgQtQuick/OSGGeoTransformNode.cpp | 56 +-- .../osgQtQuick/OSGGeoTransformNode.hpp | 7 +- .../src/libs/osgearth/osgQtQuick/OSGGroup.cpp | 37 +- .../src/libs/osgearth/osgQtQuick/OSGGroup.hpp | 3 - .../src/libs/osgearth/osgQtQuick/OSGNode.cpp | 78 +-- .../src/libs/osgearth/osgQtQuick/OSGNode.hpp | 24 +- .../libs/osgearth/osgQtQuick/OSGShapeNode.cpp | 20 +- .../libs/osgearth/osgQtQuick/OSGShapeNode.hpp | 3 - .../libs/osgearth/osgQtQuick/OSGSkyNode.cpp | 88 ++-- .../libs/osgearth/osgQtQuick/OSGSkyNode.hpp | 10 +- .../libs/osgearth/osgQtQuick/OSGTextNode.cpp | 21 +- .../libs/osgearth/osgQtQuick/OSGTextNode.hpp | 3 - .../osgearth/osgQtQuick/OSGTransformNode.cpp | 37 +- .../osgearth/osgQtQuick/OSGTransformNode.hpp | 3 - .../libs/osgearth/osgQtQuick/OSGViewport.cpp | 410 +++++++++------- .../libs/osgearth/osgQtQuick/OSGViewport.hpp | 32 +- .../osgQtQuick/ga/OSGCameraManipulator.cpp | 143 ++++++ .../osgQtQuick/ga/OSGCameraManipulator.hpp | 74 +++ .../osgQtQuick/ga/OSGEarthManipulator.cpp | 70 +++ .../osgQtQuick/ga/OSGEarthManipulator.hpp | 50 ++ .../ga/OSGGeoTransformManipulator.cpp | 337 +++++++++++++ .../ga/OSGGeoTransformManipulator.hpp | 78 +++ .../ga/OSGNodeTrackerManipulator.cpp | 169 +++++++ .../ga/OSGNodeTrackerManipulator.hpp | 71 +++ .../osgQtQuick/ga/OSGTrackballManipulator.cpp | 70 +++ .../osgQtQuick/ga/OSGTrackballManipulator.hpp | 50 ++ ground/gcs/src/libs/osgearth/osgearth.pro | 18 + ground/gcs/src/libs/osgearth/utility.cpp | 24 +- ground/gcs/src/share/qml/EarthView.qml | 19 +- .../src/share/qml/model/ModelTerrainView.qml | 45 +- ground/gcs/src/share/qml/model/ModelView.qml | 18 +- .../gcs/src/share/qml/pfd/PfdTerrainView.qml | 40 +- 38 files changed, 1770 insertions(+), 968 deletions(-) create mode 100644 ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGCameraManipulator.cpp create mode 100644 ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGCameraManipulator.hpp create mode 100644 ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGEarthManipulator.cpp create mode 100644 ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGEarthManipulator.hpp create mode 100644 ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGGeoTransformManipulator.cpp create mode 100644 ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGGeoTransformManipulator.hpp create mode 100644 ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGNodeTrackerManipulator.cpp create mode 100644 ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGNodeTrackerManipulator.hpp create mode 100644 ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGTrackballManipulator.cpp create mode 100644 ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGTrackballManipulator.hpp diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBackgroundNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBackgroundNode.cpp index 48560d963..870fdf2de 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBackgroundNode.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBackgroundNode.cpp @@ -35,6 +35,8 @@ #include namespace osgQtQuick { +enum DirtyFlag { URL = 1 << 0 }; + struct OSGBackgroundNode::Hidden : public QObject { Q_OBJECT @@ -44,17 +46,15 @@ private: public: QUrl url; - Hidden(OSGBackgroundNode *parent) : QObject(parent), self(parent), url() {} + Hidden(OSGBackgroundNode *self) : QObject(self), self(self), url() + {} - void updateNode() + void updateURL() { - // qDebug() << "OSGBackgroundNode::realize - reading image file" << url.path(); + qDebug() << "OSGBackgroundNode::updateNode - reading image file" << url.path(); osg::ref_ptr texture = new osg::Texture2D; - osg::ref_ptr image = osgDB::readImageFile(url.path().toStdString()); - texture->setImage(image.get()); - - osg::ref_ptr quad = osg::createTexturedQuadGeometry( + osg::ref_ptr quad = osg::createTexturedQuadGeometry( osg::Vec3(), osg::Vec3(1.0f, 0.0f, 0.0f), osg::Vec3(0.0f, 1.0f, 0.0f)); quad->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture.get()); @@ -75,21 +75,20 @@ public: ss->setAttributeAndModes(new osg::Depth(osg::Depth::LEQUAL, 1.0, 1.0)); self->setNode(camera); + + osg::ref_ptr image = osgDB::readImageFile(url.path().toStdString()); + texture->setImage(image.get()); } }; /* class OSGBackgroundNode */ -enum DirtyFlag { URL = 1 << 0 }; - OSGBackgroundNode::OSGBackgroundNode(QObject *parent) : OSGNode(parent), h(new Hidden(this)) -{ - qDebug() << "OSGBackgroundNode::OSGBackgroundNode"; -} +{} OSGBackgroundNode::~OSGBackgroundNode() { - // qDebug() << "OSGBackgroundNode::~OSGBackgroundNode"; + qDebug() << "OSGBackgroundNode::~OSGBackgroundNode"; delete h; } @@ -100,7 +99,6 @@ const QUrl OSGBackgroundNode::imageFile() const void OSGBackgroundNode::setImageFile(const QUrl &url) { - // qDebug() << "OSGBackgroundNode::setImageFile" << url; if (h->url != url) { h->url = url; setDirty(URL); @@ -111,18 +109,9 @@ void OSGBackgroundNode::setImageFile(const QUrl &url) void OSGBackgroundNode::update() { if (isDirty(URL)) { - h->updateNode(); + h->updateURL(); } } - -void OSGBackgroundNode::attach(osgViewer::View *view) -{ - update(); - clearDirty(); -} - -void OSGBackgroundNode::detach(osgViewer::View *view) -{} } // namespace osgQtQuick #include "OSGBackgroundNode.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBackgroundNode.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBackgroundNode.hpp index a14e421d1..87c08507a 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBackgroundNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBackgroundNode.hpp @@ -55,9 +55,6 @@ private: Hidden *const h; virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.cpp index 023762592..461db5205 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.cpp @@ -29,28 +29,18 @@ #include "OSGNode.hpp" -#include "../utility.h" - #include -#include #include -#include - -#include -#include - -#include #ifdef USE_OSGEARTH -#include #include #endif #include -#include -#include namespace osgQtQuick { +enum DirtyFlag { FieldOfView = 1 << 0, ClearColor = 1 << 1, LogDepthBuffer = 1 << 4 }; + struct OSGCamera::Hidden : public QObject { Q_OBJECT @@ -60,34 +50,34 @@ private: osg::ref_ptr camera; public: - OSGNode *sceneNode; - // Camera vertical field of view in degrees - qreal fieldOfView; + // fov depends on the scenery space (probably distance) + // here are some value: 75°, 60°, 45° many gamers use + // x-plane uses 45° for 4:3 and 60° for 16:9/16:10 + // flightgear uses 55° / 70° + qreal fieldOfView; - ManipulatorMode::Enum manipulatorMode; + QColor clearColor; - // for NodeTrackerManipulator - TrackerMode::Enum trackerMode; - OSGNode *trackNode; + bool logDepthBufferEnabled; - bool logDepthBufferEnabled; #ifdef USE_OSGEARTH osgEarth::Util::LogarithmicDepthBuffer *logDepthBuffer; #endif - bool clampToTerrain; - bool intoTerrain; - - QVector3D attitude; - QVector3D position; - public: - Hidden(OSGCamera *camera) : - QObject(camera), self(camera), sceneNode(NULL), fieldOfView(90), - manipulatorMode(ManipulatorMode::Default), trackerMode(TrackerMode::NodeCenterAndAzim), trackNode(NULL), - logDepthBufferEnabled(false), clampToTerrain(false), intoTerrain(false) + Hidden(OSGCamera *self) : QObject(self), self(self), fieldOfView(90), clearColor(0, 0, 0, 255), logDepthBufferEnabled(false) { + // default blue osg::Vec4f(0.2f, 0.99f, 0.4f, 1.0f) + camera = new osg::Camera(); + + camera->setClearColor(osg::Vec4(clearColor.redF(), clearColor.greenF(), clearColor.blueF(), clearColor.alphaF())); + + osg::StateSet *stateset = camera->getOrCreateStateSet(); + stateset->setGlobalDefaults(); + + self->setNode(camera); + #ifdef USE_OSGEARTH logDepthBuffer = NULL; #endif @@ -95,97 +85,6 @@ public: ~Hidden() { -#ifdef USE_OSGEARTH - if (logDepthBuffer) { - delete logDepthBuffer; - logDepthBuffer = NULL; - } -#endif - } - - bool acceptSceneNode(OSGNode *node) - { - qDebug() << "OSGCamera::acceptSceneNode" << node; - if (sceneNode == node) { - return true; - } - - if (sceneNode) { - disconnect(sceneNode); - } - - sceneNode = node; - - if (sceneNode) { - connect(sceneNode, &OSGNode::nodeChanged, this, &Hidden::onSceneNodeChanged); - } - - return true; - } - - bool acceptManipulatorMode(ManipulatorMode::Enum mode) - { - // qDebug() << "OSGCamera::acceptManipulatorMode" << mode; - if (manipulatorMode == mode) { - return false; - } - - manipulatorMode = mode; - - return true; - } - - bool acceptTrackNode(OSGNode *node) - { - qDebug() << "OSGCamera::acceptTrackNode" << node; - if (trackNode == node) { - return false; - } - - if (trackNode) { - disconnect(trackNode); - } - - trackNode = node; - - if (trackNode) { - connect(trackNode, SIGNAL(nodeChanged(osg::Node *)), this, SLOT(onTrackNodeChanged(osg::Node *))); - } - - return true; - } - - void attachCamera(osg::Camera *camera) - { - qDebug() << "OSGCamera::attach" << camera; - - this->camera = camera; - self->setNode(this->camera.get()); - -#ifdef USE_OSGEARTH - // install log depth buffer if requested - if (logDepthBufferEnabled) { - qDebug() << "OSGCamera::attach - install logarithmic depth buffer"; - logDepthBuffer = new osgEarth::Util::LogarithmicDepthBuffer(); - logDepthBuffer->setUseFragDepth(true); - logDepthBuffer->install(camera); - } -#endif - - updateFieldOfView(); - updateAspectRatio(); - } - - void detachCamera(osg::Camera *camera) - { - qDebug() << "OSGCamera::detach" << camera; - - if (camera != this->camera) { - qWarning() << "OSGCamera::detach - camera not attached" << camera; - return; - } - this->camera = NULL; - #ifdef USE_OSGEARTH if (logDepthBuffer) { logDepthBuffer->uninstall(camera); @@ -195,93 +94,26 @@ public: #endif } - void attachManipulator(osgViewer::View *view) + void updateClearColor() { - qDebug() << "OSGCamera::attachManipulator" << view; - - osgGA::CameraManipulator *cm = NULL; - - switch (manipulatorMode) { - case ManipulatorMode::Default: - { - qDebug() << "OSGCamera::attachManipulator - use TrackballManipulator"; - osgGA::TrackballManipulator *tm = new osgGA::TrackballManipulator(); - // Set the minimum distance of the eye point from the center before the center is pushed forward. - // tm->setMinimumDistance(1, true); - cm = tm; - break; - } - case ManipulatorMode::User: - qDebug() << "OSGCamera::attachManipulator - no camera manipulator"; - // disable any installed camera manipulator - // TODO create and use own camera manipulator to avoid disabling ON_DEMAND frame update scheme - // see https://github.com/gwaldron/osgearth/commit/796daf4792ccaf18ae7eb6a5cb268eef0d42888d - // TODO see StandardManipulator for an example on how to react to events (to have FOV changes without the need for an update callback?) - cm = NULL; - break; - case ManipulatorMode::Earth: - { -#ifdef USE_OSGEARTH - qDebug() << "OSGCamera::attachManipulator - use EarthManipulator"; - osgEarth::Util::EarthManipulator *em = new osgEarth::Util::EarthManipulator(); - em->getSettings()->setThrowingEnabled(true); - cm = em; -#endif - break; - } - case ManipulatorMode::Track: - qDebug() << "OSGCamera::attachManipulator - use NodeTrackerManipulator"; - if (trackNode && trackNode->node()) { - // setup tracking camera - // TODO when camera is thrown, then changing attitude has jitter - osgGA::NodeTrackerManipulator *ntm = new osgGA::NodeTrackerManipulator( - /*osgGA::StandardManipulator::COMPUTE_HOME_USING_BBOX | osgGA::StandardManipulator::DEFAULT_SETTINGS*/); - switch (trackerMode) { - case TrackerMode::NodeCenter: - ntm->setTrackerMode(osgGA::NodeTrackerManipulator::NODE_CENTER); - break; - case TrackerMode::NodeCenterAndAzim: - ntm->setTrackerMode(osgGA::NodeTrackerManipulator::NODE_CENTER_AND_AZIM); - break; - case TrackerMode::NodeCenterAndRotation: - ntm->setTrackerMode(osgGA::NodeTrackerManipulator::NODE_CENTER_AND_ROTATION); - break; - } - ntm->setTrackNode(trackNode->node()); - ntm->setVerticalAxisFixed(false); - cm = ntm; - } else { - qWarning() << "OSGCamera::attachManipulator - no track node provided."; - cm = NULL; - } - break; - default: - qWarning() << "OSGCamera::attachManipulator - should not reach here!"; - break; + if (!camera.valid()) { + qDebug() << "OSGCamera::updateClearColor - invalid camera"; + return; } - view->setCameraManipulator(cm, false); - if (cm && sceneNode && sceneNode->node()) { - qDebug() << "OSGCamera::attachManipulator - camera node" << sceneNode; - // set node used to auto compute home position - // needs to be done after setting the manipulator on the view as the view will set its scene as the node - cm->setNode(sceneNode->node()); - } - if (cm) { - view->home(); - } - } + qDebug() << "OSGCamera::updateClearColor" << clearColor; - void detachManipulator(osgViewer::View *view) - { - qDebug() << "OSGCamera::detachManipulator" << view; - - view->setCameraManipulator(NULL, false); + camera->setClearColor(osg::Vec4(clearColor.redF(), clearColor.greenF(), clearColor.blueF(), clearColor.alphaF())); } void updateFieldOfView() { - qDebug() << "OSGCamera::updateCameraFOV" << fieldOfView; + if (!camera.valid()) { + qDebug() << "OSGCamera::updateFieldOfView - invalid camera"; + return; + } + + qDebug() << "OSGCamera::updateFieldOfView" << fieldOfView; double fovy, ar, zn, zf; camera->getProjectionMatrixAsPerspective(fovy, ar, zn, zf); @@ -291,7 +123,16 @@ public: void updateAspectRatio() { + if (!camera.valid()) { + qDebug() << "OSGCamera::updateAspectRatio - invalid camera"; + return; + } osg::Viewport *viewport = camera->getViewport(); + if (!viewport) { + qDebug() << "OSGCamera::updateAspectRatio - no viewport" << viewport; + return; + } + double aspectRatio = static_cast(viewport->width()) / static_cast(viewport->height()); qDebug() << "OSGCamera::updateAspectRatio" << aspectRatio; @@ -302,80 +143,57 @@ public: camera->setProjectionMatrixAsPerspective(fovy, ar, zn, zf); } - void updatePosition() + void updateLogDepthBuffer() { - if (manipulatorMode != ManipulatorMode::User) { + qDebug() << "OSGCamera::updateLogDepthBuffer" << logDepthBufferEnabled; + if (!camera.valid()) { + qWarning() << "OSGCamera::updateLogDepthBuffer - invalid camera"; return; } - // Altitude mode is absolute (absolute height above MSL/HAE) - // HAE : Height above ellipsoid. This is the default. - // MSL : Height above Mean Sea Level (MSL) if a geoid separation value is specified. - // TODO handle the case where the terrain SRS is not "wgs84" - // TODO check if position is not below terrain? - // TODO compensate antenna height when source of position is GPS (i.e. subtract antenna height from altitude) ;) - - // Camera position - osg::Matrix cameraPosition; - #ifdef USE_OSGEARTH - osgEarth::GeoPoint geoPoint = osgQtQuick::toGeoPoint(position); - if (clampToTerrain) { - if (sceneNode) { - osgEarth::MapNode *mapNode = osgEarth::MapNode::findMapNode(sceneNode->node()); - if (mapNode) { - intoTerrain = clampGeoPoint(geoPoint, 0.5f, mapNode); - } else { - qWarning() << "OSGCamera::updateNode - scene data does not contain a map node"; - } - } + // install log depth buffer if requested + if (logDepthBufferEnabled && !logDepthBuffer) { + qDebug() << "OSGCamera::updateLogDepthBuffer - installing logarithmic depth buffer"; + logDepthBuffer = new osgEarth::Util::LogarithmicDepthBuffer(); + logDepthBuffer->setUseFragDepth(true); + logDepthBuffer->install(camera); + } else if (!logDepthBufferEnabled && logDepthBuffer) { + qDebug() << "OSGCamera::updateLogDepthBuffer - uninstalling logarithmic depth buffer"; + logDepthBuffer->uninstall(camera); + delete logDepthBuffer; + logDepthBuffer = NULL; + } +#endif + } + + void setGraphicsContext(osg::GraphicsContext *gc) + { + if (!camera.valid()) { + qDebug() << "OSGCamera::setGraphicsContext - invalid camera"; + return; } - geoPoint.createLocalToWorld(cameraPosition); -#endif + qDebug() << "OSGCamera::setGraphicsContext" << gc; - // Camera orientation - // By default the camera looks toward -Z, we must rotate it so it looks toward Y - osg::Matrix cameraRotation; - cameraRotation.makeRotate(osg::DegreesToRadians(90.0), osg::Vec3(1.0, 0.0, 0.0), - osg::DegreesToRadians(0.0), osg::Vec3(0.0, 1.0, 0.0), - osg::DegreesToRadians(0.0), osg::Vec3(0.0, 0.0, 1.0)); + camera->setGraphicsContext(gc); + camera->setViewport(0, 0, gc->getTraits()->width, gc->getTraits()->height); - // Final camera matrix - double roll = osg::DegreesToRadians(attitude.x()); - double pitch = osg::DegreesToRadians(attitude.y()); - double yaw = osg::DegreesToRadians(attitude.z()); - osg::Matrix cameraMatrix = cameraRotation - * osg::Matrix::rotate(roll, osg::Vec3(0, 1, 0)) - * osg::Matrix::rotate(pitch, osg::Vec3(1, 0, 0)) - * osg::Matrix::rotate(yaw, osg::Vec3(0, 0, -1)) * cameraPosition; + double aspectRatio = static_cast(gc->getTraits()->width) / static_cast(gc->getTraits()->height); - // Inverse the camera's position and orientation matrix to obtain the view matrix - cameraMatrix = osg::Matrix::inverse(cameraMatrix); - camera->setViewMatrix(cameraMatrix); - } + camera->setProjectionMatrixAsPerspective(fieldOfView, aspectRatio, 1.0f, 10000.0f); -private slots: - void onSceneNodeChanged(osg::Node *node) - { - qDebug() << "OSGCamera::onSceneNodeChanged" << node; - qWarning() << "OSGCamera::onSceneNodeChanged - needs to be implemented"; - } + double fovy, ar, zn, zf; + camera->getProjectionMatrixAsPerspective(fovy, ar, zn, zf); - void onTrackNodeChanged(osg::Node *node) - { - qDebug() << "OSGCamera::onTrackNodeChanged" << node; - qWarning() << "OSGCamera::onTrackNodeChanged - needs to be implemented"; + // FIXME this is needed for PFD + Terrain (because of "user" mode) + // updatePosition(); } }; /* class OSGCamera */ -enum DirtyFlag { FieldOfView = 1 << 0, Position = 1 << 1, Attitude = 1 << 2 }; - OSGCamera::OSGCamera(QObject *parent) : OSGNode(parent), h(new Hidden(this)) -{ - qDebug() << "OSGCamera::OSGCamera"; -} +{} OSGCamera::~OSGCamera() { @@ -383,15 +201,16 @@ OSGCamera::~OSGCamera() delete h; } -OSGNode *OSGCamera::sceneNode() const +QColor OSGCamera::clearColor() const { - return h->sceneNode; + return h->clearColor; } -void OSGCamera::setSceneNode(OSGNode *node) +void OSGCamera::setClearColor(const QColor &color) { - if (h->acceptSceneNode(node)) { - emit sceneNodeChanged(node); + if (h->clearColor != color) { + h->clearColor = color; + emit clearColorChanged(color); } } @@ -409,89 +228,6 @@ void OSGCamera::setFieldOfView(qreal arg) } } -ManipulatorMode::Enum OSGCamera::manipulatorMode() const -{ - return h->manipulatorMode; -} - -void OSGCamera::setManipulatorMode(ManipulatorMode::Enum mode) -{ - if (h->acceptManipulatorMode(mode)) { - emit manipulatorModeChanged(manipulatorMode()); - } -} - -OSGNode *OSGCamera::trackNode() const -{ - return h->trackNode; -} - -void OSGCamera::setTrackNode(OSGNode *node) -{ - if (h->acceptTrackNode(node)) { - emit trackNodeChanged(node); - } -} - -TrackerMode::Enum OSGCamera::trackerMode() const -{ - return h->trackerMode; -} - -void OSGCamera::setTrackerMode(TrackerMode::Enum mode) -{ - if (h->trackerMode != mode) { - h->trackerMode = mode; - emit trackerModeChanged(trackerMode()); - } -} - -bool OSGCamera::clampToTerrain() const -{ - return h->clampToTerrain; -} - -void OSGCamera::setClampToTerrain(bool arg) -{ - if (h->clampToTerrain != arg) { - h->clampToTerrain = arg; - emit clampToTerrainChanged(clampToTerrain()); - } -} - -bool OSGCamera::intoTerrain() const -{ - return h->intoTerrain; -} - -QVector3D OSGCamera::attitude() const -{ - return h->attitude; -} - -void OSGCamera::setAttitude(QVector3D arg) -{ - if (h->attitude != arg) { - h->attitude = arg; - setDirty(Attitude); - emit attitudeChanged(attitude()); - } -} - -QVector3D OSGCamera::position() const -{ - return h->position; -} - -void OSGCamera::setPosition(QVector3D arg) -{ - if (h->position != arg) { - h->position = arg; - setDirty(Position); - emit positionChanged(position()); - } -} - bool OSGCamera::logarithmicDepthBuffer() const { return h->logDepthBufferEnabled; @@ -501,33 +237,34 @@ void OSGCamera::setLogarithmicDepthBuffer(bool enabled) { if (h->logDepthBufferEnabled != enabled) { h->logDepthBufferEnabled = enabled; + setDirty(LogDepthBuffer); emit logarithmicDepthBufferChanged(logarithmicDepthBuffer()); } } +osg::Camera *OSGCamera::asCamera() const +{ + // BAD introduce templating + return (osg::Camera *)node(); +} + +void OSGCamera::setGraphicsContext(osg::GraphicsContext *gc) +{ + h->setGraphicsContext(gc); +} + void OSGCamera::update() { + if (isDirty(ClearColor)) { + h->updateClearColor(); + } if (isDirty(FieldOfView)) { h->updateFieldOfView(); } - if (isDirty(Position | Attitude)) { - h->updatePosition(); + if (isDirty(LogDepthBuffer)) { + h->updateLogDepthBuffer(); } } - -void OSGCamera::attach(osgViewer::View *view) -{ - h->attachCamera(view->getCamera()); - h->attachManipulator(view); - update(); - clearDirty(); -} - -void OSGCamera::detach(osgViewer::View *view) -{ - h->detachManipulator(view); - h->detachCamera(view->getCamera()); -} } // namespace osgQtQuick #include "OSGCamera.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.hpp index a5b1d5493..5db7a715d 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.hpp @@ -32,47 +32,17 @@ #include "OSGNode.hpp" #include -#include +#include -namespace osgViewer { -class View; +namespace osg { +class Camera; +class GraphicsContext; } namespace osgQtQuick { -class ManipulatorMode : public QObject { - Q_OBJECT -public: - enum Enum { Default, Earth, Track, User }; - Q_ENUMS(Enum) // TODO switch to Q_ENUM once on Qt 5.5 -}; - -class TrackerMode : public QObject { - Q_OBJECT -public: - enum Enum { NodeCenter, NodeCenterAndAzim, NodeCenterAndRotation }; - Q_ENUMS(Enum) // TODO switch to Q_ENUM once on Qt 5.5 -}; - -// This class does too much: -// - tracking a geo point and attitude -// - tracking another node -// camera should be simpler and provide only tracking -// - tracking of a modelnode (for ModelView) -// - tracking of a virtual node (for PFD with Terrain) -// -// TODO -// - expose track mode -// - provide good default distance and attitude for tracker camera class OSGQTQUICK_EXPORT OSGCamera : public OSGNode { - Q_OBJECT Q_PROPERTY(osgQtQuick::OSGNode *sceneNode READ sceneNode WRITE setSceneNode NOTIFY sceneNodeChanged) + Q_OBJECT Q_PROPERTY(QColor clearColor READ clearColor WRITE setClearColor NOTIFY clearColorChanged) Q_PROPERTY(qreal fieldOfView READ fieldOfView WRITE setFieldOfView NOTIFY fieldOfViewChanged) - Q_PROPERTY(osgQtQuick::ManipulatorMode::Enum manipulatorMode READ manipulatorMode WRITE setManipulatorMode NOTIFY manipulatorModeChanged) - Q_PROPERTY(osgQtQuick::OSGNode * trackNode READ trackNode WRITE setTrackNode NOTIFY trackNodeChanged) - Q_PROPERTY(osgQtQuick::TrackerMode::Enum trackerMode READ trackerMode WRITE setTrackerMode NOTIFY trackerModeChanged) - Q_PROPERTY(bool clampToTerrain READ clampToTerrain WRITE setClampToTerrain NOTIFY clampToTerrainChanged) - Q_PROPERTY(bool intoTerrain READ intoTerrain NOTIFY intoTerrainChanged) - Q_PROPERTY(QVector3D attitude READ attitude WRITE setAttitude NOTIFY attitudeChanged) - Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged) Q_PROPERTY(bool logarithmicDepthBuffer READ logarithmicDepthBuffer WRITE setLogarithmicDepthBuffer NOTIFY logarithmicDepthBufferChanged) friend class OSGViewport; @@ -81,65 +51,28 @@ public: explicit OSGCamera(QObject *parent = 0); virtual ~OSGCamera(); - OSGNode *sceneNode() const; - void setSceneNode(OSGNode *node); + QColor clearColor() const; + void setClearColor(const QColor &color); - // fov depends on the scenery space (probaby distance) - // here are some value: 75°, 60°, 45° many gamers use - // x-plane uses 45° for 4:3 and 60° for 16:9/16:10 - // flightgear uses 55° / 70° qreal fieldOfView() const; void setFieldOfView(qreal arg); - ManipulatorMode::Enum manipulatorMode() const; - void setManipulatorMode(ManipulatorMode::Enum); - - OSGNode *trackNode() const; - void setTrackNode(OSGNode *node); - - TrackerMode::Enum trackerMode() const; - void setTrackerMode(TrackerMode::Enum); - - bool clampToTerrain() const; - void setClampToTerrain(bool arg); - - bool intoTerrain() const; - - QVector3D attitude() const; - void setAttitude(QVector3D arg); - - QVector3D position() const; - void setPosition(QVector3D arg); - bool logarithmicDepthBuffer() const; void setLogarithmicDepthBuffer(bool enabled); signals: - void sceneNodeChanged(OSGNode *node); - + void clearColorChanged(const QColor &color); void fieldOfViewChanged(qreal arg); - - void manipulatorModeChanged(ManipulatorMode::Enum); - - void trackNodeChanged(OSGNode *node); - void trackerModeChanged(TrackerMode::Enum); - - void clampToTerrainChanged(bool arg); - void intoTerrainChanged(bool arg); - - void attitudeChanged(QVector3D arg); - void positionChanged(QVector3D arg); - void logarithmicDepthBufferChanged(bool enabled); private: struct Hidden; Hidden *const h; - virtual void update(); + osg::Camera *asCamera() const; + void setGraphicsContext(osg::GraphicsContext *gc); - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); + virtual void update(); }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGFileNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGFileNode.cpp index a9ba9dba2..218f09898 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGFileNode.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGFileNode.cpp @@ -37,11 +37,14 @@ #include namespace osgQtQuick { +enum DirtyFlag { Source = 1 << 0, Async = 1 << 1, OptimizeMode = 1 << 2 }; + class OSGFileLoader : public QThread { Q_OBJECT public: - OSGFileLoader(const QUrl &url) : url(url) {} + OSGFileLoader(const QUrl &url) : url(url) + {} void run() { @@ -54,9 +57,12 @@ public: QElapsedTimer t; t.start(); - qDebug() << "OSGFileLoader::load - reading node file" << url.path(); + // qDebug() << "OSGFileLoader::load - reading node file" << url.path(); // qDebug() << "OSGFileLoader - load - currentContext" << QOpenGLContext::currentContext(); osg::Node *node = osgDB::readNodeFile(url.path().toStdString()); + if (!node) { + qWarning() << "OSGFileLoader::load - failed to load" << url.path(); + } // qDebug() << "OSGFileLoader::load - reading node" << node << "took" << t.elapsed() << "ms"; return node; } @@ -79,11 +85,12 @@ public: bool async; OptimizeMode::Enum optimizeMode; - Hidden(OSGFileNode *node) : QObject(node), self(node), source(), async(false), optimizeMode(OptimizeMode::None) {} + Hidden(OSGFileNode *self) : QObject(self), self(self), source(), async(false), optimizeMode(OptimizeMode::None) + {} void updateNode() { - // qDebug() << "OSGFileNode::updateNode" << source; + qDebug() << "OSGFileNode::updateNode" << source; if (!source.isValid()) { self->setNode(NULL); if (!source.isEmpty()) { @@ -118,7 +125,7 @@ private: void setNode(osg::Node *node) { - qDebug() << "OSGFileNode::setNode" << node; + // qDebug() << "OSGFileNode::setNode" << node; if (node && optimizeMode != OptimizeMode::None) { // qDebug() << "OSGFileNode::acceptNode - optimize" << node << optimizeMode; osgUtil::Optimizer optimizer; @@ -139,18 +146,12 @@ private slots: /* class OSGFileNode */ -enum DirtyFlag { Source = 1 << 0, Async = 1 << 1, OptimizeMode = 1 << 2 }; - OSGFileNode::OSGFileNode(QObject *parent) : OSGNode(parent), h(new Hidden(this)) -{ - qDebug() << "OSGFileNode::OSGFileNode"; - setAsync(false); - setOptimizeMode(OptimizeMode::None); -} +{} OSGFileNode::~OSGFileNode() { - // qDebug() << "OSGFileNode::~OSGFileNode"; + qDebug() << "OSGFileNode::~OSGFileNode"; delete h; } @@ -161,7 +162,6 @@ const QUrl OSGFileNode::source() const void OSGFileNode::setSource(const QUrl &source) { - qDebug() << "OSGFileNode::setSource" << source; if (h->source != source) { h->source = source; setDirty(Source); @@ -176,7 +176,6 @@ bool OSGFileNode::async() const void OSGFileNode::setAsync(const bool async) { - // qDebug() << "OSGFileNode::setAsync" << async; if (h->async != async) { h->async = async; setDirty(Async); @@ -191,7 +190,6 @@ OptimizeMode::Enum OSGFileNode::optimizeMode() const void OSGFileNode::setOptimizeMode(OptimizeMode::Enum optimizeMode) { - // qDebug() << "OSGFileNode::setOptimizeMode" << optimizeMode; if (h->optimizeMode != optimizeMode) { h->optimizeMode = optimizeMode; setDirty(OptimizeMode); @@ -211,15 +209,6 @@ void OSGFileNode::update() h->updateNode(); } } - -void OSGFileNode::attach(osgViewer::View *view) -{ - update(); - clearDirty(); -} - -void OSGFileNode::detach(osgViewer::View *view) -{} } // namespace osgQtQuick #include "OSGFileNode.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGFileNode.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGFileNode.hpp index fcd639a43..b269f0869 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGFileNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGFileNode.hpp @@ -72,9 +72,6 @@ private: Hidden *const h; virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGeoTransformNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGeoTransformNode.cpp index 3171d2894..8ff0f73aa 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGeoTransformNode.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGeoTransformNode.cpp @@ -38,6 +38,8 @@ #include namespace osgQtQuick { +enum DirtyFlag { Child = 1 << 0, Scene = 1 << 1, Position = 1 << 2, Clamp = 1 << 3 }; + struct OSGGeoTransformNode::Hidden : public QObject { Q_OBJECT @@ -57,7 +59,7 @@ public: QVector3D position; - Hidden(OSGGeoTransformNode *node) : QObject(node), self(node), childNode(NULL), sceneNode(NULL), offset(-1.0), clampToTerrain(false), intoTerrain(false) + Hidden(OSGGeoTransformNode *self) : QObject(self), self(self), childNode(NULL), sceneNode(NULL), offset(-1.0), clampToTerrain(false), intoTerrain(false) { transform = new osgEarth::GeoTransform(); transform->setAutoRecomputeHeights(true); @@ -104,10 +106,10 @@ public: return true; } - void updateTransformNode() + void updateChildNode() { + qDebug() << "OSGGeoTransformNode::updateChildNode" << childNode; bool updated = false; - if (transform->getNumChildren() == 0) { if (childNode && childNode->node()) { updated |= transform->addChild(childNode->node()); @@ -129,6 +131,7 @@ public: void updateSceneNode() { + qDebug() << "OSGGeoTransformNode::updateSceneNode" << sceneNode; if (sceneNode && sceneNode->node()) { osgEarth::MapNode *mapNode = osgEarth::MapNode::findMapNode(sceneNode->node()); if (mapNode) { @@ -141,15 +144,19 @@ public: void updatePosition() { - osgEarth::MapNode *mapNode = NULL; + qDebug() << "OSGGeoTransformNode::updatePosition" << position; + osgEarth::MapNode *mapNode = NULL; if (sceneNode && sceneNode->node()) { mapNode = osgEarth::MapNode::findMapNode(sceneNode->node()); - } - if (!mapNode) { - qWarning() << "OSGGeoTransformNode::updatePosition - scene node does not contain a map node"; + if (!mapNode) { + qWarning() << "OSGGeoTransformNode::updatePosition - scene node does not contain a map node"; + } + } else { + qWarning() << "OSGGeoTransformNode::updatePosition - scene node is not valid"; } + // TODO factorize this logic to utility (same logic is found elsewhere) osgEarth::GeoPoint geoPoint; if (mapNode) { geoPoint = osgQtQuick::toGeoPoint(mapNode->getTerrain()->getSRS(), position); @@ -168,7 +175,10 @@ public: // clamp model to terrain if needed intoTerrain = clampGeoPoint(geoPoint, offset, mapNode); + } else if (clampToTerrain) { + qWarning() << "OSGGeoTransformNode::onChildNodeChanged - cannot clamp without map node"; } + transform->setPosition(geoPoint); } @@ -176,28 +186,25 @@ private slots: void onChildNodeChanged(osg::Node *node) { qDebug() << "OSGGeoTransformNode::onChildNodeChanged" << node; - updateTransformNode(); + updateChildNode(); } void onSceneNodeChanged(osg::Node *node) { qDebug() << "OSGGeoTransformNode::onSceneNodeChanged" << node; - // TODO + updateSceneNode(); + updatePosition(); } }; /* class OSGGeoTransformNode */ -enum DirtyFlag { Child = 1 << 0, Scene = 1 << 1, Position = 1 << 2, Clamp = 1 << 3 }; - OSGGeoTransformNode::OSGGeoTransformNode(QObject *parent) : OSGNode(parent), h(new Hidden(this)) -{ - qDebug() << "OSGGeoTransformNode::OSGGeoTransformNode"; -} +{} OSGGeoTransformNode::~OSGGeoTransformNode() { - // qDebug() << "OSGGeoTransformNode::~OSGGeoTransformNode"; + qDebug() << "OSGGeoTransformNode::~OSGGeoTransformNode"; delete h; } @@ -263,29 +270,18 @@ void OSGGeoTransformNode::setPosition(QVector3D arg) void OSGGeoTransformNode::update() { if (isDirty(Child)) { - h->updateTransformNode(); + h->updateChildNode(); } if (isDirty(Scene)) { h->updateSceneNode(); } - if (isDirty(Clamp)) {} + if (isDirty(Clamp)) { + // do nothing... + } if (isDirty(Position)) { h->updatePosition(); } } - -void OSGGeoTransformNode::attach(osgViewer::View *view) -{ - OSGNode::attach(h->childNode, view); - - update(); - clearDirty(); -} - -void OSGGeoTransformNode::detach(osgViewer::View *view) -{ - OSGNode::detach(h->childNode, view); -} } // namespace osgQtQuick #include "OSGGeoTransformNode.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGeoTransformNode.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGeoTransformNode.hpp index 67726fe63..22963b5b0 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGeoTransformNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGeoTransformNode.hpp @@ -37,9 +37,9 @@ namespace osgQtQuick { class OSGQTQUICK_EXPORT OSGGeoTransformNode : public OSGNode { Q_OBJECT - // TODO rename to childNode - Q_PROPERTY(osgQtQuick::OSGNode *modelData READ childNode WRITE setChildNode NOTIFY childNodeChanged) // TODO rename to sceneNode + Q_PROPERTY(osgQtQuick::OSGNode *modelData READ childNode WRITE setChildNode NOTIFY childNodeChanged) + // TODO rename to earthNode Q_PROPERTY(osgQtQuick::OSGNode * sceneData READ sceneNode WRITE setSceneNode NOTIFY sceneNodeChanged) Q_PROPERTY(bool clampToTerrain READ clampToTerrain WRITE setClampToTerrain NOTIFY clampToTerrainChanged) @@ -80,9 +80,6 @@ private: Hidden *const h; virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.cpp index cee785f31..d74a3a9c4 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.cpp @@ -46,14 +46,14 @@ private: QMap cache; public: - Hidden(OSGGroup *node) : QObject(node), self(node), group(new osg::Group) + QList children; + + Hidden(OSGGroup *self) : QObject(self), self(self) { group = new osg::Group(); self->setNode(group); } - QList children; - void appendChild(OSGNode *childNode) { cache[childNode] = childNode->node(); @@ -88,6 +88,7 @@ public: void updateGroupNode() { + qDebug() << "OSGGeoTransformNode::updateGroupNode"; bool updated = false; unsigned int index = 0; @@ -161,13 +162,11 @@ private slots: /* class OSGGGroupNode */ OSGGroup::OSGGroup(QObject *parent) : OSGNode(parent), h(new Hidden(this)) -{ - qDebug() << "OSGGroup::OSGGroup"; -} +{} OSGGroup::~OSGGroup() { - // qDebug() << "OSGGroup::~OSGGroup"; + qDebug() << "OSGGroup::~OSGGroup"; delete h; } @@ -186,30 +185,6 @@ void OSGGroup::update() h->updateGroupNode(); } } - -void OSGGroup::attach(osgViewer::View *view) -{ - // qDebug() << "OSGGroup::attach " << view; - QListIterator i(h->children); - while (i.hasNext()) { - OSGNode *node = i.next(); - // qDebug() << "OSGGroup::attach - child" << node; - OSGNode::attach(node, view); - } - update(); - clearDirty(); -} - -void OSGGroup::detach(osgViewer::View *view) -{ - // qDebug() << "OSGGroup::detach " << view; - QListIterator i(h->children); - while (i.hasNext()) { - OSGNode *node = i.next(); - // qDebug() << "OSGGroup::detach - child" << node; - OSGNode::detach(node, view); - } -} } // namespace osgQtQuick #include "OSGGroup.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.hpp index 35f43f01e..be115edb5 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.hpp @@ -50,9 +50,6 @@ private: Hidden *const h; virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGNode.cpp index 8c1660249..018ed7613 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGNode.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGNode.cpp @@ -36,9 +36,10 @@ namespace osgQtQuick { class OSGNode; class Hidden; -struct NodeUpdateCallback : public osg::NodeCallback { +struct OSGNode::NodeUpdateCallback : public osg::NodeCallback { public: - NodeUpdateCallback(OSGNode::Hidden *h) : h(h) {} + NodeUpdateCallback(OSGNode::Hidden *h) : h(h) + {} void operator()(osg::Node *node, osg::NodeVisitor *nv); @@ -58,53 +59,46 @@ private: osg::ref_ptr nodeUpdateCallback; - int dirty; + bool complete; + int dirty; public: - Hidden(OSGNode *node) : QObject(node), self(node), dirty(0) + Hidden(OSGNode *self) : QObject(self), self(self), complete(false), dirty(0) {} bool isDirty(int mask) const { - return (dirty && mask) != 0; + return (dirty & mask) != 0; } void setDirty(int mask) { - // qDebug() << "OSGNode::setDirty BEGIN"; if (!dirty) { if (node) { if (!nodeUpdateCallback.valid()) { // lazy creation - // qDebug() << "OSGNode::setDirty CREATE"; nodeUpdateCallback = new NodeUpdateCallback(this); } - // qDebug() << "OSGNode::setDirty ADD" << node; - node->setUpdateCallback(nodeUpdateCallback); + node->addUpdateCallback(nodeUpdateCallback.get()); } } dirty |= mask; - // qDebug() << "OSGNode::setDirty DONE"; } void clearDirty() { - dirty = 0; if (node && nodeUpdateCallback.valid()) { - // qDebug() << "OSGNode::clearDirty REMOVE CALLBACK"; - node->setUpdateCallback(NULL); + node->removeUpdateCallback(nodeUpdateCallback.get()); } + dirty = 0; } void update() { - // qDebug() << "OSGNode::update BEGIN"; if (dirty) { - // qDebug() << "OSGNode::update UPDATE"; self->update(); } clearDirty(); - // qDebug() << "OSGNode::update DONE"; } bool acceptNode(osg::Node *aNode) @@ -113,7 +107,6 @@ public: return false; } if (node && dirty) { - // qDebug() << "OSGNode::acceptNode REMOVE CALLBACK" << node; node->setUpdateCallback(NULL); } node = aNode; @@ -121,10 +114,8 @@ public: if (dirty) { if (!nodeUpdateCallback.valid()) { // lazy creation - // qDebug() << "OSGNode::acceptNode CREATE CALLBACK"; nodeUpdateCallback = new NodeUpdateCallback(this); } - // qDebug() << "OSGNode::acceptNode ADD CALLBACK"; node->setUpdateCallback(nodeUpdateCallback); } } @@ -132,14 +123,18 @@ public: } }; -void NodeUpdateCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) +/* struct OSGNode::NodeUpdateCallback */ + +void OSGNode::NodeUpdateCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) { - // qDebug() << "NodeUpdateCallback::"; + // qDebug() << "OSGNode::NodeUpdateCallback"; nv->traverse(*node); h->update(); } -OSGNode::OSGNode(QObject *parent) : QObject(parent), h(new Hidden(this)) +/* class OSGNode */ + +OSGNode::OSGNode(QObject *parent) : QObject(parent), QQmlParserStatus(), h(new Hidden(this)) {} OSGNode::~OSGNode() @@ -155,7 +150,7 @@ osg::Node *OSGNode::node() const void OSGNode::setNode(osg::Node *node) { if (h->acceptNode(node)) { - emit nodeChanged(node); + emitNodeChanged(); } } @@ -179,30 +174,37 @@ void OSGNode::clearDirty() h->clearDirty(); } -void OSGNode::attach(OSGNode *node, osgViewer::View *view) +void OSGNode::classBegin() { - if (!node) { - return; - } - node->attach(view); + // qDebug() << "OSGNode::classBegin" << this; } -void OSGNode::detach(OSGNode *node, osgViewer::View *view) +void OSGNode::componentComplete() { - if (!node) { - return; + qDebug() << "OSGNode::componentComplete" << this; + update(); + clearDirty(); + h->complete = h->node.valid(); + if (!isComponentComplete()) { + qWarning() << "OSGNode::componentComplete - not complete !!!" << this; + } +} + +bool OSGNode::isComponentComplete() +{ + return h->complete; +} + + +void OSGNode::emitNodeChanged() +{ + if (isComponentComplete()) { + emit nodeChanged(node()); } - node->detach(view); } void OSGNode::update() {} - -void OSGNode::attach(osgViewer::View *view) -{} - -void OSGNode::detach(osgViewer::View *view) -{} } // namespace osgQtQuick #include "OSGNode.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGNode.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGNode.hpp index 9e2898ad8..1f1764362 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGNode.hpp @@ -31,6 +31,7 @@ #include "Export.hpp" #include +#include /** * Only update() methods are allowed to update the OSG scenegraph. @@ -44,17 +45,15 @@ * - if a child sets a parent dirty, the parent will be updated later on the next update traversal (i.e. before the next frame). * */ + namespace osg { class Node; } // namespace osg -namespace osgViewer { -class View; -} // namespace osgViewer - namespace osgQtQuick { -class OSGQTQUICK_EXPORT OSGNode : public QObject { +class OSGQTQUICK_EXPORT OSGNode : public QObject, public QQmlParserStatus { Q_OBJECT + Q_INTERFACES(QQmlParserStatus) friend class OSGViewport; friend class NodeUpdateCallback; @@ -72,24 +71,21 @@ protected: void setDirty(int mask); void clearDirty(); - void emitNodeChanged() - { - emit nodeChanged(node()); - } + void classBegin(); + void componentComplete(); - void attach(OSGNode *node, osgViewer::View *view); - void detach(OSGNode *node, osgViewer::View *view); + bool isComponentComplete(); + + void emitNodeChanged(); signals: void nodeChanged(osg::Node *node) const; private: struct Hidden; + struct NodeUpdateCallback; Hidden *const h; - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); - virtual void update(); }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGShapeNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGShapeNode.cpp index ae215e4ec..a0cff9da5 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGShapeNode.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGShapeNode.cpp @@ -37,6 +37,8 @@ #include namespace osgQtQuick { +enum DirtyFlag { Type = 1 << 0 }; + struct OSGShapeNode::Hidden : public QObject { Q_OBJECT @@ -46,7 +48,7 @@ private: public: ShapeType::Enum shapeType; - Hidden(OSGShapeNode *node) : QObject(node), self(node), shapeType(ShapeType::Sphere) + Hidden(OSGShapeNode *self) : QObject(self), self(self), shapeType(ShapeType::Sphere) {} void updateNode() @@ -74,19 +76,16 @@ public: /* class OSGShapeNode */ -enum DirtyFlag { Type = 1 << 0 }; - // TODO turn into generic shape node... // see http://trac.openscenegraph.org/projects/osg//wiki/Support/Tutorials/TransformsAndStates OSGShapeNode::OSGShapeNode(QObject *parent) : OSGNode(parent), h(new Hidden(this)) { - qDebug() << "OSGShapeNode::OSGShapeNode"; - setShapeType(ShapeType::Sphere); + setDirty(Type); } OSGShapeNode::~OSGShapeNode() { - // qDebug() << "OSGShapeNode::~OSGShapeNode"; + qDebug() << "OSGShapeNode::~OSGShapeNode"; delete h; } @@ -110,15 +109,6 @@ void OSGShapeNode::update() h->updateNode(); } } - -void OSGShapeNode::attach(osgViewer::View *view) -{ - update(); - clearDirty(); -} - -void OSGShapeNode::detach(osgViewer::View *view) -{} } // namespace osgQtQuick #include "OSGShapeNode.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGShapeNode.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGShapeNode.hpp index 90a57ac64..d11f069b3 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGShapeNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGShapeNode.hpp @@ -57,9 +57,6 @@ private: Hidden *const h; virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGSkyNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGSkyNode.cpp index c520c5472..75f46d688 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGSkyNode.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGSkyNode.cpp @@ -27,6 +27,8 @@ #include "OSGSkyNode.hpp" +#include "OSGViewport.hpp" + #include #include @@ -39,6 +41,8 @@ #include namespace osgQtQuick { +enum DirtyFlag { Scene = 1 << 0, Viewport = 1 << 1, DateTime = 1 << 2, Light = 1 << 3 }; + struct OSGSkyNode::Hidden : public QObject { Q_OBJECT @@ -48,13 +52,15 @@ private: osg::ref_ptr skyNode; public: - OSGNode *sceneNode; + OSGNode *sceneNode; + OSGViewport *viewport; - bool sunLightEnabled; - QDateTime dateTime; - double minimumAmbientLight; + bool sunLightEnabled; + QDateTime dateTime; + double minimumAmbientLight; - Hidden(OSGSkyNode *node) : QObject(node), self(node), sceneNode(NULL), sunLightEnabled(true), minimumAmbientLight(0.03) + Hidden(OSGSkyNode *self) : QObject(self), self(self), sceneNode(NULL), viewport(NULL), + sunLightEnabled(true), minimumAmbientLight(0.03) { dateTime = QDateTime::currentDateTime(); } @@ -85,18 +91,19 @@ public: void updateSkyNode() { if (!sceneNode || !sceneNode->node()) { - qWarning() << "OSGSkyNode::acceptNode - scene node not valid"; + qWarning() << "OSGSkyNode::updateSkyNode - scene node not valid"; self->setNode(NULL); return; } + qDebug() << "OSGSkyNode::updateSkyNode - scene node" << sceneNode->node(); osgEarth::MapNode *mapNode = osgEarth::MapNode::findMapNode(sceneNode->node()); if (!mapNode) { - qWarning() << "OSGSkyNode::acceptNode - scene node does not contain a map node"; + qWarning() << "OSGSkyNode::updateSkyNode - scene node does not contain a map node"; self->setNode(NULL); return; } if (!mapNode->getMap()->isGeocentric()) { - qWarning() << "OSGSkyNode::acceptNode - map node is not geocentric"; + qWarning() << "OSGSkyNode::updateSkyNode - map node is not geocentric"; self->setNode(NULL); return; } @@ -142,8 +149,23 @@ public: } */ + void updateViewport() + { + qDebug() << "OSGSkyNode::updateViewport" << skyNode; + if (!skyNode.valid()) { + qWarning() << "OSGSkyNode::updateViewport - invalid sky node" << skyNode; + return; + } + qDebug() << "OSGSkyNode::updateViewport - attaching to" << viewport->asView(); + skyNode->attach(viewport->asView()); + } + void updateSunLightEnabled() { + if (!skyNode.valid()) { + qWarning() << "OSGSkyNode::updateSunLightEnabled - invalid sky node"; + return; + } if (!skyNode.valid()) { return; } @@ -153,10 +175,11 @@ public: void updateDateTime() { if (!skyNode.valid()) { + qWarning() << "OSGSkyNode::updateDateTime - invalid sky node"; return; } if (!dateTime.isValid()) { - qWarning() << "OSGSkyNode::acceptDateTime - invalid date/time" << dateTime; + qWarning() << "OSGSkyNode::updateDateTime - invalid date/time" << dateTime; } QDate date = dateTime.date(); @@ -168,6 +191,7 @@ public: void updateMinimumAmbientLight() { if (!skyNode.valid()) { + qWarning() << "OSGSkyNode::updateMinimumAmbientLight - invalid sky node"; return; } double d = minimumAmbientLight; @@ -199,18 +223,14 @@ private slots: /* class OSGSkyNode */ -enum DirtyFlag { Child = 1 << 0, DateTime = 1 << 1, Light = 1 << 2 }; - OSGSkyNode::OSGSkyNode(QObject *parent) : OSGNode(parent), h(new Hidden(this)) { - qDebug() << "OSGSkyNode::OSGSkyNode"; - setSunLightEnabled(true); - setMinimumAmbientLight(0.03); + setDirty(DateTime | Light); } OSGSkyNode::~OSGSkyNode() { - // qDebug() << "OSGSkyNode::~OSGSkyNode"; + qDebug() << "OSGSkyNode::~OSGSkyNode"; delete h; } @@ -222,11 +242,25 @@ OSGNode *OSGSkyNode::sceneNode() const void OSGSkyNode::setSceneNode(OSGNode *node) { if (h->acceptSceneNode(node)) { - setDirty(Child); + setDirty(Scene); emit sceneNodeChanged(node); } } +OSGViewport *OSGSkyNode::viewport() const +{ + return h->viewport; +} + +void OSGSkyNode::setViewport(OSGViewport *viewport) +{ + if (h->viewport != viewport) { + h->viewport = viewport; + setDirty(Viewport); + emit viewportChanged(viewport); + } +} + bool OSGSkyNode::sunLightEnabled() const { return h->sunLightEnabled; @@ -271,9 +305,12 @@ void OSGSkyNode::setMinimumAmbientLight(double ambient) void OSGSkyNode::update() { - if (isDirty(Child)) { + if (isDirty(Scene)) { h->updateSkyNode(); } + if (isDirty(Viewport)) { + h->updateViewport(); + } if (isDirty(Light)) { h->updateSunLightEnabled(); h->updateMinimumAmbientLight(); @@ -282,23 +319,6 @@ void OSGSkyNode::update() h->updateDateTime(); } } - -void OSGSkyNode::attach(osgViewer::View *view) -{ - // qDebug() << "OSGSkyNode::attach " << view; - OSGNode::attach(h->sceneNode, view); - - h->attachSkyNode(view); - update(); - clearDirty(); -} - -void OSGSkyNode::detach(osgViewer::View *view) -{ - // qDebug() << "OSGSkyNode::detach " << view; - h->detachSkyNode(view); - OSGNode::detach(h->sceneNode, view); -} } // namespace osgQtQuick #include "OSGSkyNode.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGSkyNode.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGSkyNode.hpp index 492c2d2ff..8ae64c7df 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGSkyNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGSkyNode.hpp @@ -43,9 +43,12 @@ class QUrl; QT_END_NAMESPACE namespace osgQtQuick { +class OSGViewport; + class OSGQTQUICK_EXPORT OSGSkyNode : public OSGNode { // TODO rename to sceneNode Q_OBJECT Q_PROPERTY(osgQtQuick::OSGNode *sceneData READ sceneNode WRITE setSceneNode NOTIFY sceneNodeChanged) + Q_PROPERTY(osgQtQuick::OSGViewport * viewport READ viewport WRITE setViewport NOTIFY viewportChanged) Q_PROPERTY(bool sunLightEnabled READ sunLightEnabled WRITE setSunLightEnabled NOTIFY sunLightEnabledChanged) Q_PROPERTY(QDateTime dateTime READ dateTime WRITE setDateTime NOTIFY dateTimeChanged) @@ -58,6 +61,9 @@ public: OSGNode *sceneNode() const; void setSceneNode(OSGNode *node); + OSGViewport *viewport() const; + void setViewport(OSGViewport *viewport); + bool sunLightEnabled() const; void setSunLightEnabled(bool arg); @@ -69,6 +75,7 @@ public: signals: void sceneNodeChanged(OSGNode *node); + void viewportChanged(OSGViewport *viewport); void sunLightEnabledChanged(bool arg); void dateTimeChanged(QDateTime arg); @@ -79,9 +86,6 @@ private: Hidden *const h; virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTextNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTextNode.cpp index 43fcaefd1..43e9a2924 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTextNode.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTextNode.cpp @@ -37,6 +37,8 @@ #include namespace osgQtQuick { +enum DirtyFlag { Text = 1 << 0, Color = 1 << 1 }; + struct OSGTextNode::Hidden : public QObject { Q_OBJECT @@ -49,7 +51,7 @@ public: QString textString; QColor color; - Hidden(OSGTextNode *node) : QObject(node), self(node) + Hidden(OSGTextNode *self) : QObject(self), self(self) { osg::ref_ptr textFont = createFont(QFont("Times")); @@ -88,10 +90,10 @@ public: /* class OSGTextNode */ -enum DirtyFlag { Text = 1 << 0, Color = 1 << 1 }; - -OSGTextNode::OSGTextNode(QObject *node) : OSGNode(node), h(new Hidden(this)) -{} +OSGTextNode::OSGTextNode(QObject *parent) : OSGNode(parent), h(new Hidden(this)) +{ + setDirty(Text | Color); +} OSGTextNode::~OSGTextNode() { @@ -135,15 +137,6 @@ void OSGTextNode::update() h->updateColor(); } } - -void OSGTextNode::attach(osgViewer::View *view) -{ - update(); - clearDirty(); -} - -void OSGTextNode::detach(osgViewer::View *view) -{} } // namespace osgQtQuick #include "OSGTextNode.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTextNode.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTextNode.hpp index 81379293d..21cc7d5d9 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTextNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTextNode.hpp @@ -57,9 +57,6 @@ private: Hidden *const h; virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTransformNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTransformNode.cpp index 67b9f3de0..c0cf7a8b9 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTransformNode.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTransformNode.cpp @@ -34,6 +34,8 @@ #include namespace osgQtQuick { +enum DirtyFlag { Child = 1 << 0, Scale = 1 << 1, Position = 1 << 2, Attitude = 1 << 3 }; + struct OSGTransformNode::Hidden : public QObject { Q_OBJECT @@ -49,7 +51,7 @@ public: QVector3D attitude; QVector3D position; - Hidden(OSGTransformNode *node) : QObject(node), self(node), childNode(NULL) + Hidden(OSGTransformNode *self) : QObject(self), self(self), childNode(NULL) { transform = new osg::PositionAttitudeTransform(); self->setNode(transform); @@ -75,10 +77,10 @@ public: return true; } - void updateTransformNode() + void updateChildNode() { + qDebug() << "OSGTransformNode::updateChildNode" << childNode; bool updated = false; - if (transform->getNumChildren() == 0) { if (childNode && childNode->node()) { updated |= transform->addChild(childNode->node()); @@ -100,6 +102,7 @@ public: void updateScale() { + qDebug() << "OSGTransformNode::updateScale" << scale; if ((scale.x() != 0.0) || (scale.y() != 0.0) || (scale.z() != 0.0)) { transform->setScale(osg::Vec3d(scale.x(), scale.y(), scale.z())); // transform->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); @@ -118,9 +121,6 @@ public: yaw, osg::Vec3d(0, 0, -1)); transform->setAttitude(q); - - // position - transform->setPosition(osg::Vec3d(position.x(), position.y(), position.z())); } void updatePosition() @@ -132,22 +132,18 @@ private slots: void onChildNodeChanged(osg::Node *node) { qDebug() << "OSGTransformNode::onChildNodeChanged" << node; - updateTransformNode(); + updateChildNode(); } }; /* class OSGTransformNode */ -enum DirtyFlag { Child = 1 << 0, Scale = 1 << 1, Position = 1 << 2, Attitude = 1 << 3 }; - OSGTransformNode::OSGTransformNode(QObject *parent) : OSGNode(parent), h(new Hidden(this)) -{ - qDebug() << "OSGTransformNode::OSGTransformNode"; -} +{} OSGTransformNode::~OSGTransformNode() { - // qDebug() << "OSGTransformNode::~OSGTransformNode"; + qDebug() << "OSGTransformNode::~OSGTransformNode"; delete h; } @@ -209,7 +205,7 @@ void OSGTransformNode::setPosition(QVector3D arg) void OSGTransformNode::update() { if (isDirty(Child)) { - h->updateTransformNode(); + h->updateChildNode(); } if (isDirty(Scale)) { h->updateScale(); @@ -221,19 +217,6 @@ void OSGTransformNode::update() h->updatePosition(); } } - -void OSGTransformNode::attach(osgViewer::View *view) -{ - OSGNode::attach(h->childNode, view); - - update(); - clearDirty(); -} - -void OSGTransformNode::detach(osgViewer::View *view) -{ - OSGNode::detach(h->childNode, view); -} } // namespace osgQtQuick #include "OSGTransformNode.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTransformNode.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTransformNode.hpp index 4f33bd81c..430269dec 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTransformNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTransformNode.hpp @@ -72,9 +72,6 @@ private: Hidden *const h; virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.cpp index f2bae73bd..1104105c5 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.cpp @@ -34,6 +34,7 @@ #include "OSGCamera.hpp" #include +#include #include #include #include @@ -41,10 +42,7 @@ #include #include #include - -#ifdef USE_OSGEARTH -#include -#endif +#include #include #include @@ -55,9 +53,6 @@ #include -#include -#include - /* Debugging tips - export OSG_NOTIFY_LEVEL=DEBUG @@ -80,6 +75,8 @@ */ namespace osgQtQuick { +enum DirtyFlag { Scene = 1 << 0, Camera = 1 << 1 }; + class ViewportRenderer; struct OSGViewport::Hidden : public QObject { @@ -94,27 +91,26 @@ private: int frameTimer; + osg::ref_ptr gc; + + public: OSGNode *sceneNode; - OSGCamera *camera; + OSGCamera *cameraNode; osg::ref_ptr viewer; osg::ref_ptr view; - UpdateMode::Enum updateMode; + OSGCameraManipulator *manipulator; + + UpdateMode::Enum updateMode; bool busy; static QtKeyboardMap keyMap; - Hidden(OSGViewport *viewport) : QObject(viewport), - self(viewport), - window(NULL), - frameTimer(-1), - sceneNode(NULL), - camera(NULL), - updateMode(UpdateMode::OnDemand), - busy(false) + Hidden(OSGViewport *self) : QObject(self), self(self), window(NULL), frameTimer(-1), + sceneNode(NULL), cameraNode(NULL), manipulator(NULL), updateMode(UpdateMode::OnDemand), busy(false) { OsgEarth::initialize(); @@ -125,7 +121,9 @@ public: ~Hidden() { - stop(); + disconnect(self); + + stopTimer(); destroyViewer(); } @@ -137,13 +135,16 @@ public slots: // osgQtQuick::openGLContextInfo(QOpenGLContext::currentContext(), "onWindowChanged"); if (window) { // window->setClearBeforeRendering(false); - connect(window, &QQuickWindow::sceneGraphInitialized, this, &Hidden::onSceneGraphInitialized, Qt::DirectConnection); - connect(window, &QQuickWindow::sceneGraphAboutToStop, this, &Hidden::onSceneGraphAboutToStop, Qt::DirectConnection); - connect(window, &QQuickWindow::sceneGraphInvalidated, this, &Hidden::onSceneGraphInvalidated, Qt::DirectConnection); +// connect(window, &QQuickWindow::sceneGraphInitialized, this, &Hidden::onSceneGraphInitialized, Qt::DirectConnection); +// connect(window, &QQuickWindow::sceneGraphAboutToStop, this, &Hidden::onSceneGraphAboutToStop, Qt::DirectConnection); +// connect(window, &QQuickWindow::sceneGraphInvalidated, this, &Hidden::onSceneGraphInvalidated, Qt::DirectConnection); +// connect(window, &QQuickWindow::visibleChanged, this, &Hidden::visibleChanged, Qt::DirectConnection); +// connect(window, &QQuickWindow::widthChanged, this, &Hidden::widthChanged, Qt::DirectConnection); +// connect(window, &QQuickWindow::heightChanged, this, &Hidden::heightChanged, Qt::DirectConnection); } else { - if (this->window) { - disconnect(this->window); - } +// if (this->window) { +// disconnect(this->window); +// } } this->window = window; } @@ -163,123 +164,99 @@ public: sceneNode = node; if (sceneNode) { - connect(sceneNode, &OSGNode::nodeChanged, this, &Hidden::onNodeChanged); + connect(sceneNode, &OSGNode::nodeChanged, this, &Hidden::onSceneNodeChanged); } return true; } - void attach(osgViewer::View *view) + bool acceptCameraNode(OSGCamera *node) { - if (!sceneNode) { - qWarning() << "OSGViewport::attach - invalid scene!"; - return; + qDebug() << "OSGViewport::acceptCameraNode" << node; + if (cameraNode == node) { + return true; } - // attach scene - attach(view, sceneNode->node()); - // attach camera - if (camera) { - camera->attach(view); - } else { - qWarning() << "OSGViewport::attach - no camera!"; + + if (cameraNode) { + disconnect(cameraNode); } + + cameraNode = node; + + if (cameraNode) { + connect(cameraNode, &OSGNode::nodeChanged, this, &Hidden::onCameraNodeChanged); + } + + return true; } - void attach(osgViewer::View *view, osg::Node *node) + bool acceptManipulator(OSGCameraManipulator *m) { - if (!view) { - qWarning() << "OSGViewport::attach - view is null"; - return; - } - if (!node) { - qWarning() << "OSGViewport::attach - node is null"; - view->setSceneData(NULL); - return; + qDebug() << "OSGViewport::acceptManipulator" << manipulator; + if (manipulator == m) { + return true; } -#ifdef USE_OSGEARTH - // TODO map handling should not be done here - osgEarth::MapNode *mapNode = osgEarth::MapNode::findMapNode(node); - if (mapNode) { - qDebug() << "OSGViewport::attach - found map node" << mapNode; + manipulator = m; - // remove light to prevent unnecessary state changes in SceneView - // scene will get light from sky (works only with latest > 2.7) - // view->setLightingMode(osg::View::NO_LIGHT); - } -#endif - - qDebug() << "OSGViewport::attach - set scene" << node; - view->setSceneData(node); - } - - void detach(osgViewer::View *view) - { - // detach camera - if (camera) { - camera->detach(view); - } - // detach scene - view->setSceneData(NULL); - } - - void onSceneGraphInitialized() - { - qDebug() << "OSGViewport::onSceneGraphInitialized"; - // osgQtQuick::openGLContextInfo(QOpenGLContext::currentContext(), "onSceneGraphInitialized"); - } - - void onSceneGraphAboutToStop() - { - qDebug() << "OSGViewport::onSceneGraphAboutToStop"; - // osgQtQuick::openGLContextInfo(QOpenGLContext::currentContext(), "onSceneGraphAboutToStop"); - } - - void onSceneGraphInvalidated() - { - qDebug() << "OSGViewport::onSceneGraphInvalidated"; - // osgQtQuick::openGLContextInfo(QOpenGLContext::currentContext(), "onSceneGraphInvalidated"); + return true; } void initializeResources() { - qDebug() << "OSGViewport::initializeResources"; - if (view.valid()) { - qWarning() << "OSGViewport::initializeResources - view already created!"; + if (gc.valid()) { + // qWarning() << "OSGViewport::initializeResources - gc already created!"; return; } - view = createView(); - viewer->addView(view); - self->attach(view.get()); - start(); + qDebug() << "OSGViewport::initializeResources"; + + // setup graphics context and camera + gc = createGraphicsContext(); + + cameraNode->setGraphicsContext(gc); + + qDebug() << "OSGViewport::initializeResources - camera" << cameraNode->asCamera(); + view->setCamera(cameraNode->asCamera()); + + qDebug() << "OSGViewport::initializeResources - scene data" << sceneNode->node(); + view->setSceneData(sceneNode->node()); + + if (manipulator) { + osgGA::CameraManipulator *m = manipulator->asCameraManipulator(); + qDebug() << "OSGViewport::initializeResources - manipulator" << m; + + // Setting the manipulator on the camera will change the manipulator node (used to compute the camera home position) + // to the view scene node. So we need to save and restore the manipulator node. + osg::Node *node = m->getNode(); + view->setCameraManipulator(m, false); + if (node) { + m->setNode(node); + } + + view->home(); + } else { + view->setCameraManipulator(NULL, false); + } + + installHanders(); + + startTimer(); } void releaseResources() { qDebug() << "OSGViewport::releaseResources"; - if (!view.valid()) { - qWarning() << "OSGViewport::releaseResources - view is not valid!"; + if (!gc.valid()) { + qWarning() << "OSGViewport::releaseResources - gc is not valid!"; return; } - osg::deleteAllGLObjects(view->getCamera()->getGraphicsContext()->getState()->getContextID()); + osg::deleteAllGLObjects(gc->getState()->getContextID()); // view->getSceneData()->releaseGLObjects(view->getCamera()->getGraphicsContext()->getState()); // view->getCamera()->releaseGLObjects(view->getCamera()->getGraphicsContext()->getState()); // view->getCamera()->getGraphicsContext()->close(); // view->getCamera()->setGraphicsContext(NULL); } - bool acceptCamera(OSGCamera *camera) - { - qDebug() << "OSGViewport::acceptCamera" << camera; - if (this->camera == camera) { - return true; - } - - this->camera = camera; - - return true; - } - private: void createViewer() { @@ -297,6 +274,9 @@ private: // disable the default setting of viewer.done() by pressing Escape. viewer->setKeyEventSetsDone(0); // viewer->setQuitEventSetsDone(false); + + view = createView(); + viewer->addView(view); } void destroyViewer() @@ -316,6 +296,15 @@ private: qDebug() << "OSGViewport::createView"; osgViewer::View *view = new osgViewer::View(); + // TODO expose as Qml properties + view->setLightingMode(osgViewer::View::SKY_LIGHT); + view->getLight()->setAmbient(osg::Vec4(0.6f, 0.6f, 0.6f, 1.0f)); + + return view; + } + + void installHanders() + { // TODO will the handlers be destroyed??? // add the state manipulator view->addEventHandler(new osgGA::StateSetManipulator(view->getCamera()->getOrCreateStateSet())); @@ -341,19 +330,6 @@ private: // add the screen capture handler // view->addEventHandler(new osgViewer::ScreenCaptureHandler); - - // setup graphics context and camera - osg::GraphicsContext *gc = createGraphicsContext(); - - // TODO expose as Qml properties - view->setLightingMode(osgViewer::View::SKY_LIGHT); - view->getLight()->setAmbient(osg::Vec4(0.6f, 0.6f, 0.6f, 1.0f)); - - osg::Camera *camera = view->getCamera(); - camera->setGraphicsContext(gc); - camera->setViewport(0, 0, gc->getTraits()->width, gc->getTraits()->height); - - return view; } osg::GraphicsContext *createGraphicsContext() @@ -407,19 +383,19 @@ private: return traits; } - void start() + void startTimer() { - if (updateMode != UpdateMode::Continuous && (frameTimer < 0)) { - qDebug() << "OSGViewport::start - starting timer"; - frameTimer = startTimer(33, Qt::PreciseTimer); + if ((updateMode != UpdateMode::Continuous) && (frameTimer < 0)) { + qDebug() << "OSGViewport::startTimer - starting timer"; + frameTimer = QObject::startTimer(33, Qt::PreciseTimer); } } - void stop() + void stopTimer() { if (frameTimer >= 0) { - qDebug() << "OSGViewport::stop - killing timer"; - killTimer(frameTimer); + qDebug() << "OSGViewport::stopTimer - killing timer"; + QObject::killTimer(frameTimer); frameTimer = -1; } } @@ -439,29 +415,33 @@ protected: private slots: - void onNodeChanged(osg::Node *node) + void onSceneNodeChanged(osg::Node *node) { - qDebug() << "OSGViewport::onNodeChanged" << node; - qWarning() << "OSGViewport::onNodeChanged - not implemented"; - // if (view.valid()) { - // acceptNode(node); - // } + qWarning() << "OSGViewport::onSceneNodeChanged - not implemented"; + } + + void onCameraNodeChanged(osg::Node *node) + { + qWarning() << "OSGViewport::onCameraNodeChanged - not implemented"; } }; /* class ViewportRenderer */ class ViewportRenderer : public QQuickFramebufferObject::Renderer { +private: + OSGViewport::Hidden *const h; + + int frameCount; + bool needToDoFrame; + public: - ViewportRenderer(OSGViewport::Hidden *h) : h(h) + ViewportRenderer(OSGViewport::Hidden *h) : h(h), frameCount(0), needToDoFrame(false) { qDebug() << "ViewportRenderer::ViewportRenderer"; // osgQtQuick::openGLContextInfo(QOpenGLContext::currentContext(), "ViewportRenderer::ViewportRenderer"); h->initializeResources(); - - firstFrame = true; - needToDoFrame = false; } ~ViewportRenderer() @@ -486,25 +466,42 @@ public: return; } - needToDoFrame = firstFrame; + // we want to always draw the first frame + needToDoFrame = (frameCount == 0); + + // if not on-demand then do frame if (h->updateMode != UpdateMode::OnDemand) { needToDoFrame = true; } - if (firstFrame) { + if (frameCount == 0) { h->view->init(); if (!h->viewer->isRealized()) { h->viewer->realize(); } - firstFrame = false; } - osg::Viewport *viewport = h->view->getCamera()->getViewport(); if ((viewport->width() != item->width()) || (viewport->height() != item->height())) { + qDebug() << "*** RESIZE" << frameCount << viewport->width() << "x" << viewport->height() << "->" << item->width() << "x" << item->height(); needToDoFrame = true; + // h->view->getCamera()->resize(item->width(), item->height()); int dpr = h->self->window()->devicePixelRatio(); h->view->getCamera()->getGraphicsContext()->resized(0, 0, item->width() * dpr, item->height() * dpr); + // h->view.get()->getEventQueue()->windowResize(0, 0, item->width() * dpr, item->height() * dpr); + + // trick to force a "home" on first few frames to absorb initial spurious resizes + if (frameCount <= 2) { + h->view->home(); + } + } + + // refresh busy state + h->self->setBusy(h->view->getDatabasePager()->getRequestsInProgress()); + + // TODO also expose request list size to Qml + if (h->view->getDatabasePager()->getFileRequestListSize() > 0) { + // qDebug() << h->view->getDatabasePager()->getFileRequestListSize(); } h->self->setBusy(h->view->getDatabasePager()->getRequestsInProgress()); @@ -515,16 +512,39 @@ public: needToDoFrame = h->viewer->checkNeedToDoFrame(); } if (!needToDoFrame) { - // calling checkNeedToDoFrame is not enough... + // workarounds to osg issues needToDoFrame = !h->view->getEventQueue()->empty(); + if (h->view->getSceneData()) { + needToDoFrame |= !(h->view->getSceneData()->getUpdateCallback() == NULL); + } } if (needToDoFrame) { + // qDebug() << "ViewportRenderer::synchronize - update scene" << frameCount; + + // info(); h->viewer->advance(); h->viewer->eventTraversal(); h->viewer->updateTraversal(); } } + void info() + { + if (!h->view.valid()) { + return; + } + // If the database pager is going to update the scene the render flag is + // set so that the updates show up + qDebug() << "DatabasePager" << (h->view->getDatabasePager()->requiresUpdateSceneGraph() || h->view->getDatabasePager()->getRequestsInProgress()); + + // if there update callbacks then we need to do frame. + qDebug() << "Camera" << (h->view->getCamera()->getUpdateCallback()); + qDebug() << "Scene" << (h->view->getSceneData() && h->view->getSceneData()->getNumChildrenRequiringUpdateTraversal() > 0); + + // check if events are available and need processing + qDebug() << "Events" << (h->viewer->checkEvents()); + } + // This function is called when the FBO should be rendered into. // The framebuffer is bound at this point and the glViewport has been set up to match the FBO size. void render() @@ -538,6 +558,8 @@ public: } if (needToDoFrame) { + // qDebug() << "ViewportRenderer::render - render scene" << frameCount; + // needed to properly render models without terrain (Qt bug?) QOpenGLContext::currentContext()->functions()->glUseProgram(0); h->viewer->renderingTraversals(); @@ -548,6 +570,8 @@ public: // trigger next update update(); } + + ++frameCount; } QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) @@ -557,6 +581,28 @@ public: format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); // format.setSamples(4); + /** + * that's a typical error when working with high-resolution (retina) + displays. The issue here is that on the high-resolution devices, the UI + operates with a virtual pixel size that is smaller than the real number + of pixels on the device. For example, you get coordinates from 0 to 2048 + while the real device resolution if 4096 pixels. This factor has to be + taken into account when mapping from window coordinates to OpenGL, e.g., + when calling glViewport. + + How you can get this factor depends on the GUI library you are using. In + Qt, you can query it with QWindow::devicePixelRatio(): + http://doc.qt.io/qt-5/qwindow.html#devicePixelRatio + + So, there should be something like + glViewport(0, 0, window->width() * window->devicePixelRatio(), + window->height() * window->devicePixelRatio()). + + Also keep in mind that you have to do the same e.g. for mouse coordinates. + + I think osgQt already handles this correctly, so you shouldn't have to + worry about this if you use the classes provided by osgQt ... + */ // Keeping this for reference : // Mac need(ed) to have devicePixelRatio (dpr) taken into account (i.e. dpr = 2). // Further tests on Mac have shown that although dpr is still 2 it should not be used to scale the fbo. @@ -566,12 +612,6 @@ public: return fbo; } - -private: - OSGViewport::Hidden *const h; - - bool firstFrame; - bool needToDoFrame; }; QtKeyboardMap OSGViewport::Hidden::keyMap = QtKeyboardMap(); @@ -580,7 +620,6 @@ QtKeyboardMap OSGViewport::Hidden::keyMap = QtKeyboardMap(); OSGViewport::OSGViewport(QQuickItem *parent) : QQuickFramebufferObject(parent), h(new Hidden(this)) { - qDebug() << "OSGViewport::OSGViewport"; // setClearBeforeRendering(false); setMirrorVertically(true); setAcceptHoverEvents(true); @@ -601,19 +640,34 @@ OSGNode *OSGViewport::sceneNode() const void OSGViewport::setSceneNode(OSGNode *node) { if (h->acceptSceneNode(node)) { + // setDirty(Scene); emit sceneNodeChanged(node); } } -OSGCamera *OSGViewport::camera() const +OSGCamera *OSGViewport::cameraNode() const { - return h->camera; + return h->cameraNode; } -void OSGViewport::setCamera(OSGCamera *camera) +void OSGViewport::setCameraNode(OSGCamera *node) { - if (h->acceptCamera(camera)) { - emit cameraChanged(camera); + if (h->acceptCameraNode(node)) { + // setDirty(Camera); + emit cameraNodeChanged(node); + } +} + +OSGCameraManipulator *OSGViewport::manipulator() const +{ + return h->manipulator; +} + +void OSGViewport::setManipulator(OSGCameraManipulator *manipulator) +{ + if (h->acceptManipulator(manipulator)) { + // setDirty(Manipulator); + emit manipulatorChanged(manipulator); } } @@ -643,21 +697,9 @@ void OSGViewport::setBusy(const bool busy) } } -QColor OSGViewport::color() const +osgViewer::View *OSGViewport::asView() const { - const osg::Vec4 osgColor = h->view->getCamera()->getClearColor(); - - return QColor::fromRgbF(osgColor.r(), osgColor.g(), osgColor.b(), osgColor.a()); -} - -void OSGViewport::setColor(const QColor &color) -{ - osg::Vec4 osgColor(color.redF(), color.greenF(), color.blueF(), color.alphaF()); - - if (h->view->getCamera()->getClearColor() != osgColor) { - h->view->getCamera()->setClearColor(osgColor); - emit colorChanged(color); - } + return h->view; } QQuickFramebufferObject::Renderer *OSGViewport::createRenderer() const @@ -667,29 +709,23 @@ QQuickFramebufferObject::Renderer *OSGViewport::createRenderer() const return new ViewportRenderer(h); } -void OSGViewport::attach(osgViewer::View *view) -{ - // qDebug() << "OSGViewport::attach" << view; - if (h->sceneNode) { - h->sceneNode->attach(view); - } - h->attach(view); -} - -void OSGViewport::detach(osgViewer::View *view) -{ - qDebug() << "OSGViewport::detach" << view; - h->detach(view); - if (h->sceneNode) { - h->sceneNode->detach(view); - } -} - void OSGViewport::releaseResources() { QQuickFramebufferObject::releaseResources(); } +void OSGViewport::classBegin() +{ + // qDebug() << "OSGViewport::classBegin" << this; + QQuickFramebufferObject::classBegin(); +} + +void OSGViewport::componentComplete() +{ + qDebug() << "OSGViewport::componentComplete" << this; + QQuickFramebufferObject::componentComplete(); +} + // see https://bugreports.qt-project.org/browse/QTBUG-41073 QSGNode *OSGViewport::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *nodeData) { diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.hpp index a45415050..66fd8a342 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.hpp @@ -30,6 +30,8 @@ #include "Export.hpp" +#include "ga/OSGCameraManipulator.hpp" + #include namespace osgViewer { @@ -50,10 +52,10 @@ public: class OSGQTQUICK_EXPORT OSGViewport : public QQuickFramebufferObject { Q_OBJECT Q_PROPERTY(osgQtQuick::OSGNode *sceneData READ sceneNode WRITE setSceneNode NOTIFY sceneNodeChanged) - Q_PROPERTY(osgQtQuick::OSGCamera * camera READ camera WRITE setCamera NOTIFY cameraChanged) + Q_PROPERTY(osgQtQuick::OSGCamera * camera READ cameraNode WRITE setCameraNode NOTIFY cameraNodeChanged) + Q_PROPERTY(osgQtQuick::OSGCameraManipulator * manipulator READ manipulator WRITE setManipulator NOTIFY manipulatorChanged) Q_PROPERTY(osgQtQuick::UpdateMode::Enum updateMode READ updateMode WRITE setUpdateMode NOTIFY updateModeChanged) Q_PROPERTY(bool busy READ busy NOTIFY busyChanged) - Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) public: friend class ViewportRenderer; @@ -64,8 +66,11 @@ public: OSGNode *sceneNode() const; void setSceneNode(OSGNode *node); - OSGCamera *camera() const; - void setCamera(OSGCamera *camera); + OSGCamera *cameraNode() const; + void setCameraNode(OSGCamera *node); + + OSGCameraManipulator *manipulator() const; + void setManipulator(OSGCameraManipulator *manipulator); UpdateMode::Enum updateMode() const; void setUpdateMode(UpdateMode::Enum mode); @@ -73,20 +78,24 @@ public: bool busy() const; void setBusy(const bool busy); - QColor color() const; - void setColor(const QColor &color); - Renderer *createRenderer() const; void releaseResources(); + osgViewer::View *asView() const; + signals: void sceneNodeChanged(OSGNode *node); - void cameraChanged(OSGCamera *camera); + void cameraNodeChanged(OSGCamera *node); + void manipulatorChanged(OSGCameraManipulator *manipulator); void updateModeChanged(UpdateMode::Enum mode); void busyChanged(bool busy); - void colorChanged(const QColor &color); protected: + QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData); + + void classBegin(); + void componentComplete(); + void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); @@ -97,11 +106,6 @@ protected: void setKeyboardModifiers(QInputEvent *event); QPointF mousePoint(QMouseEvent *event); - QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData); - - void attach(osgViewer::View *view); - void detach(osgViewer::View *view); - private: struct Hidden; Hidden *const h; diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGCameraManipulator.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGCameraManipulator.cpp new file mode 100644 index 000000000..88badea24 --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGCameraManipulator.cpp @@ -0,0 +1,143 @@ +/** + ****************************************************************************** + * + * @file OSGCameraManipulator.cpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @addtogroup + * @{ + * @addtogroup + * @{ + * @brief + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OSGCameraManipulator.hpp" + +#include "../OSGNode.hpp" + +#include + +#include + +namespace osgQtQuick { +struct OSGCameraManipulator::Hidden : public QObject { + Q_OBJECT + +private: + OSGCameraManipulator * const self; + +public: + osg::ref_ptr manipulator; + + OSGNode *sceneNode; + +public: + Hidden(OSGCameraManipulator *self) : QObject(self), self(self), sceneNode(NULL) + {} + + ~Hidden() + {} + + bool acceptSceneNode(OSGNode *node) + { + qDebug() << "OSGCameraManipulator::acceptSceneNode" << node; + if (sceneNode == node) { + return true; + } + + if (sceneNode) { + disconnect(sceneNode); + } + + sceneNode = node; + + if (sceneNode) { + connect(sceneNode, &OSGNode::nodeChanged, this, &Hidden::onSceneNodeChanged); + } + + return true; + } + + void updateSceneNode() + { + if (!sceneNode) { + qWarning() << "OSGCameraManipulator::updateSceneNode - no scene node"; + return; + } + qDebug() << "OSGCameraManipulator::updateSceneNode" << sceneNode->node(); + manipulator->setNode(sceneNode->node()); + } + +private slots: + void onSceneNodeChanged(osg::Node *node) + { + qDebug() << "OSGCameraManipulator::onSceneNodeChanged" << node; + qWarning() << "OSGCameraManipulator::onSceneNodeChanged - needs to be implemented"; + } +}; + +/* class OSGCameraManipulator */ + +OSGCameraManipulator::OSGCameraManipulator(QObject *parent) : QObject(parent), h(new Hidden(this)) +{} + +OSGCameraManipulator::~OSGCameraManipulator() +{ + qDebug() << "OSGCameraManipulator::~OSGCameraManipulator"; + delete h; +} + +OSGNode *OSGCameraManipulator::sceneNode() const +{ + return h->sceneNode; +} + +void OSGCameraManipulator::setSceneNode(OSGNode *node) +{ + if (h->acceptSceneNode(node)) { + emit sceneNodeChanged(node); + } +} + +void OSGCameraManipulator::classBegin() +{ + // qDebug() << "OSGCameraManipulator::classBegin" << this; +} + +void OSGCameraManipulator::componentComplete() +{ + qDebug() << "OSGCameraManipulator::componentComplete" << this; + h->updateSceneNode(); +} + +osgGA::CameraManipulator *OSGCameraManipulator::manipulator() const +{ + return h->manipulator; +} + +void OSGCameraManipulator::setManipulator(osgGA::CameraManipulator *manipulator) +{ + h->manipulator = manipulator; +} + +osgGA::CameraManipulator *OSGCameraManipulator::asCameraManipulator() const +{ + return h->manipulator; +} +} // namespace osgQtQuick + +#include "OSGCameraManipulator.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGCameraManipulator.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGCameraManipulator.hpp new file mode 100644 index 000000000..a5f2c48af --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGCameraManipulator.hpp @@ -0,0 +1,74 @@ +/** + ****************************************************************************** + * + * @file OSGCameraManipulator.hpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @addtogroup + * @{ + * @addtogroup + * @{ + * @brief + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _H_OSGQTQUICK_OSGCAMERAMANIPULATOR_H_ +#define _H_OSGQTQUICK_OSGCAMERAMANIPULATOR_H_ + +#include "../Export.hpp" + +#include +#include + +namespace osgGA { +class CameraManipulator; +} + +namespace osgQtQuick { +class OSGNode; + +class OSGQTQUICK_EXPORT OSGCameraManipulator : public QObject, public QQmlParserStatus { + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + + Q_PROPERTY(osgQtQuick::OSGNode * sceneNode READ sceneNode WRITE setSceneNode NOTIFY sceneNodeChanged) + +public: + explicit OSGCameraManipulator(QObject *parent = 0); + virtual ~OSGCameraManipulator(); + + osgGA::CameraManipulator *asCameraManipulator() const; + + OSGNode *sceneNode() const; + void setSceneNode(OSGNode *node); + +signals: + void sceneNodeChanged(OSGNode *node); + +protected: + void classBegin(); + void componentComplete(); + + osgGA::CameraManipulator *manipulator() const; + void setManipulator(osgGA::CameraManipulator *manipulator); + +private: + struct Hidden; + Hidden *const h; +}; +} // namespace osgQtQuick + +#endif // _H_OSGQTQUICK_OSGCAMERAMANIPULATOR_H_ diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGEarthManipulator.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGEarthManipulator.cpp new file mode 100644 index 000000000..b751fd108 --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGEarthManipulator.cpp @@ -0,0 +1,70 @@ +/** + ****************************************************************************** + * + * @file OSGEarthManipulator.cpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @addtogroup + * @{ + * @addtogroup + * @{ + * @brief + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OSGEarthManipulator.hpp" + +#include "../OSGNode.hpp" + +#include + +#include + +namespace osgQtQuick { +struct OSGEarthManipulator::Hidden : public QObject { + Q_OBJECT + +private: + OSGEarthManipulator * const self; + +public: + osg::ref_ptr manipulator; + + Hidden(OSGEarthManipulator *self) : QObject(self), self(self) + { + manipulator = new osgEarth::Util::EarthManipulator( + /*osgGA::StandardManipulator::COMPUTE_HOME_USING_BBOX | osgGA::StandardManipulator::DEFAULT_SETTINGS*/); + manipulator->getSettings()->setThrowingEnabled(true); + self->setManipulator(manipulator); + } + + ~Hidden() + {} +}; + +/* class OSGEarthManipulator */ + +OSGEarthManipulator::OSGEarthManipulator(QObject *parent) : OSGCameraManipulator(parent), h(new Hidden(this)) +{} + +OSGEarthManipulator::~OSGEarthManipulator() +{ + qDebug() << "OSGEarthManipulator::~OSGEarthManipulator"; + delete h; +} +} // namespace osgQtQuick + +#include "OSGEarthManipulator.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGEarthManipulator.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGEarthManipulator.hpp new file mode 100644 index 000000000..3104b7a0d --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGEarthManipulator.hpp @@ -0,0 +1,50 @@ +/** + ****************************************************************************** + * + * @file OSGEarthManipulator.hpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @addtogroup + * @{ + * @addtogroup + * @{ + * @brief + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _H_OSGQTQUICK_OSGEARTHMANIPULATOR_H_ +#define _H_OSGQTQUICK_OSGEARTHMANIPULATOR_H_ + +#include "../Export.hpp" +#include "OSGCameraManipulator.hpp" + +#include + +namespace osgQtQuick { +class OSGQTQUICK_EXPORT OSGEarthManipulator : public OSGCameraManipulator { + Q_OBJECT + +public: + explicit OSGEarthManipulator(QObject *parent = 0); + virtual ~OSGEarthManipulator(); + +private: + struct Hidden; + Hidden *const h; +}; +} // namespace osgQtQuick + +#endif // _H_OSGQTQUICK_OSGEARTHMANIPULATOR_H_ diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGGeoTransformManipulator.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGGeoTransformManipulator.cpp new file mode 100644 index 000000000..f8c1470f9 --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGGeoTransformManipulator.cpp @@ -0,0 +1,337 @@ +/** + ****************************************************************************** + * + * @file OSGGeoTransformManipulator.cpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @addtogroup + * @{ + * @addtogroup + * @{ + * @brief + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OSGGeoTransformManipulator.hpp" + +#include "../OSGNode.hpp" +#include "../../utility.h" + +#include +#include +#include +#include + +#include + +#include +#include + +#include + +namespace osgQtQuick { +class MyManipulator : public osgGA::CameraManipulator { +public: + MyManipulator() + {} + + virtual void updateCamera(osg::Camera &camera); + + virtual const char *className() const + { + return "MyManipulator"; + } + + virtual void setByMatrix(const osg::Matrixd &matrix) + { + this->matrix = matrix; + } + + virtual void setByInverseMatrix(const osg::Matrixd &matrix) + { + this->invMatrix = matrix; + } + + virtual osg::Matrixd getMatrix() const + { + return matrix; + } + + virtual osg::Matrixd getInverseMatrix() const + { + return invMatrix; + } + + virtual void setNode(osg::Node *node) + { + this->node = node; + } + + virtual const osg::Node *getNode() const + { + return node.get(); + } + + virtual osg::Node *getNode() + { + return node.get(); + } + +private: + osg::Matrixd matrix; + osg::Matrixd invMatrix; + osg::ref_ptr node; +}; + +struct OSGGeoTransformManipulator::NodeUpdateCallback : public osg::NodeCallback { +public: + NodeUpdateCallback(OSGGeoTransformManipulator::Hidden *h) : h(h) + {} + + void operator()(osg::Node *node, osg::NodeVisitor *nv); + +private: + OSGGeoTransformManipulator::Hidden *const h; +}; + +struct OSGGeoTransformManipulator::Hidden : public QObject { + Q_OBJECT + +private: + OSGGeoTransformManipulator * const self; + + osg::ref_ptr nodeUpdateCallback; + + osg::Matrix cameraPosition; + osg::Matrix cameraRotation; + + bool dirty; + +public: + osg::ref_ptr manipulator; + + QVector3D attitude; + QVector3D position; + + bool clampToTerrain; + bool intoTerrain; + + Hidden(OSGGeoTransformManipulator *self) : QObject(self), self(self), dirty(false), clampToTerrain(false), intoTerrain(false) + { + manipulator = new MyManipulator(); + self->setManipulator(manipulator); + } + + ~Hidden() + {} + + // TODO factorize up + void setDirty() + { + if (dirty) { + return; + } + // qDebug() << "OSGGeoTransformManipulator::setDirty"; + dirty = true; + osg::Node *node = manipulator->getNode(); + if (node) { + if (!nodeUpdateCallback.valid()) { + // lazy creation + nodeUpdateCallback = new NodeUpdateCallback(this); + } + node->addUpdateCallback(nodeUpdateCallback.get()); + } else { + qWarning() << "OSGGeoTransformManipulator::setDirty - no node..."; + } + } + + // TODO factorize up + void clearDirty() + { + // qDebug() << "OSGGeoTransformManipulator::clearDirty"; + osg::Node *node = manipulator->getNode(); + + if (node && nodeUpdateCallback.valid()) { + node->removeUpdateCallback(nodeUpdateCallback.get()); + } + dirty = false; + } + + void update() + { + updatePosition(); + updateAttitude(); + updateManipulator(); + } + + void updateManipulator() + { + // qDebug() << "OSGGeoTransformManipulator::updateManipulator"; + + osg::Matrix cameraMatrix = cameraRotation * cameraPosition; + + manipulator->setByMatrix(cameraMatrix); + + // Inverse the camera's position and orientation matrix to obtain the view matrix + cameraMatrix = osg::Matrix::inverse(cameraMatrix); + manipulator->setByInverseMatrix(cameraMatrix); + } + + void updatePosition() + { + // qDebug() << "OSGGeoTransformManipulator::updatePosition" << position; + + // Altitude mode is absolute (absolute height above MSL/HAE) + // HAE : Height above ellipsoid. This is the default. + // MSL : Height above Mean Sea Level (MSL) if a geoid separation value is specified. + // TODO handle the case where the terrain SRS is not "wgs84" + // TODO check if position is not below terrain? + // TODO compensate antenna height when source of position is GPS (i.e. subtract antenna height from altitude) ;) + + osgEarth::MapNode *mapNode = NULL; + + if (manipulator->getNode()) { + mapNode = osgEarth::MapNode::findMapNode(manipulator->getNode()); + if (!mapNode) { + qWarning() << "OSGGeoTransformManipulator::updatePosition - manipulator node does not contain a map node"; + } + } else { + qWarning() << "OSGGeoTransformManipulator::updatePosition - manipulator node is null"; + } + + osgEarth::GeoPoint geoPoint; + if (mapNode) { + geoPoint = osgQtQuick::toGeoPoint(mapNode->getTerrain()->getSRS(), position); + } else { + geoPoint = osgQtQuick::toGeoPoint(position); + } + if (clampToTerrain && mapNode) { + // clamp model to terrain if needed + intoTerrain = osgQtQuick::clampGeoPoint(geoPoint, 0, mapNode); + } else if (clampToTerrain) { + qWarning() << "OSGGeoTransformManipulator::updatePosition - cannot clamp without map node"; + } + + geoPoint.createLocalToWorld(cameraPosition); + } + + void updateAttitude() + { + // qDebug() << "OSGGeoTransformManipulator::updateAttitude" << attitude; + + // By default the camera looks toward -Z, we must rotate it so it looks toward Y + cameraRotation.makeRotate(osg::DegreesToRadians(90.0), osg::Vec3(1.0, 0.0, 0.0), + osg::DegreesToRadians(0.0), osg::Vec3(0.0, 1.0, 0.0), + osg::DegreesToRadians(0.0), osg::Vec3(0.0, 0.0, 1.0)); + + // Final camera matrix + double roll = osg::DegreesToRadians(attitude.x()); + double pitch = osg::DegreesToRadians(attitude.y()); + double yaw = osg::DegreesToRadians(attitude.z()); + cameraRotation = cameraRotation + * osg::Matrix::rotate(roll, osg::Vec3(0, 1, 0)) + * osg::Matrix::rotate(pitch, osg::Vec3(1, 0, 0)) + * osg::Matrix::rotate(yaw, osg::Vec3(0, 0, -1)); + } +}; + +/* class OSGGeoTransformManipulator::MyManipulator */ + +void MyManipulator::updateCamera(osg::Camera & camera) +{ + // qDebug() << "MyManipulator::updateCamera"; + CameraManipulator::updateCamera(camera); +} + +/* struct OSGGeoTransformManipulator::NodeUpdateCallback */ + +void OSGGeoTransformManipulator::NodeUpdateCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) +{ + // qDebug() << "OSGGeoTransformManipulator::NodeUpdateCallback"; + nv->traverse(*node); + h->update(); + h->clearDirty(); +} + +/* class OSGGeoTransformManipulator */ + +OSGGeoTransformManipulator::OSGGeoTransformManipulator(QObject *parent) : OSGCameraManipulator(parent), h(new Hidden(this)) +{} + +OSGGeoTransformManipulator::~OSGGeoTransformManipulator() +{ + qDebug() << "OSGGeoTransformManipulator::~OSGGeoTransformManipulator"; + delete h; +} + +bool OSGGeoTransformManipulator::clampToTerrain() const +{ + return h->clampToTerrain; +} + +void OSGGeoTransformManipulator::setClampToTerrain(bool arg) +{ + if (h->clampToTerrain != arg) { + h->clampToTerrain = arg; + emit clampToTerrainChanged(clampToTerrain()); + } +} + +bool OSGGeoTransformManipulator::intoTerrain() const +{ + return h->intoTerrain; +} + +QVector3D OSGGeoTransformManipulator::attitude() const +{ + return h->attitude; +} + +void OSGGeoTransformManipulator::setAttitude(QVector3D arg) +{ + if (h->attitude != arg) { + h->attitude = arg; + h->setDirty(); + emit attitudeChanged(attitude()); + } +} + +QVector3D OSGGeoTransformManipulator::position() const +{ + return h->position; +} + +void OSGGeoTransformManipulator::setPosition(QVector3D arg) +{ + if (h->position != arg) { + h->position = arg; + h->setDirty(); + emit positionChanged(position()); + } +} + +// TODO factorize up +void OSGGeoTransformManipulator::componentComplete() +{ + OSGCameraManipulator::componentComplete(); + + qDebug() << "OSGGeoTransformManipulator::componentComplete" << this; + h->update(); + h->clearDirty(); +} +} // namespace osgQtQuick + +#include "OSGGeoTransformManipulator.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGGeoTransformManipulator.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGGeoTransformManipulator.hpp new file mode 100644 index 000000000..3a7ee129a --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGGeoTransformManipulator.hpp @@ -0,0 +1,78 @@ +/** + ****************************************************************************** + * + * @file OSGGeoTransformManipulator.hpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @addtogroup + * @{ + * @addtogroup + * @{ + * @brief + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _H_OSGQTQUICK_OSGGEOTRANSFORMMANIPULATOR_H_ +#define _H_OSGQTQUICK_OSGGEOTRANSFORMMANIPULATOR_H_ + +#include "../Export.hpp" +#include "OSGCameraManipulator.hpp" + +#include +#include + +namespace osgQtQuick { +class OSGQTQUICK_EXPORT OSGGeoTransformManipulator : public OSGCameraManipulator { + Q_OBJECT Q_PROPERTY(QVector3D attitude READ attitude WRITE setAttitude NOTIFY attitudeChanged) + Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(bool clampToTerrain READ clampToTerrain WRITE setClampToTerrain NOTIFY clampToTerrainChanged) + Q_PROPERTY(bool intoTerrain READ intoTerrain NOTIFY intoTerrainChanged) + + friend class NodeUpdateCallback; + friend class MyManipulator; + +public: + explicit OSGGeoTransformManipulator(QObject *parent = 0); + virtual ~OSGGeoTransformManipulator(); + + QVector3D attitude() const; + void setAttitude(QVector3D arg); + + QVector3D position() const; + void setPosition(QVector3D arg); + + bool clampToTerrain() const; + void setClampToTerrain(bool arg); + + bool intoTerrain() const; + +signals: + void attitudeChanged(QVector3D arg); + void positionChanged(QVector3D arg); + void clampToTerrainChanged(bool arg); + void intoTerrainChanged(bool arg); + +protected: + void componentComplete(); + +private: + struct Hidden; + struct NodeUpdateCallback; + Hidden *const h; +}; +} // namespace osgQtQuick + +#endif // _H_OSGQTQUICK_OSGGEOTRANSFORMMANIPULATOR_H_ diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGNodeTrackerManipulator.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGNodeTrackerManipulator.cpp new file mode 100644 index 000000000..a832d4928 --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGNodeTrackerManipulator.cpp @@ -0,0 +1,169 @@ +/** + ****************************************************************************** + * + * @file OSGNodeTrackerManipulator.cpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @addtogroup + * @{ + * @addtogroup + * @{ + * @brief + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OSGNodeTrackerManipulator.hpp" + +#include "../OSGNode.hpp" + +#include + +#include + +namespace osgQtQuick { +struct OSGNodeTrackerManipulator::Hidden : public QObject { + Q_OBJECT + +private: + OSGNodeTrackerManipulator * const self; + +public: + osg::ref_ptr manipulator; + + OSGNode *trackNode; + TrackerMode::Enum trackerMode; + +public: + Hidden(OSGNodeTrackerManipulator *self) : QObject(self), self(self), + trackNode(NULL), trackerMode(TrackerMode::NodeCenterAndAzim) + { + manipulator = new osgGA::NodeTrackerManipulator( + /*osgGA::StandardManipulator::COMPUTE_HOME_USING_BBOX | osgGA::StandardManipulator::DEFAULT_SETTINGS*/); + manipulator->setTrackerMode(toOsg(trackerMode)); + manipulator->setVerticalAxisFixed(false); + + self->setManipulator(manipulator); + } + + ~Hidden() + {} + + bool acceptTrackNode(OSGNode *node) + { + qDebug() << "OSGNodeTrackerManipulator::acceptTrackNode" << node; + if (trackNode == node) { + return false; + } + + if (trackNode) { + disconnect(trackNode); + } + + trackNode = node; + + if (trackNode) { + connect(trackNode, SIGNAL(nodeChanged(osg::Node *)), this, SLOT(onTrackNodeChanged(osg::Node *))); + } + + return true; + } + + void updateTrackNode() + { + if (!trackNode) { + qWarning() << "OSGNodeTrackerManipulator::updateTrackNode - no track node"; + return; + } + qDebug() << "OSGNodeTrackerManipulator::updateTrackNode" << trackNode->node(); + manipulator->setTrackNode(trackNode->node()); + } + + void updateTrackerMode() + { + // qDebug() << "OSGNodeTrackerManipulator::updateTrackerMode" << mode; + manipulator->setTrackerMode(toOsg(trackerMode)); + } + + osgGA::NodeTrackerManipulator::TrackerMode toOsg(TrackerMode::Enum mode) + { + switch (mode) { + case TrackerMode::NodeCenter: + return osgGA::NodeTrackerManipulator::NODE_CENTER; + + case TrackerMode::NodeCenterAndAzim: + return osgGA::NodeTrackerManipulator::NODE_CENTER_AND_AZIM; + + case TrackerMode::NodeCenterAndRotation: + return osgGA::NodeTrackerManipulator::NODE_CENTER_AND_ROTATION; + } + return osgGA::NodeTrackerManipulator::NODE_CENTER_AND_ROTATION; + } + +private slots: + void onTrackNodeChanged(osg::Node *node) + { + qDebug() << "OSGNodeTrackerManipulator::onTrackNodeChanged" << node; + qWarning() << "OSGNodeTrackerManipulator::onTrackNodeChanged - needs to be implemented"; + } +}; + +/* class OSGNodeTrackerManipulator */ + +OSGNodeTrackerManipulator::OSGNodeTrackerManipulator(QObject *parent) : OSGCameraManipulator(parent), h(new Hidden(this)) +{} + +OSGNodeTrackerManipulator::~OSGNodeTrackerManipulator() +{ + qDebug() << "OSGNodeTrackerManipulator::~OSGNodeTrackerManipulator"; + delete h; +} + +OSGNode *OSGNodeTrackerManipulator::trackNode() const +{ + return h->trackNode; +} + +void OSGNodeTrackerManipulator::setTrackNode(OSGNode *node) +{ + if (h->acceptTrackNode(node)) { + emit trackNodeChanged(node); + } +} + +TrackerMode::Enum OSGNodeTrackerManipulator::trackerMode() const +{ + return h->trackerMode; +} + +void OSGNodeTrackerManipulator::setTrackerMode(TrackerMode::Enum mode) +{ + if (h->trackerMode != mode) { + h->trackerMode = mode; + emit trackerModeChanged(trackerMode()); + } +} + +void OSGNodeTrackerManipulator::componentComplete() +{ + OSGCameraManipulator::componentComplete(); + + qDebug() << "OSGNodeTrackerManipulator::componentComplete" << this; + h->updateTrackerMode(); + h->updateTrackNode(); +} +} // namespace osgQtQuick + +#include "OSGNodeTrackerManipulator.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGNodeTrackerManipulator.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGNodeTrackerManipulator.hpp new file mode 100644 index 000000000..378271e13 --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGNodeTrackerManipulator.hpp @@ -0,0 +1,71 @@ +/** + ****************************************************************************** + * + * @file OSGNodeTrackerManipulator.hpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @addtogroup + * @{ + * @addtogroup + * @{ + * @brief + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _H_OSGQTQUICK_OSGNODETRACKERMANIPULATOR_H_ +#define _H_OSGQTQUICK_OSGNODETRACKERMANIPULATOR_H_ + +#include "../Export.hpp" +#include "OSGCameraManipulator.hpp" + +#include + +namespace osgQtQuick { +class TrackerMode : public QObject { + Q_OBJECT +public: + enum Enum { NodeCenter, NodeCenterAndAzim, NodeCenterAndRotation }; + Q_ENUMS(Enum) // TODO switch to Q_ENUM once on Qt 5.5 +}; + +class OSGQTQUICK_EXPORT OSGNodeTrackerManipulator : public OSGCameraManipulator { + Q_OBJECT Q_PROPERTY(osgQtQuick::OSGNode *trackNode READ trackNode WRITE setTrackNode NOTIFY trackNodeChanged) + Q_PROPERTY(osgQtQuick::TrackerMode::Enum trackerMode READ trackerMode WRITE setTrackerMode NOTIFY trackerModeChanged) + +public: + explicit OSGNodeTrackerManipulator(QObject *parent = 0); + virtual ~OSGNodeTrackerManipulator(); + + OSGNode *trackNode() const; + void setTrackNode(OSGNode *node); + + TrackerMode::Enum trackerMode() const; + void setTrackerMode(TrackerMode::Enum); + +signals: + void trackNodeChanged(OSGNode *node); + void trackerModeChanged(TrackerMode::Enum); + +protected: + void componentComplete(); + +private: + struct Hidden; + Hidden *const h; +}; +} // namespace osgQtQuick + +#endif // _H_OSGQTQUICK_OSGNODETRACKERMANIPULATOR_H_ diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGTrackballManipulator.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGTrackballManipulator.cpp new file mode 100644 index 000000000..99a3f6ca3 --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGTrackballManipulator.cpp @@ -0,0 +1,70 @@ +/** + ****************************************************************************** + * + * @file OSGTrackballManipulator.cpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @addtogroup + * @{ + * @addtogroup + * @{ + * @brief + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OSGTrackballManipulator.hpp" + +#include "../OSGNode.hpp" + +#include + +#include + +namespace osgQtQuick { +struct OSGTrackballManipulator::Hidden : public QObject { + Q_OBJECT + +private: + OSGTrackballManipulator * const self; + +public: + osg::ref_ptr manipulator; + + Hidden(OSGTrackballManipulator *self) : QObject(self), self(self) + { + manipulator = new osgGA::TrackballManipulator( + /*osgGA::StandardManipulator::COMPUTE_HOME_USING_BBOX | osgGA::StandardManipulator::DEFAULT_SETTINGS*/); + + self->setManipulator(manipulator); + } + + ~Hidden() + {} +}; + +/* class OSGTrackballManipulator */ + +OSGTrackballManipulator::OSGTrackballManipulator(QObject *parent) : OSGCameraManipulator(parent), h(new Hidden(this)) +{} + +OSGTrackballManipulator::~OSGTrackballManipulator() +{ + qDebug() << "OSGTrackballManipulator::~OSGTrackballManipulator"; + delete h; +} +} // namespace osgQtQuick + +#include "OSGTrackballManipulator.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGTrackballManipulator.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGTrackballManipulator.hpp new file mode 100644 index 000000000..4ce01eeef --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGTrackballManipulator.hpp @@ -0,0 +1,50 @@ +/** + ****************************************************************************** + * + * @file OSGTrackballManipulator.hpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @addtogroup + * @{ + * @addtogroup + * @{ + * @brief + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _H_OSGQTQUICK_OSGTRACKBALLMANIPULATOR_H_ +#define _H_OSGQTQUICK_OSGTRACKBALLMANIPULATOR_H_ + +#include "../Export.hpp" +#include "OSGCameraManipulator.hpp" + +#include + +namespace osgQtQuick { +class OSGQTQUICK_EXPORT OSGTrackballManipulator : public OSGCameraManipulator { + Q_OBJECT + +public: + explicit OSGTrackballManipulator(QObject *parent = 0); + virtual ~OSGTrackballManipulator(); + +private: + struct Hidden; + Hidden *const h; +}; +} // namespace osgQtQuick + +#endif // _H_OSGQTQUICK_OSGTRACKBALLMANIPULATOR_H_ diff --git a/ground/gcs/src/libs/osgearth/osgearth.pro b/ground/gcs/src/libs/osgearth/osgearth.pro index fda4784e1..6969314cf 100644 --- a/ground/gcs/src/libs/osgearth/osgearth.pro +++ b/ground/gcs/src/libs/osgearth/osgearth.pro @@ -69,6 +69,16 @@ SOURCES += \ osgQtQuick/OSGCamera.cpp \ osgQtQuick/OSGViewport.cpp +HEADERS += \ + osgQtQuick/ga/OSGCameraManipulator.hpp \ + osgQtQuick/ga/OSGNodeTrackerManipulator.hpp \ + osgQtQuick/ga/OSGTrackballManipulator.hpp + +SOURCES += \ + osgQtQuick/ga/OSGCameraManipulator.cpp \ + osgQtQuick/ga/OSGNodeTrackerManipulator.cpp \ + osgQtQuick/ga/OSGTrackballManipulator.cpp + osgearth:HEADERS += \ osgQtQuick/OSGSkyNode.hpp \ osgQtQuick/OSGGeoTransformNode.hpp @@ -77,4 +87,12 @@ osgearth:SOURCES += \ osgQtQuick/OSGSkyNode.cpp \ osgQtQuick/OSGGeoTransformNode.cpp +osgearth:HEADERS += \ + osgQtQuick/ga/OSGEarthManipulator.hpp \ + osgQtQuick/ga/OSGGeoTransformManipulator.hpp + +osgearth:SOURCES += \ + osgQtQuick/ga/OSGEarthManipulator.cpp \ + osgQtQuick/ga/OSGGeoTransformManipulator.cpp + copy_osg:include(copydata.pro) diff --git a/ground/gcs/src/libs/osgearth/utility.cpp b/ground/gcs/src/libs/osgearth/utility.cpp index a35f25cc9..5551d40ee 100644 --- a/ground/gcs/src/libs/osgearth/utility.cpp +++ b/ground/gcs/src/libs/osgearth/utility.cpp @@ -38,6 +38,10 @@ #include "osgQtQuick/OSGCamera.hpp" #include "osgQtQuick/OSGViewport.hpp" +#include "osgQtQuick/ga/OSGCameraManipulator.hpp" +#include "osgQtQuick/ga/OSGNodeTrackerManipulator.hpp" +#include "osgQtQuick/ga/OSGTrackballManipulator.hpp" + #include #include #include @@ -61,6 +65,9 @@ #include "osgQtQuick/OSGSkyNode.hpp" #include "osgQtQuick/OSGGeoTransformNode.hpp" +#include "osgQtQuick/ga/OSGEarthManipulator.hpp" +#include "osgQtQuick/ga/OSGGeoTransformManipulator.hpp" + #include #include #include @@ -75,9 +82,11 @@ namespace osgQtQuick { class CullCallback : public osg::NodeCallback { public: - CullCallback() {} + CullCallback() + {} - virtual ~CullCallback() {} + virtual ~CullCallback() + {} public: virtual void operator()(osg::Node *node, osg::NodeVisitor *nv) @@ -101,12 +110,14 @@ class InsertCallbacksVisitor : public osg::NodeVisitor { public: InsertCallbacksVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + virtual void apply(osg::Node & node) { // node.setUpdateCallback(new UpdateCallback()); node.setCullCallback(new CullCallback()); traverse(node); } + virtual void apply(osg::Geode & geode) { // geode.setUpdateCallback(new UpdateCallback()); @@ -122,6 +133,7 @@ public: // geode.getDrawable(i)->setDrawCallback(new DrawableDrawCallback()); // } } + virtual void apply(osg::Transform & node) { apply((osg::Node &)node); @@ -543,12 +555,18 @@ void registerTypes() qmlRegisterType("OsgQtQuick", maj, min, "UpdateMode"); qmlRegisterType("OsgQtQuick", maj, min, "OSGCamera"); - qmlRegisterType("OsgQtQuick", maj, min, "ManipulatorMode"); + + qmlRegisterType("OsgQtQuick", maj, min, "OSGCameraManipulator"); + qmlRegisterType("OsgQtQuick", maj, min, "OSGNodeTrackerManipulator"); qmlRegisterType("OsgQtQuick", maj, min, "TrackerMode"); + qmlRegisterType("OsgQtQuick", maj, min, "OSGTrackballManipulator"); #ifdef USE_OSGEARTH qmlRegisterType("OsgQtQuick", maj, min, "OSGSkyNode"); qmlRegisterType("OsgQtQuick", maj, min, "OSGGeoTransformNode"); + + qmlRegisterType("OsgQtQuick", maj, min, "OSGEarthManipulator"); + qmlRegisterType("OsgQtQuick", maj, min, "OSGGeoTransformManipulator"); #endif // USE_OSGEARTH } } // namespace osgQtQuick diff --git a/ground/gcs/src/share/qml/EarthView.qml b/ground/gcs/src/share/qml/EarthView.qml index 4622db30d..ae0a7dde6 100644 --- a/ground/gcs/src/share/qml/EarthView.qml +++ b/ground/gcs/src/share/qml/EarthView.qml @@ -28,14 +28,27 @@ import "common.js" as Utils Item { OSGViewport { id: osgViewport + anchors.fill: parent focus: true + sceneData: skyNode camera: camera + manipulator: earthManipulator + + OSGCamera { + id: camera + fieldOfView: 90 + } + + OSGEarthManipulator { + id: earthManipulator + } OSGSkyNode { id: skyNode sceneData: terrainNode + viewport: osgViewport dateTime: Utils.getDateTime() minimumAmbientLight: pfdContext.minimumAmbientLight } @@ -46,11 +59,7 @@ Item { async: false } - OSGCamera { - id: camera - fieldOfView: 90 - manipulatorMode: ManipulatorMode.Earth - } + } BusyIndicator { width: 24 diff --git a/ground/gcs/src/share/qml/model/ModelTerrainView.qml b/ground/gcs/src/share/qml/model/ModelTerrainView.qml index 8575b43d1..4853bfe6f 100644 --- a/ground/gcs/src/share/qml/model/ModelTerrainView.qml +++ b/ground/gcs/src/share/qml/model/ModelTerrainView.qml @@ -28,34 +28,46 @@ import "../uav.js" as UAV OSGViewport { id: osgViewport + anchors.fill: parent focus: true + sceneData: skyNode camera: camera + manipulator: nodeTrackerManipulator + + OSGCamera { + id: camera + fieldOfView: 90 + logarithmicDepthBuffer: true + } + + OSGNodeTrackerManipulator { + id: nodeTrackerManipulator + // use model to compute camera home position + sceneNode: modelTransformNode + // model will be tracked + trackNode: modelTransformNode + } OSGSkyNode { id: skyNode sceneData: sceneGroup + viewport: osgViewport dateTime: Utils.getDateTime() minimumAmbientLight: pfdContext.minimumAmbientLight } OSGGroup { id: sceneGroup - children: [ terrainNode, modelNode ] - } - - OSGFileNode { - id: terrainNode - source: pfdContext.terrainFile - async: false + children: [ terrainFileNode, modelNode ] } OSGGeoTransformNode { id: modelNode modelData: modelTransformNode - sceneData: terrainNode + sceneData: terrainFileNode clampToTerrain: true @@ -70,6 +82,11 @@ OSGViewport { attitude: UAV.attitude() } + OSGFileNode { + id: terrainFileNode + source: pfdContext.terrainFile + } + OSGFileNode { id: modelFileNode @@ -77,21 +94,9 @@ OSGViewport { // see http://docs.osgearth.org/en/latest/faq.html#i-added-a-node-but-it-has-no-texture-lighting-etc-in-osgearth-why source: pfdContext.modelFile + ".osgearth_shadergen" - async: false optimizeMode: OptimizeMode.OptimizeAndCheck } - OSGCamera { - id: camera - fieldOfView: 90 - logarithmicDepthBuffer: true - manipulatorMode: ManipulatorMode.Track - // use model to compute camera home position - sceneNode: modelTransformNode - // model will be tracked - trackNode: modelTransformNode - } - Keys.onUpPressed: { pfdContext.nextModel(); } diff --git a/ground/gcs/src/share/qml/model/ModelView.qml b/ground/gcs/src/share/qml/model/ModelView.qml index 9bb15ad7a..9e4bd697b 100644 --- a/ground/gcs/src/share/qml/model/ModelView.qml +++ b/ground/gcs/src/share/qml/model/ModelView.qml @@ -28,8 +28,20 @@ Item { OSGViewport { anchors.fill: parent focus: true + sceneData: sceneNode camera: camera + manipulator: trackballManipulator + + OSGCamera { + id: camera + fieldOfView: 90 + } + + OSGTrackballManipulator { + id: trackballManipulator + sceneNode: transformNode + } OSGGroup { id: sceneNode @@ -57,12 +69,6 @@ Item { optimizeMode: OptimizeMode.OptimizeAndCheck } - OSGCamera { - id: camera - fieldOfView: 90 - sceneNode: transformNode - } - Keys.onUpPressed: { pfdContext.nextModel(); } diff --git a/ground/gcs/src/share/qml/pfd/PfdTerrainView.qml b/ground/gcs/src/share/qml/pfd/PfdTerrainView.qml index 57da2a4fb..3ca04f9c5 100644 --- a/ground/gcs/src/share/qml/pfd/PfdTerrainView.qml +++ b/ground/gcs/src/share/qml/pfd/PfdTerrainView.qml @@ -26,11 +26,14 @@ import "../common.js" as Utils import "../uav.js" as UAV OSGViewport { - id: fullview + id: osgViewport + //anchors.fill: parent focus: true + sceneData: skyNode camera: camera + manipulator: geoTransformManipulator property real horizontCenter : horizontCenterItem.horizontCenter @@ -41,31 +44,36 @@ OSGViewport { //height: height * (1 + factor) y: -height * factor + OSGCamera { + id: camera + + fieldOfView: 100 + logarithmicDepthBuffer: true + } + + OSGGeoTransformManipulator { + id: geoTransformManipulator + + clampToTerrain: true + + attitude: UAV.attitude() + position: UAV.position() + } + OSGSkyNode { id: skyNode - sceneData: terrainNode + sceneData: terrainFileNode + viewport: osgViewport dateTime: Utils.getDateTime() minimumAmbientLight: pfdContext.minimumAmbientLight } OSGFileNode { - id: terrainNode + id: terrainFileNode source: pfdContext.terrainFile async: false } - OSGCamera { - id: camera - fieldOfView: 100 - sceneNode: terrainNode - logarithmicDepthBuffer: true - clampToTerrain: true - manipulatorMode: ManipulatorMode.User - - attitude: UAV.attitude() - position: UAV.position() - } - Rectangle { // using rectangle instead of svg rendered to pixmap // as it's much more memory efficient @@ -104,7 +112,7 @@ OSGViewport { property variant scaledBounds: svgRenderer.scaledElementBounds("pfd/pfd.svg", "pitch-window-terrain") x: Math.floor(scaledBounds.x * sceneItem.width) - y: Math.floor(scaledBounds.y * sceneItem.height) - fullview.y + y: Math.floor(scaledBounds.y * sceneItem.height) - osgViewport.y width: Math.floor(scaledBounds.width * sceneItem.width) height: Math.floor(scaledBounds.height * sceneItem.height)