1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-20 10:54:14 +01:00

LP-29 factorize dirty flag handling in new DirtySupport class

simplifies OSGNode and OSGCameraManipulator
OSGViewport should use DirtySupport too
This commit is contained in:
Philippe Renon 2016-03-20 22:51:37 +01:00
parent c1d0d03ba0
commit a124ddd5da
14 changed files with 312 additions and 216 deletions

View File

@ -0,0 +1,145 @@
/**
******************************************************************************
*
* @file DirtySupport.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 "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)
{
if (!dirtyFlags) {
osg::Node *node = self->hookNode();
if (node) {
if (!nodeUpdateCallback.valid()) {
// lazy creation
nodeUpdateCallback = new NodeUpdateCallback(this);
}
node->addUpdateCallback(nodeUpdateCallback.get());
} else {
qWarning() << "DirtySupport::setDirty - node is null";
}
}
dirtyFlags |= mask;
}
void clearDirty()
{
osg::Node *node = self->hookNode();
if (node && nodeUpdateCallback.valid()) {
node->removeUpdateCallback(nodeUpdateCallback.get());
}
dirtyFlags = 0;
}
void update()
{
if (dirtyFlags) {
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) 2015.
* @addtogroup
* @{
* @addtogroup
* @{
* @brief
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_OSGQTQUICK_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 *hookNode() const = 0;
virtual void update() = 0;
};
} // namespace osgQtQuick
#endif // _H_OSGQTQUICK_DIRTYSUPPORT_H_

View File

@ -100,9 +100,7 @@ public:
qDebug() << "OSGCamera::updateClearColor - invalid camera";
return;
}
qDebug() << "OSGCamera::updateClearColor" << clearColor;
// qDebug() << "OSGCamera::updateClearColor" << clearColor;
camera->setClearColor(osg::Vec4(clearColor.redF(), clearColor.greenF(), clearColor.blueF(), clearColor.alphaF()));
}
@ -145,11 +143,12 @@ public:
void updateLogDepthBuffer()
{
qDebug() << "OSGCamera::updateLogDepthBuffer" << logDepthBufferEnabled;
if (!camera.valid()) {
qWarning() << "OSGCamera::updateLogDepthBuffer - invalid camera";
return;
}
// qDebug() << "OSGCamera::updateLogDepthBuffer" << logDepthBufferEnabled;
#ifdef USE_OSGEARTH
// install log depth buffer if requested
if (logDepthBufferEnabled && !logDepthBuffer) {

View File

@ -144,7 +144,7 @@ public:
void updatePosition()
{
qDebug() << "OSGGeoTransformNode::updatePosition" << position;
// qDebug() << "OSGGeoTransformNode::updatePosition" << position;
osgEarth::MapNode *mapNode = NULL;
if (sceneNode && sceneNode->node()) {

View File

@ -27,27 +27,16 @@
#include "OSGNode.hpp"
#include "DirtySupport.hpp"
#include <osg/Node>
#include <osg/NodeVisitor>
#include <QDebug>
namespace osgQtQuick {
class OSGNode;
class Hidden;
struct OSGNode::NodeUpdateCallback : public osg::NodeCallback {
public:
NodeUpdateCallback(OSGNode::Hidden *h) : h(h)
{}
void operator()(osg::Node *node, osg::NodeVisitor *nv);
private:
OSGNode::Hidden *const h;
};
struct OSGNode::Hidden : public QObject {
struct OSGNode::Hidden : public QObject, public DirtySupport {
Q_OBJECT
friend class OSGNode;
@ -57,48 +46,20 @@ private:
osg::ref_ptr<osg::Node> node;
osg::ref_ptr<osg::NodeCallback> nodeUpdateCallback;
bool complete;
int dirty;
public:
Hidden(OSGNode *self) : QObject(self), self(self), complete(false), dirty(0)
Hidden(OSGNode *self) : QObject(self), self(self), complete(false) /*, dirty(0)*/
{}
bool isDirty(int mask) const
osg::Node *hookNode() const
{
return (dirty & mask) != 0;
}
void setDirty(int mask)
{
if (!dirty) {
if (node) {
if (!nodeUpdateCallback.valid()) {
// lazy creation
nodeUpdateCallback = new NodeUpdateCallback(this);
}
node->addUpdateCallback(nodeUpdateCallback.get());
}
}
dirty |= mask;
}
void clearDirty()
{
if (node && nodeUpdateCallback.valid()) {
node->removeUpdateCallback(nodeUpdateCallback.get());
}
dirty = 0;
return self->node();
}
void update()
{
if (dirty) {
self->update();
}
clearDirty();
return self->update();
}
bool acceptNode(osg::Node *aNode)
@ -106,32 +67,21 @@ public:
if (node == aNode) {
return false;
}
if (node && dirty) {
node->setUpdateCallback(NULL);
int flags = dirty();
if (flags) {
clearDirty();
}
node = aNode;
if (node) {
if (dirty) {
if (!nodeUpdateCallback.valid()) {
// lazy creation
nodeUpdateCallback = new NodeUpdateCallback(this);
}
node->setUpdateCallback(nodeUpdateCallback);
if (flags) {
setDirty(flags);
}
}
return true;
}
};
/* struct OSGNode::NodeUpdateCallback */
void OSGNode::NodeUpdateCallback::operator()(osg::Node *node, osg::NodeVisitor *nv)
{
// qDebug() << "OSGNode::NodeUpdateCallback";
nv->traverse(*node);
h->update();
}
/* class OSGNode */
OSGNode::OSGNode(QObject *parent) : QObject(parent), QQmlParserStatus(), h(new Hidden(this))
@ -154,11 +104,6 @@ void OSGNode::setNode(osg::Node *node)
}
}
bool OSGNode::isDirty() const
{
return h->isDirty(0xFFFFFFFF);
}
bool OSGNode::isDirty(int mask) const
{
return h->isDirty(mask);

View File

@ -40,7 +40,6 @@
* - node change events should be handled right away.
*
* Setting an OSGNode dirty will trigger the addition of a one time update callback.
* *
* This approach leads to some potential issues:
* - if a child sets a parent dirty, the parent will be updated later on the next update traversal (i.e. before the next frame).
*
@ -55,9 +54,6 @@ class OSGQTQUICK_EXPORT OSGNode : public QObject, public QQmlParserStatus {
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
friend class OSGViewport;
friend class NodeUpdateCallback;
public:
explicit OSGNode(QObject *parent = 0);
virtual ~OSGNode();
@ -66,9 +62,8 @@ public:
void setNode(osg::Node *node);
protected:
bool isDirty() const;
bool isDirty(int mask) const;
void setDirty(int mask);
bool isDirty(int mask = 0xFFFF) const;
void setDirty(int mask = 0xFFFF);
void clearDirty();
void classBegin();
@ -83,7 +78,6 @@ signals:
private:
struct Hidden;
struct NodeUpdateCallback;
Hidden *const h;
virtual void update();

View File

@ -102,7 +102,7 @@ public:
void updateScale()
{
qDebug() << "OSGTransformNode::updateScale" << scale;
// qDebug() << "OSGTransformNode::updateScale" << scale;
if ((scale.x() != 0.0) || (scale.y() != 0.0) || (scale.z() != 0.0)) {
transform->setScale(osg::Vec3d(scale.x(), scale.y(), scale.z()));
// transform->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);

View File

@ -72,7 +72,30 @@
which will separate the clip plane calculations of the helicopter from those of the earth. *
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 };
@ -93,7 +116,6 @@ private:
osg::ref_ptr<osg::GraphicsContext> gc;
public:
OSGNode *sceneNode;
OSGCamera *cameraNode;
@ -483,12 +505,12 @@ public:
osg::Viewport *viewport = h->view->getCamera()->getViewport();
if ((viewport->width() != item->width()) || (viewport->height() != item->height())) {
qDebug() << "*** RESIZE" << frameCount << viewport->width() << "x" << viewport->height() << "->" << item->width() << "x" << item->height();
// qDebug() << "*** RESIZE" << frameCount << viewport->width() << "x" << viewport->height() << "->" << item->width() << "x" << item->height();
needToDoFrame = true;
// h->view->getCamera()->resize(item->width(), item->height());
int dpr = h->self->window()->devicePixelRatio();
h->view->getCamera()->getGraphicsContext()->resized(0, 0, item->width() * dpr, item->height() * dpr);
// h->view.get()->getEventQueue()->windowResize(0, 0, item->width() * dpr, item->height() * dpr);
// trick to force a "home" on first few frames to absorb initial spurious resizes
if (frameCount <= 2) {
@ -498,16 +520,11 @@ public:
// refresh busy state
h->self->setBusy(h->view->getDatabasePager()->getRequestsInProgress());
// TODO also expose request list size to Qml
if (h->view->getDatabasePager()->getFileRequestListSize() > 0) {
// qDebug() << h->view->getDatabasePager()->getFileRequestListSize();
}
h->self->setBusy(h->view->getDatabasePager()->getRequestsInProgress());
// TODO also expose request list size to Qml
// qDebug() << h->view->getDatabasePager()->getFileRequestListSize();
if (!needToDoFrame) {
needToDoFrame = h->viewer->checkNeedToDoFrame();
}
@ -520,31 +537,12 @@ public:
}
if (needToDoFrame) {
// qDebug() << "ViewportRenderer::synchronize - update scene" << frameCount;
// info();
h->viewer->advance();
h->viewer->eventTraversal();
h->viewer->updateTraversal();
}
}
void info()
{
if (!h->view.valid()) {
return;
}
// If the database pager is going to update the scene the render flag is
// set so that the updates show up
qDebug() << "DatabasePager" << (h->view->getDatabasePager()->requiresUpdateSceneGraph() || h->view->getDatabasePager()->getRequestsInProgress());
// if there update callbacks then we need to do frame.
qDebug() << "Camera" << (h->view->getCamera()->getUpdateCallback());
qDebug() << "Scene" << (h->view->getSceneData() && h->view->getSceneData()->getNumChildrenRequiringUpdateTraversal() > 0);
// check if events are available and need processing
qDebug() << "Events" << (h->viewer->checkEvents());
}
// This function is called when the FBO should be rendered into.
// The framebuffer is bound at this point and the glViewport has been set up to match the FBO size.
void render()
@ -581,34 +579,7 @@ public:
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
// format.setSamples(4);
/**
* that's a typical error when working with high-resolution (retina)
displays. The issue here is that on the high-resolution devices, the UI
operates with a virtual pixel size that is smaller than the real number
of pixels on the device. For example, you get coordinates from 0 to 2048
while the real device resolution if 4096 pixels. This factor has to be
taken into account when mapping from window coordinates to OpenGL, e.g.,
when calling glViewport.
How you can get this factor depends on the GUI library you are using. In
Qt, you can query it with QWindow::devicePixelRatio():
http://doc.qt.io/qt-5/qwindow.html#devicePixelRatio
So, there should be something like
glViewport(0, 0, window->width() * window->devicePixelRatio(),
window->height() * window->devicePixelRatio()).
Also keep in mind that you have to do the same e.g. for mouse coordinates.
I think osgQt already handles this correctly, so you shouldn't have to
worry about this if you use the classes provided by osgQt ...
*/
// Keeping this for reference :
// Mac need(ed) to have devicePixelRatio (dpr) taken into account (i.e. dpr = 2).
// Further tests on Mac have shown that although dpr is still 2 it should not be used to scale the fbo.
// Note that getting the window to get the devicePixelRatio is not great (messing with windows is often a bad idea...)
int dpr = 1; // h->self->window()->devicePixelRatio();
QOpenGLFramebufferObject *fbo = new QOpenGLFramebufferObject(size.width() / dpr, size.height() / dpr, format);
QOpenGLFramebufferObject *fbo = new QOpenGLFramebufferObject(size.width(), size.height(), format);
return fbo;
}
@ -731,7 +702,7 @@ QSGNode *OSGViewport::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNode
{
// qDebug() << "OSGViewport::updatePaintNode";
if (!node) {
qDebug() << "OSGViewport::updatePaintNode - set transform";
// qDebug() << "OSGViewport::updatePaintNode - set transform";
node = QQuickFramebufferObject::updatePaintNode(node, nodeData);
QSGSimpleTextureNode *n = static_cast<QSGSimpleTextureNode *>(node);
return node;

View File

@ -57,9 +57,9 @@ class OSGQTQUICK_EXPORT OSGViewport : public QQuickFramebufferObject {
Q_PROPERTY(osgQtQuick::UpdateMode::Enum updateMode READ updateMode WRITE setUpdateMode NOTIFY updateModeChanged)
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
public:
friend class ViewportRenderer;
public:
explicit OSGViewport(QQuickItem *parent = 0);
virtual ~OSGViewport();

View File

@ -27,6 +27,7 @@
#include "OSGCameraManipulator.hpp"
#include "../DirtySupport.hpp"
#include "../OSGNode.hpp"
#include <osgGA/CameraManipulator>
@ -34,11 +35,13 @@
#include <QDebug>
namespace osgQtQuick {
struct OSGCameraManipulator::Hidden : public QObject {
struct OSGCameraManipulator::Hidden : public QObject, public DirtySupport {
Q_OBJECT
friend class OSGCameraManipulator;
private:
OSGCameraManipulator * const self;
OSGCameraManipulator *const self;
public:
osg::ref_ptr<osgGA::CameraManipulator> manipulator;
@ -52,6 +55,16 @@ public:
~Hidden()
{}
osg::Node *hookNode() const
{
return manipulator->getNode();
}
void update()
{
return self->update();
}
bool acceptSceneNode(OSGNode *node)
{
qDebug() << "OSGCameraManipulator::acceptSceneNode" << node;
@ -113,6 +126,21 @@ void OSGCameraManipulator::setSceneNode(OSGNode *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;
@ -138,6 +166,9 @@ osgGA::CameraManipulator *OSGCameraManipulator::asCameraManipulator() const
{
return h->manipulator;
}
void OSGCameraManipulator::update()
{}
} // namespace osgQtQuick
#include "OSGCameraManipulator.moc"

View File

@ -59,6 +59,10 @@ signals:
void sceneNodeChanged(OSGNode *node);
protected:
bool isDirty(int mask = 0xFFFF) const;
void setDirty(int mask = 0xFFFF);
void clearDirty();
void classBegin();
void componentComplete();
@ -68,6 +72,8 @@ protected:
private:
struct Hidden;
Hidden *const h;
virtual void update();
};
} // namespace osgQtQuick

View File

@ -32,7 +32,6 @@
#include <osg/Matrix>
#include <osg/Node>
#include <osg/NodeVisitor>
#include <osg/Vec3d>
#include <osgGA/CameraManipulator>
@ -96,30 +95,15 @@ private:
osg::ref_ptr<osg::Node> node;
};
struct OSGGeoTransformManipulator::NodeUpdateCallback : public osg::NodeCallback {
public:
NodeUpdateCallback(OSGGeoTransformManipulator::Hidden *h) : h(h)
{}
void operator()(osg::Node *node, osg::NodeVisitor *nv);
private:
OSGGeoTransformManipulator::Hidden *const h;
};
struct OSGGeoTransformManipulator::Hidden : public QObject {
Q_OBJECT
private:
OSGGeoTransformManipulator * const self;
osg::ref_ptr<osg::NodeCallback> nodeUpdateCallback;
osg::Matrix cameraPosition;
osg::Matrix cameraRotation;
bool dirty;
public:
osg::ref_ptr<MyManipulator> manipulator;
@ -129,7 +113,7 @@ public:
bool clampToTerrain;
bool intoTerrain;
Hidden(OSGGeoTransformManipulator *self) : QObject(self), self(self), dirty(false), clampToTerrain(false), intoTerrain(false)
Hidden(OSGGeoTransformManipulator *self) : QObject(self), self(self), clampToTerrain(false), intoTerrain(false)
{
manipulator = new MyManipulator();
self->setManipulator(manipulator);
@ -138,45 +122,6 @@ public:
~Hidden()
{}
// TODO factorize up
void setDirty()
{
if (dirty) {
return;
}
// qDebug() << "OSGGeoTransformManipulator::setDirty";
dirty = true;
osg::Node *node = manipulator->getNode();
if (node) {
if (!nodeUpdateCallback.valid()) {
// lazy creation
nodeUpdateCallback = new NodeUpdateCallback(this);
}
node->addUpdateCallback(nodeUpdateCallback.get());
} else {
qWarning() << "OSGGeoTransformManipulator::setDirty - no node...";
}
}
// TODO factorize up
void clearDirty()
{
// qDebug() << "OSGGeoTransformManipulator::clearDirty";
osg::Node *node = manipulator->getNode();
if (node && nodeUpdateCallback.valid()) {
node->removeUpdateCallback(nodeUpdateCallback.get());
}
dirty = false;
}
void update()
{
updatePosition();
updateAttitude();
updateManipulator();
}
void updateManipulator()
{
// qDebug() << "OSGGeoTransformManipulator::updateManipulator";
@ -256,16 +201,6 @@ void MyManipulator::updateCamera(osg::Camera & camera)
CameraManipulator::updateCamera(camera);
}
/* struct OSGGeoTransformManipulator::NodeUpdateCallback */
void OSGGeoTransformManipulator::NodeUpdateCallback::operator()(osg::Node *node, osg::NodeVisitor *nv)
{
// qDebug() << "OSGGeoTransformManipulator::NodeUpdateCallback";
nv->traverse(*node);
h->update();
h->clearDirty();
}
/* class OSGGeoTransformManipulator */
OSGGeoTransformManipulator::OSGGeoTransformManipulator(QObject *parent) : OSGCameraManipulator(parent), h(new Hidden(this))
@ -304,7 +239,7 @@ void OSGGeoTransformManipulator::setAttitude(QVector3D arg)
{
if (h->attitude != arg) {
h->attitude = arg;
h->setDirty();
setDirty();
emit attitudeChanged(attitude());
}
}
@ -318,7 +253,7 @@ void OSGGeoTransformManipulator::setPosition(QVector3D arg)
{
if (h->position != arg) {
h->position = arg;
h->setDirty();
setDirty();
emit positionChanged(position());
}
}
@ -329,8 +264,15 @@ void OSGGeoTransformManipulator::componentComplete()
OSGCameraManipulator::componentComplete();
qDebug() << "OSGGeoTransformManipulator::componentComplete" << this;
h->update();
h->clearDirty();
update();
clearDirty();
}
void OSGGeoTransformManipulator::update()
{
h->updatePosition();
h->updateAttitude();
h->updateManipulator();
}
} // namespace osgQtQuick

View File

@ -41,9 +41,6 @@ class OSGQTQUICK_EXPORT OSGGeoTransformManipulator : public OSGCameraManipulator
Q_PROPERTY(bool clampToTerrain READ clampToTerrain WRITE setClampToTerrain NOTIFY clampToTerrainChanged)
Q_PROPERTY(bool intoTerrain READ intoTerrain NOTIFY intoTerrainChanged)
friend class NodeUpdateCallback;
friend class MyManipulator;
public:
explicit OSGGeoTransformManipulator(QObject *parent = 0);
virtual ~OSGGeoTransformManipulator();
@ -70,8 +67,9 @@ protected:
private:
struct Hidden;
struct NodeUpdateCallback;
Hidden *const h;
virtual void update();
};
} // namespace osgQtQuick

View File

@ -48,6 +48,7 @@ SOURCES += \
HEADERS += \
osgQtQuick/Export.hpp \
osgQtQuick/DirtySupport.hpp \
osgQtQuick/OSGNode.hpp \
osgQtQuick/OSGGroup.hpp \
osgQtQuick/OSGTransformNode.hpp \
@ -59,6 +60,7 @@ HEADERS += \
osgQtQuick/OSGViewport.hpp
SOURCES += \
osgQtQuick/DirtySupport.cpp \
osgQtQuick/OSGNode.cpp \
osgQtQuick/OSGGroup.cpp \
osgQtQuick/OSGTransformNode.cpp \