diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/DirtySupport.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/DirtySupport.cpp new file mode 100644 index 000000000..c5d488159 --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/DirtySupport.cpp @@ -0,0 +1,148 @@ +/** + ****************************************************************************** + * + * @file DirtySupport.cpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @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 "DirtySupport.hpp" + +#include +#include + +#include + +namespace osgQtQuick { +class Hidden; + +struct DirtySupport::NodeUpdateCallback : public osg::NodeCallback { +public: + NodeUpdateCallback(DirtySupport::Hidden *h) : h(h) + {} + + void operator()(osg::Node *node, osg::NodeVisitor *nv); + +private: + DirtySupport::Hidden *const h; +}; + +struct DirtySupport::Hidden { +private: + DirtySupport *const self; + + osg::ref_ptr nodeUpdateCallback; + + int dirtyFlags; + +public: + Hidden(DirtySupport *self) : self(self), dirtyFlags(0) + {} + + bool isDirty(int mask) const + { + return (dirtyFlags & mask) != 0; + } + + int dirty() const + { + return dirtyFlags; + } + + void setDirty(int mask) + { + // qDebug() << "DirtySupport::setDirty" << mask; + if (!dirtyFlags) { + osg::Node *node = self->nodeToUpdate(); + if (node) { + if (!nodeUpdateCallback.valid()) { + // lazy creation + nodeUpdateCallback = new NodeUpdateCallback(this); + } + node->addUpdateCallback(nodeUpdateCallback.get()); + } else { + // qWarning() << "DirtySupport::setDirty - node to update is null"; + } + } + dirtyFlags |= mask; + } + + void clearDirty() + { + osg::Node *node = self->nodeToUpdate(); + + if (node && nodeUpdateCallback.valid()) { + node->removeUpdateCallback(nodeUpdateCallback.get()); + } + dirtyFlags = 0; + } + + void update() + { + // qDebug() << "DirtySupport::update"; + if (dirtyFlags) { + // qDebug() << "DirtySupport::update - updating..."; + self->update(); + } + clearDirty(); + } +}; + +/* struct DirtySupport::NodeUpdateCallback */ + +void DirtySupport::NodeUpdateCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) +{ + // qDebug() << "DirtySupport::NodeUpdateCallback"; + nv->traverse(*node); + h->update(); +} + +/* class DirtySupport */ + +DirtySupport::DirtySupport() : h(new Hidden(this)) +{} + +DirtySupport::~DirtySupport() +{ + delete h; +} + +int DirtySupport::dirty() const +{ + return h->dirty(); +} + +bool DirtySupport::isDirty(int mask) const +{ + return h->isDirty(mask); +} + +void DirtySupport::setDirty(int mask) +{ + h->setDirty(mask); +} + +void DirtySupport::clearDirty() +{ + h->clearDirty(); +} +} // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/DirtySupport.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/DirtySupport.hpp new file mode 100644 index 000000000..f802fc8c6 --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/DirtySupport.hpp @@ -0,0 +1,63 @@ +/** + ****************************************************************************** + * + * @file DirtySupport.hpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @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_DIRTYSUPPORT_H_ +#define _H_OSGQTQUICK_DIRTYSUPPORT_H_ + +namespace osg { +class Node; +} // namespace osg + +namespace osgQtQuick { +/** + * Provides support to: + * - manage dirty state flags + * - add/remove node callback to trigger refresh (compatible with viewer on demand mode) + */ +class DirtySupport { +public: + explicit DirtySupport(); + virtual ~DirtySupport(); + +protected: + int dirty() const; + bool isDirty(int mask = 0xFFFF) const; + void setDirty(int mask = 0xFFFF); + void clearDirty(); + +private: + struct Hidden; + struct NodeUpdateCallback; + Hidden *const h; + + virtual osg::Node *nodeToUpdate() const = 0; + + virtual void update() = 0; +}; +} // namespace osgQtQuick + +#endif // _H_OSGQTQUICK_DIRTYSUPPORT_H_ diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/Export.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/Export.hpp index e7499efc0..779eea607 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/Export.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/Export.hpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file Export.hpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBackgroundNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBackgroundNode.cpp deleted file mode 100644 index 48560d963..000000000 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBackgroundNode.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/** - ****************************************************************************** - * - * @file OSGBackgroundNode.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 "OSGBackgroundNode.hpp" - -#include -#include -#include - -#include -#include - -namespace osgQtQuick { -struct OSGBackgroundNode::Hidden : public QObject { - Q_OBJECT - -private: - OSGBackgroundNode * const self; - -public: - QUrl url; - - Hidden(OSGBackgroundNode *parent) : QObject(parent), self(parent), url() {} - - void updateNode() - { - // qDebug() << "OSGBackgroundNode::realize - 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::Vec3(), osg::Vec3(1.0f, 0.0f, 0.0f), osg::Vec3(0.0f, 1.0f, 0.0f)); - quad->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture.get()); - - osg::ref_ptr geode = new osg::Geode; - geode->addDrawable(quad.get()); - - osg::Camera *camera = new osg::Camera; - camera->setClearMask(0); - camera->setCullingActive(false); - camera->setAllowEventFocus(false); - camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); - camera->setRenderOrder(osg::Camera::POST_RENDER); - camera->setProjectionMatrix(osg::Matrix::ortho2D(0.0, 1.0, 0.0, 1.0)); - camera->addChild(geode.get()); - - osg::StateSet *ss = camera->getOrCreateStateSet(); - ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - ss->setAttributeAndModes(new osg::Depth(osg::Depth::LEQUAL, 1.0, 1.0)); - - self->setNode(camera); - } -}; - -/* 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"; - delete h; -} - -const QUrl OSGBackgroundNode::imageFile() const -{ - return h->url; -} - -void OSGBackgroundNode::setImageFile(const QUrl &url) -{ - // qDebug() << "OSGBackgroundNode::setImageFile" << url; - if (h->url != url) { - h->url = url; - setDirty(URL); - emit imageFileChanged(url); - } -} - -void OSGBackgroundNode::update() -{ - if (isDirty(URL)) { - h->updateNode(); - } -} - -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/OSGBillboardNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBillboardNode.cpp new file mode 100644 index 000000000..f5a27efba --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBillboardNode.cpp @@ -0,0 +1,94 @@ +/** + ****************************************************************************** + * + * @file OSGBillboardNode.cpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @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 "OSGBillboardNode.hpp" + +#include +#include +#include + +#include + +#include + +namespace osgQtQuick { +// NOTE : these flags should not overlap with OSGGroup flags!!! +// TODO : find a better way... +enum DirtyFlag {}; + +struct OSGBillboardNode::Hidden : public QObject { + Q_OBJECT + +private: + OSGBillboardNode * const self; + + osg::ref_ptr camera; + +public: + Hidden(OSGBillboardNode *self) : QObject(self), self(self) + {} + + osg::Node *createNode() + { + camera = new osg::Camera; + camera->setClearMask(0); + camera->setCullingActive(false); + camera->setAllowEventFocus(false); + camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); + camera->setRenderOrder(osg::Camera::POST_RENDER); + camera->setProjectionMatrix(osg::Matrix::ortho2D(0.0, 1.0, 0.0, 1.0)); + + osg::StateSet *ss = camera->getOrCreateStateSet(); + ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + ss->setAttributeAndModes(new osg::Depth(osg::Depth::LEQUAL, 1.0, 1.0)); + + return camera; + } +}; + +/* class OSGBillboardNode */ + +OSGBillboardNode::OSGBillboardNode(QObject *parent) : Inherited(parent), h(new Hidden(this)) +{} + +OSGBillboardNode::~OSGBillboardNode() +{ + delete h; +} + +osg::Node *OSGBillboardNode::createNode() +{ + return h->createNode(); +} + +void OSGBillboardNode::updateNode() +{ + Inherited::updateNode(); +} +} // namespace osgQtQuick + +#include "OSGBillboardNode.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBillboardNode.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBillboardNode.hpp new file mode 100644 index 000000000..b2edda15c --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBillboardNode.hpp @@ -0,0 +1,54 @@ +/** + ****************************************************************************** + * + * @file OSGBillboardNode.hpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @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_BILLBOARDNODE_H_ +#define _H_OSGQTQUICK_BILLBOARDNODE_H_ + +#include "Export.hpp" +#include "OSGGroup.hpp" + +namespace osgQtQuick { +class OSGQTQUICK_EXPORT OSGBillboardNode : public OSGGroup { + Q_OBJECT + + typedef OSGGroup Inherited; + +public: + OSGBillboardNode(QObject *parent = 0); + virtual ~OSGBillboardNode(); + +protected: + virtual osg::Node *createNode(); + virtual void updateNode(); + +private: + struct Hidden; + Hidden *const h; +}; +} // namespace osgQtQuick + +#endif // _H_OSGQTQUICK_BILLBOARDNODE_H_ diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.cpp index 8c5b873f6..ccc83c1ff 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGCamera.cpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -27,41 +27,45 @@ #include "OSGCamera.hpp" -#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 -public: - Hidden(OSGCamera *camera) : - QObject(camera), self(camera), sceneNode(NULL), - manipulatorMode(ManipulatorMode::Default), trackerMode(TrackerMode::NodeCenterAndAzim), trackNode(NULL), - logDepthBufferEnabled(false), clampToTerrain(false), intoTerrain(false) - { - fieldOfView = 90.0; +private: + OSGCamera * const self; + osg::ref_ptr camera; + +public: + // Camera vertical field of view in degrees + // 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; + + QColor clearColor; + + bool logDepthBufferEnabled; + +#ifdef USE_OSGEARTH + osgEarth::Util::LogarithmicDepthBuffer *logDepthBuffer; +#endif + +public: + Hidden(OSGCamera *self) : QObject(self), self(self), fieldOfView(90), clearColor(0, 0, 0, 255), logDepthBufferEnabled(false) + { #ifdef USE_OSGEARTH logDepthBuffer = NULL; #endif @@ -69,97 +73,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); @@ -169,93 +82,36 @@ public: #endif } - void attachManipulator(osgViewer::View *view) + osg::Node *createNode() { - qDebug() << "OSGCamera::attachManipulator" << view; + camera = new osg::Camera(); - osgGA::CameraManipulator *cm = NULL; + camera->setClearColor(osg::Vec4(clearColor.redF(), clearColor.greenF(), clearColor.blueF(), clearColor.alphaF())); - 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; - } + osg::StateSet *stateset = camera->getOrCreateStateSet(); + stateset->setGlobalDefaults(); - 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(); - } + return camera; } - void detachManipulator(osgViewer::View *view) + void updateClearColor() { - qDebug() << "OSGCamera::detachManipulator" << view; - - view->setCameraManipulator(NULL, false); + if (!camera.valid()) { + qDebug() << "OSGCamera::updateClearColor - invalid camera"; + return; + } + // qDebug() << "OSGCamera::updateClearColor" << clearColor; + 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); @@ -265,7 +121,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; @@ -276,113 +141,77 @@ public: camera->setProjectionMatrixAsPerspective(fovy, ar, zn, zf); } - void updatePosition() + void updateLogDepthBuffer() { - if (manipulatorMode != ManipulatorMode::User) { + 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; + // qDebug() << "OSGCamera::updateLogDepthBuffer" << logDepthBufferEnabled; #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); - OSGCamera *const self; + double fovy, ar, zn, zf; + camera->getProjectionMatrixAsPerspective(fovy, ar, zn, zf); - osg::ref_ptr camera; - - // Camera vertical field of view in degrees - qreal fieldOfView; - - OSGNode *sceneNode; - - ManipulatorMode::Enum manipulatorMode; - - // for NodeTrackerManipulator - TrackerMode::Enum trackerMode; - OSGNode *trackNode; - - bool logDepthBufferEnabled; -#ifdef USE_OSGEARTH - osgEarth::Util::LogarithmicDepthBuffer *logDepthBuffer; -#endif - - bool clampToTerrain; - bool intoTerrain; - - QVector3D attitude; - QVector3D position; - -private slots: - void onSceneNodeChanged(osg::Node *node) - { - qDebug() << "OSGCamera::onSceneNodeChanged" << node; - qWarning() << "OSGCamera::onSceneNodeChanged - needs to be implemented"; - } - - 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(QObject *parent) : Inherited(parent), h(new Hidden(this)) +{} OSGCamera::~OSGCamera() { - qDebug() << "OSGCamera::~OSGCamera"; delete h; } +QColor OSGCamera::clearColor() const +{ + return h->clearColor; +} + +void OSGCamera::setClearColor(const QColor &color) +{ + if (h->clearColor != color) { + h->clearColor = color; + emit clearColorChanged(color); + } +} + qreal OSGCamera::fieldOfView() const { return h->fieldOfView; @@ -397,102 +226,7 @@ void OSGCamera::setFieldOfView(qreal arg) } } -OSGNode *OSGCamera::sceneNode() -{ - return h->sceneNode; -} - -void OSGCamera::setSceneNode(OSGNode *node) -{ - if (h->acceptSceneNode(node)) { - emit sceneNodeChanged(node); - } -} - -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() +bool OSGCamera::logarithmicDepthBuffer() const { return h->logDepthBufferEnabled; } @@ -501,32 +235,40 @@ void OSGCamera::setLogarithmicDepthBuffer(bool enabled) { if (h->logDepthBufferEnabled != enabled) { h->logDepthBufferEnabled = enabled; + setDirty(LogDepthBuffer); emit logarithmicDepthBufferChanged(logarithmicDepthBuffer()); } } -void OSGCamera::update() +osg::Node *OSGCamera::createNode() { + return h->createNode(); +} + +void OSGCamera::updateNode() +{ + Inherited::updateNode(); + + 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) +osg::Camera *OSGCamera::asCamera() const { - h->attachCamera(view->getCamera()); - h->attachManipulator(view); - update(); - clearDirty(); + // BAD introduce templating + return (osg::Camera *)node(); } -void OSGCamera::detach(osgViewer::View *view) +void OSGCamera::setGraphicsContext(osg::GraphicsContext *gc) { - h->detachManipulator(view); - h->detachCamera(view->getCamera()); + h->setGraphicsContext(gc); } } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.hpp index 48a2d4ace..812c5b897 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGCamera.hpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGCamera.hpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -32,114 +32,51 @@ #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(qreal fieldOfView READ fieldOfView WRITE setFieldOfView NOTIFY fieldOfViewChanged) - Q_PROPERTY(osgQtQuick::OSGNode * sceneNode READ sceneNode WRITE setSceneNode NOTIFY sceneNodeChanged) - 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_OBJECT Q_PROPERTY(QColor clearColor READ clearColor WRITE setClearColor NOTIFY clearColorChanged) + Q_PROPERTY(qreal fieldOfView READ fieldOfView WRITE setFieldOfView NOTIFY fieldOfViewChanged) Q_PROPERTY(bool logarithmicDepthBuffer READ logarithmicDepthBuffer WRITE setLogarithmicDepthBuffer NOTIFY logarithmicDepthBufferChanged) + typedef OSGNode Inherited; + friend class OSGViewport; public: explicit OSGCamera(QObject *parent = 0); virtual ~OSGCamera(); - // 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° + QColor clearColor() const; + void setClearColor(const QColor &color); + qreal fieldOfView() const; void setFieldOfView(qreal arg); - OSGNode *sceneNode(); - void setSceneNode(OSGNode *node); - - 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(); + bool logarithmicDepthBuffer() const; void setLogarithmicDepthBuffer(bool enabled); signals: + void clearColorChanged(const QColor &color); void fieldOfViewChanged(qreal arg); - - void sceneNodeChanged(OSGNode *node); - - 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); +protected: + virtual osg::Node *createNode(); + virtual void updateNode(); + private: struct Hidden; - Hidden *h; + Hidden *const h; - virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); + osg::Camera *asCamera() const; + void setGraphicsContext(osg::GraphicsContext *gc); }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGFileNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGFileNode.cpp index a9ba9dba2..196f9fe0b 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGFileNode.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGFileNode.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGFileNode.cpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -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() + void updateSource() { - // 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,11 @@ 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(QObject *parent) : Inherited(parent), h(new Hidden(this)) +{} OSGFileNode::~OSGFileNode() { - // qDebug() << "OSGFileNode::~OSGFileNode"; delete h; } @@ -161,7 +161,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 +175,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 +189,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); @@ -199,8 +196,16 @@ void OSGFileNode::setOptimizeMode(OptimizeMode::Enum optimizeMode) } } -void OSGFileNode::update() +osg::Node *OSGFileNode::createNode() { + // node is created later + return NULL; +} + +void OSGFileNode::updateNode() +{ + Inherited::updateNode(); + if (isDirty(Async)) { // do nothing... } @@ -208,18 +213,9 @@ void OSGFileNode::update() // TODO: trigger a node update ? } if (isDirty(Source)) { - h->updateNode(); + h->updateSource(); } } - -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 9ea870507..4057c05ac 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGFileNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGFileNode.hpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGFileNode.hpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -39,6 +39,7 @@ QT_END_NAMESPACE namespace osgQtQuick { class OSGQTQUICK_EXPORT OptimizeMode : public QObject { Q_OBJECT + public: enum Enum { None, Optimize, OptimizeAndCheck }; Q_ENUMS(Enum) // TODO switch to Q_ENUM once on Qt 5.5 @@ -49,6 +50,8 @@ class OSGQTQUICK_EXPORT OSGFileNode : public OSGNode { Q_PROPERTY(bool async READ async WRITE setAsync NOTIFY asyncChanged) Q_PROPERTY(osgQtQuick::OptimizeMode::Enum optimizeMode READ optimizeMode WRITE setOptimizeMode NOTIFY optimizeModeChanged) + typedef OSGNode Inherited; + public: OSGFileNode(QObject *parent = 0); virtual ~OSGFileNode(); @@ -67,14 +70,13 @@ signals: void asyncChanged(const bool async); void optimizeModeChanged(OptimizeMode::Enum); +protected: + virtual osg::Node *createNode(); + virtual void updateNode(); + private: struct Hidden; - Hidden *h; - - virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); + Hidden *const h; }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGeoTransformNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGeoTransformNode.cpp index 66287942c..f32e0ba56 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGeoTransformNode.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGeoTransformNode.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGGeoTransformNode.cpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -27,7 +27,7 @@ #include "OSGGeoTransformNode.hpp" -#include "../utility.h" +#include "utils/utility.h" #include @@ -38,6 +38,10 @@ #include namespace osgQtQuick { +// NOTE : these flags should not overlap with OSGGroup flags!!! +// TODO : find a better way... +enum DirtyFlag { Scene = 1 << 10, Position = 1 << 11, Clamp = 1 << 12 }; + struct OSGGeoTransformNode::Hidden : public QObject { Q_OBJECT @@ -47,7 +51,6 @@ private: osg::ref_ptr transform; public: - OSGNode *childNode; OSGNode *sceneNode; float offset; @@ -57,31 +60,14 @@ 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), sceneNode(NULL), offset(-1.0), clampToTerrain(false), intoTerrain(false) + {} + + osg::Node *createNode() { transform = new osgEarth::GeoTransform(); transform->setAutoRecomputeHeights(true); - self->setNode(transform); - } - - bool acceptChildNode(OSGNode *node) - { - qDebug() << "OSGGeoTransformNode::acceptChildNode" << node; - if (childNode == node) { - return false; - } - - if (childNode) { - disconnect(childNode); - } - - childNode = node; - - if (childNode) { - connect(childNode, SIGNAL(nodeChanged(osg::Node *)), this, SLOT(onChildNodeChanged(osg::Node *))); - } - - return true; + return transform; } bool acceptSceneNode(OSGNode *node) @@ -98,37 +84,15 @@ public: sceneNode = node; if (sceneNode) { - connect(sceneNode, SIGNAL(nodeChanged(osg::Node *)), this, SLOT(onSceneNodeChanged(osg::Node *))); + connect(sceneNode, &OSGNode::nodeChanged, this, &OSGGeoTransformNode::Hidden::onSceneNodeChanged); } return true; } - void updateTransformNode() - { - bool updated = false; - - if (transform->getNumChildren() == 0) { - if (childNode && childNode->node()) { - updated |= transform->addChild(childNode->node()); - } - } else { - if (childNode && childNode->node()) { - if (transform->getChild(0) != childNode->node()) { - updated |= transform->removeChild(0, 1); - updated |= transform->addChild(childNode->node()); - } - } else { - updated |= transform->removeChild(0, 1); - } - } - // if (updated) { - self->emitNodeChanged(); - // } - } - void updateSceneNode() { + qDebug() << "OSGGeoTransformNode::updateSceneNode" << sceneNode; if (sceneNode && sceneNode->node()) { osgEarth::MapNode *mapNode = osgEarth::MapNode::findMapNode(sceneNode->node()); if (mapNode) { @@ -141,15 +105,20 @@ public: void updatePosition() { + // 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); @@ -160,7 +129,7 @@ public: // get "size" of model // TODO this should be done once only... osg::ComputeBoundsVisitor cbv; - childNode->node()->accept(cbv); + transform->accept(cbv); const osg::BoundingBox & bbox = cbv.getBoundingBox(); offset = bbox.radius(); @@ -168,53 +137,33 @@ 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); } private slots: - void onChildNodeChanged(osg::Node *node) - { - qDebug() << "OSGGeoTransformNode::onChildNodeChanged" << node; - updateTransformNode(); - } - 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(QObject *parent) : Inherited(parent), h(new Hidden(this)) +{} OSGGeoTransformNode::~OSGGeoTransformNode() { - // qDebug() << "OSGGeoTransformNode::~OSGGeoTransformNode"; delete h; } -OSGNode *OSGGeoTransformNode::childNode() -{ - return h->childNode; -} - -void OSGGeoTransformNode::setChildNode(OSGNode *node) -{ - if (h->acceptChildNode(node)) { - setDirty(Child); - emit childNodeChanged(node); - } -} - -OSGNode *OSGGeoTransformNode::sceneNode() +OSGNode *OSGGeoTransformNode::sceneNode() const { return h->sceneNode; } @@ -260,32 +209,25 @@ void OSGGeoTransformNode::setPosition(QVector3D arg) } } -void OSGGeoTransformNode::update() +osg::Node *OSGGeoTransformNode::createNode() { - if (isDirty(Child)) { - h->updateTransformNode(); - } + return h->createNode(); +} + +void OSGGeoTransformNode::updateNode() +{ + Inherited::updateNode(); + if (isDirty(Scene)) { h->updateSceneNode(); } - if (isDirty(Clamp)) {} - if (isDirty(Position)) { + if (isDirty(Clamp)) { + // do nothing... + } + if (isDirty(Scene | Clamp | 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 9c2d81ccf..29f41eac8 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGeoTransformNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGeoTransformNode.hpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGGeoTransformNode.hpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -29,32 +29,24 @@ #define _H_OSGQTQUICK_GEOTRANSFORMNODE_H_ #include "Export.hpp" -#include "OSGNode.hpp" +#include "OSGGroup.hpp" #include -// TODO derive from OSGGroup... 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 * sceneData READ sceneNode WRITE setSceneNode NOTIFY sceneNodeChanged) - +class OSGQTQUICK_EXPORT OSGGeoTransformNode : public OSGGroup { + Q_OBJECT Q_PROPERTY(osgQtQuick::OSGNode *sceneNode READ sceneNode WRITE setSceneNode NOTIFY sceneNodeChanged) Q_PROPERTY(bool clampToTerrain READ clampToTerrain WRITE setClampToTerrain NOTIFY clampToTerrainChanged) Q_PROPERTY(bool intoTerrain READ intoTerrain NOTIFY intoTerrainChanged) - Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged) + typedef OSGGroup Inherited; + public: OSGGeoTransformNode(QObject *parent = 0); virtual ~OSGGeoTransformNode(); - OSGNode *childNode(); - void setChildNode(OSGNode *node); - - OSGNode *sceneNode(); + OSGNode *sceneNode() const; void setSceneNode(OSGNode *node); bool clampToTerrain() const; @@ -66,23 +58,18 @@ public: void setPosition(QVector3D arg); signals: - void childNodeChanged(OSGNode *node); - void sceneNodeChanged(OSGNode *node); - void clampToTerrainChanged(bool arg); void intoTerrainChanged(bool arg); - void positionChanged(QVector3D arg); +protected: + virtual osg::Node *createNode(); + virtual void updateNode(); + private: struct Hidden; - Hidden *h; - - virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); + Hidden *const h; }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.cpp index 4918360d4..95e1afb30 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGGroup.cpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -39,26 +39,26 @@ struct OSGGroup::Hidden : public QObject { Q_OBJECT private: - OSGGroup * self; - - osg::ref_ptr group; + OSGGroup * const self; QMap cache; -public: - Hidden(OSGGroup *node) : QObject(node), self(node), group(new osg::Group) - { - group = new osg::Group(); - self->setNode(group); - } - QList children; +public: + Hidden(OSGGroup *self) : QObject(self), self(self) + {} + + osg::Node *createNode() + { + return new osg::Group(); + } + void appendChild(OSGNode *childNode) { - cache[childNode] = childNode->node(); + // qDebug() << "OSGGroup::appendChild" << childNode; children.append(childNode); - connect(childNode, SIGNAL(nodeChanged(osg::Node *)), this, SLOT(onChildNodeChanged(osg::Node *)), Qt::UniqueConnection); + connect(childNode, &OSGNode::nodeChanged, this, &osgQtQuick::OSGGroup::Hidden::onChildNodeChanged, Qt::UniqueConnection); self->setDirty(Children); } @@ -86,27 +86,39 @@ public: self->setDirty(Children); } - void updateGroupNode() + void updateChildren() { + qDebug() << "OSGGroup::updateChildren"; + + osg::Group *group = static_cast(self->node()); + if (!group) { + qWarning() << "OSGGroup::updateChildren - null group"; + return; + } + bool updated = false; unsigned int index = 0; QListIterator i(children); while (i.hasNext()) { OSGNode *childNode = i.next(); - if (index < group->getNumChildren()) { - updated |= group->replaceChild(group->getChild(index), childNode->node()); - } else { - updated |= group->addChild(childNode->node()); + // qDebug() << "OSGGroup::updateChildren - child" << childNode; + if (childNode->node()) { + if (index < group->getNumChildren()) { + updated |= group->replaceChild(group->getChild(index), childNode->node()); + } else { + updated |= group->addChild(childNode->node()); + } + cache.insert(childNode, childNode->node()); + index++; } - index++; } // removing eventual left overs if (index < group->getNumChildren()) { updated |= group->removeChild(index, group->getNumChildren() - index); } // if (updated) { - self->emitNodeChanged(); + // self->emitNodeChanged(); // } } @@ -141,37 +153,53 @@ public: } private slots: - void onChildNodeChanged(osg::Node *node) + void onChildNodeChanged(osg::Node *child) { - qDebug() << "OSGGroup::onChildNodeChanged" << node; - OSGNode *obj = qobject_cast(sender()); - if (obj) { - osg::Node *cacheNode = cache.value(obj, NULL); - if (cacheNode) { - group->replaceChild(cacheNode, node); - } else { - // should not happen... - } - cache[obj] = node; - // emit self->nodeChanged(group.get()); + // qDebug() << "OSGGroup::onChildNodeChanged" << node; + + osg::Group *group = static_cast(self->node()); + + if (!group) { + qWarning() << "OSGGroup::onChildNodeChanged - null group"; + return; } + + OSGNode *childNode = qobject_cast(sender()); + // qDebug() << "OSGGroup::onChildNodeChanged - child node" << obj; + if (!childNode) { + qWarning() << "OSGGroup::onChildNodeChanged - sender is not an OSGNode" << sender(); + return; + } + if (childNode->node() != child) { + qWarning() << "OSGGroup::onChildNodeChanged - child node is not valid" << childNode; + return; + } + bool updated = false; + osg::Node *current = cache.value(childNode, NULL); + if (current) { + updated |= group->replaceChild(current, child); + } else { + // should not happen... + qWarning() << "OSGGroup::onChildNodeChanged - child node is not a child" << childNode; + } + cache[childNode] = childNode->node(); + // if (updated) { + // emit self->nodeChanged(group.get()); + // } } }; /* class OSGGGroupNode */ -OSGGroup::OSGGroup(QObject *parent) : OSGNode(parent), h(new Hidden(this)) -{ - qDebug() << "OSGGroup::OSGGroup"; -} +OSGGroup::OSGGroup(QObject *parent) : Inherited(parent), h(new Hidden(this)) +{} OSGGroup::~OSGGroup() { - // qDebug() << "OSGGroup::~OSGGroup"; delete h; } -QQmlListProperty OSGGroup::children() +QQmlListProperty OSGGroup::children() const { return QQmlListProperty(h, 0, &Hidden::append_child, @@ -180,34 +208,17 @@ QQmlListProperty OSGGroup::children() &Hidden::clear_child); } -void OSGGroup::update() +osg::Node *OSGGroup::createNode() { + return h->createNode(); +} + +void OSGGroup::updateNode() +{ + Inherited::updateNode(); + if (isDirty(Children)) { - 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); + h->updateChildren(); } } } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.hpp index c9a95a516..00a8c7314 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGGroup.hpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGGroup.hpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -39,20 +39,21 @@ class OSGQTQUICK_EXPORT OSGGroup : public OSGNode { Q_CLASSINFO("DefaultProperty", "children") + typedef OSGNode Inherited; + public: explicit OSGGroup(QObject *parent = 0); virtual ~OSGGroup(); - QQmlListProperty children(); + QQmlListProperty children() const; + +protected: + virtual osg::Node *createNode(); + virtual void updateNode(); private: struct Hidden; - Hidden *h; - - virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); + Hidden *const h; }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGImageNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGImageNode.cpp new file mode 100644 index 000000000..ab138d979 --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGImageNode.cpp @@ -0,0 +1,128 @@ +/** + ****************************************************************************** + * + * @file OSGImageNode.cpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @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 "OSGImageNode.hpp" + +#include + +#include + +#include +#include + +namespace osgQtQuick { +enum DirtyFlag { ImageFile = 1 << 0 }; + +struct OSGImageNode::Hidden : public QObject { + Q_OBJECT + +private: + OSGImageNode * const self; + + osg::ref_ptr texture; + +public: + QUrl url; + + Hidden(OSGImageNode *self) : QObject(self), self(self), url() + {} + + osg::Node *createNode() + { + osg::Drawable *quad = osg::createTexturedQuadGeometry(osg::Vec3(0, 0, 0), osg::Vec3(1, 0, 0), osg::Vec3(0, 1, 0)); + + osg::Geode *geode = new osg::Geode; + + geode->addDrawable(quad); + + geode->setStateSet(createState()); + + return geode; + } + + osg::StateSet *createState() + { + texture = new osg::Texture2D; + + // create the StateSet to store the texture data + osg::StateSet *stateset = new osg::StateSet; + + stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); + + return stateset; + } + + void updateImageFile() + { + qDebug() << "OSGImageNode::updateImageFile - reading image file" << url.path(); + osg::Image *image = osgDB::readImageFile(url.path().toStdString()); + if (texture.valid()) { + texture->setImage(image); + } + } +}; + +/* class OSGImageNode */ + +OSGImageNode::OSGImageNode(QObject *parent) : Inherited(parent), h(new Hidden(this)) +{} + +OSGImageNode::~OSGImageNode() +{ + delete h; +} + +const QUrl OSGImageNode::imageFile() const +{ + return h->url; +} + +void OSGImageNode::setImageFile(const QUrl &url) +{ + if (h->url != url) { + h->url = url; + setDirty(ImageFile); + emit imageFileChanged(url); + } +} + +osg::Node *OSGImageNode::createNode() +{ + return h->createNode(); +} + +void OSGImageNode::updateNode() +{ + Inherited::updateNode(); + + if (isDirty(ImageFile)) { + h->updateImageFile(); + } +} +} // namespace osgQtQuick + +#include "OSGImageNode.moc" diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBackgroundNode.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGImageNode.hpp similarity index 73% rename from ground/gcs/src/libs/osgearth/osgQtQuick/OSGBackgroundNode.hpp rename to ground/gcs/src/libs/osgearth/osgQtQuick/OSGImageNode.hpp index 746da7615..f543a0b54 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGBackgroundNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGImageNode.hpp @@ -1,8 +1,8 @@ /** ****************************************************************************** * - * @file OSGBackgroundNode.hpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @file OSGImageNode.hpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -25,24 +25,23 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _H_OSGQTQUICK_BACKGROUNDNODE_H_ -#define _H_OSGQTQUICK_BACKGROUNDNODE_H_ +#ifndef _H_OSGQTQUICK_IMAGENODE_H_ +#define _H_OSGQTQUICK_IMAGENODE_H_ #include "Export.hpp" #include "OSGNode.hpp" #include -QT_BEGIN_NAMESPACE -class QUrl; -QT_END_NAMESPACE namespace osgQtQuick { -class OSGQTQUICK_EXPORT OSGBackgroundNode : public OSGNode { +class OSGQTQUICK_EXPORT OSGImageNode : public OSGNode { Q_OBJECT Q_PROPERTY(QUrl imageFile READ imageFile WRITE setImageFile NOTIFY imageFileChanged) + typedef OSGNode Inherited; + public: - OSGBackgroundNode(QObject *parent = 0); - virtual ~OSGBackgroundNode(); + OSGImageNode(QObject *parent = 0); + virtual ~OSGImageNode(); const QUrl imageFile() const; void setImageFile(const QUrl &url); @@ -50,15 +49,14 @@ public: signals: void imageFileChanged(const QUrl &url); +protected: + virtual osg::Node *createNode(); + virtual void updateNode(); + private: struct Hidden; - Hidden *h; - - virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); + Hidden *const h; }; } // namespace osgQtQuick -#endif // _H_OSGQTQUICK_BACKGROUNDNODE_H_ +#endif // _H_OSGQTQUICK_IMAGENODE_H_ diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGNode.cpp index 1bbcb50e5..7e78bb0bb 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGNode.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGNode.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGNode.cpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -27,75 +27,39 @@ #include "OSGNode.hpp" +#include "DirtySupport.hpp" + #include -#include #include namespace osgQtQuick { class OSGNode; -class Hidden; -struct NodeUpdateCallback : public osg::NodeCallback { -public: - NodeUpdateCallback(OSGNode::Hidden *h) : h(h) {} - - void operator()(osg::Node *node, osg::NodeVisitor *nv); - -private: - OSGNode::Hidden *const h; -}; - -struct OSGNode::Hidden : public QObject { +struct OSGNode::Hidden : public QObject, public DirtySupport { Q_OBJECT friend class OSGNode; +private: + OSGNode *const self; + + osg::ref_ptr node; + + bool complete; + 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) + osg::Node *nodeToUpdate() const { - 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); - } - } - dirty |= mask; - // qDebug() << "OSGNode::setDirty DONE"; - } - - void clearDirty() - { - dirty = 0; - if (node && nodeUpdateCallback.valid()) { - // qDebug() << "OSGNode::clearDirty REMOVE CALLBACK"; - node->setUpdateCallback(NULL); - } + return self->node(); } void update() { - // qDebug() << "OSGNode::update BEGIN"; - if (dirty) { - // qDebug() << "OSGNode::update UPDATE"; - self->update(); - } - clearDirty(); - // qDebug() << "OSGNode::update DONE"; + return self->updateNode(); } bool acceptNode(osg::Node *aNode) @@ -103,43 +67,24 @@ public: if (node == aNode) { return false; } - if (node && dirty) { - // qDebug() << "OSGNode::acceptNode REMOVE CALLBACK" << node; - node->setUpdateCallback(NULL); + + int flags = dirty(); + if (flags) { + clearDirty(); } node = aNode; if (node) { - if (dirty) { - if (!nodeUpdateCallback.valid()) { - // lazy creation - // qDebug() << "OSGNode::acceptNode CREATE CALLBACK"; - nodeUpdateCallback = new NodeUpdateCallback(this); - } - // qDebug() << "OSGNode::acceptNode ADD CALLBACK"; - node->setUpdateCallback(nodeUpdateCallback); + if (flags) { + setDirty(flags); } } return true; } - -private: - OSGNode *const self; - - osg::ref_ptr node; - - osg::ref_ptr nodeUpdateCallback; - - int dirty; }; -void NodeUpdateCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) -{ - // qDebug() << "NodeUpdateCallback::"; - nv->traverse(*node); - h->update(); -} +/* class OSGNode */ -OSGNode::OSGNode(QObject *parent) : QObject(parent), h(new Hidden(this)) +OSGNode::OSGNode(QObject *parent) : QObject(parent), QQmlParserStatus(), h(new Hidden(this)) {} OSGNode::~OSGNode() @@ -155,16 +100,11 @@ osg::Node *OSGNode::node() const void OSGNode::setNode(osg::Node *node) { if (h->acceptNode(node)) { - emit nodeChanged(node); + emitNodeChanged(); } } -bool OSGNode::isDirty() -{ - return h->isDirty(0xFFFFFFFF); -} - -bool OSGNode::isDirty(int mask) +bool OSGNode::isDirty(int mask) const { return h->isDirty(mask); } @@ -179,30 +119,39 @@ void OSGNode::clearDirty() h->clearDirty(); } -void OSGNode::attach(OSGNode *node, osgViewer::View *view) +osg::Node *OSGNode::createNode() { - if (!node) { - return; - } - node->attach(view); + return NULL; } -void OSGNode::detach(OSGNode *node, osgViewer::View *view) +void OSGNode::updateNode() +{} + +void OSGNode::emitNodeChanged() { - if (!node) { - return; + if (h->complete) { + emit nodeChanged(node()); } - node->detach(view); } -void OSGNode::update() -{} +void OSGNode::classBegin() +{ + // qDebug() << "OSGNode::classBegin" << this; -void OSGNode::attach(osgViewer::View *view) -{} + setNode(createNode()); +} -void OSGNode::detach(osgViewer::View *view) -{} +void OSGNode::componentComplete() +{ + // qDebug() << "OSGNode::componentComplete" << this; + + updateNode(); + clearDirty(); + h->complete = true; + if (!h->node.valid()) { + qWarning() << "OSGNode::componentComplete - node is not valid!" << this; + } +} } // 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 e4690afb8..3b998aa6a 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGNode.hpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGNode.hpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -31,6 +31,7 @@ #include "Export.hpp" #include +#include /** * Only update() methods are allowed to update the OSG scenegraph. @@ -39,25 +40,19 @@ * - node change events should be handled right away. * * Setting an OSGNode dirty will trigger the addition of a one time update callback. - * * * This approach leads to some potential issues: * - 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 - - friend class OSGViewport; - friend class NodeUpdateCallback; + Q_INTERFACES(QQmlParserStatus) public: explicit OSGNode(QObject *parent = 0); @@ -66,31 +61,25 @@ public: osg::Node *node() const; void setNode(osg::Node *node); -protected: - bool isDirty(); - bool isDirty(int mask); - void setDirty(int mask); - void clearDirty(); - - void emitNodeChanged() - { - emit nodeChanged(node()); - } - - void attach(OSGNode *node, osgViewer::View *view); - void detach(OSGNode *node, osgViewer::View *view); - signals: void nodeChanged(osg::Node *node) const; +protected: + bool isDirty(int mask = 0xFFFF) const; + void setDirty(int mask = 0xFFFF); + void clearDirty(); + + virtual osg::Node *createNode(); + virtual void updateNode(); + + void emitNodeChanged(); + + void classBegin(); + void componentComplete(); + private: struct Hidden; - Hidden *h; - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); - - virtual void update(); + Hidden *const h; }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGShapeNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGShapeNode.cpp index cffd64255..b8ddb9158 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGShapeNode.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGShapeNode.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGShapeNode.cpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -27,7 +27,7 @@ #include "OSGShapeNode.hpp" -#include "../shapeutils.h" +#include "utils/shapeutils.h" #include #include @@ -37,19 +37,21 @@ #include namespace osgQtQuick { +enum DirtyFlag { ShapeType = 1 << 0 }; + struct OSGShapeNode::Hidden : public QObject { Q_OBJECT private: - OSGShapeNode * self; + OSGShapeNode * const self; 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() + void updateShapeType() { osg::Node *node = NULL; @@ -67,26 +69,19 @@ public: node = ShapeUtils::create3DAxis(); break; } - // Add the node to the scene self->setNode(node); } }; /* 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)) +OSGShapeNode::OSGShapeNode(QObject *parent) : Inherited(parent), h(new Hidden(this)) { - qDebug() << "OSGShapeNode::OSGShapeNode"; - setShapeType(ShapeType::Sphere); + setDirty(ShapeType); } OSGShapeNode::~OSGShapeNode() { - // qDebug() << "OSGShapeNode::~OSGShapeNode"; delete h; } @@ -99,26 +94,24 @@ void OSGShapeNode::setShapeType(ShapeType::Enum type) { if (h->shapeType != type) { h->shapeType = type; - setDirty(Type); + setDirty(ShapeType); emit shapeTypeChanged(type); } } -void OSGShapeNode::update() +osg::Node *OSGShapeNode::createNode() { - if (isDirty(Type)) { - h->updateNode(); + return NULL; +} + +void OSGShapeNode::updateNode() +{ + Inherited::updateNode(); + + if (isDirty(ShapeType)) { + h->updateShapeType(); } } - -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 409779d4f..9a37b9086 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGShapeNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGShapeNode.hpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGShapeNode.hpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -42,6 +42,8 @@ public: class OSGQTQUICK_EXPORT OSGShapeNode : public OSGNode { Q_OBJECT Q_PROPERTY(osgQtQuick::ShapeType::Enum shapeType READ shapeType WRITE setShapeType NOTIFY shapeTypeChanged) + typedef OSGNode Inherited; + public: OSGShapeNode(QObject *parent = 0); virtual ~OSGShapeNode(); @@ -52,14 +54,13 @@ public: signals: void shapeTypeChanged(ShapeType::Enum); +protected: + virtual osg::Node *createNode(); + virtual void updateNode(); + private: struct Hidden; - Hidden *h; - - virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); + Hidden *const h; }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGSkyNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGSkyNode.cpp index f23f69770..e14ac7541 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGSkyNode.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGSkyNode.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGSkyNode.cpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -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(); } @@ -76,27 +82,28 @@ public: sceneNode = node; if (sceneNode) { - connect(sceneNode, SIGNAL(nodeChanged(osg::Node *)), this, SLOT(onSceneNodeChanged(osg::Node *))); + connect(sceneNode, &OSGNode::nodeChanged, this, &OSGSkyNode::Hidden::onSceneNodeChanged); } return true; } - void updateSkyNode() + void updateScene() { if (!sceneNode || !sceneNode->node()) { - qWarning() << "OSGSkyNode::acceptNode - scene node not valid"; + qWarning() << "OSGSkyNode::updateScene - scene node not valid"; self->setNode(NULL); return; } + qDebug() << "OSGSkyNode::updateScene - 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::updateScene - 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::updateScene - map node is not geocentric"; self->setNode(NULL); return; } @@ -117,7 +124,7 @@ public: } else { skyNode->removeChild(0, 1); skyNode->addChild(sceneNode->node()); - self->emitNodeChanged(); + // self->emitNodeChanged(); } } @@ -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; @@ -193,28 +217,23 @@ private slots: void onSceneNodeChanged(osg::Node *node) { qDebug() << "OSGSkyNode::onSceneNodeChanged" << node; - updateSkyNode(); + updateScene(); } }; /* class OSGSkyNode */ -enum DirtyFlag { Child = 1 << 0, DateTime = 1 << 1, Light = 1 << 2 }; - -OSGSkyNode::OSGSkyNode(QObject *parent) : OSGNode(parent), h(new Hidden(this)) +OSGSkyNode::OSGSkyNode(QObject *parent) : Inherited(parent), h(new Hidden(this)) { - qDebug() << "OSGSkyNode::OSGSkyNode"; - setSunLightEnabled(true); - setMinimumAmbientLight(0.03); + setDirty(DateTime | Light); } OSGSkyNode::~OSGSkyNode() { - // qDebug() << "OSGSkyNode::~OSGSkyNode"; delete h; } -OSGNode *OSGSkyNode::sceneNode() +OSGNode *OSGSkyNode::sceneNode() const { return h->sceneNode; } @@ -222,12 +241,26 @@ OSGNode *OSGSkyNode::sceneNode() void OSGSkyNode::setSceneNode(OSGNode *node) { if (h->acceptSceneNode(node)) { - setDirty(Child); + setDirty(Scene); emit sceneNodeChanged(node); } } -bool OSGSkyNode::sunLightEnabled() +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; } @@ -241,7 +274,7 @@ void OSGSkyNode::setSunLightEnabled(bool enabled) } } -QDateTime OSGSkyNode::dateTime() +QDateTime OSGSkyNode::dateTime() const { return h->dateTime; } @@ -255,7 +288,7 @@ void OSGSkyNode::setDateTime(QDateTime dateTime) } } -double OSGSkyNode::minimumAmbientLight() +double OSGSkyNode::minimumAmbientLight() const { return h->minimumAmbientLight; } @@ -269,10 +302,20 @@ void OSGSkyNode::setMinimumAmbientLight(double ambient) } } -void OSGSkyNode::update() +osg::Node *OSGSkyNode::createNode() { - if (isDirty(Child)) { - h->updateSkyNode(); + return NULL; +} + +void OSGSkyNode::updateNode() +{ + Inherited::updateNode(); + + if (isDirty(Scene)) { + h->updateScene(); + } + if (isDirty(Viewport)) { + h->updateViewport(); } if (isDirty(Light)) { h->updateSunLightEnabled(); @@ -282,23 +325,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 b3332916f..3640610a3 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGSkyNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGSkyNode.hpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGSkyNode.hpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -43,45 +43,52 @@ class QUrl; QT_END_NAMESPACE namespace osgQtQuick { -class OSGQTQUICK_EXPORT OSGSkyNode : public OSGNode { - // TODO rename to sceneNode - Q_OBJECT Q_PROPERTY(osgQtQuick::OSGNode *sceneData READ sceneNode WRITE setSceneNode NOTIFY sceneNodeChanged) +class OSGViewport; +// TODO should derive from OSGGroup +class OSGQTQUICK_EXPORT OSGSkyNode : public OSGNode { + Q_OBJECT Q_PROPERTY(osgQtQuick::OSGNode *sceneNode 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) Q_PROPERTY(double minimumAmbientLight READ minimumAmbientLight WRITE setMinimumAmbientLight NOTIFY minimumAmbientLightChanged) + typedef OSGNode Inherited; + public: OSGSkyNode(QObject *parent = 0); virtual ~OSGSkyNode(); - OSGNode *sceneNode(); + OSGNode *sceneNode() const; void setSceneNode(OSGNode *node); - bool sunLightEnabled(); + OSGViewport *viewport() const; + void setViewport(OSGViewport *viewport); + + bool sunLightEnabled() const; void setSunLightEnabled(bool arg); - QDateTime dateTime(); + QDateTime dateTime() const; void setDateTime(QDateTime arg); - double minimumAmbientLight(); + double minimumAmbientLight() const; void setMinimumAmbientLight(double arg); signals: void sceneNodeChanged(OSGNode *node); + void viewportChanged(OSGViewport *viewport); void sunLightEnabledChanged(bool arg); void dateTimeChanged(QDateTime arg); void minimumAmbientLightChanged(double arg); +protected: + virtual osg::Node *createNode(); + virtual void updateNode(); + private: struct Hidden; - Hidden *h; - - virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); + Hidden *const h; }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTextNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTextNode.cpp index 43fcaefd1..05624f809 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTextNode.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTextNode.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGTextNode.cpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -27,7 +27,7 @@ #include "OSGTextNode.hpp" -#include "../utility.h" +#include "utils/utility.h" #include #include @@ -37,6 +37,8 @@ #include namespace osgQtQuick { +enum DirtyFlag { Text = 1 << 0, Color = 1 << 1 }; + struct OSGTextNode::Hidden : public QObject { Q_OBJECT @@ -49,24 +51,24 @@ public: QString textString; QColor color; - Hidden(OSGTextNode *node) : QObject(node), self(node) + Hidden(OSGTextNode *self) : QObject(self), self(self) + {} + + osg::Node *createNode() { osg::ref_ptr textFont = createFont(QFont("Times")); - text = createText(osg::Vec3(-100, 20, 0), "Hello World", 20.0f, - textFont.get()); - osg::ref_ptr textGeode = new osg::Geode(); + text = createText(osg::Vec3(-100, 20, 0), "Hello World", 20.0f, textFont.get()); + osg::ref_ptr textGeode = new osg::Geode(); textGeode->addDrawable(text.get()); #if 0 text->setAutoRotateToScreen(true); - self->setNode(textGeode.get()); #else osg::Camera *camera = createHUDCamera(-100, 100, -100, 100); camera->addChild(textGeode.get()); - camera->getOrCreateStateSet()->setMode( - GL_LIGHTING, osg::StateAttribute::OFF); - self->setNode(camera); + camera->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); #endif + return text; } void updateText() @@ -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) : Inherited(parent), h(new Hidden(this)) +{ + setDirty(Text | Color); +} OSGTextNode::~OSGTextNode() { @@ -126,8 +128,15 @@ void OSGTextNode::setColor(const QColor &color) } } -void OSGTextNode::update() +osg::Node *OSGTextNode::createNode() { + return h->createNode(); +} + +void OSGTextNode::updateNode() +{ + Inherited::updateNode(); + if (isDirty(Text)) { h->updateText(); } @@ -135,15 +144,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 aa3deb770..0232b4335 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTextNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTextNode.hpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGTextNode.hpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -38,6 +38,8 @@ class OSGQTQUICK_EXPORT OSGTextNode : public OSGNode { Q_OBJECT Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) + typedef OSGNode Inherited; + public: explicit OSGTextNode(QObject *parent = 0); virtual ~OSGTextNode(); @@ -52,14 +54,13 @@ signals: void textChanged(const QString &text); void colorChanged(const QColor &color); +protected: + virtual osg::Node *createNode(); + virtual void updateNode(); + private: struct Hidden; - Hidden *h; - - virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); + Hidden *const h; }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTransformNode.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTransformNode.cpp index 816b3f3d5..0b28bb3d2 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTransformNode.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTransformNode.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGTransformNode.cpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -34,6 +34,10 @@ #include namespace osgQtQuick { +// NOTE : these flags should not overlap with OSGGroup flags!!! +// TODO : find a better way... +enum DirtyFlag { Scale = 1 << 10, Position = 1 << 11, Attitude = 1 << 12 }; + struct OSGTransformNode::Hidden : public QObject { Q_OBJECT @@ -43,63 +47,22 @@ private: osg::ref_ptr transform; public: - OSGNode *childNode; - QVector3D scale; QVector3D attitude; QVector3D position; - Hidden(OSGTransformNode *node) : QObject(node), self(node), childNode(NULL) + Hidden(OSGTransformNode *self) : QObject(self), self(self) + {} + + osg::Node *createNode() { transform = new osg::PositionAttitudeTransform(); - self->setNode(transform); - } - - bool acceptChildNode(OSGNode *node) - { - qDebug() << "OSGTransformNode::acceptChildNode" << node; - if (childNode == node) { - return false; - } - - if (childNode) { - disconnect(childNode); - } - - childNode = node; - - if (childNode) { - connect(childNode, SIGNAL(nodeChanged(osg::Node *)), this, SLOT(onChildNodeChanged(osg::Node *))); - } - - return true; - } - - void updateTransformNode() - { - bool updated = false; - - if (transform->getNumChildren() == 0) { - if (childNode && childNode->node()) { - updated |= transform->addChild(childNode->node()); - } - } else { - if (childNode && childNode->node()) { - if (transform->getChild(0) != childNode->node()) { - updated |= transform->removeChild(0, 1); - updated |= transform->addChild(childNode->node()); - } - } else { - updated |= transform->removeChild(0, 1); - } - } - // if (updated) { - self->emitNodeChanged(); - // } + return transform; } 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,52 +81,24 @@ public: yaw, osg::Vec3d(0, 0, -1)); transform->setAttitude(q); - - // position - transform->setPosition(osg::Vec3d(position.x(), position.y(), position.z())); } void updatePosition() { transform->setPosition(osg::Vec3d(position.x(), position.y(), position.z())); } - -private slots: - void onChildNodeChanged(osg::Node *node) - { - qDebug() << "OSGTransformNode::onChildNodeChanged" << node; - updateTransformNode(); - } }; /* 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(QObject *parent) : Inherited(parent), h(new Hidden(this)) +{} OSGTransformNode::~OSGTransformNode() { - // qDebug() << "OSGTransformNode::~OSGTransformNode"; delete h; } -OSGNode *OSGTransformNode::childNode() -{ - return h->childNode; -} - -void OSGTransformNode::setChildNode(OSGNode *node) -{ - if (h->acceptChildNode(node)) { - setDirty(Child); - emit childNodeChanged(node); - } -} - QVector3D OSGTransformNode::scale() const { return h->scale; @@ -206,11 +141,15 @@ void OSGTransformNode::setPosition(QVector3D arg) } } -void OSGTransformNode::update() +osg::Node *OSGTransformNode::createNode() { - if (isDirty(Child)) { - h->updateTransformNode(); - } + return h->createNode(); +} + +void OSGTransformNode::updateNode() +{ + Inherited::updateNode(); + if (isDirty(Scale)) { h->updateScale(); } @@ -221,19 +160,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 fb42dd0a8..2ca5cc0e7 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTransformNode.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGTransformNode.hpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGTransformNode.hpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -29,28 +29,22 @@ #define _H_OSGQTQUICK_TRANSFORMNODE_H_ #include "Export.hpp" -#include "OSGNode.hpp" +#include "OSGGroup.hpp" #include -// TODO derive from OSGGroup... namespace osgQtQuick { -class OSGQTQUICK_EXPORT OSGTransformNode : public OSGNode { - Q_OBJECT - // TODO rename to childNode - Q_PROPERTY(osgQtQuick::OSGNode *modelData READ childNode WRITE setChildNode NOTIFY childNodeChanged) - - Q_PROPERTY(QVector3D scale READ scale WRITE setScale NOTIFY scaleChanged) +class OSGQTQUICK_EXPORT OSGTransformNode : public OSGGroup { + Q_OBJECT Q_PROPERTY(QVector3D scale READ scale WRITE setScale NOTIFY scaleChanged) Q_PROPERTY(QVector3D attitude READ attitude WRITE setAttitude NOTIFY attitudeChanged) Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged) + typedef OSGGroup Inherited; + public: OSGTransformNode(QObject *parent = 0); virtual ~OSGTransformNode(); - OSGNode *childNode(); - void setChildNode(OSGNode *node); - QVector3D scale() const; void setScale(QVector3D arg); @@ -61,20 +55,17 @@ public: void setPosition(QVector3D arg); signals: - void childNodeChanged(OSGNode *node); - void scaleChanged(QVector3D arg); void attitudeChanged(QVector3D arg); void positionChanged(QVector3D arg); +protected: + virtual osg::Node *createNode(); + virtual void updateNode(); + private: struct Hidden; - Hidden *h; - - virtual void update(); - - virtual void attach(osgViewer::View *view); - virtual void detach(osgViewer::View *view); + Hidden *const h; }; } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.cpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.cpp index 425e28bf0..de46be9ea 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.cpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGViewport.cpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -27,13 +27,14 @@ #include "OSGViewport.hpp" -#include "../osgearth.h" -#include "../utility.h" +#include "osgearth.h" +#include "utils/utility.h" #include "OSGNode.hpp" #include "OSGCamera.hpp" #include +#include #include #include #include @@ -41,10 +42,7 @@ #include #include #include - -#ifdef USE_OSGEARTH -#include -#endif +#include #include #include @@ -55,10 +53,6 @@ #include -#include -#include - -namespace osgQtQuick { /* Debugging tips - export OSG_NOTIFY_LEVEL=DEBUG @@ -79,18 +73,66 @@ namespace osgQtQuick { TODO : add OSGView to handle multiple views for a given OSGViewport */ + +/* + 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 ... + */ + +namespace osgQtQuick { +// enum DirtyFlag { Scene = 1 << 0, Camera = 1 << 1 }; + +class ViewportRenderer; + struct OSGViewport::Hidden : public QObject { Q_OBJECT -public: + friend ViewportRenderer; - Hidden(OSGViewport *viewport) : QObject(viewport), - self(viewport), - window(NULL), - sceneData(NULL), - camera(NULL), - updateMode(UpdateMode::Discrete), - frameTimer(-1) +private: + OSGViewport *const self; + + QQuickWindow *window; + + int frameTimer; + + osg::ref_ptr gc; + +public: + OSGNode *sceneNode; + OSGCamera *cameraNode; + + osg::ref_ptr viewer; + osg::ref_ptr view; + + OSGCameraManipulator *manipulator; + + UpdateMode::Enum updateMode; + + bool busy; + + static QtKeyboardMap keyMap; + + Hidden(OSGViewport *self) : QObject(self), self(self), window(NULL), frameTimer(-1), + sceneNode(NULL), cameraNode(NULL), manipulator(NULL), updateMode(UpdateMode::OnDemand), busy(false) { OsgEarth::initialize(); @@ -101,7 +143,9 @@ public: ~Hidden() { - stop(); + disconnect(self); + + stopTimer(); destroyViewer(); } @@ -109,195 +153,140 @@ public: public slots: void onWindowChanged(QQuickWindow *window) { - qDebug() << "OSGViewport::onWindowChanged" << window; + // qDebug() << "OSGViewport::onWindowChanged" << window; // 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; } public: - - bool acceptSceneData(OSGNode *node) + bool acceptSceneNode(OSGNode *node) { - qDebug() << "OSGViewport::acceptSceneData" << node; - if (sceneData == node) { + qDebug() << "OSGViewport::acceptSceneNode" << node; + if (sceneNode == node) { return true; } - if (sceneData) { - disconnect(sceneData); + if (sceneNode) { + disconnect(sceneNode); } - sceneData = node; + sceneNode = node; - if (sceneData) { - acceptNode(sceneData->node()); - connect(sceneData, &OSGNode::nodeChanged, this, &Hidden::onNodeChanged); + if (sceneNode) { + connect(sceneNode, &OSGNode::nodeChanged, this, &Hidden::onSceneNodeChanged); } return true; } - bool acceptNode(osg::Node *node) + bool acceptCameraNode(OSGCamera *node) { + qDebug() << "OSGViewport::acceptCameraNode" << node; + if (cameraNode == node) { + return true; + } + + if (cameraNode) { + disconnect(cameraNode); + } + + cameraNode = node; + + if (cameraNode) { + connect(cameraNode, &OSGNode::nodeChanged, this, &Hidden::onCameraNodeChanged); + } + return true; } - void attach(osgViewer::View *view) + bool acceptManipulator(OSGCameraManipulator *m) { - if (!sceneData) { - qWarning() << "OSGViewport::attach - invalid scene!"; - return; - } - // attach scene - attach(view, sceneData->node()); - // attach camera - if (camera) { - camera->attach(view); - } else { - qWarning() << "OSGViewport::attach - no camera!"; - } - } - - void attach(osgViewer::View *view, osg::Node *node) - { - 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!"; + // qDebug() << "OSGViewport::releaseResources"; + 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 acceptUpdateMode(UpdateMode::Enum mode) - { - if (updateMode == mode) { - return true; - } - - updateMode = mode; - - return true; - } - - bool acceptCamera(OSGCamera *camera) - { - qDebug() << "OSGViewport::acceptCamera" << camera; - if (this->camera == camera) { - return true; - } - - this->camera = camera; - - return true; - } - - OSGViewport *self; - - QQuickWindow *window; - - OSGNode *sceneData; - OSGCamera *camera; - - UpdateMode::Enum updateMode; - - int frameTimer; - - osg::ref_ptr viewer; - osg::ref_ptr view; - - static QtKeyboardMap keyMap; - +private: void createViewer() { if (viewer.valid()) { qWarning() << "OSGViewport::createViewer - viewer is valid"; return; } - - qDebug() << "OSGViewport::createViewer"; + // qDebug() << "OSGViewport::createViewer"; viewer = new osgViewer::CompositeViewer(); viewer->setThreadingModel(osgViewer::ViewerBase::SingleThreaded); @@ -306,6 +295,9 @@ public: // disable the default setting of viewer.done() by pressing Escape. viewer->setKeyEventSetsDone(0); // viewer->setQuitEventSetsDone(false); + + view = createView(); + viewer->addView(view); } void destroyViewer() @@ -314,17 +306,25 @@ public: qWarning() << "OSGViewport::destroyViewer - viewer is not valid"; return; } - - qDebug() << "OSGViewport::destroyViewer"; + // qDebug() << "OSGViewport::destroyViewer"; viewer = NULL; } osgViewer::View *createView() { - qDebug() << "OSGViewport::createView"; + // 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())); @@ -350,26 +350,14 @@ public: // 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() { - qDebug() << "OSGViewport::createGraphicsContext"; + // qDebug() << "OSGViewport::createGraphicsContext"; osg::GraphicsContext::Traits *traits = getTraits(); + // traitsInfo(*traits); traits->pbuffer = true; @@ -416,19 +404,19 @@ public: return traits; } - void start() + void startTimer() { - if (updateMode == UpdateMode::Discrete && (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; } } @@ -448,34 +436,38 @@ 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"; + // qDebug() << "ViewportRenderer::ViewportRenderer"; // osgQtQuick::openGLContextInfo(QOpenGLContext::currentContext(), "ViewportRenderer::ViewportRenderer"); h->initializeResources(); - - firstFrame = true; - needToDoFrame = false; } ~ViewportRenderer() { - qDebug() << "ViewportRenderer::~ViewportRenderer"; + // qDebug() << "ViewportRenderer::~ViewportRenderer"; // osgQtQuick::openGLContextInfo(QOpenGLContext::currentContext(), "ViewportRenderer::~ViewportRenderer"); } @@ -495,29 +487,71 @@ public: return; } - if (firstFrame) { + // TODO this is not correct : switching workspaces in GCS will destroy and recreate the renderer (and frameCount is thus reset to 0). + if (frameCount == 0) { h->view->init(); if (!h->viewer->isRealized()) { h->viewer->realize(); } - firstFrame = false; } - needToDoFrame = false; - osg::Viewport *viewport = h->view->getCamera()->getViewport(); - if ((viewport->width() != item->width()) || (viewport->height() != item->height())) { + // we always want to draw the first frame + needToDoFrame = (frameCount == 0); + + // if not on-demand then do frame + if (h->updateMode != UpdateMode::OnDemand) { needToDoFrame = true; - int dpr = h->self->window()->devicePixelRatio(); - h->view->getCamera()->getGraphicsContext()->resized(0, 0, item->width() * dpr, item->height() * dpr); + } + + // check if viewport needs to be resized + // a redraw will be requested if necessary + osg::Viewport *viewport = h->view->getCamera()->getViewport(); + int dpr = h->self->window()->devicePixelRatio(); + int width = item->width() * dpr; + int height = item->height() * dpr; + if ((viewport->width() != width) || (viewport->height() != height)) { + // qDebug() << "*** RESIZE" << frameCount << viewport->width() << "x" << viewport->height() << "->" << width << "x" << height; + needToDoFrame = true; + + // h->view->getCamera()->resize(width, height); + h->view->getCamera()->getGraphicsContext()->resized(0, 0, width, height); + + // trick to force a "home" on first few frames to absorb initial spurious resizes + if (frameCount <= 2) { + h->view->home(); + } + } + + // refresh busy state + // TODO state becomes busy when scene is loading or downloading tiles (should do it only for download) + 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(); } if (!needToDoFrame) { needToDoFrame = h->viewer->checkNeedToDoFrame(); } + // workarounds to osg issues if (!needToDoFrame) { + // issue 1 : if only root node has an update callback checkNeedToDoFrame should return true but does not + // a fix will be submitted to osg (current version is 3.5.1) + if (h->view->getSceneData()) { + needToDoFrame |= !(h->view->getSceneData()->getUpdateCallback() == NULL); + } + } + if (!needToDoFrame) { + // issue 2 : UI events don't trigger a redraw + // this issue should be fixed here... + // event handling needs a lot of attention : + // - sometimes the scene is redrawing continuously (after a drag for example, and single click will stop continuous redraw) + // - some events (simple click for instance) trigger a redraw when not needed + // - in Earth View : continuous zoom (triggered by holding right button and moving mouse up/down) sometimes stops working when holding mouse still after initiating needToDoFrame = !h->view->getEventQueue()->empty(); } if (needToDoFrame) { + // qDebug() << "ViewportRenderer::synchronize - update scene" << frameCount; h->viewer->advance(); h->viewer->eventTraversal(); h->viewer->updateTraversal(); @@ -537,6 +571,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(); @@ -547,6 +583,8 @@ public: // trigger next update update(); } + + ++frameCount; } QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) @@ -556,30 +594,18 @@ public: format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); // format.setSamples(4); - // 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. - // Note that getting the window to get the devicePixelRatio is not great (messing with windows is often a bad idea...) - int dpr = 1; // h->self->window()->devicePixelRatio(); - QOpenGLFramebufferObject *fbo = new QOpenGLFramebufferObject(size.width() / dpr, size.height() / dpr, format); + QOpenGLFramebufferObject *fbo = new QOpenGLFramebufferObject(size.width(), size.height(), format); return fbo; } - -private: - OSGViewport::Hidden *h; - - bool firstFrame; - bool needToDoFrame; }; QtKeyboardMap OSGViewport::Hidden::keyMap = QtKeyboardMap(); /* class OSGViewport */ -OSGViewport::OSGViewport(QQuickItem *parent) : QQuickFramebufferObject(parent), h(new Hidden(this)) +OSGViewport::OSGViewport(QQuickItem *parent) : Inherited(parent), h(new Hidden(this)) { - qDebug() << "OSGViewport::OSGViewport"; // setClearBeforeRendering(false); setMirrorVertically(true); setAcceptHoverEvents(true); @@ -588,10 +614,48 @@ OSGViewport::OSGViewport(QQuickItem *parent) : QQuickFramebufferObject(parent), OSGViewport::~OSGViewport() { - qDebug() << "OSGViewport::~OSGViewport"; delete h; } +OSGNode *OSGViewport::sceneNode() const +{ + return h->sceneNode; +} + +void OSGViewport::setSceneNode(OSGNode *node) +{ + if (h->acceptSceneNode(node)) { + // setDirty(Scene); + emit sceneNodeChanged(node); + } +} + +OSGCamera *OSGViewport::cameraNode() const +{ + return h->cameraNode; +} + +void OSGViewport::setCameraNode(OSGCamera *node) +{ + 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); + } +} + UpdateMode::Enum OSGViewport::updateMode() const { return h->updateMode; @@ -599,95 +663,54 @@ UpdateMode::Enum OSGViewport::updateMode() const void OSGViewport::setUpdateMode(UpdateMode::Enum mode) { - if (h->acceptUpdateMode(mode)) { - emit updateModeChanged(updateMode()); + if (h->updateMode != mode) { + h->updateMode = mode; + emit updateModeChanged(mode); } } -QColor OSGViewport::color() const +bool OSGViewport::busy() const { - const osg::Vec4 osgColor = h->view->getCamera()->getClearColor(); - - return QColor::fromRgbF(osgColor.r(), osgColor.g(), osgColor.b(), osgColor.a()); + return h->busy; } -void OSGViewport::setColor(const QColor &color) +void OSGViewport::setBusy(const bool busy) { - 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); + if (h->busy != busy) { + h->busy = busy; + emit busyChanged(busy); } } -OSGNode *OSGViewport::sceneData() +osgViewer::View *OSGViewport::asView() const { - return h->sceneData; -} - -void OSGViewport::setSceneData(OSGNode *node) -{ - if (h->acceptSceneData(node)) { - emit sceneDataChanged(node); - } -} - -OSGCamera *OSGViewport::camera() -{ - return h->camera; -} - -void OSGViewport::setCamera(OSGCamera *camera) -{ - if (h->acceptCamera(camera)) { - emit cameraChanged(camera); - } + return h->view; } QQuickFramebufferObject::Renderer *OSGViewport::createRenderer() const { - qDebug() << "OSGViewport::createRenderer"; + // qDebug() << "OSGViewport::createRenderer"; // osgQtQuick::openGLContextInfo(QOpenGLContext::currentContext(), "createRenderer"); return new ViewportRenderer(h); } -void OSGViewport::attach(osgViewer::View *view) -{ - // qDebug() << "OSGViewport::attach" << view; - if (h->sceneData) { - h->sceneData->attach(view); - } - h->attach(view); -} - -void OSGViewport::detach(osgViewer::View *view) -{ - qDebug() << "OSGViewport::detach" << view; - h->detach(view); - if (h->sceneData) { - h->sceneData->detach(view); - } -} - void OSGViewport::releaseResources() { - QQuickFramebufferObject::releaseResources(); + // qDebug() << "OSGViewport::releaseResources" << this; + Inherited::releaseResources(); } -// see https://bugreports.qt-project.org/browse/QTBUG-41073 -QSGNode *OSGViewport::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *nodeData) +void OSGViewport::classBegin() { - // qDebug() << "OSGViewport::updatePaintNode"; - if (!node) { - qDebug() << "OSGViewport::updatePaintNode - set transform"; - node = QQuickFramebufferObject::updatePaintNode(node, nodeData); - QSGSimpleTextureNode *n = static_cast(node); - return node; - } - return QQuickFramebufferObject::updatePaintNode(node, nodeData); + // qDebug() << "OSGViewport::classBegin" << this; + Inherited::classBegin(); } +void OSGViewport::componentComplete() +{ + // qDebug() << "OSGViewport::componentComplete" << this; + Inherited::componentComplete(); +} QPointF OSGViewport::mousePoint(QMouseEvent *event) { @@ -785,7 +808,7 @@ void OSGViewport::keyPressEvent(QKeyEvent *event) // among others, it closes popup windows on ESC and forwards the event to the parent widgets // TODO implement // if( _forwardKeyEvents ) - // inherited::keyPressEvent( event ); + // Inherited::keyPressEvent(event); } void OSGViewport::keyReleaseEvent(QKeyEvent *event) @@ -804,7 +827,7 @@ void OSGViewport::keyReleaseEvent(QKeyEvent *event) // among others, it closes popup windows on ESC and forwards the event to the parent widgets // TODO implement // if( _forwardKeyEvents ) - // inherited::keyReleaseEvent( event ); + // Inherited::keyReleaseEvent(event); } } // namespace osgQtQuick diff --git a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.hpp b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.hpp index 4b32398b4..46e6d366e 100644 --- a/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.hpp +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/OSGViewport.hpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file OSGViewport.hpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -30,6 +30,8 @@ #include "Export.hpp" +#include "ga/OSGCameraManipulator.hpp" + #include namespace osgViewer { @@ -49,39 +51,49 @@ public: }; class OSGQTQUICK_EXPORT OSGViewport : public QQuickFramebufferObject { - Q_OBJECT Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) + Q_OBJECT Q_PROPERTY(osgQtQuick::OSGNode *sceneNode READ sceneNode WRITE setSceneNode NOTIFY sceneNodeChanged) + 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(osgQtQuick::OSGNode * sceneData READ sceneData WRITE setSceneData NOTIFY sceneDataChanged) - Q_PROPERTY(osgQtQuick::OSGCamera * camera READ camera WRITE setCamera NOTIFY cameraChanged) + Q_PROPERTY(bool busy READ busy NOTIFY busyChanged) + + typedef QQuickFramebufferObject Inherited; -public: friend class ViewportRenderer; +public: explicit OSGViewport(QQuickItem *parent = 0); virtual ~OSGViewport(); + OSGNode *sceneNode() const; + void setSceneNode(OSGNode *node); + + OSGCamera *cameraNode() const; + void setCameraNode(OSGCamera *node); + + OSGCameraManipulator *manipulator() const; + void setManipulator(OSGCameraManipulator *manipulator); + UpdateMode::Enum updateMode() const; void setUpdateMode(UpdateMode::Enum mode); - QColor color() const; - void setColor(const QColor &color); - - OSGNode *sceneData(); - void setSceneData(OSGNode *node); - - OSGCamera *camera(); - void setCamera(OSGCamera *camera); + bool busy() const; + void setBusy(const bool busy); Renderer *createRenderer() const; void releaseResources(); + osgViewer::View *asView() const; + signals: + void sceneNodeChanged(OSGNode *node); + void cameraNodeChanged(OSGCamera *node); + void manipulatorChanged(OSGCameraManipulator *manipulator); void updateModeChanged(UpdateMode::Enum mode); - void colorChanged(const QColor &color); - void sceneDataChanged(OSGNode *node); - void cameraChanged(OSGCamera *camera); + void busyChanged(bool busy); protected: + // QQuickItem void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); @@ -92,14 +104,13 @@ 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); + // QQmlParserStatus + void classBegin(); + void componentComplete(); private: struct Hidden; - Hidden *h; + Hidden *const h; }; } // namespace osgQtQuick 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..96fbc7ff6 --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGCameraManipulator.cpp @@ -0,0 +1,181 @@ +/** + ****************************************************************************** + * + * @file OSGCameraManipulator.cpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @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 "../DirtySupport.hpp" +#include "../OSGNode.hpp" + +#include + +#include + +namespace osgQtQuick { +enum DirtyFlag { Scene = 1 << 0 }; + +struct OSGCameraManipulator::Hidden : public QObject, public DirtySupport { + Q_OBJECT + + friend class OSGCameraManipulator; + +private: + OSGCameraManipulator *const self; + +public: + osg::ref_ptr manipulator; + + OSGNode *sceneNode; + +public: + Hidden(OSGCameraManipulator *self) : QObject(self), self(self), sceneNode(NULL) + {} + + ~Hidden() + {} + + osg::Node *nodeToUpdate() const + { + return manipulator->getNode(); + } + + void update() + { + return self->update(); + } + + 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, &OSGCameraManipulator::Hidden::onSceneNodeChanged); + } + + return true; + } + + void updateSceneNode() + { + if (!sceneNode) { + qWarning() << "OSGCameraManipulator::updateSceneNode - no scene node"; + return; + } + qDebug() << "OSGCameraManipulator::updateSceneNode" << sceneNode; + manipulator->setNode(sceneNode->node()); + } + +private slots: + void onSceneNodeChanged(osg::Node *node) + { + qDebug() << "OSGCameraManipulator::onSceneNodeChanged" << node; + updateSceneNode(); + } +}; + +/* class OSGCameraManipulator */ + +OSGCameraManipulator::OSGCameraManipulator(QObject *parent) : QObject(parent), h(new Hidden(this)) +{} + +OSGCameraManipulator::~OSGCameraManipulator() +{ + delete h; +} + +OSGNode *OSGCameraManipulator::sceneNode() const +{ + return h->sceneNode; +} + +void OSGCameraManipulator::setSceneNode(OSGNode *node) +{ + if (h->acceptSceneNode(node)) { + setDirty(Scene); + emit sceneNodeChanged(node); + } +} + +bool OSGCameraManipulator::isDirty(int mask) const +{ + return h->isDirty(mask); +} + +void OSGCameraManipulator::setDirty(int mask) +{ + h->setDirty(mask); +} + +void OSGCameraManipulator::clearDirty() +{ + h->clearDirty(); +} + +void OSGCameraManipulator::classBegin() +{ + // qDebug() << "OSGCameraManipulator::classBegin" << this; +} + +void OSGCameraManipulator::componentComplete() +{ + qDebug() << "OSGCameraManipulator::componentComplete" << this; + update(); + clearDirty(); +} + +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; +} + +void OSGCameraManipulator::update() +{ + if (isDirty(Scene)) { + h->updateSceneNode(); + } +} +} // 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..2546adbf1 --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGCameraManipulator.hpp @@ -0,0 +1,81 @@ +/** + ****************************************************************************** + * + * @file OSGCameraManipulator.hpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @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: + bool isDirty(int mask = 0xFFFF) const; + void setDirty(int mask = 0xFFFF); + void clearDirty(); + + void classBegin(); + void componentComplete(); + + osgGA::CameraManipulator *manipulator() const; + void setManipulator(osgGA::CameraManipulator *manipulator); + +protected: + virtual void update(); + +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..4da67960d --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGEarthManipulator.cpp @@ -0,0 +1,69 @@ +/** + ****************************************************************************** + * + * @file OSGEarthManipulator.cpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @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) : Inherited(parent), h(new Hidden(this)) +{} + +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..dbefa3411 --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGEarthManipulator.hpp @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * + * @file OSGEarthManipulator.hpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @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 + + typedef OSGCameraManipulator Inherited; + +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..bda1cc8fc --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGGeoTransformManipulator.cpp @@ -0,0 +1,285 @@ +/** + ****************************************************************************** + * + * @file OSGGeoTransformManipulator.cpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @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 "utils/utility.h" + +#include +#include +#include + +#include + +#include +#include + +#include + +namespace osgQtQuick { +enum DirtyFlag { Position = 1 << 10, Attitude = 1 << 11, Clamp = 1 << 12 }; + +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::Hidden : public QObject { + Q_OBJECT + +private: + OSGGeoTransformManipulator * const self; + + osg::Matrix cameraPosition; + osg::Matrix cameraRotation; + +public: + osg::ref_ptr manipulator; + + QVector3D attitude; + QVector3D position; + + bool clampToTerrain; + bool intoTerrain; + + Hidden(OSGGeoTransformManipulator *self) : QObject(self), self(self), clampToTerrain(false), intoTerrain(false) + { + manipulator = new MyManipulator(); + self->setManipulator(manipulator); + } + + ~Hidden() + {} + + 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; + + OSGNode *sceneNode = self->sceneNode(); + + if (sceneNode && sceneNode->node()) { + mapNode = osgEarth::MapNode::findMapNode(sceneNode->node()); + if (!mapNode) { + qWarning() << "OSGGeoTransformManipulator::updatePosition - manipulator node does not contain a map node"; + } + } else { + qWarning() << "OSGGeoTransformManipulator::updatePosition - scene 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); +} + +/* class OSGGeoTransformManipulator */ + +OSGGeoTransformManipulator::OSGGeoTransformManipulator(QObject *parent) : Inherited(parent), h(new Hidden(this)) +{} + +OSGGeoTransformManipulator::~OSGGeoTransformManipulator() +{ + delete h; +} + +bool OSGGeoTransformManipulator::clampToTerrain() const +{ + return h->clampToTerrain; +} + +void OSGGeoTransformManipulator::setClampToTerrain(bool arg) +{ + if (h->clampToTerrain != arg) { + h->clampToTerrain = arg; + setDirty(Clamp); + 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; + setDirty(Attitude); + emit attitudeChanged(attitude()); + } +} + +QVector3D OSGGeoTransformManipulator::position() const +{ + return h->position; +} + +void OSGGeoTransformManipulator::setPosition(QVector3D arg) +{ + if (h->position != arg) { + h->position = arg; + setDirty(Position); + emit positionChanged(position()); + } +} + +void OSGGeoTransformManipulator::update() +{ + Inherited::update(); + + bool b = false; + + if (isDirty(Clamp | Position)) { + h->updatePosition(); + b = true; + } + if (isDirty(Attitude)) { + h->updateAttitude(); + b = true; + } + if (b) { + h->updateManipulator(); + } +} +} // 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..be5c6b1e7 --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGGeoTransformManipulator.hpp @@ -0,0 +1,75 @@ +/** + ****************************************************************************** + * + * @file OSGGeoTransformManipulator.hpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @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) + + typedef OSGCameraManipulator Inherited; + +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); + +private: + struct Hidden; + Hidden *const h; + + virtual void update(); +}; +} // 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..1194054b7 --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGNodeTrackerManipulator.cpp @@ -0,0 +1,175 @@ +/** + ****************************************************************************** + * + * @file OSGNodeTrackerManipulator.cpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @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 { +enum DirtyFlag { TrackNode = 1 << 10, TrackerMode = 1 << 11 }; + +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, &OSGNode::nodeChanged, this, &OSGNodeTrackerManipulator::Hidden::onTrackNodeChanged); + } + + 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) : Inherited(parent), h(new Hidden(this)) +{} + +OSGNodeTrackerManipulator::~OSGNodeTrackerManipulator() +{ + delete h; +} + +OSGNode *OSGNodeTrackerManipulator::trackNode() const +{ + return h->trackNode; +} + +void OSGNodeTrackerManipulator::setTrackNode(OSGNode *node) +{ + if (h->acceptTrackNode(node)) { + setDirty(TrackNode); + emit trackNodeChanged(node); + } +} + +TrackerMode::Enum OSGNodeTrackerManipulator::trackerMode() const +{ + return h->trackerMode; +} + +void OSGNodeTrackerManipulator::setTrackerMode(TrackerMode::Enum mode) +{ + if (h->trackerMode != mode) { + h->trackerMode = mode; + setDirty(TrackerMode); + emit trackerModeChanged(trackerMode()); + } +} + +void OSGNodeTrackerManipulator::update() +{ + Inherited::update(); + + if (isDirty(TrackNode)) { + h->updateTrackNode(); + } + if (isDirty(TrackerMode)) { + h->updateTrackerMode(); + } +} +} // 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..8215b6ccc --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGNodeTrackerManipulator.hpp @@ -0,0 +1,72 @@ +/** + ****************************************************************************** + * + * @file OSGNodeTrackerManipulator.hpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @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) + + typedef OSGCameraManipulator Inherited; + +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); + +private: + struct Hidden; + Hidden *const h; + + virtual void update(); +}; +} // 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..f79d533c5 --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGTrackballManipulator.cpp @@ -0,0 +1,69 @@ +/** + ****************************************************************************** + * + * @file OSGTrackballManipulator.cpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @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) : Inherited(parent), h(new Hidden(this)) +{} + +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..75120a4ca --- /dev/null +++ b/ground/gcs/src/libs/osgearth/osgQtQuick/ga/OSGTrackballManipulator.hpp @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * + * @file OSGTrackballManipulator.hpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @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 + + typedef OSGCameraManipulator Inherited; + +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.cpp b/ground/gcs/src/libs/osgearth/osgearth.cpp index b40d864c5..12ea13beb 100644 --- a/ground/gcs/src/libs/osgearth/osgearth.cpp +++ b/ground/gcs/src/libs/osgearth/osgearth.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file osgearth.cpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -27,8 +27,8 @@ #include "osgearth.h" -#include "utility.h" -#include "qtwindowingsystem.h" +#include "utils/utility.h" +#include "utils/qtwindowingsystem.h" #include "utils/pathutils.h" @@ -107,7 +107,9 @@ void OsgEarth::initialize() initializeCache(); +#ifdef OSG_VERBOSE displayInfo(); +#endif } void OsgEarth::initializePathes() diff --git a/ground/gcs/src/libs/osgearth/osgearth.h b/ground/gcs/src/libs/osgearth/osgearth.h index 438c9865c..afe8b0bcd 100644 --- a/ground/gcs/src/libs/osgearth/osgearth.h +++ b/ground/gcs/src/libs/osgearth/osgearth.h @@ -2,7 +2,7 @@ ****************************************************************************** * * @file osgearth.h - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup diff --git a/ground/gcs/src/libs/osgearth/osgearth.pro b/ground/gcs/src/libs/osgearth/osgearth.pro index 01c70636d..8780eafd2 100644 --- a/ground/gcs/src/libs/osgearth/osgearth.pro +++ b/ground/gcs/src/libs/osgearth/osgearth.pro @@ -2,7 +2,7 @@ TEMPLATE = lib TARGET = GCSOsgEarth DEFINES += OSGEARTH_LIBRARY -#CONFIG += mys2 +#DEFINES += OSG_VERBOSE osg:DEFINES += USE_OSG osgQt:DEFINES += USE_OSG_QT @@ -35,40 +35,54 @@ QMAKE_CXXFLAGS += -Wno-unused-parameter HEADERS += \ osgearth_global.h \ - utility.h \ - shapeutils.h \ - qtwindowingsystem.h \ - osgearth.h + osgearth.h \ + utils/qtwindowingsystem.h \ + utils/utility.h \ + utils/shapeutils.h SOURCES += \ - utility.cpp \ - shapeutils.cpp \ - qtwindowingsystem.cpp \ - osgearth.cpp + osgearth.cpp \ + utils/qtwindowingsystem.cpp \ + utils/utility.cpp \ + utils/shapeutils.cpp HEADERS += \ osgQtQuick/Export.hpp \ + osgQtQuick/DirtySupport.hpp \ osgQtQuick/OSGNode.hpp \ osgQtQuick/OSGGroup.hpp \ osgQtQuick/OSGTransformNode.hpp \ osgQtQuick/OSGShapeNode.hpp \ + osgQtQuick/OSGImageNode.hpp \ osgQtQuick/OSGTextNode.hpp \ osgQtQuick/OSGFileNode.hpp \ - osgQtQuick/OSGBackgroundNode.hpp \ + osgQtQuick/OSGBillboardNode.hpp \ osgQtQuick/OSGCamera.hpp \ osgQtQuick/OSGViewport.hpp SOURCES += \ + osgQtQuick/DirtySupport.cpp \ osgQtQuick/OSGNode.cpp \ osgQtQuick/OSGGroup.cpp \ osgQtQuick/OSGTransformNode.cpp \ osgQtQuick/OSGShapeNode.cpp \ + osgQtQuick/OSGImageNode.cpp \ osgQtQuick/OSGTextNode.cpp \ osgQtQuick/OSGFileNode.cpp \ - osgQtQuick/OSGBackgroundNode.cpp \ + osgQtQuick/OSGBillboardNode.cpp \ 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 +91,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/osgearth_global.h b/ground/gcs/src/libs/osgearth/osgearth_global.h index dc4fa1b11..a06c850a2 100644 --- a/ground/gcs/src/libs/osgearth/osgearth_global.h +++ b/ground/gcs/src/libs/osgearth/osgearth_global.h @@ -2,7 +2,7 @@ ****************************************************************************** * * @file osgearth_global.h - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup diff --git a/ground/gcs/src/libs/osgearth/readme.txt b/ground/gcs/src/libs/osgearth/readme.txt index 3937dae12..b6fddbc68 100644 --- a/ground/gcs/src/libs/osgearth/readme.txt +++ b/ground/gcs/src/libs/osgearth/readme.txt @@ -4,3 +4,6 @@ References : - https://wiki.qt.io/OsgQtQuick-Demo - https://github.com/podsvirov - https://github.com/podsvirov/osgqtquick + +known issues: +- http://forum.osgearth.org/VERTEX-glCompileShader-quot-oe-mp-vertModel-quot-FAILED-tt7588106.html#none diff --git a/ground/gcs/src/libs/osgearth/qtwindowingsystem.cpp b/ground/gcs/src/libs/osgearth/utils/qtwindowingsystem.cpp similarity index 94% rename from ground/gcs/src/libs/osgearth/qtwindowingsystem.cpp rename to ground/gcs/src/libs/osgearth/utils/qtwindowingsystem.cpp index 3ac9a0297..470368069 100644 --- a/ground/gcs/src/libs/osgearth/qtwindowingsystem.cpp +++ b/ground/gcs/src/libs/osgearth/utils/qtwindowingsystem.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file qtwindowingsystem.cpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -103,20 +103,20 @@ GraphicsWindowQt::GraphicsWindowQt(osg::GraphicsContext::Traits *traits) : _glContext(NULL), _surface(NULL) { - qDebug() << "GraphicsWindowQt::GraphicsWindowQt"; + // qDebug() << "GraphicsWindowQt::GraphicsWindowQt"; _traits = traits; init(); } GraphicsWindowQt::~GraphicsWindowQt() { - qDebug() << "GraphicsWindowQt::~GraphicsWindowQt"; + // qDebug() << "GraphicsWindowQt::~GraphicsWindowQt"; close(); } void GraphicsWindowQt::init() { - qDebug() << "GraphicsWindowQt::init"; + // qDebug() << "GraphicsWindowQt::init"; if (_closing || _initialized) { return; } @@ -199,7 +199,7 @@ bool GraphicsWindowQt::valid() const bool GraphicsWindowQt::realizeImplementation() { - qDebug() << "GraphicsWindowQt::realizeImplementation"; + // qDebug() << "GraphicsWindowQt::realizeImplementation"; // save the current context // note: this will save only Qt-based contexts @@ -217,16 +217,18 @@ bool GraphicsWindowQt::realizeImplementation() QOpenGLContext *currentContext = QOpenGLContext::currentContext(); if (!currentContext) { - qDebug() << "GraphicsWindowQt::realizeImplementation - creating owned context"; + // qDebug() << "GraphicsWindowQt::realizeImplementation - creating owned context"; _owned = true; _glContext = new QOpenGLContext(); _glContext->create(); _surface = new QOffscreenSurface(); _surface->setFormat(_glContext->format()); _surface->create(); +#ifdef OSG_VERBOSE osgQtQuick::formatInfo(_surface->format()); +#endif } else { - qDebug() << "GraphicsWindowQt::realizeImplementation - using current context"; + // qDebug() << "GraphicsWindowQt::realizeImplementation - using current context"; _glContext = currentContext; } @@ -316,7 +318,7 @@ bool GraphicsWindowQt::releaseContextImplementation() return false; } if (_owned && _glContext) { - qDebug() << "GraphicsWindowQt::releaseContextImplementation"; + // qDebug() << "GraphicsWindowQt::releaseContextImplementation"; _glContext->doneCurrent(); } return true; @@ -324,14 +326,14 @@ bool GraphicsWindowQt::releaseContextImplementation() void GraphicsWindowQt::closeImplementation() { - qDebug() << "GraphicsWindowQt::closeImplementation"; + // qDebug() << "GraphicsWindowQt::closeImplementation"; _closing = true; _initialized = false; _valid = false; _realized = false; if (_owned) { if (_glContext) { - qDebug() << "GraphicsWindowQt::closeImplementation - deleting owned context"; + // qDebug() << "GraphicsWindowQt::closeImplementation - deleting owned context"; delete _glContext; } if (_surface) { diff --git a/ground/gcs/src/libs/osgearth/qtwindowingsystem.h b/ground/gcs/src/libs/osgearth/utils/qtwindowingsystem.h similarity index 99% rename from ground/gcs/src/libs/osgearth/qtwindowingsystem.h rename to ground/gcs/src/libs/osgearth/utils/qtwindowingsystem.h index 958c04fb1..f23079f47 100644 --- a/ground/gcs/src/libs/osgearth/qtwindowingsystem.h +++ b/ground/gcs/src/libs/osgearth/utils/qtwindowingsystem.h @@ -2,7 +2,7 @@ ****************************************************************************** * * @file qtwindowingsystem.h - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup diff --git a/ground/gcs/src/libs/osgearth/shapeutils.cpp b/ground/gcs/src/libs/osgearth/utils/shapeutils.cpp similarity index 99% rename from ground/gcs/src/libs/osgearth/shapeutils.cpp rename to ground/gcs/src/libs/osgearth/utils/shapeutils.cpp index 31fb6aedf..ed3cea5fc 100644 --- a/ground/gcs/src/libs/osgearth/shapeutils.cpp +++ b/ground/gcs/src/libs/osgearth/utils/shapeutils.cpp @@ -1,4 +1,4 @@ -#include "shapeutils.h" +#include "utils/shapeutils.h" #include diff --git a/ground/gcs/src/libs/osgearth/shapeutils.h b/ground/gcs/src/libs/osgearth/utils/shapeutils.h similarity index 100% rename from ground/gcs/src/libs/osgearth/shapeutils.h rename to ground/gcs/src/libs/osgearth/utils/shapeutils.h diff --git a/ground/gcs/src/libs/osgearth/utility.cpp b/ground/gcs/src/libs/osgearth/utils/utility.cpp similarity index 93% rename from ground/gcs/src/libs/osgearth/utility.cpp rename to ground/gcs/src/libs/osgearth/utils/utility.cpp index a35f25cc9..82981be2d 100644 --- a/ground/gcs/src/libs/osgearth/utility.cpp +++ b/ground/gcs/src/libs/osgearth/utils/utility.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file utility.cpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup @@ -25,7 +25,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "utility.h" +#include "utils/utility.h" // osgQtQuick qml types #include "osgQtQuick/OSGNode.hpp" @@ -33,11 +33,16 @@ #include "osgQtQuick/OSGFileNode.hpp" #include "osgQtQuick/OSGTransformNode.hpp" #include "osgQtQuick/OSGShapeNode.hpp" +#include "osgQtQuick/OSGImageNode.hpp" #include "osgQtQuick/OSGTextNode.hpp" -#include "osgQtQuick/OSGBackgroundNode.hpp" +#include "osgQtQuick/OSGBillboardNode.hpp" #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 +66,9 @@ #include "osgQtQuick/OSGSkyNode.hpp" #include "osgQtQuick/OSGGeoTransformNode.hpp" +#include "osgQtQuick/ga/OSGEarthManipulator.hpp" +#include "osgQtQuick/ga/OSGGeoTransformManipulator.hpp" + #include #include #include @@ -75,9 +83,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 +111,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 +134,7 @@ public: // geode.getDrawable(i)->setDrawCallback(new DrawableDrawCallback()); // } } + virtual void apply(osg::Transform & node) { apply((osg::Node &)node); @@ -469,7 +482,7 @@ bool clampGeoPoint(osgEarth::GeoPoint &geoPoint, float offset, osgEarth::MapNode if (eq.getElevation(geoPoint, elevation, 0.0)) { clamped = ((geoPoint.z() - offset) < elevation); if (clamped) { - qDebug() << "Utility::clampGeoPoint - clamping" << geoPoint.z() - offset << "/" << elevation; + // qDebug() << "Utility::clampGeoPoint - clamping" << geoPoint.z() - offset << "/" << elevation; geoPoint.z() = elevation + offset; } } else { @@ -522,33 +535,45 @@ void registerTypes() { int maj = 1, min = 0; - // @uri osgQtQuick + // viewport + qmlRegisterType("OsgQtQuick", maj, min, "OSGViewport"); + qmlRegisterType("OsgQtQuick", maj, min, "UpdateMode"); + + // basic nodes qmlRegisterType("OsgQtQuick", maj, min, "OSGNode"); qmlRegisterType("OsgQtQuick", maj, min, "OSGGroup"); - qmlRegisterType("OsgQtQuick", maj, min, "OSGFileNode"); - qmlRegisterType("OsgQtQuick", maj, min, "OptimizeMode"); - qmlRegisterType("OsgQtQuick", maj, min, "OSGTransformNode"); - qmlRegisterType("OsgQtQuick", maj, min, "OSGTextNode"); - + // primitive nodes qmlRegisterType("OsgQtQuick", maj, min, "OSGShapeNode"); qmlRegisterType("OsgQtQuick", maj, min, "ShapeType"); - qmlRegisterType("OsgQtQuick", maj, min, "OSGBackgroundNode"); + qmlRegisterType("OsgQtQuick", maj, min, "OSGImageNode"); - qmlRegisterType("OsgQtQuick", maj, min, "OSGViewport"); - qmlRegisterType("OsgQtQuick", maj, min, "UpdateMode"); + qmlRegisterType("OsgQtQuick", maj, min, "OSGTextNode"); + qmlRegisterType("OsgQtQuick", maj, min, "OSGBillboardNode"); + + qmlRegisterType("OsgQtQuick", maj, min, "OSGFileNode"); + qmlRegisterType("OsgQtQuick", maj, min, "OptimizeMode"); + + // camera nodes qmlRegisterType("OsgQtQuick", maj, min, "OSGCamera"); - qmlRegisterType("OsgQtQuick", maj, min, "ManipulatorMode"); + + // camera manipulators + 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/libs/osgearth/utility.h b/ground/gcs/src/libs/osgearth/utils/utility.h similarity index 99% rename from ground/gcs/src/libs/osgearth/utility.h rename to ground/gcs/src/libs/osgearth/utils/utility.h index b266ce4ae..2f7124847 100644 --- a/ground/gcs/src/libs/osgearth/utility.h +++ b/ground/gcs/src/libs/osgearth/utils/utility.h @@ -2,7 +2,7 @@ ****************************************************************************** * * @file utility.h - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * @addtogroup * @{ * @addtogroup diff --git a/ground/gcs/src/libs/utils/quickwidgetproxy.cpp b/ground/gcs/src/libs/utils/quickwidgetproxy.cpp index fe5a615e6..1f93c4e3c 100644 --- a/ground/gcs/src/libs/utils/quickwidgetproxy.cpp +++ b/ground/gcs/src/libs/utils/quickwidgetproxy.cpp @@ -127,16 +127,16 @@ void QuickWidgetProxy::onStatusChanged(QQuickWidget::Status status) { switch (status) { case QQuickWidget::Null: - qDebug() << "QuickWidgetProxy - status Null"; + qWarning() << "QuickWidgetProxy - status Null"; break; case QQuickWidget::Ready: - qDebug() << "QuickWidgetProxy - status Ready"; + // qDebug() << "QuickWidgetProxy - status Ready"; break; case QQuickWidget::Loading: - qDebug() << "QuickWidgetProxy - status Loading"; + // qDebug() << "QuickWidgetProxy - status Loading"; break; case QQuickWidget::Error: - qDebug() << "QuickWidgetProxy - status Error"; + qWarning() << "QuickWidgetProxy - status Error"; foreach(const QQmlError &error, errors()) { qWarning() << error.description(); } @@ -148,16 +148,16 @@ void QuickWidgetProxy::onStatusChanged(QQuickView::Status status) { switch (status) { case QQuickView::Null: - qDebug() << "QuickWidgetProxy - status Null"; + qWarning() << "QuickWidgetProxy - status Null"; break; case QQuickView::Ready: - qDebug() << "QuickWidgetProxy - status Ready"; + // qDebug() << "QuickWidgetProxy - status Ready"; break; case QQuickView::Loading: - qDebug() << "QuickWidgetProxy - status Loading"; + // qDebug() << "QuickWidgetProxy - status Loading"; break; case QQuickView::Error: - qDebug() << "QuickWidgetProxy - status Error"; + qWarning() << "QuickWidgetProxy - status Error"; foreach(const QQmlError &error, errors()) { qWarning() << error.description(); } diff --git a/ground/gcs/src/plugins/pfdqml/pfdqmlcontext.cpp b/ground/gcs/src/plugins/pfdqml/pfdqmlcontext.cpp index 9f3331c00..22aa9bf81 100644 --- a/ground/gcs/src/plugins/pfdqml/pfdqmlcontext.cpp +++ b/ground/gcs/src/plugins/pfdqml/pfdqmlcontext.cpp @@ -28,13 +28,18 @@ #include "pfdqmlcontext.h" #include "extensionsystem/pluginmanager.h" -#include "uavobjectmanager.h" #include "uavobject.h" +#include "uavobjectmanager.h" #include "utils/stringutils.h" +#include "utils/pathutils.h" + #include "flightbatterysettings.h" #include #include +#include + +const QString PfdQmlContext::CONTEXT_PROPERTY_NAME = "pfdContext"; PfdQmlContext::PfdQmlContext(QObject *parent) : QObject(parent), m_speedUnit("m/s"), @@ -50,8 +55,13 @@ PfdQmlContext::PfdQmlContext(QObject *parent) : QObject(parent), m_dateTime(QDateTime()), m_minAmbientLight(0.03), m_modelFile(""), + m_modelIndex(0), m_backgroundImageFile("") -{} +{ + addModelDir("helis"); + addModelDir("multi"); + addModelDir("planes"); +} PfdQmlContext::~PfdQmlContext() {} @@ -220,11 +230,32 @@ QString PfdQmlContext::modelFile() const void PfdQmlContext::setModelFile(const QString &arg) { if (m_modelFile != arg) { - m_modelFile = arg; + m_modelFile = arg; + m_modelIndex = m_modelFileList.indexOf(m_modelFile); + if (m_modelIndex == -1) { + m_modelIndex = 0; + } emit modelFileChanged(modelFile()); } } +void PfdQmlContext::nextModel() +{ + m_modelIndex = (m_modelIndex + 1) % m_modelFileList.length(); + setModelFile(m_modelFileList[m_modelIndex]); +} + +void PfdQmlContext::previousModel() +{ + m_modelIndex = (m_modelFileList.length() + m_modelIndex - 1) % m_modelFileList.length(); + setModelFile(m_modelFileList[m_modelIndex]); +} + +QStringList PfdQmlContext::modelFileList() const +{ + return m_modelFileList; +} + QString PfdQmlContext::backgroundImageFile() const { return m_backgroundImageFile; @@ -281,12 +312,16 @@ void PfdQmlContext::loadConfiguration(PfdQmlGadgetConfiguration *config) void PfdQmlContext::saveState(QSettings *settings) { - Q_UNUSED(settings); + settings->setValue("modelFile", modelFile()); } void PfdQmlContext::restoreState(QSettings *settings) { - Q_UNUSED(settings); + QString file = settings->value("modelFile").toString(); + + if (!file.isEmpty()) { + setModelFile(file); + } } void PfdQmlContext::apply(QQmlContext *context) @@ -339,6 +374,17 @@ void PfdQmlContext::apply(QQmlContext *context) } } - // to expose settings values - context->setContextProperty("pfdContext", this); + // expose this context to Qml + context->setContextProperty(CONTEXT_PROPERTY_NAME, this); +} + +void PfdQmlContext::addModelDir(QString dir) +{ + QDirIterator it(Utils::GetDataPath() + "models/" + dir, QStringList("*.3ds"), QDir::NoFilter, QDirIterator::Subdirectories); + + while (it.hasNext()) { + QString file = QDir::toNativeSeparators(it.next()); + // qDebug() << file; + m_modelFileList.append(file); + } } diff --git a/ground/gcs/src/plugins/pfdqml/pfdqmlcontext.h b/ground/gcs/src/plugins/pfdqml/pfdqmlcontext.h index e26a4d9d1..ca0e88730 100644 --- a/ground/gcs/src/plugins/pfdqml/pfdqmlcontext.h +++ b/ground/gcs/src/plugins/pfdqml/pfdqmlcontext.h @@ -52,7 +52,11 @@ class PfdQmlContext : public QObject { Q_PROPERTY(QDateTime dateTime READ dateTime WRITE setDateTime NOTIFY dateTimeChanged) Q_PROPERTY(double minimumAmbientLight READ minimumAmbientLight WRITE setMinimumAmbientLight NOTIFY minimumAmbientLightChanged) - Q_PROPERTY(QString modelFile READ modelFile WRITE setModelFile NOTIFY modelFileChanged) + // model + Q_PROPERTY(QString modelFile READ modelFile NOTIFY modelFileChanged) + Q_PROPERTY(QStringList modelFileList READ modelFileList CONSTANT FINAL) + + // background Q_PROPERTY(QString backgroundImageFile READ backgroundImageFile WRITE setBackgroundImageFile NOTIFY backgroundImageFileChanged) public: @@ -87,8 +91,14 @@ public: double minimumAmbientLight() const; void setMinimumAmbientLight(double arg); + // model QString modelFile() const; void setModelFile(const QString &arg); + QStringList modelFileList() const; + Q_INVOKABLE void nextModel(); + Q_INVOKABLE void previousModel(); + + // background QString backgroundImageFile() const; void setBackgroundImageFile(const QString &arg); @@ -121,6 +131,9 @@ signals: void backgroundImageFileChanged(QString arg); private: + // constants + static const QString CONTEXT_PROPERTY_NAME; + QString m_speedUnit; double m_speedFactor; QString m_altitudeUnit; @@ -138,7 +151,11 @@ private: double m_minAmbientLight; QString m_modelFile; + int m_modelIndex; + QStringList m_modelFileList; QString m_backgroundImageFile; + + void addModelDir(QString dir); }; #endif /* PFDQMLCONTEXT_H_ */ diff --git a/ground/gcs/src/plugins/welcome/welcomeplugin.cpp b/ground/gcs/src/plugins/welcome/welcomeplugin.cpp index 0dfbf91bd..aedfbd330 100644 --- a/ground/gcs/src/plugins/welcome/welcomeplugin.cpp +++ b/ground/gcs/src/plugins/welcome/welcomeplugin.cpp @@ -52,14 +52,10 @@ WelcomePlugin::WelcomePlugin() WelcomePlugin::~WelcomePlugin() { - // The below code is commented out to avoid having the application - // crash when it is terminated. TODO: Fix a real solution. - /* - if (m_welcomeMode) { + if (m_welcomeMode) { removeObject(m_welcomeMode); delete m_welcomeMode; - } - */ + } } /*! Initializes the plugin. Returns true on success. diff --git a/ground/gcs/src/share/configurations/default.xml b/ground/gcs/src/share/configurations/default.xml index fc34482f9..a5136e1bb 100644 --- a/ground/gcs/src/share/configurations/default.xml +++ b/ground/gcs/src/share/configurations/default.xml @@ -1635,7 +1635,7 @@ 0.0.0 - %%DATAPATH%%qml/Pfd.qml + %%DATAPATH%%qml/PfdTerrain.qml 1 1 true @@ -1659,7 +1659,7 @@ 0.0.0 - %%DATAPATH%%qml/Pfd.qml + %%DATAPATH%%qml/PfdTerrain.qml 1 1 true @@ -1683,7 +1683,7 @@ 0.0.0 - %%DATAPATH%%qml/ModelView.qml + %%DATAPATH%%qml/Model.qml 1 1 false @@ -1707,7 +1707,7 @@ 0.0.0 - %%DATAPATH%%qml/ModelView.qml + %%DATAPATH%%qml/ModelTerrain.qml 1 1 true @@ -1731,7 +1731,7 @@ 0.0.0 - %%DATAPATH%%qml/ModelView.qml + %%DATAPATH%%qml/ModelTerrain.qml 1 1 true @@ -1755,7 +1755,7 @@ 0.0.0 - %%DATAPATH%%qml/EarthView.qml + %%DATAPATH%%qml/Earth.qml 1 1 true diff --git a/ground/gcs/src/share/qml/CubeView.qml b/ground/gcs/src/share/qml/Cube.qml similarity index 100% rename from ground/gcs/src/share/qml/CubeView.qml rename to ground/gcs/src/share/qml/Cube.qml diff --git a/ground/gcs/src/share/qml/EarthView.qml b/ground/gcs/src/share/qml/Earth.qml similarity index 66% rename from ground/gcs/src/share/qml/EarthView.qml rename to ground/gcs/src/share/qml/Earth.qml index 97cd5cc88..198a412e2 100644 --- a/ground/gcs/src/share/qml/EarthView.qml +++ b/ground/gcs/src/share/qml/Earth.qml @@ -18,22 +18,37 @@ * along with LibrePilot GCS. If not, see . */ import QtQuick 2.4 +import QtQuick.Controls 1.4 import Pfd 1.0 import OsgQtQuick 1.0 -import "common.js" as Utils +import "js/common.js" as Utils Item { OSGViewport { + id: osgViewport + anchors.fill: parent focus: true - sceneData: skyNode + + sceneNode: skyNode camera: camera + manipulator: earthManipulator + + OSGCamera { + id: camera + fieldOfView: 90 + } + + OSGEarthManipulator { + id: earthManipulator + } OSGSkyNode { id: skyNode - sceneData: terrainNode + sceneNode: terrainNode + viewport: osgViewport dateTime: Utils.getDateTime() minimumAmbientLight: pfdContext.minimumAmbientLight } @@ -44,11 +59,25 @@ Item { async: false } - OSGCamera { - id: camera - fieldOfView: 90 - manipulatorMode: ManipulatorMode.Earth - } + } + BusyIndicator { + width: 24 + height: 24 + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: 4 + + running: osgViewport.busy + } + + BusyIndicator { + width: 24 + height: 24 + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: 4 + + running: osgViewport.busy } } diff --git a/ground/gcs/src/share/qml/ModelView.qml b/ground/gcs/src/share/qml/Model.qml similarity index 82% rename from ground/gcs/src/share/qml/ModelView.qml rename to ground/gcs/src/share/qml/Model.qml index 24b41786d..a31c91a3b 100644 --- a/ground/gcs/src/share/qml/ModelView.qml +++ b/ground/gcs/src/share/qml/Model.qml @@ -19,10 +19,7 @@ */ import QtQuick 2.4 -Item { - Loader { - anchors.fill: parent - focus: true - source: pfdContext.terrainEnabled ? "model/ModelTerrainView.qml" : "model/ModelView.qml" - } -} \ No newline at end of file +import "model" + +ModelView { +} diff --git a/ground/gcs/src/share/qml/ModelTerrain.qml b/ground/gcs/src/share/qml/ModelTerrain.qml new file mode 100644 index 000000000..8ec9abc56 --- /dev/null +++ b/ground/gcs/src/share/qml/ModelTerrain.qml @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 The LibrePilot Project + * Contact: http://www.librepilot.org + * + * This file is part of LibrePilot GCS. + * + * LibrePilot GCS 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. + * + * LibrePilot GCS 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 LibrePilot GCS. If not, see . + */ +import QtQuick 2.4 + +import "model" + +ModelTerrainView { +} diff --git a/ground/gcs/src/share/qml/Pfd.qml b/ground/gcs/src/share/qml/Pfd.qml index 8e007dd01..c7a004730 100644 --- a/ground/gcs/src/share/qml/Pfd.qml +++ b/ground/gcs/src/share/qml/Pfd.qml @@ -19,107 +19,8 @@ */ import QtQuick 2.4 -import "pfd" as Pfd +import "pfd" -Rectangle { - color: "#515151" - - Pfd.SvgElementImage { - id: background - elementName: "pfd-window" - fillMode: Image.PreserveAspectFit - anchors.fill: parent - sceneSize: Qt.size(width, height) - - Rectangle { - width: Math.floor(parent.paintedHeight * 1.319) - height: Math.floor(parent.paintedHeight - parent.paintedHeight * 0.008) - - color: "transparent" - border.color: "white" - border.width: Math.floor(parent.paintedHeight * 0.008) - radius: Math.floor(parent.paintedHeight * 0.01) - anchors.centerIn: parent - } - - Item { - id: sceneItem - - FontLoader { - id: pt_bold - source: "qrc:/utils/fonts/PTS75F.ttf" - } - - width: Math.floor((parent.paintedHeight * 1.32) - (parent.paintedHeight * 0.013)) - height: Math.floor(parent.paintedHeight - parent.paintedHeight * 0.02) - property variant viewportSize : Qt.size(width, height) - - anchors.centerIn: parent - clip: true - - Loader { - id: worldLoader - anchors.fill: parent - focus: true - source: pfdContext.terrainEnabled ? "pfd/PfdTerrainView.qml" : "pfd/PfdWorldView.qml" - } - - Pfd.HorizontCenter { - id: horizontCenterItem - sceneSize: sceneItem.viewportSize - anchors.fill: parent - } - - Pfd.RollScale { - id: rollscale - sceneSize: sceneItem.viewportSize - horizontCenter: horizontCenterItem.horizontCenter - anchors.fill: parent - } - - Pfd.SvgElementImage { - id: side_slip_fixed - elementName: "sideslip-fixed" - sceneSize: sceneItem.viewportSize - - x: scaledBounds.x * sceneItem.width - } - - Pfd.Compass { - anchors.fill: parent - sceneSize: sceneItem.viewportSize - } - - Pfd.SpeedScale { - anchors.fill: parent - sceneSize: sceneItem.viewportSize - } - - Pfd.AltitudeScale { - anchors.fill: parent - sceneSize: sceneItem.viewportSize - } - - Pfd.VsiScale { - anchors.fill: parent - sceneSize: sceneItem.viewportSize - visible: pfdContext.altitudeUnit != 0 - } - - Pfd.Info { - anchors.fill: parent - sceneSize: sceneItem.viewportSize - } - - Pfd.Panels { - anchors.fill: parent - sceneSize: sceneItem.viewportSize - } - - Pfd.Warnings { - anchors.fill: parent - sceneSize: sceneItem.viewportSize - } - } - } +PfdView { + worldFile: "PfdSimpleWorld.qml" } diff --git a/ground/gcs/src/share/qml/PfdTerrain.qml b/ground/gcs/src/share/qml/PfdTerrain.qml new file mode 100644 index 000000000..8c92bbeae --- /dev/null +++ b/ground/gcs/src/share/qml/PfdTerrain.qml @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 The LibrePilot Project + * Contact: http://www.librepilot.org + * + * This file is part of LibrePilot GCS. + * + * LibrePilot GCS 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. + * + * LibrePilot GCS 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 LibrePilot GCS. If not, see . + */ +import QtQuick 2.4 + +import "pfd" + +PfdView { + opaque: false + worldFile: "PfdTerrainWorld.qml" +} diff --git a/ground/gcs/src/share/qml/common.js b/ground/gcs/src/share/qml/js/common.js similarity index 100% rename from ground/gcs/src/share/qml/common.js rename to ground/gcs/src/share/qml/js/common.js diff --git a/ground/gcs/src/share/qml/uav.js b/ground/gcs/src/share/qml/js/uav.js similarity index 97% rename from ground/gcs/src/share/qml/uav.js rename to ground/gcs/src/share/qml/js/uav.js index 922027b05..451cfb163 100644 --- a/ground/gcs/src/share/qml/uav.js +++ b/ground/gcs/src/share/qml/js/uav.js @@ -28,7 +28,7 @@ .import UAVTalk.VtolPathFollowerSettings 1.0 as VtolPathFollowerSettings // Navigation -.import UAVTalk.HomeLocation 1.0 as HomeLocation +.import UAVTalk.HomeLocation 1.0 as HomeLocation .import UAVTalk.TakeOffLocation 1.0 as TakeOffLocation // Sensors @@ -147,7 +147,7 @@ function defaultPosition() { * */ function isCC3D() { - // Hack: detect Coptercontrol with mem free + // Hack: detect Coptercontrol with mem free return (freeMemoryBytes() < 3096); } @@ -251,7 +251,7 @@ function gpsStatus() { return ["NO GPS", "NO FIX", "2D", "3D"][gpsPositionSensor.status]; } -function fusionAlgorithm() { +function fusionAlgorithm() { return ["None", "Basic (No Nav)", "CompMag", "Comp+Mag+GPS", "EKFIndoor", "GPSNav (INS13)"][revoSettings.fusionAlgorithm]; } @@ -271,7 +271,7 @@ function batteryModuleEnabled() { return (hwSettings.optionalModulesBattery == HwSettings.OptionalModules.Enabled); } -function batteryNbCells() { +function batteryNbCells() { return flightBatterySettings.nbCells; } @@ -287,7 +287,7 @@ function batteryConsumedEnergy() { return flightBatteryState.consumedEnergy.toFixed(0); } -function estimatedFlightTimeValue() { +function estimatedFlightTimeValue() { return Math.round(flightBatteryState.estimatedFlightTime); } @@ -351,7 +351,7 @@ function waypointHeading() { } function homeDistance() { - return Math.sqrt(Math.pow((takeOffLocation.east - positionState.east), 2) + + return Math.sqrt(Math.pow((takeOffLocation.east - positionState.east), 2) + Math.pow((takeOffLocation.north - positionState.north), 2)); } @@ -377,8 +377,8 @@ function isVtolPathFollowerSettingsThrustAuto() { } function flightModeName() { - return ["MANUAL", "STAB 1", "STAB 2", "STAB 3", "STAB 4", "STAB 5", "STAB 6", - "POS HOLD", "COURSELOCK", "VEL ROAM", "HOME LEASH", "ABS POS", "RTB", + return ["MANUAL", "STAB 1", "STAB 2", "STAB 3", "STAB 4", "STAB 5", "STAB 6", + "POS HOLD", "COURSELOCK", "VEL ROAM", "HOME LEASH", "ABS POS", "RTB", "LAND", "PATHPLAN", "POI", "AUTOCRUISE", "AUTOTAKEOFF"][flightStatus.flightMode]; } diff --git a/ground/gcs/src/share/qml/model/ModelTerrainView.qml b/ground/gcs/src/share/qml/model/ModelTerrainView.qml index 9f3fd0536..aac169efb 100644 --- a/ground/gcs/src/share/qml/model/ModelTerrainView.qml +++ b/ground/gcs/src/share/qml/model/ModelTerrainView.qml @@ -18,75 +18,105 @@ * along with LibrePilot GCS. If not, see . */ import QtQuick 2.4 +import QtQuick.Controls 1.4 import Pfd 1.0 import OsgQtQuick 1.0 -import "../common.js" as Utils -import "../uav.js" as UAV +import "../js/common.js" as Utils +import "../js/uav.js" as UAV -OSGViewport { - anchors.fill: parent - focus: true - sceneData: skyNode - camera: camera +Item { + OSGViewport { + id: osgViewport - OSGSkyNode { - id: skyNode - sceneData: sceneGroup - dateTime: Utils.getDateTime() - minimumAmbientLight: pfdContext.minimumAmbientLight - } + anchors.fill: parent + focus: true - OSGGroup { - id: sceneGroup - children: [ terrainNode, modelNode ] - } + sceneNode: skyNode + camera: camera + manipulator: nodeTrackerManipulator - OSGFileNode { - id: terrainNode - source: pfdContext.terrainFile - async: false - } + OSGCamera { + id: camera + fieldOfView: 90 + logarithmicDepthBuffer: true + } - OSGGeoTransformNode { - id: modelNode + OSGNodeTrackerManipulator { + id: nodeTrackerManipulator + // use model to compute camera home position + sceneNode: modelTransformNode + // model will be tracked + trackNode: modelTransformNode + } - modelData: modelTransformNode - sceneData: terrainNode + OSGSkyNode { + id: skyNode + sceneNode: sceneGroup + viewport: osgViewport + dateTime: Utils.getDateTime() + minimumAmbientLight: pfdContext.minimumAmbientLight + } - clampToTerrain: true + OSGGroup { + id: sceneGroup + children: [ terrainFileNode, modelNode ] + } - position: UAV.position() - } + OSGGeoTransformNode { + id: modelNode - OSGTransformNode { - id: modelTransformNode - modelData: modelFileNode - // model dimensions are in mm, scale to meters - scale: Qt.vector3d(0.001, 0.001, 0.001) - attitude: UAV.attitude() - } + sceneNode: terrainFileNode + children: [ modelTransformNode ] - OSGFileNode { - id: modelFileNode + clampToTerrain: true - // use ShaderGen pseudoloader to generate the shaders expected by osgEarth - // 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" + position: UAV.position() + } - async: false - optimizeMode: OptimizeMode.OptimizeAndCheck - } + OSGTransformNode { + id: modelTransformNode + + children: [ modelFileNode ] + + // model dimensions are in mm, scale to meters + scale: Qt.vector3d(0.001, 0.001, 0.001) + attitude: UAV.attitude() + } + + OSGFileNode { + id: terrainFileNode + source: pfdContext.terrainFile + } + + OSGFileNode { + id: modelFileNode + + // use ShaderGen pseudoloader to generate the shaders expected by osgEarth + // 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" + + optimizeMode: OptimizeMode.OptimizeAndCheck + } + + Keys.onUpPressed: { + pfdContext.nextModel(); + } + + Keys.onDownPressed: { + pfdContext.previousModel(); + } + + BusyIndicator { + width: 24 + height: 24 + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: 4 + + running: osgViewport.busy + } - 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 } } diff --git a/ground/gcs/src/share/qml/model/ModelView.qml b/ground/gcs/src/share/qml/model/ModelView.qml index 68ea35ad5..4dbf9566a 100644 --- a/ground/gcs/src/share/qml/model/ModelView.qml +++ b/ground/gcs/src/share/qml/model/ModelView.qml @@ -21,32 +21,48 @@ import QtQuick 2.4 import OsgQtQuick 1.0 -import "../uav.js" as UAV +import "../js/uav.js" as UAV Item { OSGViewport { anchors.fill: parent focus: true - sceneData: sceneNode + + sceneNode: sceneNode camera: camera + manipulator: trackballManipulator + + OSGCamera { + id: camera + fieldOfView: 90 + } + + OSGTrackballManipulator { + id: trackballManipulator + sceneNode: transformNode + } OSGGroup { id: sceneNode - children: [ - transformNode, - backgroundNode - ] + children: [ transformNode, backgroundNode ] } - OSGBackgroundNode { + OSGBillboardNode { id: backgroundNode + children: [ backgroundImageNode ] + } + + OSGImageNode { + id: backgroundImageNode imageFile: pfdContext.backgroundImageFile } OSGTransformNode { id: transformNode - modelData: fileNode + + children: [ fileNode ] + attitude: UAV.attitude() } @@ -57,10 +73,12 @@ Item { optimizeMode: OptimizeMode.OptimizeAndCheck } - OSGCamera { - id: camera - fieldOfView: 90 - sceneNode: transformNode + Keys.onUpPressed: { + pfdContext.nextModel(); + } + + Keys.onDownPressed: { + pfdContext.previousModel(); } } diff --git a/ground/gcs/src/share/qml/pfd/AltitudeScale.qml b/ground/gcs/src/share/qml/pfd/AltitudeScale.qml index 3fb9adbf7..8a38935af 100644 --- a/ground/gcs/src/share/qml/pfd/AltitudeScale.qml +++ b/ground/gcs/src/share/qml/pfd/AltitudeScale.qml @@ -19,8 +19,8 @@ */ import QtQuick 2.4 -import "../common.js" as Utils -import "../uav.js" as UAV +import "../js/common.js" as Utils +import "../js/uav.js" as UAV Item { id: sceneItem diff --git a/ground/gcs/src/share/qml/pfd/Compass.qml b/ground/gcs/src/share/qml/pfd/Compass.qml index 02d905a7a..81dec7daf 100644 --- a/ground/gcs/src/share/qml/pfd/Compass.qml +++ b/ground/gcs/src/share/qml/pfd/Compass.qml @@ -19,7 +19,7 @@ */ import QtQuick 2.4 -import "../uav.js" as UAV +import "../js/uav.js" as UAV Item { id: sceneItem diff --git a/ground/gcs/src/share/qml/pfd/Info.qml b/ground/gcs/src/share/qml/pfd/Info.qml index 9fae25d24..827d2e039 100644 --- a/ground/gcs/src/share/qml/pfd/Info.qml +++ b/ground/gcs/src/share/qml/pfd/Info.qml @@ -19,8 +19,8 @@ */ import QtQuick 2.4 -import "../common.js" as Utils -import "../uav.js" as UAV +import "../js/common.js" as Utils +import "../js/uav.js" as UAV Item { id: info @@ -62,7 +62,7 @@ Item { sceneSize: info.sceneSize elementName: "info-bg" width: parent.width - opacity: pfdContext.terrainEnabled ? 0.3 : 1 + opacity: opaque ? 1 : 0.3 } // @@ -452,7 +452,7 @@ Item { x: Math.floor(scaledBounds.x * sceneItem.width) y: Math.floor(scaledBounds.y * sceneItem.height) - opacity: pfdContext.terrainEnabled ? 0.6 : 1 + opacity: opaque ? 1 : 0.6 states: State { name: "fading" diff --git a/ground/gcs/src/share/qml/pfd/Panels.qml b/ground/gcs/src/share/qml/pfd/Panels.qml index e433bc2e7..e9a865de0 100644 --- a/ground/gcs/src/share/qml/pfd/Panels.qml +++ b/ground/gcs/src/share/qml/pfd/Panels.qml @@ -19,8 +19,8 @@ */ import QtQuick 2.0 -import "../common.js" as Utils -import "../uav.js" as UAV +import "../js/common.js" as Utils +import "../js/uav.js" as UAV Item { id: panels diff --git a/ground/gcs/src/share/qml/pfd/PfdWorldView.qml b/ground/gcs/src/share/qml/pfd/PfdSimpleWorld.qml similarity index 99% rename from ground/gcs/src/share/qml/pfd/PfdWorldView.qml rename to ground/gcs/src/share/qml/pfd/PfdSimpleWorld.qml index e61060e06..a238ff777 100644 --- a/ground/gcs/src/share/qml/pfd/PfdWorldView.qml +++ b/ground/gcs/src/share/qml/pfd/PfdSimpleWorld.qml @@ -19,7 +19,7 @@ */ import QtQuick 2.4 -import "../uav.js" as UAV +import "../js/uav.js" as UAV Item { id: worldView diff --git a/ground/gcs/src/share/qml/pfd/PfdTerrainView.qml b/ground/gcs/src/share/qml/pfd/PfdTerrainWorld.qml similarity index 88% rename from ground/gcs/src/share/qml/pfd/PfdTerrainView.qml rename to ground/gcs/src/share/qml/pfd/PfdTerrainWorld.qml index 57da2a4fb..3afabcae4 100644 --- a/ground/gcs/src/share/qml/pfd/PfdTerrainView.qml +++ b/ground/gcs/src/share/qml/pfd/PfdTerrainWorld.qml @@ -22,50 +22,59 @@ import QtQuick 2.4 import Pfd 1.0 import OsgQtQuick 1.0 -import "../common.js" as Utils -import "../uav.js" as UAV +import "../js/common.js" as Utils +import "../js/uav.js" as UAV OSGViewport { - id: fullview + id: osgViewport + //anchors.fill: parent focus: true - sceneData: skyNode - camera: camera - property real horizontCenter : horizontCenterItem.horizontCenter + readonly property real horizontCenter : horizontCenterItem.horizontCenter - // Factor for OSGview vertical offset - property double factor: 0.04 + // Factor for OSGViewer vertical offset + readonly property double factor: 0.04 // Stretch height and apply offset //height: height * (1 + factor) y: -height * factor + sceneNode: skyNode + camera: camera + manipulator: geoTransformManipulator + + OSGCamera { + id: camera + + fieldOfView: 100 + logarithmicDepthBuffer: true + } + + OSGGeoTransformManipulator { + id: geoTransformManipulator + + sceneNode: terrainFileNode + clampToTerrain: true + + attitude: UAV.attitude() + position: UAV.position() + } + OSGSkyNode { id: skyNode - sceneData: terrainNode + sceneNode: 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 @@ -82,7 +91,6 @@ OSGViewport { property double pitch1DegHeight: sceneItem.height * pitch1DegScaledHeight - transform: [ Translate { id: pitchTranslate @@ -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) diff --git a/ground/gcs/src/share/qml/pfd/PfdView.qml b/ground/gcs/src/share/qml/pfd/PfdView.qml new file mode 100644 index 000000000..3d60dffb5 --- /dev/null +++ b/ground/gcs/src/share/qml/pfd/PfdView.qml @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2016 The LibrePilot Project + * Contact: http://www.librepilot.org + * + * This file is part of LibrePilot GCS. + * + * LibrePilot GCS 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. + * + * LibrePilot GCS 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 LibrePilot GCS. If not, see . + */ +import QtQuick 2.4 + +Rectangle { + + color: "#515151" + + property string worldFile: "PfdSimpleWorld.qml" + property bool opaque: true + + SvgElementImage { + id: background + elementName: "pfd-window" + fillMode: Image.PreserveAspectFit + anchors.fill: parent + sceneSize: Qt.size(width, height) + + Rectangle { + width: Math.floor(parent.paintedHeight * 1.319) + height: Math.floor(parent.paintedHeight - parent.paintedHeight * 0.008) + + color: "transparent" + border.color: "white" + border.width: Math.floor(parent.paintedHeight * 0.008) + radius: Math.floor(parent.paintedHeight * 0.01) + anchors.centerIn: parent + } + + Item { + id: sceneItem + + FontLoader { + id: pt_bold + source: "qrc:/utils/fonts/PTS75F.ttf" + } + + width: Math.floor((parent.paintedHeight * 1.32) - (parent.paintedHeight * 0.013)) + height: Math.floor(parent.paintedHeight - parent.paintedHeight * 0.02) + property variant viewportSize : Qt.size(width, height) + + anchors.centerIn: parent + clip: true + + Loader { + id: worldLoader + anchors.fill: parent + focus: true + source: worldFile + } + + HorizontCenter { + id: horizontCenterItem + sceneSize: sceneItem.viewportSize + anchors.fill: parent + } + + RollScale { + id: rollscale + sceneSize: sceneItem.viewportSize + horizontCenter: horizontCenterItem.horizontCenter + anchors.fill: parent + } + + SvgElementImage { + id: side_slip_fixed + elementName: "sideslip-fixed" + sceneSize: sceneItem.viewportSize + + x: scaledBounds.x * sceneItem.width + } + + Compass { + anchors.fill: parent + sceneSize: sceneItem.viewportSize + } + + SpeedScale { + anchors.fill: parent + sceneSize: sceneItem.viewportSize + } + + AltitudeScale { + anchors.fill: parent + sceneSize: sceneItem.viewportSize + } + + VsiScale { + anchors.fill: parent + sceneSize: sceneItem.viewportSize + visible: pfdContext.altitudeUnit != 0 + } + + Info { + anchors.fill: parent + sceneSize: sceneItem.viewportSize + } + + Panels { + anchors.fill: parent + sceneSize: sceneItem.viewportSize + } + + Warnings { + anchors.fill: parent + sceneSize: sceneItem.viewportSize + } + } + } +} diff --git a/ground/gcs/src/share/qml/pfd/RollScale.qml b/ground/gcs/src/share/qml/pfd/RollScale.qml index 0cf36d533..9aed9ba02 100644 --- a/ground/gcs/src/share/qml/pfd/RollScale.qml +++ b/ground/gcs/src/share/qml/pfd/RollScale.qml @@ -19,7 +19,7 @@ */ import QtQuick 2.4 -import "../uav.js" as UAV +import "../js/uav.js" as UAV Item { id: sceneItem diff --git a/ground/gcs/src/share/qml/pfd/SpeedScale.qml b/ground/gcs/src/share/qml/pfd/SpeedScale.qml index 0b80e4241..ed5606bfb 100644 --- a/ground/gcs/src/share/qml/pfd/SpeedScale.qml +++ b/ground/gcs/src/share/qml/pfd/SpeedScale.qml @@ -19,7 +19,7 @@ */ import QtQuick 2.4 -import "../uav.js" as UAV +import "../js/uav.js" as UAV Item { id: sceneItem diff --git a/ground/gcs/src/share/qml/pfd/VsiScale.qml b/ground/gcs/src/share/qml/pfd/VsiScale.qml index 0aef9b2b5..3ee9c73eb 100644 --- a/ground/gcs/src/share/qml/pfd/VsiScale.qml +++ b/ground/gcs/src/share/qml/pfd/VsiScale.qml @@ -19,7 +19,7 @@ */ import QtQuick 2.4 -import "../uav.js" as UAV +import "../js/uav.js" as UAV Item { id: sceneItem diff --git a/ground/gcs/src/share/qml/pfd/Warnings.qml b/ground/gcs/src/share/qml/pfd/Warnings.qml index 34bf3c7ac..bb399a50b 100644 --- a/ground/gcs/src/share/qml/pfd/Warnings.qml +++ b/ground/gcs/src/share/qml/pfd/Warnings.qml @@ -19,8 +19,8 @@ */ import QtQuick 2.4 -import "../common.js" as Utils -import "../uav.js" as UAV +import "../js/common.js" as Utils +import "../js/uav.js" as UAV Item { id: warnings