/* -*-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 using namespace osg; using namespace osgDB; class Registry::AvailableReaderWriterIterator { public: AvailableReaderWriterIterator(Registry::ReaderWriterList& rwList): _rwList(rwList) {} ReaderWriter& operator * () { return *get(); } ReaderWriter* operator -> () { return get(); } bool valid() { return get()!=0; } void operator ++() { _rwUsed.insert(get()); } protected: Registry::ReaderWriterList& _rwList; std::set _rwUsed; ReaderWriter* get() { Registry::ReaderWriterList::iterator itr=_rwList.begin(); for(;itr!=_rwList.end();++itr) { if (_rwUsed.find(itr->get())==_rwUsed.end()) { return itr->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 = 0; } return s_registry.get(); // will return NULL on erase } // definition of the Registry Registry::Registry() { // comment out because it was causing problems under OSX - causing it to crash osgconv when constucting ostream in osg::notify(). // notify(INFO) << "Constructing osg::Registry"<[:path]..","Paths for locating datafiles"); #else static osg::ApplicationUsageProxy Registry_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_FILE_PATH [;path]..","Paths for locating datafiles"); #endif #include void Registry::initDataFilePathList() { FilePathList filepath; // // set up data file paths // char *ptr; if( (ptr = getenv( "OSG_FILE_PATH" )) ) { //notify(DEBUG_INFO) << "OSG_FILE_PATH("<[:path]..","Paths for locating libraries/ plugins"); #else static osg::ApplicationUsageProxy Registry_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_LIBRARY_PATH [;path]..","Paths for locating libraries/ plugins"); #endif void Registry::initLibraryFilePathList() { // // set up library paths // char* ptr; if( (ptr = getenv( "OSG_LIBRARY_PATH")) ) { //notify(DEBUG_INFO) << "OSG_LIBRARY_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)) { loadLibrary(value); } while(arguments.read("-e",value)) { std::string libName = createLibraryNameForExtension(value); loadLibrary(libName); } while(arguments.read("-O",value)) { setOptions(new osgDB::ReaderWriter::Options(value)); } } void Registry::addDotOsgWrapper(DotOsgWrapper* wrapper) { if (wrapper==0L) return; //notify(INFO) << "osg::Registry::addDotOsgWrapper("<getName()<<")"<< std::endl; const DotOsgWrapper::Associates& assoc = wrapper->getAssociates(); for(DotOsgWrapper::Associates::const_iterator itr=assoc.begin(); itr!=assoc.end(); ++itr) { //notify(INFO) << " ("<<*itr<<")"<< std::endl; } const std::string& name = wrapper->getName(); const osg::Object* proto = wrapper->getPrototype(); _objectWrapperMap[name] = wrapper; if (wrapper->getReadWriteMode()==DotOsgWrapper::READ_AND_WRITE) _classNameWrapperMap[name] = wrapper; if (proto) { std::string libraryName = proto->libraryName(); std::string compositeName = libraryName + "::" + name; _objectWrapperMap[compositeName] = wrapper; if (wrapper->getReadWriteMode()==DotOsgWrapper::READ_AND_WRITE) _classNameWrapperMap[compositeName] = wrapper; if (dynamic_cast(proto)) { _imageWrapperMap[name] = wrapper; _imageWrapperMap[compositeName] = wrapper; } if (dynamic_cast(proto)) { _drawableWrapperMap[name] = wrapper; _drawableWrapperMap[compositeName] = wrapper; } if (dynamic_cast(proto)) { _stateAttrWrapperMap[name] = wrapper; _stateAttrWrapperMap[compositeName] = wrapper; } if (dynamic_cast(proto)) { _uniformWrapperMap[name] = wrapper; _uniformWrapperMap[compositeName] = wrapper; } if (dynamic_cast(proto)) { _nodeWrapperMap[name] = wrapper; _nodeWrapperMap[compositeName] = wrapper; } } } // need to change to delete all instances of wrapper, since we // now can have a wrapper entered twice with the addition of the // library::class composite name. void Registry::eraseWrapper(DotOsgWrapperMap& wrappermap,DotOsgWrapper* wrapper) { typedef std::vector EraseList; EraseList eraseList; for(DotOsgWrapperMap::iterator witr=wrappermap.begin(); witr!=wrappermap.end(); ++witr) { if (witr->second==wrapper) eraseList.push_back(witr); } for(EraseList::iterator eitr=eraseList.begin(); eitr!=eraseList.end(); ++eitr) { wrappermap.erase(*eitr); } } void Registry::removeDotOsgWrapper(DotOsgWrapper* wrapper) { if (wrapper==0L) return; eraseWrapper(_objectWrapperMap,wrapper); eraseWrapper(_classNameWrapperMap,wrapper); eraseWrapper(_imageWrapperMap,wrapper); eraseWrapper(_drawableWrapperMap,wrapper); eraseWrapper(_uniformWrapperMap,wrapper); eraseWrapper(_stateAttrWrapperMap,wrapper); eraseWrapper(_nodeWrapperMap,wrapper); } void Registry::addReaderWriter(ReaderWriter* rw) { if (rw==0L) return; // notify(INFO) << "osg::Registry::addReaderWriter("<className()<<")"<< std::endl; _rwList.push_back(rw); } void Registry::removeReaderWriter(ReaderWriter* rw) { if (rw==0L) return; // notify(INFO) << "osg::Registry::removeReaderWriter();"<< std::endl; ReaderWriterList::iterator rwitr = std::find(_rwList.begin(),_rwList.end(),rw); if (rwitr!=_rwList.end()) { _rwList.erase(rwitr); } } void Registry::addFileExtensionAlias(const std::string mapExt, const std::string toExt) { _extAliasMap[mapExt] = 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; } std::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) { std::string ext = getLowerCaseFileExtension(fileName); return createLibraryNameForExtension(ext); } std::string Registry::createLibraryNameForExtension(const std::string& ext) { ExtensionAliasMap::iterator itr=_extAliasMap.find(ext); if (itr!=_extAliasMap.end() && ext != itr->second) return createLibraryNameForExtension(itr->second); #ifdef OSG_JAVA_BUILD static std::string prepend = "java"; #else static std::string prepend = ""; #endif #if defined(WIN32) // !! recheck evolving Cygwin DLL extension naming protocols !! NHV #ifdef __CYGWIN__ return "cyg"+prepend+"osgdb_"+ext+".dll"; #elif defined(__MINGW32__) return "lib"+prepend+"osgdb_"+ext+".dll"; #else #ifdef _DEBUG return prepend+"osgdb_"+ext+"d.dll"; #else return prepend+"osgdb_"+ext+".dll"; #endif #endif #elif macintosh return prepend+"osgdb_"+ext; #elif defined(__hpux__) // why don't we use PLUGIN_EXT from the makefiles here? return prepend+"osgdb_"+ext+".sl"; #else return prepend+"osgdb_"+ext+".so"; #endif } std::string Registry::createLibraryNameForNodeKit(const std::string& name) { #if defined(WIN32) // !! recheck evolving Cygwin DLL extension naming protocols !! NHV #ifdef __CYGWIN__ // [ return "cyg"+name+".dll"; #elif defined(__MINGW32__) return "lib"+name+".dll"; #else #ifdef _DEBUG return name+"d.dll"; #else return name+".dll"; #endif #endif #elif macintosh return name; #elif defined(__hpux__) // why don't we use PLUGIN_EXT from the makefiles here? return "lib"+name+".sl"; #else return "lib"+name+".so"; #endif } bool Registry::loadLibrary(const std::string& fileName) { DynamicLibrary* dl = getLibrary(fileName); if (dl) return false; _openingLibrary=true; dl = DynamicLibrary::loadLibrary(fileName); _openingLibrary=false; if (dl) { _dlList.push_back(dl); return true; } return false; } bool Registry::closeLibrary(const std::string& fileName) { DynamicLibraryList::iterator ditr = getLibraryItr(fileName); if (ditr!=_dlList.end()) { _dlList.erase(ditr); return true; } return false; } void Registry::closeAllLibraries() { _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) { 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; // first attemt 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); notify(INFO) << "Now checking for plug-in "<get())==rwOriginal.end()) if((*itr)->acceptsExtension(ext)) return (*itr).get(); } } return NULL; } 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_; }; osg::Object* Registry::readObjectOfType(const osg::Object& compObj,Input& fr) { return readObjectOfType(concrete_wrapper(&compObj), fr); } osg::Object* Registry::readObjectOfType(const basic_type_wrapper &btw,Input& fr) { const char *str = fr[0].getStr(); if (str==NULL) return NULL; if (fr[0].matchWord("Use")) { if (fr[1].isString()) { Object* obj = fr.getObjectForUniqueID(fr[1].getStr()); if (obj && btw.matches(obj)) { fr+=2; return obj; } } else return NULL; } std::string name = str; DotOsgWrapperMap::iterator itr = _objectWrapperMap.find(name); if (itr==_objectWrapperMap.end()) { // not found so check if a library::class composite name. std::string token = fr[0].getStr(); std::string::size_type posDoubleColon = token.rfind("::"); if (posDoubleColon != std::string::npos) { // we have a composite name so now strip off the library name // are try to load it, and then retry the readObject to see // if we can recongise the objects. std::string libraryName = std::string(token,0,posDoubleColon); // first try the standard nodekit library. std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName); if (loadLibrary(nodeKitLibraryName)) return readObjectOfType(btw,fr); // otherwise try the osgdb_ plugin library. std::string pluginLibraryName = createLibraryNameForExtension(libraryName); if (loadLibrary(pluginLibraryName)) return readObjectOfType(btw,fr); } } else if (fr[1].isOpenBracket()) { DotOsgWrapper* wrapper = itr->second.get(); const osg::Object* proto = wrapper->getPrototype(); if (proto==NULL) { osg::notify(osg::WARN)<<"Token "<getAssociates(); osg::Object* obj = proto->cloneType(); while(!fr.eof() && fr[0].getNoNestedBrackets()>entry) { bool iteratorAdvanced = false; if (fr[0].matchWord("UniqueID") && fr[1].isString()) { fr.regisiterUniqueIDForObject(fr[1].getStr(),obj); fr += 2; iteratorAdvanced = true; } // read the local data by iterating through the associate // list, mapping the associate names to DotOsgWrapper's which // in turn have the appropriate functions. for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin(); aitr!=assoc.end(); ++aitr) { DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr); if (mitr==_objectWrapperMap.end()) { // not found so check if a library::class composite name. std::string token = *aitr; std::string::size_type posDoubleColon = token.rfind("::"); if (posDoubleColon != std::string::npos) { // we have a composite name so now strip off the library name // are try to load it, and then retry the find to see // if we can recongise the objects. std::string libraryName = std::string(token,0,posDoubleColon); // first try the standard nodekit library. std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName); if (loadLibrary(nodeKitLibraryName)) { mitr = _objectWrapperMap.find(*aitr); } if (mitr==_objectWrapperMap.end()) { // otherwise try the osgdb_ plugin library. std::string pluginLibraryName = createLibraryNameForExtension(libraryName); if (loadLibrary(pluginLibraryName)) { mitr = _objectWrapperMap.find(*aitr); } } } } if (mitr!=_objectWrapperMap.end()) { // get the function to read the data... DotOsgWrapper::ReadFunc rf = mitr->second->getReadFunc(); if (rf && (*rf)(*obj,fr)) iteratorAdvanced = true; } } if (!iteratorAdvanced) fr.advanceOverCurrentFieldOrBlock(); } ++fr; // step over trailing '}' return obj; } return 0L; } // // read object from input iterator. // osg::Object* Registry::readObject(DotOsgWrapperMap& dowMap,Input& fr) { const char *str = fr[0].getStr(); if (str==NULL) return NULL; std::string name = str; DotOsgWrapperMap::iterator itr = dowMap.find(name); if (itr==dowMap.end()) { // not found so check if a library::class composite name. std::string token = fr[0].getStr(); std::string::size_type posDoubleColon = token.rfind("::"); if (posDoubleColon != std::string::npos) { // we have a composite name so now strip off the library name // are try to load it, and then retry the readObject to see // if we can recongise the objects. std::string libraryName = std::string(token,0,posDoubleColon); // first try the standard nodekit library. std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName); if (loadLibrary(nodeKitLibraryName)) return readObject(dowMap,fr); // otherwise try the osgdb_ plugin library. std::string pluginLibraryName = createLibraryNameForExtension(libraryName); if (loadLibrary(pluginLibraryName)) return readObject(dowMap,fr); } } else if (fr[1].isOpenBracket()) { DotOsgWrapper* wrapper = itr->second.get(); const osg::Object* proto = wrapper->getPrototype(); if (proto==NULL) { osg::notify(osg::WARN)<<"Token "<getAssociates(); osg::Object* obj = proto->cloneType(); while(!fr.eof() && fr[0].getNoNestedBrackets()>entry) { bool iteratorAdvanced = false; if (fr[0].matchWord("UniqueID") && fr[1].isString()) { fr.regisiterUniqueIDForObject(fr[1].getStr(),obj); fr += 2; iteratorAdvanced = true; } // read the local data by iterating through the associate // list, mapping the associate names to DotOsgWrapper's which // in turn have the appropriate functions. for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin(); aitr!=assoc.end(); ++aitr) { DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr); if (mitr==_objectWrapperMap.end()) { // not found so check if a library::class composite name. std::string token = *aitr; std::string::size_type posDoubleColon = token.rfind("::"); if (posDoubleColon != std::string::npos) { // we have a composite name so now strip off the library name // are try to load it, and then retry the find to see // if we can recongise the objects. std::string libraryName = std::string(token,0,posDoubleColon); // first try the standard nodekit library. std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName); if (loadLibrary(nodeKitLibraryName)) { mitr = _objectWrapperMap.find(*aitr); } if (mitr==_objectWrapperMap.end()) { // otherwise try the osgdb_ plugin library. std::string pluginLibraryName = createLibraryNameForExtension(libraryName); if (loadLibrary(pluginLibraryName)) { mitr = _objectWrapperMap.find(*aitr); } } } } if (mitr!=_objectWrapperMap.end()) { // get the function to read the data... DotOsgWrapper::ReadFunc rf = mitr->second->getReadFunc(); if (rf && (*rf)(*obj,fr)) iteratorAdvanced = true; } } if (!iteratorAdvanced) fr.advanceOverCurrentFieldOrBlock(); } ++fr; // step over trailing '}' return obj; } return 0L; } // // read object from input iterator. // Object* Registry::readObject(Input& fr) { if (fr[0].matchWord("Use")) { if (fr[1].isString()) { Object* obj = fr.getObjectForUniqueID(fr[1].getStr()); if (obj) fr+=2; return obj; } else return NULL; } return readObject(_objectWrapperMap,fr); } // // read image from input iterator. // Image* Registry::readImage(Input& fr) { if (fr[0].matchWord("Use")) { if (fr[1].isString()) { Image* image = dynamic_cast(fr.getObjectForUniqueID(fr[1].getStr())); if (image) fr+=2; return image; } else return NULL; } osg::Object* obj = readObject(_imageWrapperMap,fr); osg::Image* image = dynamic_cast(obj); if (image) return image; else if (obj) obj->unref(); return NULL; } // // read drawable from input iterator. // Drawable* Registry::readDrawable(Input& fr) { if (fr[0].matchWord("Use")) { if (fr[1].isString()) { Drawable* drawable = dynamic_cast(fr.getObjectForUniqueID(fr[1].getStr())); if (drawable) fr+=2; return drawable; } else return NULL; } osg::Object* obj = readObject(_drawableWrapperMap,fr); osg::Drawable* drawable = dynamic_cast(obj); if (drawable) return drawable; else if (obj) obj->unref(); return NULL; } // // read drawable from input iterator. // StateAttribute* Registry::readStateAttribute(Input& fr) { if (fr[0].matchWord("Use")) { if (fr[1].isString()) { StateAttribute* attribute = dynamic_cast(fr.getObjectForUniqueID(fr[1].getStr())); if (attribute) fr+=2; return attribute; } else return NULL; } return dynamic_cast(readObject(_stateAttrWrapperMap,fr)); } // // read drawable from input iterator. // Uniform* Registry::readUniform(Input& fr) { if (fr[0].matchWord("Use")) { if (fr[1].isString()) { Uniform* attribute = dynamic_cast(fr.getObjectForUniqueID(fr[1].getStr())); if (attribute) fr+=2; return attribute; } else return NULL; } return dynamic_cast(readObject(_uniformWrapperMap,fr)); } // // read node from input iterator. // Node* Registry::readNode(Input& fr) { if (fr[0].matchWord("Use")) { if (fr[1].isString()) { Node* node = dynamic_cast(fr.getObjectForUniqueID(fr[1].getStr())); if (node) fr+=2; return node; } else return NULL; } osg::Object* obj = readObject(_nodeWrapperMap,fr); osg::Node* node = dynamic_cast(obj); if (node) return node; else if (obj) obj->unref(); return NULL; } // // Write object to output // bool Registry::writeObject(const osg::Object& obj,Output& fw) { if (obj.referenceCount()>1) { std::string uniqueID; if (fw.getUniqueIDForObject(&obj,uniqueID)) { fw.writeUseID( uniqueID ); return true; } } const std::string classname( obj.className() ); const std::string libraryName( obj.libraryName() ); const std::string compositeName( libraryName + "::" + classname ); // try composite name first DotOsgWrapperMap::iterator itr = _classNameWrapperMap.find(compositeName); if (itr==_classNameWrapperMap.end()) { // first try the standard nodekit library. std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName); if (loadLibrary(nodeKitLibraryName)) return writeObject(obj,fw); // otherwise try the osgdb_ plugin library. std::string pluginLibraryName = createLibraryNameForExtension(libraryName); if (loadLibrary(pluginLibraryName)) return writeObject(obj,fw); // otherwise try simple class name if (itr == _classNameWrapperMap.end()) itr = _classNameWrapperMap.find(classname); } if (itr!=_classNameWrapperMap.end()) { DotOsgWrapper* wrapper = itr->second.get(); const DotOsgWrapper::Associates& assoc = wrapper->getAssociates(); if (libraryName=="osg") { // member of the core osg, so no need to have composite library::class name. fw.writeBeginObject( wrapper->getName() ); } else { // member of the node kit so must use composite library::class name. std::string::size_type posDoubleColon = wrapper->getName().find("::"); if (posDoubleColon != std::string::npos) { fw.writeBeginObject( wrapper->getName() ); } else { fw.writeBeginObject( libraryName + "::" + wrapper->getName() ); } } fw.moveIn(); // write out the unique ID if required. if (obj.referenceCount()>1) { std::string uniqueID; fw.createUniqueIDForObject(&obj,uniqueID); fw.registerUniqueIDForObject(&obj,uniqueID); fw.writeUniqueID( uniqueID ); } // read the local data by iterating through the associate // list, mapping the associate names to DotOsgWrapper's which // in turn have the appropriate functions. for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin(); aitr!=assoc.end(); ++aitr) { DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr); if (mitr==_objectWrapperMap.end()) { // not found so check if a library::class composite name. std::string token = *aitr; std::string::size_type posDoubleColon = token.rfind("::"); if (posDoubleColon != std::string::npos) { // we have a composite name so now strip off the library name // are try to load it, and then retry the find to see // if we can recongise the objects. std::string libraryName = std::string(token,0,posDoubleColon); // first try the standard nodekit library. std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName); if (loadLibrary(nodeKitLibraryName)) { mitr = _objectWrapperMap.find(*aitr); } if (mitr==_objectWrapperMap.end()) { // otherwise try the osgdb_ plugin library. std::string pluginLibraryName = createLibraryNameForExtension(libraryName); if (loadLibrary(pluginLibraryName)) { mitr = _objectWrapperMap.find(*aitr); } } } } if (mitr!=_objectWrapperMap.end()) { // get the function to read the data... DotOsgWrapper::WriteFunc wf = mitr->second->getWriteFunc(); if (wf) (*wf)(obj,fw); } } fw.moveOut(); fw.writeEndObject(); return true; } return false; } struct Registry::ReadObjectFunctor : public Registry::ReadFunctor { ReadObjectFunctor(const std::string& filename, const ReaderWriter::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; } }; struct Registry::ReadImageFunctor : public Registry::ReadFunctor { ReadImageFunctor(const std::string& filename, const ReaderWriter::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; } }; struct Registry::ReadHeightFieldFunctor : public Registry::ReadFunctor { ReadHeightFieldFunctor(const std::string& filename, const ReaderWriter::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; } }; struct Registry::ReadNodeFunctor : public Registry::ReadFunctor { ReadNodeFunctor(const std::string& filename, const ReaderWriter::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; } }; struct Registry::ReadArchiveFunctor : public Registry::ReadFunctor { ReadArchiveFunctor(const std::string& filename, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const ReaderWriter::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; } }; 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); }; ReaderWriter::ReadResult Registry::read(const ReadFunctor& readFunctor) { for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin(); aitr!=_archiveExtList.end(); ++aitr) { std::string archiveName = "." + (*aitr); std::string::size_type positionArchive = readFunctor._filename.find(archiveName+'/'); if (positionArchive==std::string::npos) positionArchive = readFunctor._filename.find(archiveName+'\\'); if (positionArchive!=std::string::npos) { std::string archiveName(readFunctor._filename.substr(0,positionArchive+5)); std::string fileName(readFunctor._filename.substr(positionArchive+6,std::string::npos)); osg::notify(osg::INFO)<<"Contains archive : "< options = new ReaderWriter::Options; options->setDatabasePath(archiveName); return archive->readObject(fileName,options.get()); } } // if filename contains archive // then get archive name // if archive name is not in the cache then do an openArchive on // that archive name // use that archive to read the file. if (containsServerAddress(readFunctor._filename)) { std::string serverName = getServerAddress(readFunctor._filename); std::string serverFile = getServerFileName(readFunctor._filename); osg::notify(osg::INFO)<<"Contains sever address : "<(readFunctor._filename); filename = serverName+':'+serverFile; return readFunctor.doRead(*rw); } 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 = readFunctor.doRead(*itr); if (readFunctor.isValid(rr)) 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; Results::iterator ritr; for(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()) { for(ritr=results.begin(); ritr!=results.end(); ++ritr) { if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE) { osg::notify(osg::NOTICE)<<"Warning: error reading file \""<status()==ReaderWriter::ReadResult::FILE_NOT_FOUND) { osg::notify(osg::NOTICE)<<"Warning: could not find file \""<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()) { for(ritr=results.begin(); ritr!=results.end(); ++ritr) { if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE) { osg::notify(osg::NOTICE)<<"Warning: error reading file \""<status()==ReaderWriter::ReadResult::FILE_NOT_FOUND) { osg::notify(osg::NOTICE)<<"Warning: could not find file \""< lock(_objectCacheMutex); ObjectCache::iterator oitr=_objectCache.find(file); if (oitr!=_objectCache.end()) { notify(INFO)<<"returning cached instanced of "<second.first.get())) return ReaderWriter::ReadResult(oitr->second.first.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()) { // update cache with new entry. notify(INFO)<<"Adding to object cache "< lock(_objectCacheMutex); tmpObjectCache.swap(_objectCache); } ReaderWriter::ReadResult rr = read(readFunctor); { OpenThreads::ScopedLock lock(_objectCacheMutex); tmpObjectCache.swap(_objectCache); } return rr; } } ReaderWriter::ReadResult Registry::openArchiveImplementation(const std::string& fileName, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const ReaderWriter::Options* options) { osgDB::Archive* archive = getFromArchiveCache(fileName); if (archive) return archive; ReaderWriter::ReadResult result = readImplementation(ReadArchiveFunctor(fileName, status, indexBlockSizeHint, options),false); // default to using chaching archive if no options structure provided, but if options are provided use archives // only if supplied. if (result.validArchive() && (!options || (options->getObjectCacheHint() & ReaderWriter::Options::CACHE_ARCHIVES)) ) { addToArchiveCache(fileName,result.getArchive()); } return result; } ReaderWriter::ReadResult Registry::readObjectImplementation(const std::string& fileName,const ReaderWriter::Options* options) { return readImplementation(ReadObjectFunctor(fileName, options), options ? (options->getObjectCacheHint()&ReaderWriter::Options::CACHE_OBJECTS)!=0: false); } ReaderWriter::WriteResult Registry::writeObjectImplementation(const Object& obj,const std::string& fileName) { // 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::WriteResult rr = itr->writeObject(obj,fileName,_options.get()); 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)) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,_options.get()); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Warning: Could not find plugin to write objects to file \""+fileName+"\"."); } if (results.front().message().empty()) { switch(results.front().status()) { case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break; case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break; default: break; } } return results.front(); } ReaderWriter::ReadResult Registry::readImageImplementation(const std::string& fileName,const ReaderWriter::Options* options) { return readImplementation(ReadImageFunctor(fileName, options), options ? (options->getObjectCacheHint()&ReaderWriter::Options::CACHE_IMAGES)!=0: false); } ReaderWriter::WriteResult Registry::writeImageImplementation(const Image& image,const std::string& fileName) { // 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::WriteResult rr = itr->writeImage(image,fileName,_options.get()); 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)) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,_options.get()); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Warning: Could not find plugin to write image to file \""+fileName+"\"."); } if (results.front().message().empty()) { switch(results.front().status()) { case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break; case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break; default: break; } } return results.front(); } ReaderWriter::ReadResult Registry::readHeightFieldImplementation(const std::string& fileName,const ReaderWriter::Options* options) { return readImplementation(ReadHeightFieldFunctor(fileName, options), options ? (options->getObjectCacheHint()&ReaderWriter::Options::CACHE_HEIGHTFIELDS)!=0: false); } ReaderWriter::WriteResult Registry::writeHeightFieldImplementation(const HeightField& HeightField,const std::string& fileName) { // 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::WriteResult rr = itr->writeHeightField(HeightField,fileName,_options.get()); 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)) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,_options.get()); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Warning: Could not find plugin to write HeightField to file \""+fileName+"\"."); } if (results.front().message().empty()) { switch(results.front().status()) { case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break; case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break; default: break; } } return results.front(); } ReaderWriter::ReadResult Registry::readNodeImplementation(const std::string& fileName,const ReaderWriter::Options* options) { return readImplementation(ReadNodeFunctor(fileName, options), options ? (options->getObjectCacheHint()&ReaderWriter::Options::CACHE_NODES)!=0: false); } ReaderWriter::WriteResult Registry::writeNodeImplementation(const Node& node,const std::string& fileName) { // record the errors reported by readerwriters. typedef std::vector Results; Results results; // first attempt to write the file from existing ReaderWriter's AvailableReaderWriterIterator itr(_rwList); for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,_options.get()); 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)) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,_options.get()); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Warning: Could not find plugin to write nodes to file \""+fileName+"\"."); } if (results.front().message().empty()) { switch(results.front().status()) { case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break; case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break; default: break; } } return results.front(); } void Registry::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp) { OpenThreads::ScopedLock lock(_objectCacheMutex); _objectCache[filename]=ObjectTimeStampPair(object,timestamp); } osg::Object* Registry::getFromObjectCache(const std::string& fileName) { OpenThreads::ScopedLock lock(_objectCacheMutex); ObjectCache::iterator itr = _objectCache.find(fileName); if (itr!=_objectCache.end()) return itr->second.first.get(); else return 0; } void Registry::updateTimeStampOfObjectsInCacheWithExtenalReferences(double currentTime) { OpenThreads::ScopedLock lock(_objectCacheMutex); // look for objects with external references and update their time stamp. for(ObjectCache::iterator itr=_objectCache.begin(); itr!=_objectCache.end(); ++itr) { // if ref count is greater the 1 the object has an external reference. if (itr->second.first->referenceCount()>1) { // so update it time stamp. itr->second.second = currentTime; } } } void Registry::removeExpiredObjectsInCache(double expiryTime) { OpenThreads::ScopedLock lock(_objectCacheMutex); typedef std::vector ObjectsToRemove; ObjectsToRemove objectsToRemove; // first collect all the exprired entries in the ObjectToRemove list. for(ObjectCache::iterator oitr=_objectCache.begin(); oitr!=_objectCache.end(); ++oitr) { if (oitr->second.second<=expiryTime) { // record the filename of the entry to use as key for deleting // afterwards/ objectsToRemove.push_back(oitr->first); } } // remove the entries from the _objectCaache. for(ObjectsToRemove::iterator ritr=objectsToRemove.begin(); ritr!=objectsToRemove.end(); ++ritr) { // std::cout<<"Removing from Registry object cache '"<<*ritr<<"'"< lock(_objectCacheMutex); _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; } void Registry::clearArchiveCache() { OpenThreads::ScopedLock lock(_archiveCacheMutex); _archiveCache.clear(); } void Registry::releaseGLObjects(osg::State* state) { OpenThreads::ScopedLock lock(_objectCacheMutex); for(ObjectCache::iterator itr = _objectCache.begin(); itr != _objectCache.end(); ++itr) { osg::Object* object = itr->second.first.get(); object->releaseGLObjects(state); } } DatabasePager* Registry::getOrCreateDatabasePager() { if (!_databasePager) _databasePager = new DatabasePager; return _databasePager.get(); } SharedStateManager* Registry::getOrCreateSharedStateManager() { if (!_sharedStateManager) _sharedStateManager = new SharedStateManager; return _sharedStateManager.get(); }