511 lines
22 KiB
C++
511 lines
22 KiB
C++
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 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.
|
|
*/
|
|
|
|
#ifndef OSGDB_REGISTRY
|
|
#define OSGDB_REGISTRY 1
|
|
|
|
#include <osg/ref_ptr>
|
|
#include <osg/ArgumentParser>
|
|
|
|
#include <osgDB/DynamicLibrary>
|
|
#include <osgDB/ReaderWriter>
|
|
#include <osgDB/DotOsgWrapper>
|
|
#include <osgDB/DatabasePager>
|
|
|
|
#include <vector>
|
|
#include <map>
|
|
#include <string>
|
|
#include <deque>
|
|
|
|
|
|
namespace osgDB {
|
|
|
|
/** basic structure for custom runtime inheritance checking */
|
|
struct basic_type_wrapper {
|
|
virtual bool matches(const osg::Object *proto) const = 0;
|
|
};
|
|
|
|
/** a class template that checks inheritance between a given
|
|
Object's class and a class defined at compile time through
|
|
the template parameter T.
|
|
This is used in conjunction with readObjectOfType() to
|
|
specify an abstract class as reference type.
|
|
**/
|
|
template<class T>
|
|
struct type_wrapper: basic_type_wrapper {
|
|
bool matches(const osg::Object *proto) const
|
|
{
|
|
return dynamic_cast<const T*>(proto) != 0;
|
|
}
|
|
};
|
|
|
|
/** list of directories to search through which searching for files. */
|
|
typedef std::deque<std::string> FilePathList;
|
|
|
|
/**
|
|
Registry is a singleton factory which stores
|
|
the reader/writers which are linked in
|
|
at runtime for reading non-native file formats.
|
|
|
|
The RegisterDotOsgWrapperProxy can be used to automatically register
|
|
DotOsgWrappers, at runtime with the Registry. A DotOsgWrapper encapsulates
|
|
the functions that can read and write to the .osg for each osg::Object.
|
|
|
|
The RegisterReaderWriterProxy can be used to automatically
|
|
register at runtime a reader/writer with the Registry.
|
|
*/
|
|
class OSGDB_EXPORT Registry : public osg::Referenced
|
|
{
|
|
public:
|
|
|
|
/// bit mask for setting up which object types get cached by readObject/Image/HeightField/Node(filename) calls
|
|
enum CacheHintOptions
|
|
{ /// do not cache objects of any type
|
|
CACHE_NONE = 0,
|
|
|
|
/// cache nodes loaded via readNode(filename)
|
|
CACHE_NODES = 1,
|
|
|
|
/// cache images loaded via readImage(filename)
|
|
CACHE_IMAGES = 2,
|
|
|
|
/// cache heightfield loaded via readHeightField(filename)
|
|
CACHE_HEIGHTFIELDS = 4,
|
|
|
|
/// cache objects loaded via readObject(filename)
|
|
CACHE_OBJECTS = 8,
|
|
|
|
/// cache on all read*(filename) calls
|
|
CACHE_ALL = CACHE_NODES |
|
|
CACHE_IMAGES |
|
|
CACHE_HEIGHTFIELDS |
|
|
CACHE_OBJECTS
|
|
};
|
|
|
|
|
|
|
|
static Registry* instance(bool erase = false);
|
|
|
|
/** read the command line arguments.*/
|
|
void readCommandLine(osg::ArgumentParser& commandLine);
|
|
|
|
/** register an .fileextension alias to mapExt toExt, the later
|
|
* should the the extension name of the readerwriter plugin library.
|
|
* For example to map .tif files to the tiff loader, use
|
|
* addExtAlias("tif","tiff") which will enable .tif to be read
|
|
* by the libdb_tiff readerwriter plugin.*/
|
|
void addFileExtensionAlias(const std::string mapExt, const std::string toExt);
|
|
|
|
void addDotOsgWrapper(DotOsgWrapper* wrapper);
|
|
void removeDotOsgWrapper(DotOsgWrapper* wrapper);
|
|
|
|
void addReaderWriter(ReaderWriter* rw);
|
|
void removeReaderWriter(ReaderWriter* rw);
|
|
|
|
/** create the platform specific library name associated with file.*/
|
|
std::string createLibraryNameForFile(const std::string& fileName);
|
|
|
|
/** create the platform specific library name associated with file extension.*/
|
|
std::string createLibraryNameForExtension(const std::string& ext);
|
|
|
|
/** create the platform specific library name associated with nodekit library name.*/
|
|
std::string createLibraryNameForNodeKit(const std::string& name);
|
|
|
|
/** find the library in the SG_LIBRARY_PATH and load it.*/
|
|
bool loadLibrary(const std::string& fileName);
|
|
/** close the attached library with specified name.*/
|
|
bool closeLibrary(const std::string& fileName);
|
|
/** close all libraries.*/
|
|
void closeAllLibraries();
|
|
|
|
/** get a reader writer which handles specified extension.*/
|
|
ReaderWriter* getReaderWriterForExtension(const std::string& ext);
|
|
|
|
osg::Object* readObjectOfType(const osg::Object& compObj,Input& fr);
|
|
osg::Object* readObjectOfType(const basic_type_wrapper &btw, Input& fr);
|
|
|
|
osg::Object* readObject(Input& fr);
|
|
osg::Image* readImage(Input& fr);
|
|
osg::Drawable* readDrawable(Input& fr);
|
|
osg::StateAttribute* readStateAttribute(Input& fr);
|
|
osg::Node* readNode(Input& fr);
|
|
|
|
bool writeObject(const osg::Object& obj,Output& fw);
|
|
|
|
|
|
class ReadFileCallback : public osg::Referenced
|
|
{
|
|
public:
|
|
|
|
virtual ReaderWriter::ReadResult readObject(const std::string& filename, CacheHintOptions options)
|
|
{
|
|
return osgDB::Registry::instance()->readObjectImplementation(filename,options);
|
|
}
|
|
|
|
virtual ReaderWriter::ReadResult readImage(const std::string& filename, CacheHintOptions options)
|
|
{
|
|
return osgDB::Registry::instance()->readImageImplementation(filename,options);
|
|
}
|
|
|
|
virtual ReaderWriter::ReadResult readHeightField(const std::string& filename, CacheHintOptions options)
|
|
{
|
|
return osgDB::Registry::instance()->readHeightFieldImplementation(filename,options);
|
|
}
|
|
|
|
virtual ReaderWriter::ReadResult readNode(const std::string& filename, CacheHintOptions options)
|
|
{
|
|
return osgDB::Registry::instance()->readNodeImplementation(filename,options);
|
|
}
|
|
|
|
protected:
|
|
virtual ~ReadFileCallback() {}
|
|
};
|
|
|
|
/** Set the Registry callback to use in place of the default readFile calls.*/
|
|
void setReadFileCallback( ReadFileCallback* cb) { _readFileCallback = cb; }
|
|
|
|
/** Get the readFile callback.*/
|
|
ReadFileCallback* getReadFileCallback() { return _readFileCallback.get(); }
|
|
|
|
/** Get the const readFile callback.*/
|
|
const ReadFileCallback* getReadFileCallback() const { return _readFileCallback.get(); }
|
|
|
|
|
|
ReaderWriter::ReadResult readObject(const std::string& fileName,CacheHintOptions useObjectCache)
|
|
{
|
|
if (_readFileCallback.valid()) return _readFileCallback->readObject(fileName,useObjectCache);
|
|
else return readObjectImplementation(fileName,useObjectCache);
|
|
}
|
|
ReaderWriter::ReadResult readObjectImplementation(const std::string& fileName,CacheHintOptions useObjectCache);
|
|
|
|
ReaderWriter::ReadResult readImage(const std::string& fileName,CacheHintOptions useObjectCache)
|
|
{
|
|
if (_readFileCallback.valid()) return _readFileCallback->readImage(fileName,useObjectCache);
|
|
else return readImageImplementation(fileName,useObjectCache);
|
|
}
|
|
ReaderWriter::ReadResult readImageImplementation(const std::string& fileName,CacheHintOptions useObjectCache);
|
|
|
|
ReaderWriter::ReadResult readHeightField(const std::string& fileName,CacheHintOptions useObjectCache)
|
|
{
|
|
if (_readFileCallback.valid()) return _readFileCallback->readHeightField(fileName,useObjectCache);
|
|
else return readHeightFieldImplementation(fileName,useObjectCache);
|
|
}
|
|
ReaderWriter::ReadResult readHeightFieldImplementation(const std::string& fileName,CacheHintOptions useObjectCache);
|
|
|
|
ReaderWriter::ReadResult readNode(const std::string& fileName,CacheHintOptions useObjectCache)
|
|
{
|
|
if (_readFileCallback.valid()) return _readFileCallback->readNode(fileName,useObjectCache);
|
|
else return readNodeImplementation(fileName,useObjectCache);
|
|
}
|
|
ReaderWriter::ReadResult readNodeImplementation(const std::string& fileName,CacheHintOptions useObjectCache);
|
|
|
|
|
|
class WriteFileCallback : public osg::Referenced
|
|
{
|
|
public:
|
|
|
|
virtual ReaderWriter::WriteResult writeObject(const osg::Object& obj, const std::string& fileName)
|
|
{
|
|
return osgDB::Registry::instance()->writeObjectImplementation(obj,fileName);
|
|
}
|
|
|
|
virtual ReaderWriter::WriteResult writeImage(const osg::Image& obj, const std::string& fileName)
|
|
{
|
|
return osgDB::Registry::instance()->writeImageImplementation(obj,fileName);
|
|
}
|
|
|
|
virtual ReaderWriter::WriteResult writeHeightField(const osg::HeightField& obj, const std::string& fileName)
|
|
{
|
|
return osgDB::Registry::instance()->writeHeightFieldImplementation(obj,fileName);
|
|
}
|
|
|
|
virtual ReaderWriter::WriteResult writeNode(const osg::Node& obj, const std::string& fileName)
|
|
{
|
|
return osgDB::Registry::instance()->writeNodeImplementation(obj,fileName);
|
|
}
|
|
|
|
protected:
|
|
virtual ~WriteFileCallback() {}
|
|
};
|
|
|
|
/** Set the Registry callback to use in place of the default writeFile calls.*/
|
|
void setWriteFileCallback( WriteFileCallback* cb) { _writeFileCallback = cb; }
|
|
|
|
/** Get the writeFile callback.*/
|
|
WriteFileCallback* getWriteFileCallback() { return _writeFileCallback.get(); }
|
|
|
|
/** Get the const writeFile callback.*/
|
|
const WriteFileCallback* getWriteFileCallback() const { return _writeFileCallback.get(); }
|
|
|
|
|
|
ReaderWriter::WriteResult writeObject(const osg::Object& obj, const std::string& fileName)
|
|
{
|
|
if (_writeFileCallback.valid()) return _writeFileCallback->writeObject(obj,fileName);
|
|
else return writeObjectImplementation(obj,fileName);
|
|
}
|
|
ReaderWriter::WriteResult writeObjectImplementation(const osg::Object& obj, const std::string& fileName);
|
|
|
|
ReaderWriter::WriteResult writeImage(const osg::Image& obj, const std::string& fileName)
|
|
{
|
|
if (_writeFileCallback.valid()) return _writeFileCallback->writeImage(obj,fileName);
|
|
else return writeImageImplementation(obj,fileName);
|
|
}
|
|
ReaderWriter::WriteResult writeImageImplementation(const osg::Image& obj, const std::string& fileName);
|
|
|
|
ReaderWriter::WriteResult writeHeightField(const osg::HeightField& obj, const std::string& fileName)
|
|
{
|
|
if (_writeFileCallback.valid()) return _writeFileCallback->writeHeightField(obj,fileName);
|
|
else return writeHeightFieldImplementation(obj,fileName);
|
|
}
|
|
ReaderWriter::WriteResult writeHeightFieldImplementation(const osg::HeightField& obj, const std::string& fileName);
|
|
|
|
ReaderWriter::WriteResult writeNode(const osg::Node& node, const std::string& fileName)
|
|
{
|
|
if (_writeFileCallback.valid()) return _writeFileCallback->writeNode(node,fileName);
|
|
else return writeNodeImplementation(node,fileName);
|
|
}
|
|
ReaderWriter::WriteResult writeNodeImplementation(const osg::Node& node, const std::string& fileName);
|
|
|
|
|
|
void setCreateNodeFromImage(bool flag) { _createNodeFromImage = flag; }
|
|
bool getCreateNodeFromImage() const { return _createNodeFromImage; }
|
|
|
|
|
|
void setOptions(ReaderWriter::Options* opt) { _options = opt; }
|
|
ReaderWriter::Options* getOptions() { return _options.get(); }
|
|
const ReaderWriter::Options* getOptions() const { return _options.get(); }
|
|
|
|
|
|
/** initilize both the Data and Library FilePaths, by default called by the
|
|
* constructor, so it should only be required if you want to force
|
|
* the re-reading of environmental variables.*/
|
|
void initFilePathLists() { initDataFilePathList(); initLibraryFilePathList(); }
|
|
|
|
/** initilize the Data FilePath by reading the OSG_FILE_PATH environmental variable.*/
|
|
void initDataFilePathList();
|
|
|
|
/** Set the data file path using a list of paths stored in a FilePath, which is used when search for data files.*/
|
|
void setDataFilePathList(const FilePathList& filepath) { _dataFilePath = filepath; }
|
|
|
|
/** Set the data file path using a single string deliminated either with ';' (Windows) or ':' (All other platforms), which is used when search for data files.*/
|
|
void setDataFilePathList(const std::string& paths);
|
|
|
|
/** get the data file path which is used when search for data files.*/
|
|
FilePathList& getDataFilePathList() { return _dataFilePath; }
|
|
|
|
/** get the const data file path which is used when search for data files.*/
|
|
const FilePathList& getDataFilePathList() const { return _dataFilePath; }
|
|
|
|
/** initilize the Library FilePath by reading the OSG_LIBRARY_PATH
|
|
* and the appropriate system environmental variables*/
|
|
void initLibraryFilePathList();
|
|
|
|
/** Set the library file path using a list of paths stored in a FilePath, which is used when search for data files.*/
|
|
void setLibraryFilePathList(const FilePathList& filepath) { _libraryFilePath = filepath; }
|
|
|
|
/** Set the library file path using a single string deliminated either with ';' (Windows) or ':' (All other platforms), which is used when search for data files.*/
|
|
void setLibraryFilePathList(const std::string& paths);
|
|
|
|
/** get the library file path which is used when search for library (dso/dll's) files.*/
|
|
FilePathList& getLibraryFilePathList() { return _libraryFilePath; }
|
|
|
|
/** get the const library file path which is used when search for library (dso/dll's) files.*/
|
|
const FilePathList& getLibraryFilePathList() const { return _libraryFilePath; }
|
|
|
|
/** For each object in the cache which has an reference count greater than 1
|
|
* (and therefore referenced by elsewhere in the application) set the time stamp
|
|
* for that object in the cache to specified time.
|
|
* This would typically be called once per frame by applications which are doing database paging,
|
|
* and need to prune objects that are no longer required.
|
|
* Time value is time in sceonds.*/
|
|
void updateTimeStampOfObjectsInCacheWithExtenalReferences(double currentTime);
|
|
|
|
/** Removed object in the cache which have a time stamp at or before the specified expiry time.
|
|
* This would typically be called once per frame by applications which are doing database paging,
|
|
* and need to prune objects that are no longer required, and called after the a called
|
|
* after the call to updateTimeStampOfObjectsInCacheWithExtenalReferences(currentTime).
|
|
* Note, the currentTime is not the expiryTime, one would typically set the expiry time
|
|
* to a fixed amount of time before currentTime, such as expiryTime = currentTime-10.0.
|
|
* Time value is time in sceonds.*/
|
|
void removeExpiredObjectsInCache(double expiryTime);
|
|
|
|
/** Remove all objects in the cache regardless of having external references or expiry times.*/
|
|
void clearObjectCache();
|
|
|
|
/** Add a filename,object,timestamp tripple to the Registry::ObjectCache.*/
|
|
void addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp = 0.0);
|
|
|
|
/** Set whether the Registry::ObjectCache should be used by default.*/
|
|
void setUseObjectCacheHint(CacheHintOptions useObjectCache) { _useObjectCacheHint = useObjectCache; }
|
|
|
|
/** Get whether the Registry::ObjectCache should be used by default.*/
|
|
CacheHintOptions getUseObjectCacheHint() const { return _useObjectCacheHint; }
|
|
|
|
/** get the attached library with specified name.*/
|
|
DynamicLibrary* getLibrary(const std::string& fileName);
|
|
|
|
typedef std::vector< osg::ref_ptr<ReaderWriter> > ReaderWriterList;
|
|
|
|
|
|
/** Set the DatabasePager.*/
|
|
void setDatabasePager(DatabasePager* databasePager) { _databasePager = databasePager; }
|
|
|
|
/** Get the DatabasePager, creating one if one is not already created.*/
|
|
DatabasePager* getOrCreateDatabasePager();
|
|
|
|
/** Get the DatabasePager. Return 0 if no DatabasePager has been assigned.*/
|
|
DatabasePager* getDatabasePager() { return _databasePager.get(); }
|
|
|
|
|
|
/** Set the SharedStateManager.*/
|
|
void setSharedStateManager(SharedStateManager* SharedStateManager) { _sharedStateManager = SharedStateManager; }
|
|
|
|
/** Get the SharedStateManager, creating one if one is not already created.*/
|
|
SharedStateManager* getOrCreateSharedStateManager();
|
|
|
|
/** Get the SharedStateManager. Return 0 if no SharedStateManager has been assigned.*/
|
|
SharedStateManager* getSharedStateManager() { return _sharedStateManager.get(); }
|
|
|
|
protected:
|
|
|
|
virtual ~Registry();
|
|
|
|
typedef std::map< std::string, osg::ref_ptr<DotOsgWrapper> > DotOsgWrapperMap;
|
|
typedef std::vector< osg::ref_ptr<DynamicLibrary> > DynamicLibraryList;
|
|
typedef std::map< std::string, std::string> ExtensionAliasMap;
|
|
|
|
typedef std::pair<osg::ref_ptr<osg::Object>, double > ObjectTimeStampPair;
|
|
typedef std::map<std::string, ObjectTimeStampPair > ObjectCache;
|
|
|
|
/** constructor is private, as its a singleton, preventing
|
|
construction other than via the instance() method and
|
|
therefore ensuring only one copy is ever constructed*/
|
|
Registry();
|
|
|
|
/** get the attached library with specified name.*/
|
|
DynamicLibraryList::iterator getLibraryItr(const std::string& fileName);
|
|
|
|
bool _createNodeFromImage;
|
|
|
|
osg::Object* readObject(DotOsgWrapperMap& dowMap,Input& fr);
|
|
|
|
void eraseWrapper(DotOsgWrapperMap& wrappermap,DotOsgWrapper* wrapper);
|
|
|
|
ReaderWriter::ReadResult readObject(const std::string& fileName);
|
|
ReaderWriter::ReadResult readImage(const std::string& fileName);
|
|
ReaderWriter::ReadResult readHeightField(const std::string& fileName);
|
|
ReaderWriter::ReadResult readNode(const std::string& fileName);
|
|
|
|
osg::ref_ptr<ReadFileCallback> _readFileCallback;
|
|
osg::ref_ptr<WriteFileCallback> _writeFileCallback;
|
|
|
|
DotOsgWrapperMap _objectWrapperMap;
|
|
DotOsgWrapperMap _imageWrapperMap;
|
|
DotOsgWrapperMap _drawableWrapperMap;
|
|
DotOsgWrapperMap _stateAttrWrapperMap;
|
|
DotOsgWrapperMap _nodeWrapperMap;
|
|
|
|
DotOsgWrapperMap _classNameWrapperMap;
|
|
|
|
ReaderWriterList _rwList;
|
|
DynamicLibraryList _dlList;
|
|
|
|
bool _openingLibrary;
|
|
|
|
// map to alias to extensions to plugins.
|
|
ExtensionAliasMap _extAliasMap;
|
|
|
|
// options to pass to reader writers.
|
|
osg::ref_ptr<ReaderWriter::Options> _options;
|
|
|
|
FilePathList _dataFilePath;
|
|
FilePathList _libraryFilePath;
|
|
|
|
CacheHintOptions _useObjectCacheHint;
|
|
ObjectCache _objectCache;
|
|
OpenThreads::Mutex _objectCacheMutex;
|
|
|
|
osg::ref_ptr<DatabasePager> _databasePager;
|
|
osg::ref_ptr<SharedStateManager> _sharedStateManager;
|
|
|
|
};
|
|
|
|
/** read the command line arguments.*/
|
|
inline void readCommandLine(osg::ArgumentParser& parser)
|
|
{
|
|
Registry::instance()->readCommandLine(parser);
|
|
}
|
|
|
|
/** Proxy class for automatic registration of DotOsgWrappers with the Registry.*/
|
|
class RegisterDotOsgWrapperProxy
|
|
{
|
|
public:
|
|
|
|
RegisterDotOsgWrapperProxy(osg::Object* proto,
|
|
const std::string& name,
|
|
const std::string& associates,
|
|
DotOsgWrapper::ReadFunc readFunc,
|
|
DotOsgWrapper::WriteFunc writeFunc,
|
|
DotOsgWrapper::ReadWriteMode readWriteMode=DotOsgWrapper::READ_AND_WRITE)
|
|
{
|
|
if (Registry::instance())
|
|
{
|
|
_wrapper = new DotOsgWrapper(proto,name,associates,readFunc,writeFunc,readWriteMode);
|
|
Registry::instance()->addDotOsgWrapper(_wrapper.get());
|
|
}
|
|
}
|
|
|
|
~RegisterDotOsgWrapperProxy()
|
|
{
|
|
if (Registry::instance())
|
|
{
|
|
Registry::instance()->removeDotOsgWrapper(_wrapper.get());
|
|
}
|
|
}
|
|
|
|
protected:
|
|
osg::ref_ptr<DotOsgWrapper> _wrapper;
|
|
};
|
|
|
|
/** Proxy class for automatic registration of reader/writers with the Registry.*/
|
|
template<class T>
|
|
class RegisterReaderWriterProxy
|
|
{
|
|
public:
|
|
RegisterReaderWriterProxy()
|
|
{
|
|
if (Registry::instance())
|
|
{
|
|
_rw = new T;
|
|
Registry::instance()->addReaderWriter(_rw.get());
|
|
}
|
|
}
|
|
|
|
~RegisterReaderWriterProxy()
|
|
{
|
|
if (Registry::instance())
|
|
{
|
|
Registry::instance()->removeReaderWriter(_rw.get());
|
|
}
|
|
}
|
|
|
|
T* get() { return _rw.get(); }
|
|
|
|
protected:
|
|
osg::ref_ptr<T> _rw;
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|