1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 06:49:55 +00:00
openmw-tes3mp/apps/opencs/view/render/actor.cpp

162 lines
5 KiB
C++
Raw Normal View History

2018-07-14 02:48:59 +00:00
#include "actor.hpp"
#include <osg/Group>
#include <osg/Node>
2018-08-21 19:41:05 +00:00
#include <components/debug/debuglog.hpp>
2018-07-14 02:48:59 +00:00
#include <components/esm/mappings.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcemanager.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/sceneutil/actorutil.hpp>
2018-07-14 02:48:59 +00:00
#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\\";
2018-07-14 02:48:59 +00:00
Actor::Actor(const std::string& id, int type, CSMWorld::Data& data)
: mId(id)
, mType(type)
, mData(data)
, mBaseNode(new osg::Group())
, mSkeleton(nullptr)
2018-07-14 02:48:59 +00:00
{
}
osg::Group* Actor::getBaseNode()
{
return mBaseNode;
}
void Actor::update()
{
2018-07-22 20:38:30 +00:00
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)
{
2018-08-21 19:41:05 +00:00
Log(Debug::Error) << "Exception in Actor::update(): " << e.what();
2018-07-22 20:38:30 +00:00
}
}
void Actor::updateCreature()
{
auto& referenceables = mData.getReferenceables();
auto& creature = dynamic_cast<const CSMWorld::Record<ESM::Creature>& >(referenceables.getRecord(mId)).get();
// Load skeleton with meshes
2018-07-22 20:38:30 +00:00
std::string skeletonModel = MeshPrefix + creature.mModel;
skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS());
loadSkeleton(skeletonModel);
SceneUtil::RemoveTriBipVisitor removeTriBipVisitor;
mSkeleton->accept(removeTriBipVisitor);
removeTriBipVisitor.remove();
// Attach weapons
loadBodyParts(creature.mId);
2018-07-22 20:38:30 +00:00
// Post setup
mSkeleton->markDirty();
mSkeleton->setActive(SceneUtil::Skeleton::Active);
}
void Actor::updateNpc()
{
2018-07-14 02:48:59 +00:00
auto& races = mData.getRaces();
auto& referenceables = mData.getReferenceables();
2018-07-22 20:38:30 +00:00
auto& npc = dynamic_cast<const CSMWorld::Record<ESM::NPC>& >(referenceables.getRecord(mId)).get();
auto& race = dynamic_cast<const CSMWorld::Record<ESM::Race>& >(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);
2018-07-22 20:38:30 +00:00
// Post setup
mSkeleton->markDirty();
mSkeleton->setActive(SceneUtil::Skeleton::Active);
}
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-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);
// Map bone names to bones
mNodeMap.clear();
SceneUtil::NodeMapVisitor nmVisitor(mNodeMap);
mSkeleton->accept(nmVisitor);
}
void Actor::loadBodyParts(const std::string& actorId)
{
auto actorAdapter = mData.getActorAdapter();
auto partMap = actorAdapter->getActorPartMap(actorId);
if (partMap)
{
for (auto& pair : *partMap)
attachBodyPart(pair.first, getBodyPartMesh(pair.second));
}
}
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);
}
2018-07-22 20:38:30 +00:00
}
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 "";
2018-07-14 02:48:59 +00:00
}
}