From d9a133476a6471d9542a6b294376a4912d39fe0a Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 23 Sep 2010 16:12:05 +0000 Subject: [PATCH] Refactored the handling of readImage/writeImage/readObject/writeObject to avoid double setting of unique ID's, fixing the problem in reading/writing files with images --- include/osgDB/InputStream | 1 + include/osgDB/OutputStream | 5 +- src/osgDB/InputStream.cpp | 43 ++++-- src/osgDB/OutputStream.cpp | 297 ++++++++++++++++++++----------------- 4 files changed, 194 insertions(+), 152 deletions(-) diff --git a/include/osgDB/InputStream b/include/osgDB/InputStream index 5c1ab61f4..749c98473 100644 --- a/include/osgDB/InputStream +++ b/include/osgDB/InputStream @@ -137,6 +137,7 @@ public: osg::PrimitiveSet* readPrimitiveSet(); osg::Image* readImage(); osg::Object* readObject( osg::Object* existingObj=0 ); + osg::Object* readObjectFields( const std::string& className, osg::Object* existingObj=0); ReadType start( InputIterator* ); void decompress(); diff --git a/include/osgDB/OutputStream b/include/osgDB/OutputStream index d18506c6c..4a3681e5f 100644 --- a/include/osgDB/OutputStream +++ b/include/osgDB/OutputStream @@ -146,6 +146,7 @@ public: void writePrimitiveSet( const osg::PrimitiveSet* p ); void writeImage( const osg::Image* img ); void writeObject( const osg::Object* obj ); + void writeObjectFields( const osg::Object* obj ); void start( OutputIterator* outIterator, WriteType type ); void compress( std::ostream* ostream ); @@ -161,8 +162,8 @@ protected: template void writeArrayImplementation( const T*, int write_size, unsigned int numInRow=1 ); - unsigned int findOrCreateArrayID( const osg::Array* array ); - unsigned int findOrCreateObjectID( const osg::Object* obj ); + unsigned int findOrCreateArrayID( const osg::Array* array, bool& newID ); + unsigned int findOrCreateObjectID( const osg::Object* obj, bool& newID ); ArrayMap _arrayMap; ObjectMap _objectMap; diff --git a/src/osgDB/InputStream.cpp b/src/osgDB/InputStream.cpp index 09f4d7d84..3449f48b2 100644 --- a/src/osgDB/InputStream.cpp +++ b/src/osgDB/InputStream.cpp @@ -171,7 +171,10 @@ osg::Array* InputStream::readArray() *this >> PROPERTY("ArrayID") >> id; ArrayMap::iterator itr = _arrayMap.find( id ); - if ( itr!=_arrayMap.end() ) return itr->second.get(); + if ( itr!=_arrayMap.end() ) + { + return itr->second.get(); + } DEF_MAPPEE(ArrayType, type); *this >> type; @@ -330,6 +333,7 @@ osg::Array* InputStream::readArray() if ( getException() ) return NULL; _arrayMap[id] = array; + return array.release(); } @@ -417,23 +421,24 @@ osg::PrimitiveSet* InputStream::readPrimitiveSet() osg::Image* InputStream::readImage() { + std::string className="osg::Image"; unsigned int id = 0; - *this >> PROPERTY("ImageID") >> id; + + *this >> PROPERTY("UniqueID") >> id; if ( getException() ) return NULL; - + IdentifierMap::iterator itr = _identifierMap.find( id ); if ( itr!=_identifierMap.end() ) { - advanceToCurrentEndBracket(); return static_cast( itr->second.get() ); } - + std::string name; int writeHint, decision = IMAGE_EXTERNAL; *this >> PROPERTY("FileName"); readWrappedString(name); *this >> PROPERTY("WriteHint") >> writeHint >> decision; if ( getException() ) return NULL; - + osg::ref_ptr image = NULL; bool readFromExternal = true; switch ( decision ) @@ -533,9 +538,12 @@ osg::Image* InputStream::readImage() image->setFileName( name ); image->setWriteHint( (osg::Image::WriteHint)writeHint ); } - - image = static_cast( readObject(image.get()) ); - return image.release(); + + image = static_cast( readObjectFields(className, image.get()) ); + + _identifierMap[id] = image; + + return image.release(); } osg::Object* InputStream::readObject( osg::Object* existingObj ) @@ -551,13 +559,23 @@ osg::Object* InputStream::readObject( osg::Object* existingObj ) advanceToCurrentEndBracket(); return itr->second.get(); } - + + osg::ref_ptr obj = readObjectFields( className ); + + _identifierMap[id] = obj; + + advanceToCurrentEndBracket(); + + return obj.release(); +} + +osg::Object* InputStream::readObjectFields( const std::string& className, osg::Object* existingObj ) +{ ObjectWrapper* wrapper = Registry::instance()->getObjectWrapperManager()->findWrapper( className ); if ( !wrapper ) { OSG_WARN << "InputStream::readObject(): Unsupported wrapper class " << className << std::endl; - advanceToCurrentEndBracket(); return NULL; } _fields.push_back( className ); @@ -565,8 +583,6 @@ osg::Object* InputStream::readObject( osg::Object* existingObj ) osg::ref_ptr obj = existingObj ? existingObj : wrapper->getProto()->cloneType(); if ( obj.valid() ) { - _identifierMap[id] = obj; - const StringList& associates = wrapper->getAssociates(); for ( StringList::const_iterator itr=associates.begin(); itr!=associates.end(); ++itr ) { @@ -585,7 +601,6 @@ osg::Object* InputStream::readObject( osg::Object* existingObj ) _fields.pop_back(); } } - advanceToCurrentEndBracket(); _fields.pop_back(); return obj.release(); } diff --git a/src/osgDB/OutputStream.cpp b/src/osgDB/OutputStream.cpp index bd67e84f7..7d15c4276 100644 --- a/src/osgDB/OutputStream.cpp +++ b/src/osgDB/OutputStream.cpp @@ -139,11 +139,11 @@ OutputStream& OutputStream::operator<<( const osg::Matrixd& mat ) void OutputStream::writeArray( const osg::Array* a ) { if ( !a ) return; - - size_t oldSize = _arrayMap.size(); - unsigned int id = findOrCreateArrayID( a ); + + bool newID = false; + unsigned int id = findOrCreateArrayID( a, newID ); *this << PROPERTY("ArrayID") << id; - if ( id<=oldSize ) // Shared array + if ( !newID ) // Shared array { *this << std::endl; return; @@ -294,176 +294,197 @@ void OutputStream::writePrimitiveSet( const osg::PrimitiveSet* p ) void OutputStream::writeImage( const osg::Image* img ) { if ( !img ) return; - - unsigned int id = findOrCreateObjectID( img ); - *this << PROPERTY("ImageID") << id << std::endl; // Write image ID + + // std::string name = img->libraryName(); + // name += std::string("::") + img->className(); + + bool newID = false; + unsigned int id = findOrCreateObjectID( img, newID ); + + // *this << name << BEGIN_BRACKET << std::endl; // Write object name + *this << PROPERTY("UniqueID") << id << std::endl; // Write image ID if ( getException() ) return; - - *this << PROPERTY("FileName"); writeWrappedString(img->getFileName()); *this << std::endl; - *this << PROPERTY("WriteHint") << (int)img->getWriteHint(); - if ( getException() ) return; - - int decision = IMAGE_EXTERNAL; - switch ( _writeImageHint ) + + if (newID) { - case OutputStream::WRITE_INLINE_DATA: decision = IMAGE_INLINE_DATA; break; - case OutputStream::WRITE_INLINE_FILE: decision = IMAGE_INLINE_FILE; break; - case OutputStream::WRITE_EXTERNAL_FILE: decision = IMAGE_EXTERNAL; break; - case OutputStream::WRITE_USE_EXTERNAL: decision = IMAGE_WRITE_OUT; break; - default: - if ( img->getWriteHint()==osg::Image::EXTERNAL_FILE ) - decision = IMAGE_EXTERNAL; - else if ( isBinary() ) - decision = IMAGE_INLINE_DATA; - break; - } - - *this << decision << std::endl; - if ( decision==IMAGE_WRITE_OUT || _writeImageHint==WRITE_EXTERNAL_FILE ) - { - bool result = osgDB::writeImageFile( *img, img->getFileName() ); - OSG_NOTICE << "OutputStream::writeImage(): Write image data to external file " - << img->getFileName() << std::endl; - if ( !result ) + *this << PROPERTY("FileName"); writeWrappedString(img->getFileName()); *this << std::endl; + *this << PROPERTY("WriteHint") << (int)img->getWriteHint(); + if ( getException() ) return; + + int decision = IMAGE_EXTERNAL; + switch ( _writeImageHint ) { - OSG_WARN << "OutputStream::writeImage(): Failed to write " - << img->getFileName() << std::endl; + case OutputStream::WRITE_INLINE_DATA: decision = IMAGE_INLINE_DATA; break; + case OutputStream::WRITE_INLINE_FILE: decision = IMAGE_INLINE_FILE; break; + case OutputStream::WRITE_EXTERNAL_FILE: decision = IMAGE_EXTERNAL; break; + case OutputStream::WRITE_USE_EXTERNAL: decision = IMAGE_WRITE_OUT; break; + default: + if ( img->getWriteHint()==osg::Image::EXTERNAL_FILE ) + decision = IMAGE_EXTERNAL; + else if ( isBinary() ) + decision = IMAGE_INLINE_DATA; + break; } - } - - switch ( decision ) - { - case IMAGE_INLINE_DATA: - if ( isBinary() ) + + *this << decision << std::endl; + if ( decision==IMAGE_WRITE_OUT || _writeImageHint==WRITE_EXTERNAL_FILE ) { - *this << img->getOrigin(); // _origin - *this << img->s() << img->t() << img->r(); // _s & _t & _r - *this << img->getInternalTextureFormat(); // _internalTextureFormat - *this << img->getPixelFormat(); // _pixelFormat - *this << img->getDataType(); // _dataType - *this << img->getPacking(); // _packing - *this << img->getAllocationMode(); // _allocationMode - - // _data - unsigned int size = img->getTotalSizeInBytesIncludingMipmaps(); - writeSize(size); writeCharArray( (char*)img->data(), size ); - - // _mipmapData - const osg::Image::MipmapDataType& levels = img->getMipmapLevels(); - writeSize(levels.size()); - for ( osg::Image::MipmapDataType::const_iterator itr=levels.begin(); - itr!=levels.end(); ++itr ) + bool result = osgDB::writeImageFile( *img, img->getFileName() ); + OSG_NOTICE << "OutputStream::writeImage(): Write image data to external file " + << img->getFileName() << std::endl; + if ( !result ) { - *this << *itr; + OSG_WARN << "OutputStream::writeImage(): Failed to write " + << img->getFileName() << std::endl; } } - break; - case IMAGE_INLINE_FILE: - if ( isBinary() ) + + switch ( decision ) { - std::string fullPath = osgDB::findDataFile( img->getFileName() ); - std::ifstream infile( fullPath.c_str(), std::ios::in|std::ios::binary ); - if ( infile ) + case IMAGE_INLINE_DATA: + if ( isBinary() ) { - infile.seekg( 0, std::ios::end ); - unsigned int size = infile.tellg(); - writeSize(size); - - if ( size>0 ) + *this << img->getOrigin(); // _origin + *this << img->s() << img->t() << img->r(); // _s & _t & _r + *this << img->getInternalTextureFormat(); // _internalTextureFormat + *this << img->getPixelFormat(); // _pixelFormat + *this << img->getDataType(); // _dataType + *this << img->getPacking(); // _packing + *this << img->getAllocationMode(); // _allocationMode + + // _data + unsigned int size = img->getTotalSizeInBytesIncludingMipmaps(); + writeSize(size); writeCharArray( (char*)img->data(), size ); + + // _mipmapData + const osg::Image::MipmapDataType& levels = img->getMipmapLevels(); + writeSize(levels.size()); + for ( osg::Image::MipmapDataType::const_iterator itr=levels.begin(); + itr!=levels.end(); ++itr ) { - char* data = new char[size]; - if ( !data ) - throwException( "OutputStream::writeImage(): Out of memory." ); - if ( getException() ) return; - - infile.seekg( 0, std::ios::beg ); - infile.read( data, size ); - writeCharArray( data, size ); - delete[] data; + *this << *itr; } - infile.close(); } - else + break; + case IMAGE_INLINE_FILE: + if ( isBinary() ) { - OSG_WARN << "OutputStream::writeImage(): Failed to open image file " - << img->getFileName() << std::endl; - *this << (unsigned int)0; + std::string fullPath = osgDB::findDataFile( img->getFileName() ); + std::ifstream infile( fullPath.c_str(), std::ios::in|std::ios::binary ); + if ( infile ) + { + infile.seekg( 0, std::ios::end ); + unsigned int size = infile.tellg(); + writeSize(size); + + if ( size>0 ) + { + char* data = new char[size]; + if ( !data ) + throwException( "OutputStream::writeImage(): Out of memory." ); + if ( getException() ) return; + + infile.seekg( 0, std::ios::beg ); + infile.read( data, size ); + writeCharArray( data, size ); + delete[] data; + } + infile.close(); + } + else + { + OSG_WARN << "OutputStream::writeImage(): Failed to open image file " + << img->getFileName() << std::endl; + *this << (unsigned int)0; + } } + break; + case IMAGE_EXTERNAL: + break; + default: + break; } - break; - case IMAGE_EXTERNAL: - break; - default: - break; + + writeObjectFields( img ); } - writeObject( img ); + + // *this << END_BRACKET << std::endl; } void OutputStream::writeObject( const osg::Object* obj ) { if ( !obj ) return; - + std::string name = obj->libraryName(); name += std::string("::") + obj->className(); - size_t oldSize = _objectMap.size(); - unsigned int id = findOrCreateObjectID( obj ); - + + bool newID = false; + unsigned int id = findOrCreateObjectID( obj, newID ); + *this << name << BEGIN_BRACKET << std::endl; // Write object name *this << PROPERTY("UniqueID") << id << std::endl; // Write object ID if ( getException() ) return; - - // Check whether this is a shared object or not - if ( id>oldSize ) + + if (newID) { - ObjectWrapper* wrapper = Registry::instance()->getObjectWrapperManager()->findWrapper( name ); - if ( !wrapper ) + writeObjectFields(obj); + } + + *this << END_BRACKET << std::endl; +} + +void OutputStream::writeObjectFields( const osg::Object* obj ) +{ + std::string name = obj->libraryName(); + name += std::string("::") + obj->className(); + + ObjectWrapper* wrapper = Registry::instance()->getObjectWrapperManager()->findWrapper( name ); + if ( !wrapper ) + { + OSG_WARN << "OutputStream::writeObject(): Unsupported wrapper class " + << name << std::endl; + return; + } + _fields.push_back( name ); + + const StringList& associates = wrapper->getAssociates(); + 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_WARN << "OutputStream::writeObject(): Unsupported wrapper class " - << name << std::endl; - *this << END_BRACKET << std::endl; - return; + OSG_WARN << "OutputStream::writeObject(): Unsupported associated class " + << assocName << std::endl; + continue; } - _fields.push_back( name ); - - const StringList& associates = wrapper->getAssociates(); - for ( StringList::const_iterator itr=associates.begin(); itr!=associates.end(); ++itr ) + else if ( _useSchemaData ) { - const std::string& assocName = *itr; - ObjectWrapper* assocWrapper = Registry::instance()->getObjectWrapperManager()->findWrapper(assocName); - if ( !assocWrapper ) + if ( _inbuiltSchemaMap.find(assocName)==_inbuiltSchemaMap.end() ) { - OSG_WARN << "OutputStream::writeObject(): Unsupported associated class " - << assocName << std::endl; - continue; - } - else if ( _useSchemaData ) - { - if ( _inbuiltSchemaMap.find(assocName)==_inbuiltSchemaMap.end() ) + StringList properties; + assocWrapper->writeSchema( properties ); + if ( properties.size()>0 ) { - StringList properties; - assocWrapper->writeSchema( properties ); - if ( properties.size()>0 ) + std::string propertiesString; + for ( StringList::iterator sitr=properties.begin(); sitr!=properties.end(); ++sitr ) { - std::string propertiesString; - for ( StringList::iterator sitr=properties.begin(); sitr!=properties.end(); ++sitr ) - { - propertiesString += *sitr; - propertiesString += ' '; - } - _inbuiltSchemaMap[assocName] = propertiesString; + propertiesString += *sitr; + propertiesString += ' '; } + _inbuiltSchemaMap[assocName] = propertiesString; } } - _fields.push_back( assocWrapper->getName() ); - - assocWrapper->write( *this, *obj ); - if ( getException() ) return; - - _fields.pop_back(); } + _fields.push_back( assocWrapper->getName() ); + + assocWrapper->write( *this, *obj ); + if ( getException() ) return; + _fields.pop_back(); } - *this << END_BRACKET << std::endl; + _fields.pop_back(); + } void OutputStream::start( OutputIterator* outIterator, OutputStream::WriteType type ) @@ -635,26 +656,30 @@ void OutputStream::writeArrayImplementation( const T* a, int write_size, unsigne *this << END_BRACKET << std::endl; } -unsigned int OutputStream::findOrCreateArrayID( const osg::Array* array ) +unsigned int OutputStream::findOrCreateArrayID( const osg::Array* array, bool& newID ) { ArrayMap::iterator itr = _arrayMap.find( array ); if ( itr==_arrayMap.end() ) { unsigned int id = _arrayMap.size()+1; _arrayMap[array] = id; + newID = true; return id; } + newID = false; return itr->second; } -unsigned int OutputStream::findOrCreateObjectID( const osg::Object* obj ) +unsigned int OutputStream::findOrCreateObjectID( const osg::Object* obj, bool& newID ) { ObjectMap::iterator itr = _objectMap.find( obj ); if ( itr==_objectMap.end() ) { unsigned int id = _objectMap.size()+1; _objectMap[obj] = id; + newID = true; return id; } + newID = false; return itr->second; }