mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-18 13:12:50 +00:00
a854a6e04a
Currently, we use an `UnrefQueue` which supposedly aims to transfer destruction costs to another thread. The implications of this unusual pattern can not be well understood because some allocators might free resources more efficiently if they are freed by the same thread that allocated them. In addition, `UnrefQueue` complicates the validation of thread safety in our engine. Lastly, our current usage of `UnrefQueue` triggers `ref()`, `unref()` atomic operations as objects are passed into the queue. These operations could be more expensive than the actual destruction. With this PR we thus remove `UnrefQueue`. We can expect these changes to have a minor impact at most because we free most resources elsewhere in `ResourceSystem::updateCache`.
223 lines
6.3 KiB
C++
223 lines
6.3 KiB
C++
#include "objects.hpp"
|
|
|
|
#include <osg/Group>
|
|
#include <osg/UserDataContainer>
|
|
|
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
|
|
|
#include "../mwworld/ptr.hpp"
|
|
#include "../mwworld/class.hpp"
|
|
|
|
#include "animation.hpp"
|
|
#include "npcanimation.hpp"
|
|
#include "creatureanimation.hpp"
|
|
#include "vismask.hpp"
|
|
|
|
|
|
namespace MWRender
|
|
{
|
|
|
|
Objects::Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> rootNode)
|
|
: mRootNode(rootNode)
|
|
, mResourceSystem(resourceSystem)
|
|
{
|
|
}
|
|
|
|
Objects::~Objects()
|
|
{
|
|
mObjects.clear();
|
|
|
|
for (CellMap::iterator iter = mCellSceneNodes.begin(); iter != mCellSceneNodes.end(); ++iter)
|
|
iter->second->getParent(0)->removeChild(iter->second);
|
|
mCellSceneNodes.clear();
|
|
}
|
|
|
|
void Objects::insertBegin(const MWWorld::Ptr& ptr)
|
|
{
|
|
assert(mObjects.find(ptr) == mObjects.end());
|
|
|
|
osg::ref_ptr<osg::Group> cellnode;
|
|
|
|
CellMap::iterator found = mCellSceneNodes.find(ptr.getCell());
|
|
if (found == mCellSceneNodes.end())
|
|
{
|
|
cellnode = new osg::Group;
|
|
cellnode->setName("Cell Root");
|
|
mRootNode->addChild(cellnode);
|
|
mCellSceneNodes[ptr.getCell()] = cellnode;
|
|
}
|
|
else
|
|
cellnode = found->second;
|
|
|
|
osg::ref_ptr<SceneUtil::PositionAttitudeTransform> insert (new SceneUtil::PositionAttitudeTransform);
|
|
cellnode->addChild(insert);
|
|
|
|
insert->getOrCreateUserDataContainer()->addUserObject(new PtrHolder(ptr));
|
|
|
|
const float *f = ptr.getRefData().getPosition().pos;
|
|
|
|
insert->setPosition(osg::Vec3(f[0], f[1], f[2]));
|
|
|
|
const float scale = ptr.getCellRef().getScale();
|
|
osg::Vec3f scaleVec(scale, scale, scale);
|
|
ptr.getClass().adjustScale(ptr, scaleVec, true);
|
|
insert->setScale(scaleVec);
|
|
|
|
ptr.getRefData().setBaseNode(insert);
|
|
}
|
|
|
|
void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool animated, bool allowLight)
|
|
{
|
|
insertBegin(ptr);
|
|
ptr.getRefData().getBaseNode()->setNodeMask(Mask_Object);
|
|
|
|
osg::ref_ptr<ObjectAnimation> anim (new ObjectAnimation(ptr, mesh, mResourceSystem, animated, allowLight));
|
|
|
|
mObjects.insert(std::make_pair(ptr, anim));
|
|
}
|
|
|
|
void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, bool weaponsShields)
|
|
{
|
|
insertBegin(ptr);
|
|
ptr.getRefData().getBaseNode()->setNodeMask(Mask_Actor);
|
|
|
|
// CreatureAnimation
|
|
osg::ref_ptr<Animation> anim;
|
|
|
|
if (weaponsShields)
|
|
anim = new CreatureWeaponAnimation(ptr, mesh, mResourceSystem);
|
|
else
|
|
anim = new CreatureAnimation(ptr, mesh, mResourceSystem);
|
|
|
|
if (mObjects.insert(std::make_pair(ptr, anim)).second)
|
|
ptr.getClass().getContainerStore(ptr).setContListener(static_cast<ActorAnimation*>(anim.get()));
|
|
}
|
|
|
|
void Objects::insertNPC(const MWWorld::Ptr &ptr)
|
|
{
|
|
insertBegin(ptr);
|
|
ptr.getRefData().getBaseNode()->setNodeMask(Mask_Actor);
|
|
|
|
osg::ref_ptr<NpcAnimation> anim (new NpcAnimation(ptr, osg::ref_ptr<osg::Group>(ptr.getRefData().getBaseNode()), mResourceSystem));
|
|
|
|
if (mObjects.insert(std::make_pair(ptr, anim)).second)
|
|
{
|
|
ptr.getClass().getInventoryStore(ptr).setInvListener(anim.get(), ptr);
|
|
ptr.getClass().getInventoryStore(ptr).setContListener(anim.get());
|
|
}
|
|
}
|
|
|
|
bool Objects::removeObject (const MWWorld::Ptr& ptr)
|
|
{
|
|
if(!ptr.getRefData().getBaseNode())
|
|
return true;
|
|
|
|
PtrAnimationMap::iterator iter = mObjects.find(ptr);
|
|
if(iter != mObjects.end())
|
|
{
|
|
mObjects.erase(iter);
|
|
|
|
if (ptr.getClass().isActor())
|
|
{
|
|
if (ptr.getClass().hasInventoryStore(ptr))
|
|
ptr.getClass().getInventoryStore(ptr).setInvListener(nullptr, ptr);
|
|
|
|
ptr.getClass().getContainerStore(ptr).setContListener(nullptr);
|
|
}
|
|
|
|
ptr.getRefData().getBaseNode()->getParent(0)->removeChild(ptr.getRefData().getBaseNode());
|
|
|
|
ptr.getRefData().setBaseNode(nullptr);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
void Objects::removeCell(const MWWorld::CellStore* store)
|
|
{
|
|
for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();)
|
|
{
|
|
MWWorld::Ptr ptr = iter->second->getPtr();
|
|
if(ptr.getCell() == store)
|
|
{
|
|
if (ptr.getClass().isNpc() && ptr.getRefData().getCustomData())
|
|
{
|
|
MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr);
|
|
invStore.setInvListener(nullptr, ptr);
|
|
invStore.setContListener(nullptr);
|
|
}
|
|
|
|
mObjects.erase(iter++);
|
|
}
|
|
else
|
|
++iter;
|
|
}
|
|
|
|
CellMap::iterator cell = mCellSceneNodes.find(store);
|
|
if(cell != mCellSceneNodes.end())
|
|
{
|
|
cell->second->getParent(0)->removeChild(cell->second);
|
|
mCellSceneNodes.erase(cell);
|
|
}
|
|
}
|
|
|
|
void Objects::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &cur)
|
|
{
|
|
osg::Node* objectNode = cur.getRefData().getBaseNode();
|
|
if (!objectNode)
|
|
return;
|
|
|
|
MWWorld::CellStore *newCell = cur.getCell();
|
|
|
|
osg::Group* cellnode;
|
|
if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) {
|
|
cellnode = new osg::Group;
|
|
mRootNode->addChild(cellnode);
|
|
mCellSceneNodes[newCell] = cellnode;
|
|
} else {
|
|
cellnode = mCellSceneNodes[newCell];
|
|
}
|
|
|
|
osg::UserDataContainer* userDataContainer = objectNode->getUserDataContainer();
|
|
if (userDataContainer)
|
|
for (unsigned int i=0; i<userDataContainer->getNumUserObjects(); ++i)
|
|
{
|
|
if (dynamic_cast<PtrHolder*>(userDataContainer->getUserObject(i)))
|
|
userDataContainer->setUserObject(i, new PtrHolder(cur));
|
|
}
|
|
|
|
if (objectNode->getNumParents())
|
|
objectNode->getParent(0)->removeChild(objectNode);
|
|
cellnode->addChild(objectNode);
|
|
|
|
PtrAnimationMap::iterator iter = mObjects.find(old);
|
|
if(iter != mObjects.end())
|
|
{
|
|
osg::ref_ptr<Animation> anim = iter->second;
|
|
mObjects.erase(iter);
|
|
anim->updatePtr(cur);
|
|
mObjects[cur] = anim;
|
|
}
|
|
}
|
|
|
|
Animation* Objects::getAnimation(const MWWorld::Ptr &ptr)
|
|
{
|
|
PtrAnimationMap::const_iterator iter = mObjects.find(ptr);
|
|
if(iter != mObjects.end())
|
|
return iter->second;
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
const Animation* Objects::getAnimation(const MWWorld::ConstPtr &ptr) const
|
|
{
|
|
PtrAnimationMap::const_iterator iter = mObjects.find(ptr);
|
|
if(iter != mObjects.end())
|
|
return iter->second;
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
}
|