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.
This commit is contained in:
Robert Osfield
2013-09-19 16:19:32 +00:00
parent f42481b60f
commit 250d9f2ed7
9 changed files with 909 additions and 18 deletions

View File

@@ -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

View File

@@ -945,7 +945,7 @@ void InputStream::setWrapperSchema( const std::string& name, const std::string&
}
StringList schema, methods, keyAndValue;
std::vector<int> 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<BaseSerializer::Type>(atoi(keyAndValue.back().c_str())) );
}
else
{
methods.push_back( *itr );
types.push_back( 0 );
types.push_back( BaseSerializer::RW_UNDEFINED );
}
keyAndValue.clear();
}

View File

@@ -104,7 +104,7 @@ void ObjectWrapper::addSerializer( BaseSerializer* s, BaseSerializer::Type t )
{
s->_firstVersion = _version;
_serializers.push_back(s);
_typeList.push_back(static_cast<int>(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<int>& )
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<int>& 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<int>& types
properties.push_back( (*itr)->getName() );
}
for ( std::vector<int>::iterator itr=_typeList.begin();
for ( TypeList::iterator itr=_typeList.begin();
itr!=_typeList.end(); ++itr )
{
types.push_back( (*itr) );

View File

@@ -615,7 +615,7 @@ void OutputStream::writeObjectFields( const osg::Object* obj )
if ( _inbuiltSchemaMap.find(assocName)==_inbuiltSchemaMap.end() )
{
StringList properties;
std::vector<int> 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<int> types;
ObjectWrapper::TypeList types;
wrapper->writeSchema( properties, types );
std::string propertiesString;

View File

@@ -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 <osgDB/PropertyInterface>
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<typename T>
inline void write(T t)
{
char* ptr = reinterpret_cast<char*>(&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<char>(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<typename T>
void read(T& value)
{
memcpy(reinterpret_cast<char*>(&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<typename T>
void set(const T& value)
{
if (_bufferData) delete [] _bufferData;
_bufferData = new char[sizeof(T)];
_bufferSize = sizeof(T);
_currentPtr = _bufferData;
memcpy(_bufferData, reinterpret_cast<const char*>(&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<const char*>(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<std::string*>(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<const std::string*>(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<const osg::ValueObject*>(userObject);
if (valueObject)
{
GetPropertyType gpt;
valueObject->get(gpt);
type = gpt.type;
return gpt.type!=osgDB::BaseSerializer::RW_UNDEFINED;
}
}
return false;
}
} // end of osgDB namespace