From 4a567d99543d956986d1eb288eb41e6179918109 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 15 Feb 2010 20:14:32 +0000 Subject: [PATCH] Introduced new osg::ObserverNodePath class that robustly manages a NodePath in a thread safe manner, making it easier for users to track a NodePath even when nodes in the path get deleted. --- include/osg/ObserverNodePath | 73 ++++++++++++++++ src/osg/CMakeLists.txt | 3 + src/osg/ObserverNodePath.cpp | 157 +++++++++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+) create mode 100644 include/osg/ObserverNodePath create mode 100644 src/osg/ObserverNodePath.cpp diff --git a/include/osg/ObserverNodePath b/include/osg/ObserverNodePath new file mode 100644 index 000000000..ee7d27caf --- /dev/null +++ b/include/osg/ObserverNodePath @@ -0,0 +1,73 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library 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 + * OpenSceneGraph Public License for more details. +*/ + +#ifndef OSG_OBSERVERNODEPATH +#define OSG_OBSERVERNODEPATH 1 + +#include +#include +#include +#include + +namespace osg { + +typedef std::list< osg::ref_ptr > RefNodePath; + +/** ObserverNodePath is an observer class for tracking changes to a NodePath, + * that automatically invalidates it when nodes are deleted.*/ +class OSG_EXPORT ObserverNodePath : public osg::Observer +{ + public: + ObserverNodePath(); + + ObserverNodePath(const ObserverNodePath& rhs); + + ObserverNodePath(const osg::NodePath& nodePath); + + ~ObserverNodePath(); + + ObserverNodePath& operator = (const ObserverNodePath& rhs); + + bool valid() const { return _valid; } + + void setNodePath(const osg::RefNodePath& nodePath); + + void setNodePath(const osg::NodePath& nodePath); + + void clearNodePath(); + + /** Get a thread safe RefNodePath.*/ + bool getRefNodePath(RefNodePath& refNodePath) const; + + /** Get a lightweight NodePath that isn't thread safe but + * may be safely used in single threaded applications, or when + * its known that the NodePath won't be invalidated during usage + * of the NodePath.*/ + bool getNodePath(NodePath& nodePath) const; + + protected: + + void _setNodePath(const osg::NodePath& nodePath); + + void _clearNodePath(); + + virtual bool objectUnreferenced(void* ptr); + + mutable OpenThreads::Mutex _mutex; + osg::NodePath _nodePath; + bool _valid; +}; + +} + +#endif \ No newline at end of file diff --git a/src/osg/CMakeLists.txt b/src/osg/CMakeLists.txt index 68911d91b..d34d16396 100644 --- a/src/osg/CMakeLists.txt +++ b/src/osg/CMakeLists.txt @@ -111,6 +111,8 @@ SET(LIB_PUBLIC_HEADERS ${HEADER_PATH}/Notify ${HEADER_PATH}/Object ${HEADER_PATH}/observer_ptr + ${HEADER_PATH}/Observer + ${HEADER_PATH}/ObserverNodePath ${HEADER_PATH}/OccluderNode ${HEADER_PATH}/OcclusionQueryNode ${HEADER_PATH}/OperationThread @@ -274,6 +276,7 @@ ADD_LIBRARY(${LIB_NAME} NodeVisitor.cpp Notify.cpp Object.cpp + ObserverNodePath.cpp OccluderNode.cpp OcclusionQueryNode.cpp OperationThread.cpp diff --git a/src/osg/ObserverNodePath.cpp b/src/osg/ObserverNodePath.cpp new file mode 100644 index 000000000..0adf40ca5 --- /dev/null +++ b/src/osg/ObserverNodePath.cpp @@ -0,0 +1,157 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library 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 + * OpenSceneGraph Public License for more details. +*/ + +#include + +using namespace osg; + +ObserverNodePath::ObserverNodePath(): + _valid(false) +{ +} + +ObserverNodePath::ObserverNodePath(const ObserverNodePath& rhs): + _valid(false) +{ + RefNodePath refNodePath; + if (rhs.getRefNodePath(refNodePath)) + { + setNodePath(refNodePath); + } +} + +ObserverNodePath::ObserverNodePath(const osg::NodePath& nodePath): + _valid(false) +{ + setNodePath(nodePath); +} + +ObserverNodePath::~ObserverNodePath() +{ + clearNodePath(); +} + +ObserverNodePath& ObserverNodePath::operator = (const ObserverNodePath& rhs) +{ + if (&rhs==this) return *this; + + RefNodePath refNodePath; + if (rhs.getRefNodePath(refNodePath)) + { + setNodePath(refNodePath); + } + return *this; +} + +void ObserverNodePath::setNodePath(const osg::NodePath& nodePath) +{ + OpenThreads::ScopedLock lock(_mutex); + _setNodePath(nodePath); +} + +void ObserverNodePath::setNodePath(const osg::RefNodePath& refNodePath) +{ + osg::NodePath nodePath; + for(RefNodePath::const_iterator itr = refNodePath.begin(); itr != refNodePath.end(); ++itr) + { + nodePath.push_back(itr->get()); + } + setNodePath(nodePath); +} + +void ObserverNodePath::clearNodePath() +{ + OpenThreads::ScopedLock lock(_mutex); + _clearNodePath(); +} + +bool ObserverNodePath::getRefNodePath(RefNodePath& refNodePath) const +{ + refNodePath.clear(); + + OpenThreads::ScopedLock lock(_mutex); + if (!_valid) return false; + + for(osg::NodePath::const_iterator itr = _nodePath.begin(); + itr != _nodePath.end(); + ++itr) + { + refNodePath.push_back(*itr); + } + + return !refNodePath.empty(); +} + +bool ObserverNodePath::getNodePath(NodePath& nodePath) const +{ + nodePath.clear(); + + OpenThreads::ScopedLock lock(_mutex); + if (!_valid) return false; + nodePath = _nodePath; + return !nodePath.empty(); +} + +void ObserverNodePath::_setNodePath(const osg::NodePath& nodePath) +{ + if (nodePath==_nodePath) return; + + _clearNodePath(); + + _nodePath = nodePath; + + for(osg::NodePath::iterator itr = _nodePath.begin(); + itr != _nodePath.end(); + ++itr) + { + (*itr)->addObserver(this); + } + + _valid = true; +} + +void ObserverNodePath::_clearNodePath() +{ + for(osg::NodePath::iterator itr = _nodePath.begin(); + itr != _nodePath.end(); + ++itr) + { + (*itr)->removeObserver(this); + } + _nodePath.clear(); + _valid = false; +} + +bool ObserverNodePath::objectUnreferenced(void* ptr) +{ + osg::Node* node = reinterpret_cast(ptr); + + OpenThreads::ScopedLock lock(_mutex); + + _valid = false; + + for(osg::NodePath::iterator itr = _nodePath.begin(); + itr != _nodePath.end(); + ++itr) + { + if (*itr == node) + { + _nodePath.erase(itr); + + // return true as we wish calling method to remove self from observert set. + return true; + } + } + // return true as we wish calling method to remove self from observert set. + return true; +}