#include "actor.hpp" #include #include #include #include #include #include #include #include #include #include #include "../../model/world/data.hpp" namespace CSVRender { const std::string Actor::MeshPrefix = "meshes\\"; Actor::Actor(const std::string& id, int type, CSMWorld::Data& data) : mId(id) , mInitialized(false) , mType(type) , mData(data) , mBaseNode(new osg::Group()) , mSkeleton(nullptr) { mActorData = mData.getActorAdapter()->getActorData(mId); } osg::Group* Actor::getBaseNode() { return mBaseNode; } void Actor::update() { try { mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); if (mType == CSMWorld::UniversalId::Type_Npc) updateNpc(); else if (mType == CSMWorld::UniversalId::Type_Creature) updateCreature(); } catch (std::exception& e) { Log(Debug::Info) << "Exception in Actor::update(): " << e.what(); } if (!mInitialized) { mInitialized = true; connect(mData.getActorAdapter(), SIGNAL(actorChanged(const std::string&)), this, SLOT(handleActorChanged(const std::string&))); } } void Actor::handleActorChanged(const std::string& refId) { if (mId == refId) { update(); } } void Actor::updateCreature() { auto& referenceables = mData.getReferenceables(); auto& creature = dynamic_cast& >(referenceables.getRecord(mId)).get(); // Load skeleton with meshes std::string skeletonModel = MeshPrefix + creature.mModel; skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); loadSkeleton(skeletonModel); SceneUtil::RemoveTriBipVisitor removeTriBipVisitor; mSkeleton->accept(removeTriBipVisitor); removeTriBipVisitor.remove(); // Post setup mSkeleton->markDirty(); mSkeleton->setActive(SceneUtil::Skeleton::Active); } void Actor::updateNpc() { auto& races = mData.getRaces(); auto& referenceables = mData.getReferenceables(); auto& npc = dynamic_cast& >(referenceables.getRecord(mId)).get(); auto& race = dynamic_cast& >(races.getRecord(npc.mRace)).get(); bool is1stPerson = false; bool isFemale = !npc.isMale(); bool isBeast = race.mData.mFlags & ESM::Race::Beast; bool isWerewolf = false; // Load skeleton std::string skeletonModel = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf); skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); loadSkeleton(skeletonModel); // Get rid of the extra attachments SceneUtil::CleanObjectRootVisitor cleanVisitor; mSkeleton->accept(cleanVisitor); cleanVisitor.remove(); // Attach parts to skeleton loadBodyParts(npc.mId); // Post setup mSkeleton->markDirty(); mSkeleton->setActive(SceneUtil::Skeleton::Active); } void Actor::loadSkeleton(const std::string& model) { auto sceneMgr = mData.getResourceSystem()->getSceneManager(); osg::ref_ptr temp = sceneMgr->getInstance(model); mSkeleton = dynamic_cast(temp.get()); if (!mSkeleton) { mSkeleton = new SceneUtil::Skeleton(); mSkeleton->addChild(temp); } mBaseNode->addChild(mSkeleton); // Map bone names to bones mNodeMap.clear(); SceneUtil::NodeMapVisitor nmVisitor(mNodeMap); mSkeleton->accept(nmVisitor); } void Actor::loadBodyParts(const std::string& actorId) { for (int i = 0; i < ESM::PRT_Count; ++i) { auto type = (ESM::PartReferenceType) i; std::string partId = mActorData->getPart(type); attachBodyPart(type, getBodyPartMesh(partId)); } } void Actor::attachBodyPart(ESM::PartReferenceType type, const std::string& mesh) { auto sceneMgr = mData.getResourceSystem()->getSceneManager(); // Attach to skeleton std::string boneName = ESM::getBoneName(type); auto node = mNodeMap.find(boneName); if (!mesh.empty() && node != mNodeMap.end()) { auto instance = sceneMgr->getInstance(mesh); SceneUtil::attach(instance, mSkeleton, boneName, node->second); } } std::string Actor::getBodyPartMesh(const std::string& bodyPartId) { const auto& bodyParts = mData.getBodyParts(); int index = bodyParts.searchId(bodyPartId); if (index != -1 && !bodyParts.getRecord(index).isDeleted()) return MeshPrefix + bodyParts.getRecord(index).get().mModel; else return ""; } }