2018-07-14 02:48:59 +00:00
|
|
|
#include "actor.hpp"
|
|
|
|
|
2022-10-10 11:41:36 +00:00
|
|
|
#include <memory>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <utility>
|
|
|
|
|
2018-07-14 02:48:59 +00:00
|
|
|
#include <osg/Group>
|
2022-10-10 11:41:36 +00:00
|
|
|
#include <osg/MatrixTransform>
|
2018-07-14 02:48:59 +00:00
|
|
|
#include <osg/Node>
|
|
|
|
|
2022-10-10 11:41:36 +00:00
|
|
|
#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>
|
2022-01-22 14:58:41 +00:00
|
|
|
#include <components/esm3/mappings.hpp>
|
2018-07-14 02:48:59 +00:00
|
|
|
#include <components/misc/resourcehelpers.hpp>
|
2022-10-10 11:41:36 +00:00
|
|
|
#include <components/resource/resourcesystem.hpp>
|
2018-07-14 02:48:59 +00:00
|
|
|
#include <components/resource/scenemanager.hpp>
|
|
|
|
#include <components/sceneutil/attach.hpp>
|
|
|
|
#include <components/sceneutil/skeleton.hpp>
|
|
|
|
|
|
|
|
#include "../../model/world/data.hpp"
|
|
|
|
|
|
|
|
namespace CSVRender
|
|
|
|
{
|
2018-07-22 20:38:30 +00:00
|
|
|
const std::string Actor::MeshPrefix = "meshes\\";
|
|
|
|
|
2022-10-06 17:39:46 +00:00
|
|
|
Actor::Actor(const ESM::RefId& id, CSMWorld::Data& data)
|
2018-07-14 02:48:59 +00:00
|
|
|
: mId(id)
|
|
|
|
, mData(data)
|
|
|
|
, mBaseNode(new osg::Group())
|
2018-07-28 17:23:43 +00:00
|
|
|
, mSkeleton(nullptr)
|
2018-07-14 02:48:59 +00:00
|
|
|
{
|
2018-08-26 05:13:50 +00:00
|
|
|
mActorData = mData.getActorAdapter()->getActorData(mId);
|
2022-08-23 02:28:58 +00:00
|
|
|
connect(mData.getActorAdapter(), &CSMWorld::ActorAdapter::actorChanged, this, &Actor::handleActorChanged);
|
2018-07-14 02:48:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
osg::Group* Actor::getBaseNode()
|
|
|
|
{
|
|
|
|
return mBaseNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::update()
|
|
|
|
{
|
2018-09-08 06:06:48 +00:00
|
|
|
mBaseNode->removeChildren(0, mBaseNode->getNumChildren());
|
|
|
|
|
|
|
|
// Load skeleton
|
|
|
|
std::string skeletonModel = mActorData->getSkeleton();
|
|
|
|
skeletonModel
|
|
|
|
= Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS());
|
|
|
|
loadSkeleton(skeletonModel);
|
|
|
|
|
|
|
|
if (!mActorData->isCreature())
|
2018-07-22 20:38:30 +00:00
|
|
|
{
|
2018-09-08 06:06:48 +00:00
|
|
|
// Get rid of the extra attachments
|
|
|
|
SceneUtil::CleanObjectRootVisitor cleanVisitor;
|
|
|
|
mSkeleton->accept(cleanVisitor);
|
|
|
|
cleanVisitor.remove();
|
2018-07-22 20:38:30 +00:00
|
|
|
|
2018-09-08 06:06:48 +00:00
|
|
|
// Attach parts to skeleton
|
|
|
|
loadBodyParts();
|
2018-07-22 20:38:30 +00:00
|
|
|
}
|
2018-09-08 06:06:48 +00:00
|
|
|
else
|
2018-07-22 20:38:30 +00:00
|
|
|
{
|
2018-09-08 06:06:48 +00:00
|
|
|
SceneUtil::RemoveTriBipVisitor removeTriBipVisitor;
|
|
|
|
mSkeleton->accept(removeTriBipVisitor);
|
|
|
|
removeTriBipVisitor.remove();
|
2018-08-24 02:40:43 +00:00
|
|
|
}
|
|
|
|
|
2018-09-08 06:06:48 +00:00
|
|
|
// Post setup
|
|
|
|
mSkeleton->markDirty();
|
|
|
|
mSkeleton->setActive(SceneUtil::Skeleton::Active);
|
2018-08-24 02:40:43 +00:00
|
|
|
}
|
|
|
|
|
2022-10-06 17:39:46 +00:00
|
|
|
void Actor::handleActorChanged(const ESM::RefId& refId)
|
2018-08-24 02:40:43 +00:00
|
|
|
{
|
|
|
|
if (mId == refId)
|
|
|
|
{
|
|
|
|
update();
|
2018-07-22 20:38:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::loadSkeleton(const std::string& model)
|
|
|
|
{
|
|
|
|
auto sceneMgr = mData.getResourceSystem()->getSceneManager();
|
|
|
|
|
|
|
|
osg::ref_ptr<osg::Node> temp = sceneMgr->getInstance(model);
|
|
|
|
mSkeleton = dynamic_cast<SceneUtil::Skeleton*>(temp.get());
|
|
|
|
if (!mSkeleton)
|
2018-07-18 02:28:05 +00:00
|
|
|
{
|
2018-07-22 20:38:30 +00:00
|
|
|
mSkeleton = new SceneUtil::Skeleton();
|
|
|
|
mSkeleton->addChild(temp);
|
2018-07-14 02:48:59 +00:00
|
|
|
}
|
2018-07-22 20:38:30 +00:00
|
|
|
mBaseNode->addChild(mSkeleton);
|
2018-07-28 17:23:43 +00:00
|
|
|
|
|
|
|
// Map bone names to bones
|
|
|
|
mNodeMap.clear();
|
|
|
|
SceneUtil::NodeMapVisitor nmVisitor(mNodeMap);
|
|
|
|
mSkeleton->accept(nmVisitor);
|
|
|
|
}
|
|
|
|
|
2018-09-08 06:06:48 +00:00
|
|
|
void Actor::loadBodyParts()
|
2018-07-28 17:23:43 +00:00
|
|
|
{
|
2018-08-26 05:13:50 +00:00
|
|
|
for (int i = 0; i < ESM::PRT_Count; ++i)
|
2018-07-28 17:23:43 +00:00
|
|
|
{
|
2018-08-26 05:13:50 +00:00
|
|
|
auto type = (ESM::PartReferenceType)i;
|
2021-09-04 16:07:23 +00:00
|
|
|
const std::string_view partId = mActorData->getPart(type);
|
2018-08-26 05:13:50 +00:00
|
|
|
attachBodyPart(type, getBodyPartMesh(partId));
|
2018-07-28 17:23:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2021-10-23 08:31:46 +00:00
|
|
|
SceneUtil::attach(instance, mSkeleton, boneName, node->second, sceneMgr);
|
2018-07-28 17:23:43 +00:00
|
|
|
}
|
2018-07-22 20:38:30 +00:00
|
|
|
}
|
|
|
|
|
2021-09-04 16:07:23 +00:00
|
|
|
std::string Actor::getBodyPartMesh(std::string_view bodyPartId)
|
2018-07-22 20:38:30 +00:00
|
|
|
{
|
|
|
|
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 "";
|
2018-07-14 02:48:59 +00:00
|
|
|
}
|
|
|
|
}
|