Add NifFileManager to avoid duplicate parsing of the NIFFile in SceneManager and BulletShapeManager.

openmw-38
scrawl 9 years ago
parent 84305a1297
commit 3d12b2ca9d

@ -636,7 +636,7 @@ namespace MWPhysics
// --------------------------------------------------------------- // ---------------------------------------------------------------
PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> parentNode) PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> parentNode)
: mShapeManager(new Resource::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager())) : mShapeManager(new Resource::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager(), resourceSystem->getNifFileManager()))
, mDebugDrawEnabled(false) , mDebugDrawEnabled(false)
, mTimeAccum(0.0f) , mTimeAccum(0.0f)
, mWaterHeight(0) , mWaterHeight(0)

@ -403,6 +403,8 @@ namespace MWWorld
// Delay the map update until scripts have been given a chance to run. // Delay the map update until scripts have been given a chance to run.
// If we don't do this, objects that should be disabled will still appear on the map. // If we don't do this, objects that should be disabled will still appear on the map.
mNeedMapUpdate = true; mNeedMapUpdate = true;
mRendering.getResourceSystem()->clearCache();
} }
void Scene::changePlayerCell(CellStore *cell, const ESM::Position &pos, bool adjustPlayerPos) void Scene::changePlayerCell(CellStore *cell, const ESM::Position &pos, bool adjustPlayerPos)
@ -518,6 +520,8 @@ namespace MWWorld
// Delay the map update until scripts have been given a chance to run. // Delay the map update until scripts have been given a chance to run.
// If we don't do this, objects that should be disabled will still appear on the map. // If we don't do this, objects that should be disabled will still appear on the map.
mNeedMapUpdate = true; mNeedMapUpdate = true;
mRendering.getResourceSystem()->clearCache();
} }
void Scene::changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos) void Scene::changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos)

