From c703f39459d5368ac7190a35e2ee9563bd10e8f3 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 2 Jun 2011 22:04:08 +0000 Subject: [PATCH] Introduced new user object support into osg::Object that allows assignment of a list of user objects to an osg::Object. Refactored original UserData and Descriptions strings to be managed alongside the new user object suppport within a single osg::Object::UserDataContainer. --- include/osg/CopyOp | 1 + include/osg/Node | 27 ----- include/osg/Object | 121 ++++++++++++++++++++-- include/osg/ValueObject | 199 +++++++++++++++++++++++++++++++++++ src/osg/Drawable.cpp | 3 - src/osg/Node.cpp | 6 +- src/osg/Object.cpp | 224 +++++++++++++++++++++++++++++++++++++++- 7 files changed, 535 insertions(+), 46 deletions(-) create mode 100644 include/osg/ValueObject diff --git a/include/osg/CopyOp b/include/osg/CopyOp index 7ad159b18..129225b9e 100644 --- a/include/osg/CopyOp +++ b/include/osg/CopyOp @@ -56,6 +56,7 @@ class OSG_EXPORT CopyOp DEEP_COPY_SHAPES = 1<<9, DEEP_COPY_UNIFORMS = 1<<10, DEEP_COPY_CALLBACKS = 1<<11, + DEEP_COPY_USERDATA = 1<<12, DEEP_COPY_ALL = 0x7FFFFFFF }; diff --git a/include/osg/Node b/include/osg/Node index 04ddb13a6..799c74fa3 100644 --- a/include/osg/Node +++ b/include/osg/Node @@ -304,31 +304,6 @@ class OSG_EXPORT Node : public Object - /** A vector of std::string's which are used to describe the object.*/ - typedef std::vector DescriptionList; - - /** Set the description list of the node.*/ - inline void setDescriptions(const DescriptionList& descriptions) { _descriptions=descriptions; } - - /** Get the description list of the node.*/ - inline DescriptionList& getDescriptions() { return _descriptions; } - - /** Get the const description list of the const node.*/ - inline const DescriptionList& getDescriptions() const { return _descriptions; } - - /** Get a single const description of the const node.*/ - inline const std::string& getDescription(unsigned int i) const { return _descriptions[i]; } - - /** Get a single description of the node.*/ - inline std::string& getDescription(unsigned int i) { return _descriptions[i]; } - - /** Get the number of descriptions of the node.*/ - inline unsigned int getNumDescriptions() const { return static_cast(_descriptions.size()); } - - /** Add a description string to the node.*/ - void addDescription(const std::string& desc) { _descriptions.push_back(desc); } - - /** Set the node's StateSet.*/ void setStateSet(osg::StateSet* stateset); @@ -453,8 +428,6 @@ class OSG_EXPORT Node : public Object void setNumChildrenWithOccluderNodes(unsigned int num); NodeMask _nodeMask; - - DescriptionList _descriptions; ref_ptr _stateset; diff --git a/include/osg/Object b/include/osg/Object index b1f171109..fe76d3b1a 100644 --- a/include/osg/Object +++ b/include/osg/Object @@ -20,6 +20,7 @@ #include #include +#include namespace osg { @@ -147,7 +148,10 @@ class OSG_EXPORT Object : public Referenced /** return the name of the object's class type. Must be defined by derived classes.*/ virtual const char* className() const = 0; - + + + /** Set whether to use a mutex to ensure ref() and unref() are thread safe.*/ + virtual void setThreadSafeRefUnref(bool threadSafe); /** Set the name of object using C++ style string.*/ virtual void setName( const std::string& name ) { _name = name; } @@ -190,14 +194,83 @@ class OSG_EXPORT Object : public Referenced * subclassed from Referenced then create an adapter object * which points to your own object and handles the memory addressing. */ - inline void setUserData(Referenced* obj) { _userData = obj; } - - /** Get user data.*/ - inline Referenced* getUserData() { return _userData.get(); } - - /** Get const user data.*/ - inline const Referenced* getUserData() const { return _userData.get(); } + void setUserData(Referenced* obj); + /** Get user data.*/ + Referenced* getUserData(); + + /** Get const user data.*/ + const Referenced* getUserData() const; + + + /** Add user data object.*/ + void addUserObject(Object* obj); + + /** Add element to list of user data objects.*/ + void setUserObject(unsigned int i, Object* obj); + + /** Remove element from the list of user data objects.*/ + void removeUserObject(unsigned int i); + + /** Get the index position of specified user data object.*/ + unsigned int getUserObjectIndex(const osg::Object* obj) const; + + /** Get the index position of first user data object that matches specified name.*/ + unsigned int getUserObjectIndex(const std::string& name) const; + + /** Get user data object as specified index position. */ + Object* getUserObject(unsigned int i); + + /** Get const user data object as specified index position. */ + const Object* getUserObject(unsigned int i) const; + + /** Get first user data object with specified name. */ + Object* getUserObject(const std::string& name); + + /** Get first const user data object with specified name. */ + const Object* getUserObject(const std::string& name) const; + + /** Get number of user objects assigned to this object.*/ + unsigned int getNumUserObjects() const; + + /** Convinience method that casts the named UserObject to osg::TemplateValueObject and gets the value. + * To use this template method you need to include the osg/ValueObject header.*/ + template + bool getUserValue(const std::string& name, T& value) const; + + /** Convinience method that creates the osg::TemplateValueObject to store the + * specified value and adds it as a named UserObject. + * To use this template method you need to include the osg/ValueObject header. */ + template + void setUserValue(const std::string& name, const T& value); + + + + /** A vector of std::string's which are used to describe the object.*/ + typedef std::vector DescriptionList; + + /** Set the list of string descriptions.*/ + void setDescriptions(const DescriptionList& descriptions); + + /** Get the description list of the node.*/ + DescriptionList& getDescriptions(); + + /** Get the const description list of the const node.*/ + const DescriptionList& getDescriptions() const; + + /** Get a single const description of the const node.*/ + const std::string& getDescription(unsigned int i) const; + + /** Get a single description of the node.*/ + std::string& getDescription(unsigned int i); + + /** Get the number of descriptions of the node.*/ + unsigned int getNumDescriptions() const; + + /** Add a description string to the node.*/ + void addDescription(const std::string& desc); + + /** Resize any per context GLObject buffers to specified size. */ virtual void resizeGLObjectBuffers(unsigned int /*maxSize*/) {} @@ -206,6 +279,7 @@ class OSG_EXPORT Object : public Referenced * for all graphics contexts. */ virtual void releaseGLObjects(osg::State* = 0) const {} + protected: /** Object destructor. Note, is protected so that Objects cannot @@ -219,7 +293,35 @@ class OSG_EXPORT Object : public Referenced std::string _name; DataVariance _dataVariance; - ref_ptr _userData; + + /** Internal structure for storing all user data.*/ + class OSG_EXPORT UserDataContainer : public osg::Referenced + { + public: + UserDataContainer(); + UserDataContainer(const UserDataContainer& udc, const osg::CopyOp& copyop=CopyOp::SHALLOW_COPY); + + virtual void setThreadSafeRefUnref(bool threadSafe); + + typedef std::vector< osg::ref_ptr > ObjectList; + + ref_ptr _userData; + DescriptionList _descriptionList; + ObjectList _objectList; + + protected: + virtual ~UserDataContainer() {} + }; + + ref_ptr _userDataContainer; + + /** Convinience method that returns the UserDataContainer, and if one doesn't already exist creates and assigns + * one to the Object and then return this new UserDataContainer.*/ + UserDataContainer* getOrCreateUserDataContainer() + { + if (!_userDataContainer.valid()) _userDataContainer = new UserDataContainer; + return _userDataContainer.get(); + } private: @@ -227,6 +329,7 @@ class OSG_EXPORT Object : public Referenced Object& operator = (const Object&) { return *this; } }; + } #endif diff --git a/include/osg/ValueObject b/include/osg/ValueObject new file mode 100644 index 000000000..cccb1de51 --- /dev/null +++ b/include/osg/ValueObject @@ -0,0 +1,199 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 2011 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_VALUEOBJECT +#define OSG_VALUEOBJECT 1 + +#include + +namespace osg { + +// foward declare core OSG math classes +class Vec2f; +class Vec3f; +class Vec4f; +class Vec2d; +class Vec3d; +class Vec4d; +class Quat; +class Plane; +class Matrixf; +class Matrixd; + +class ValueObject : public Object +{ + public: + + ValueObject() : Object(true) {} + ValueObject(const std::string& name) : Object(true) { setName(name); } + ValueObject(const ValueObject& rhs, const osg::CopyOp copyop=osg::CopyOp::SHALLOW_COPY): Object(rhs,copyop) {} + + META_Object(osg, ValueObject) + + class GetValueVisitor + { + public: + virtual void apply(bool value) {} + virtual void apply(char value) {} + virtual void apply(unsigned char value) {} + virtual void apply(short value) {} + virtual void apply(unsigned short value) {} + virtual void apply(int value) {} + virtual void apply(unsigned int value) {} + virtual void apply(float value) {} + virtual void apply(double value) {} + virtual void apply(const std::string& value) {} + virtual void apply(const osg::Vec2f& value) {} + virtual void apply(const osg::Vec3f& value) {} + virtual void apply(const osg::Vec4f& value) {} + virtual void apply(const osg::Vec2d& value) {} + virtual void apply(const osg::Vec3d& value) {} + virtual void apply(const osg::Vec4d& value) {} + virtual void apply(const osg::Quat& value) {} + virtual void apply(const osg::Plane& value) {} + virtual void apply(const osg::Matrixf& value) {} + virtual void apply(const osg::Matrixd& value) {} + }; + + class SetValueVisitor + { + public: + virtual void apply(bool& value) {} + virtual void apply(char& value) {} + virtual void apply(unsigned char& value) {} + virtual void apply(short& value) {} + virtual void apply(unsigned short& value) {} + virtual void apply(int& value) {} + virtual void apply(unsigned int& value) {} + virtual void apply(float& value) {} + virtual void apply(double& value) {} + virtual void apply(std::string& value) {} + virtual void apply(osg::Vec2f& value) {} + virtual void apply(osg::Vec3f& value) {} + virtual void apply(osg::Vec4f& value) {} + virtual void apply(osg::Vec2d& value) {} + virtual void apply(osg::Vec3d& value) {} + virtual void apply(osg::Vec4d& value) {} + virtual void apply(osg::Quat& value) {} + virtual void apply(osg::Plane& value) {} + virtual void apply(osg::Matrixf& value) {} + virtual void apply(osg::Matrixd& value) {} + }; + + virtual bool get(GetValueVisitor& gvv) const { return false; } + virtual bool set(SetValueVisitor& gvv) { return false; } +}; + +template< typename T > +struct ValueObjectClassNameTrait +{ + static const char* s_className; +}; + +template< typename T > +const char* ValueObjectClassNameTrait::s_className = "TemplateValueObject"; + + +template< typename T > +class TemplateValueObject : public ValueObject +{ + public: + + TemplateValueObject(): + ValueObject(), + _value() {} + + TemplateValueObject(const std::string& name, const T& value) : + ValueObject(name), + _value(value) {} + + TemplateValueObject(const TemplateValueObject& rhs, const osg::CopyOp copyop=osg::CopyOp::SHALLOW_COPY) : + ValueObject(rhs,copyop), + _value(rhs._value) {} + + virtual Object* cloneType() const { return new TemplateValueObject(); } + virtual Object* clone(const CopyOp& copyop) const { return new TemplateValueObject(*this, copyop); } + virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast(obj)!=NULL; } + virtual const char* libraryName() const { return "osg"; } + virtual const char* className() const { return ValueObjectClassNameTrait::s_className; } + + void setValue(const T& value) { _value = value; } + const T& getValue() const { return _value; } + + virtual bool get(GetValueVisitor& gvv) const { gvv.apply(_value); return true; } + virtual bool set(SetValueVisitor& svv) { svv.apply(_value); return true; } + +protected: + + static const char* s_TemplateValueObject_className; + + T _value; +}; + +#define META_ValueObject(TYPE,NAME) \ + template<> struct ValueObjectClassNameTrait { static const char* s_className; }; \ + const char* ValueObjectClassNameTrait::s_className = #NAME; \ + typedef TemplateValueObject NAME; + +META_ValueObject(std::string, StringValueObject) +META_ValueObject(bool, BoolValueObject) +META_ValueObject(char, CharValueObject) +META_ValueObject(unsigned char, UCharValueObject) +META_ValueObject(short, ShortValueObject) +META_ValueObject(unsigned short, UShortValueObject) +META_ValueObject(int, IntValueObject) +META_ValueObject(unsigned int, UIntValueObject) +META_ValueObject(float, FloatValueObject) +META_ValueObject(double, DoubleValueObject) +META_ValueObject(Vec2f, Vec2fValueObject) +META_ValueObject(Vec3f, Vec3fValueObject) +META_ValueObject(Vec4f, Vec4fValueObject) +META_ValueObject(Vec2d, Vec2dValueObject) +META_ValueObject(Vec3d, Vec3dValueObject) +META_ValueObject(Vec4d, Vec4dValueObject) +META_ValueObject(Quat, QuatValueObject) +META_ValueObject(Plane, PlaneValueObject) +META_ValueObject(Matrixf, MatrixfValueObject) +META_ValueObject(Matrixd, MatrixdValueObject) + +/** provide implementation og osg::Object::getUserValue(..) template*/ +template +bool osg::Object::getUserValue(const std::string& name, T& value) const +{ + typedef TemplateValueObject UserValueObject; + const UserValueObject* uvo = dynamic_cast(getUserObject(name)); + if (uvo) + { + value = uvo->getValue(); + return true; + } + else + { + return false; + } +} + +/** provide implementation og osg::Object::setUserValue(..) template.*/ +template +void osg::Object::setUserValue(const std::string& name, const T& value) +{ + typedef TemplateValueObject UserValueObject; + + unsigned int i = getUserObjectIndex(name); + if (isetThreadSafeRefUnref(threadSafe); - if (_updateCallback.valid()) _updateCallback->setThreadSafeRefUnref(threadSafe); if (_eventCallback.valid()) _eventCallback->setThreadSafeRefUnref(threadSafe); if (_cullCallback.valid()) _cullCallback->setThreadSafeRefUnref(threadSafe); if (_drawCallback.valid()) _drawCallback->setThreadSafeRefUnref(threadSafe); - - if (_userData.valid()) _userData->setThreadSafeRefUnref(threadSafe); } void Drawable::resizeGLObjectBuffers(unsigned int maxSize) diff --git a/src/osg/Node.cpp b/src/osg/Node.cpp index a4d3f8dac..1d1b68f0c 100644 --- a/src/osg/Node.cpp +++ b/src/osg/Node.cpp @@ -81,8 +81,7 @@ Node::Node(const Node& node,const CopyOp& copyop): _cullingActive(node._cullingActive), _numChildrenWithCullingDisabled(0), // assume no children yet. _numChildrenWithOccluderNodes(0), - _nodeMask(node._nodeMask), - _descriptions(node._descriptions) + _nodeMask(node._nodeMask) { setStateSet(copyop(node._stateset.get())); } @@ -501,12 +500,9 @@ void Node::setThreadSafeRefUnref(bool threadSafe) Object::setThreadSafeRefUnref(threadSafe); if (_stateset.valid()) _stateset->setThreadSafeRefUnref(threadSafe); - if (_updateCallback.valid()) _updateCallback->setThreadSafeRefUnref(threadSafe); if (_eventCallback.valid()) _eventCallback->setThreadSafeRefUnref(threadSafe); if (_cullCallback.valid()) _cullCallback->setThreadSafeRefUnref(threadSafe); - - if (_userData.valid()) _userData->setThreadSafeRefUnref(threadSafe); } void Node::resizeGLObjectBuffers(unsigned int maxSize) diff --git a/src/osg/Object.cpp b/src/osg/Object.cpp index 71854779c..2ff5db9dd 100644 --- a/src/osg/Object.cpp +++ b/src/osg/Object.cpp @@ -15,11 +15,231 @@ namespace osg { +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Object +// Object::Object(const Object& obj,const CopyOp& copyop): Referenced(), _name(obj._name), - _dataVariance(obj._dataVariance), - _userData(copyop(obj._userData.get())) {} + _dataVariance(obj._dataVariance) +{ + if (copyop.getCopyFlags()&osg::CopyOp::DEEP_COPY_USERDATA) + { + _userDataContainer = new UserDataContainer(*obj._userDataContainer, copyop); + } + else + { + _userDataContainer = obj._userDataContainer; + } +} + +void Object::setThreadSafeRefUnref(bool threadSafe) +{ + Referenced::setThreadSafeRefUnref(threadSafe); + if (_userDataContainer.valid()) _userDataContainer->setThreadSafeRefUnref(threadSafe); +} + +void Object::setUserData(Referenced* obj) +{ + getOrCreateUserDataContainer()->_userData = obj; +} + +Referenced* Object::getUserData() +{ + return _userDataContainer.valid() ? _userDataContainer->_userData.get() : 0; +} + +const Referenced* Object::getUserData() const +{ + return _userDataContainer.valid() ? _userDataContainer->_userData.get() : 0; +} + +void Object::addUserObject(Object* obj) +{ + // make sure the UserDataContainer exists + getOrCreateUserDataContainer(); + + // make sure that the object isn't already in the container + unsigned int i = getUserObjectIndex(obj); + if (i<_userDataContainer->_objectList.size()) + { + // object already in container so just return. + return; + } + + // object not already on user data container so add it in. + _userDataContainer->_objectList.push_back(obj); +} + +void Object::removeUserObject(unsigned int i) +{ + if (_userDataContainer.valid() && i<_userDataContainer->_objectList.size()) + { + _userDataContainer->_objectList.erase(_userDataContainer->_objectList.begin()+i); + } +} + +void Object::setUserObject(unsigned int i, Object* obj) +{ + if (_userDataContainer.valid() && i<_userDataContainer->_objectList.size()) + { + _userDataContainer->_objectList[i] = obj; + } +} + +Object* Object::getUserObject(unsigned int i) +{ + if (_userDataContainer.valid() && i<_userDataContainer->_objectList.size()) + { + return _userDataContainer->_objectList[i].get(); + } + return 0; +} + +const Object* Object::getUserObject(unsigned int i) const +{ + if (_userDataContainer.valid() && i<_userDataContainer->_objectList.size()) + { + return _userDataContainer->_objectList[i].get(); + } + return 0; +} + +unsigned int Object::getUserObjectIndex(const osg::Object* obj) const +{ + if (_userDataContainer.valid()) + { + for(unsigned int i = 0; i < _userDataContainer->_objectList.size(); ++i) + { + if (_userDataContainer->_objectList[i]==obj) return i; + } + return _userDataContainer->_objectList.size(); + } + return 0; +} + +unsigned int Object::getUserObjectIndex(const std::string& name) const +{ + if (_userDataContainer.valid()) + { + for(unsigned int i = 0; i < _userDataContainer->_objectList.size(); ++i) + { + Object* obj = _userDataContainer->_objectList[i].get(); + if (obj && obj->getName()==name) return i; + } + return _userDataContainer->_objectList.size(); + } + return 0; +} + +Object* Object::getUserObject(const std::string& name) +{ + if (_userDataContainer.valid()) + { + unsigned int i = getUserObjectIndex(name); + return (i<_userDataContainer->_objectList.size()) ? _userDataContainer->_objectList[i].get() : 0; + } + else + { + return 0; + } +} + +const Object* Object::getUserObject(const std::string& name) const +{ + if (_userDataContainer.valid()) + { + unsigned int i = getUserObjectIndex(name); + return (i<_userDataContainer->_objectList.size()) ? _userDataContainer->_objectList[i].get() : 0; + } + else + { + return 0; + } +} + +unsigned int Object::getNumUserObjects() const +{ + return _userDataContainer.valid() ? _userDataContainer->_objectList.size() : 0; +} + + +void Object::setDescriptions(const DescriptionList& descriptions) +{ + getOrCreateUserDataContainer()->_descriptionList = descriptions; +} + +Object::DescriptionList& Object::getDescriptions() +{ + return getOrCreateUserDataContainer()->_descriptionList; +} + +static OpenThreads::Mutex s_mutex_StaticDescriptionList; +static const Object::DescriptionList& getStaticDescriptionList() +{ + OpenThreads::ScopedLock lock(s_mutex_StaticDescriptionList); + static Object::DescriptionList s_descriptionList; + return s_descriptionList; +} + +const Object::DescriptionList& Object::getDescriptions() const +{ + if (_userDataContainer.valid()) return _userDataContainer->_descriptionList; + else return getStaticDescriptionList(); +} + +std::string& Object::getDescription(unsigned int i) +{ + return getOrCreateUserDataContainer()->_descriptionList[i]; +} + +const std::string& Object::getDescription(unsigned int i) const +{ + if (_userDataContainer.valid()) return _userDataContainer->_descriptionList[i]; + else return getStaticDescriptionList()[i]; +} + +unsigned int Object::getNumDescriptions() const +{ + return _userDataContainer.valid() ? _userDataContainer->_descriptionList.size() : 0; +} + +void Object::addDescription(const std::string& desc) +{ + getOrCreateUserDataContainer()->_descriptionList.push_back(desc); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// UserDataContainer +// +Object::UserDataContainer::UserDataContainer(): + Referenced(true) +{ +} + +Object::UserDataContainer::UserDataContainer(const UserDataContainer& udc, const osg::CopyOp& copyop): + Referenced(true) +{ + _userData = udc._userData; + _descriptionList = udc._descriptionList; +} + +void Object::UserDataContainer::setThreadSafeRefUnref(bool threadSafe) +{ + Referenced::setThreadSafeRefUnref(threadSafe); + + if (_userData.valid()) _userData->setThreadSafeRefUnref(threadSafe); + + for(ObjectList::iterator itr = _objectList.begin(); + itr != _objectList.end(); + ++itr) + { + (*itr)->setThreadSafeRefUnref(threadSafe); + } +} + } // end of namespace osg