forcing users to use osgDB::readRef*File() methods. The later is preferable as it closes a potential threading bug when using paging databases in conjunction
with the osgDB::Registry Object Cache. This threading bug occurs when one thread gets an object from the Cache via an osgDB::read*File() call where only
a pointer to the object is passed back, so taking a reference to the object is delayed till it gets reassigned to a ref_ptr<>, but at the same time another
thread calls a flush of the Object Cache deleting this object as it's referenceCount is now zero. Using osgDB::readREf*File() makes sure the a ref_ptr<> is
passed back and the referenceCount never goes to zero.
To ensure the OSG builds when OSG_PROVIDE_READFILE is to OFF the many cases of osgDB::read*File() usage had to be replaced with a ref_ptr<> osgDB::readRef*File()
usage. The avoid this change causing lots of other client code to be rewritten to handle the use of ref_ptr<> in place of C pointer I introduced a serious of
templte methods in various class to adapt ref_ptr<> to the underly C pointer to be passed to old OSG API's, example of this is found in include/osg/Group:
bool addChild(Node* child); // old method which can only be used with a Node*
tempalte<class T> bool addChild(const osg::ref_ptr<T>& child) { return addChild(child.get()); } // adapter template method
These changes together cover 149 modified files, so it's a large submission. This extent of changes are warrent to make use of the Object Cache
and multi-threaded loaded more robust.
git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@15164 16af8721-9629-0410-8352-f15c8da7e697
403 lines
15 KiB
C++
403 lines
15 KiB
C++
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 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.
|
|
*/
|
|
// Written by Wang Rui, (C) 2010
|
|
|
|
#include <osgDB/FileNameUtils>
|
|
#include <osgDB/FileUtils>
|
|
#include <osgDB/Registry>
|
|
#include <osgDB/ObjectWrapper>
|
|
#include <stdlib.h>
|
|
#include "AsciiStreamOperator.h"
|
|
#include "BinaryStreamOperator.h"
|
|
#include "XmlStreamOperator.h"
|
|
|
|
using namespace osgDB;
|
|
|
|
#define CATCH_EXCEPTION(s) \
|
|
if (s.getException()) return (s.getException()->getError() + " At " + s.getException()->getField());
|
|
|
|
#define OSG_REVERSE(value) ( ((value & 0x000000ff)<<24) | ((value & 0x0000ff00)<<8) | ((value & 0x00ff0000)>>8) | ((value & 0xff000000)>>24) )
|
|
|
|
InputIterator* readInputIterator( std::istream& fin, const Options* options )
|
|
{
|
|
bool extensionIsAscii = false, extensionIsXML = false;
|
|
if ( options )
|
|
{
|
|
const std::string& optionString = options->getPluginStringData("fileType");
|
|
if ( optionString=="Ascii") extensionIsAscii = true;
|
|
else if ( optionString=="XML" ) extensionIsXML = true;
|
|
}
|
|
|
|
if ( !extensionIsAscii && !extensionIsXML )
|
|
{
|
|
unsigned int headerLow = 0, headerHigh = 0;
|
|
fin.read( (char*)&headerLow, INT_SIZE );
|
|
fin.read( (char*)&headerHigh, INT_SIZE );
|
|
if ( headerLow==OSG_HEADER_LOW && headerHigh==OSG_HEADER_HIGH )
|
|
{
|
|
OSG_INFO<<"Reading OpenSceneGraph binary file with the same endian as this computer."<<std::endl;
|
|
return new BinaryInputIterator(&fin, 0); // endian the same so no byte swap required
|
|
}
|
|
else if ( headerLow==OSG_REVERSE(OSG_HEADER_LOW) && headerHigh==OSG_REVERSE(OSG_HEADER_HIGH) )
|
|
{
|
|
OSG_INFO<<"Reading OpenSceneGraph binary file with the different endian to this computer, doing byte swap."<<std::endl;
|
|
return new BinaryInputIterator(&fin, 1); // endian different so byte swap required
|
|
}
|
|
|
|
fin.seekg( 0, std::ios::beg );
|
|
}
|
|
|
|
if ( !extensionIsXML )
|
|
{
|
|
std::string header; fin >> header;
|
|
if ( header=="#Ascii" )
|
|
{
|
|
return new AsciiInputIterator(&fin);
|
|
}
|
|
fin.seekg( 0, std::ios::beg );
|
|
}
|
|
|
|
if ( 1 )
|
|
{
|
|
std::string header; std::getline( fin, header );
|
|
if ( !header.compare(0, 5, "<?xml") )
|
|
{
|
|
return new XmlInputIterator(&fin);
|
|
}
|
|
fin.seekg( 0, std::ios::beg );
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
OutputIterator* writeOutputIterator( std::ostream& fout, const Options* options )
|
|
{
|
|
// Read precision parameter, for text & XML formats
|
|
int precision(-1);
|
|
if ( options ) {
|
|
std::istringstream iss(options->getOptionString());
|
|
std::string opt;
|
|
while (iss >> opt)
|
|
{
|
|
if(opt=="PRECISION" || opt=="precision")
|
|
{
|
|
iss >> precision;
|
|
}
|
|
}
|
|
}
|
|
|
|
const std::string optionString = (options!=0) ? options->getPluginStringData("fileType") : std::string();
|
|
if (optionString == "Ascii")
|
|
{
|
|
fout << std::string("#Ascii") << ' ';
|
|
return new AsciiOutputIterator(&fout, precision);
|
|
}
|
|
else if ( optionString == "XML")
|
|
{
|
|
fout << std::string("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>") << std::endl;
|
|
return new XmlOutputIterator(&fout, precision);
|
|
}
|
|
else
|
|
{
|
|
unsigned int low = OSG_HEADER_LOW, high = OSG_HEADER_HIGH;
|
|
fout.write( (char*)&low, INT_SIZE );
|
|
fout.write( (char*)&high, INT_SIZE );
|
|
return new BinaryOutputIterator(&fout);
|
|
}
|
|
}
|
|
|
|
class ReaderWriterOSG2 : public osgDB::ReaderWriter
|
|
{
|
|
public:
|
|
ReaderWriterOSG2()
|
|
{
|
|
supportsExtension( "osg2", "OpenSceneGraph extendable format" );
|
|
supportsExtension( "osgt", "OpenSceneGraph extendable ascii format" );
|
|
supportsExtension( "osgb", "OpenSceneGraph extendable binary format" );
|
|
supportsExtension( "osgx", "OpenSceneGraph extendable XML format" );
|
|
|
|
supportsOption( "Ascii", "Import/Export option: Force reading/writing ascii file" );
|
|
supportsOption( "XML", "Import/Export option: Force reading/writing XML file" );
|
|
supportsOption( "ForceReadingImage", "Import option: Load an empty image instead if required file missed" );
|
|
supportsOption( "SchemaData", "Export option: Record inbuilt schema data into a binary file" );
|
|
supportsOption( "SchemaFile=<file>", "Import/Export option: Use/Record an ascii schema file" );
|
|
supportsOption( "Compressor=<name>", "Export option: Use an inbuilt or user-defined compressor" );
|
|
supportsOption( "WriteImageHint=<hint>", "Export option: Hint of writing image to stream: "
|
|
"<IncludeData> writes Image::data() directly; "
|
|
"<IncludeFile> writes the image file itself to stream; "
|
|
"<UseExternal> writes only the filename; "
|
|
"<WriteOut> writes Image::data() to disk as external file." );
|
|
}
|
|
|
|
virtual const char* className() const { return "OpenSceneGraph Native Format Reader/Writer"; }
|
|
|
|
|
|
Options* prepareReading( ReadResult& result, std::string& fileName, std::ios::openmode& mode, const Options* options ) const
|
|
{
|
|
std::string ext = osgDB::getLowerCaseFileExtension( fileName );
|
|
if ( !acceptsExtension(ext) )
|
|
{
|
|
result = ReadResult::FILE_NOT_HANDLED;
|
|
return 0;
|
|
}
|
|
fileName = osgDB::findDataFile( fileName, options );
|
|
if ( fileName.empty() )
|
|
{
|
|
result = ReadResult::FILE_NOT_FOUND;
|
|
return 0;
|
|
}
|
|
|
|
osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
|
|
local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));
|
|
if ( ext=="osgt" ) local_opt->setPluginStringData( "fileType", "Ascii" );
|
|
else if ( ext=="osgx" ) local_opt->setPluginStringData( "fileType", "XML" );
|
|
else if ( ext=="osgb" )
|
|
{
|
|
local_opt->setPluginStringData( "fileType", "Binary" );
|
|
mode |= std::ios::binary;
|
|
}
|
|
else
|
|
{
|
|
local_opt->setPluginStringData( "fileType", std::string() );
|
|
mode |= std::ios::binary;
|
|
}
|
|
|
|
return local_opt.release();
|
|
}
|
|
|
|
virtual ReadResult readObject( const std::string& file, const Options* options ) const
|
|
{
|
|
ReadResult result = ReadResult::FILE_LOADED;
|
|
std::string fileName = file;
|
|
std::ios::openmode mode = std::ios::in;
|
|
Options* local_opt = prepareReading( result, fileName, mode, options );
|
|
if ( !result.success() ) return result;
|
|
|
|
osgDB::ifstream istream( fileName.c_str(), mode );
|
|
return readObject( istream, local_opt );
|
|
}
|
|
|
|
virtual ReadResult readObject( std::istream& fin, const Options* options ) const
|
|
{
|
|
osg::ref_ptr<InputIterator> ii = readInputIterator(fin, options);
|
|
if ( !ii ) return ReadResult::FILE_NOT_HANDLED;
|
|
|
|
InputStream is( options );
|
|
|
|
osgDB::InputStream::ReadType readType = is.start(ii.get());
|
|
if ( readType==InputStream::READ_UNKNOWN )
|
|
{
|
|
CATCH_EXCEPTION(is);
|
|
return ReadResult::FILE_NOT_HANDLED;
|
|
}
|
|
is.decompress(); CATCH_EXCEPTION(is);
|
|
|
|
osg::ref_ptr<osg::Object> obj = is.readObject(); CATCH_EXCEPTION(is);
|
|
return obj;
|
|
}
|
|
|
|
virtual ReadResult readImage( const std::string& file, const Options* options ) const
|
|
{
|
|
ReadResult result = ReadResult::FILE_LOADED;
|
|
std::string fileName = file;
|
|
std::ios::openmode mode = std::ios::in;
|
|
Options* local_opt = prepareReading( result, fileName, mode, options );
|
|
if ( !result.success() ) return result;
|
|
|
|
osgDB::ifstream istream( fileName.c_str(), mode );
|
|
return readImage( istream, local_opt );
|
|
}
|
|
|
|
virtual ReadResult readImage( std::istream& fin, const Options* options ) const
|
|
{
|
|
osg::ref_ptr<InputIterator> ii = readInputIterator(fin, options);
|
|
if ( !ii ) return ReadResult::FILE_NOT_HANDLED;
|
|
|
|
|
|
InputStream is( options );
|
|
if ( is.start(ii.get())!=InputStream::READ_IMAGE )
|
|
{
|
|
CATCH_EXCEPTION(is);
|
|
return ReadResult::FILE_NOT_HANDLED;
|
|
}
|
|
|
|
is.decompress(); CATCH_EXCEPTION(is);
|
|
osg::ref_ptr<osg::Image> image = is.readImage(); CATCH_EXCEPTION(is);
|
|
|
|
return image;
|
|
}
|
|
|
|
virtual ReadResult readNode( const std::string& file, const Options* options ) const
|
|
{
|
|
ReadResult result = ReadResult::FILE_LOADED;
|
|
std::string fileName = file;
|
|
std::ios::openmode mode = std::ios::in;
|
|
Options* local_opt = prepareReading( result, fileName, mode, options );
|
|
if ( !result.success() ) return result;
|
|
|
|
osgDB::ifstream istream( fileName.c_str(), mode );
|
|
return readNode( istream, local_opt );
|
|
}
|
|
|
|
virtual ReadResult readNode( std::istream& fin, const Options* options ) const
|
|
{
|
|
osg::ref_ptr<InputIterator> ii = readInputIterator(fin, options);
|
|
if ( !ii ) return ReadResult::FILE_NOT_HANDLED;
|
|
|
|
InputStream is( options );
|
|
osgDB::InputStream::ReadType readType = is.start(ii.get());
|
|
if ( readType!=InputStream::READ_SCENE && readType!=InputStream::READ_OBJECT )
|
|
{
|
|
CATCH_EXCEPTION(is);
|
|
return ReadResult::FILE_NOT_HANDLED;
|
|
}
|
|
|
|
is.decompress(); CATCH_EXCEPTION(is);
|
|
osg::ref_ptr<osg::Node> node = is.readObjectOfType<osg::Node>(); CATCH_EXCEPTION(is);
|
|
if ( !node ) return ReadResult::FILE_NOT_HANDLED;
|
|
return node;
|
|
}
|
|
|
|
Options* prepareWriting( WriteResult& result, const std::string& fileName, std::ios::openmode& mode, const Options* options ) const
|
|
{
|
|
std::string ext = osgDB::getLowerCaseFileExtension( fileName );
|
|
if ( !acceptsExtension(ext) ) result = WriteResult::FILE_NOT_HANDLED;
|
|
|
|
osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
|
|
local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));
|
|
if ( ext=="osgt" ) local_opt->setPluginStringData( "fileType", "Ascii" );
|
|
else if ( ext=="osgx" ) local_opt->setPluginStringData( "fileType", "XML" );
|
|
else if ( ext=="osgb" )
|
|
{
|
|
local_opt->setPluginStringData( "fileType", "Binary" );
|
|
mode |= std::ios::binary;
|
|
}
|
|
else
|
|
{
|
|
local_opt->setPluginStringData( "fileType", std::string() );
|
|
mode |= std::ios::binary;
|
|
}
|
|
|
|
return local_opt.release();
|
|
}
|
|
|
|
virtual WriteResult writeObject( const osg::Object& object, const std::string& fileName, const Options* options ) const
|
|
{
|
|
WriteResult result = WriteResult::FILE_SAVED;
|
|
std::ios::openmode mode = std::ios::out;
|
|
osg::ref_ptr<Options> local_opt = prepareWriting( result, fileName, mode, options );
|
|
if ( !result.success() ) return result;
|
|
|
|
osgDB::ofstream fout( fileName.c_str(), mode );
|
|
if ( !fout ) return WriteResult::ERROR_IN_WRITING_FILE;
|
|
|
|
result = writeObject( object, fout, local_opt.get() );
|
|
fout.close();
|
|
return result;
|
|
}
|
|
|
|
virtual WriteResult writeObject( const osg::Object& object, std::ostream& fout, const Options* options ) const
|
|
{
|
|
osg::ref_ptr<OutputIterator> oi = writeOutputIterator(fout, options);
|
|
|
|
OutputStream os( options );
|
|
os.start( oi.get(), OutputStream::WRITE_OBJECT ); CATCH_EXCEPTION(os);
|
|
os.writeObject( &object ); CATCH_EXCEPTION(os);
|
|
os.compress( &fout ); CATCH_EXCEPTION(os);
|
|
|
|
oi->flush();
|
|
if ( !os.getSchemaName().empty() )
|
|
{
|
|
osgDB::ofstream schemaStream( os.getSchemaName().c_str(), std::ios::out );
|
|
if ( !schemaStream.fail() ) os.writeSchema( schemaStream );
|
|
schemaStream.close();
|
|
}
|
|
|
|
if ( fout.fail() ) return WriteResult::ERROR_IN_WRITING_FILE;
|
|
return WriteResult::FILE_SAVED;
|
|
}
|
|
|
|
virtual WriteResult writeImage( const osg::Image& image, const std::string& fileName, const Options* options ) const
|
|
{
|
|
WriteResult result = WriteResult::FILE_SAVED;
|
|
std::ios::openmode mode = std::ios::out;
|
|
osg::ref_ptr<Options> local_opt = prepareWriting( result, fileName, mode, options );
|
|
if ( !result.success() ) return result;
|
|
|
|
osgDB::ofstream fout( fileName.c_str(), mode );
|
|
if ( !fout ) return WriteResult::ERROR_IN_WRITING_FILE;
|
|
|
|
result = writeImage( image, fout, local_opt.get() );
|
|
fout.close();
|
|
return result;
|
|
}
|
|
|
|
virtual WriteResult writeImage( const osg::Image& image, std::ostream& fout, const Options* options ) const
|
|
{
|
|
osg::ref_ptr<OutputIterator> oi = writeOutputIterator(fout, options);
|
|
|
|
OutputStream os( options );
|
|
os.start( oi.get(), OutputStream::WRITE_IMAGE ); CATCH_EXCEPTION(os);
|
|
os.writeImage( &image ); CATCH_EXCEPTION(os);
|
|
os.compress( &fout ); CATCH_EXCEPTION(os);
|
|
|
|
oi->flush();
|
|
if ( !os.getSchemaName().empty() )
|
|
{
|
|
osgDB::ofstream schemaStream( os.getSchemaName().c_str(), std::ios::out );
|
|
if ( !schemaStream.fail() ) os.writeSchema( schemaStream );
|
|
schemaStream.close();
|
|
}
|
|
|
|
if ( fout.fail() ) return WriteResult::ERROR_IN_WRITING_FILE;
|
|
return WriteResult::FILE_SAVED;
|
|
}
|
|
|
|
virtual WriteResult writeNode( const osg::Node& node, const std::string& fileName, const Options* options ) const
|
|
{
|
|
WriteResult result = WriteResult::FILE_SAVED;
|
|
std::ios::openmode mode = std::ios::out;
|
|
osg::ref_ptr<Options> local_opt = prepareWriting( result, fileName, mode, options );
|
|
if ( !result.success() ) return result;
|
|
|
|
osgDB::ofstream fout( fileName.c_str(), mode );
|
|
if ( !fout ) return WriteResult::ERROR_IN_WRITING_FILE;
|
|
|
|
result = writeNode( node, fout, local_opt.get() );
|
|
fout.close();
|
|
return result;
|
|
}
|
|
|
|
virtual WriteResult writeNode( const osg::Node& node, std::ostream& fout, const Options* options ) const
|
|
{
|
|
osg::ref_ptr<OutputIterator> oi = writeOutputIterator(fout, options);
|
|
|
|
OutputStream os( options );
|
|
os.start( oi.get(), OutputStream::WRITE_SCENE ); CATCH_EXCEPTION(os);
|
|
os.writeObject( &node ); CATCH_EXCEPTION(os);
|
|
os.compress( &fout ); CATCH_EXCEPTION(os);
|
|
|
|
oi->flush();
|
|
if ( !os.getSchemaName().empty() )
|
|
{
|
|
osgDB::ofstream schemaStream( os.getSchemaName().c_str(), std::ios::out );
|
|
if ( !schemaStream.fail() ) os.writeSchema( schemaStream );
|
|
schemaStream.close();
|
|
}
|
|
|
|
if ( fout.fail() ) return WriteResult::ERROR_IN_WRITING_FILE;
|
|
return WriteResult::FILE_SAVED;
|
|
}
|
|
};
|
|
|
|
REGISTER_OSGPLUGIN( osg2, ReaderWriterOSG2 )
|