#include "objects.hpp" #include #include #include #include #include #include "../mwworld/class.hpp" #include "../mwworld/ptr.hpp" #include "animation.hpp" #include "creatureanimation.hpp" #include "npcanimation.hpp" #include "vismask.hpp" namespace MWRender { Objects::Objects(Resource::ResourceSystem* resourceSystem, const osg::ref_ptr& rootNode, SceneUtil::UnrefQueue& unrefQueue) : mRootNode(rootNode) , mResourceSystem(resourceSystem) , mUnrefQueue(unrefQueue) { } 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.mRef) == mObjects.end()); osg::ref_ptr 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 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 allowLight) { insertBegin(ptr); ptr.getRefData().getBaseNode()->setNodeMask(Mask_Object); bool animated = ptr.getClass().useAnim(); std::string animationMesh = mesh; if (animated && !mesh.empty()) { animationMesh = Misc::ResourceHelpers::correctActorModelPath(mesh, mResourceSystem->getVFS()); if (animationMesh == mesh) animated = false; } osg::ref_ptr anim( new ObjectAnimation(ptr, animationMesh, mResourceSystem, animated, allowLight)); mObjects.emplace(ptr.mRef, std::move(anim)); } void Objects::insertCreature(const MWWorld::Ptr& ptr, const std::string& mesh, bool weaponsShields) { insertBegin(ptr); ptr.getRefData().getBaseNode()->setNodeMask(Mask_Actor); bool animated = true; std::string animationMesh = Misc::ResourceHelpers::correctActorModelPath(mesh, mResourceSystem->getVFS()); if (animationMesh == mesh) animated = false; // CreatureAnimation osg::ref_ptr anim; if (weaponsShields) anim = new CreatureWeaponAnimation(ptr, animationMesh, mResourceSystem, animated); else anim = new CreatureAnimation(ptr, animationMesh, mResourceSystem, animated); if (mObjects.emplace(ptr.mRef, anim).second) ptr.getClass().getContainerStore(ptr).setContListener(static_cast(anim.get())); } void Objects::insertNPC(const MWWorld::Ptr& ptr) { insertBegin(ptr); ptr.getRefData().getBaseNode()->setNodeMask(Mask_Actor); osg::ref_ptr anim( new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem)); if (mObjects.emplace(ptr.mRef, anim).second) { ptr.getClass().getInventoryStore(ptr).setInvListener(anim.get()); ptr.getClass().getInventoryStore(ptr).setContListener(anim.get()); } } bool Objects::removeObject(const MWWorld::Ptr& ptr) { if (!ptr.getRefData().getBaseNode()) return true; const auto iter = mObjects.find(ptr.mRef); if (iter != mObjects.end()) { iter->second->removeFromScene(); mUnrefQueue.push(std::move(iter->second)); mObjects.erase(iter); if (ptr.getClass().isActor()) { if (ptr.getClass().hasInventoryStore(ptr)) ptr.getClass().getInventoryStore(ptr).setInvListener(nullptr); 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().isActor() && ptr.getRefData().getCustomData()) { if (ptr.getClass().hasInventoryStore(ptr)) ptr.getClass().getInventoryStore(ptr).setInvListener(nullptr); ptr.getClass().getContainerStore(ptr).setContListener(nullptr); } iter->second->removeFromScene(); mUnrefQueue.push(std::move(iter->second)); iter = 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::ref_ptr 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(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.mRef); if (iter != mObjects.end()) iter->second->updatePtr(cur); } Animation* Objects::getAnimation(const MWWorld::Ptr& ptr) { PtrAnimationMap::const_iterator iter = mObjects.find(ptr.mRef); 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.mRef); if (iter != mObjects.end()) return iter->second; return nullptr; } }