mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-20 15:40:32 +00:00
Preload instances in SceneManager
This commit is contained in:
parent
2e62298bd3
commit
e28dc3e72f
@ -100,7 +100,7 @@ void CSVRender::Object::update()
|
||||
{
|
||||
std::string path = "meshes\\" + model;
|
||||
|
||||
mResourceSystem->getSceneManager()->createInstance(path, mBaseNode);
|
||||
mResourceSystem->getSceneManager()->getInstance(path, mBaseNode);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
|
@ -997,7 +997,7 @@ namespace MWRender
|
||||
|
||||
if (!forceskeleton)
|
||||
{
|
||||
osg::ref_ptr<osg::Node> created = mResourceSystem->getSceneManager()->createInstance(model, mInsert);
|
||||
osg::ref_ptr<osg::Node> created = mResourceSystem->getSceneManager()->getInstance(model, mInsert);
|
||||
mObjectRoot = created->asGroup();
|
||||
if (!mObjectRoot)
|
||||
{
|
||||
@ -1009,7 +1009,7 @@ namespace MWRender
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::ref_ptr<osg::Node> created = mResourceSystem->getSceneManager()->createInstance(model);
|
||||
osg::ref_ptr<osg::Node> created = mResourceSystem->getSceneManager()->getInstance(model);
|
||||
osg::ref_ptr<SceneUtil::Skeleton> skel = dynamic_cast<SceneUtil::Skeleton*>(created.get());
|
||||
if (!skel)
|
||||
{
|
||||
@ -1136,7 +1136,7 @@ namespace MWRender
|
||||
|
||||
parentNode = found->second;
|
||||
}
|
||||
osg::ref_ptr<osg::Node> node = mResourceSystem->getSceneManager()->createInstance(model, parentNode);
|
||||
osg::ref_ptr<osg::Node> node = mResourceSystem->getSceneManager()->getInstance(model, parentNode);
|
||||
|
||||
node->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
|
||||
|
@ -105,7 +105,7 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot)
|
||||
else
|
||||
bonename = "Shield Bone";
|
||||
|
||||
osg::ref_ptr<osg::Node> node = mResourceSystem->getSceneManager()->createInstance(item.getClass().getModel(item));
|
||||
osg::ref_ptr<osg::Node> node = mResourceSystem->getSceneManager()->getInstance(item.getClass().getModel(item));
|
||||
osg::ref_ptr<osg::Node> attached = SceneUtil::attach(node, mObjectRoot, bonename, bonename);
|
||||
mResourceSystem->getSceneManager()->notifyAttached(attached);
|
||||
|
||||
|
@ -27,7 +27,7 @@ EffectManager::~EffectManager()
|
||||
|
||||
void EffectManager::addEffect(const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, float scale)
|
||||
{
|
||||
osg::ref_ptr<osg::Node> node = mResourceSystem->getSceneManager()->createInstance(model);
|
||||
osg::ref_ptr<osg::Node> node = mResourceSystem->getSceneManager()->getInstance(model);
|
||||
|
||||
node->setNodeMask(Mask_Effect);
|
||||
|
||||
|
@ -647,7 +647,7 @@ void NpcAnimation::updateParts()
|
||||
|
||||
PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor)
|
||||
{
|
||||
osg::ref_ptr<osg::Node> instance = mResourceSystem->getSceneManager()->createInstance(model);
|
||||
osg::ref_ptr<osg::Node> instance = mResourceSystem->getSceneManager()->getInstance(model);
|
||||
osg::ref_ptr<osg::Node> attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename);
|
||||
mResourceSystem->getSceneManager()->notifyAttached(attached);
|
||||
if (enchantedGlow)
|
||||
|
@ -1146,7 +1146,7 @@ void SkyManager::create()
|
||||
{
|
||||
assert(!mCreated);
|
||||
|
||||
mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mEarlyRenderBinRoot);
|
||||
mAtmosphereDay = mSceneManager->getInstance("meshes/sky_atmosphere.nif", mEarlyRenderBinRoot);
|
||||
ModVertexAlphaVisitor modAtmosphere(0);
|
||||
mAtmosphereDay->accept(modAtmosphere);
|
||||
|
||||
@ -1159,9 +1159,9 @@ void SkyManager::create()
|
||||
|
||||
osg::ref_ptr<osg::Node> atmosphereNight;
|
||||
if (mSceneManager->getVFS()->exists("meshes/sky_night_02.nif"))
|
||||
atmosphereNight = mSceneManager->createInstance("meshes/sky_night_02.nif", mAtmosphereNightNode);
|
||||
atmosphereNight = mSceneManager->getInstance("meshes/sky_night_02.nif", mAtmosphereNightNode);
|
||||
else
|
||||
atmosphereNight = mSceneManager->createInstance("meshes/sky_night_01.nif", mAtmosphereNightNode);
|
||||
atmosphereNight = mSceneManager->getInstance("meshes/sky_night_01.nif", mAtmosphereNightNode);
|
||||
atmosphereNight->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
||||
ModVertexAlphaVisitor modStars(2);
|
||||
atmosphereNight->accept(modStars);
|
||||
@ -1176,14 +1176,14 @@ void SkyManager::create()
|
||||
|
||||
mCloudNode = new osg::PositionAttitudeTransform;
|
||||
mEarlyRenderBinRoot->addChild(mCloudNode);
|
||||
mCloudMesh = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode);
|
||||
mCloudMesh = mSceneManager->getInstance("meshes/sky_clouds_01.nif", mCloudNode);
|
||||
ModVertexAlphaVisitor modClouds(1);
|
||||
mCloudMesh->accept(modClouds);
|
||||
mCloudUpdater = new CloudUpdater;
|
||||
mCloudUpdater->setOpacity(1.f);
|
||||
mCloudMesh->addUpdateCallback(mCloudUpdater);
|
||||
|
||||
mCloudMesh2 = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode);
|
||||
mCloudMesh2 = mSceneManager->getInstance("meshes/sky_clouds_01.nif", mCloudNode);
|
||||
mCloudMesh2->accept(modClouds);
|
||||
mCloudUpdater2 = new CloudUpdater;
|
||||
mCloudUpdater2->setOpacity(0.f);
|
||||
@ -1537,7 +1537,7 @@ void SkyManager::setWeather(const WeatherResult& weather)
|
||||
mParticleNode->setNodeMask(Mask_WeatherParticles);
|
||||
mRootNode->addChild(mParticleNode);
|
||||
}
|
||||
mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode);
|
||||
mParticleEffect = mSceneManager->getInstance(mCurrentParticleEffect, mParticleNode);
|
||||
|
||||
SceneUtil::AssignControllerSourcesVisitor assignVisitor(boost::shared_ptr<SceneUtil::ControllerSource>(new SceneUtil::FrameTimeSource));
|
||||
mParticleEffect->accept(assignVisitor);
|
||||
|
@ -84,7 +84,7 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor)
|
||||
return;
|
||||
std::string model = ammo->getClass().getModel(*ammo);
|
||||
|
||||
osg::ref_ptr<osg::Node> arrow = getResourceSystem()->getSceneManager()->createInstance(model, parent);
|
||||
osg::ref_ptr<osg::Node> arrow = getResourceSystem()->getSceneManager()->getInstance(model, parent);
|
||||
|
||||
mAmmunition = PartHolderPtr(new PartHolder(arrow));
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ namespace MWWorld
|
||||
|
||||
//std::cout << "preloading " << mesh << std::endl;
|
||||
|
||||
mPreloadedNodes.push_back(mSceneManager->getTemplate(mesh));
|
||||
mPreloadedNodes.push_back(mSceneManager->cacheInstance(mesh));
|
||||
mPreloadedShapes.push_back(mBulletShapeManager->getShape(mesh));
|
||||
|
||||
size_t slashpos = mesh.find_last_of("/\\");
|
||||
@ -104,8 +104,6 @@ namespace MWWorld
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: do a createInstance() and hold on to it since we can make use of it when the cell goes active
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
@ -185,6 +183,11 @@ namespace MWWorld
|
||||
mPreloadCells[cell] = PreloadEntry(timestamp, item);
|
||||
}
|
||||
|
||||
void CellPreloader::notifyLoaded(CellStore *cell)
|
||||
{
|
||||
mPreloadCells.erase(cell);
|
||||
}
|
||||
|
||||
void CellPreloader::updateCache(double timestamp)
|
||||
{
|
||||
// TODO: add settings for a minimum/maximum size of the cache
|
||||
|
@ -24,6 +24,8 @@ namespace MWWorld
|
||||
/// @note The cell itself must be in State_Loaded or State_Preloaded.
|
||||
void preload(MWWorld::CellStore* cell, double timestamp);
|
||||
|
||||
void notifyLoaded(MWWorld::CellStore* cell);
|
||||
|
||||
/// Removes preloaded cells that have not had a preload request for a while.
|
||||
void updateCache(double timestamp);
|
||||
|
||||
|
@ -92,7 +92,7 @@ namespace MWWorld
|
||||
attachTo = rotateNode;
|
||||
}
|
||||
|
||||
mResourceSystem->getSceneManager()->createInstance(model, attachTo);
|
||||
mResourceSystem->getSceneManager()->getInstance(model, attachTo);
|
||||
|
||||
SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor;
|
||||
state.mNode->accept(disableFreezeOnCullVisitor);
|
||||
|
@ -296,6 +296,8 @@ namespace MWWorld
|
||||
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
|
||||
mRendering.configureAmbient(cell->getCell());
|
||||
}
|
||||
|
||||
mPreloader->notifyLoaded(cell);
|
||||
}
|
||||
|
||||
void Scene::changeToVoid()
|
||||
|
@ -41,7 +41,7 @@ add_component_dir (vfs
|
||||
)
|
||||
|
||||
add_component_dir (resource
|
||||
scenemanager keyframemanager imagemanager bulletshapemanager bulletshape niffilemanager objectcache resourcesystem resourcemanager
|
||||
scenemanager keyframemanager imagemanager bulletshapemanager bulletshape niffilemanager objectcache multiobjectcache resourcesystem resourcemanager
|
||||
)
|
||||
|
||||
add_component_dir (sceneutil
|
||||
|
79
components/resource/multiobjectcache.cpp
Normal file
79
components/resource/multiobjectcache.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include "multiobjectcache.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <osg/Object>
|
||||
|
||||
namespace Resource
|
||||
{
|
||||
|
||||
MultiObjectCache::MultiObjectCache()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MultiObjectCache::~MultiObjectCache()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MultiObjectCache::removeUnreferencedObjectsInCache()
|
||||
{
|
||||
std::vector<osg::ref_ptr<osg::Object> > objectsToRemove;
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
||||
|
||||
// Remove unreferenced entries from object cache
|
||||
ObjectCacheMap::iterator oitr = _objectCache.begin();
|
||||
while(oitr != _objectCache.end())
|
||||
{
|
||||
if (oitr->second->referenceCount() <= 1)
|
||||
{
|
||||
objectsToRemove.push_back(oitr->second);
|
||||
_objectCache.erase(oitr++);
|
||||
}
|
||||
else
|
||||
{
|
||||
++oitr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// note, actual unref happens outside of the lock
|
||||
objectsToRemove.clear();
|
||||
}
|
||||
|
||||
void MultiObjectCache::addEntryToObjectCache(const std::string &filename, osg::Object *object)
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
||||
_objectCache.insert(std::make_pair(filename, object));
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Object> MultiObjectCache::takeFromObjectCache(const std::string &fileName)
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
||||
ObjectCacheMap::iterator found = _objectCache.find(fileName);
|
||||
if (found == _objectCache.end())
|
||||
return osg::ref_ptr<osg::Object>();
|
||||
else
|
||||
{
|
||||
osg::ref_ptr<osg::Object> object = found->second;
|
||||
_objectCache.erase(found);
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiObjectCache::releaseGLObjects(osg::State *state)
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
||||
|
||||
for(ObjectCacheMap::iterator itr = _objectCache.begin();
|
||||
itr != _objectCache.end();
|
||||
++itr)
|
||||
{
|
||||
osg::Object* object = itr->second.get();
|
||||
object->releaseGLObjects(state);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
47
components/resource/multiobjectcache.hpp
Normal file
47
components/resource/multiobjectcache.hpp
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef OPENMW_COMPONENTS_MULTIOBJECTCACHE_H
|
||||
#define OPENMW_COMPONENTS_MULTIOBJECTCACHE_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Referenced>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Object;
|
||||
class State;
|
||||
}
|
||||
|
||||
namespace Resource
|
||||
{
|
||||
|
||||
/// @brief Cache for "non reusable" objects.
|
||||
class MultiObjectCache : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
MultiObjectCache();
|
||||
~MultiObjectCache();
|
||||
|
||||
void removeUnreferencedObjectsInCache();
|
||||
|
||||
void addEntryToObjectCache(const std::string& filename, osg::Object* object);
|
||||
|
||||
/** Take an Object from cache. Return NULL if no object found. */
|
||||
osg::ref_ptr<osg::Object> takeFromObjectCache(const std::string& fileName);
|
||||
|
||||
/** call releaseGLObjects on all objects attached to the object cache.*/
|
||||
void releaseGLObjects(osg::State* state);
|
||||
|
||||
protected:
|
||||
|
||||
typedef std::multimap<std::string, osg::ref_ptr<osg::Object> > ObjectCacheMap;
|
||||
|
||||
ObjectCacheMap _objectCache;
|
||||
OpenThreads::Mutex _objectCacheMutex;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -28,6 +28,7 @@
|
||||
#include "imagemanager.hpp"
|
||||
#include "niffilemanager.hpp"
|
||||
#include "objectcache.hpp"
|
||||
#include "multiobjectcache.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -233,6 +234,7 @@ namespace Resource
|
||||
|
||||
SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager)
|
||||
: ResourceManager(vfs)
|
||||
, mInstanceCache(new MultiObjectCache)
|
||||
, mImageManager(imageManager)
|
||||
, mNifFileManager(nifFileManager)
|
||||
, mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR)
|
||||
@ -246,7 +248,6 @@ namespace Resource
|
||||
SceneManager::~SceneManager()
|
||||
{
|
||||
// this has to be defined in the .cpp file as we can't delete incomplete types
|
||||
|
||||
}
|
||||
|
||||
/// @brief Callback to read image files from the VFS.
|
||||
@ -372,7 +373,17 @@ namespace Resource
|
||||
}
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Node> SceneManager::createInstance(const std::string &name)
|
||||
osg::ref_ptr<osg::Node> SceneManager::cacheInstance(const std::string &name)
|
||||
{
|
||||
std::string normalized = name;
|
||||
mVFS->normalizeFilename(normalized);
|
||||
|
||||
osg::ref_ptr<osg::Node> node = createInstance(normalized);
|
||||
mInstanceCache->addEntryToObjectCache(normalized, node.get());
|
||||
return node;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Node> SceneManager::createInstance(const std::string& name)
|
||||
{
|
||||
osg::ref_ptr<const osg::Node> scene = getTemplate(name);
|
||||
osg::ref_ptr<osg::Node> cloned = osg::clone(scene.get(), SceneUtil::CopyOp());
|
||||
@ -383,9 +394,22 @@ namespace Resource
|
||||
return cloned;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Node> SceneManager::createInstance(const std::string &name, osg::Group* parentNode)
|
||||
osg::ref_ptr<osg::Node> SceneManager::getInstance(const std::string &name)
|
||||
{
|
||||
osg::ref_ptr<osg::Node> cloned = createInstance(name);
|
||||
std::string normalized = name;
|
||||
mVFS->normalizeFilename(normalized);
|
||||
|
||||
osg::ref_ptr<osg::Object> obj = mInstanceCache->takeFromObjectCache(normalized);
|
||||
if (obj.get())
|
||||
return static_cast<osg::Node*>(obj.get());
|
||||
|
||||
return createInstance(normalized);
|
||||
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Node> SceneManager::getInstance(const std::string &name, osg::Group* parentNode)
|
||||
{
|
||||
osg::ref_ptr<osg::Node> cloned = getInstance(name);
|
||||
attachTo(cloned, parentNode);
|
||||
return cloned;
|
||||
}
|
||||
@ -487,4 +511,11 @@ namespace Resource
|
||||
mUnRefImageDataAfterApply = unref;
|
||||
}
|
||||
|
||||
void SceneManager::updateCache(double referenceTime)
|
||||
{
|
||||
ResourceManager::updateCache(referenceTime);
|
||||
|
||||
mInstanceCache->removeUnreferencedObjectsInCache();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ namespace osgViewer
|
||||
namespace Resource
|
||||
{
|
||||
|
||||
class MultiObjectCache;
|
||||
|
||||
/// @brief Handles loading and caching of scenes, e.g. .nif files or .osg files
|
||||
/// @note Some methods of the scene manager can be used from any thread, see the methods documentation for more details.
|
||||
class SceneManager : public ResourceManager
|
||||
@ -43,15 +45,21 @@ namespace Resource
|
||||
/// @note Thread safe.
|
||||
osg::ref_ptr<const osg::Node> getTemplate(const std::string& name);
|
||||
|
||||
/// Create an instance of the given scene template
|
||||
/// Create an instance of the given scene template and cache it for later use, so that future calls to getInstance() can simply
|
||||
/// return this cached object instead of creating a new one.
|
||||
/// @note The returned ref_ptr may be kept around by the caller to ensure that the object stays in cache for as long as needed.
|
||||
/// @note Thread safe.
|
||||
osg::ref_ptr<osg::Node> cacheInstance(const std::string& name);
|
||||
|
||||
/// Get an instance of the given scene template
|
||||
/// @see getTemplate
|
||||
/// @note Thread safe.
|
||||
osg::ref_ptr<osg::Node> createInstance(const std::string& name);
|
||||
osg::ref_ptr<osg::Node> getInstance(const std::string& name);
|
||||
|
||||
/// Create an instance of the given scene template and immediately attach it to a parent node
|
||||
/// Get an instance of the given scene template and immediately attach it to a parent node
|
||||
/// @see getTemplate
|
||||
/// @note Not thread safe, unless parentNode is not part of the main scene graph yet.
|
||||
osg::ref_ptr<osg::Node> createInstance(const std::string& name, osg::Group* parentNode);
|
||||
osg::ref_ptr<osg::Node> getInstance(const std::string& name, osg::Group* parentNode);
|
||||
|
||||
/// Attach the given scene instance to the given parent node
|
||||
/// @note You should have the parentNode in its intended position before calling this method,
|
||||
@ -88,7 +96,15 @@ namespace Resource
|
||||
/// otherwise should be disabled to reduce memory usage.
|
||||
void setUnRefImageDataAfterApply(bool unref);
|
||||
|
||||
/// @see ResourceManager::updateCache
|
||||
virtual void updateCache(double referenceTime);
|
||||
|
||||
private:
|
||||
|
||||
osg::ref_ptr<osg::Node> createInstance(const std::string& name);
|
||||
|
||||
osg::ref_ptr<MultiObjectCache> mInstanceCache;
|
||||
|
||||
OpenThreads::Mutex mSharedStateMutex;
|
||||
|
||||
Resource::ImageManager* mImageManager;
|
||||
|
Loading…
x
Reference in New Issue
Block a user