1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-12-01 09:24:10 +01:00

Merged in filnet/librepilot/filnet/LP-29_osgearth_integration (pull request #222)

LP-29_osgearth_integration
This commit is contained in:
Lalanne Laurent 2016-04-14 22:14:59 +02:00
commit 23f1867746
75 changed files with 3094 additions and 1816 deletions

View File

@ -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 <osg/Node>
#include <osg/NodeVisitor>
#include <QDebug>
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<osg::NodeCallback> 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

View File

@ -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_

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file Export.hpp * @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
* @{ * @{
* @addtogroup * @addtogroup

View File

@ -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 <osg/Depth>
#include <osg/Texture2D>
#include <osgDB/ReadFile>
#include <QUrl>
#include <QDebug>
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<osg::Texture2D> texture = new osg::Texture2D;
osg::ref_ptr<osg::Image> image = osgDB::readImageFile(url.path().toStdString());
texture->setImage(image.get());
osg::ref_ptr<osg::Drawable> 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<osg::Geode> 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"

View File

@ -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 <osg/Depth>
#include <osg/Texture2D>
#include <osg/ImageSequence>
#include <osgDB/ReadFile>
#include <QDebug>
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<osg::Camera> 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"

View File

@ -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_

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGCamera.cpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -27,41 +27,45 @@
#include "OSGCamera.hpp" #include "OSGCamera.hpp"
#include "OSGNode.hpp"
#include "../utility.h"
#include <osg/Camera> #include <osg/Camera>
#include <osg/Matrix>
#include <osg/Node> #include <osg/Node>
#include <osg/Vec3d>
#include <osgGA/NodeTrackerManipulator>
#include <osgGA/TrackballManipulator>
#include <osgViewer/View>
#ifdef USE_OSGEARTH #ifdef USE_OSGEARTH
#include <osgEarthUtil/EarthManipulator>
#include <osgEarthUtil/LogarithmicDepthBuffer> #include <osgEarthUtil/LogarithmicDepthBuffer>
#endif #endif
#include <QDebug> #include <QDebug>
#include <QThread>
#include <QApplication>
namespace osgQtQuick { namespace osgQtQuick {
enum DirtyFlag { FieldOfView = 1 << 0, ClearColor = 1 << 1, LogDepthBuffer = 1 << 4 };
struct OSGCamera::Hidden : public QObject { struct OSGCamera::Hidden : public QObject {
Q_OBJECT Q_OBJECT
public: private:
Hidden(OSGCamera *camera) : OSGCamera * const self;
QObject(camera), self(camera), sceneNode(NULL),
manipulatorMode(ManipulatorMode::Default), trackerMode(TrackerMode::NodeCenterAndAzim), trackNode(NULL),
logDepthBufferEnabled(false), clampToTerrain(false), intoTerrain(false)
{
fieldOfView = 90.0;
osg::ref_ptr<osg::Camera> 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 #ifdef USE_OSGEARTH
logDepthBuffer = NULL; logDepthBuffer = NULL;
#endif #endif
@ -69,97 +73,6 @@ public:
~Hidden() ~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 #ifdef USE_OSGEARTH
if (logDepthBuffer) { if (logDepthBuffer) {
logDepthBuffer->uninstall(camera); logDepthBuffer->uninstall(camera);
@ -169,93 +82,36 @@ public:
#endif #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) { osg::StateSet *stateset = camera->getOrCreateStateSet();
case ManipulatorMode::Default: stateset->setGlobalDefaults();
{
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;
}
view->setCameraManipulator(cm, false); return camera;
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();
}
} }
void detachManipulator(osgViewer::View *view) void updateClearColor()
{ {
qDebug() << "OSGCamera::detachManipulator" << view; if (!camera.valid()) {
qDebug() << "OSGCamera::updateClearColor - invalid camera";
view->setCameraManipulator(NULL, false); return;
}
// qDebug() << "OSGCamera::updateClearColor" << clearColor;
camera->setClearColor(osg::Vec4(clearColor.redF(), clearColor.greenF(), clearColor.blueF(), clearColor.alphaF()));
} }
void updateFieldOfView() void updateFieldOfView()
{ {
qDebug() << "OSGCamera::updateCameraFOV" << fieldOfView; if (!camera.valid()) {
qDebug() << "OSGCamera::updateFieldOfView - invalid camera";
return;
}
qDebug() << "OSGCamera::updateFieldOfView" << fieldOfView;
double fovy, ar, zn, zf; double fovy, ar, zn, zf;
camera->getProjectionMatrixAsPerspective(fovy, ar, zn, zf); camera->getProjectionMatrixAsPerspective(fovy, ar, zn, zf);
@ -265,7 +121,16 @@ public:
void updateAspectRatio() void updateAspectRatio()
{ {
if (!camera.valid()) {
qDebug() << "OSGCamera::updateAspectRatio - invalid camera";
return;
}
osg::Viewport *viewport = camera->getViewport(); osg::Viewport *viewport = camera->getViewport();
if (!viewport) {
qDebug() << "OSGCamera::updateAspectRatio - no viewport" << viewport;
return;
}
double aspectRatio = static_cast<double>(viewport->width()) / static_cast<double>(viewport->height()); double aspectRatio = static_cast<double>(viewport->width()) / static_cast<double>(viewport->height());
qDebug() << "OSGCamera::updateAspectRatio" << aspectRatio; qDebug() << "OSGCamera::updateAspectRatio" << aspectRatio;
@ -276,113 +141,77 @@ public:
camera->setProjectionMatrixAsPerspective(fovy, ar, zn, zf); camera->setProjectionMatrixAsPerspective(fovy, ar, zn, zf);
} }
void updatePosition() void updateLogDepthBuffer()
{ {
if (manipulatorMode != ManipulatorMode::User) { if (!camera.valid()) {
qWarning() << "OSGCamera::updateLogDepthBuffer - invalid camera";
return; return;
} }
// Altitude mode is absolute (absolute height above MSL/HAE) // qDebug() << "OSGCamera::updateLogDepthBuffer" << logDepthBufferEnabled;
// HAE : Height above ellipsoid. This is the default.
// MSL : Height above Mean Sea Level (MSL) if a geoid separation value is specified.
// TODO handle the case where the terrain SRS is not "wgs84"
// TODO check if position is not below terrain?
// TODO compensate antenna height when source of position is GPS (i.e. subtract antenna height from altitude) ;)
// Camera position
osg::Matrix cameraPosition;
#ifdef USE_OSGEARTH #ifdef USE_OSGEARTH
osgEarth::GeoPoint geoPoint = osgQtQuick::toGeoPoint(position); // install log depth buffer if requested
if (clampToTerrain) { if (logDepthBufferEnabled && !logDepthBuffer) {
if (sceneNode) { qDebug() << "OSGCamera::updateLogDepthBuffer - installing logarithmic depth buffer";
osgEarth::MapNode *mapNode = osgEarth::MapNode::findMapNode(sceneNode->node()); logDepthBuffer = new osgEarth::Util::LogarithmicDepthBuffer();
if (mapNode) { logDepthBuffer->setUseFragDepth(true);
intoTerrain = clampGeoPoint(geoPoint, 0.5f, mapNode); logDepthBuffer->install(camera);
} else { } else if (!logDepthBufferEnabled && logDepthBuffer) {
qWarning() << "OSGCamera::updateNode - scene data does not contain a map node"; 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); qDebug() << "OSGCamera::setGraphicsContext" << gc;
#endif
// Camera orientation camera->setGraphicsContext(gc);
// By default the camera looks toward -Z, we must rotate it so it looks toward Y camera->setViewport(0, 0, gc->getTraits()->width, gc->getTraits()->height);
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));
// Final camera matrix double aspectRatio = static_cast<double>(gc->getTraits()->width) / static_cast<double>(gc->getTraits()->height);
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;
// Inverse the camera's position and orientation matrix to obtain the view matrix camera->setProjectionMatrixAsPerspective(fieldOfView, aspectRatio, 1.0f, 10000.0f);
cameraMatrix = osg::Matrix::inverse(cameraMatrix);
camera->setViewMatrix(cameraMatrix);
}
OSGCamera *const self; double fovy, ar, zn, zf;
camera->getProjectionMatrixAsPerspective(fovy, ar, zn, zf);
osg::ref_ptr<osg::Camera> camera; // FIXME this is needed for PFD + Terrain (because of "user" mode)
// updatePosition();
// 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";
} }
}; };
/* class OSGCamera */ /* class OSGCamera */
enum DirtyFlag { FieldOfView = 1 << 0, Position = 1 << 1, Attitude = 1 << 2 }; OSGCamera::OSGCamera(QObject *parent) : Inherited(parent), h(new Hidden(this))
{}
OSGCamera::OSGCamera(QObject *parent) : OSGNode(parent), h(new Hidden(this))
{
qDebug() << "OSGCamera::OSGCamera";
}
OSGCamera::~OSGCamera() OSGCamera::~OSGCamera()
{ {
qDebug() << "OSGCamera::~OSGCamera";
delete h; 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 qreal OSGCamera::fieldOfView() const
{ {
return h->fieldOfView; return h->fieldOfView;
@ -397,102 +226,7 @@ void OSGCamera::setFieldOfView(qreal arg)
} }
} }
OSGNode *OSGCamera::sceneNode() bool OSGCamera::logarithmicDepthBuffer() const
{
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()
{ {
return h->logDepthBufferEnabled; return h->logDepthBufferEnabled;
} }
@ -501,32 +235,40 @@ void OSGCamera::setLogarithmicDepthBuffer(bool enabled)
{ {
if (h->logDepthBufferEnabled != enabled) { if (h->logDepthBufferEnabled != enabled) {
h->logDepthBufferEnabled = enabled; h->logDepthBufferEnabled = enabled;
setDirty(LogDepthBuffer);
emit logarithmicDepthBufferChanged(logarithmicDepthBuffer()); 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)) { if (isDirty(FieldOfView)) {
h->updateFieldOfView(); h->updateFieldOfView();
} }
if (isDirty(Position | Attitude)) { if (isDirty(LogDepthBuffer)) {
h->updatePosition(); h->updateLogDepthBuffer();
} }
} }
void OSGCamera::attach(osgViewer::View *view) osg::Camera *OSGCamera::asCamera() const
{ {
h->attachCamera(view->getCamera()); // BAD introduce templating
h->attachManipulator(view); return (osg::Camera *)node();
update();
clearDirty();
} }
void OSGCamera::detach(osgViewer::View *view) void OSGCamera::setGraphicsContext(osg::GraphicsContext *gc)
{ {
h->detachManipulator(view); h->setGraphicsContext(gc);
h->detachCamera(view->getCamera());
} }
} // namespace osgQtQuick } // namespace osgQtQuick

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGCamera.hpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -32,114 +32,51 @@
#include "OSGNode.hpp" #include "OSGNode.hpp"
#include <QObject> #include <QObject>
#include <QVector3D> #include <QColor>
namespace osgViewer { namespace osg {
class View; class Camera;
class GraphicsContext;
} }
namespace osgQtQuick { 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 { class OSGQTQUICK_EXPORT OSGCamera : public OSGNode {
Q_OBJECT Q_PROPERTY(qreal fieldOfView READ fieldOfView WRITE setFieldOfView NOTIFY fieldOfViewChanged) Q_OBJECT Q_PROPERTY(QColor clearColor READ clearColor WRITE setClearColor NOTIFY clearColorChanged)
Q_PROPERTY(osgQtQuick::OSGNode * sceneNode READ sceneNode WRITE setSceneNode NOTIFY sceneNodeChanged) Q_PROPERTY(qreal fieldOfView READ fieldOfView WRITE setFieldOfView NOTIFY fieldOfViewChanged)
Q_PROPERTY(osgQtQuick::ManipulatorMode::Enum manipulatorMode READ manipulatorMode WRITE setManipulatorMode NOTIFY manipulatorModeChanged)
Q_PROPERTY(osgQtQuick::OSGNode * trackNode READ trackNode WRITE setTrackNode NOTIFY trackNodeChanged)
Q_PROPERTY(osgQtQuick::TrackerMode::Enum trackerMode READ trackerMode WRITE setTrackerMode NOTIFY trackerModeChanged)
Q_PROPERTY(bool clampToTerrain READ clampToTerrain WRITE setClampToTerrain NOTIFY clampToTerrainChanged)
Q_PROPERTY(bool intoTerrain READ intoTerrain NOTIFY intoTerrainChanged)
Q_PROPERTY(QVector3D attitude READ attitude WRITE setAttitude NOTIFY attitudeChanged)
Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged)
Q_PROPERTY(bool logarithmicDepthBuffer READ logarithmicDepthBuffer WRITE setLogarithmicDepthBuffer NOTIFY logarithmicDepthBufferChanged) Q_PROPERTY(bool logarithmicDepthBuffer READ logarithmicDepthBuffer WRITE setLogarithmicDepthBuffer NOTIFY logarithmicDepthBufferChanged)
typedef OSGNode Inherited;
friend class OSGViewport; friend class OSGViewport;
public: public:
explicit OSGCamera(QObject *parent = 0); explicit OSGCamera(QObject *parent = 0);
virtual ~OSGCamera(); virtual ~OSGCamera();
// fov depends on the scenery space (probaby distance) QColor clearColor() const;
// here are some value: 75°, 60°, 45° many gamers use void setClearColor(const QColor &color);
// x-plane uses 45° for 4:3 and 60° for 16:9/16:10
// flightgear uses 55° / 70°
qreal fieldOfView() const; qreal fieldOfView() const;
void setFieldOfView(qreal arg); void setFieldOfView(qreal arg);
OSGNode *sceneNode(); bool logarithmicDepthBuffer() const;
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();
void setLogarithmicDepthBuffer(bool enabled); void setLogarithmicDepthBuffer(bool enabled);
signals: signals:
void clearColorChanged(const QColor &color);
void fieldOfViewChanged(qreal arg); 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); void logarithmicDepthBufferChanged(bool enabled);
protected:
virtual osg::Node *createNode();
virtual void updateNode();
private: private:
struct Hidden; struct Hidden;
Hidden *h; Hidden *const h;
virtual void update(); osg::Camera *asCamera() const;
void setGraphicsContext(osg::GraphicsContext *gc);
virtual void attach(osgViewer::View *view);
virtual void detach(osgViewer::View *view);
}; };
} // namespace osgQtQuick } // namespace osgQtQuick

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGFileNode.cpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -37,11 +37,14 @@
#include <QDebug> #include <QDebug>
namespace osgQtQuick { namespace osgQtQuick {
enum DirtyFlag { Source = 1 << 0, Async = 1 << 1, OptimizeMode = 1 << 2 };
class OSGFileLoader : public QThread { class OSGFileLoader : public QThread {
Q_OBJECT Q_OBJECT
public: public:
OSGFileLoader(const QUrl &url) : url(url) {} OSGFileLoader(const QUrl &url) : url(url)
{}
void run() void run()
{ {
@ -54,9 +57,12 @@ public:
QElapsedTimer t; QElapsedTimer t;
t.start(); t.start();
qDebug() << "OSGFileLoader::load - reading node file" << url.path(); // qDebug() << "OSGFileLoader::load - reading node file" << url.path();
// qDebug() << "OSGFileLoader - load - currentContext" << QOpenGLContext::currentContext(); // qDebug() << "OSGFileLoader - load - currentContext" << QOpenGLContext::currentContext();
osg::Node *node = osgDB::readNodeFile(url.path().toStdString()); 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"; // qDebug() << "OSGFileLoader::load - reading node" << node << "took" << t.elapsed() << "ms";
return node; return node;
} }
@ -79,11 +85,12 @@ public:
bool async; bool async;
OptimizeMode::Enum optimizeMode; 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()) { if (!source.isValid()) {
self->setNode(NULL); self->setNode(NULL);
if (!source.isEmpty()) { if (!source.isEmpty()) {
@ -118,7 +125,7 @@ private:
void setNode(osg::Node *node) void setNode(osg::Node *node)
{ {
qDebug() << "OSGFileNode::setNode" << node; // qDebug() << "OSGFileNode::setNode" << node;
if (node && optimizeMode != OptimizeMode::None) { if (node && optimizeMode != OptimizeMode::None) {
// qDebug() << "OSGFileNode::acceptNode - optimize" << node << optimizeMode; // qDebug() << "OSGFileNode::acceptNode - optimize" << node << optimizeMode;
osgUtil::Optimizer optimizer; osgUtil::Optimizer optimizer;
@ -139,18 +146,11 @@ private slots:
/* class OSGFileNode */ /* class OSGFileNode */
enum DirtyFlag { Source = 1 << 0, Async = 1 << 1, OptimizeMode = 1 << 2 }; OSGFileNode::OSGFileNode(QObject *parent) : Inherited(parent), h(new Hidden(this))
{}
OSGFileNode::OSGFileNode(QObject *parent) : OSGNode(parent), h(new Hidden(this))
{
qDebug() << "OSGFileNode::OSGFileNode";
setAsync(false);
setOptimizeMode(OptimizeMode::None);
}
OSGFileNode::~OSGFileNode() OSGFileNode::~OSGFileNode()
{ {
// qDebug() << "OSGFileNode::~OSGFileNode";
delete h; delete h;
} }
@ -161,7 +161,6 @@ const QUrl OSGFileNode::source() const
void OSGFileNode::setSource(const QUrl &source) void OSGFileNode::setSource(const QUrl &source)
{ {
qDebug() << "OSGFileNode::setSource" << source;
if (h->source != source) { if (h->source != source) {
h->source = source; h->source = source;
setDirty(Source); setDirty(Source);
@ -176,7 +175,6 @@ bool OSGFileNode::async() const
void OSGFileNode::setAsync(const bool async) void OSGFileNode::setAsync(const bool async)
{ {
// qDebug() << "OSGFileNode::setAsync" << async;
if (h->async != async) { if (h->async != async) {
h->async = async; h->async = async;
setDirty(Async); setDirty(Async);
@ -191,7 +189,6 @@ OptimizeMode::Enum OSGFileNode::optimizeMode() const
void OSGFileNode::setOptimizeMode(OptimizeMode::Enum optimizeMode) void OSGFileNode::setOptimizeMode(OptimizeMode::Enum optimizeMode)
{ {
// qDebug() << "OSGFileNode::setOptimizeMode" << optimizeMode;
if (h->optimizeMode != optimizeMode) { if (h->optimizeMode != optimizeMode) {
h->optimizeMode = optimizeMode; h->optimizeMode = optimizeMode;
setDirty(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)) { if (isDirty(Async)) {
// do nothing... // do nothing...
} }
@ -208,18 +213,9 @@ void OSGFileNode::update()
// TODO: trigger a node update ? // TODO: trigger a node update ?
} }
if (isDirty(Source)) { if (isDirty(Source)) {
h->updateNode(); h->updateSource();
} }
} }
void OSGFileNode::attach(osgViewer::View *view)
{
update();
clearDirty();
}
void OSGFileNode::detach(osgViewer::View *view)
{}
} // namespace osgQtQuick } // namespace osgQtQuick
#include "OSGFileNode.moc" #include "OSGFileNode.moc"

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGFileNode.hpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -39,6 +39,7 @@ QT_END_NAMESPACE
namespace osgQtQuick { namespace osgQtQuick {
class OSGQTQUICK_EXPORT OptimizeMode : public QObject { class OSGQTQUICK_EXPORT OptimizeMode : public QObject {
Q_OBJECT Q_OBJECT
public: public:
enum Enum { None, Optimize, OptimizeAndCheck }; enum Enum { None, Optimize, OptimizeAndCheck };
Q_ENUMS(Enum) // TODO switch to Q_ENUM once on Qt 5.5 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(bool async READ async WRITE setAsync NOTIFY asyncChanged)
Q_PROPERTY(osgQtQuick::OptimizeMode::Enum optimizeMode READ optimizeMode WRITE setOptimizeMode NOTIFY optimizeModeChanged) Q_PROPERTY(osgQtQuick::OptimizeMode::Enum optimizeMode READ optimizeMode WRITE setOptimizeMode NOTIFY optimizeModeChanged)
typedef OSGNode Inherited;
public: public:
OSGFileNode(QObject *parent = 0); OSGFileNode(QObject *parent = 0);
virtual ~OSGFileNode(); virtual ~OSGFileNode();
@ -67,14 +70,13 @@ signals:
void asyncChanged(const bool async); void asyncChanged(const bool async);
void optimizeModeChanged(OptimizeMode::Enum); void optimizeModeChanged(OptimizeMode::Enum);
protected:
virtual osg::Node *createNode();
virtual void updateNode();
private: private:
struct Hidden; struct Hidden;
Hidden *h; Hidden *const h;
virtual void update();
virtual void attach(osgViewer::View *view);
virtual void detach(osgViewer::View *view);
}; };
} // namespace osgQtQuick } // namespace osgQtQuick

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGGeoTransformNode.cpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -27,7 +27,7 @@
#include "OSGGeoTransformNode.hpp" #include "OSGGeoTransformNode.hpp"
#include "../utility.h" #include "utils/utility.h"
#include <osg/ComputeBoundsVisitor> #include <osg/ComputeBoundsVisitor>
@ -38,6 +38,10 @@
#include <QDebug> #include <QDebug>
namespace osgQtQuick { 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 { struct OSGGeoTransformNode::Hidden : public QObject {
Q_OBJECT Q_OBJECT
@ -47,7 +51,6 @@ private:
osg::ref_ptr<osgEarth::GeoTransform> transform; osg::ref_ptr<osgEarth::GeoTransform> transform;
public: public:
OSGNode *childNode;
OSGNode *sceneNode; OSGNode *sceneNode;
float offset; float offset;
@ -57,31 +60,14 @@ public:
QVector3D position; 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 = new osgEarth::GeoTransform();
transform->setAutoRecomputeHeights(true); transform->setAutoRecomputeHeights(true);
self->setNode(transform); return 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;
} }
bool acceptSceneNode(OSGNode *node) bool acceptSceneNode(OSGNode *node)
@ -98,37 +84,15 @@ public:
sceneNode = node; sceneNode = node;
if (sceneNode) { if (sceneNode) {
connect(sceneNode, SIGNAL(nodeChanged(osg::Node *)), this, SLOT(onSceneNodeChanged(osg::Node *))); connect(sceneNode, &OSGNode::nodeChanged, this, &OSGGeoTransformNode::Hidden::onSceneNodeChanged);
} }
return true; 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() void updateSceneNode()
{ {
qDebug() << "OSGGeoTransformNode::updateSceneNode" << sceneNode;
if (sceneNode && sceneNode->node()) { if (sceneNode && sceneNode->node()) {
osgEarth::MapNode *mapNode = osgEarth::MapNode::findMapNode(sceneNode->node()); osgEarth::MapNode *mapNode = osgEarth::MapNode::findMapNode(sceneNode->node());
if (mapNode) { if (mapNode) {
@ -141,15 +105,20 @@ public:
void updatePosition() void updatePosition()
{ {
// qDebug() << "OSGGeoTransformNode::updatePosition" << position;
osgEarth::MapNode *mapNode = NULL; osgEarth::MapNode *mapNode = NULL;
if (sceneNode && sceneNode->node()) { if (sceneNode && sceneNode->node()) {
mapNode = osgEarth::MapNode::findMapNode(sceneNode->node()); mapNode = osgEarth::MapNode::findMapNode(sceneNode->node());
} if (!mapNode) {
if (!mapNode) { qWarning() << "OSGGeoTransformNode::updatePosition - scene node does not contain a map node";
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; osgEarth::GeoPoint geoPoint;
if (mapNode) { if (mapNode) {
geoPoint = osgQtQuick::toGeoPoint(mapNode->getTerrain()->getSRS(), position); geoPoint = osgQtQuick::toGeoPoint(mapNode->getTerrain()->getSRS(), position);
@ -160,7 +129,7 @@ public:
// get "size" of model // get "size" of model
// TODO this should be done once only... // TODO this should be done once only...
osg::ComputeBoundsVisitor cbv; osg::ComputeBoundsVisitor cbv;
childNode->node()->accept(cbv); transform->accept(cbv);
const osg::BoundingBox & bbox = cbv.getBoundingBox(); const osg::BoundingBox & bbox = cbv.getBoundingBox();
offset = bbox.radius(); offset = bbox.radius();
@ -168,53 +137,33 @@ public:
// clamp model to terrain if needed // clamp model to terrain if needed
intoTerrain = clampGeoPoint(geoPoint, offset, mapNode); intoTerrain = clampGeoPoint(geoPoint, offset, mapNode);
} else if (clampToTerrain) {
qWarning() << "OSGGeoTransformNode::onChildNodeChanged - cannot clamp without map node";
} }
transform->setPosition(geoPoint); transform->setPosition(geoPoint);
} }
private slots: private slots:
void onChildNodeChanged(osg::Node *node)
{
qDebug() << "OSGGeoTransformNode::onChildNodeChanged" << node;
updateTransformNode();
}
void onSceneNodeChanged(osg::Node *node) void onSceneNodeChanged(osg::Node *node)
{ {
qDebug() << "OSGGeoTransformNode::onSceneNodeChanged" << node; qDebug() << "OSGGeoTransformNode::onSceneNodeChanged" << node;
// TODO updateSceneNode();
updatePosition();
} }
}; };
/* class OSGGeoTransformNode */ /* class OSGGeoTransformNode */
enum DirtyFlag { Child = 1 << 0, Scene = 1 << 1, Position = 1 << 2, Clamp = 1 << 3 }; OSGGeoTransformNode::OSGGeoTransformNode(QObject *parent) : Inherited(parent), h(new Hidden(this))
{}
OSGGeoTransformNode::OSGGeoTransformNode(QObject *parent) : OSGNode(parent), h(new Hidden(this))
{
qDebug() << "OSGGeoTransformNode::OSGGeoTransformNode";
}
OSGGeoTransformNode::~OSGGeoTransformNode() OSGGeoTransformNode::~OSGGeoTransformNode()
{ {
// qDebug() << "OSGGeoTransformNode::~OSGGeoTransformNode";
delete h; delete h;
} }
OSGNode *OSGGeoTransformNode::childNode() OSGNode *OSGGeoTransformNode::sceneNode() const
{
return h->childNode;
}
void OSGGeoTransformNode::setChildNode(OSGNode *node)
{
if (h->acceptChildNode(node)) {
setDirty(Child);
emit childNodeChanged(node);
}
}
OSGNode *OSGGeoTransformNode::sceneNode()
{ {
return h->sceneNode; return h->sceneNode;
} }
@ -260,32 +209,25 @@ void OSGGeoTransformNode::setPosition(QVector3D arg)
} }
} }
void OSGGeoTransformNode::update() osg::Node *OSGGeoTransformNode::createNode()
{ {
if (isDirty(Child)) { return h->createNode();
h->updateTransformNode(); }
}
void OSGGeoTransformNode::updateNode()
{
Inherited::updateNode();
if (isDirty(Scene)) { if (isDirty(Scene)) {
h->updateSceneNode(); h->updateSceneNode();
} }
if (isDirty(Clamp)) {} if (isDirty(Clamp)) {
if (isDirty(Position)) { // do nothing...
}
if (isDirty(Scene | Clamp | Position)) {
h->updatePosition(); 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 } // namespace osgQtQuick
#include "OSGGeoTransformNode.moc" #include "OSGGeoTransformNode.moc"

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGGeoTransformNode.hpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -29,32 +29,24 @@
#define _H_OSGQTQUICK_GEOTRANSFORMNODE_H_ #define _H_OSGQTQUICK_GEOTRANSFORMNODE_H_
#include "Export.hpp" #include "Export.hpp"
#include "OSGNode.hpp" #include "OSGGroup.hpp"
#include <QVector3D> #include <QVector3D>
// TODO derive from OSGGroup...
namespace osgQtQuick { namespace osgQtQuick {
class OSGQTQUICK_EXPORT OSGGeoTransformNode : public OSGNode { class OSGQTQUICK_EXPORT OSGGeoTransformNode : public OSGGroup {
Q_OBJECT Q_OBJECT Q_PROPERTY(osgQtQuick::OSGNode *sceneNode READ sceneNode WRITE setSceneNode NOTIFY sceneNodeChanged)
// 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)
Q_PROPERTY(bool clampToTerrain READ clampToTerrain WRITE setClampToTerrain NOTIFY clampToTerrainChanged) Q_PROPERTY(bool clampToTerrain READ clampToTerrain WRITE setClampToTerrain NOTIFY clampToTerrainChanged)
Q_PROPERTY(bool intoTerrain READ intoTerrain NOTIFY intoTerrainChanged) Q_PROPERTY(bool intoTerrain READ intoTerrain NOTIFY intoTerrainChanged)
Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged) Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged)
typedef OSGGroup Inherited;
public: public:
OSGGeoTransformNode(QObject *parent = 0); OSGGeoTransformNode(QObject *parent = 0);
virtual ~OSGGeoTransformNode(); virtual ~OSGGeoTransformNode();
OSGNode *childNode(); OSGNode *sceneNode() const;
void setChildNode(OSGNode *node);
OSGNode *sceneNode();
void setSceneNode(OSGNode *node); void setSceneNode(OSGNode *node);
bool clampToTerrain() const; bool clampToTerrain() const;
@ -66,23 +58,18 @@ public:
void setPosition(QVector3D arg); void setPosition(QVector3D arg);
signals: signals:
void childNodeChanged(OSGNode *node);
void sceneNodeChanged(OSGNode *node); void sceneNodeChanged(OSGNode *node);
void clampToTerrainChanged(bool arg); void clampToTerrainChanged(bool arg);
void intoTerrainChanged(bool arg); void intoTerrainChanged(bool arg);
void positionChanged(QVector3D arg); void positionChanged(QVector3D arg);
protected:
virtual osg::Node *createNode();
virtual void updateNode();
private: private:
struct Hidden; struct Hidden;
Hidden *h; Hidden *const h;
virtual void update();
virtual void attach(osgViewer::View *view);
virtual void detach(osgViewer::View *view);
}; };
} // namespace osgQtQuick } // namespace osgQtQuick

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGGroup.cpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -39,26 +39,26 @@ struct OSGGroup::Hidden : public QObject {
Q_OBJECT Q_OBJECT
private: private:
OSGGroup * self; OSGGroup * const self;
osg::ref_ptr<osg::Group> group;
QMap<OSGNode *, osg::Node *> cache; QMap<OSGNode *, osg::Node *> cache;
public:
Hidden(OSGGroup *node) : QObject(node), self(node), group(new osg::Group)
{
group = new osg::Group();
self->setNode(group);
}
QList<OSGNode *> children; QList<OSGNode *> children;
public:
Hidden(OSGGroup *self) : QObject(self), self(self)
{}
osg::Node *createNode()
{
return new osg::Group();
}
void appendChild(OSGNode *childNode) void appendChild(OSGNode *childNode)
{ {
cache[childNode] = childNode->node(); // qDebug() << "OSGGroup::appendChild" << childNode;
children.append(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); self->setDirty(Children);
} }
@ -86,27 +86,39 @@ public:
self->setDirty(Children); self->setDirty(Children);
} }
void updateGroupNode() void updateChildren()
{ {
qDebug() << "OSGGroup::updateChildren";
osg::Group *group = static_cast<osg::Group *>(self->node());
if (!group) {
qWarning() << "OSGGroup::updateChildren - null group";
return;
}
bool updated = false; bool updated = false;
unsigned int index = 0; unsigned int index = 0;
QListIterator<OSGNode *> i(children); QListIterator<OSGNode *> i(children);
while (i.hasNext()) { while (i.hasNext()) {
OSGNode *childNode = i.next(); OSGNode *childNode = i.next();
if (index < group->getNumChildren()) { // qDebug() << "OSGGroup::updateChildren - child" << childNode;
updated |= group->replaceChild(group->getChild(index), childNode->node()); if (childNode->node()) {
} else { if (index < group->getNumChildren()) {
updated |= group->addChild(childNode->node()); 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 // removing eventual left overs
if (index < group->getNumChildren()) { if (index < group->getNumChildren()) {
updated |= group->removeChild(index, group->getNumChildren() - index); updated |= group->removeChild(index, group->getNumChildren() - index);
} }
// if (updated) { // if (updated) {
self->emitNodeChanged(); // self->emitNodeChanged();
// } // }
} }
@ -141,37 +153,53 @@ public:
} }
private slots: private slots:
void onChildNodeChanged(osg::Node *node) void onChildNodeChanged(osg::Node *child)
{ {
qDebug() << "OSGGroup::onChildNodeChanged" << node; // qDebug() << "OSGGroup::onChildNodeChanged" << node;
OSGNode *obj = qobject_cast<OSGNode *>(sender());
if (obj) { osg::Group *group = static_cast<osg::Group *>(self->node());
osg::Node *cacheNode = cache.value(obj, NULL);
if (cacheNode) { if (!group) {
group->replaceChild(cacheNode, node); qWarning() << "OSGGroup::onChildNodeChanged - null group";
} else { return;
// should not happen...
}
cache[obj] = node;
// emit self->nodeChanged(group.get());
} }
OSGNode *childNode = qobject_cast<OSGNode *>(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 */ /* class OSGGGroupNode */
OSGGroup::OSGGroup(QObject *parent) : OSGNode(parent), h(new Hidden(this)) OSGGroup::OSGGroup(QObject *parent) : Inherited(parent), h(new Hidden(this))
{ {}
qDebug() << "OSGGroup::OSGGroup";
}
OSGGroup::~OSGGroup() OSGGroup::~OSGGroup()
{ {
// qDebug() << "OSGGroup::~OSGGroup";
delete h; delete h;
} }
QQmlListProperty<OSGNode> OSGGroup::children() QQmlListProperty<OSGNode> OSGGroup::children() const
{ {
return QQmlListProperty<OSGNode>(h, 0, return QQmlListProperty<OSGNode>(h, 0,
&Hidden::append_child, &Hidden::append_child,
@ -180,34 +208,17 @@ QQmlListProperty<OSGNode> OSGGroup::children()
&Hidden::clear_child); &Hidden::clear_child);
} }
void OSGGroup::update() osg::Node *OSGGroup::createNode()
{ {
return h->createNode();
}
void OSGGroup::updateNode()
{
Inherited::updateNode();
if (isDirty(Children)) { if (isDirty(Children)) {
h->updateGroupNode(); h->updateChildren();
}
}
void OSGGroup::attach(osgViewer::View *view)
{
// qDebug() << "OSGGroup::attach " << view;
QListIterator<OSGNode *> 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<OSGNode *> i(h->children);
while (i.hasNext()) {
OSGNode *node = i.next();
// qDebug() << "OSGGroup::detach - child" << node;
OSGNode::detach(node, view);
} }
} }
} // namespace osgQtQuick } // namespace osgQtQuick

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGGroup.hpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -39,20 +39,21 @@ class OSGQTQUICK_EXPORT OSGGroup : public OSGNode {
Q_CLASSINFO("DefaultProperty", "children") Q_CLASSINFO("DefaultProperty", "children")
typedef OSGNode Inherited;
public: public:
explicit OSGGroup(QObject *parent = 0); explicit OSGGroup(QObject *parent = 0);
virtual ~OSGGroup(); virtual ~OSGGroup();
QQmlListProperty<OSGNode> children(); QQmlListProperty<OSGNode> children() const;
protected:
virtual osg::Node *createNode();
virtual void updateNode();
private: private:
struct Hidden; struct Hidden;
Hidden *h; Hidden *const h;
virtual void update();
virtual void attach(osgViewer::View *view);
virtual void detach(osgViewer::View *view);
}; };
} // namespace osgQtQuick } // namespace osgQtQuick

View File

@ -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 <osg/Texture2D>
#include <osgDB/ReadFile>
#include <QUrl>
#include <QDebug>
namespace osgQtQuick {
enum DirtyFlag { ImageFile = 1 << 0 };
struct OSGImageNode::Hidden : public QObject {
Q_OBJECT
private:
OSGImageNode * const self;
osg::ref_ptr<osg::Texture2D> 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"

View File

@ -1,8 +1,8 @@
/** /**
****************************************************************************** ******************************************************************************
* *
* @file OSGBackgroundNode.hpp * @file OSGImageNode.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
* @{ * @{
* @addtogroup * @addtogroup
@ -25,24 +25,23 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#ifndef _H_OSGQTQUICK_BACKGROUNDNODE_H_ #ifndef _H_OSGQTQUICK_IMAGENODE_H_
#define _H_OSGQTQUICK_BACKGROUNDNODE_H_ #define _H_OSGQTQUICK_IMAGENODE_H_
#include "Export.hpp" #include "Export.hpp"
#include "OSGNode.hpp" #include "OSGNode.hpp"
#include <QUrl> #include <QUrl>
QT_BEGIN_NAMESPACE
class QUrl;
QT_END_NAMESPACE
namespace osgQtQuick { 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) Q_OBJECT Q_PROPERTY(QUrl imageFile READ imageFile WRITE setImageFile NOTIFY imageFileChanged)
typedef OSGNode Inherited;
public: public:
OSGBackgroundNode(QObject *parent = 0); OSGImageNode(QObject *parent = 0);
virtual ~OSGBackgroundNode(); virtual ~OSGImageNode();
const QUrl imageFile() const; const QUrl imageFile() const;
void setImageFile(const QUrl &url); void setImageFile(const QUrl &url);
@ -50,15 +49,14 @@ public:
signals: signals:
void imageFileChanged(const QUrl &url); void imageFileChanged(const QUrl &url);
protected:
virtual osg::Node *createNode();
virtual void updateNode();
private: private:
struct Hidden; struct Hidden;
Hidden *h; Hidden *const h;
virtual void update();
virtual void attach(osgViewer::View *view);
virtual void detach(osgViewer::View *view);
}; };
} // namespace osgQtQuick } // namespace osgQtQuick
#endif // _H_OSGQTQUICK_BACKGROUNDNODE_H_ #endif // _H_OSGQTQUICK_IMAGENODE_H_

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGNode.cpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -27,75 +27,39 @@
#include "OSGNode.hpp" #include "OSGNode.hpp"
#include "DirtySupport.hpp"
#include <osg/Node> #include <osg/Node>
#include <osg/NodeVisitor>
#include <QDebug> #include <QDebug>
namespace osgQtQuick { namespace osgQtQuick {
class OSGNode; class OSGNode;
class Hidden;
struct NodeUpdateCallback : public osg::NodeCallback { struct OSGNode::Hidden : public QObject, public DirtySupport {
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 {
Q_OBJECT Q_OBJECT
friend class OSGNode; friend class OSGNode;
private:
OSGNode *const self;
osg::ref_ptr<osg::Node> node;
bool complete;
public: 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; return self->node();
}
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);
}
} }
void update() void update()
{ {
// qDebug() << "OSGNode::update BEGIN"; return self->updateNode();
if (dirty) {
// qDebug() << "OSGNode::update UPDATE";
self->update();
}
clearDirty();
// qDebug() << "OSGNode::update DONE";
} }
bool acceptNode(osg::Node *aNode) bool acceptNode(osg::Node *aNode)
@ -103,43 +67,24 @@ public:
if (node == aNode) { if (node == aNode) {
return false; return false;
} }
if (node && dirty) {
// qDebug() << "OSGNode::acceptNode REMOVE CALLBACK" << node; int flags = dirty();
node->setUpdateCallback(NULL); if (flags) {
clearDirty();
} }
node = aNode; node = aNode;
if (node) { if (node) {
if (dirty) { if (flags) {
if (!nodeUpdateCallback.valid()) { setDirty(flags);
// lazy creation
// qDebug() << "OSGNode::acceptNode CREATE CALLBACK";
nodeUpdateCallback = new NodeUpdateCallback(this);
}
// qDebug() << "OSGNode::acceptNode ADD CALLBACK";
node->setUpdateCallback(nodeUpdateCallback);
} }
} }
return true; return true;
} }
private:
OSGNode *const self;
osg::ref_ptr<osg::Node> node;
osg::ref_ptr<osg::NodeCallback> nodeUpdateCallback;
int dirty;
}; };
void NodeUpdateCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) /* class OSGNode */
{
// qDebug() << "NodeUpdateCallback::";
nv->traverse(*node);
h->update();
}
OSGNode::OSGNode(QObject *parent) : QObject(parent), h(new Hidden(this)) OSGNode::OSGNode(QObject *parent) : QObject(parent), QQmlParserStatus(), h(new Hidden(this))
{} {}
OSGNode::~OSGNode() OSGNode::~OSGNode()
@ -155,16 +100,11 @@ osg::Node *OSGNode::node() const
void OSGNode::setNode(osg::Node *node) void OSGNode::setNode(osg::Node *node)
{ {
if (h->acceptNode(node)) { if (h->acceptNode(node)) {
emit nodeChanged(node); emitNodeChanged();
} }
} }
bool OSGNode::isDirty() bool OSGNode::isDirty(int mask) const
{
return h->isDirty(0xFFFFFFFF);
}
bool OSGNode::isDirty(int mask)
{ {
return h->isDirty(mask); return h->isDirty(mask);
} }
@ -179,30 +119,39 @@ void OSGNode::clearDirty()
h->clearDirty(); h->clearDirty();
} }
void OSGNode::attach(OSGNode *node, osgViewer::View *view) osg::Node *OSGNode::createNode()
{ {
if (!node) { return NULL;
return;
}
node->attach(view);
} }
void OSGNode::detach(OSGNode *node, osgViewer::View *view) void OSGNode::updateNode()
{}
void OSGNode::emitNodeChanged()
{ {
if (!node) { if (h->complete) {
return; 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 } // namespace osgQtQuick
#include "OSGNode.moc" #include "OSGNode.moc"

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGNode.hpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -31,6 +31,7 @@
#include "Export.hpp" #include "Export.hpp"
#include <QObject> #include <QObject>
#include <QQmlParserStatus>
/** /**
* Only update() methods are allowed to update the OSG scenegraph. * Only update() methods are allowed to update the OSG scenegraph.
@ -39,25 +40,19 @@
* - node change events should be handled right away. * - node change events should be handled right away.
* *
* Setting an OSGNode dirty will trigger the addition of a one time update callback. * Setting an OSGNode dirty will trigger the addition of a one time update callback.
* *
* This approach leads to some potential issues: * 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). * - 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 { namespace osg {
class Node; class Node;
} // namespace osg } // namespace osg
namespace osgViewer {
class View;
} // namespace osgViewer
namespace osgQtQuick { namespace osgQtQuick {
class OSGQTQUICK_EXPORT OSGNode : public QObject { class OSGQTQUICK_EXPORT OSGNode : public QObject, public QQmlParserStatus {
Q_OBJECT Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
friend class OSGViewport;
friend class NodeUpdateCallback;
public: public:
explicit OSGNode(QObject *parent = 0); explicit OSGNode(QObject *parent = 0);
@ -66,31 +61,25 @@ public:
osg::Node *node() const; osg::Node *node() const;
void setNode(osg::Node *node); 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: signals:
void nodeChanged(osg::Node *node) const; 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: private:
struct Hidden; struct Hidden;
Hidden *h; Hidden *const h;
virtual void attach(osgViewer::View *view);
virtual void detach(osgViewer::View *view);
virtual void update();
}; };
} // namespace osgQtQuick } // namespace osgQtQuick

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGShapeNode.cpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -27,7 +27,7 @@
#include "OSGShapeNode.hpp" #include "OSGShapeNode.hpp"
#include "../shapeutils.h" #include "utils/shapeutils.h"
#include <osg/Geode> #include <osg/Geode>
#include <osg/Group> #include <osg/Group>
@ -37,19 +37,21 @@
#include <QDebug> #include <QDebug>
namespace osgQtQuick { namespace osgQtQuick {
enum DirtyFlag { ShapeType = 1 << 0 };
struct OSGShapeNode::Hidden : public QObject { struct OSGShapeNode::Hidden : public QObject {
Q_OBJECT Q_OBJECT
private: private:
OSGShapeNode * self; OSGShapeNode * const self;
public: public:
ShapeType::Enum shapeType; 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; osg::Node *node = NULL;
@ -67,26 +69,19 @@ public:
node = ShapeUtils::create3DAxis(); node = ShapeUtils::create3DAxis();
break; break;
} }
// Add the node to the scene
self->setNode(node); self->setNode(node);
} }
}; };
/* class OSGShapeNode */ /* class OSGShapeNode */
enum DirtyFlag { Type = 1 << 0 }; OSGShapeNode::OSGShapeNode(QObject *parent) : Inherited(parent), h(new Hidden(this))
// TODO turn into generic shape node...
// see http://trac.openscenegraph.org/projects/osg//wiki/Support/Tutorials/TransformsAndStates
OSGShapeNode::OSGShapeNode(QObject *parent) : OSGNode(parent), h(new Hidden(this))
{ {
qDebug() << "OSGShapeNode::OSGShapeNode"; setDirty(ShapeType);
setShapeType(ShapeType::Sphere);
} }
OSGShapeNode::~OSGShapeNode() OSGShapeNode::~OSGShapeNode()
{ {
// qDebug() << "OSGShapeNode::~OSGShapeNode";
delete h; delete h;
} }
@ -99,26 +94,24 @@ void OSGShapeNode::setShapeType(ShapeType::Enum type)
{ {
if (h->shapeType != type) { if (h->shapeType != type) {
h->shapeType = type; h->shapeType = type;
setDirty(Type); setDirty(ShapeType);
emit shapeTypeChanged(type); emit shapeTypeChanged(type);
} }
} }
void OSGShapeNode::update() osg::Node *OSGShapeNode::createNode()
{ {
if (isDirty(Type)) { return NULL;
h->updateNode(); }
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 } // namespace osgQtQuick
#include "OSGShapeNode.moc" #include "OSGShapeNode.moc"

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGShapeNode.hpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -42,6 +42,8 @@ public:
class OSGQTQUICK_EXPORT OSGShapeNode : public OSGNode { class OSGQTQUICK_EXPORT OSGShapeNode : public OSGNode {
Q_OBJECT Q_PROPERTY(osgQtQuick::ShapeType::Enum shapeType READ shapeType WRITE setShapeType NOTIFY shapeTypeChanged) Q_OBJECT Q_PROPERTY(osgQtQuick::ShapeType::Enum shapeType READ shapeType WRITE setShapeType NOTIFY shapeTypeChanged)
typedef OSGNode Inherited;
public: public:
OSGShapeNode(QObject *parent = 0); OSGShapeNode(QObject *parent = 0);
virtual ~OSGShapeNode(); virtual ~OSGShapeNode();
@ -52,14 +54,13 @@ public:
signals: signals:
void shapeTypeChanged(ShapeType::Enum); void shapeTypeChanged(ShapeType::Enum);
protected:
virtual osg::Node *createNode();
virtual void updateNode();
private: private:
struct Hidden; struct Hidden;
Hidden *h; Hidden *const h;
virtual void update();
virtual void attach(osgViewer::View *view);
virtual void detach(osgViewer::View *view);
}; };
} // namespace osgQtQuick } // namespace osgQtQuick

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGSkyNode.cpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -27,6 +27,8 @@
#include "OSGSkyNode.hpp" #include "OSGSkyNode.hpp"
#include "OSGViewport.hpp"
#include <osgViewer/View> #include <osgViewer/View>
#include <osgEarth/Config> #include <osgEarth/Config>
@ -39,6 +41,8 @@
#include <QDebug> #include <QDebug>
namespace osgQtQuick { namespace osgQtQuick {
enum DirtyFlag { Scene = 1 << 0, Viewport = 1 << 1, DateTime = 1 << 2, Light = 1 << 3 };
struct OSGSkyNode::Hidden : public QObject { struct OSGSkyNode::Hidden : public QObject {
Q_OBJECT Q_OBJECT
@ -48,13 +52,15 @@ private:
osg::ref_ptr<osgEarth::Util::SkyNode> skyNode; osg::ref_ptr<osgEarth::Util::SkyNode> skyNode;
public: public:
OSGNode *sceneNode; OSGNode *sceneNode;
OSGViewport *viewport;
bool sunLightEnabled; bool sunLightEnabled;
QDateTime dateTime; QDateTime dateTime;
double minimumAmbientLight; 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(); dateTime = QDateTime::currentDateTime();
} }
@ -76,27 +82,28 @@ public:
sceneNode = node; sceneNode = node;
if (sceneNode) { if (sceneNode) {
connect(sceneNode, SIGNAL(nodeChanged(osg::Node *)), this, SLOT(onSceneNodeChanged(osg::Node *))); connect(sceneNode, &OSGNode::nodeChanged, this, &OSGSkyNode::Hidden::onSceneNodeChanged);
} }
return true; return true;
} }
void updateSkyNode() void updateScene()
{ {
if (!sceneNode || !sceneNode->node()) { if (!sceneNode || !sceneNode->node()) {
qWarning() << "OSGSkyNode::acceptNode - scene node not valid"; qWarning() << "OSGSkyNode::updateScene - scene node not valid";
self->setNode(NULL); self->setNode(NULL);
return; return;
} }
qDebug() << "OSGSkyNode::updateScene - scene node" << sceneNode->node();
osgEarth::MapNode *mapNode = osgEarth::MapNode::findMapNode(sceneNode->node()); osgEarth::MapNode *mapNode = osgEarth::MapNode::findMapNode(sceneNode->node());
if (!mapNode) { 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); self->setNode(NULL);
return; return;
} }
if (!mapNode->getMap()->isGeocentric()) { if (!mapNode->getMap()->isGeocentric()) {
qWarning() << "OSGSkyNode::acceptNode - map node is not geocentric"; qWarning() << "OSGSkyNode::updateScene - map node is not geocentric";
self->setNode(NULL); self->setNode(NULL);
return; return;
} }
@ -117,7 +124,7 @@ public:
} else { } else {
skyNode->removeChild(0, 1); skyNode->removeChild(0, 1);
skyNode->addChild(sceneNode->node()); 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() void updateSunLightEnabled()
{ {
if (!skyNode.valid()) {
qWarning() << "OSGSkyNode::updateSunLightEnabled - invalid sky node";
return;
}
if (!skyNode.valid()) { if (!skyNode.valid()) {
return; return;
} }
@ -153,10 +175,11 @@ public:
void updateDateTime() void updateDateTime()
{ {
if (!skyNode.valid()) { if (!skyNode.valid()) {
qWarning() << "OSGSkyNode::updateDateTime - invalid sky node";
return; return;
} }
if (!dateTime.isValid()) { if (!dateTime.isValid()) {
qWarning() << "OSGSkyNode::acceptDateTime - invalid date/time" << dateTime; qWarning() << "OSGSkyNode::updateDateTime - invalid date/time" << dateTime;
} }
QDate date = dateTime.date(); QDate date = dateTime.date();
@ -168,6 +191,7 @@ public:
void updateMinimumAmbientLight() void updateMinimumAmbientLight()
{ {
if (!skyNode.valid()) { if (!skyNode.valid()) {
qWarning() << "OSGSkyNode::updateMinimumAmbientLight - invalid sky node";
return; return;
} }
double d = minimumAmbientLight; double d = minimumAmbientLight;
@ -193,28 +217,23 @@ private slots:
void onSceneNodeChanged(osg::Node *node) void onSceneNodeChanged(osg::Node *node)
{ {
qDebug() << "OSGSkyNode::onSceneNodeChanged" << node; qDebug() << "OSGSkyNode::onSceneNodeChanged" << node;
updateSkyNode(); updateScene();
} }
}; };
/* class OSGSkyNode */ /* class OSGSkyNode */
enum DirtyFlag { Child = 1 << 0, DateTime = 1 << 1, Light = 1 << 2 }; OSGSkyNode::OSGSkyNode(QObject *parent) : Inherited(parent), h(new Hidden(this))
OSGSkyNode::OSGSkyNode(QObject *parent) : OSGNode(parent), h(new Hidden(this))
{ {
qDebug() << "OSGSkyNode::OSGSkyNode"; setDirty(DateTime | Light);
setSunLightEnabled(true);
setMinimumAmbientLight(0.03);
} }
OSGSkyNode::~OSGSkyNode() OSGSkyNode::~OSGSkyNode()
{ {
// qDebug() << "OSGSkyNode::~OSGSkyNode";
delete h; delete h;
} }
OSGNode *OSGSkyNode::sceneNode() OSGNode *OSGSkyNode::sceneNode() const
{ {
return h->sceneNode; return h->sceneNode;
} }
@ -222,12 +241,26 @@ OSGNode *OSGSkyNode::sceneNode()
void OSGSkyNode::setSceneNode(OSGNode *node) void OSGSkyNode::setSceneNode(OSGNode *node)
{ {
if (h->acceptSceneNode(node)) { if (h->acceptSceneNode(node)) {
setDirty(Child); setDirty(Scene);
emit sceneNodeChanged(node); 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; return h->sunLightEnabled;
} }
@ -241,7 +274,7 @@ void OSGSkyNode::setSunLightEnabled(bool enabled)
} }
} }
QDateTime OSGSkyNode::dateTime() QDateTime OSGSkyNode::dateTime() const
{ {
return h->dateTime; return h->dateTime;
} }
@ -255,7 +288,7 @@ void OSGSkyNode::setDateTime(QDateTime dateTime)
} }
} }
double OSGSkyNode::minimumAmbientLight() double OSGSkyNode::minimumAmbientLight() const
{ {
return h->minimumAmbientLight; return h->minimumAmbientLight;
} }
@ -269,10 +302,20 @@ void OSGSkyNode::setMinimumAmbientLight(double ambient)
} }
} }
void OSGSkyNode::update() osg::Node *OSGSkyNode::createNode()
{ {
if (isDirty(Child)) { return NULL;
h->updateSkyNode(); }
void OSGSkyNode::updateNode()
{
Inherited::updateNode();
if (isDirty(Scene)) {
h->updateScene();
}
if (isDirty(Viewport)) {
h->updateViewport();
} }
if (isDirty(Light)) { if (isDirty(Light)) {
h->updateSunLightEnabled(); h->updateSunLightEnabled();
@ -282,23 +325,6 @@ void OSGSkyNode::update()
h->updateDateTime(); 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 } // namespace osgQtQuick
#include "OSGSkyNode.moc" #include "OSGSkyNode.moc"

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGSkyNode.hpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -43,45 +43,52 @@ class QUrl;
QT_END_NAMESPACE QT_END_NAMESPACE
namespace osgQtQuick { namespace osgQtQuick {
class OSGQTQUICK_EXPORT OSGSkyNode : public OSGNode { class OSGViewport;
// TODO rename to sceneNode
Q_OBJECT Q_PROPERTY(osgQtQuick::OSGNode *sceneData READ sceneNode WRITE setSceneNode NOTIFY sceneNodeChanged)
// 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(bool sunLightEnabled READ sunLightEnabled WRITE setSunLightEnabled NOTIFY sunLightEnabledChanged)
Q_PROPERTY(QDateTime dateTime READ dateTime WRITE setDateTime NOTIFY dateTimeChanged) Q_PROPERTY(QDateTime dateTime READ dateTime WRITE setDateTime NOTIFY dateTimeChanged)
Q_PROPERTY(double minimumAmbientLight READ minimumAmbientLight WRITE setMinimumAmbientLight NOTIFY minimumAmbientLightChanged) Q_PROPERTY(double minimumAmbientLight READ minimumAmbientLight WRITE setMinimumAmbientLight NOTIFY minimumAmbientLightChanged)
typedef OSGNode Inherited;
public: public:
OSGSkyNode(QObject *parent = 0); OSGSkyNode(QObject *parent = 0);
virtual ~OSGSkyNode(); virtual ~OSGSkyNode();
OSGNode *sceneNode(); OSGNode *sceneNode() const;
void setSceneNode(OSGNode *node); void setSceneNode(OSGNode *node);
bool sunLightEnabled(); OSGViewport *viewport() const;
void setViewport(OSGViewport *viewport);
bool sunLightEnabled() const;
void setSunLightEnabled(bool arg); void setSunLightEnabled(bool arg);
QDateTime dateTime(); QDateTime dateTime() const;
void setDateTime(QDateTime arg); void setDateTime(QDateTime arg);
double minimumAmbientLight(); double minimumAmbientLight() const;
void setMinimumAmbientLight(double arg); void setMinimumAmbientLight(double arg);
signals: signals:
void sceneNodeChanged(OSGNode *node); void sceneNodeChanged(OSGNode *node);
void viewportChanged(OSGViewport *viewport);
void sunLightEnabledChanged(bool arg); void sunLightEnabledChanged(bool arg);
void dateTimeChanged(QDateTime arg); void dateTimeChanged(QDateTime arg);
void minimumAmbientLightChanged(double arg); void minimumAmbientLightChanged(double arg);
protected:
virtual osg::Node *createNode();
virtual void updateNode();
private: private:
struct Hidden; struct Hidden;
Hidden *h; Hidden *const h;
virtual void update();
virtual void attach(osgViewer::View *view);
virtual void detach(osgViewer::View *view);
}; };
} // namespace osgQtQuick } // namespace osgQtQuick

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGTextNode.cpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -27,7 +27,7 @@
#include "OSGTextNode.hpp" #include "OSGTextNode.hpp"
#include "../utility.h" #include "utils/utility.h"
#include <osgText/Text> #include <osgText/Text>
#include <osg/Geode> #include <osg/Geode>
@ -37,6 +37,8 @@
#include <QColor> #include <QColor>
namespace osgQtQuick { namespace osgQtQuick {
enum DirtyFlag { Text = 1 << 0, Color = 1 << 1 };
struct OSGTextNode::Hidden : public QObject { struct OSGTextNode::Hidden : public QObject {
Q_OBJECT Q_OBJECT
@ -49,24 +51,24 @@ public:
QString textString; QString textString;
QColor color; QColor color;
Hidden(OSGTextNode *node) : QObject(node), self(node) Hidden(OSGTextNode *self) : QObject(self), self(self)
{}
osg::Node *createNode()
{ {
osg::ref_ptr<osgText::Font> textFont = createFont(QFont("Times")); osg::ref_ptr<osgText::Font> textFont = createFont(QFont("Times"));
text = createText(osg::Vec3(-100, 20, 0), "Hello World", 20.0f, text = createText(osg::Vec3(-100, 20, 0), "Hello World", 20.0f, textFont.get());
textFont.get()); osg::ref_ptr<osg::Geode> textGeode = new osg::Geode();
osg::ref_ptr<osg::Geode> textGeode = new osg::Geode();
textGeode->addDrawable(text.get()); textGeode->addDrawable(text.get());
#if 0 #if 0
text->setAutoRotateToScreen(true); text->setAutoRotateToScreen(true);
self->setNode(textGeode.get());
#else #else
osg::Camera *camera = createHUDCamera(-100, 100, -100, 100); osg::Camera *camera = createHUDCamera(-100, 100, -100, 100);
camera->addChild(textGeode.get()); camera->addChild(textGeode.get());
camera->getOrCreateStateSet()->setMode( camera->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
GL_LIGHTING, osg::StateAttribute::OFF);
self->setNode(camera);
#endif #endif
return text;
} }
void updateText() void updateText()
@ -88,10 +90,10 @@ public:
/* class OSGTextNode */ /* class OSGTextNode */
enum DirtyFlag { Text = 1 << 0, Color = 1 << 1 }; OSGTextNode::OSGTextNode(QObject *parent) : Inherited(parent), h(new Hidden(this))
{
OSGTextNode::OSGTextNode(QObject *node) : OSGNode(node), h(new Hidden(this)) setDirty(Text | Color);
{} }
OSGTextNode::~OSGTextNode() 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)) { if (isDirty(Text)) {
h->updateText(); h->updateText();
} }
@ -135,15 +144,6 @@ void OSGTextNode::update()
h->updateColor(); h->updateColor();
} }
} }
void OSGTextNode::attach(osgViewer::View *view)
{
update();
clearDirty();
}
void OSGTextNode::detach(osgViewer::View *view)
{}
} // namespace osgQtQuick } // namespace osgQtQuick
#include "OSGTextNode.moc" #include "OSGTextNode.moc"

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGTextNode.hpp * @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
* @{ * @{
* @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_OBJECT Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
typedef OSGNode Inherited;
public: public:
explicit OSGTextNode(QObject *parent = 0); explicit OSGTextNode(QObject *parent = 0);
virtual ~OSGTextNode(); virtual ~OSGTextNode();
@ -52,14 +54,13 @@ signals:
void textChanged(const QString &text); void textChanged(const QString &text);
void colorChanged(const QColor &color); void colorChanged(const QColor &color);
protected:
virtual osg::Node *createNode();
virtual void updateNode();
private: private:
struct Hidden; struct Hidden;
Hidden *h; Hidden *const h;
virtual void update();
virtual void attach(osgViewer::View *view);
virtual void detach(osgViewer::View *view);
}; };
} // namespace osgQtQuick } // namespace osgQtQuick

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGTransformNode.cpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -34,6 +34,10 @@
#include <QDebug> #include <QDebug>
namespace osgQtQuick { 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 { struct OSGTransformNode::Hidden : public QObject {
Q_OBJECT Q_OBJECT
@ -43,63 +47,22 @@ private:
osg::ref_ptr<osg::PositionAttitudeTransform> transform; osg::ref_ptr<osg::PositionAttitudeTransform> transform;
public: public:
OSGNode *childNode;
QVector3D scale; QVector3D scale;
QVector3D attitude; QVector3D attitude;
QVector3D position; 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(); transform = new osg::PositionAttitudeTransform();
self->setNode(transform); return 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();
// }
} }
void updateScale() void updateScale()
{ {
// qDebug() << "OSGTransformNode::updateScale" << scale;
if ((scale.x() != 0.0) || (scale.y() != 0.0) || (scale.z() != 0.0)) { if ((scale.x() != 0.0) || (scale.y() != 0.0) || (scale.z() != 0.0)) {
transform->setScale(osg::Vec3d(scale.x(), scale.y(), scale.z())); transform->setScale(osg::Vec3d(scale.x(), scale.y(), scale.z()));
// transform->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); // transform->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
@ -118,52 +81,24 @@ public:
yaw, osg::Vec3d(0, 0, -1)); yaw, osg::Vec3d(0, 0, -1));
transform->setAttitude(q); transform->setAttitude(q);
// position
transform->setPosition(osg::Vec3d(position.x(), position.y(), position.z()));
} }
void updatePosition() void updatePosition()
{ {
transform->setPosition(osg::Vec3d(position.x(), position.y(), position.z())); transform->setPosition(osg::Vec3d(position.x(), position.y(), position.z()));
} }
private slots:
void onChildNodeChanged(osg::Node *node)
{
qDebug() << "OSGTransformNode::onChildNodeChanged" << node;
updateTransformNode();
}
}; };
/* class OSGTransformNode */ /* class OSGTransformNode */
enum DirtyFlag { Child = 1 << 0, Scale = 1 << 1, Position = 1 << 2, Attitude = 1 << 3 }; OSGTransformNode::OSGTransformNode(QObject *parent) : Inherited(parent), h(new Hidden(this))
{}
OSGTransformNode::OSGTransformNode(QObject *parent) : OSGNode(parent), h(new Hidden(this))
{
qDebug() << "OSGTransformNode::OSGTransformNode";
}
OSGTransformNode::~OSGTransformNode() OSGTransformNode::~OSGTransformNode()
{ {
// qDebug() << "OSGTransformNode::~OSGTransformNode";
delete h; 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 QVector3D OSGTransformNode::scale() const
{ {
return h->scale; return h->scale;
@ -206,11 +141,15 @@ void OSGTransformNode::setPosition(QVector3D arg)
} }
} }
void OSGTransformNode::update() osg::Node *OSGTransformNode::createNode()
{ {
if (isDirty(Child)) { return h->createNode();
h->updateTransformNode(); }
}
void OSGTransformNode::updateNode()
{
Inherited::updateNode();
if (isDirty(Scale)) { if (isDirty(Scale)) {
h->updateScale(); h->updateScale();
} }
@ -221,19 +160,6 @@ void OSGTransformNode::update()
h->updatePosition(); 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 } // namespace osgQtQuick
#include "OSGTransformNode.moc" #include "OSGTransformNode.moc"

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGTransformNode.hpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -29,28 +29,22 @@
#define _H_OSGQTQUICK_TRANSFORMNODE_H_ #define _H_OSGQTQUICK_TRANSFORMNODE_H_
#include "Export.hpp" #include "Export.hpp"
#include "OSGNode.hpp" #include "OSGGroup.hpp"
#include <QVector3D> #include <QVector3D>
// TODO derive from OSGGroup...
namespace osgQtQuick { namespace osgQtQuick {
class OSGQTQUICK_EXPORT OSGTransformNode : public OSGNode { class OSGQTQUICK_EXPORT OSGTransformNode : public OSGGroup {
Q_OBJECT Q_OBJECT Q_PROPERTY(QVector3D scale READ scale WRITE setScale NOTIFY scaleChanged)
// 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)
Q_PROPERTY(QVector3D attitude READ attitude WRITE setAttitude NOTIFY attitudeChanged) Q_PROPERTY(QVector3D attitude READ attitude WRITE setAttitude NOTIFY attitudeChanged)
Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged) Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged)
typedef OSGGroup Inherited;
public: public:
OSGTransformNode(QObject *parent = 0); OSGTransformNode(QObject *parent = 0);
virtual ~OSGTransformNode(); virtual ~OSGTransformNode();
OSGNode *childNode();
void setChildNode(OSGNode *node);
QVector3D scale() const; QVector3D scale() const;
void setScale(QVector3D arg); void setScale(QVector3D arg);
@ -61,20 +55,17 @@ public:
void setPosition(QVector3D arg); void setPosition(QVector3D arg);
signals: signals:
void childNodeChanged(OSGNode *node);
void scaleChanged(QVector3D arg); void scaleChanged(QVector3D arg);
void attitudeChanged(QVector3D arg); void attitudeChanged(QVector3D arg);
void positionChanged(QVector3D arg); void positionChanged(QVector3D arg);
protected:
virtual osg::Node *createNode();
virtual void updateNode();
private: private:
struct Hidden; struct Hidden;
Hidden *h; Hidden *const h;
virtual void update();
virtual void attach(osgViewer::View *view);
virtual void detach(osgViewer::View *view);
}; };
} // namespace osgQtQuick } // namespace osgQtQuick

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGViewport.cpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -27,13 +27,14 @@
#include "OSGViewport.hpp" #include "OSGViewport.hpp"
#include "../osgearth.h" #include "osgearth.h"
#include "../utility.h" #include "utils/utility.h"
#include "OSGNode.hpp" #include "OSGNode.hpp"
#include "OSGCamera.hpp" #include "OSGCamera.hpp"
#include <osg/Node> #include <osg/Node>
#include <osg/Vec4>
#include <osg/DeleteHandler> #include <osg/DeleteHandler>
#include <osg/GLObjects> #include <osg/GLObjects>
#include <osg/ApplicationUsage> #include <osg/ApplicationUsage>
@ -41,10 +42,7 @@
#include <osgViewer/CompositeViewer> #include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers> #include <osgViewer/ViewerEventHandlers>
#include <osgGA/StateSetManipulator> #include <osgGA/StateSetManipulator>
#include <osgGA/CameraManipulator>
#ifdef USE_OSGEARTH
#include <osgEarth/MapNode>
#endif
#include <QOpenGLContext> #include <QOpenGLContext>
#include <QQuickWindow> #include <QQuickWindow>
@ -55,10 +53,6 @@
#include <QDebug> #include <QDebug>
#include <QThread>
#include <QApplication>
namespace osgQtQuick {
/* /*
Debugging tips Debugging tips
- export OSG_NOTIFY_LEVEL=DEBUG - export OSG_NOTIFY_LEVEL=DEBUG
@ -79,18 +73,66 @@ namespace osgQtQuick {
TODO : add OSGView to handle multiple views for a given OSGViewport 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 { struct OSGViewport::Hidden : public QObject {
Q_OBJECT Q_OBJECT
public: friend ViewportRenderer;
Hidden(OSGViewport *viewport) : QObject(viewport), private:
self(viewport), OSGViewport *const self;
window(NULL),
sceneData(NULL), QQuickWindow *window;
camera(NULL),
updateMode(UpdateMode::Discrete), int frameTimer;
frameTimer(-1)
osg::ref_ptr<osg::GraphicsContext> gc;
public:
OSGNode *sceneNode;
OSGCamera *cameraNode;
osg::ref_ptr<osgViewer::CompositeViewer> viewer;
osg::ref_ptr<osgViewer::View> 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(); OsgEarth::initialize();
@ -101,7 +143,9 @@ public:
~Hidden() ~Hidden()
{ {
stop(); disconnect(self);
stopTimer();
destroyViewer(); destroyViewer();
} }
@ -109,195 +153,140 @@ public:
public slots: public slots:
void onWindowChanged(QQuickWindow *window) void onWindowChanged(QQuickWindow *window)
{ {
qDebug() << "OSGViewport::onWindowChanged" << window; // qDebug() << "OSGViewport::onWindowChanged" << window;
// osgQtQuick::openGLContextInfo(QOpenGLContext::currentContext(), "onWindowChanged"); // osgQtQuick::openGLContextInfo(QOpenGLContext::currentContext(), "onWindowChanged");
if (window) { if (window) {
// window->setClearBeforeRendering(false); // window->setClearBeforeRendering(false);
connect(window, &QQuickWindow::sceneGraphInitialized, this, &Hidden::onSceneGraphInitialized, Qt::DirectConnection); // connect(window, &QQuickWindow::sceneGraphInitialized, this, &Hidden::onSceneGraphInitialized, Qt::DirectConnection);
connect(window, &QQuickWindow::sceneGraphAboutToStop, this, &Hidden::onSceneGraphAboutToStop, Qt::DirectConnection); // connect(window, &QQuickWindow::sceneGraphAboutToStop, this, &Hidden::onSceneGraphAboutToStop, Qt::DirectConnection);
connect(window, &QQuickWindow::sceneGraphInvalidated, this, &Hidden::onSceneGraphInvalidated, 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 { } else {
if (this->window) { // if (this->window) {
disconnect(this->window); // disconnect(this->window);
} // }
} }
this->window = window; this->window = window;
} }
public: public:
bool acceptSceneNode(OSGNode *node)
bool acceptSceneData(OSGNode *node)
{ {
qDebug() << "OSGViewport::acceptSceneData" << node; qDebug() << "OSGViewport::acceptSceneNode" << node;
if (sceneData == node) { if (sceneNode == node) {
return true; return true;
} }
if (sceneData) { if (sceneNode) {
disconnect(sceneData); disconnect(sceneNode);
} }
sceneData = node; sceneNode = node;
if (sceneData) { if (sceneNode) {
acceptNode(sceneData->node()); connect(sceneNode, &OSGNode::nodeChanged, this, &Hidden::onSceneNodeChanged);
connect(sceneData, &OSGNode::nodeChanged, this, &Hidden::onNodeChanged);
} }
return true; 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; return true;
} }
void attach(osgViewer::View *view) bool acceptManipulator(OSGCameraManipulator *m)
{ {
if (!sceneData) { qDebug() << "OSGViewport::acceptManipulator" << manipulator;
qWarning() << "OSGViewport::attach - invalid scene!"; if (manipulator == m) {
return; return true;
}
// 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;
} }
#ifdef USE_OSGEARTH manipulator = m;
// TODO map handling should not be done here
osgEarth::MapNode *mapNode = osgEarth::MapNode::findMapNode(node);
if (mapNode) {
qDebug() << "OSGViewport::attach - found map node" << mapNode;
// remove light to prevent unnecessary state changes in SceneView return true;
// 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");
} }
void initializeResources() void initializeResources()
{ {
qDebug() << "OSGViewport::initializeResources"; if (gc.valid()) {
if (view.valid()) { // qWarning() << "OSGViewport::initializeResources - gc already created!";
qWarning() << "OSGViewport::initializeResources - view already created!";
return; return;
} }
view = createView(); // qDebug() << "OSGViewport::initializeResources";
viewer->addView(view);
self->attach(view.get()); // setup graphics context and camera
start(); 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() void releaseResources()
{ {
qDebug() << "OSGViewport::releaseResources"; // qDebug() << "OSGViewport::releaseResources";
if (!view.valid()) { if (!gc.valid()) {
qWarning() << "OSGViewport::releaseResources - view is not valid!"; qWarning() << "OSGViewport::releaseResources - gc is not valid!";
return; return;
} }
osg::deleteAllGLObjects(view->getCamera()->getGraphicsContext()->getState()->getContextID()); osg::deleteAllGLObjects(gc->getState()->getContextID());
// view->getSceneData()->releaseGLObjects(view->getCamera()->getGraphicsContext()->getState()); // view->getSceneData()->releaseGLObjects(view->getCamera()->getGraphicsContext()->getState());
// view->getCamera()->releaseGLObjects(view->getCamera()->getGraphicsContext()->getState()); // view->getCamera()->releaseGLObjects(view->getCamera()->getGraphicsContext()->getState());
// view->getCamera()->getGraphicsContext()->close(); // view->getCamera()->getGraphicsContext()->close();
// view->getCamera()->setGraphicsContext(NULL); // view->getCamera()->setGraphicsContext(NULL);
} }
bool acceptUpdateMode(UpdateMode::Enum mode) private:
{
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<osgViewer::CompositeViewer> viewer;
osg::ref_ptr<osgViewer::View> view;
static QtKeyboardMap keyMap;
void createViewer() void createViewer()
{ {
if (viewer.valid()) { if (viewer.valid()) {
qWarning() << "OSGViewport::createViewer - viewer is valid"; qWarning() << "OSGViewport::createViewer - viewer is valid";
return; return;
} }
// qDebug() << "OSGViewport::createViewer";
qDebug() << "OSGViewport::createViewer";
viewer = new osgViewer::CompositeViewer(); viewer = new osgViewer::CompositeViewer();
viewer->setThreadingModel(osgViewer::ViewerBase::SingleThreaded); viewer->setThreadingModel(osgViewer::ViewerBase::SingleThreaded);
@ -306,6 +295,9 @@ public:
// disable the default setting of viewer.done() by pressing Escape. // disable the default setting of viewer.done() by pressing Escape.
viewer->setKeyEventSetsDone(0); viewer->setKeyEventSetsDone(0);
// viewer->setQuitEventSetsDone(false); // viewer->setQuitEventSetsDone(false);
view = createView();
viewer->addView(view);
} }
void destroyViewer() void destroyViewer()
@ -314,17 +306,25 @@ public:
qWarning() << "OSGViewport::destroyViewer - viewer is not valid"; qWarning() << "OSGViewport::destroyViewer - viewer is not valid";
return; return;
} }
// qDebug() << "OSGViewport::destroyViewer";
qDebug() << "OSGViewport::destroyViewer";
viewer = NULL; viewer = NULL;
} }
osgViewer::View *createView() osgViewer::View *createView()
{ {
qDebug() << "OSGViewport::createView"; // qDebug() << "OSGViewport::createView";
osgViewer::View *view = new osgViewer::View(); 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??? // TODO will the handlers be destroyed???
// add the state manipulator // add the state manipulator
view->addEventHandler(new osgGA::StateSetManipulator(view->getCamera()->getOrCreateStateSet())); view->addEventHandler(new osgGA::StateSetManipulator(view->getCamera()->getOrCreateStateSet()));
@ -350,26 +350,14 @@ public:
// add the screen capture handler // add the screen capture handler
// view->addEventHandler(new osgViewer::ScreenCaptureHandler); // 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() osg::GraphicsContext *createGraphicsContext()
{ {
qDebug() << "OSGViewport::createGraphicsContext"; // qDebug() << "OSGViewport::createGraphicsContext";
osg::GraphicsContext::Traits *traits = getTraits(); osg::GraphicsContext::Traits *traits = getTraits();
// traitsInfo(*traits); // traitsInfo(*traits);
traits->pbuffer = true; traits->pbuffer = true;
@ -416,19 +404,19 @@ public:
return traits; return traits;
} }
void start() void startTimer()
{ {
if (updateMode == UpdateMode::Discrete && (frameTimer < 0)) { if ((updateMode != UpdateMode::Continuous) && (frameTimer < 0)) {
qDebug() << "OSGViewport::start - starting timer"; // qDebug() << "OSGViewport::startTimer - starting timer";
frameTimer = startTimer(33, Qt::PreciseTimer); frameTimer = QObject::startTimer(33, Qt::PreciseTimer);
} }
} }
void stop() void stopTimer()
{ {
if (frameTimer >= 0) { if (frameTimer >= 0) {
qDebug() << "OSGViewport::stop - killing timer"; // qDebug() << "OSGViewport::stopTimer - killing timer";
killTimer(frameTimer); QObject::killTimer(frameTimer);
frameTimer = -1; frameTimer = -1;
} }
} }
@ -448,34 +436,38 @@ protected:
private slots: private slots:
void onNodeChanged(osg::Node *node) void onSceneNodeChanged(osg::Node *node)
{ {
qDebug() << "OSGViewport::onNodeChanged" << node; qWarning() << "OSGViewport::onSceneNodeChanged - not implemented";
qWarning() << "OSGViewport::onNodeChanged - not implemented"; }
// if (view.valid()) {
// acceptNode(node); void onCameraNodeChanged(osg::Node *node)
// } {
qWarning() << "OSGViewport::onCameraNodeChanged - not implemented";
} }
}; };
/* class ViewportRenderer */ /* class ViewportRenderer */
class ViewportRenderer : public QQuickFramebufferObject::Renderer { class ViewportRenderer : public QQuickFramebufferObject::Renderer {
private:
OSGViewport::Hidden *const h;
int frameCount;
bool needToDoFrame;
public: 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"); // osgQtQuick::openGLContextInfo(QOpenGLContext::currentContext(), "ViewportRenderer::ViewportRenderer");
h->initializeResources(); h->initializeResources();
firstFrame = true;
needToDoFrame = false;
} }
~ViewportRenderer() ~ViewportRenderer()
{ {
qDebug() << "ViewportRenderer::~ViewportRenderer"; // qDebug() << "ViewportRenderer::~ViewportRenderer";
// osgQtQuick::openGLContextInfo(QOpenGLContext::currentContext(), "ViewportRenderer::~ViewportRenderer"); // osgQtQuick::openGLContextInfo(QOpenGLContext::currentContext(), "ViewportRenderer::~ViewportRenderer");
} }
@ -495,29 +487,71 @@ public:
return; 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(); h->view->init();
if (!h->viewer->isRealized()) { if (!h->viewer->isRealized()) {
h->viewer->realize(); h->viewer->realize();
} }
firstFrame = false;
} }
needToDoFrame = false; // we always want to draw the first frame
osg::Viewport *viewport = h->view->getCamera()->getViewport(); needToDoFrame = (frameCount == 0);
if ((viewport->width() != item->width()) || (viewport->height() != item->height())) {
// if not on-demand then do frame
if (h->updateMode != UpdateMode::OnDemand) {
needToDoFrame = true; 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) { if (!needToDoFrame) {
needToDoFrame = h->viewer->checkNeedToDoFrame(); needToDoFrame = h->viewer->checkNeedToDoFrame();
} }
// workarounds to osg issues
if (!needToDoFrame) { 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(); needToDoFrame = !h->view->getEventQueue()->empty();
} }
if (needToDoFrame) { if (needToDoFrame) {
// qDebug() << "ViewportRenderer::synchronize - update scene" << frameCount;
h->viewer->advance(); h->viewer->advance();
h->viewer->eventTraversal(); h->viewer->eventTraversal();
h->viewer->updateTraversal(); h->viewer->updateTraversal();
@ -537,6 +571,8 @@ public:
} }
if (needToDoFrame) { if (needToDoFrame) {
// qDebug() << "ViewportRenderer::render - render scene" << frameCount;
// needed to properly render models without terrain (Qt bug?) // needed to properly render models without terrain (Qt bug?)
QOpenGLContext::currentContext()->functions()->glUseProgram(0); QOpenGLContext::currentContext()->functions()->glUseProgram(0);
h->viewer->renderingTraversals(); h->viewer->renderingTraversals();
@ -547,6 +583,8 @@ public:
// trigger next update // trigger next update
update(); update();
} }
++frameCount;
} }
QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) QOpenGLFramebufferObject *createFramebufferObject(const QSize &size)
@ -556,30 +594,18 @@ public:
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
// format.setSamples(4); // format.setSamples(4);
// Keeping this for reference : QOpenGLFramebufferObject *fbo = new QOpenGLFramebufferObject(size.width(), size.height(), format);
// 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);
return fbo; return fbo;
} }
private:
OSGViewport::Hidden *h;
bool firstFrame;
bool needToDoFrame;
}; };
QtKeyboardMap OSGViewport::Hidden::keyMap = QtKeyboardMap(); QtKeyboardMap OSGViewport::Hidden::keyMap = QtKeyboardMap();
/* class OSGViewport */ /* 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); // setClearBeforeRendering(false);
setMirrorVertically(true); setMirrorVertically(true);
setAcceptHoverEvents(true); setAcceptHoverEvents(true);
@ -588,10 +614,48 @@ OSGViewport::OSGViewport(QQuickItem *parent) : QQuickFramebufferObject(parent),
OSGViewport::~OSGViewport() OSGViewport::~OSGViewport()
{ {
qDebug() << "OSGViewport::~OSGViewport";
delete h; 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 UpdateMode::Enum OSGViewport::updateMode() const
{ {
return h->updateMode; return h->updateMode;
@ -599,95 +663,54 @@ UpdateMode::Enum OSGViewport::updateMode() const
void OSGViewport::setUpdateMode(UpdateMode::Enum mode) void OSGViewport::setUpdateMode(UpdateMode::Enum mode)
{ {
if (h->acceptUpdateMode(mode)) { if (h->updateMode != mode) {
emit updateModeChanged(updateMode()); h->updateMode = mode;
emit updateModeChanged(mode);
} }
} }
QColor OSGViewport::color() const bool OSGViewport::busy() const
{ {
const osg::Vec4 osgColor = h->view->getCamera()->getClearColor(); return h->busy;
return QColor::fromRgbF(osgColor.r(), osgColor.g(), osgColor.b(), osgColor.a());
} }
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->busy != busy) {
h->busy = busy;
if (h->view->getCamera()->getClearColor() != osgColor) { emit busyChanged(busy);
h->view->getCamera()->setClearColor(osgColor);
emit colorChanged(color);
} }
} }
OSGNode *OSGViewport::sceneData() osgViewer::View *OSGViewport::asView() const
{ {
return h->sceneData; return h->view;
}
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);
}
} }
QQuickFramebufferObject::Renderer *OSGViewport::createRenderer() const QQuickFramebufferObject::Renderer *OSGViewport::createRenderer() const
{ {
qDebug() << "OSGViewport::createRenderer"; // qDebug() << "OSGViewport::createRenderer";
// osgQtQuick::openGLContextInfo(QOpenGLContext::currentContext(), "createRenderer"); // osgQtQuick::openGLContextInfo(QOpenGLContext::currentContext(), "createRenderer");
return new ViewportRenderer(h); 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() void OSGViewport::releaseResources()
{ {
QQuickFramebufferObject::releaseResources(); // qDebug() << "OSGViewport::releaseResources" << this;
Inherited::releaseResources();
} }
// see https://bugreports.qt-project.org/browse/QTBUG-41073 void OSGViewport::classBegin()
QSGNode *OSGViewport::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *nodeData)
{ {
// qDebug() << "OSGViewport::updatePaintNode"; // qDebug() << "OSGViewport::classBegin" << this;
if (!node) { Inherited::classBegin();
qDebug() << "OSGViewport::updatePaintNode - set transform";
node = QQuickFramebufferObject::updatePaintNode(node, nodeData);
QSGSimpleTextureNode *n = static_cast<QSGSimpleTextureNode *>(node);
return node;
}
return QQuickFramebufferObject::updatePaintNode(node, nodeData);
} }
void OSGViewport::componentComplete()
{
// qDebug() << "OSGViewport::componentComplete" << this;
Inherited::componentComplete();
}
QPointF OSGViewport::mousePoint(QMouseEvent *event) 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 // among others, it closes popup windows on ESC and forwards the event to the parent widgets
// TODO implement // TODO implement
// if( _forwardKeyEvents ) // if( _forwardKeyEvents )
// inherited::keyPressEvent( event ); // Inherited::keyPressEvent(event);
} }
void OSGViewport::keyReleaseEvent(QKeyEvent *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 // among others, it closes popup windows on ESC and forwards the event to the parent widgets
// TODO implement // TODO implement
// if( _forwardKeyEvents ) // if( _forwardKeyEvents )
// inherited::keyReleaseEvent( event ); // Inherited::keyReleaseEvent(event);
} }
} // namespace osgQtQuick } // namespace osgQtQuick

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file OSGViewport.hpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -30,6 +30,8 @@
#include "Export.hpp" #include "Export.hpp"
#include "ga/OSGCameraManipulator.hpp"
#include <QQuickFramebufferObject> #include <QQuickFramebufferObject>
namespace osgViewer { namespace osgViewer {
@ -49,39 +51,49 @@ public:
}; };
class OSGQTQUICK_EXPORT OSGViewport : public QQuickFramebufferObject { 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::UpdateMode::Enum updateMode READ updateMode WRITE setUpdateMode NOTIFY updateModeChanged)
Q_PROPERTY(osgQtQuick::OSGNode * sceneData READ sceneData WRITE setSceneData NOTIFY sceneDataChanged) Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
Q_PROPERTY(osgQtQuick::OSGCamera * camera READ camera WRITE setCamera NOTIFY cameraChanged)
typedef QQuickFramebufferObject Inherited;
public:
friend class ViewportRenderer; friend class ViewportRenderer;
public:
explicit OSGViewport(QQuickItem *parent = 0); explicit OSGViewport(QQuickItem *parent = 0);
virtual ~OSGViewport(); 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; UpdateMode::Enum updateMode() const;
void setUpdateMode(UpdateMode::Enum mode); void setUpdateMode(UpdateMode::Enum mode);
QColor color() const; bool busy() const;
void setColor(const QColor &color); void setBusy(const bool busy);
OSGNode *sceneData();
void setSceneData(OSGNode *node);
OSGCamera *camera();
void setCamera(OSGCamera *camera);
Renderer *createRenderer() const; Renderer *createRenderer() const;
void releaseResources(); void releaseResources();
osgViewer::View *asView() const;
signals: signals:
void sceneNodeChanged(OSGNode *node);
void cameraNodeChanged(OSGCamera *node);
void manipulatorChanged(OSGCameraManipulator *manipulator);
void updateModeChanged(UpdateMode::Enum mode); void updateModeChanged(UpdateMode::Enum mode);
void colorChanged(const QColor &color); void busyChanged(bool busy);
void sceneDataChanged(OSGNode *node);
void cameraChanged(OSGCamera *camera);
protected: protected:
// QQuickItem
void mousePressEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event);
@ -92,14 +104,13 @@ protected:
void setKeyboardModifiers(QInputEvent *event); void setKeyboardModifiers(QInputEvent *event);
QPointF mousePoint(QMouseEvent *event); QPointF mousePoint(QMouseEvent *event);
QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData); // QQmlParserStatus
void classBegin();
void attach(osgViewer::View *view); void componentComplete();
void detach(osgViewer::View *view);
private: private:
struct Hidden; struct Hidden;
Hidden *h; Hidden *const h;
}; };
} // namespace osgQtQuick } // namespace osgQtQuick

View File

@ -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 <osgGA/CameraManipulator>
#include <QDebug>
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<osgGA::CameraManipulator> 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"

View File

@ -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 <QObject>
#include <QQmlParserStatus>
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_

View File

@ -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 <osgEarthUtil/EarthManipulator>
#include <QDebug>
namespace osgQtQuick {
struct OSGEarthManipulator::Hidden : public QObject {
Q_OBJECT
private:
OSGEarthManipulator * const self;
public:
osg::ref_ptr<osgEarth::Util::EarthManipulator> 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"

View File

@ -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 <QObject>
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_

View File

@ -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 <osg/Matrix>
#include <osg/Node>
#include <osg/Vec3d>
#include <osgGA/CameraManipulator>
#include <osgEarth/GeoData>
#include <osgEarth/MapNode>
#include <QDebug>
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<osg::Node> node;
};
struct OSGGeoTransformManipulator::Hidden : public QObject {
Q_OBJECT
private:
OSGGeoTransformManipulator * const self;
osg::Matrix cameraPosition;
osg::Matrix cameraRotation;
public:
osg::ref_ptr<MyManipulator> 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"

View File

@ -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 <QObject>
#include <QVector3D>
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_

View File

@ -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 <osgGA/NodeTrackerManipulator>
#include <QDebug>
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<osgGA::NodeTrackerManipulator> 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"

View File

@ -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 <QObject>
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_

View File

@ -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 <osgGA/TrackballManipulator>
#include <QDebug>
namespace osgQtQuick {
struct OSGTrackballManipulator::Hidden : public QObject {
Q_OBJECT
private:
OSGTrackballManipulator * const self;
public:
osg::ref_ptr<osgGA::TrackballManipulator> 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"

View File

@ -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 <QObject>
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_

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file osgearth.cpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -27,8 +27,8 @@
#include "osgearth.h" #include "osgearth.h"
#include "utility.h" #include "utils/utility.h"
#include "qtwindowingsystem.h" #include "utils/qtwindowingsystem.h"
#include "utils/pathutils.h" #include "utils/pathutils.h"
@ -107,7 +107,9 @@ void OsgEarth::initialize()
initializeCache(); initializeCache();
#ifdef OSG_VERBOSE
displayInfo(); displayInfo();
#endif
} }
void OsgEarth::initializePathes() void OsgEarth::initializePathes()

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file osgearth.h * @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
* @{ * @{
* @addtogroup * @addtogroup

View File

@ -2,7 +2,7 @@ TEMPLATE = lib
TARGET = GCSOsgEarth TARGET = GCSOsgEarth
DEFINES += OSGEARTH_LIBRARY DEFINES += OSGEARTH_LIBRARY
#CONFIG += mys2 #DEFINES += OSG_VERBOSE
osg:DEFINES += USE_OSG osg:DEFINES += USE_OSG
osgQt:DEFINES += USE_OSG_QT osgQt:DEFINES += USE_OSG_QT
@ -35,40 +35,54 @@ QMAKE_CXXFLAGS += -Wno-unused-parameter
HEADERS += \ HEADERS += \
osgearth_global.h \ osgearth_global.h \
utility.h \ osgearth.h \
shapeutils.h \ utils/qtwindowingsystem.h \
qtwindowingsystem.h \ utils/utility.h \
osgearth.h utils/shapeutils.h
SOURCES += \ SOURCES += \
utility.cpp \ osgearth.cpp \
shapeutils.cpp \ utils/qtwindowingsystem.cpp \
qtwindowingsystem.cpp \ utils/utility.cpp \
osgearth.cpp utils/shapeutils.cpp
HEADERS += \ HEADERS += \
osgQtQuick/Export.hpp \ osgQtQuick/Export.hpp \
osgQtQuick/DirtySupport.hpp \
osgQtQuick/OSGNode.hpp \ osgQtQuick/OSGNode.hpp \
osgQtQuick/OSGGroup.hpp \ osgQtQuick/OSGGroup.hpp \
osgQtQuick/OSGTransformNode.hpp \ osgQtQuick/OSGTransformNode.hpp \
osgQtQuick/OSGShapeNode.hpp \ osgQtQuick/OSGShapeNode.hpp \
osgQtQuick/OSGImageNode.hpp \
osgQtQuick/OSGTextNode.hpp \ osgQtQuick/OSGTextNode.hpp \
osgQtQuick/OSGFileNode.hpp \ osgQtQuick/OSGFileNode.hpp \
osgQtQuick/OSGBackgroundNode.hpp \ osgQtQuick/OSGBillboardNode.hpp \
osgQtQuick/OSGCamera.hpp \ osgQtQuick/OSGCamera.hpp \
osgQtQuick/OSGViewport.hpp osgQtQuick/OSGViewport.hpp
SOURCES += \ SOURCES += \
osgQtQuick/DirtySupport.cpp \
osgQtQuick/OSGNode.cpp \ osgQtQuick/OSGNode.cpp \
osgQtQuick/OSGGroup.cpp \ osgQtQuick/OSGGroup.cpp \
osgQtQuick/OSGTransformNode.cpp \ osgQtQuick/OSGTransformNode.cpp \
osgQtQuick/OSGShapeNode.cpp \ osgQtQuick/OSGShapeNode.cpp \
osgQtQuick/OSGImageNode.cpp \
osgQtQuick/OSGTextNode.cpp \ osgQtQuick/OSGTextNode.cpp \
osgQtQuick/OSGFileNode.cpp \ osgQtQuick/OSGFileNode.cpp \
osgQtQuick/OSGBackgroundNode.cpp \ osgQtQuick/OSGBillboardNode.cpp \
osgQtQuick/OSGCamera.cpp \ osgQtQuick/OSGCamera.cpp \
osgQtQuick/OSGViewport.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 += \ osgearth:HEADERS += \
osgQtQuick/OSGSkyNode.hpp \ osgQtQuick/OSGSkyNode.hpp \
osgQtQuick/OSGGeoTransformNode.hpp osgQtQuick/OSGGeoTransformNode.hpp
@ -77,4 +91,12 @@ osgearth:SOURCES += \
osgQtQuick/OSGSkyNode.cpp \ osgQtQuick/OSGSkyNode.cpp \
osgQtQuick/OSGGeoTransformNode.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) copy_osg:include(copydata.pro)

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file osgearth_global.h * @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
* @{ * @{
* @addtogroup * @addtogroup

View File

@ -4,3 +4,6 @@ References :
- https://wiki.qt.io/OsgQtQuick-Demo - https://wiki.qt.io/OsgQtQuick-Demo
- https://github.com/podsvirov - https://github.com/podsvirov
- https://github.com/podsvirov/osgqtquick - https://github.com/podsvirov/osgqtquick
known issues:
- http://forum.osgearth.org/VERTEX-glCompileShader-quot-oe-mp-vertModel-quot-FAILED-tt7588106.html#none

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file qtwindowingsystem.cpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -103,20 +103,20 @@ GraphicsWindowQt::GraphicsWindowQt(osg::GraphicsContext::Traits *traits) :
_glContext(NULL), _glContext(NULL),
_surface(NULL) _surface(NULL)
{ {
qDebug() << "GraphicsWindowQt::GraphicsWindowQt"; // qDebug() << "GraphicsWindowQt::GraphicsWindowQt";
_traits = traits; _traits = traits;
init(); init();
} }
GraphicsWindowQt::~GraphicsWindowQt() GraphicsWindowQt::~GraphicsWindowQt()
{ {
qDebug() << "GraphicsWindowQt::~GraphicsWindowQt"; // qDebug() << "GraphicsWindowQt::~GraphicsWindowQt";
close(); close();
} }
void GraphicsWindowQt::init() void GraphicsWindowQt::init()
{ {
qDebug() << "GraphicsWindowQt::init"; // qDebug() << "GraphicsWindowQt::init";
if (_closing || _initialized) { if (_closing || _initialized) {
return; return;
} }
@ -199,7 +199,7 @@ bool GraphicsWindowQt::valid() const
bool GraphicsWindowQt::realizeImplementation() bool GraphicsWindowQt::realizeImplementation()
{ {
qDebug() << "GraphicsWindowQt::realizeImplementation"; // qDebug() << "GraphicsWindowQt::realizeImplementation";
// save the current context // save the current context
// note: this will save only Qt-based contexts // note: this will save only Qt-based contexts
@ -217,16 +217,18 @@ bool GraphicsWindowQt::realizeImplementation()
QOpenGLContext *currentContext = QOpenGLContext::currentContext(); QOpenGLContext *currentContext = QOpenGLContext::currentContext();
if (!currentContext) { if (!currentContext) {
qDebug() << "GraphicsWindowQt::realizeImplementation - creating owned context"; // qDebug() << "GraphicsWindowQt::realizeImplementation - creating owned context";
_owned = true; _owned = true;
_glContext = new QOpenGLContext(); _glContext = new QOpenGLContext();
_glContext->create(); _glContext->create();
_surface = new QOffscreenSurface(); _surface = new QOffscreenSurface();
_surface->setFormat(_glContext->format()); _surface->setFormat(_glContext->format());
_surface->create(); _surface->create();
#ifdef OSG_VERBOSE
osgQtQuick::formatInfo(_surface->format()); osgQtQuick::formatInfo(_surface->format());
#endif
} else { } else {
qDebug() << "GraphicsWindowQt::realizeImplementation - using current context"; // qDebug() << "GraphicsWindowQt::realizeImplementation - using current context";
_glContext = currentContext; _glContext = currentContext;
} }
@ -316,7 +318,7 @@ bool GraphicsWindowQt::releaseContextImplementation()
return false; return false;
} }
if (_owned && _glContext) { if (_owned && _glContext) {
qDebug() << "GraphicsWindowQt::releaseContextImplementation"; // qDebug() << "GraphicsWindowQt::releaseContextImplementation";
_glContext->doneCurrent(); _glContext->doneCurrent();
} }
return true; return true;
@ -324,14 +326,14 @@ bool GraphicsWindowQt::releaseContextImplementation()
void GraphicsWindowQt::closeImplementation() void GraphicsWindowQt::closeImplementation()
{ {
qDebug() << "GraphicsWindowQt::closeImplementation"; // qDebug() << "GraphicsWindowQt::closeImplementation";
_closing = true; _closing = true;
_initialized = false; _initialized = false;
_valid = false; _valid = false;
_realized = false; _realized = false;
if (_owned) { if (_owned) {
if (_glContext) { if (_glContext) {
qDebug() << "GraphicsWindowQt::closeImplementation - deleting owned context"; // qDebug() << "GraphicsWindowQt::closeImplementation - deleting owned context";
delete _glContext; delete _glContext;
} }
if (_surface) { if (_surface) {

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file qtwindowingsystem.h * @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
* @{ * @{
* @addtogroup * @addtogroup

View File

@ -1,4 +1,4 @@
#include "shapeutils.h" #include "utils/shapeutils.h"
#include <math.h> #include <math.h>

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file utility.cpp * @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
* @{ * @{
* @addtogroup * @addtogroup
@ -25,7 +25,7 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "utility.h" #include "utils/utility.h"
// osgQtQuick qml types // osgQtQuick qml types
#include "osgQtQuick/OSGNode.hpp" #include "osgQtQuick/OSGNode.hpp"
@ -33,11 +33,16 @@
#include "osgQtQuick/OSGFileNode.hpp" #include "osgQtQuick/OSGFileNode.hpp"
#include "osgQtQuick/OSGTransformNode.hpp" #include "osgQtQuick/OSGTransformNode.hpp"
#include "osgQtQuick/OSGShapeNode.hpp" #include "osgQtQuick/OSGShapeNode.hpp"
#include "osgQtQuick/OSGImageNode.hpp"
#include "osgQtQuick/OSGTextNode.hpp" #include "osgQtQuick/OSGTextNode.hpp"
#include "osgQtQuick/OSGBackgroundNode.hpp" #include "osgQtQuick/OSGBillboardNode.hpp"
#include "osgQtQuick/OSGCamera.hpp" #include "osgQtQuick/OSGCamera.hpp"
#include "osgQtQuick/OSGViewport.hpp" #include "osgQtQuick/OSGViewport.hpp"
#include "osgQtQuick/ga/OSGCameraManipulator.hpp"
#include "osgQtQuick/ga/OSGNodeTrackerManipulator.hpp"
#include "osgQtQuick/ga/OSGTrackballManipulator.hpp"
#include <osg/NodeCallback> #include <osg/NodeCallback>
#include <osg/Camera> #include <osg/Camera>
#include <osg/MatrixTransform> #include <osg/MatrixTransform>
@ -61,6 +66,9 @@
#include "osgQtQuick/OSGSkyNode.hpp" #include "osgQtQuick/OSGSkyNode.hpp"
#include "osgQtQuick/OSGGeoTransformNode.hpp" #include "osgQtQuick/OSGGeoTransformNode.hpp"
#include "osgQtQuick/ga/OSGEarthManipulator.hpp"
#include "osgQtQuick/ga/OSGGeoTransformManipulator.hpp"
#include <osgEarth/Capabilities> #include <osgEarth/Capabilities>
#include <osgEarth/MapNode> #include <osgEarth/MapNode>
#include <osgEarth/SpatialReference> #include <osgEarth/SpatialReference>
@ -75,9 +83,11 @@
namespace osgQtQuick { namespace osgQtQuick {
class CullCallback : public osg::NodeCallback { class CullCallback : public osg::NodeCallback {
public: public:
CullCallback() {} CullCallback()
{}
virtual ~CullCallback() {} virtual ~CullCallback()
{}
public: public:
virtual void operator()(osg::Node *node, osg::NodeVisitor *nv) virtual void operator()(osg::Node *node, osg::NodeVisitor *nv)
@ -101,12 +111,14 @@ class InsertCallbacksVisitor : public osg::NodeVisitor {
public: public:
InsertCallbacksVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) InsertCallbacksVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{} {}
virtual void apply(osg::Node & node) virtual void apply(osg::Node & node)
{ {
// node.setUpdateCallback(new UpdateCallback()); // node.setUpdateCallback(new UpdateCallback());
node.setCullCallback(new CullCallback()); node.setCullCallback(new CullCallback());
traverse(node); traverse(node);
} }
virtual void apply(osg::Geode & geode) virtual void apply(osg::Geode & geode)
{ {
// geode.setUpdateCallback(new UpdateCallback()); // geode.setUpdateCallback(new UpdateCallback());
@ -122,6 +134,7 @@ public:
// geode.getDrawable(i)->setDrawCallback(new DrawableDrawCallback()); // geode.getDrawable(i)->setDrawCallback(new DrawableDrawCallback());
// } // }
} }
virtual void apply(osg::Transform & node) virtual void apply(osg::Transform & node)
{ {
apply((osg::Node &)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)) { if (eq.getElevation(geoPoint, elevation, 0.0)) {
clamped = ((geoPoint.z() - offset) < elevation); clamped = ((geoPoint.z() - offset) < elevation);
if (clamped) { if (clamped) {
qDebug() << "Utility::clampGeoPoint - clamping" << geoPoint.z() - offset << "/" << elevation; // qDebug() << "Utility::clampGeoPoint - clamping" << geoPoint.z() - offset << "/" << elevation;
geoPoint.z() = elevation + offset; geoPoint.z() = elevation + offset;
} }
} else { } else {
@ -522,33 +535,45 @@ void registerTypes()
{ {
int maj = 1, min = 0; int maj = 1, min = 0;
// @uri osgQtQuick // viewport
qmlRegisterType<osgQtQuick::OSGViewport>("OsgQtQuick", maj, min, "OSGViewport");
qmlRegisterType<osgQtQuick::UpdateMode>("OsgQtQuick", maj, min, "UpdateMode");
// basic nodes
qmlRegisterType<osgQtQuick::OSGNode>("OsgQtQuick", maj, min, "OSGNode"); qmlRegisterType<osgQtQuick::OSGNode>("OsgQtQuick", maj, min, "OSGNode");
qmlRegisterType<osgQtQuick::OSGGroup>("OsgQtQuick", maj, min, "OSGGroup"); qmlRegisterType<osgQtQuick::OSGGroup>("OsgQtQuick", maj, min, "OSGGroup");
qmlRegisterType<osgQtQuick::OSGFileNode>("OsgQtQuick", maj, min, "OSGFileNode");
qmlRegisterType<osgQtQuick::OptimizeMode>("OsgQtQuick", maj, min, "OptimizeMode");
qmlRegisterType<osgQtQuick::OSGTransformNode>("OsgQtQuick", maj, min, "OSGTransformNode"); qmlRegisterType<osgQtQuick::OSGTransformNode>("OsgQtQuick", maj, min, "OSGTransformNode");
qmlRegisterType<osgQtQuick::OSGTextNode>("OsgQtQuick", maj, min, "OSGTextNode"); // primitive nodes
qmlRegisterType<osgQtQuick::OSGShapeNode>("OsgQtQuick", maj, min, "OSGShapeNode"); qmlRegisterType<osgQtQuick::OSGShapeNode>("OsgQtQuick", maj, min, "OSGShapeNode");
qmlRegisterType<osgQtQuick::ShapeType>("OsgQtQuick", maj, min, "ShapeType"); qmlRegisterType<osgQtQuick::ShapeType>("OsgQtQuick", maj, min, "ShapeType");
qmlRegisterType<osgQtQuick::OSGBackgroundNode>("OsgQtQuick", maj, min, "OSGBackgroundNode"); qmlRegisterType<osgQtQuick::OSGImageNode>("OsgQtQuick", maj, min, "OSGImageNode");
qmlRegisterType<osgQtQuick::OSGViewport>("OsgQtQuick", maj, min, "OSGViewport"); qmlRegisterType<osgQtQuick::OSGTextNode>("OsgQtQuick", maj, min, "OSGTextNode");
qmlRegisterType<osgQtQuick::UpdateMode>("OsgQtQuick", maj, min, "UpdateMode");
qmlRegisterType<osgQtQuick::OSGBillboardNode>("OsgQtQuick", maj, min, "OSGBillboardNode");
qmlRegisterType<osgQtQuick::OSGFileNode>("OsgQtQuick", maj, min, "OSGFileNode");
qmlRegisterType<osgQtQuick::OptimizeMode>("OsgQtQuick", maj, min, "OptimizeMode");
// camera nodes
qmlRegisterType<osgQtQuick::OSGCamera>("OsgQtQuick", maj, min, "OSGCamera"); qmlRegisterType<osgQtQuick::OSGCamera>("OsgQtQuick", maj, min, "OSGCamera");
qmlRegisterType<osgQtQuick::ManipulatorMode>("OsgQtQuick", maj, min, "ManipulatorMode");
// camera manipulators
qmlRegisterType<osgQtQuick::OSGCameraManipulator>("OsgQtQuick", maj, min, "OSGCameraManipulator");
qmlRegisterType<osgQtQuick::OSGNodeTrackerManipulator>("OsgQtQuick", maj, min, "OSGNodeTrackerManipulator");
qmlRegisterType<osgQtQuick::TrackerMode>("OsgQtQuick", maj, min, "TrackerMode"); qmlRegisterType<osgQtQuick::TrackerMode>("OsgQtQuick", maj, min, "TrackerMode");
qmlRegisterType<osgQtQuick::OSGTrackballManipulator>("OsgQtQuick", maj, min, "OSGTrackballManipulator");
#ifdef USE_OSGEARTH #ifdef USE_OSGEARTH
qmlRegisterType<osgQtQuick::OSGSkyNode>("OsgQtQuick", maj, min, "OSGSkyNode"); qmlRegisterType<osgQtQuick::OSGSkyNode>("OsgQtQuick", maj, min, "OSGSkyNode");
qmlRegisterType<osgQtQuick::OSGGeoTransformNode>("OsgQtQuick", maj, min, "OSGGeoTransformNode"); qmlRegisterType<osgQtQuick::OSGGeoTransformNode>("OsgQtQuick", maj, min, "OSGGeoTransformNode");
qmlRegisterType<osgQtQuick::OSGEarthManipulator>("OsgQtQuick", maj, min, "OSGEarthManipulator");
qmlRegisterType<osgQtQuick::OSGGeoTransformManipulator>("OsgQtQuick", maj, min, "OSGGeoTransformManipulator");
#endif // USE_OSGEARTH #endif // USE_OSGEARTH
} }
} // namespace osgQtQuick } // namespace osgQtQuick

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* *
* @file utility.h * @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
* @{ * @{
* @addtogroup * @addtogroup

View File

@ -127,16 +127,16 @@ void QuickWidgetProxy::onStatusChanged(QQuickWidget::Status status)
{ {
switch (status) { switch (status) {
case QQuickWidget::Null: case QQuickWidget::Null:
qDebug() << "QuickWidgetProxy - status Null"; qWarning() << "QuickWidgetProxy - status Null";
break; break;
case QQuickWidget::Ready: case QQuickWidget::Ready:
qDebug() << "QuickWidgetProxy - status Ready"; // qDebug() << "QuickWidgetProxy - status Ready";
break; break;
case QQuickWidget::Loading: case QQuickWidget::Loading:
qDebug() << "QuickWidgetProxy - status Loading"; // qDebug() << "QuickWidgetProxy - status Loading";
break; break;
case QQuickWidget::Error: case QQuickWidget::Error:
qDebug() << "QuickWidgetProxy - status Error"; qWarning() << "QuickWidgetProxy - status Error";
foreach(const QQmlError &error, errors()) { foreach(const QQmlError &error, errors()) {
qWarning() << error.description(); qWarning() << error.description();
} }
@ -148,16 +148,16 @@ void QuickWidgetProxy::onStatusChanged(QQuickView::Status status)
{ {
switch (status) { switch (status) {
case QQuickView::Null: case QQuickView::Null:
qDebug() << "QuickWidgetProxy - status Null"; qWarning() << "QuickWidgetProxy - status Null";
break; break;
case QQuickView::Ready: case QQuickView::Ready:
qDebug() << "QuickWidgetProxy - status Ready"; // qDebug() << "QuickWidgetProxy - status Ready";
break; break;
case QQuickView::Loading: case QQuickView::Loading:
qDebug() << "QuickWidgetProxy - status Loading"; // qDebug() << "QuickWidgetProxy - status Loading";
break; break;
case QQuickView::Error: case QQuickView::Error:
qDebug() << "QuickWidgetProxy - status Error"; qWarning() << "QuickWidgetProxy - status Error";
foreach(const QQmlError &error, errors()) { foreach(const QQmlError &error, errors()) {
qWarning() << error.description(); qWarning() << error.description();
} }

View File

@ -28,13 +28,18 @@
#include "pfdqmlcontext.h" #include "pfdqmlcontext.h"
#include "extensionsystem/pluginmanager.h" #include "extensionsystem/pluginmanager.h"
#include "uavobjectmanager.h"
#include "uavobject.h" #include "uavobject.h"
#include "uavobjectmanager.h"
#include "utils/stringutils.h" #include "utils/stringutils.h"
#include "utils/pathutils.h"
#include "flightbatterysettings.h" #include "flightbatterysettings.h"
#include <QQmlContext> #include <QQmlContext>
#include <QDebug> #include <QDebug>
#include <QDirIterator>
const QString PfdQmlContext::CONTEXT_PROPERTY_NAME = "pfdContext";
PfdQmlContext::PfdQmlContext(QObject *parent) : QObject(parent), PfdQmlContext::PfdQmlContext(QObject *parent) : QObject(parent),
m_speedUnit("m/s"), m_speedUnit("m/s"),
@ -50,8 +55,13 @@ PfdQmlContext::PfdQmlContext(QObject *parent) : QObject(parent),
m_dateTime(QDateTime()), m_dateTime(QDateTime()),
m_minAmbientLight(0.03), m_minAmbientLight(0.03),
m_modelFile(""), m_modelFile(""),
m_modelIndex(0),
m_backgroundImageFile("") m_backgroundImageFile("")
{} {
addModelDir("helis");
addModelDir("multi");
addModelDir("planes");
}
PfdQmlContext::~PfdQmlContext() PfdQmlContext::~PfdQmlContext()
{} {}
@ -220,11 +230,32 @@ QString PfdQmlContext::modelFile() const
void PfdQmlContext::setModelFile(const QString &arg) void PfdQmlContext::setModelFile(const QString &arg)
{ {
if (m_modelFile != 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()); 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 QString PfdQmlContext::backgroundImageFile() const
{ {
return m_backgroundImageFile; return m_backgroundImageFile;
@ -281,12 +312,16 @@ void PfdQmlContext::loadConfiguration(PfdQmlGadgetConfiguration *config)
void PfdQmlContext::saveState(QSettings *settings) void PfdQmlContext::saveState(QSettings *settings)
{ {
Q_UNUSED(settings); settings->setValue("modelFile", modelFile());
} }
void PfdQmlContext::restoreState(QSettings *settings) void PfdQmlContext::restoreState(QSettings *settings)
{ {
Q_UNUSED(settings); QString file = settings->value("modelFile").toString();
if (!file.isEmpty()) {
setModelFile(file);
}
} }
void PfdQmlContext::apply(QQmlContext *context) void PfdQmlContext::apply(QQmlContext *context)
@ -339,6 +374,17 @@ void PfdQmlContext::apply(QQmlContext *context)
} }
} }
// to expose settings values // expose this context to Qml
context->setContextProperty("pfdContext", this); 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);
}
} }

View File

@ -52,7 +52,11 @@ class PfdQmlContext : public QObject {
Q_PROPERTY(QDateTime dateTime READ dateTime WRITE setDateTime NOTIFY dateTimeChanged) Q_PROPERTY(QDateTime dateTime READ dateTime WRITE setDateTime NOTIFY dateTimeChanged)
Q_PROPERTY(double minimumAmbientLight READ minimumAmbientLight WRITE setMinimumAmbientLight NOTIFY minimumAmbientLightChanged) 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) Q_PROPERTY(QString backgroundImageFile READ backgroundImageFile WRITE setBackgroundImageFile NOTIFY backgroundImageFileChanged)
public: public:
@ -87,8 +91,14 @@ public:
double minimumAmbientLight() const; double minimumAmbientLight() const;
void setMinimumAmbientLight(double arg); void setMinimumAmbientLight(double arg);
// model
QString modelFile() const; QString modelFile() const;
void setModelFile(const QString &arg); void setModelFile(const QString &arg);
QStringList modelFileList() const;
Q_INVOKABLE void nextModel();
Q_INVOKABLE void previousModel();
// background
QString backgroundImageFile() const; QString backgroundImageFile() const;
void setBackgroundImageFile(const QString &arg); void setBackgroundImageFile(const QString &arg);
@ -121,6 +131,9 @@ signals:
void backgroundImageFileChanged(QString arg); void backgroundImageFileChanged(QString arg);
private: private:
// constants
static const QString CONTEXT_PROPERTY_NAME;
QString m_speedUnit; QString m_speedUnit;
double m_speedFactor; double m_speedFactor;
QString m_altitudeUnit; QString m_altitudeUnit;
@ -138,7 +151,11 @@ private:
double m_minAmbientLight; double m_minAmbientLight;
QString m_modelFile; QString m_modelFile;
int m_modelIndex;
QStringList m_modelFileList;
QString m_backgroundImageFile; QString m_backgroundImageFile;
void addModelDir(QString dir);
}; };
#endif /* PFDQMLCONTEXT_H_ */ #endif /* PFDQMLCONTEXT_H_ */

View File

@ -52,14 +52,10 @@ WelcomePlugin::WelcomePlugin()
WelcomePlugin::~WelcomePlugin() WelcomePlugin::~WelcomePlugin()
{ {
// The below code is commented out to avoid having the application if (m_welcomeMode) {
// crash when it is terminated. TODO: Fix a real solution.
/*
if (m_welcomeMode) {
removeObject(m_welcomeMode); removeObject(m_welcomeMode);
delete m_welcomeMode; delete m_welcomeMode;
} }
*/
} }
/*! Initializes the plugin. Returns true on success. /*! Initializes the plugin. Returns true on success.

View File

@ -1635,7 +1635,7 @@
<version>0.0.0</version> <version>0.0.0</version>
</configInfo> </configInfo>
<data> <data>
<qmlFile>%%DATAPATH%%qml/Pfd.qml</qmlFile> <qmlFile>%%DATAPATH%%qml/PfdTerrain.qml</qmlFile>
<altitudeFactor>1</altitudeFactor> <altitudeFactor>1</altitudeFactor>
<speedFactor>1</speedFactor> <speedFactor>1</speedFactor>
<terrainEnabled>true</terrainEnabled> <terrainEnabled>true</terrainEnabled>
@ -1659,7 +1659,7 @@
<version>0.0.0</version> <version>0.0.0</version>
</configInfo> </configInfo>
<data> <data>
<qmlFile>%%DATAPATH%%qml/Pfd.qml</qmlFile> <qmlFile>%%DATAPATH%%qml/PfdTerrain.qml</qmlFile>
<altitudeFactor>1</altitudeFactor> <altitudeFactor>1</altitudeFactor>
<speedFactor>1</speedFactor> <speedFactor>1</speedFactor>
<terrainEnabled>true</terrainEnabled> <terrainEnabled>true</terrainEnabled>
@ -1683,7 +1683,7 @@
<version>0.0.0</version> <version>0.0.0</version>
</configInfo> </configInfo>
<data> <data>
<qmlFile>%%DATAPATH%%qml/ModelView.qml</qmlFile> <qmlFile>%%DATAPATH%%qml/Model.qml</qmlFile>
<altitudeFactor>1</altitudeFactor> <altitudeFactor>1</altitudeFactor>
<speedFactor>1</speedFactor> <speedFactor>1</speedFactor>
<terrainEnabled>false</terrainEnabled> <terrainEnabled>false</terrainEnabled>
@ -1707,7 +1707,7 @@
<version>0.0.0</version> <version>0.0.0</version>
</configInfo> </configInfo>
<data> <data>
<qmlFile>%%DATAPATH%%qml/ModelView.qml</qmlFile> <qmlFile>%%DATAPATH%%qml/ModelTerrain.qml</qmlFile>
<altitudeFactor>1</altitudeFactor> <altitudeFactor>1</altitudeFactor>
<speedFactor>1</speedFactor> <speedFactor>1</speedFactor>
<terrainEnabled>true</terrainEnabled> <terrainEnabled>true</terrainEnabled>
@ -1731,7 +1731,7 @@
<version>0.0.0</version> <version>0.0.0</version>
</configInfo> </configInfo>
<data> <data>
<qmlFile>%%DATAPATH%%qml/ModelView.qml</qmlFile> <qmlFile>%%DATAPATH%%qml/ModelTerrain.qml</qmlFile>
<altitudeFactor>1</altitudeFactor> <altitudeFactor>1</altitudeFactor>
<speedFactor>1</speedFactor> <speedFactor>1</speedFactor>
<terrainEnabled>true</terrainEnabled> <terrainEnabled>true</terrainEnabled>
@ -1755,7 +1755,7 @@
<version>0.0.0</version> <version>0.0.0</version>
</configInfo> </configInfo>
<data> <data>
<qmlFile>%%DATAPATH%%qml/EarthView.qml</qmlFile> <qmlFile>%%DATAPATH%%qml/Earth.qml</qmlFile>
<altitudeFactor>1</altitudeFactor> <altitudeFactor>1</altitudeFactor>
<speedFactor>1</speedFactor> <speedFactor>1</speedFactor>
<terrainEnabled>true</terrainEnabled> <terrainEnabled>true</terrainEnabled>

View File

@ -18,22 +18,37 @@
* along with LibrePilot GCS. If not, see <http://www.gnu.org/licenses/>. * along with LibrePilot GCS. If not, see <http://www.gnu.org/licenses/>.
*/ */
import QtQuick 2.4 import QtQuick 2.4
import QtQuick.Controls 1.4
import Pfd 1.0 import Pfd 1.0
import OsgQtQuick 1.0 import OsgQtQuick 1.0
import "common.js" as Utils import "js/common.js" as Utils
Item { Item {
OSGViewport { OSGViewport {
id: osgViewport
anchors.fill: parent anchors.fill: parent
focus: true focus: true
sceneData: skyNode
sceneNode: skyNode
camera: camera camera: camera
manipulator: earthManipulator
OSGCamera {
id: camera
fieldOfView: 90
}
OSGEarthManipulator {
id: earthManipulator
}
OSGSkyNode { OSGSkyNode {
id: skyNode id: skyNode
sceneData: terrainNode sceneNode: terrainNode
viewport: osgViewport
dateTime: Utils.getDateTime() dateTime: Utils.getDateTime()
minimumAmbientLight: pfdContext.minimumAmbientLight minimumAmbientLight: pfdContext.minimumAmbientLight
} }
@ -44,11 +59,25 @@ Item {
async: false 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
} }
} }

View File

@ -19,10 +19,7 @@
*/ */
import QtQuick 2.4 import QtQuick 2.4
Item { import "model"
Loader {
anchors.fill: parent ModelView {
focus: true }
source: pfdContext.terrainEnabled ? "model/ModelTerrainView.qml" : "model/ModelView.qml"
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.4
import "model"
ModelTerrainView {
}

View File

@ -19,107 +19,8 @@
*/ */
import QtQuick 2.4 import QtQuick 2.4
import "pfd" as Pfd import "pfd"
Rectangle { PfdView {
color: "#515151" worldFile: "PfdSimpleWorld.qml"
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
}
}
}
} }

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.4
import "pfd"
PfdView {
opaque: false
worldFile: "PfdTerrainWorld.qml"
}

View File

@ -28,7 +28,7 @@
.import UAVTalk.VtolPathFollowerSettings 1.0 as VtolPathFollowerSettings .import UAVTalk.VtolPathFollowerSettings 1.0 as VtolPathFollowerSettings
// Navigation // Navigation
.import UAVTalk.HomeLocation 1.0 as HomeLocation .import UAVTalk.HomeLocation 1.0 as HomeLocation
.import UAVTalk.TakeOffLocation 1.0 as TakeOffLocation .import UAVTalk.TakeOffLocation 1.0 as TakeOffLocation
// Sensors // Sensors
@ -147,7 +147,7 @@ function defaultPosition() {
* *
*/ */
function isCC3D() { function isCC3D() {
// Hack: detect Coptercontrol with mem free // Hack: detect Coptercontrol with mem free
return (freeMemoryBytes() < 3096); return (freeMemoryBytes() < 3096);
} }
@ -251,7 +251,7 @@ function gpsStatus() {
return ["NO GPS", "NO FIX", "2D", "3D"][gpsPositionSensor.status]; 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]; 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); return (hwSettings.optionalModulesBattery == HwSettings.OptionalModules.Enabled);
} }
function batteryNbCells() { function batteryNbCells() {
return flightBatterySettings.nbCells; return flightBatterySettings.nbCells;
} }
@ -287,7 +287,7 @@ function batteryConsumedEnergy() {
return flightBatteryState.consumedEnergy.toFixed(0); return flightBatteryState.consumedEnergy.toFixed(0);
} }
function estimatedFlightTimeValue() { function estimatedFlightTimeValue() {
return Math.round(flightBatteryState.estimatedFlightTime); return Math.round(flightBatteryState.estimatedFlightTime);
} }
@ -351,7 +351,7 @@ function waypointHeading() {
} }
function homeDistance() { 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)); Math.pow((takeOffLocation.north - positionState.north), 2));
} }
@ -377,8 +377,8 @@ function isVtolPathFollowerSettingsThrustAuto() {
} }
function flightModeName() { function flightModeName() {
return ["MANUAL", "STAB 1", "STAB 2", "STAB 3", "STAB 4", "STAB 5", "STAB 6", return ["MANUAL", "STAB 1", "STAB 2", "STAB 3", "STAB 4", "STAB 5", "STAB 6",
"POS HOLD", "COURSELOCK", "VEL ROAM", "HOME LEASH", "ABS POS", "RTB", "POS HOLD", "COURSELOCK", "VEL ROAM", "HOME LEASH", "ABS POS", "RTB",
"LAND", "PATHPLAN", "POI", "AUTOCRUISE", "AUTOTAKEOFF"][flightStatus.flightMode]; "LAND", "PATHPLAN", "POI", "AUTOCRUISE", "AUTOTAKEOFF"][flightStatus.flightMode];
} }

View File

@ -18,75 +18,105 @@
* along with LibrePilot GCS. If not, see <http://www.gnu.org/licenses/>. * along with LibrePilot GCS. If not, see <http://www.gnu.org/licenses/>.
*/ */
import QtQuick 2.4 import QtQuick 2.4
import QtQuick.Controls 1.4
import Pfd 1.0 import Pfd 1.0
import OsgQtQuick 1.0 import OsgQtQuick 1.0
import "../common.js" as Utils import "../js/common.js" as Utils
import "../uav.js" as UAV import "../js/uav.js" as UAV
OSGViewport { Item {
anchors.fill: parent OSGViewport {
focus: true id: osgViewport
sceneData: skyNode
camera: camera
OSGSkyNode { anchors.fill: parent
id: skyNode focus: true
sceneData: sceneGroup
dateTime: Utils.getDateTime()
minimumAmbientLight: pfdContext.minimumAmbientLight
}
OSGGroup { sceneNode: skyNode
id: sceneGroup camera: camera
children: [ terrainNode, modelNode ] manipulator: nodeTrackerManipulator
}
OSGFileNode { OSGCamera {
id: terrainNode id: camera
source: pfdContext.terrainFile fieldOfView: 90
async: false logarithmicDepthBuffer: true
} }
OSGGeoTransformNode { OSGNodeTrackerManipulator {
id: modelNode id: nodeTrackerManipulator
// use model to compute camera home position
sceneNode: modelTransformNode
// model will be tracked
trackNode: modelTransformNode
}
modelData: modelTransformNode OSGSkyNode {
sceneData: terrainNode 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 { sceneNode: terrainFileNode
id: modelTransformNode children: [ modelTransformNode ]
modelData: modelFileNode
// model dimensions are in mm, scale to meters
scale: Qt.vector3d(0.001, 0.001, 0.001)
attitude: UAV.attitude()
}
OSGFileNode { clampToTerrain: true
id: modelFileNode
// use ShaderGen pseudoloader to generate the shaders expected by osgEarth position: UAV.position()
// see http://docs.osgearth.org/en/latest/faq.html#i-added-a-node-but-it-has-no-texture-lighting-etc-in-osgearth-why }
source: pfdContext.modelFile + ".osgearth_shadergen"
async: false OSGTransformNode {
optimizeMode: OptimizeMode.OptimizeAndCheck 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
} }
} }

View File

@ -21,32 +21,48 @@ import QtQuick 2.4
import OsgQtQuick 1.0 import OsgQtQuick 1.0
import "../uav.js" as UAV import "../js/uav.js" as UAV
Item { Item {
OSGViewport { OSGViewport {
anchors.fill: parent anchors.fill: parent
focus: true focus: true
sceneData: sceneNode
sceneNode: sceneNode
camera: camera camera: camera
manipulator: trackballManipulator
OSGCamera {
id: camera
fieldOfView: 90
}
OSGTrackballManipulator {
id: trackballManipulator
sceneNode: transformNode
}
OSGGroup { OSGGroup {
id: sceneNode id: sceneNode
children: [ children: [ transformNode, backgroundNode ]
transformNode,
backgroundNode
]
} }
OSGBackgroundNode { OSGBillboardNode {
id: backgroundNode id: backgroundNode
children: [ backgroundImageNode ]
}
OSGImageNode {
id: backgroundImageNode
imageFile: pfdContext.backgroundImageFile imageFile: pfdContext.backgroundImageFile
} }
OSGTransformNode { OSGTransformNode {
id: transformNode id: transformNode
modelData: fileNode
children: [ fileNode ]
attitude: UAV.attitude() attitude: UAV.attitude()
} }
@ -57,10 +73,12 @@ Item {
optimizeMode: OptimizeMode.OptimizeAndCheck optimizeMode: OptimizeMode.OptimizeAndCheck
} }
OSGCamera { Keys.onUpPressed: {
id: camera pfdContext.nextModel();
fieldOfView: 90 }
sceneNode: transformNode
Keys.onDownPressed: {
pfdContext.previousModel();
} }
} }

View File

@ -19,8 +19,8 @@
*/ */
import QtQuick 2.4 import QtQuick 2.4
import "../common.js" as Utils import "../js/common.js" as Utils
import "../uav.js" as UAV import "../js/uav.js" as UAV
Item { Item {
id: sceneItem id: sceneItem

View File

@ -19,7 +19,7 @@
*/ */
import QtQuick 2.4 import QtQuick 2.4
import "../uav.js" as UAV import "../js/uav.js" as UAV
Item { Item {
id: sceneItem id: sceneItem

View File

@ -19,8 +19,8 @@
*/ */
import QtQuick 2.4 import QtQuick 2.4
import "../common.js" as Utils import "../js/common.js" as Utils
import "../uav.js" as UAV import "../js/uav.js" as UAV
Item { Item {
id: info id: info
@ -62,7 +62,7 @@ Item {
sceneSize: info.sceneSize sceneSize: info.sceneSize
elementName: "info-bg" elementName: "info-bg"
width: parent.width 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) x: Math.floor(scaledBounds.x * sceneItem.width)
y: Math.floor(scaledBounds.y * sceneItem.height) y: Math.floor(scaledBounds.y * sceneItem.height)
opacity: pfdContext.terrainEnabled ? 0.6 : 1 opacity: opaque ? 1 : 0.6
states: State { states: State {
name: "fading" name: "fading"

View File

@ -19,8 +19,8 @@
*/ */
import QtQuick 2.0 import QtQuick 2.0
import "../common.js" as Utils import "../js/common.js" as Utils
import "../uav.js" as UAV import "../js/uav.js" as UAV
Item { Item {
id: panels id: panels

View File

@ -19,7 +19,7 @@
*/ */
import QtQuick 2.4 import QtQuick 2.4
import "../uav.js" as UAV import "../js/uav.js" as UAV
Item { Item {
id: worldView id: worldView

View File

@ -22,50 +22,59 @@ import QtQuick 2.4
import Pfd 1.0 import Pfd 1.0
import OsgQtQuick 1.0 import OsgQtQuick 1.0
import "../common.js" as Utils import "../js/common.js" as Utils
import "../uav.js" as UAV import "../js/uav.js" as UAV
OSGViewport { OSGViewport {
id: fullview id: osgViewport
//anchors.fill: parent //anchors.fill: parent
focus: true focus: true
sceneData: skyNode
camera: camera
property real horizontCenter : horizontCenterItem.horizontCenter readonly property real horizontCenter : horizontCenterItem.horizontCenter
// Factor for OSGview vertical offset // Factor for OSGViewer vertical offset
property double factor: 0.04 readonly property double factor: 0.04
// Stretch height and apply offset // Stretch height and apply offset
//height: height * (1 + factor) //height: height * (1 + factor)
y: -height * 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 { OSGSkyNode {
id: skyNode id: skyNode
sceneData: terrainNode sceneNode: terrainFileNode
viewport: osgViewport
dateTime: Utils.getDateTime() dateTime: Utils.getDateTime()
minimumAmbientLight: pfdContext.minimumAmbientLight minimumAmbientLight: pfdContext.minimumAmbientLight
} }
OSGFileNode { OSGFileNode {
id: terrainNode id: terrainFileNode
source: pfdContext.terrainFile source: pfdContext.terrainFile
async: false async: false
} }
OSGCamera {
id: camera
fieldOfView: 100
sceneNode: terrainNode
logarithmicDepthBuffer: true
clampToTerrain: true
manipulatorMode: ManipulatorMode.User
attitude: UAV.attitude()
position: UAV.position()
}
Rectangle { Rectangle {
// using rectangle instead of svg rendered to pixmap // using rectangle instead of svg rendered to pixmap
// as it's much more memory efficient // as it's much more memory efficient
@ -82,7 +91,6 @@ OSGViewport {
property double pitch1DegHeight: sceneItem.height * pitch1DegScaledHeight property double pitch1DegHeight: sceneItem.height * pitch1DegScaledHeight
transform: [ transform: [
Translate { Translate {
id: pitchTranslate id: pitchTranslate
@ -104,7 +112,7 @@ OSGViewport {
property variant scaledBounds: svgRenderer.scaledElementBounds("pfd/pfd.svg", "pitch-window-terrain") property variant scaledBounds: svgRenderer.scaledElementBounds("pfd/pfd.svg", "pitch-window-terrain")
x: Math.floor(scaledBounds.x * sceneItem.width) 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) width: Math.floor(scaledBounds.width * sceneItem.width)
height: Math.floor(scaledBounds.height * sceneItem.height) height: Math.floor(scaledBounds.height * sceneItem.height)

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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
}
}
}
}

View File

@ -19,7 +19,7 @@
*/ */
import QtQuick 2.4 import QtQuick 2.4
import "../uav.js" as UAV import "../js/uav.js" as UAV
Item { Item {
id: sceneItem id: sceneItem

View File

@ -19,7 +19,7 @@
*/ */
import QtQuick 2.4 import QtQuick 2.4
import "../uav.js" as UAV import "../js/uav.js" as UAV
Item { Item {
id: sceneItem id: sceneItem

View File

@ -19,7 +19,7 @@
*/ */
import QtQuick 2.4 import QtQuick 2.4
import "../uav.js" as UAV import "../js/uav.js" as UAV
Item { Item {
id: sceneItem id: sceneItem

View File

@ -19,8 +19,8 @@
*/ */
import QtQuick 2.4 import QtQuick 2.4
import "../common.js" as Utils import "../js/common.js" as Utils
import "../uav.js" as UAV import "../js/uav.js" as UAV
Item { Item {
id: warnings id: warnings