@ -37,7 +37,7 @@ add_component_dir (vfs
) )
add_component_dir (resource add_component_dir (resource
scenemanager texturemanager resourcesystem bulletshapemanager bulletshape scenemanager texturemanager resourcesystem bulletshapemanager bulletshape niffilemanager
) )
add_component_dir (sceneutil add_component_dir (sceneutil

@ -12,6 +12,7 @@
#include "bulletshape.hpp" #include "bulletshape.hpp"
#include "scenemanager.hpp" #include "scenemanager.hpp"
#include "niffilemanager.hpp"
namespace Resource namespace Resource
@ -94,9 +95,10 @@ private:
btTriangleMesh* mTriangleMesh; btTriangleMesh* mTriangleMesh;
}; };
BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr) BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager)
: mVFS(vfs) : mVFS(vfs)
, mSceneManager(sceneMgr) , mSceneManager(sceneMgr)
, mNifFileManager(nifFileManager)
{ {
} }
@ -115,8 +117,6 @@ osg::ref_ptr<BulletShapeInstance> BulletShapeManager::createInstance(const std::
Index::iterator it = mIndex.find(normalized); Index::iterator it = mIndex.find(normalized);
if (it == mIndex.end()) if (it == mIndex.end())
{ {
Files::IStreamPtr file = mVFS->get(normalized);
size_t extPos = normalized.find_last_of('.'); size_t extPos = normalized.find_last_of('.');
std::string ext; std::string ext;
if (extPos != std::string::npos && extPos+1 < normalized.size()) if (extPos != std::string::npos && extPos+1 < normalized.size())
@ -126,7 +126,7 @@ osg::ref_ptr<BulletShapeInstance> BulletShapeManager::createInstance(const std::
{ {
NifBullet::BulletNifLoader loader; NifBullet::BulletNifLoader loader;
// might be worth sharing NIFFiles with SceneManager in some way // might be worth sharing NIFFiles with SceneManager in some way
shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); shape = loader.load(mNifFileManager->get(normalized));
} }
else else
{ {

@ -16,6 +16,7 @@ namespace VFS
namespace Resource namespace Resource
{ {
class SceneManager; class SceneManager;
class NifFileManager;
class BulletShape; class BulletShape;
class BulletShapeInstance; class BulletShapeInstance;
@ -23,7 +24,7 @@ namespace Resource
class BulletShapeManager class BulletShapeManager
{ {
public: public:
BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr); BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager);
~BulletShapeManager(); ~BulletShapeManager();
osg::ref_ptr<BulletShapeInstance> createInstance(const std::string& name); osg::ref_ptr<BulletShapeInstance> createInstance(const std::string& name);
@ -31,6 +32,7 @@ namespace Resource
private: private:
const VFS::Manager* mVFS; const VFS::Manager* mVFS;
SceneManager* mSceneManager; SceneManager* mSceneManager;
NifFileManager* mNifFileManager;
typedef std::map<std::string, osg::ref_ptr<BulletShape> > Index; typedef std::map<std::string, osg::ref_ptr<BulletShape> > Index;
Index mIndex; Index mIndex;

@ -0,0 +1,64 @@
#include "niffilemanager.hpp"
#include <osgDB/ObjectCache>
#include <components/vfs/manager.hpp>
#include <osg/Timer>
namespace Resource
{
class NifFileHolder : public osg::Object
{
public:
NifFileHolder(const Nif::NIFFilePtr& file)
: mNifFile(file)
{
}
NifFileHolder(const NifFileHolder& copy, const osg::CopyOp& copyop)
: mNifFile(copy.mNifFile)
{
}
NifFileHolder()
{
}
META_Object(Resource, NifFileHolder)
Nif::NIFFilePtr mNifFile;
};
NifFileManager::NifFileManager(const VFS::Manager *vfs)
: mVFS(vfs)
{
mCache = new osgDB::ObjectCache;
}
NifFileManager::~NifFileManager()
{
}
void NifFileManager::clearCache()
{
// NIF files aren't needed any more when the converted objects are cached in SceneManager / BulletShapeManager,
// so we'll simply drop all nif files here, unlikely to need them again
mCache->clear();
}
Nif::NIFFilePtr NifFileManager::get(const std::string &name)
{
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(name);
if (obj)
return static_cast<NifFileHolder*>(obj.get())->mNifFile;
else
{
Nif::NIFFilePtr file (new Nif::NIFFile(mVFS->get(name), name));
obj = new NifFileHolder(file);
mCache->addEntryToObjectCache(name, obj);
return file;
}
}
}

@ -0,0 +1,45 @@
#ifndef OPENMW_COMPONENTS_RESOURCE_NIFFILEMANAGER_H
#define OPENMW_COMPONENTS_RESOURCE_NIFFILEMANAGER_H
#include <osg/ref_ptr>
#include <components/nif/niffile.hpp>
namespace VFS
{
class Manager;
}
namespace osgDB
{
class ObjectCache;
}
namespace Resource
{
/// @brief Handles caching of NIFFiles.
/// @note The NifFileManager is completely thread safe.
class NifFileManager
{
public:
NifFileManager(const VFS::Manager* vfs);
~NifFileManager();
void clearCache();
/// Retrieve a NIF file from the cache, or load it from the VFS if not cached yet.
/// @note For performance reasons the NifFileManager does not handle case folding, needs
/// to be done in advance by other managers accessing the NifFileManager.
Nif::NIFFilePtr get(const std::string& name);
private:
// Use the osgDB::ObjectCache so objects are retrieved in thread safe way
osg::ref_ptr<osgDB::ObjectCache> mCache;
const VFS::Manager* mVFS;
};
}
#endif

@ -2,6 +2,7 @@
#include "scenemanager.hpp" #include "scenemanager.hpp"
#include "texturemanager.hpp" #include "texturemanager.hpp"
#include "niffilemanager.hpp"
namespace Resource namespace Resource
{ {
@ -9,8 +10,9 @@ namespace Resource
ResourceSystem::ResourceSystem(const VFS::Manager *vfs) ResourceSystem::ResourceSystem(const VFS::Manager *vfs)
: mVFS(vfs) : mVFS(vfs)
{ {
mNifFileManager.reset(new NifFileManager(vfs));
mTextureManager.reset(new TextureManager(vfs)); mTextureManager.reset(new TextureManager(vfs));
mSceneManager.reset(new SceneManager(vfs, mTextureManager.get())); mSceneManager.reset(new SceneManager(vfs, mTextureManager.get(), mNifFileManager.get()));
} }
ResourceSystem::~ResourceSystem() ResourceSystem::~ResourceSystem()
@ -28,6 +30,16 @@ namespace Resource
return mTextureManager.get(); return mTextureManager.get();
} }
NifFileManager *ResourceSystem::getNifFileManager()
{
return mNifFileManager.get();
}
void ResourceSystem::clearCache()
{
mNifFileManager->clearCache();
}
const VFS::Manager* ResourceSystem::getVFS() const const VFS::Manager* ResourceSystem::getVFS() const
{ {
return mVFS; return mVFS;

@ -13,8 +13,9 @@ namespace Resource
class SceneManager; class SceneManager;
class TextureManager; class TextureManager;
class NifFileManager;
/// @brief Wrapper class that constructs and provides access to the various resource subsystems. /// @brief Wrapper class that constructs and provides access to the most commonly used resource subsystems.
/// @par Resource subsystems can be used with multiple OpenGL contexts, just like the OSG equivalents, but /// @par Resource subsystems can be used with multiple OpenGL contexts, just like the OSG equivalents, but
/// are built around the use of a single virtual file system. /// are built around the use of a single virtual file system.
class ResourceSystem class ResourceSystem
@ -25,12 +26,17 @@ namespace Resource
SceneManager* getSceneManager(); SceneManager* getSceneManager();
TextureManager* getTextureManager(); TextureManager* getTextureManager();
NifFileManager* getNifFileManager();
/// Indicates to each resource manager to clear the cache, i.e. to drop cached objects that are no longer referenced.
void clearCache();
const VFS::Manager* getVFS() const; const VFS::Manager* getVFS() const;
private: private:
std::auto_ptr<SceneManager> mSceneManager; std::auto_ptr<SceneManager> mSceneManager;
std::auto_ptr<TextureManager> mTextureManager; std::auto_ptr<TextureManager> mTextureManager;
std::auto_ptr<NifFileManager> mNifFileManager;
const VFS::Manager* mVFS; const VFS::Manager* mVFS;

@ -21,6 +21,7 @@
#include <components/sceneutil/util.hpp> #include <components/sceneutil/util.hpp>
#include "texturemanager.hpp" #include "texturemanager.hpp"
#include "niffilemanager.hpp"
namespace namespace
{ {
@ -104,9 +105,10 @@ namespace
namespace Resource namespace Resource
{ {
SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager) SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager, Resource::NifFileManager* nifFileManager)
: mVFS(vfs) : mVFS(vfs)
, mTextureManager(textureManager) , mTextureManager(textureManager)
, mNifFileManager(nifFileManager)
, mParticleSystemMask(~0u) , mParticleSystemMask(~0u)
{ {
} }
@ -150,11 +152,11 @@ namespace Resource
return std::string(); return std::string();
} }
osg::ref_ptr<osg::Node> load (Files::IStreamPtr file, const std::string& normalizedFilename, Resource::TextureManager* textureMgr) osg::ref_ptr<osg::Node> load (Files::IStreamPtr file, const std::string& normalizedFilename, Resource::TextureManager* textureMgr, Resource::NifFileManager* nifFileManager)
{ {
std::string ext = getFileExtension(normalizedFilename); std::string ext = getFileExtension(normalizedFilename);
if (ext == "nif") if (ext == "nif")
return NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalizedFilename)), textureMgr); return NifOsg::Loader::load(nifFileManager->get(normalizedFilename), textureMgr);
else else
{ {
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext);
@ -195,14 +197,14 @@ namespace Resource
{ {
Files::IStreamPtr file = mVFS->get(normalized); Files::IStreamPtr file = mVFS->get(normalized);
loaded = load(file, normalized, mTextureManager); loaded = load(file, normalized, mTextureManager, mNifFileManager);
} }
catch (std::exception& e) catch (std::exception& e)
{ {
std::cerr << "Failed to load '" << name << "': " << e.what() << ", using marker_error.nif instead" << std::endl; std::cerr << "Failed to load '" << name << "': " << e.what() << ", using marker_error.nif instead" << std::endl;
Files::IStreamPtr file = mVFS->get("meshes/marker_error.nif"); Files::IStreamPtr file = mVFS->get("meshes/marker_error.nif");
normalized = "meshes/marker_error.nif"; normalized = "meshes/marker_error.nif";
loaded = load(file, normalized, mTextureManager); loaded = load(file, normalized, mTextureManager, mNifFileManager);
} }
osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get());

@ -10,6 +10,7 @@
namespace Resource namespace Resource
{ {
class TextureManager; class TextureManager;
class NifFileManager;
} }
namespace VFS namespace VFS
@ -34,7 +35,7 @@ namespace Resource
class SceneManager class SceneManager
{ {
public: public:
SceneManager(const VFS::Manager* vfs, Resource::TextureManager* textureManager); SceneManager(const VFS::Manager* vfs, Resource::TextureManager* textureManager, Resource::NifFileManager* nifFileManager);
~SceneManager(); ~SceneManager();
/// Get a read-only copy of this scene "template" /// Get a read-only copy of this scene "template"
@ -66,7 +67,7 @@ namespace Resource
/// Set up an IncrementalCompileOperation for background compiling of loaded scenes. /// Set up an IncrementalCompileOperation for background compiling of loaded scenes.
void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico); void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico);
/// @note If you used SceneManager::attachTo, this was called automatically. /// @note SceneManager::attachTo calls this method automatically, only needs to be called by users if manually attaching
void notifyAttached(osg::Node* node) const; void notifyAttached(osg::Node* node) const;
const VFS::Manager* getVFS() const; const VFS::Manager* getVFS() const;
@ -79,6 +80,7 @@ namespace Resource
private: private:
const VFS::Manager* mVFS; const VFS::Manager* mVFS;
Resource::TextureManager* mTextureManager; Resource::TextureManager* mTextureManager;
Resource::NifFileManager* mNifFileManager;
osg::ref_ptr<osgUtil::IncrementalCompileOperation> mIncrementalCompileOperation; osg::ref_ptr<osgUtil::IncrementalCompileOperation> mIncrementalCompileOperation;

Loading…
Cancel
Save