|
|
|
@ -20,40 +20,44 @@
|
|
|
|
|
namespace MWRender
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = {
|
|
|
|
|
{ ESM::PRT_Head, "Head" },
|
|
|
|
|
{ ESM::PRT_Hair, "Head" },
|
|
|
|
|
{ ESM::PRT_Neck, "Neck" },
|
|
|
|
|
{ ESM::PRT_Cuirass, "Chest" },
|
|
|
|
|
{ ESM::PRT_Groin, "Groin" },
|
|
|
|
|
{ ESM::PRT_Skirt, "Groin" },
|
|
|
|
|
{ ESM::PRT_RHand, "Right Hand" },
|
|
|
|
|
{ ESM::PRT_LHand, "Left Hand" },
|
|
|
|
|
{ ESM::PRT_RWrist, "Right Wrist" },
|
|
|
|
|
{ ESM::PRT_LWrist, "Left Wrist" },
|
|
|
|
|
{ ESM::PRT_Shield, "Shield Bone" },
|
|
|
|
|
{ ESM::PRT_RForearm, "Right Forearm" },
|
|
|
|
|
{ ESM::PRT_LForearm, "Left Forearm" },
|
|
|
|
|
{ ESM::PRT_RUpperarm, "Right Upper Arm" },
|
|
|
|
|
{ ESM::PRT_LUpperarm, "Left Upper Arm" },
|
|
|
|
|
{ ESM::PRT_RFoot, "Right Foot" },
|
|
|
|
|
{ ESM::PRT_LFoot, "Left Foot" },
|
|
|
|
|
{ ESM::PRT_RAnkle, "Right Ankle" },
|
|
|
|
|
{ ESM::PRT_LAnkle, "Left Ankle" },
|
|
|
|
|
{ ESM::PRT_RKnee, "Right Knee" },
|
|
|
|
|
{ ESM::PRT_LKnee, "Left Knee" },
|
|
|
|
|
{ ESM::PRT_RLeg, "Right Upper Leg" },
|
|
|
|
|
{ ESM::PRT_LLeg, "Left Upper Leg" },
|
|
|
|
|
{ ESM::PRT_RPauldron, "Right Clavicle" },
|
|
|
|
|
{ ESM::PRT_LPauldron, "Left Clavicle" },
|
|
|
|
|
{ ESM::PRT_Weapon, "Weapon Bone" },
|
|
|
|
|
{ ESM::PRT_Tail, "Tail" }
|
|
|
|
|
};
|
|
|
|
|
static NpcAnimation::PartBoneMap createPartListMap()
|
|
|
|
|
{
|
|
|
|
|
NpcAnimation::PartBoneMap result;
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_Head, "Head"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_Hair, "Head"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_Neck, "Neck"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_Cuirass, "Chest"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_Groin, "Groin"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_Skirt, "Groin"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_RHand, "Right Hand"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_LHand, "Left Hand"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_RWrist, "Right Wrist"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_LWrist, "Left Wrist"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_Shield, "Shield Bone"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_RForearm, "Right Forearm"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_LForearm, "Left Forearm"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_RUpperarm, "Right Upper Arm"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_LUpperarm, "Left Upper Arm"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_RFoot, "Right Foot"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_LFoot, "Left Foot"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_RAnkle, "Right Ankle"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_LAnkle, "Left Ankle"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_RKnee, "Right Knee"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_LKnee, "Left Knee"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_RLeg, "Right Upper Leg"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_LLeg, "Left Upper Leg"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_RPauldron, "Right Clavicle"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_LPauldron, "Left Clavicle"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_Weapon, "Weapon Bone"));
|
|
|
|
|
result.insert(std::make_pair(ESM::PRT_Tail, "Tail"));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
const NpcAnimation::PartBoneMap NpcAnimation::sPartList = createPartListMap();
|
|
|
|
|
|
|
|
|
|
NpcAnimation::~NpcAnimation()
|
|
|
|
|
{
|
|
|
|
|
Ogre::SceneManager *sceneMgr = mInsert->getCreator();
|
|
|
|
|
for(size_t i = 0;i < sPartListSize;i++)
|
|
|
|
|
for(size_t i = 0;i < ESM::PRT_Count;i++)
|
|
|
|
|
destroyObjectList(sceneMgr, mObjectParts[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -82,7 +86,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor
|
|
|
|
|
{
|
|
|
|
|
mNpc = mPtr.get<ESM::NPC>()->mBase;
|
|
|
|
|
|
|
|
|
|
for(size_t i = 0;i < sPartListSize;i++)
|
|
|
|
|
for(size_t i = 0;i < ESM::PRT_Count;i++)
|
|
|
|
|
{
|
|
|
|
|
mPartslots[i] = -1; //each slot is empty
|
|
|
|
|
mPartPriorities[i] = 0;
|
|
|
|
@ -168,8 +172,8 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
|
|
|
|
|
}
|
|
|
|
|
MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr);
|
|
|
|
|
|
|
|
|
|
for(size_t i = 0;i < sPartListSize;i++)
|
|
|
|
|
removeIndividualPart(i);
|
|
|
|
|
for(size_t i = 0;i < ESM::PRT_Count;i++)
|
|
|
|
|
removeIndividualPart((ESM::PartReferenceType)i);
|
|
|
|
|
forceUpdate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -276,14 +280,7 @@ void NpcAnimation::updateParts(bool forceupdate)
|
|
|
|
|
const ESM::Light *light = part.get<ESM::Light>()->mBase;
|
|
|
|
|
addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft,
|
|
|
|
|
1, "meshes\\"+light->mModel);
|
|
|
|
|
for(size_t i = 0;i < sPartListSize;i++)
|
|
|
|
|
{
|
|
|
|
|
if(ESM::PRT_Shield == sPartList[i].type)
|
|
|
|
|
{
|
|
|
|
|
addExtraLight(mInsert->getCreator(), mObjectParts[i], light);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], light);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -386,7 +383,8 @@ void NpcAnimation::updateParts(bool forceupdate)
|
|
|
|
|
{
|
|
|
|
|
const ESM::BodyPart* bodypart = parts[part];
|
|
|
|
|
if(bodypart)
|
|
|
|
|
addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel);
|
|
|
|
|
addOrReplaceIndividualPart((ESM::PartReferenceType)part, -1, 1,
|
|
|
|
|
"meshes\\"+bodypart->mModel);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -442,7 +440,7 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
|
|
|
|
|
node->pitch(Ogre::Radian(pitch*0.75f), Ogre::Node::TS_WORLD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(size_t i = 0;i < sPartListSize;i++)
|
|
|
|
|
for(size_t i = 0;i < ESM::PRT_Count;i++)
|
|
|
|
|
{
|
|
|
|
|
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(mObjectParts[i].mControllers.begin());
|
|
|
|
|
for(;ctrl != mObjectParts[i].mControllers.end();ctrl++)
|
|
|
|
@ -457,22 +455,15 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NpcAnimation::removeIndividualPart(int type)
|
|
|
|
|
void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type)
|
|
|
|
|
{
|
|
|
|
|
mPartPriorities[type] = 0;
|
|
|
|
|
mPartslots[type] = -1;
|
|
|
|
|
|
|
|
|
|
for(size_t i = 0;i < sPartListSize;i++)
|
|
|
|
|
{
|
|
|
|
|
if(type == sPartList[i].type)
|
|
|
|
|
{
|
|
|
|
|
destroyObjectList(mInsert->getCreator(), mObjectParts[i]);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
destroyObjectList(mInsert->getCreator(), mObjectParts[type]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NpcAnimation::reserveIndividualPart(int type, int group, int priority)
|
|
|
|
|
void NpcAnimation::reserveIndividualPart(ESM::PartReferenceType type, int group, int priority)
|
|
|
|
|
{
|
|
|
|
|
if(priority > mPartPriorities[type])
|
|
|
|
|
{
|
|
|
|
@ -484,14 +475,14 @@ void NpcAnimation::reserveIndividualPart(int type, int group, int priority)
|
|
|
|
|
|
|
|
|
|
void NpcAnimation::removePartGroup(int group)
|
|
|
|
|
{
|
|
|
|
|
for(int i = 0; i < 27; i++)
|
|
|
|
|
for(int i = 0; i < ESM::PRT_Count; i++)
|
|
|
|
|
{
|
|
|
|
|
if(mPartslots[i] == group)
|
|
|
|
|
removeIndividualPart(i);
|
|
|
|
|
removeIndividualPart((ESM::PartReferenceType)i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh)
|
|
|
|
|
bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string &mesh)
|
|
|
|
|
{
|
|
|
|
|
if(priority <= mPartPriorities[type])
|
|
|
|
|
return false;
|
|
|
|
@ -500,43 +491,36 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority,
|
|
|
|
|
mPartslots[type] = group;
|
|
|
|
|
mPartPriorities[type] = priority;
|
|
|
|
|
|
|
|
|
|
for(size_t i = 0;i < sPartListSize;i++)
|
|
|
|
|
mObjectParts[type] = insertBoundedPart(mesh, group, sPartList.at(type));
|
|
|
|
|
if(mObjectParts[type].mSkelBase && mObjectParts[type].mSkelBase->isParentTagPoint())
|
|
|
|
|
{
|
|
|
|
|
if(type == sPartList[i].type)
|
|
|
|
|
Ogre::Node *root = mObjectParts[type].mSkelBase->getParentNode();
|
|
|
|
|
Ogre::SkeletonInstance *skel = mObjectParts[type].mSkelBase->getSkeleton();
|
|
|
|
|
if(skel->hasBone("BoneOffset"))
|
|
|
|
|
{
|
|
|
|
|
mObjectParts[i] = insertBoundedPart(mesh, group, sPartList[i].name);
|
|
|
|
|
if(mObjectParts[i].mSkelBase && mObjectParts[i].mSkelBase->isParentTagPoint())
|
|
|
|
|
{
|
|
|
|
|
Ogre::Node *root = mObjectParts[i].mSkelBase->getParentNode();
|
|
|
|
|
Ogre::SkeletonInstance *skel = mObjectParts[i].mSkelBase->getSkeleton();
|
|
|
|
|
if(skel->hasBone("BoneOffset"))
|
|
|
|
|
{
|
|
|
|
|
Ogre::Bone *offset = skel->getBone("BoneOffset");
|
|
|
|
|
root->translate(offset->getPosition());
|
|
|
|
|
root->rotate(offset->getOrientation());
|
|
|
|
|
// HACK: Why an extra -90 degree rotation?
|
|
|
|
|
root->pitch(Ogre::Degree(-90.0f));
|
|
|
|
|
root->scale(offset->getScale());
|
|
|
|
|
root->setInitialState();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO:
|
|
|
|
|
// type == ESM::PRT_Head should get an animation source based on the current output of
|
|
|
|
|
// the actor's 'say' sound (0 = silent, 1 = loud?).
|
|
|
|
|
// type == ESM::PRT_Weapon should get an animation source based on the current offset
|
|
|
|
|
// of the weapon attack animation (from its beginning, or start marker?)
|
|
|
|
|
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(mObjectParts[i].mControllers.begin());
|
|
|
|
|
for(;ctrl != mObjectParts[i].mControllers.end();ctrl++)
|
|
|
|
|
{
|
|
|
|
|
if(ctrl->getSource().isNull())
|
|
|
|
|
ctrl->setSource(mNullAnimationValuePtr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
Ogre::Bone *offset = skel->getBone("BoneOffset");
|
|
|
|
|
root->translate(offset->getPosition());
|
|
|
|
|
root->rotate(offset->getOrientation());
|
|
|
|
|
// HACK: Why an extra -90 degree rotation?
|
|
|
|
|
root->pitch(Ogre::Degree(-90.0f));
|
|
|
|
|
root->scale(offset->getScale());
|
|
|
|
|
root->setInitialState();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// TODO:
|
|
|
|
|
// type == ESM::PRT_Head should get an animation source based on the current output of
|
|
|
|
|
// the actor's 'say' sound (0 = silent, 1 = loud?).
|
|
|
|
|
// type == ESM::PRT_Weapon should get an animation source based on the current offset
|
|
|
|
|
// of the weapon attack animation (from its beginning, or start marker?)
|
|
|
|
|
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(mObjectParts[type].mControllers.begin());
|
|
|
|
|
for(;ctrl != mObjectParts[type].mControllers.end();ctrl++)
|
|
|
|
|
{
|
|
|
|
|
if(ctrl->getSource().isNull())
|
|
|
|
|
ctrl->setSource(mNullAnimationValuePtr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts)
|
|
|
|
@ -577,9 +561,9 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(bodypart)
|
|
|
|
|
addOrReplaceIndividualPart(part->mPart, group, priority, "meshes\\"+bodypart->mModel);
|
|
|
|
|
addOrReplaceIndividualPart((ESM::PartReferenceType)part->mPart, group, priority, "meshes\\"+bodypart->mModel);
|
|
|
|
|
else
|
|
|
|
|
reserveIndividualPart(part->mPart, group, priority);
|
|
|
|
|
reserveIndividualPart((ESM::PartReferenceType)part->mPart, group, priority);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|