From 250d9f2ed7f4dbaf11b4da3a28cd5881b03692c7 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 19 Sep 2013 16:19:32 +0000 Subject: [PATCH] Introduce osgDB::PropetyInterface class that provided a generic interface for get/setting properties on scene graph objects, utilizing the osgDB serializers to do the actual interface query and set/gets. --- examples/osgpresentation/CMakeLists.txt | 3 +- examples/osgpresentation/osgpresentation.cpp | 300 +++++++++++++++- include/osgDB/ObjectWrapper | 16 +- include/osgDB/PropertyInterface | 189 ++++++++++ src/osgDB/CMakeLists.txt | 10 +- src/osgDB/InputStream.cpp | 6 +- src/osgDB/ObjectWrapper.cpp | 50 ++- src/osgDB/OutputStream.cpp | 4 +- src/osgDB/PropertyInterface.cpp | 349 +++++++++++++++++++ 9 files changed, 909 insertions(+), 18 deletions(-) create mode 100644 include/osgDB/PropertyInterface create mode 100644 src/osgDB/PropertyInterface.cpp diff --git a/examples/osgpresentation/CMakeLists.txt b/examples/osgpresentation/CMakeLists.txt index a3ad9a94d..9769050c9 100644 --- a/examples/osgpresentation/CMakeLists.txt +++ b/examples/osgpresentation/CMakeLists.txt @@ -1,4 +1,5 @@ -SET(TARGET_SRC osgpresentation.cpp ) +SET(TARGET_SRC + osgpresentation.cpp ) SET(TARGET_ADDED_LIBRARIES osgPresentation ) diff --git a/examples/osgpresentation/osgpresentation.cpp b/examples/osgpresentation/osgpresentation.cpp index bada73f49..244c04127 100644 --- a/examples/osgpresentation/osgpresentation.cpp +++ b/examples/osgpresentation/osgpresentation.cpp @@ -27,6 +27,9 @@ #include #include +#include + +#include int main(int argc, char** argv) { @@ -158,5 +161,300 @@ int main(int argc, char** argv) osgDB::writeNodeFile(*presentation, "pres.osgt"); - return viewer.run(); + + typedef std::map TypeNameMap; + TypeNameMap typeNameMap; + +#define TYPENAME(A) typeNameMap[osgDB::BaseSerializer::A] = #A; + + + TYPENAME(RW_UNDEFINED) + TYPENAME(RW_USER) + TYPENAME(RW_OBJECT) + TYPENAME(RW_IMAGE) + TYPENAME(RW_LIST) + + TYPENAME(RW_BOOL) + TYPENAME(RW_CHAR) + TYPENAME(RW_UCHAR) + TYPENAME(RW_SHORT) + TYPENAME(RW_USHORT) + TYPENAME(RW_INT) + TYPENAME(RW_UINT) + TYPENAME(RW_FLOAT) + TYPENAME(RW_DOUBLE) + + TYPENAME(RW_VEC2F) + TYPENAME(RW_VEC2D) + TYPENAME(RW_VEC3F) + TYPENAME(RW_VEC3D) + TYPENAME(RW_VEC4F) + TYPENAME(RW_VEC4D) + TYPENAME(RW_QUAT) + TYPENAME(RW_PLANE) + + TYPENAME(RW_MATRIXF) + TYPENAME(RW_MATRIXD) + TYPENAME(RW_MATRIX) + TYPENAME(RW_GLENUM) + TYPENAME(RW_STRING) + TYPENAME(RW_ENUM) + + TYPENAME(RW_VEC2B) + TYPENAME(RW_VEC2UB) + TYPENAME(RW_VEC2S) + TYPENAME(RW_VEC2US) + TYPENAME(RW_VEC2I) + TYPENAME(RW_VEC2UI) + + TYPENAME(RW_VEC3B) + TYPENAME(RW_VEC3UB) + TYPENAME(RW_VEC3S) + TYPENAME(RW_VEC3US) + TYPENAME(RW_VEC3I) + TYPENAME(RW_VEC3UI) + + TYPENAME(RW_VEC4B) + TYPENAME(RW_VEC4UB) + TYPENAME(RW_VEC4S) + TYPENAME(RW_VEC4US) + TYPENAME(RW_VEC4I) + TYPENAME(RW_VEC4UI) +#if 0 + osgDB::ObjectWrapperManager* owm = osgDB::Registry::instance()->getObjectWrapperManager(); + if (owm) + { + const osgDB::ObjectWrapperManager::WrapperMap& wrapperMap = owm->getWrapperMap(); + for(osgDB::ObjectWrapperManager::WrapperMap::const_iterator itr = wrapperMap.begin(); + itr != wrapperMap.end(); + ++itr) + { + osgDB::ObjectWrapper* ow = itr->second.get(); + + OSG_NOTICE<first<<", Domain="<getDomain()<<", Name="<getName()<getAssociates(); + for(osgDB::StringList::const_iterator aitr = associates.begin(); + aitr != associates.end(); + ++aitr) + { + OSG_NOTICE<<" associate = "<<*aitr< types; + ow->writeSchema(properties, types); + OSG_NOTICE<<" properties.size() = "<first<<"]"<second.getStringToValue(); + for(osgDB::IntLookup::StringToValue::iterator sitr = stv.begin(); + sitr != stv.end(); + ++sitr) + { + OSG_NOTICE<<" "<first<<", "<second<setName("[this is a test]"); + + osgDB::PropertyInterface pi; + if (pi.setProperty(presentation.get(), "Name", std::string("[this is new improved test]"))) + { + OSG_NOTICE<<"setProperty(presentation.get(), Name) succeeded."<setDataVariance(osg::Object::DYNAMIC); + + int variance = 1234; + if (pi.getProperty(presentation.get(), "DataVariance", variance)) + { + OSG_NOTICE<<"getProperty(presentation.get(), DataVariance) succeeded, variance = "<setMatrix(osg::Matrixd::translate(osg::Vec3d(1.0,2.0,3.0))); + +// if (pi.setProperty(presentation.get(), "Matrix", osg::Matrixd::scale(1.0,2.0,2.0))) + if (pi.setProperty(presentation.get(), "Matrix", osg::Matrixd::scale(2.0,2.0,2.0))) + { + OSG_NOTICE<<"setProperty(..,Matrix) succedded."< geometry = new osg::Geometry; + osg::ref_ptr node = new osg::Node; + osgDB::PropertyInterface::PropertyList properties; + if (pi.getSupportedProperties(presentation.get(), properties, true)) + { + OSG_NOTICE<<"Have supported properites found."<first<<", "<second<()<()<()<()<()<()<()<()<()<()<()< TypeList; typedef std::vector< osg::ref_ptr > SerializerList; typedef std::vector< osg::ref_ptr > FinishedObjectReadCallbackList; @@ -57,19 +58,28 @@ public: int getUpdatedVersion() const { return _version; } const osg::Object* getProto() const { return _proto.get(); } + const std::string& getDomain() const { return _domain; } const std::string& getName() const { return _name; } const StringList& getAssociates() const { return _associates; } + SerializerList& getSerializerList() { return _serializers; } + const SerializerList& getSerializerList() const { return _serializers; } + + TypeList& getTypeList() { return _typeList; } + const TypeList& getTypeList() const { return _typeList; } + void addSerializer( BaseSerializer* s, BaseSerializer::Type t=BaseSerializer::RW_UNDEFINED ); void markSerializerAsRemoved( const std::string& name ); BaseSerializer* getSerializer( const std::string& name ); + BaseSerializer* getSerializer( const std::string& name, BaseSerializer::Type& type); + void addFinishedObjectReadCallback ( FinishedObjectReadCallback* forc) { _finishedObjectReadCallbacks.push_back(forc); } bool read( InputStream&, osg::Object& ); bool write( OutputStream&, const osg::Object& ); - bool readSchema( const StringList& properties, const std::vector& types ); - void writeSchema( StringList& properties, std::vector& types ); + bool readSchema( const StringList& properties, const TypeList& types ); + void writeSchema( StringList& properties, TypeList& types ); void resetSchema() { if ( _backupSerializers.size()>0 ) _serializers = _backupSerializers; } @@ -83,7 +93,7 @@ protected: StringList _associates; SerializerList _serializers; SerializerList _backupSerializers; - std::vector _typeList; + TypeList _typeList; FinishedObjectReadCallbackList _finishedObjectReadCallbacks; int _version; // Last updated version of the wrapper }; diff --git a/include/osgDB/PropertyInterface b/include/osgDB/PropertyInterface new file mode 100644 index 000000000..4227c0a05 --- /dev/null +++ b/include/osgDB/PropertyInterface @@ -0,0 +1,189 @@ +/* -*-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 OSGDB_PROPERTYINTERFACE +#define OSGDB_PROPERTYINTERFACE 1 + +#include +#include +#include +#include + +namespace osgDB +{ + +template +static osgDB::BaseSerializer::Type getTypeEnum() +{ + return osgDB::BaseSerializer::RW_UNDEFINED; +} + +template +static osgDB::BaseSerializer::Type getTypeEnumFrom(T) +{ + return getTypeEnum(); +} + +template +static const char* getTypeString() +{ + return "UNDEFINED"; +} + +template +static const char* getTypeStringFrom(T) +{ + return getTypeString(); +} + +extern OSGDB_EXPORT osgDB::BaseSerializer::Type getTypeEnumFromPtr(const osg::Object*); +extern OSGDB_EXPORT const char* getTypeStringFromPtr(const osg::Object*); + +extern OSGDB_EXPORT osgDB::BaseSerializer::Type getTypeEnumFromPtr(const osg::Image*); +extern OSGDB_EXPORT const char* getTypeStringFromPtr(const osg::Image*); + + +#define DECLARE_TYPE(A,B) \ + template<> osgDB::BaseSerializer::Type getTypeEnum() { return osgDB::BaseSerializer::RW_##B; } \ + template<> const char* getTypeString() { return #B; } + +DECLARE_TYPE(osg::Image*, IMAGE) +DECLARE_TYPE(osg::Object*, OBJECT) + +DECLARE_TYPE(bool, BOOL) +DECLARE_TYPE(char, CHAR) +DECLARE_TYPE(unsigned char, UCHAR) +DECLARE_TYPE(short, SHORT) +DECLARE_TYPE(unsigned short, USHORT) +DECLARE_TYPE(int, INT) +DECLARE_TYPE(unsigned int, UINT) +DECLARE_TYPE(float, FLOAT) +DECLARE_TYPE(double, DOUBLE) + +DECLARE_TYPE(osg::Vec2f, VEC2F) +DECLARE_TYPE(osg::Vec2d, VEC2D) +DECLARE_TYPE(osg::Vec3f, VEC3F) +DECLARE_TYPE(osg::Vec3d, VEC3D) +DECLARE_TYPE(osg::Vec4f, VEC4F) +DECLARE_TYPE(osg::Vec4d, VEC4D) +DECLARE_TYPE(osg::Quat, QUAT) +DECLARE_TYPE(osg::Plane, PLANE) + +DECLARE_TYPE(osg::Matrixf, MATRIXF) +DECLARE_TYPE(osg::Matrixd, MATRIXD) +DECLARE_TYPE(std::string, STRING) + +DECLARE_TYPE(osg::Vec2b, VEC2B) +DECLARE_TYPE(osg::Vec2ub, VEC2UB) +DECLARE_TYPE(osg::Vec2s, VEC2S) +DECLARE_TYPE(osg::Vec2us, VEC2US) +DECLARE_TYPE(osg::Vec2i, VEC2I) +DECLARE_TYPE(osg::Vec2ui, VEC2UI) + +DECLARE_TYPE(osg::Vec3b, VEC3B) +DECLARE_TYPE(osg::Vec3ub, VEC3UB) +DECLARE_TYPE(osg::Vec3s, VEC3S) +DECLARE_TYPE(osg::Vec3us, VEC3US) +DECLARE_TYPE(osg::Vec3i, VEC3I) +DECLARE_TYPE(osg::Vec3ui, VEC3UI) + +DECLARE_TYPE(osg::Vec4b, VEC4B) +DECLARE_TYPE(osg::Vec4ub, VEC4UB) +DECLARE_TYPE(osg::Vec4s, VEC4S) +DECLARE_TYPE(osg::Vec4us, VEC4US) +DECLARE_TYPE(osg::Vec4i, VEC4I) +DECLARE_TYPE(osg::Vec4ui, VEC4UI) + +// forward decalare +class PropertyOutputIterator; +class PropertyInputIterator; + +class OSGDB_EXPORT PropertyInterface +{ +public: + PropertyInterface(); + + typedef std::pair PropertyNameTypePair; + typedef std::list PropertyList; + + bool getSupportedProperties(const osg::Object* object, PropertyList& properties, bool searchAssociates=true); + + bool getPropertyType(const osg::Object* object, const std::string& propertyName, osgDB::BaseSerializer::Type& type); + + bool areTypesCompatible(osgDB::BaseSerializer::Type lhs, osgDB::BaseSerializer::Type rhs) const; + + template + bool getProperty(const osg::Object* object, const std::string& propertyName, T& value); + + template + bool setProperty(osg::Object* object, const std::string& propertyName, const T& value); + +protected: + + bool copyPropertyDataFromObject(const osg::Object* object, const std::string& propertyName, void* valuePtr, unsigned int valueSize, osgDB::BaseSerializer::Type valueType); + + bool copyPropertyDataToObject(osg::Object* object, const std::string& propertyName, const void* valuePtr, unsigned int valueSize, osgDB::BaseSerializer::Type valueType); + + osgDB::ObjectWrapper* getObjectWrapper(const osg::Object* object) const + { + std::string compoundClassName = std::string(object->libraryName()) + std::string("::") + std::string(object->className()); + return osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper(compoundClassName); + } + + osgDB::BaseSerializer* getSerializer(const osg::Object* object, const std::string& propertyName, osgDB::BaseSerializer::Type& type) const + { + osgDB::ObjectWrapper* ow = getObjectWrapper(object); + return ow ? ow->getSerializer(propertyName, type) : 0; + } + + osgDB::OutputStream _outputStream; + PropertyOutputIterator* _poi; + + osgDB::InputStream _inputStream; + PropertyInputIterator* _pii; +}; + + +template +bool PropertyInterface::getProperty(const osg::Object* object, const std::string& propertyName, T& value) +{ + if (copyPropertyDataFromObject(object, propertyName, &value, sizeof(T), getTypeEnum())) + { + return true; + } + else + { + // fallback to check user data for property + return object->getUserValue(propertyName, value); + } +} + +template +bool PropertyInterface::setProperty(osg::Object* object, const std::string& propertyName, const T& value) +{ + if (copyPropertyDataToObject(object, propertyName, &value, sizeof(T), getTypeEnum())) + { + return true; + } + else + { + // fallback to using user data to store property data + object->setUserValue(propertyName, value); + return false; + } +} + +} + +#endif \ No newline at end of file diff --git a/src/osgDB/CMakeLists.txt b/src/osgDB/CMakeLists.txt index 01a1fbf12..18f2a16c7 100644 --- a/src/osgDB/CMakeLists.txt +++ b/src/osgDB/CMakeLists.txt @@ -32,7 +32,7 @@ ELSE () ADD_DEFINITIONS(-DOSG_LIBRARY_STATIC) ENDIF() -IF(APPLE AND NOT ANDROID) +IF(APPLE AND NOT ANDROID) IF(OSG_BUILD_PLATFORM_IPHONE OR OSG_BUILD_PLATFORM_IPHONE_SIMULATOR) # compile FileUtils.cpp as objective-c++ SET_SOURCE_FILES_PROPERTIES(FileUtils.cpp @@ -71,6 +71,7 @@ SET(TARGET_H ${HEADER_PATH}/Input ${HEADER_PATH}/Output ${HEADER_PATH}/Options + ${HEADER_PATH}/PropertyInterface ${HEADER_PATH}/ParameterOutput ${HEADER_PATH}/PluginQuery ${HEADER_PATH}/ReaderWriter @@ -110,6 +111,7 @@ SET(TARGET_SRC Output.cpp Options.cpp PluginQuery.cpp + PropertyInterface.cpp ReaderWriter.cpp ReadFile.cpp Registry.cpp @@ -121,12 +123,12 @@ SET(TARGET_SRC ${OPENSCENEGRAPH_VERSIONINFO_RC} ) -IF(APPLE AND NOT ANDROID) +IF(APPLE AND NOT ANDROID) IF(NOT OSG_BUILD_PLATFORM_IPHONE AND NOT OSG_BUILD_PLATFORM_IPHONE_SIMULATOR) # Needs CoreFoundation calls and a Carbon function SET(OSGDB_PLATFORM_SPECIFIC_LIBRARIES ${CARBON_LIBRARY}) ENDIF() - + IF(OSG_DEFAULT_IMAGE_PLUGIN_FOR_OSX STREQUAL "quicktime") ADD_DEFINITIONS(-DDARWIN_QUICKTIME) ELSE() @@ -163,7 +165,7 @@ ENDIF() ADD_DEFINITIONS(-DOSG_PLUGIN_EXTENSION=${CMAKE_SHARED_MODULE_SUFFIX}) -SET(TARGET_LIBRARIES +SET(TARGET_LIBRARIES osg osgUtil OpenThreads diff --git a/src/osgDB/InputStream.cpp b/src/osgDB/InputStream.cpp index c9e2ef462..efed38ec1 100644 --- a/src/osgDB/InputStream.cpp +++ b/src/osgDB/InputStream.cpp @@ -945,7 +945,7 @@ void InputStream::setWrapperSchema( const std::string& name, const std::string& } StringList schema, methods, keyAndValue; - std::vector types; + ObjectWrapper::TypeList types; split( properties, schema ); for ( StringList::iterator itr=schema.begin(); itr!=schema.end(); ++itr ) { @@ -953,12 +953,12 @@ void InputStream::setWrapperSchema( const std::string& name, const std::string& if ( keyAndValue.size()>1 ) { methods.push_back( keyAndValue.front() ); - types.push_back( atoi(keyAndValue.back().c_str()) ); + types.push_back( static_cast(atoi(keyAndValue.back().c_str())) ); } else { methods.push_back( *itr ); - types.push_back( 0 ); + types.push_back( BaseSerializer::RW_UNDEFINED ); } keyAndValue.clear(); } diff --git a/src/osgDB/ObjectWrapper.cpp b/src/osgDB/ObjectWrapper.cpp index d9a7715ed..70639b614 100644 --- a/src/osgDB/ObjectWrapper.cpp +++ b/src/osgDB/ObjectWrapper.cpp @@ -104,7 +104,7 @@ void ObjectWrapper::addSerializer( BaseSerializer* s, BaseSerializer::Type t ) { s->_firstVersion = _version; _serializers.push_back(s); - _typeList.push_back(static_cast(t)); + _typeList.push_back(t); } void ObjectWrapper::markSerializerAsRemoved( const std::string& name ) @@ -148,6 +148,48 @@ BaseSerializer* ObjectWrapper::getSerializer( const std::string& name ) return NULL; } +BaseSerializer* ObjectWrapper::getSerializer( const std::string& name, BaseSerializer::Type& type) +{ + + unsigned int i = 0; + for (SerializerList::iterator itr=_serializers.begin(); + itr!=_serializers.end(); + ++itr, ++i ) + { + if ( (*itr)->getName()==name ) + { + type = _typeList[i]; + return itr->get(); + } + } + + for ( StringList::const_iterator itr=_associates.begin(); itr!=_associates.end(); ++itr ) + { + const std::string& assocName = *itr; + ObjectWrapper* assocWrapper = Registry::instance()->getObjectWrapperManager()->findWrapper(assocName); + if ( !assocWrapper ) + { + osg::notify(osg::WARN) << "ObjectWrapper::getSerializer(): Unsupported associated class " + << assocName << std::endl; + continue; + } + + i = 0; + for ( SerializerList::iterator aitr=assocWrapper->_serializers.begin(); + aitr!=assocWrapper->_serializers.end(); + ++aitr, ++i ) + { + if ( (*aitr)->getName()==name ) + { + type = assocWrapper->_typeList[i]; + return aitr->get(); + } + } + } + type = BaseSerializer::RW_UNDEFINED; + return NULL; +} + bool ObjectWrapper::read( InputStream& is, osg::Object& obj ) { bool readOK = true; @@ -208,7 +250,7 @@ bool ObjectWrapper::write( OutputStream& os, const osg::Object& obj ) return writeOK; } -bool ObjectWrapper::readSchema( const StringList& properties, const std::vector& ) +bool ObjectWrapper::readSchema( const StringList& properties, const TypeList& ) { // FIXME: At present, I didn't do anything to determine serializers from their types... if ( !_backupSerializers.size() ) @@ -251,7 +293,7 @@ bool ObjectWrapper::readSchema( const StringList& properties, const std::vector< return size==_serializers.size(); } -void ObjectWrapper::writeSchema( StringList& properties, std::vector& types ) +void ObjectWrapper::writeSchema( StringList& properties, TypeList& types ) { for ( SerializerList::iterator itr=_serializers.begin(); itr!=_serializers.end(); ++itr ) @@ -259,7 +301,7 @@ void ObjectWrapper::writeSchema( StringList& properties, std::vector& types properties.push_back( (*itr)->getName() ); } - for ( std::vector::iterator itr=_typeList.begin(); + for ( TypeList::iterator itr=_typeList.begin(); itr!=_typeList.end(); ++itr ) { types.push_back( (*itr) ); diff --git a/src/osgDB/OutputStream.cpp b/src/osgDB/OutputStream.cpp index 93dbafa2e..a568fe969 100644 --- a/src/osgDB/OutputStream.cpp +++ b/src/osgDB/OutputStream.cpp @@ -615,7 +615,7 @@ void OutputStream::writeObjectFields( const osg::Object* obj ) if ( _inbuiltSchemaMap.find(assocName)==_inbuiltSchemaMap.end() ) { StringList properties; - std::vector types; + ObjectWrapper::TypeList types; assocWrapper->writeSchema( properties, types ); unsigned int size = osg::minimum( properties.size(), types.size() ); @@ -798,7 +798,7 @@ void OutputStream::writeSchema( std::ostream& fout ) fout << itr->first << " ="; StringList properties; - std::vector types; + ObjectWrapper::TypeList types; wrapper->writeSchema( properties, types ); std::string propertiesString; diff --git a/src/osgDB/PropertyInterface.cpp b/src/osgDB/PropertyInterface.cpp new file mode 100644 index 000000000..205306a6c --- /dev/null +++ b/src/osgDB/PropertyInterface.cpp @@ -0,0 +1,349 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2013 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 + +namespace osgDB // start of osgDB namespace +{ + +osgDB::BaseSerializer::Type getTypeEnumFromPtr(const osg::Object*) { return osgDB::BaseSerializer::RW_OBJECT; } +const char* getTypeStringFromPtr(const osg::Object*) { return "OBJECT"; } + +osgDB::BaseSerializer::Type getTypeEnumFromPtr(const osg::Image*) { return osgDB::BaseSerializer::RW_IMAGE; } +const char* getTypeStringFromPtr(const osg::Image*) { return "IMAGE"; } + +/////////////////////////////////////////////////////////////////// +// +// PropertyOutputIterator enables the get of class properties +// +class PropertyOutputIterator : public osgDB::OutputIterator +{ +public: + + PropertyOutputIterator() + { + } + + virtual ~PropertyOutputIterator() {} + + virtual bool isBinary() const { return true; } + + + template + inline void write(T t) + { + char* ptr = reinterpret_cast(&t); + _str.insert(_str.size(), ptr, sizeof(T)); + } + + virtual void writeBool( bool b ) { _str.push_back(b?0:1); } + virtual void writeChar( char c ) { _str.push_back(c); } + virtual void writeUChar( unsigned char c ) { _str.push_back(static_cast(c)); } + virtual void writeShort( short s ) { write(s); } + virtual void writeUShort( unsigned short s ) { write(s); } + virtual void writeInt( int i ) { write(i); } + virtual void writeUInt( unsigned int i ) { write(i); } + virtual void writeLong( long l ) { write(l); } + virtual void writeULong( unsigned long l ) { write(l); } + virtual void writeFloat( float f ) { write(f); } + virtual void writeDouble( double d ) { write(d); } + virtual void writeString( const std::string& s ) { _str.insert(_str.end(), s.begin(), s.end()); } + virtual void writeStream( std::ostream& (*fn)(std::ostream&) ) {} + virtual void writeBase( std::ios_base& (*fn)(std::ios_base&) ) {} + virtual void writeGLenum( const osgDB::ObjectGLenum& value ) { writeInt(value.get()); } + virtual void writeProperty( const osgDB::ObjectProperty& prop ) { _propertyName = prop._name; } + virtual void writeMark( const osgDB::ObjectMark& mark ) { _markName = mark._name; } + virtual void writeCharArray( const char* s, unsigned int size) { _str.insert(std::string::npos, s, size); } + virtual void writeWrappedString( const std::string& str ) { _str.insert(_str.end(), str.begin(), str.end()); } + + virtual void flush() + { + _str.clear(); + _propertyName.clear(); + _markName.clear(); + } + + std::string _str; + std::string _propertyName; + std::string _markName; +}; + +/////////////////////////////////////////////////////////////////// +// +// PropertyInputIterator enables the set of class properties +// +class OSGDB_EXPORT PropertyInputIterator : public osgDB::InputIterator +{ +public: + PropertyInputIterator(): + _sstream(std::stringstream::binary), + _bufferData(0), + _currentPtr(0), + _bufferSize(0) + { + setStream(&_sstream); + } + virtual ~PropertyInputIterator() + { + if (_bufferData) delete [] _bufferData; + setStream(0); + } + + virtual bool isBinary() const { return true; } + + template + void read(T& value) + { + memcpy(reinterpret_cast(&value), _currentPtr, sizeof(T)); + _currentPtr += sizeof(T); + } + + virtual void readBool( bool& b ) { char c; read(c); b = (c==1);} + virtual void readChar( char& c ) { read(c); } + virtual void readSChar( signed char& c ) { read(c); } + virtual void readUChar( unsigned char& c ) { read(c); } + virtual void readShort( short& s ) { read(s); } + virtual void readUShort( unsigned short& s ) { read(s); } + virtual void readInt( int& i ) { read(i); } + virtual void readUInt( unsigned int& i ) { read(i);} + virtual void readLong( long& l ) { read(l); } + virtual void readULong( unsigned long& l ) { read(l); } + virtual void readFloat( float& f ) { read(f); } + virtual void readDouble( double& d ) { read(d); } + virtual void readString( std::string& s ) { s = std::string(_bufferData, _bufferSize); } + + virtual void readStream( std::istream& (*fn)(std::istream&) ) {} + virtual void readBase( std::ios_base& (*fn)(std::ios_base&) ) {} + + virtual void readGLenum( ObjectGLenum& value ) { readUInt(value._value); } + virtual void readProperty( ObjectProperty& prop ) {} + virtual void readMark( ObjectMark& mark ) {} + virtual void readCharArray( char* s, unsigned int size ) { if ( size>0 ) _in->read( s, size ); } + virtual void readWrappedString( std::string& str ) { readString(str); } + + virtual bool matchString( const std::string& /*str*/ ) { return false; } + + template + void set(const T& value) + { + if (_bufferData) delete [] _bufferData; + _bufferData = new char[sizeof(T)]; + _bufferSize = sizeof(T); + _currentPtr = _bufferData; + memcpy(_bufferData, reinterpret_cast(&value), sizeof(T)); + } + + void set(const void* ptr, unsigned int valueSize) + { + if (_bufferData) delete [] _bufferData; + _bufferData = new char[valueSize]; + _currentPtr = _bufferData; + _bufferSize = valueSize; + memcpy(_bufferData, reinterpret_cast(ptr), valueSize); + } + + std::stringstream _sstream; + char* _bufferData; + char* _currentPtr; + unsigned int _bufferSize; +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// PropertyInterface class provides a generic mechanism for get/setting class properties using the osgDB serializers +// +PropertyInterface::PropertyInterface(): + _outputStream(0), + _inputStream(0) +{ + _poi = new PropertyOutputIterator; + _outputStream.setOutputIterator(_poi); + + _pii = new PropertyInputIterator; + _inputStream.setInputIterator(_pii); +} + + +bool PropertyInterface::areTypesCompatible(osgDB::BaseSerializer::Type lhs, osgDB::BaseSerializer::Type rhs) const +{ + if (lhs==rhs) return true; + +#ifdef OSG_USE_FLOAT_MATRIX + if (lhs==osgDB::BaseSerializer::RW_MATRIX) lhs = osgDB::BaseSerializer::RW_MATRIXF; + if (rhs==osgDB::BaseSerializer::RW_MATRIX) rhs = osgDB::BaseSerializer::RW_MATRIXF; +#else + if (lhs==osgDB::BaseSerializer::RW_MATRIX) lhs = osgDB::BaseSerializer::RW_MATRIXD; + if (rhs==osgDB::BaseSerializer::RW_MATRIX) rhs = osgDB::BaseSerializer::RW_MATRIXD; +#endif + + if (lhs==osgDB::BaseSerializer::RW_GLENUM) lhs = osgDB::BaseSerializer::RW_UINT; + if (rhs==osgDB::BaseSerializer::RW_GLENUM) rhs = osgDB::BaseSerializer::RW_UINT; + + if (lhs==osgDB::BaseSerializer::RW_ENUM) lhs = osgDB::BaseSerializer::RW_INT; + if (rhs==osgDB::BaseSerializer::RW_ENUM) rhs = osgDB::BaseSerializer::RW_INT; + + return lhs==rhs; +} + +bool PropertyInterface::getSupportedProperties(const osg::Object* object, PropertyList& properties, bool searchAssociates) +{ + osgDB::ObjectWrapper* ow = getObjectWrapper(object); + if (!ow) + { + return false; + } + + if (searchAssociates) + { + const osgDB::StringList& associates = ow->getAssociates(); + for(osgDB::StringList::const_iterator aitr = associates.begin(); + aitr != associates.end(); + ++aitr) + { + osgDB::ObjectWrapper* associate_wrapper = osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper(*aitr); + if (associate_wrapper) + { + const osgDB::ObjectWrapper::SerializerList& associate_serializers = associate_wrapper->getSerializerList(); + unsigned int i=0; + for(osgDB::ObjectWrapper::SerializerList::const_iterator sitr = associate_serializers.begin(); + sitr != associate_serializers.end(); + ++sitr, ++i) + { + properties.push_back(PropertyNameTypePair((*sitr)->getName(), associate_wrapper->getTypeList()[i])); + } + } + } + } + else + { + const osgDB::ObjectWrapper::SerializerList& serializers = ow->getSerializerList(); + unsigned int i=0; + for(osgDB::ObjectWrapper::SerializerList::const_iterator itr = serializers.begin(); + itr != serializers.end(); + ++itr) + { + properties.push_back(PropertyNameTypePair((*itr)->getName(), ow->getTypeList()[i])); + } + } + + + return true; +} + +bool PropertyInterface::copyPropertyDataFromObject(const osg::Object* object, const std::string& propertyName, void* valuePtr, unsigned int valueSize, osgDB::BaseSerializer::Type valueType) +{ + _poi->flush(); + + osgDB::BaseSerializer::Type sourceType; + osgDB::BaseSerializer* serializer = getSerializer(object, propertyName, sourceType); + if (serializer && areTypesCompatible(sourceType, valueType) && serializer->write(_outputStream, *object)) + { + unsigned int sourceSize = _poi->_str.size(); + + if (valueType==osgDB::BaseSerializer::RW_STRING) + { + std::string* string_ptr = reinterpret_cast(valuePtr); + (*string_ptr) = _poi->_str; + return true; + } + else if (sourceSize==valueSize) + { + memcpy(valuePtr, &(_poi->_str[0]), valueSize); + return true; + } + else + { + return false; + } + } + else return false; +} + +bool PropertyInterface::copyPropertyDataToObject(osg::Object* object, const std::string& propertyName, const void* valuePtr, unsigned int valueSize, osgDB::BaseSerializer::Type valueType) +{ + // copy data to PropertyInputIterator + if (valueType==osgDB::BaseSerializer::RW_STRING) + { + const std::string* string_ptr = reinterpret_cast(valuePtr); + _pii->set(&((*string_ptr)[0]), string_ptr->size()); + } + else + { + _pii->set(valuePtr, valueSize); + } + + osgDB::BaseSerializer::Type destinationType; + osgDB::BaseSerializer* serializer = getSerializer(object, propertyName, destinationType); + if (serializer && areTypesCompatible(valueType, destinationType)) + { + return serializer->read(_inputStream, *object); + } + else return false; +} + + +class GetPropertyType : public osg::ValueObject::GetValueVisitor +{ +public: + + GetPropertyType(): type(osgDB::BaseSerializer::RW_UNDEFINED) {} + + osgDB::BaseSerializer::Type type; + + virtual void apply(bool /*value*/) { type = osgDB::BaseSerializer::RW_BOOL; } + virtual void apply(char /*value*/) { type = osgDB::BaseSerializer::RW_CHAR; } + virtual void apply(unsigned char /*value*/) { type = osgDB::BaseSerializer::RW_UCHAR; } + virtual void apply(short /*value*/) { type = osgDB::BaseSerializer::RW_SHORT; } + virtual void apply(unsigned short /*value*/) { type = osgDB::BaseSerializer::RW_USHORT; } + virtual void apply(int /*value*/) { type = osgDB::BaseSerializer::RW_INT; } + virtual void apply(unsigned int /*value*/) { type = osgDB::BaseSerializer::RW_UINT; } + virtual void apply(float /*value*/) { type = osgDB::BaseSerializer::RW_FLOAT; } + virtual void apply(double /*value*/) { type = osgDB::BaseSerializer::RW_DOUBLE; } + virtual void apply(const std::string& /*value*/) { type = osgDB::BaseSerializer::RW_STRING; } + virtual void apply(const osg::Vec2f& /*value*/) { type = osgDB::BaseSerializer::RW_VEC2F; } + virtual void apply(const osg::Vec3f& /*value*/) { type = osgDB::BaseSerializer::RW_VEC3F; } + virtual void apply(const osg::Vec4f& /*value*/) { type = osgDB::BaseSerializer::RW_VEC4F; } + virtual void apply(const osg::Vec2d& /*value*/) { type = osgDB::BaseSerializer::RW_VEC2D; } + virtual void apply(const osg::Vec3d& /*value*/) { type = osgDB::BaseSerializer::RW_VEC3D; } + virtual void apply(const osg::Vec4d& /*value*/) { type = osgDB::BaseSerializer::RW_VEC4D; } + virtual void apply(const osg::Quat& /*value*/) { type = osgDB::BaseSerializer::RW_QUAT; } + virtual void apply(const osg::Plane& /*value*/) { type = osgDB::BaseSerializer::RW_PLANE; } + virtual void apply(const osg::Matrixf& /*value*/) { type = osgDB::BaseSerializer::RW_MATRIXF; } + virtual void apply(const osg::Matrixd& /*value*/) { type = osgDB::BaseSerializer::RW_MATRIXD; } +}; + +bool PropertyInterface::getPropertyType(const osg::Object* object, const std::string& propertyName, osgDB::BaseSerializer::Type& type) +{ + if (getSerializer(object, propertyName, type)!=0) return true; + + const osg::UserDataContainer* udc = object->getUserDataContainer(); + const osg::Object* userObject = udc ? udc->getUserObject(propertyName) : 0; + if (userObject) + { + const osg::ValueObject* valueObject = dynamic_cast(userObject); + if (valueObject) + { + GetPropertyType gpt; + valueObject->get(gpt); + type = gpt.type; + return gpt.type!=osgDB::BaseSerializer::RW_UNDEFINED; + } + } + return false; +} + +} // end of osgDB namespace + +