/* -*-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(static_cast(b?1:0)); } 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!=0); } 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; }; //////////////////////////////////////////////////////////////////////////////////////////////////////////// // // ClassInterface class provides a generic mechanism for get/setting class properties using the osgDB serializers // ClassInterface::ClassInterface(): _outputStream(0), _inputStream(0) { _poi = new PropertyOutputIterator; _outputStream.setOutputIterator(_poi); _pii = new PropertyInputIterator; _inputStream.setInputIterator(_pii); // initialize the type maps #define TYPENAME(A) \ _typeToTypeNameMap[osgDB::BaseSerializer::RW_##A] = #A; \ _typeNameToTypeMap[#A] = osgDB::BaseSerializer::RW_##A; TYPENAME(UNDEFINED) TYPENAME(USER) TYPENAME(OBJECT) TYPENAME(IMAGE) TYPENAME(LIST) TYPENAME(BOOL) TYPENAME(CHAR) TYPENAME(UCHAR) TYPENAME(SHORT) TYPENAME(USHORT) TYPENAME(INT) TYPENAME(UINT) TYPENAME(FLOAT) TYPENAME(DOUBLE) TYPENAME(VEC2F) TYPENAME(VEC2D) TYPENAME(VEC3F) TYPENAME(VEC3D) TYPENAME(VEC4F) TYPENAME(VEC4D) TYPENAME(QUAT) TYPENAME(PLANE) TYPENAME(MATRIXF) TYPENAME(MATRIXD) TYPENAME(MATRIX) TYPENAME(BOUNDINGBOXF) TYPENAME(BOUNDINGBOXD) TYPENAME(BOUNDINGSPHEREF) TYPENAME(BOUNDINGSPHERED) TYPENAME(GLENUM) TYPENAME(STRING) TYPENAME(ENUM) TYPENAME(VEC2B) TYPENAME(VEC2UB) TYPENAME(VEC2S) TYPENAME(VEC2US) TYPENAME(VEC2I) TYPENAME(VEC2UI) TYPENAME(VEC3B) TYPENAME(VEC3UB) TYPENAME(VEC3S) TYPENAME(VEC3US) TYPENAME(VEC3I) TYPENAME(VEC3UI) TYPENAME(VEC4B) TYPENAME(VEC4UB) TYPENAME(VEC4S) TYPENAME(VEC4US) TYPENAME(VEC4I) TYPENAME(VEC4UI) TYPENAME(LIST) TYPENAME(VECTOR) TYPENAME(MAP) } bool ClassInterface::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; if (lhs==osgDB::BaseSerializer::RW_IMAGE) lhs = osgDB::BaseSerializer::RW_OBJECT; return lhs==rhs; } std::string ClassInterface::getTypeName(osgDB::BaseSerializer::Type type) const { TypeToTypeNameMap::const_iterator itr = _typeToTypeNameMap.find(type); if (itr != _typeToTypeNameMap.end()) return itr->second; else return std::string(); } osgDB::BaseSerializer::Type ClassInterface::getType(const std::string& typeName) const { TypeNameToTypeMap::const_iterator itr = _typeNameToTypeMap.find(typeName); if (itr != _typeNameToTypeMap.end()) return itr->second; else return osgDB::BaseSerializer::RW_UNDEFINED; } osgDB::ObjectWrapper* ClassInterface::getObjectWrapper(const osg::Object* object) const { return osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper(object->getCompoundClassName()); } osgDB::BaseSerializer* ClassInterface::getSerializer(const osg::Object* object, const std::string& propertyName, osgDB::BaseSerializer::Type& type) const { osgDB::ObjectWrapper* ow = getObjectWrapper(object); return (ow!=0) ? ow->getSerializer(propertyName, type) : 0; } osg::Object* ClassInterface::createObject(const std::string& compoundClassName) const { osgDB::ObjectWrapper* ow = osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper(compoundClassName); if (ow) { osg::Object* object = ow->createInstance(); // OSG_NOTICE<<"ClassInterface::createObject("<createInstance() : 0; } bool ClassInterface::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) return false; if (!areTypesCompatible(sourceType, valueType)) { OSG_NOTICE<<"ClassInterface::copyPropertyDataFromObject() Types are not compatible, valueType = "<(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) { if (areTypesCompatible(valueType, destinationType)) { return serializer->read(_inputStream, *object); } else { OSG_NOTICE<<"ClassInterface::copyPropertyDataToObject() Types are not compatible, valueType = "<get(*object, valuePtr); } else { OSG_NOTICE<<"ClassInterface::copyPropertyObjectFromObject() Types are not compatible, valueType = "<set(*object, const_cast(valuePtr)); } else { OSG_NOTICE<<"ClassInterface::copyPropertyObjectToObject() Types are not compatible, valueType = "<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; } bool ClassInterface::getSupportedProperties(const osg::Object* object, PropertyMap& properties, bool searchAssociates) const { osgDB::ObjectWrapper* ow = getObjectWrapper(object); if (!ow) { return false; } std::string compoundClassName = object->getCompoundClassName(); ObjectPropertyMap::const_iterator wl_itr = _whiteList.find(compoundClassName); if (wl_itr != _whiteList.end()) { properties = wl_itr->second; } ObjectPropertyMap::const_iterator bl_itr = _blackList.find(compoundClassName); 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) { const std::string& propertyName = (*sitr)->getName(); bool notBlackListed = (bl_itr == _blackList.end()) || (bl_itr->second.count(propertyName)==0); if (notBlackListed) properties[propertyName] = 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, ++i) { const std::string& propertyName = (*itr)->getName(); bool notBlackListed = (bl_itr == _blackList.end()) || (bl_itr->second.count(propertyName)==0); if (notBlackListed) properties[propertyName] = ow->getTypeList()[i]; } } return true; } bool ClassInterface::isObjectOfType(const osg::Object* object, const std::string& compoundClassName) const { if (!object) return false; if (object->getCompoundClassName()==compoundClassName) return true; osgDB::ObjectWrapper* ow = getObjectWrapper(object); if (!ow) { return false; } const osgDB::StringList& associates = ow->getAssociates(); for(osgDB::StringList::const_iterator aitr = associates.begin(); aitr != associates.end(); ++aitr) { if ((*aitr)==compoundClassName) return true; } return false; } bool ClassInterface::run(void* objectPtr, const std::string& compoundClassName, const std::string& methodName, osg::Parameters& inputParameters, osg::Parameters& outputParameters) const { ObjectWrapper* ow = osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper(compoundClassName); if (!ow) return false; const ObjectWrapper::MethodObjectMap& methodObjectMap = ow->getMethodObjectMap(); ObjectWrapper::MethodObjectMap::const_iterator itr = methodObjectMap.find(methodName); while ((itr!=methodObjectMap.end()) && (itr->first==methodName)) { MethodObject* mo = itr->second.get(); if (mo->run(objectPtr, inputParameters, outputParameters)) return true; ++itr; } const osgDB::StringList& associates = ow->getAssociates(); for(osgDB::StringList::const_iterator aitr = associates.begin(); aitr != associates.end(); ++aitr) { osgDB::ObjectWrapper* aow = osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper(*aitr); if (aow) { const ObjectWrapper::MethodObjectMap& methodObjectMap = aow->getMethodObjectMap(); ObjectWrapper::MethodObjectMap::const_iterator itr = methodObjectMap.find(methodName); while ((itr!=methodObjectMap.end()) && (itr->first==methodName)) { MethodObject* mo = itr->second.get(); if (mo->run(objectPtr, inputParameters, outputParameters)) return true; ++itr; } } } return false; } bool ClassInterface::run(osg::Object* object, const std::string& methodName, osg::Parameters& inputParameters, osg::Parameters& outputParameters) const { return run(object, object->getCompoundClassName(), methodName, inputParameters, outputParameters); } bool ClassInterface::hasMethod(const std::string& compoundClassName, const std::string& methodName) const { ObjectWrapper* ow = osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper(compoundClassName); if (!ow) return false; const ObjectWrapper::MethodObjectMap& methodObjectMap = ow->getMethodObjectMap(); ObjectWrapper::MethodObjectMap::const_iterator itr = methodObjectMap.find(methodName); if (itr!=methodObjectMap.end()) return true; const osgDB::StringList& associates = ow->getAssociates(); for(osgDB::StringList::const_iterator aitr = associates.begin(); aitr != associates.end(); ++aitr) { osgDB::ObjectWrapper* aow = osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper(*aitr); if (aow) { const ObjectWrapper::MethodObjectMap& methodObjectMap = aow->getMethodObjectMap(); ObjectWrapper::MethodObjectMap::const_iterator itr = methodObjectMap.find(methodName); if (itr!=methodObjectMap.end()) return true; } } return false; } bool ClassInterface::hasMethod(const osg::Object* object, const std::string& methodName) const { return hasMethod(object->getCompoundClassName(), methodName); } } // end of osgDB namespace