diff --git a/include/osgDB/Archive b/include/osgDB/Archive index 537c9efb0..69adb3e80 100644 --- a/include/osgDB/Archive +++ b/include/osgDB/Archive @@ -15,6 +15,7 @@ #define OSGDB_ARCHIVE 1 #include +#include #include #include @@ -23,8 +24,6 @@ namespace osgDB { /** Base class for implementing database Archives. */ - - class OSGDB_EXPORT Archive : public ReaderWriter { public: @@ -37,15 +36,8 @@ class OSGDB_EXPORT Archive : public ReaderWriter virtual bool acceptsExtension(const std::string& /*extension*/) { return true; } - enum Status - { - READ, - WRITE, - CREATE - }; - /** open the archive.*/ - virtual bool open(const std::string& filename, Status status, unsigned int indexBlockSizeHint=4096); + virtual bool open(const std::string& filename, ArchiveStatus status, unsigned int indexBlockSizeHint=4096); /** close the archive.*/ virtual void close(); @@ -98,9 +90,9 @@ class OSGDB_EXPORT Archive : public ReaderWriter void write(std::ostream& out); - inline bool spaceAvailable(pos_type position, size_type size, const std::string& filename) const + inline bool spaceAvailable(pos_type, size_type, const std::string& filename) const { - unsigned requiredSize = sizeof(position)+sizeof(unsigned int)+filename.size(); + unsigned requiredSize = sizeof(pos_type)+sizeof(unsigned int)+filename.size(); return (_offsetOfNextAvailableSpace + requiredSize)<_blockSize; } @@ -132,7 +124,7 @@ class OSGDB_EXPORT Archive : public ReaderWriter static float s_currentSupportedVersion; float _version; - Status _status; + ArchiveStatus _status; std::ifstream _input; std::fstream _output; @@ -142,6 +134,12 @@ class OSGDB_EXPORT Archive : public ReaderWriter }; +/** Open an archive for reading or writing.*/ +Archive* openArchive(const std::string& filename, Archive::ArchiveStatus status, unsigned int indexBlockSizeHint=4096); + +/** Open an archive for reading or writing.*/ +osgDB::Archive* osgDB::openArchive(const std::string& filename, Archive::ArchiveStatus status, unsigned int indexBlockSizeHint,Registry::CacheHintOptions useObjectCache); + } #endif // OSGDB_ARCHIVE diff --git a/include/osgDB/ReaderWriter b/include/osgDB/ReaderWriter index 36102545b..b03cea398 100644 --- a/include/osgDB/ReaderWriter +++ b/include/osgDB/ReaderWriter @@ -21,18 +21,23 @@ #include - -#include - namespace osgDB { +class Archive; /** pure virtual base class for reading and writing of non native formats. */ -class OSGDB_EXPORT ReaderWriter : public osg::Referenced +class OSGDB_EXPORT ReaderWriter : public osg::Object { public: - virtual ~ReaderWriter(); // {} - virtual const char* className() const = 0; + + + ReaderWriter() {} + ReaderWriter(const ReaderWriter& rw,const osg::CopyOp copyop=osg::CopyOp::SHALLOW_COPY):Object(rw,copyop) {} + + virtual ~ReaderWriter(); + + META_Object(osgDB,ReaderWriter); + virtual bool acceptsExtension(const std::string& /*extension*/) { return false; } /** Options base class used for passing options into plugins to control their operation.*/ @@ -85,20 +90,23 @@ class OSGDB_EXPORT ReaderWriter : public osg::Referenced ReadResult(const ReadResult& rr):_status(rr._status),_message(rr._message),_object(rr._object) {} ReadResult& operator = (const ReadResult& rr) { if (this==&rr) return *this; _status=rr._status; _message=rr._message;_object=rr._object; return *this; } - osg::Object* getObject() { return _object.get(); } - osg::Image* getImage() { return dynamic_cast(_object.get()); } - osg::HeightField* getHeightField() { return dynamic_cast(_object.get()); } - osg::Node* getNode() { return dynamic_cast(_object.get()); } + osg::Object* getObject(); + osg::Image* getImage(); + osg::HeightField* getHeightField(); + osg::Node* getNode(); + osgDB::Archive* getArchive(); bool validObject() { return _object.valid(); } bool validImage() { return getImage()!=0; } bool validHeightField() { return getHeightField()!=0; } bool validNode() { return getNode()!=0; } + bool validArchive() { return getArchive()!=0; } - osg::Object* takeObject() { osg::Object* obj = _object.get(); if (obj) { obj->ref(); _object=NULL; obj->unref_nodelete(); } return obj; } - osg::Image* takeImage() { osg::Image* image=dynamic_cast(_object.get()); if (image) { image->ref(); _object=NULL; image->unref_nodelete(); } return image; } - osg::HeightField* takeHeightField() { osg::HeightField* hf=dynamic_cast(_object.get()); if (hf) { hf->ref(); _object=NULL; hf->unref_nodelete(); } return hf; } - osg::Node* takeNode() { osg::Node* node=dynamic_cast(_object.get()); if (node) { node->ref(); _object=NULL; node->unref_nodelete(); } return node; } + osg::Object* takeObject(); + osg::Image* takeImage(); + osg::HeightField* takeHeightField(); + osg::Node* takeNode(); + osgDB::Archive* takeArchive(); const std::string& message() const { return _message; } @@ -146,6 +154,15 @@ class OSGDB_EXPORT ReaderWriter : public osg::Referenced std::string _message; }; + enum ArchiveStatus + { + READ, + WRITE, + CREATE + }; + + virtual ReadResult openArchive(const std::string& /*fileName*/,ArchiveStatus, unsigned int =4096, const Options* =NULL) { return ReadResult(ReadResult::FILE_NOT_HANDLED); } + virtual ReadResult readObject(const std::string& /*fileName*/,const Options* =NULL) { return ReadResult(ReadResult::FILE_NOT_HANDLED); } virtual ReadResult readImage(const std::string& /*fileName*/,const Options* =NULL) { return ReadResult(ReadResult::FILE_NOT_HANDLED); } virtual ReadResult readHeightField(const std::string& /*fileName*/,const Options* =NULL) { return ReadResult(ReadResult::FILE_NOT_HANDLED); } diff --git a/include/osgDB/Registry b/include/osgDB/Registry index 9e16a9b18..af48b5353 100644 --- a/include/osgDB/Registry +++ b/include/osgDB/Registry @@ -81,14 +81,18 @@ class OSGDB_EXPORT Registry : public osg::Referenced /// cache heightfield loaded via readHeightField(filename) CACHE_HEIGHTFIELDS = 4, + + /// cache heightfield loaded via readHeightField(filename) + CACHE_ARCHIVES = 8, /// cache objects loaded via readObject(filename) - CACHE_OBJECTS = 8, + CACHE_OBJECTS = 16, /// cache on all read*(filename) calls CACHE_ALL = CACHE_NODES | CACHE_IMAGES | CACHE_HEIGHTFIELDS | + CACHE_ARCHIVES | CACHE_OBJECTS }; @@ -147,6 +151,11 @@ class OSGDB_EXPORT Registry : public osg::Referenced { public: + virtual ReaderWriter::ReadResult openArchive(const std::string& filename,ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, CacheHintOptions useObjectCache) + { + return osgDB::Registry::instance()->openArchiveImplementation(filename, status, indexBlockSizeHint, useObjectCache); + } + virtual ReaderWriter::ReadResult readObject(const std::string& filename, CacheHintOptions options) { return osgDB::Registry::instance()->readObjectImplementation(filename,options); @@ -181,6 +190,13 @@ class OSGDB_EXPORT Registry : public osg::Referenced const ReadFileCallback* getReadFileCallback() const { return _readFileCallback.get(); } + ReaderWriter::ReadResult openArchive(const std::string& fileName,ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, CacheHintOptions useObjectCache) + { + if (_readFileCallback.valid()) return _readFileCallback->openArchive(fileName, status, indexBlockSizeHint, useObjectCache); + else return openArchiveImplementation(fileName, status, indexBlockSizeHint, useObjectCache); + } + ReaderWriter::ReadResult openArchiveImplementation(const std::string& fileName, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, CacheHintOptions useObjectCache); + ReaderWriter::ReadResult readObject(const std::string& fileName,CacheHintOptions useObjectCache) { if (_readFileCallback.valid()) return _readFileCallback->readObject(fileName,useObjectCache); @@ -210,6 +226,11 @@ class OSGDB_EXPORT Registry : public osg::Referenced ReaderWriter::ReadResult readNodeImplementation(const std::string& fileName,CacheHintOptions useObjectCache); + + + + + class WriteFileCallback : public osg::Referenced { public: @@ -277,6 +298,7 @@ class OSGDB_EXPORT Registry : public osg::Referenced ReaderWriter::WriteResult writeNodeImplementation(const osg::Node& node, const std::string& fileName); + void setCreateNodeFromImage(bool flag) { _createNodeFromImage = flag; } bool getCreateNodeFromImage() const { return _createNodeFromImage; } @@ -401,6 +423,7 @@ class OSGDB_EXPORT Registry : public osg::Referenced void eraseWrapper(DotOsgWrapperMap& wrappermap,DotOsgWrapper* wrapper); + ReaderWriter::ReadResult openArchive(const std::string& fileName, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint); ReaderWriter::ReadResult readObject(const std::string& fileName); ReaderWriter::ReadResult readImage(const std::string& fileName); ReaderWriter::ReadResult readHeightField(const std::string& fileName); diff --git a/src/osgDB/Archive.cpp b/src/osgDB/Archive.cpp index 2609b79b8..7d585b8bc 100644 --- a/src/osgDB/Archive.cpp +++ b/src/osgDB/Archive.cpp @@ -21,6 +21,17 @@ using namespace osgDB; float Archive::s_currentSupportedVersion = 0.0; +osgDB::Archive* osgDB::openArchive(const std::string& filename, Archive::ArchiveStatus status, unsigned int indexBlockSizeHint) +{ + return openArchive(filename, status, indexBlockSizeHint, Registry::instance()->getUseObjectCacheHint()); +} + +osgDB::Archive* osgDB::openArchive(const std::string& filename, Archive::ArchiveStatus status, unsigned int indexBlockSizeHint,Registry::CacheHintOptions useObjectCache) +{ + ReaderWriter::ReadResult result = osgDB::Registry::instance()->openArchive(filename, status, indexBlockSizeHint, useObjectCache); + return result.takeArchive(); +} + Archive::IndexBlock::IndexBlock(unsigned int blockSize): _requiresWrite(false), _filePosition(0), @@ -185,7 +196,7 @@ Archive::~Archive() } #include -bool Archive::open(const std::string& filename, Status status, unsigned int indexBlockSize) +bool Archive::open(const std::string& filename, ArchiveStatus status, unsigned int indexBlockSize) { if (status==READ) { @@ -295,6 +306,7 @@ bool Archive::open(const std::string& filename, Status status, unsigned int inde else { osg::notify(osg::NOTICE)<<"Archive::open("< +#include using namespace osgDB; +osg::Object* ReaderWriter::ReadResult::getObject() { return _object.get(); } +osg::Image* ReaderWriter::ReadResult::getImage() { return dynamic_cast(_object.get()); } +osg::HeightField* ReaderWriter::ReadResult::getHeightField() { return dynamic_cast(_object.get()); } +osg::Node* ReaderWriter::ReadResult::getNode() { return dynamic_cast(_object.get()); } +osgDB::Archive* ReaderWriter::ReadResult::getArchive() { return dynamic_cast(_object.get()); } + +osg::Object* ReaderWriter::ReadResult::takeObject() { osg::Object* obj = _object.get(); if (obj) { obj->ref(); _object=NULL; obj->unref_nodelete(); } return obj; } +osg::Image* ReaderWriter::ReadResult::takeImage() { osg::Image* image=dynamic_cast(_object.get()); if (image) { image->ref(); _object=NULL; image->unref_nodelete(); } return image; } +osg::HeightField* ReaderWriter::ReadResult::takeHeightField() { osg::HeightField* hf=dynamic_cast(_object.get()); if (hf) { hf->ref(); _object=NULL; hf->unref_nodelete(); } return hf; } +osg::Node* ReaderWriter::ReadResult::takeNode() { osg::Node* node=dynamic_cast(_object.get()); if (node) { node->ref(); _object=NULL; node->unref_nodelete(); } return node; } +osgDB::Archive* ReaderWriter::ReadResult::takeArchive() { osgDB::Archive* archive=dynamic_cast(_object.get()); if (archive) { archive->ref(); _object=NULL; archive->unref_nodelete(); } return archive; } + ReaderWriter::~ReaderWriter() { } diff --git a/src/osgDB/Registry.cpp b/src/osgDB/Registry.cpp index ee82f8245..f2d105703 100644 --- a/src/osgDB/Registry.cpp +++ b/src/osgDB/Registry.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -1113,6 +1114,162 @@ bool Registry::writeObject(const osg::Object& obj,Output& fw) return false; } + +// +// read object from specified file. +// +ReaderWriter::ReadResult Registry::openArchive(const std::string& fileName, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint) +{ + if (containsServerAddress(fileName)) + { + std::string serverName = getServerAddress(fileName); + std::string serverFile = getServerFileName(fileName); + osg::notify(osg::INFO)<<"Contains sever address : "<openArchive(serverName+":"+serverFile, status, indexBlockSizeHint, _options.get()); + } + else + { + return ReaderWriter::ReadResult("Warning: Could not find the .net plugin to read from server."); + } + } + + // record the errors reported by readerwriters. + typedef std::vector Results; + Results results; + + // first attempt to load the file from existing ReaderWriter's + AvailableReaderWriterIterator itr(_rwList); + for(;itr.valid();++itr) + { + ReaderWriter::ReadResult rr = itr->openArchive(fileName,status, indexBlockSizeHint, _options.get()); + if (rr.validArchive()) return rr; + else results.push_back(rr); + } + + if (!results.empty()) + { + unsigned int num_FILE_NOT_HANDLED = 0; + unsigned int num_FILE_NOT_FOUND = 0; + unsigned int num_ERROR_IN_READING_FILE = 0; + + for(Results::iterator ritr=results.begin(); + ritr!=results.end(); + ++ritr) + { + if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_HANDLED) ++num_FILE_NOT_HANDLED; + else if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND) ++num_FILE_NOT_FOUND; + else if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE) ++num_ERROR_IN_READING_FILE; + } + + if (num_FILE_NOT_HANDLED!=results.size()) + { + // we've come across a file not found or error in reading file. + if (num_ERROR_IN_READING_FILE) + { + osg::notify(osg::NOTICE)<<"Warning: error reading file \""<openArchive(fileName,status, indexBlockSizeHint, _options.get()); + if (rr.validArchive()) return rr; + else results.push_back(rr); + } + } + + if (results.empty()) + { + return ReaderWriter::ReadResult("Warning: Could not find plugin to read objects from file \""+fileName+"\"."); + } + + + return results.front(); +} + +ReaderWriter::ReadResult Registry::openArchiveImplementation(const std::string& fileName, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, CacheHintOptions useObjectCache) +{ + std::string file(fileName); + + if (useObjectCache & CACHE_OBJECTS) + { + // search for entry in the object cache. + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + ObjectCache::iterator oitr=_objectCache.find(file); + if (oitr!=_objectCache.end()) + { + notify(INFO)<<"returning cached instanced of "<(oitr->second.first.get()); + if (archive) return ReaderWriter::ReadResult(archive, ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE); + else return ReaderWriter::ReadResult("Error file does not contain an osg::Object"); + } + } + + PushAndPopDataPath tmpfile(getFilePath(file)); + + ReaderWriter::ReadResult rr = openArchive(file, status, indexBlockSizeHint); + if (rr.validObject()) + { + // update cache with new entry. + notify(INFO)<<"Adding to cache object "< lock(_objectCacheMutex); + tmpObjectCache.swap(_objectCache); + } + + PushAndPopDataPath tmpfile(getFilePath(file)); + + ReaderWriter::ReadResult rr = openArchive(file, status, indexBlockSizeHint); + + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + tmpObjectCache.swap(_objectCache); + } + + return rr; + + } +} + + // // read object from specified file. //