/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__sgi) #include #elif defined(__GNUC__) || !defined(WIN32) || defined(__MWERKS__) #include using std::tolower; #endif #ifdef OSG_LIBRARY_POSTFIX #define OSG_LIBRARY_POSTFIX_WITH_QUOTES ADDQUOTES(OSG_LIBRARY_POSTFIX) #else #define OSG_LIBRARY_POSTFIX_WITH_QUOTES "" #endif using namespace osg; using namespace osgDB; #if !defined(WIN32) || defined(__CYGWIN__) static osg::ApplicationUsageProxy Registry_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_FILE_PATH [:path]..","Paths for locating datafiles"); static osg::ApplicationUsageProxy Registry_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_LIBRARY_PATH [:path]..","Paths for locating libraries/ plugins"); #else static osg::ApplicationUsageProxy Registry_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_FILE_PATH [;path]..","Paths for locating datafiles"); static osg::ApplicationUsageProxy Registry_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_LIBRARY_PATH [;path]..","Paths for locating libraries/ plugins"); #endif static osg::ApplicationUsageProxy Registry_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_BUILD_KDTREES on/off","Enable/disable the automatic building of KdTrees for each loaded Geometry."); // from MimeTypes.cpp extern const char* builtinMimeTypeExtMappings[]; class Registry::AvailableReaderWriterIterator { public: AvailableReaderWriterIterator(Registry::ReaderWriterList& rwList, OpenThreads::ReentrantMutex& pluginMutex): _rwList(rwList), _pluginMutex(pluginMutex) {} ReaderWriter& operator * () { return *get(); } ReaderWriter* operator -> () { return get(); } bool valid() { return get()!=0; } void operator ++() { _rwUsed.insert(get()); } protected: AvailableReaderWriterIterator& operator = (const AvailableReaderWriterIterator&) { return *this; } Registry::ReaderWriterList& _rwList; OpenThreads::ReentrantMutex& _pluginMutex; std::set _rwUsed; ReaderWriter* get() { OpenThreads::ScopedLock lock(_pluginMutex); Registry::ReaderWriterList::iterator itr=_rwList.begin(); for(;itr!=_rwList.end();++itr) { if (_rwUsed.find(itr->get())==_rwUsed.end()) { return itr->get(); } } return 0; } }; class Registry::AvailableArchiveIterator { public: AvailableArchiveIterator(Registry::ArchiveCache& archives, OpenThreads::ReentrantMutex& mutex): _archives(archives), _mutex(mutex) {} Archive& operator * () { return *get(); } Archive* operator -> () { return get(); } bool valid() { return get()!=0; } void operator ++() { _archivesUsed.insert(get()); } protected: AvailableArchiveIterator& operator = (const AvailableArchiveIterator&) { return *this; } Registry::ArchiveCache& _archives; OpenThreads::ReentrantMutex& _mutex; std::set _archivesUsed; Archive* get() { OpenThreads::ScopedLock lock(_mutex); Registry::ArchiveCache::iterator itr=_archives.begin(); for(;itr!=_archives.end();++itr) { if (_archivesUsed.find(itr->second.get())==_archivesUsed.end()) { return itr->second.get(); } } return 0; } }; #if 0 // temporary test of autoregistering, not compiled by default. enum Methods { SET_1, SET_2, END }; typedef std::pair MethodPair; class Proxy { public: Proxy(MethodPair* methods) { std::cout<<"methods "< s_registry = new Registry; if (erase) { s_registry->destruct(); s_registry = 0; } return s_registry.get(); // will return NULL on erase } OSG_INIT_SINGLETON_PROXY(ProxyInitRegistry, Registry::instance()) // definition of the Registry Registry::Registry() { // comment out because it was causing problems under OSX - causing it to crash osgconv when constructing ostream in osg::notify(). // OSG_INFO << "Constructing osg::Registry"< void Registry::initDataFilePathList() { FilePathList filepath; // // set up data file paths // char *ptr; if( (ptr = getenv( "OSG_FILE_PATH" )) ) { //OSG_NOTIFY(DEBUG_INFO) << "OSG_FILE_PATH("<addCommandLineOption("-l ","Load the plugin"); arguments.getApplicationUsage()->addCommandLineOption("-e ","Load the plugin associated with handling files with specified extension"); arguments.getApplicationUsage()->addCommandLineOption("-O ","Provide an option string to reader/writers used to load databases"); } std::string value; while(arguments.read("-l",value)) { if (loadLibrary(value)==NOT_LOADED) { OSG_NOTICE<<"Unable to load library : "<className()<<")"<< std::endl; OpenThreads::ScopedLock lock(_pluginMutex); _rwList.push_back(rw); } void Registry::removeReaderWriter(ReaderWriter* rw) { if (rw==0L) return; // OSG_NOTIFY(INFO) << "osg::Registry::removeReaderWriter();"<< std::endl; OpenThreads::ScopedLock lock(_pluginMutex); ReaderWriterList::iterator rwitr = std::find(_rwList.begin(),_rwList.end(),rw); if (rwitr!=_rwList.end()) { _rwList.erase(rwitr); } } ImageProcessor* Registry::getImageProcessor() { { OpenThreads::ScopedLock lock(_pluginMutex); if (!_ipList.empty()) { return _ipList.front().get(); } } return getImageProcessorForExtension("nvtt"); } ImageProcessor* Registry::getImageProcessorForExtension(const std::string& ext) { { OpenThreads::ScopedLock lock(_pluginMutex); if (!_ipList.empty()) { return _ipList.front().get(); } } std::string libraryName = createLibraryNameForExtension(ext); OSG_NOTICE << "Now checking for plug-in "< lock(_pluginMutex); if (!_ipList.empty()) { OSG_NOTICE << "Loaded plug-in "<className()<<")"<< std::endl; OpenThreads::ScopedLock lock(_pluginMutex); _ipList.push_back(ip); } void Registry::removeImageProcessor(ImageProcessor* ip) { if (ip==0L) return; OSG_NOTIFY(NOTICE) << "osg::Registry::removeImageProcessor();"<< std::endl; OpenThreads::ScopedLock lock(_pluginMutex); ImageProcessorList::iterator ipitr = std::find(_ipList.begin(),_ipList.end(),ip); if (ipitr!=_ipList.end()) { _ipList.erase(ipitr); } } void Registry::addFileExtensionAlias(const std::string mapExt, const std::string toExt) { _extAliasMap[mapExt] = toExt; } void Registry::addMimeTypeExtensionMapping(const std::string fromMimeType, const std::string toExt) { _mimeTypeExtMap[fromMimeType] = toExt; } bool Registry::readPluginAliasConfigurationFile( const std::string& file ) { std::string fileName = osgDB::findDataFile( file ); if (fileName.empty()) { OSG_NOTIFY( osg::WARN) << "Can't find plugin alias config file \"" << file << "\"." << std::endl; return false; } osgDB::ifstream ifs; ifs.open( fileName.c_str() ); if (!ifs.good()) { OSG_NOTIFY( osg::WARN) << "Can't open plugin alias config file \"" << fileName << "\"." << std::endl; return false; } int lineNum( 0 ); while (ifs.good()) { std::string raw; ++lineNum; std::getline( ifs, raw ); std::string ln = trim( raw ); if (ln.empty()) continue; if (ln[0] == '#') continue; std::string::size_type spIdx = ln.find_first_of( " \t" ); if (spIdx == ln.npos) { // mapExt and toExt must be on the same line, separated by a space. OSG_NOTIFY( osg::WARN) << file << ", line " << lineNum << ": Syntax error: missing space in \"" << raw << "\"." << std::endl; continue; } const std::string mapExt = trim( ln.substr( 0, spIdx ) ); const std::string toExt = trim( ln.substr( spIdx+1 ) ); addFileExtensionAlias( mapExt, toExt ); } return true; } std::string Registry::trim( const std::string& str ) { if (!str.size()) return str; std::string::size_type first = str.find_first_not_of( " \t" ); std::string::size_type last = str.find_last_not_of( " \t\r\n" ); if ((first==str.npos) || (last==str.npos)) return std::string( "" ); return str.substr( first, last-first+1 ); } std::string Registry::createLibraryNameForFile(const std::string& fileName) { return createLibraryNameForExtension(getFileExtension(fileName)); } std::string Registry::createLibraryNameForExtension(const std::string& ext) { std::string lowercase_ext; for(std::string::const_iterator sitr=ext.begin(); sitr!=ext.end(); ++sitr) { lowercase_ext.push_back(tolower(*sitr)); } ExtensionAliasMap::iterator itr=_extAliasMap.find(lowercase_ext); if (itr!=_extAliasMap.end() && ext != itr->second) return createLibraryNameForExtension(itr->second); std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/"); #if defined(__CYGWIN__) return prepend+"cygwin_"+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll"; #elif defined(__MINGW32__) return prepend+"mingw_"+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll"; #elif defined(WIN32) return prepend+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll"; #elif macintosh return prepend+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES; #else return prepend+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+ADDQUOTES(OSG_PLUGIN_EXTENSION); #endif } std::string Registry::createLibraryNameForNodeKit(const std::string& name) { #if defined(__CYGWIN__) return "cyg"+name+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll"; #elif defined(__MINGW32__) return "lib"+name+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll"; #elif defined(WIN32) return name+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll"; #elif macintosh return name+OSG_LIBRARY_POSTFIX_WITH_QUOTES; #else return "lib"+name+OSG_LIBRARY_POSTFIX_WITH_QUOTES + ADDQUOTES(OSG_PLUGIN_EXTENSION); #endif } Registry::LoadStatus Registry::loadLibrary(const std::string& fileName) { OpenThreads::ScopedLock lock(_pluginMutex); DynamicLibraryList::iterator ditr = getLibraryItr(fileName); if (ditr!=_dlList.end()) return PREVIOUSLY_LOADED; _openingLibrary=true; DynamicLibrary* dl = DynamicLibrary::loadLibrary(fileName); _openingLibrary=false; if (dl) { _dlList.push_back(dl); return LOADED; } return NOT_LOADED; } bool Registry::closeLibrary(const std::string& fileName) { OpenThreads::ScopedLock lock(_pluginMutex); DynamicLibraryList::iterator ditr = getLibraryItr(fileName); if (ditr!=_dlList.end()) { _dlList.erase(ditr); return true; } return false; } void Registry::closeAllLibraries() { // OSG_NOTICE<<"Registry::closeAllLibraries()"< lock(_pluginMutex); _dlList.clear(); } Registry::DynamicLibraryList::iterator Registry::getLibraryItr(const std::string& fileName) { DynamicLibraryList::iterator ditr = _dlList.begin(); for(;ditr!=_dlList.end();++ditr) { if ((*ditr)->getName()==fileName) return ditr; } return _dlList.end(); } DynamicLibrary* Registry::getLibrary(const std::string& fileName) { OpenThreads::ScopedLock lock(_pluginMutex); DynamicLibraryList::iterator ditr = getLibraryItr(fileName); if (ditr!=_dlList.end()) return ditr->get(); else return NULL; } ReaderWriter* Registry::getReaderWriterForExtension(const std::string& ext) { // record the existing reader writer. std::set rwOriginal; OpenThreads::ScopedLock lock(_pluginMutex); // first attempt one of the installed loaders for(ReaderWriterList::iterator itr=_rwList.begin(); itr!=_rwList.end(); ++itr) { rwOriginal.insert(itr->get()); if((*itr)->acceptsExtension(ext)) return (*itr).get(); } // now look for a plug-in to load the file. std::string libraryName = createLibraryNameForExtension(ext); OSG_NOTIFY(INFO) << "Now checking for plug-in "<get())==rwOriginal.end()) { if((*itr)->acceptsExtension(ext)) return (*itr).get(); } } } return NULL; } ReaderWriter* Registry::getReaderWriterForMimeType(const std::string& mimeType) { MimeTypeExtensionMap::const_iterator i = _mimeTypeExtMap.find( mimeType ); return i != _mimeTypeExtMap.end()? getReaderWriterForExtension( i->second ) : NULL; } #if 0 struct concrete_wrapper: basic_type_wrapper { virtual ~concrete_wrapper() {} concrete_wrapper(const osg::Object *myobj) : myobj_(myobj) {} bool matches(const osg::Object *proto) const { return myobj_->isSameKindAs(proto); } const osg::Object *myobj_; }; #endif struct Registry::ReadObjectFunctor : public Registry::ReadFunctor { ReadObjectFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {} virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readObject(_filename, _options); } virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validObject(); } virtual bool isValid(osg::Object* object) const { return object!=0; } virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadObjectFunctor(filename, options); } }; struct Registry::ReadImageFunctor : public Registry::ReadFunctor { ReadImageFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {} virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const { return rw.readImage(_filename, _options); } virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validImage(); } virtual bool isValid(osg::Object* object) const { return dynamic_cast(object)!=0; } virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadImageFunctor(filename, options); } }; struct Registry::ReadHeightFieldFunctor : public Registry::ReadFunctor { ReadHeightFieldFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {} virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readHeightField(_filename, _options); } virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validHeightField(); } virtual bool isValid(osg::Object* object) const { return dynamic_cast(object)!=0; } virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadHeightFieldFunctor(filename, options); } }; struct Registry::ReadNodeFunctor : public Registry::ReadFunctor { ReadNodeFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {} virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readNode(_filename, _options); } virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validNode(); } virtual bool isValid(osg::Object* object) const { return dynamic_cast(object)!=0; } virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadNodeFunctor(filename, options); } }; struct Registry::ReadArchiveFunctor : public Registry::ReadFunctor { ReadArchiveFunctor(const std::string& filename, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const Options* options): ReadFunctor(filename,options), _status(status), _indexBlockSizeHint(indexBlockSizeHint) {} ReaderWriter::ArchiveStatus _status; unsigned int _indexBlockSizeHint; virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.openArchive(_filename, _status, _indexBlockSizeHint, _options); } virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validArchive(); } virtual bool isValid(osg::Object* object) const { return dynamic_cast(object)!=0; } virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadArchiveFunctor(filename, _status, _indexBlockSizeHint, options); } }; struct Registry::ReadShaderFunctor : public Registry::ReadFunctor { ReadShaderFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {} virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const { return rw.readShader(_filename, _options); } virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validShader(); } virtual bool isValid(osg::Object* object) const { return dynamic_cast(object)!=0; } virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadShaderFunctor(filename, options); } }; struct Registry::ReadScriptFunctor : public Registry::ReadFunctor { ReadScriptFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {} virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const { return rw.readScript(_filename, _options); } virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validScript(); } virtual bool isValid(osg::Object* object) const { return dynamic_cast(object)!=0; } virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadScriptFunctor(filename, options); } }; void Registry::addArchiveExtension(const std::string ext) { for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin(); aitr!=_archiveExtList.end(); ++aitr) { if ( (*aitr) == ext) // extension already in archive extension list return; } _archiveExtList.push_back(ext); } std::string Registry::findDataFileImplementation(const std::string& filename, const Options* options, CaseSensitivity caseSensitivity) { if (filename.empty()) return filename; // if data file contains a server address then we can't find it in local directories so return empty string. if (containsServerAddress(filename)) return std::string(); bool absolutePath = osgDB::isAbsolutePath(filename); if (absolutePath && fileExists(filename)) { OSG_DEBUG << "FindFileInPath(" << filename << "): returning " << filename << std::endl; return filename; } std::string fileFound; bool pathsContainsCurrentWorkingDirectory = false; if (options && !options->getDatabasePathList().empty()) { fileFound = findFileInPath(filename, options->getDatabasePathList(), caseSensitivity); if (!fileFound.empty()) return fileFound; if (osgDB::containsCurrentWorkingDirectoryReference(options->getDatabasePathList())) { pathsContainsCurrentWorkingDirectory = true; } } const FilePathList& filepaths = Registry::instance()->getDataFilePathList(); if (!filepaths.empty()) { fileFound = findFileInPath(filename, filepaths, caseSensitivity); if (!fileFound.empty()) return fileFound; if (!pathsContainsCurrentWorkingDirectory && osgDB::containsCurrentWorkingDirectoryReference(filepaths)) { pathsContainsCurrentWorkingDirectory = true; } } if (!absolutePath && !pathsContainsCurrentWorkingDirectory) { // check current working directory if (fileExists(filename)) { return filename; } } // if a directory is included in the filename, get just the (simple) filename itself and try that std::string simpleFileName = getSimpleFileName(filename); if (simpleFileName!=filename) { if(fileExists(simpleFileName)) { OSG_DEBUG << "FindFileInPath(" << filename << "): returning " << simpleFileName << std::endl; return simpleFileName; } if (options && !options->getDatabasePathList().empty()) { fileFound = findFileInPath(simpleFileName, options->getDatabasePathList(), caseSensitivity); if (!fileFound.empty()) return fileFound; } if (!filepaths.empty()) { fileFound = findFileInPath(simpleFileName, filepaths,caseSensitivity); if (!fileFound.empty()) return fileFound; } } // return empty string. return std::string(); } std::string Registry::findLibraryFileImplementation(const std::string& filename, const Options* /*options*/, CaseSensitivity caseSensitivity) { if (filename.empty()) return filename; const FilePathList& filepath = Registry::instance()->getLibraryFilePathList(); std::string fileFound = findFileInPath(filename, filepath,caseSensitivity); if (!fileFound.empty()) return fileFound; if(fileExists(filename)) { OSG_DEBUG << "FindFileInPath(" << filename << "): returning " << filename << std::endl; return filename; } // if a directory is included in the filename, get just the (simple) filename itself and try that std::string simpleFileName = getSimpleFileName(filename); if (simpleFileName!=filename) { fileFound = findFileInPath(simpleFileName, filepath,caseSensitivity); if (!fileFound.empty()) return fileFound; } // failed return empty string. return std::string(); } ReaderWriter::ReadResult Registry::read(const ReadFunctor& readFunctor) { for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin(); aitr!=_archiveExtList.end(); ++aitr) { std::string archiveExtension = "." + (*aitr); std::string::size_type positionArchive = readFunctor._filename.find(archiveExtension+'/'); if (positionArchive==std::string::npos) positionArchive = readFunctor._filename.find(archiveExtension+'\\'); if (positionArchive!=std::string::npos) { std::string::size_type endArchive = positionArchive + archiveExtension.length(); std::string archiveName( readFunctor._filename.substr(0,endArchive)); std::string fileName(readFunctor._filename.substr(endArchive+1,std::string::npos)); OSG_INFO<<"Contains archive : "< options = readFunctor._options ? readFunctor._options->cloneOptions() : new osgDB::ReaderWriter::Options; options->setDatabasePath(archiveName); osg::ref_ptr rf(readFunctor.cloneType(fileName, options.get())); result = rf->doRead(*archive); if (rf->isValid(result)) { OSG_INFO<<"Read object from archive"< Results; Results results; // first attempt to load the file from existing ReaderWriter's AvailableReaderWriterIterator itr(_rwList, _pluginMutex); for(;itr.valid();++itr) { ReaderWriter::ReadResult rr = readFunctor.doRead(*itr); if (readFunctor.isValid(rr)) return rr; else results.push_back(rr); } // check loaded archives. AvailableArchiveIterator aaitr(_archiveCache, _archiveCacheMutex); for(;aaitr.valid();++aaitr) { ReaderWriter::ReadResult rr = readFunctor.doRead(*aaitr); if (readFunctor.isValid(rr)) return rr; else { // don't pass on FILE_NOT_FOUND results as we don't want to prevent non archive plugins that haven't been // loaded yet from getting a chance to test for the presence of the file. if (rr.status()!=ReaderWriter::ReadResult::FILE_NOT_FOUND) results.push_back(rr); } } // now look for a plug-in to load the file. std::string libraryName = createLibraryNameForFile(readFunctor._filename); if (loadLibrary(libraryName)!=NOT_LOADED) { for(;itr.valid();++itr) { ReaderWriter::ReadResult rr = readFunctor.doRead(*itr); if (readFunctor.isValid(rr)) return rr; else results.push_back(rr); } } //If the filename contains a server address and wasn't loaded by any of the plugins, try to find a plugin which supports the server //protocol and supports wildcards. If not successfully use curl as a last fallback if (containsServerAddress(readFunctor._filename)) { ReaderWriter* rw = getReaderWriterForProtocolAndExtension( osgDB::getServerProtocol(readFunctor._filename), osgDB::getFileExtension(readFunctor._filename) ); if (rw) { return readFunctor.doRead(*rw); } else { return ReaderWriter::ReadResult("Could not find the .curl plugin to read from server."); } } if (results.empty()) { return ReaderWriter::ReadResult("Could not find plugin to read objects from file \""+readFunctor._filename+"\"."); } // sort the results so the most relevant (i.e. ERROR_IN_READING_FILE is more relevant than FILE_NOT_FOUND) results get placed at the end of the results list. std::sort(results.begin(), results.end()); ReaderWriter::ReadResult result = results.back(); return result; } ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFunctor,Options::CacheHintOptions cacheHint) { std::string file(readFunctor._filename); bool useObjectCache = false; const Options* options = readFunctor._options; ObjectCache* optionsCache = options ? options->getObjectCache() : 0; //Note CACHE_ARCHIVES has a different object that it caches to so it will never be used here if ((optionsCache || _objectCache.valid()) && cacheHint!=Options::CACHE_ARCHIVES) { useObjectCache= options ? (options->getObjectCacheHint()&cacheHint)!=0: false; } if (useObjectCache) { // search for entry in the object cache. osg::ref_ptr object = optionsCache ? optionsCache->getRefFromObjectCache(file, options) : 0; if (!object && _objectCache.valid()) object = _objectCache->getRefFromObjectCache(file, options); if (object.valid()) { if (readFunctor.isValid(object.get())) return ReaderWriter::ReadResult(object.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE); else return ReaderWriter::ReadResult("Error file does not contain an osg::Object"); } ReaderWriter::ReadResult rr = read(readFunctor); if (rr.validObject()) { // search AGAIN for entry in the object cache. object = _objectCache->getRefFromObjectCache(file, options); if (object.valid()) { if (readFunctor.isValid(object.get())) return ReaderWriter::ReadResult(object.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE); else { return ReaderWriter::ReadResult("Error file does not contain an osg::Object"); } } // update cache with new entry. if (optionsCache) optionsCache->addEntryToObjectCache(file, rr.getObject(), 0.0, options); else if (_objectCache.valid()) _objectCache->addEntryToObjectCache(file, rr.getObject(), 0.0, options); } else { OSG_INFO<<"No valid object found for "< archive = getRefFromArchiveCache(fileName); if (archive.valid()) return archive.get(); ReaderWriter::ReadResult result = readImplementation(ReadArchiveFunctor(fileName, status, indexBlockSizeHint, options),Options::CACHE_ARCHIVES); // default to using caching archive if no options structure provided, but if options are provided use archives // only if supplied. if (result.validArchive() && (!options || (options->getObjectCacheHint() & Options::CACHE_ARCHIVES)) ) { addToArchiveCache(fileName,result.getArchive()); } return result; } ReaderWriter::ReadResult Registry::readObjectImplementation(const std::string& fileName,const Options* options) { return readImplementation(ReadObjectFunctor(fileName, options),Options::CACHE_OBJECTS); } ReaderWriter::WriteResult Registry::writeObjectImplementation(const Object& obj,const std::string& fileName,const Options* options) { // 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, _pluginMutex); for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } // now look for a plug-in to save the file. std::string libraryName = createLibraryNameForFile(fileName); if (loadLibrary(libraryName)==LOADED) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Could not find plugin to write objects to file \""+fileName+"\"."); } // sort the results so the most relevant (i.e. ERROR_IN_WRITING_FILE is more relevant than FILE_NOT_FOUND) results get placed at the end of the results list. std::sort(results.begin(), results.end()); ReaderWriter::WriteResult result = results.back(); return result; } ReaderWriter::ReadResult Registry::readImageImplementation(const std::string& fileName,const Options* options) { return readImplementation(ReadImageFunctor(fileName, options),Options::CACHE_IMAGES); } ReaderWriter::WriteResult Registry::writeImageImplementation(const Image& image,const std::string& fileName,const Options* options) { // 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, _pluginMutex); for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } // now look for a plug-in to save the file. std::string libraryName = createLibraryNameForFile(fileName); if (loadLibrary(libraryName)==LOADED) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Could not find plugin to write image to file \""+fileName+"\"."); } // sort the results so the most relevant (i.e. ERROR_IN_WRITING_FILE is more relevant than FILE_NOT_FOUND) results get placed at the end of the results list. std::sort(results.begin(), results.end()); ReaderWriter::WriteResult result = results.back(); return result; } ReaderWriter::ReadResult Registry::readHeightFieldImplementation(const std::string& fileName,const Options* options) { return readImplementation(ReadHeightFieldFunctor(fileName, options),Options::CACHE_HEIGHTFIELDS); } ReaderWriter::WriteResult Registry::writeHeightFieldImplementation(const HeightField& HeightField,const std::string& fileName,const Options* options) { // 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, _pluginMutex); for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } // now look for a plug-in to save the file. std::string libraryName = createLibraryNameForFile(fileName); if (loadLibrary(libraryName)==LOADED) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Could not find plugin to write HeightField to file \""+fileName+"\"."); } // sort the results so the most relevant (i.e. ERROR_IN_WRITING_FILE is more relevant than FILE_NOT_FOUND) results get placed at the end of the results list. std::sort(results.begin(), results.end()); ReaderWriter::WriteResult result = results.back(); return result; } ReaderWriter::ReadResult Registry::readNodeImplementation(const std::string& fileName,const Options* options) { #if 0 osg::Timer_t startTick = osg::Timer::instance()->tick(); ReaderWriter::ReadResult result = readImplementation(ReadNodeFunctor(fileName, options),Options::CACHE_NODES); osg::Timer_t endTick = osg::Timer::instance()->tick(); OSG_NOTICE<<"time to load "<delta_m(startTick, endTick)<<"ms"< Results; Results results; // first attempt to write the file from existing ReaderWriter's AvailableReaderWriterIterator itr(_rwList, _pluginMutex); for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } // now look for a plug-in to save the file. std::string libraryName = createLibraryNameForFile(fileName); if (loadLibrary(libraryName)==LOADED) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Could not find plugin to write nodes to file \""+fileName+"\"."); } // sort the results so the most relevant (i.e. ERROR_IN_WRITING_FILE is more relevant than FILE_NOT_FOUND) results get placed at the end of the results list. std::sort(results.begin(), results.end()); ReaderWriter::WriteResult result = results.back(); return result; } ReaderWriter::ReadResult Registry::readShaderImplementation(const std::string& fileName,const Options* options) { return readImplementation(ReadShaderFunctor(fileName, options),Options::CACHE_SHADERS); } ReaderWriter::WriteResult Registry::writeShaderImplementation(const Shader& shader,const std::string& fileName,const Options* options) { // 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, _pluginMutex); for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } results.clear(); // now look for a plug-in to save the file. std::string libraryName = createLibraryNameForFile(fileName); if (loadLibrary(libraryName)==LOADED) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Could not find plugin to write shader to file \""+fileName+"\"."); } // sort the results so the most relevant (i.e. ERROR_IN_WRITING_FILE is more relevant than FILE_NOT_FOUND) results get placed at the end of the results list. std::sort(results.begin(), results.end()); ReaderWriter::WriteResult result = results.back(); return result; } ReaderWriter::ReadResult Registry::readScriptImplementation(const std::string& fileName,const Options* options) { return readImplementation(ReadScriptFunctor(fileName, options),Options::CACHE_IMAGES); } ReaderWriter::WriteResult Registry::writeScriptImplementation(const Script& image,const std::string& fileName,const Options* options) { // 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, _pluginMutex); for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeScript(image,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } // now look for a plug-in to save the file. std::string libraryName = createLibraryNameForFile(fileName); if (loadLibrary(libraryName)==LOADED) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeScript(image,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Could not find plugin to write image to file \""+fileName+"\"."); } // sort the results so the most relevant (i.e. ERROR_IN_WRITING_FILE is more relevant than FILE_NOT_FOUND) results get placed at the end of the results list. std::sort(results.begin(), results.end()); ReaderWriter::WriteResult result = results.back(); return result; } void Registry::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp, Options *options) { if (_objectCache.valid()) _objectCache->addEntryToObjectCache(filename, object, timestamp, options); } osg::Object* Registry::getFromObjectCache(const std::string& filename, Options *options) { return _objectCache.valid() ? _objectCache->getFromObjectCache(filename, options) : 0; } osg::ref_ptr Registry::getRefFromObjectCache(const std::string& filename, Options *options) { return _objectCache.valid() ? _objectCache->getRefFromObjectCache(filename, options) : 0; } void Registry::updateTimeStampOfObjectsInCacheWithExternalReferences(const osg::FrameStamp& frameStamp) { if (_objectCache.valid()) _objectCache->updateTimeStampOfObjectsInCacheWithExternalReferences(frameStamp.getReferenceTime()); } void Registry::removeExpiredObjectsInCache(const osg::FrameStamp& frameStamp) { double expiryTime = frameStamp.getReferenceTime() - _expiryDelay; if (_objectCache.valid()) _objectCache->removeExpiredObjectsInCache(expiryTime); } void Registry::removeFromObjectCache(const std::string& filename, Options *options) { if (_objectCache.valid()) _objectCache->removeFromObjectCache(filename, options); } void Registry::clearObjectCache() { if (_objectCache.valid()) _objectCache->clear(); } void Registry::addToArchiveCache(const std::string& fileName, osgDB::Archive* archive) { OpenThreads::ScopedLock lock(_archiveCacheMutex); _archiveCache[fileName] = archive; } /** Remove archive from cache.*/ void Registry::removeFromArchiveCache(const std::string& fileName) { OpenThreads::ScopedLock lock(_archiveCacheMutex); ArchiveCache::iterator itr = _archiveCache.find(fileName); if (itr!=_archiveCache.end()) { _archiveCache.erase(itr); } } osgDB::Archive* Registry::getFromArchiveCache(const std::string& fileName) { OpenThreads::ScopedLock lock(_archiveCacheMutex); ArchiveCache::iterator itr = _archiveCache.find(fileName); if (itr!=_archiveCache.end()) return itr->second.get(); else return 0; } osg::ref_ptr Registry::getRefFromArchiveCache(const std::string& fileName) { OpenThreads::ScopedLock lock(_archiveCacheMutex); ArchiveCache::iterator itr = _archiveCache.find(fileName); if (itr!=_archiveCache.end()) return itr->second; else return 0; } void Registry::clearArchiveCache() { OpenThreads::ScopedLock lock(_archiveCacheMutex); _archiveCache.clear(); } void Registry::releaseGLObjects(osg::State* state) { if (_objectCache.valid()) _objectCache->releaseGLObjects( state ); if (_sharedStateManager.valid()) _sharedStateManager->releaseGLObjects( state ); } SharedStateManager* Registry::getOrCreateSharedStateManager() { if (!_sharedStateManager) _sharedStateManager = new SharedStateManager; return _sharedStateManager.get(); } void Registry::registerProtocol(const std::string& protocol) { _registeredProtocols.insert( convertToLowerCase(protocol) ); } bool Registry::isProtocolRegistered(const std::string& protocol) { return (_registeredProtocols.find( convertToLowerCase(protocol) ) != _registeredProtocols.end()); } void Registry::getReaderWriterListForProtocol(const std::string& protocol, ReaderWriterList& results) const { for(ReaderWriterList::const_iterator i = _rwList.begin(); i != _rwList.end(); ++i) { if ((*i)->acceptsProtocol(protocol)) results.push_back(*i); } } ReaderWriter* Registry::getReaderWriterForProtocolAndExtension(const std::string& protocol, const std::string& extension) { // try first the registered ReaderWriter ReaderWriter* result = getReaderWriterForExtension(extension); if (result && result->acceptsProtocol(protocol)) return result; result = NULL; ReaderWriterList results; getReaderWriterListForProtocol(protocol, results); for(ReaderWriterList::const_iterator i = results.begin(); i != results.end(); ++i) { // if we have a readerwriter which supports wildcards, save it as a fallback if ((*i)->acceptsExtension("*")) result = i->get(); else if ((*i)->acceptsExtension(extension)) return i->get(); } return result ? result : getReaderWriterForExtension("curl"); }