Hi Robert, This is great! Being able to store meta-data in any osg::Object derived class has been something we've wanted for a while now.
Regarding serialization, will your changes break loading of older models that contained node descriptions? This is a big concern for us because we have hundreds of models that contain description strings. Anyways, I'll begin playing around with these changes and report any issues I encounter. Cheers, Farshid On Tue, May 31, 2011 at 7:19 AM, Robert Osfield <[email protected]>wrote: > Hi All, > > This morning I've been experimenting with extending the user data > support in the OSG, along the lines set out by Sukender. I've tried > to keep the class count down, and keep the user interface relatively > straight forward. Implementation wise I have gone for an > osg::Object::UserDataContainer that is used an internal implementation > structure in osg::Object, and this doesn't have any public interface. > This simple nested class is defined within the osg::Object protected > scope and looks like: > > 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<osg::Object> > ObjectList; > > ref_ptr<Referenced> _userData; > DescriptionList _descriptionList; > ObjectList _objectList; > }; > > Access methods for the old UserData and Descriptions list are > maintained, with the later moved in from osg::Node to allow all > osg::Object classes access to these convinience methods. These > methods automatically create the UserDataContainer when required and > can be used in an identical was as before. > > The new element is the ObjectList vector in UserDataContainer, this > can store any object subclasses from osg::Object which can be access > either via index into the vector or by the name of the osg::Object > (i.e. Object::setName()/getName()). I have put convience methods into > osg::Object public scope to access the UserDataContainer: > > void addUserObject(Object* obj); > void setUserObject(unsigned int i, Object* obj); > void removeUserObject(unsigned int i); > > unsigned int getUserObjectIndex(const osg::Object* obj) const; > unsigned int getUserObjectIndex(const std::string& name) const; > > Object* getUserObject(unsigned int i); > const Object* getUserObject(unsigned int i) const; > > Object* getUserObject(const std::string& name); > const Object* getUserObject(const std::string& name) const; > > unsigned int getNumUserObjects() const; > > This gets us so far, but... it forces us to provide our own subclasses > of osg::Object to be able to put in our own Data, to ease the burden I > have introduced a template<typename T> ValueObject implementation that > "has a" T _value member. > > template<typename T> > class ValueObject : public osg::Object > { > public: > > ValueObject(): > Object(true), > _value() > { > } > > ValueObject(const std::string& name, T value): > Object(true), > _value(value) > { > setName(name); > } > > ValueObject(const ValueObject& rhs, const osg::CopyOp > copyop=osg::CopyOp::SHALLOW_COPY): > Object(rhs,copyop), > _value(rhs._value) > { > } > > META_Object(osg, ValueObject) > > void setValue(const T& value) { _value = value; } > const T& getValue() const { return _value; } > > protected: > > T _value; > }; > > And a couple of convinience methods in osg::Object to create/access these: > > template<typename T> > bool getUserValue(const std::string& name, T& value) const > { > typedef ValueObject<T> UserValueObject; > UserValueObject* uvo = > dynamic_cast<UserValueObject*>(getUserObject(name)); > if (uvo) > { > value = uvo->getValue(); > return true; > } > else > { > return false; > } > } > > template<typename T> > void setUserValue(const std::string& name, const T& value) > { > typedef ValueObject<T> UserValueObject; > > unsigned int i = getUserObjectIndex(name); > if (i<getNumUserObjects()) setUserObject(i, new > UserValueObject(name,value)); > else addUserObject(new UserValueObject(name,value)); > } > > > It's these methods that I'd expect the access to go through. As a > quick test I have created an osguserdata example than we can use as a > test bed for this new functionality. My current rev looks like: > > int main(int argc, char** argv) > { > osg::ref_ptr<osg::Group> node = new osg::Group; > > int i = 10; > node->setUserValue("Int value",i); > > int j = 0; > if (node->getUserValue("Int value",j)) > { > OSG_NOTICE<<"Int value="<<j<<std::endl; > } > else > { > OSG_NOTICE<<"Int value not found"<<std::endl; > } > > std::string testString("All seems fine"); > node->setUserValue("Status",testString); > > std::string readString; > if (node->getUserValue("Status",readString)) > { > OSG_NOTICE<<"Status="<<readString<<std::endl; > } > else > { > OSG_NOTICE<<"Status not found"<<std::endl; > } > > return 0; > } > > So far I'm getting the correct values, and everything compiles OK > under g++ 4.5.2, hopefully the use of template methods want cause > problems across platforms. > > I haven't yet tackled the IO side. I'm hoping that providing wrappers > for a ValueObject<int>, ValueObject<unsigned int>, ValueObject<float>, > ValueObject<string> etc. will be sufficient. This will be my next > experiment. > > I am a little nervous about the potential for build and runtime > breakage so will post to the list a warning that I'm about to check > these changes in. I have attached my versions of include/osg/Object > and src/osg/Object.cpp for those keep to review the changes. > > Let me know what you think, > Robert. > > _______________________________________________ > osg-users mailing list > [email protected] > http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org > >
_______________________________________________ osg-users mailing list [email protected] http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

