Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142#include "actor.hpp"
#include <memory>#include <unordered_map>#include <utility>
#include <osg/Group>#include <osg/MatrixTransform>#include <osg/Node>#include <osg/Vec3d>
#include <apps/opencs/model/world/actoradapter.hpp>#include <apps/opencs/model/world/idcollection.hpp>#include <apps/opencs/model/world/record.hpp>
#include <components/esm3/loadbody.hpp>#include <components/esm3/mappings.hpp>#include <components/misc/resourcehelpers.hpp>#include <components/resource/resourcesystem.hpp>#include <components/resource/scenemanager.hpp>#include <components/sceneutil/attach.hpp>#include <components/sceneutil/skeleton.hpp>
#include "../../model/world/data.hpp"
namespace CSVRender{ Actor::Actor(const ESM::RefId& id, CSMWorld::Data& data) : mId(id) , mData(data) , mBaseNode(new osg::PositionAttitudeTransform()) , mSkeleton(nullptr) { mActorData = mData.getActorAdapter()->getActorData(mId); connect(mData.getActorAdapter(), &CSMWorld::ActorAdapter::actorChanged, this, &Actor::handleActorChanged); }
osg::Group* Actor::getBaseNode() { return mBaseNode; }
void Actor::update() { mBaseNode->removeChildren(0, mBaseNode->getNumChildren());
// Load skeleton VFS::Path::Normalized skeletonModel = mActorData->getSkeleton(); skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); loadSkeleton(skeletonModel);
if (!mActorData->isCreature()) { // Get rid of the extra attachments SceneUtil::CleanObjectRootVisitor cleanVisitor; mSkeleton->accept(cleanVisitor); cleanVisitor.remove();
// Attach parts to skeleton loadBodyParts();
const osg::Vec2f& attributes = mActorData->getRaceWeightHeight();
mBaseNode->setScale(osg::Vec3d(attributes.x(), attributes.x(), attributes.y())); } else { SceneUtil::RemoveTriBipVisitor removeTriBipVisitor; mSkeleton->accept(removeTriBipVisitor); removeTriBipVisitor.remove(); }
// Post setup mSkeleton->markDirty(); mSkeleton->setActive(SceneUtil::Skeleton::Active); }
void Actor::handleActorChanged(const ESM::RefId& refId) { if (mId == refId) { update(); } }
void Actor::loadSkeleton(const std::string& model) { auto sceneMgr = mData.getResourceSystem()->getSceneManager();
osg::ref_ptr<osg::Node> temp = sceneMgr->getInstance(VFS::Path::toNormalized(model)); mSkeleton = dynamic_cast<SceneUtil::Skeleton*>(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() { for (int i = 0; i < ESM::PRT_Count; ++i) { const auto type = static_cast<ESM::PartReferenceType>(i); attachBodyPart(type, getBodyPartMesh(mActorData->getPart(type))); } }
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(VFS::Path::toNormalized(mesh)); SceneUtil::attach(instance, mSkeleton, boneName, node->second, sceneMgr); } }
std::string Actor::getBodyPartMesh(const ESM::RefId& bodyPartId) { constexpr VFS::Path::NormalizedView meshPrefix("meshes/");
const auto& bodyParts = mData.getBodyParts();
const int index = bodyParts.searchId(bodyPartId); if (index != -1 && !bodyParts.getRecord(index).isDeleted()) return VFS::Path::join(meshPrefix, bodyParts.getRecord(index).get().mModel.getNormalized()).value(); else return ""; }}