mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-19 20:23:54 +00:00
Move data handling out of rendering code, equip armor/clothes
This commit is contained in:
parent
6b42f37918
commit
97ac0a92dd
7 changed files with 389 additions and 93 deletions
|
@ -19,6 +19,7 @@ opencs_hdrs_noqt (model/doc
|
|||
|
||||
opencs_units (model/world
|
||||
idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel landtexturetableproxymodel
|
||||
actoradapter
|
||||
)
|
||||
|
||||
|
||||
|
|
242
apps/opencs/model/world/actoradapter.cpp
Normal file
242
apps/opencs/model/world/actoradapter.cpp
Normal file
|
@ -0,0 +1,242 @@
|
|||
#include "actoradapter.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <components/esm/loadarmo.hpp>
|
||||
#include <components/esm/loadclot.hpp>
|
||||
#include <components/esm/loadnpc.hpp>
|
||||
#include <components/esm/loadrace.hpp>
|
||||
#include <components/esm/mappings.hpp>
|
||||
|
||||
#include "data.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
ActorAdapter::ActorAdapter(CSMWorld::Data& data)
|
||||
: mReferenceables(data.getReferenceables())
|
||||
, mRaces(data.getRaces())
|
||||
, mBodyParts(data.getBodyParts())
|
||||
{
|
||||
connect(data.getTableModel(UniversalId::Type_Referenceable), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
||||
this, SLOT(handleReferenceableChanged(const QModelIndex&, const QModelIndex&)));
|
||||
connect(data.getTableModel(UniversalId::Type_Race), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
||||
this, SLOT(handleRaceChanged(const QModelIndex&, const QModelIndex&)));
|
||||
connect(data.getTableModel(UniversalId::Type_BodyPart), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
||||
this, SLOT(handleBodyPartChanged(const QModelIndex&, const QModelIndex&)));
|
||||
}
|
||||
|
||||
const ActorAdapter::ActorPartMap* ActorAdapter::getActorPartMap(const std::string& refId)
|
||||
{
|
||||
auto it = mActorPartMaps.find(refId);
|
||||
if (it != mActorPartMaps.end())
|
||||
{
|
||||
return &it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
updateActor(refId);
|
||||
it = mActorPartMaps.find(refId);
|
||||
if (it != mActorPartMaps.end())
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ActorAdapter::handleReferenceableChanged(const QModelIndex& topLeft, const QModelIndex& botRight)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void ActorAdapter::handleRaceChanged(const QModelIndex& topLeft, const QModelIndex& botRight)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void ActorAdapter::handleBodyPartChanged(const QModelIndex& topLeft, const QModelIndex& botRight)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
ActorAdapter::RacePartMap& ActorAdapter::getOrCreateRacePartMap(const std::string& raceId, bool isFemale)
|
||||
{
|
||||
auto key = std::make_pair(raceId, isFemale);
|
||||
auto it = mRacePartMaps.find(key);
|
||||
if (it != mRacePartMaps.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create and find result
|
||||
updateRaceParts(raceId);
|
||||
return mRacePartMaps.find(key)->second;
|
||||
}
|
||||
}
|
||||
|
||||
void ActorAdapter::updateRaceParts(const std::string& raceId)
|
||||
{
|
||||
// Convenience function to determine if part is for 1st person view
|
||||
auto is1stPersonPart = [](std::string name) {
|
||||
return name.size() >= 4 && name.find(".1st", name.size() - 4) != std::string::npos;
|
||||
};
|
||||
|
||||
RacePartMap maleMap, femaleMap;
|
||||
for (int i = 0; i < mBodyParts.getSize(); ++i)
|
||||
{
|
||||
auto& record = mBodyParts.getRecord(i);
|
||||
if (!record.isDeleted() && record.get().mRace == raceId && record.get().mData.mType == ESM::BodyPart::MT_Skin && !is1stPersonPart(record.get().mId))
|
||||
{
|
||||
auto& part = record.get();
|
||||
auto type = (ESM::BodyPart::MeshPart) part.mData.mPart;
|
||||
// Note: Prefer the first part encountered for duplicates. emplace() does not overwrite
|
||||
if (part.mData.mFlags & ESM::BodyPart::BPF_Female)
|
||||
femaleMap.emplace(type, part.mId);
|
||||
else
|
||||
maleMap.emplace(type, part.mId);
|
||||
}
|
||||
}
|
||||
|
||||
mRacePartMaps[std::make_pair(raceId, true)] = femaleMap;
|
||||
mRacePartMaps[std::make_pair(raceId, false)] = maleMap;
|
||||
}
|
||||
|
||||
void ActorAdapter::updateActor(const std::string& refId)
|
||||
{
|
||||
int index = mReferenceables.searchId(refId);
|
||||
if (index != -1)
|
||||
{
|
||||
int typeColumn = mReferenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType);
|
||||
int recordType = mReferenceables.getData(index, typeColumn).toInt();
|
||||
if (recordType == CSMWorld::UniversalId::Type_Creature)
|
||||
updateCreature(refId);
|
||||
else if (recordType == CSMWorld::UniversalId::Type_Npc)
|
||||
updateNpc(refId);
|
||||
}
|
||||
}
|
||||
|
||||
void ActorAdapter::updateNpc(const std::string& refId)
|
||||
{
|
||||
auto& record = mReferenceables.getRecord(refId);
|
||||
if (record.isDeleted())
|
||||
{
|
||||
mActorPartMaps.erase(refId);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& npc = dynamic_cast<const Record<ESM::NPC>&>(record).get();
|
||||
auto& femaleRacePartMap = getOrCreateRacePartMap(npc.mRace, true);
|
||||
auto& maleRacePartMap = getOrCreateRacePartMap(npc.mRace, false);
|
||||
|
||||
ActorPartMap npcMap;
|
||||
|
||||
// Look at the npc's inventory first
|
||||
for (auto& item : npc.mInventory.mList)
|
||||
{
|
||||
if (item.mCount > 0)
|
||||
{
|
||||
std::string itemId = item.mItem.toString();
|
||||
// Handle armor, weapons, and clothing
|
||||
int index = mReferenceables.searchId(itemId);
|
||||
if (index != -1 && !mReferenceables.getRecord(index).isDeleted())
|
||||
{
|
||||
auto& itemRecord = mReferenceables.getRecord(index);
|
||||
|
||||
int typeColumn = mReferenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType);
|
||||
int recordType = mReferenceables.getData(index, typeColumn).toInt();
|
||||
if (recordType == CSMWorld::UniversalId::Type_Armor)
|
||||
{
|
||||
auto& armor = dynamic_cast<const Record<ESM::Armor>&>(itemRecord).get();
|
||||
for (auto& part : armor.mParts.mParts)
|
||||
{
|
||||
std::string bodyPartId;
|
||||
if (!npc.isMale())
|
||||
bodyPartId = part.mFemale;
|
||||
if (bodyPartId.empty())
|
||||
bodyPartId = part.mMale;
|
||||
|
||||
if (!bodyPartId.empty())
|
||||
npcMap.emplace(static_cast<ESM::PartReferenceType>(part.mPart), bodyPartId);
|
||||
}
|
||||
}
|
||||
else if (recordType == CSMWorld::UniversalId::Type_Clothing)
|
||||
{
|
||||
auto& clothing = dynamic_cast<const Record<ESM::Clothing>&>(itemRecord).get();
|
||||
for (auto& part : clothing.mParts.mParts)
|
||||
{
|
||||
std::string bodyPartId;
|
||||
if (!npc.isMale())
|
||||
bodyPartId = part.mFemale;
|
||||
if (bodyPartId.empty())
|
||||
bodyPartId = part.mMale;
|
||||
|
||||
if (!bodyPartId.empty())
|
||||
npcMap.emplace(static_cast<ESM::PartReferenceType>(part.mPart), bodyPartId);
|
||||
}
|
||||
}
|
||||
else if (recordType == CSMWorld::UniversalId::Type_Weapon)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the rest with body parts
|
||||
for (int i = 0; i < ESM::PRT_Count; ++i)
|
||||
{
|
||||
auto type = static_cast<ESM::PartReferenceType>(i);
|
||||
if (npcMap.find(type) == npcMap.end())
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ESM::PRT_Head:
|
||||
npcMap.emplace(type, npc.mHead);
|
||||
break;
|
||||
case ESM::PRT_Hair:
|
||||
npcMap.emplace(type, npc.mHair);
|
||||
break;
|
||||
case ESM::PRT_Skirt:
|
||||
case ESM::PRT_Shield:
|
||||
case ESM::PRT_RPauldron:
|
||||
case ESM::PRT_LPauldron:
|
||||
case ESM::PRT_Weapon:
|
||||
// No body part associated
|
||||
break;
|
||||
default:
|
||||
{
|
||||
std::string bodyPartId;
|
||||
// Check female map if applicable
|
||||
if (!npc.isMale())
|
||||
{
|
||||
auto partIt = femaleRacePartMap.find(ESM::getMeshPart(type));
|
||||
if (partIt != femaleRacePartMap.end())
|
||||
bodyPartId = partIt->second;
|
||||
}
|
||||
|
||||
// Check male map next
|
||||
if (bodyPartId.empty() || npc.isMale())
|
||||
{
|
||||
auto partIt = maleRacePartMap.find(ESM::getMeshPart(type));
|
||||
if (partIt != maleRacePartMap.end())
|
||||
bodyPartId = partIt->second;
|
||||
}
|
||||
|
||||
// Add to map
|
||||
if (!bodyPartId.empty())
|
||||
{
|
||||
npcMap.emplace(type, bodyPartId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mActorPartMaps[refId] = npcMap;
|
||||
}
|
||||
|
||||
void ActorAdapter::updateCreature(const std::string& refId)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
80
apps/opencs/model/world/actoradapter.hpp
Normal file
80
apps/opencs/model/world/actoradapter.hpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
#ifndef CSM_WOLRD_ACTORADAPTER_H
|
||||
#define CSM_WOLRD_ACTORADAPTER_H
|
||||
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <components/esm/loadarmo.hpp>
|
||||
#include <components/esm/loadbody.hpp>
|
||||
|
||||
#include "refidcollection.hpp"
|
||||
#include "idcollection.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct Race;
|
||||
enum PartReferenceType;
|
||||
}
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class Data;
|
||||
|
||||
/// Quick and dirty hashing functor.
|
||||
struct StringBoolPairHash
|
||||
{
|
||||
size_t operator()(const std::pair<std::string, bool>& value) const noexcept
|
||||
{
|
||||
auto stringHash = std::hash<std::string>();
|
||||
return stringHash(value.first) + value.second;
|
||||
}
|
||||
};
|
||||
|
||||
class ActorAdapter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
// Maps body part type to 'body part' id
|
||||
using ActorPartMap = std::unordered_map<ESM::PartReferenceType, std::string>;
|
||||
// Maps mesh part type to 'body part' id
|
||||
using RacePartMap = std::unordered_map<ESM::BodyPart::MeshPart, std::string>;
|
||||
|
||||
ActorAdapter(CSMWorld::Data& data);
|
||||
|
||||
const ActorPartMap* getActorPartMap(const std::string& refId);
|
||||
|
||||
signals:
|
||||
|
||||
void actorChanged(const std::string& refId);
|
||||
|
||||
public slots:
|
||||
|
||||
void handleReferenceableChanged(const QModelIndex&, const QModelIndex&);
|
||||
void handleRaceChanged(const QModelIndex&, const QModelIndex&);
|
||||
void handleBodyPartChanged(const QModelIndex&, const QModelIndex&);
|
||||
|
||||
private:
|
||||
|
||||
RacePartMap& getOrCreateRacePartMap(const std::string& raceId, bool isFemale);
|
||||
|
||||
void updateRaceParts(const std::string& raceId);
|
||||
void updateActor(const std::string& refId);
|
||||
void updateNpc(const std::string& refId);
|
||||
void updateCreature(const std::string& refId);
|
||||
|
||||
RefIdCollection& mReferenceables;
|
||||
IdCollection<ESM::Race>& mRaces;
|
||||
IdCollection<ESM::BodyPart>& mBodyParts;
|
||||
|
||||
// Key: referenceable id
|
||||
std::unordered_map<std::string, ActorPartMap> mActorPartMaps;
|
||||
// Key: race id, is female
|
||||
std::unordered_map<std::pair<std::string, bool>, RacePartMap, StringBoolPairHash> mRacePartMaps;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -572,6 +572,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
|
|||
UniversalId::Type_Video);
|
||||
addModel (new IdTable (&mMetaData), UniversalId::Type_MetaData);
|
||||
|
||||
mActorAdapter.reset(new ActorAdapter(*this));
|
||||
|
||||
mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files
|
||||
}
|
||||
|
||||
|
@ -912,6 +914,16 @@ QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId&
|
|||
return iter->second;
|
||||
}
|
||||
|
||||
const CSMWorld::ActorAdapter* CSMWorld::Data::getActorAdapter() const
|
||||
{
|
||||
return mActorAdapter.get();
|
||||
}
|
||||
|
||||
CSMWorld::ActorAdapter* CSMWorld::Data::getActorAdapter()
|
||||
{
|
||||
return mActorAdapter.get();
|
||||
}
|
||||
|
||||
void CSMWorld::Data::merge()
|
||||
{
|
||||
mGlobals.merge();
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include "../doc/stage.hpp"
|
||||
|
||||
#include "actoradapter.hpp"
|
||||
#include "idcollection.hpp"
|
||||
#include "nestedidcollection.hpp"
|
||||
#include "universalid.hpp"
|
||||
|
@ -73,6 +74,7 @@ namespace ESM
|
|||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class ActorAdapter;
|
||||
class ResourcesManager;
|
||||
class Resources;
|
||||
|
||||
|
@ -110,6 +112,7 @@ namespace CSMWorld
|
|||
RefCollection mRefs;
|
||||
IdCollection<ESM::Filter> mFilters;
|
||||
Collection<MetaData> mMetaData;
|
||||
std::unique_ptr<ActorAdapter> mActorAdapter;
|
||||
const Fallback::Map* mFallbackMap;
|
||||
std::vector<QAbstractItemModel *> mModels;
|
||||
std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex;
|
||||
|
@ -287,6 +290,10 @@ namespace CSMWorld
|
|||
/// \note The returned table may either be the model for the ID itself or the model that
|
||||
/// contains the record specified by the ID.
|
||||
|
||||
const ActorAdapter* getActorAdapter() const;
|
||||
|
||||
ActorAdapter* getActorAdapter();
|
||||
|
||||
void merge();
|
||||
///< Merge modified into base.
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <components/sceneutil/actorutil.hpp>
|
||||
#include <components/sceneutil/attach.hpp>
|
||||
#include <components/sceneutil/skeleton.hpp>
|
||||
#include <components/sceneutil/visitor.hpp>
|
||||
|
||||
#include "../../model/world/data.hpp"
|
||||
|
||||
|
@ -24,8 +23,8 @@ namespace CSVRender
|
|||
: mId(id)
|
||||
, mType(type)
|
||||
, mData(data)
|
||||
, mSkeleton(nullptr)
|
||||
, mBaseNode(new osg::Group())
|
||||
, mSkeleton(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -57,6 +56,7 @@ namespace CSVRender
|
|||
|
||||
auto& creature = dynamic_cast<const CSMWorld::Record<ESM::Creature>& >(referenceables.getRecord(mId)).get();
|
||||
|
||||
// Load skeleton with meshes
|
||||
std::string skeletonModel = MeshPrefix + creature.mModel;
|
||||
skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS());
|
||||
loadSkeleton(skeletonModel);
|
||||
|
@ -65,6 +65,9 @@ namespace CSVRender
|
|||
mSkeleton->accept(removeTriBipVisitor);
|
||||
removeTriBipVisitor.remove();
|
||||
|
||||
// Attach weapons
|
||||
loadBodyParts(creature.mId);
|
||||
|
||||
// Post setup
|
||||
mSkeleton->markDirty();
|
||||
mSkeleton->setActive(SceneUtil::Skeleton::Active);
|
||||
|
@ -72,12 +75,8 @@ namespace CSVRender
|
|||
|
||||
void Actor::updateNpc()
|
||||
{
|
||||
const unsigned int FemaleFlag = ESM::BodyPart::BPF_Female;
|
||||
|
||||
auto& bodyParts = mData.getBodyParts();
|
||||
auto& races = mData.getRaces();
|
||||
auto& referenceables = mData.getReferenceables();
|
||||
auto sceneMgr = mData.getResourceSystem()->getSceneManager();
|
||||
|
||||
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();
|
||||
|
@ -97,91 +96,8 @@ namespace CSVRender
|
|||
mSkeleton->accept(cleanVisitor);
|
||||
cleanVisitor.remove();
|
||||
|
||||
// Map bone names to bones
|
||||
SceneUtil::NodeMapVisitor::NodeMap nodeMap;
|
||||
SceneUtil::NodeMapVisitor nmVisitor(nodeMap);
|
||||
mSkeleton->accept(nmVisitor);
|
||||
|
||||
using BPRaceKey = std::tuple<int, int, std::string>;
|
||||
using RaceToBPMap = std::map<BPRaceKey, std::string>;
|
||||
// Convenience method to generate a map from body part + race to mesh name
|
||||
auto genRaceToBodyPartMap = [&](RaceToBPMap& bpMap) {
|
||||
int size = bodyParts.getSize();
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
auto& record = bodyParts.getRecord(i);
|
||||
if (!record.isDeleted())
|
||||
{
|
||||
// Method to check if 1st person part or not
|
||||
auto is1stPersonPart = [](std::string name) {
|
||||
return name.size() >= 4 && name.find(".1st", name.size() - 4) != std::string::npos;
|
||||
};
|
||||
|
||||
auto& bodyPart = record.get();
|
||||
if (bodyPart.mData.mType != ESM::BodyPart::MT_Skin || is1stPersonPart(bodyPart.mId))
|
||||
continue;
|
||||
|
||||
bpMap.emplace(
|
||||
BPRaceKey(bodyPart.mData.mPart, bodyPart.mData.mFlags & FemaleFlag ? 1 : 0, bodyPart.mRace),
|
||||
MeshPrefix + bodyPart.mModel);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Generate mapping
|
||||
RaceToBPMap r2bpMap;
|
||||
genRaceToBodyPartMap(r2bpMap);
|
||||
|
||||
// Convenience method to add a body part
|
||||
auto addBodyPart = [&](ESM::PartReferenceType type, std::string mesh) {
|
||||
// Retrieve mesh name if necessary
|
||||
if (mesh.empty())
|
||||
{
|
||||
auto meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), isFemale ? 1 : 0, npc.mRace));
|
||||
if (meshResult != r2bpMap.end())
|
||||
{
|
||||
mesh = meshResult->second;
|
||||
}
|
||||
else if (isFemale){
|
||||
meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), 0, npc.mRace));
|
||||
if (meshResult != r2bpMap.end())
|
||||
mesh = meshResult->second;
|
||||
}
|
||||
}
|
||||
|
||||
// Attach to skeleton
|
||||
std::string boneName = ESM::getBoneName(type);
|
||||
auto node = nodeMap.find(boneName);
|
||||
if (!mesh.empty() && node != nodeMap.end())
|
||||
{
|
||||
auto instance = sceneMgr->getInstance(mesh);
|
||||
SceneUtil::attach(instance, mSkeleton, boneName, node->second);
|
||||
}
|
||||
};
|
||||
|
||||
// Add body parts
|
||||
for (unsigned int i = 0; i < ESM::PRT_Count; ++i)
|
||||
{
|
||||
auto part = static_cast<ESM::PartReferenceType>(i);
|
||||
switch (part)
|
||||
{
|
||||
case ESM::PRT_Head:
|
||||
addBodyPart(part, getBodyPartMesh(npc.mHead));
|
||||
break;
|
||||
case ESM::PRT_Hair:
|
||||
addBodyPart(part, getBodyPartMesh(npc.mHair));
|
||||
break;
|
||||
case ESM::PRT_Skirt:
|
||||
case ESM::PRT_Shield:
|
||||
case ESM::PRT_RPauldron:
|
||||
case ESM::PRT_LPauldron:
|
||||
case ESM::PRT_Weapon:
|
||||
// No body part mesh associated
|
||||
break;
|
||||
default:
|
||||
addBodyPart(part, "");
|
||||
}
|
||||
}
|
||||
// Attach parts to skeleton
|
||||
loadBodyParts(npc.mId);
|
||||
|
||||
// Post setup
|
||||
mSkeleton->markDirty();
|
||||
|
@ -200,6 +116,37 @@ namespace CSVRender
|
|||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Actor::getBodyPartMesh(const std::string& bodyPartId)
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <components/esm/loadarmo.hpp>
|
||||
#include <components/sceneutil/visitor.hpp>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Group;
|
||||
|
@ -39,10 +42,13 @@ namespace CSVRender
|
|||
void update();
|
||||
|
||||
private:
|
||||
void loadSkeleton(const std::string& model);
|
||||
void updateCreature();
|
||||
void updateNpc();
|
||||
|
||||
void loadSkeleton(const std::string& model);
|
||||
void loadBodyParts(const std::string& actorId);
|
||||
void attachBodyPart(ESM::PartReferenceType, const std::string& mesh);
|
||||
|
||||
std::string getBodyPartMesh(const std::string& bodyPartId);
|
||||
|
||||
static const std::string MeshPrefix;
|
||||
|
@ -51,8 +57,9 @@ namespace CSVRender
|
|||
int mType;
|
||||
CSMWorld::Data& mData;
|
||||
|
||||
SceneUtil::Skeleton* mSkeleton;
|
||||
osg::ref_ptr<osg::Group> mBaseNode;
|
||||
SceneUtil::Skeleton* mSkeleton;
|
||||
SceneUtil::NodeMapVisitor::NodeMap mNodeMap;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue