mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-29 21:45:32 +00:00
Preload NPC body parts
This commit is contained in:
parent
84dcf59c50
commit
1b8e82e929
3 changed files with 136 additions and 109 deletions
|
@ -37,6 +37,7 @@
|
|||
|
||||
#include "../mwrender/objects.hpp"
|
||||
#include "../mwrender/renderinginterface.hpp"
|
||||
#include "../mwrender/npcanimation.hpp"
|
||||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
|
||||
|
@ -457,7 +458,10 @@ namespace MWClass
|
|||
models.push_back("meshes/"+hair->mModel);
|
||||
}
|
||||
|
||||
bool female = (npc->mBase->mFlags & ESM::NPC::Female);
|
||||
|
||||
// FIXME: use const version of InventoryStore functions once they are available
|
||||
// preload equipped items
|
||||
if (ptr.getClass().hasInventoryStore(ptr))
|
||||
{
|
||||
MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr);
|
||||
|
@ -486,9 +490,9 @@ namespace MWClass
|
|||
|
||||
for (std::vector<ESM::PartReference>::const_iterator it = parts.begin(); it != parts.end(); ++it)
|
||||
{
|
||||
std::string partname = (npc->mBase->mFlags & ESM::NPC::Female) ? it->mFemale : it->mMale;
|
||||
std::string partname = female ? it->mFemale : it->mMale;
|
||||
if (partname.empty())
|
||||
partname = (npc->mBase->mFlags & ESM::NPC::Female) ? it->mMale : it->mFemale;
|
||||
partname = female ? it->mMale : it->mFemale;
|
||||
const ESM::BodyPart* part = MWBase::Environment::get().getWorld()->getStore().get<ESM::BodyPart>().search(partname);
|
||||
if (part && !part->mModel.empty())
|
||||
models.push_back("meshes/"+part->mModel);
|
||||
|
@ -497,6 +501,18 @@ namespace MWClass
|
|||
}
|
||||
}
|
||||
|
||||
// preload body parts
|
||||
if (race)
|
||||
{
|
||||
const std::vector<const ESM::BodyPart*>& parts = MWRender::NpcAnimation::getBodyParts(Misc::StringUtils::lowerCase(race->mId), female, false, false);
|
||||
for (std::vector<const ESM::BodyPart*>::const_iterator it = parts.begin(); it != parts.end(); ++it)
|
||||
{
|
||||
const ESM::BodyPart* part = *it;
|
||||
if (part && !part->mModel.empty())
|
||||
models.push_back("meshes/"+part->mModel);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string Npc::getName (const MWWorld::ConstPtr& ptr) const
|
||||
|
|
|
@ -619,116 +619,10 @@ void NpcAnimation::updateParts()
|
|||
showWeapons(mShowWeapons);
|
||||
showCarriedLeft(mShowCarriedLeft);
|
||||
|
||||
// Remember body parts so we only have to search through the store once for each race/gender/viewmode combination
|
||||
static std::map< std::pair<std::string,int>,std::vector<const ESM::BodyPart*> > sRaceMapping;
|
||||
|
||||
bool isWerewolf = (mNpcType == Type_Werewolf);
|
||||
int flags = (isWerewolf ? -1 : 0);
|
||||
if(!mNpc->isMale())
|
||||
{
|
||||
static const int Flag_Female = 1<<0;
|
||||
flags |= Flag_Female;
|
||||
}
|
||||
if(mViewMode == VM_FirstPerson)
|
||||
{
|
||||
static const int Flag_FirstPerson = 1<<1;
|
||||
flags |= Flag_FirstPerson;
|
||||
}
|
||||
|
||||
std::string race = (isWerewolf ? "werewolf" : Misc::StringUtils::lowerCase(mNpc->mRace));
|
||||
std::pair<std::string, int> thisCombination = std::make_pair(race, flags);
|
||||
if (sRaceMapping.find(thisCombination) == sRaceMapping.end())
|
||||
{
|
||||
typedef std::multimap<ESM::BodyPart::MeshPart,ESM::PartReferenceType> BodyPartMapType;
|
||||
static BodyPartMapType sBodyPartMap;
|
||||
if(sBodyPartMap.empty())
|
||||
{
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Neck, ESM::PRT_Neck));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Chest, ESM::PRT_Cuirass));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Groin, ESM::PRT_Groin));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_RHand));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_LHand));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_RWrist));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_LWrist));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_RForearm));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_LForearm));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_RUpperarm));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_LUpperarm));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_RFoot));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_LFoot));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_RAnkle));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_LAnkle));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_RKnee));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_LKnee));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_RLeg));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_LLeg));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Tail, ESM::PRT_Tail));
|
||||
}
|
||||
|
||||
std::vector<const ESM::BodyPart*> &parts = sRaceMapping[thisCombination];
|
||||
parts.resize(ESM::PRT_Count, NULL);
|
||||
|
||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
const MWWorld::Store<ESM::BodyPart> &partStore = store.get<ESM::BodyPart>();
|
||||
for(MWWorld::Store<ESM::BodyPart>::iterator it = partStore.begin(); it != partStore.end(); ++it)
|
||||
{
|
||||
if(isWerewolf)
|
||||
break;
|
||||
const ESM::BodyPart& bodypart = *it;
|
||||
if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable)
|
||||
continue;
|
||||
if (bodypart.mData.mType != ESM::BodyPart::MT_Skin)
|
||||
continue;
|
||||
|
||||
if (!Misc::StringUtils::ciEqual(bodypart.mRace, mNpc->mRace))
|
||||
continue;
|
||||
|
||||
bool firstPerson = (bodypart.mId.size() >= 3)
|
||||
&& bodypart.mId[bodypart.mId.size()-3] == '1'
|
||||
&& bodypart.mId[bodypart.mId.size()-2] == 's'
|
||||
&& bodypart.mId[bodypart.mId.size()-1] == 't';
|
||||
if(firstPerson != (mViewMode == VM_FirstPerson))
|
||||
{
|
||||
if(mViewMode == VM_FirstPerson && (bodypart.mData.mPart == ESM::BodyPart::MP_Hand ||
|
||||
bodypart.mData.mPart == ESM::BodyPart::MP_Wrist ||
|
||||
bodypart.mData.mPart == ESM::BodyPart::MP_Forearm ||
|
||||
bodypart.mData.mPart == ESM::BodyPart::MP_Upperarm))
|
||||
{
|
||||
/* Allow 3rd person skins as a fallback for the arms if 1st person is missing. */
|
||||
BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart));
|
||||
while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart)
|
||||
{
|
||||
if(!parts[bIt->second])
|
||||
parts[bIt->second] = &*it;
|
||||
++bIt;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((!mNpc->isMale()) != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female))
|
||||
{
|
||||
// Allow opposite gender's parts as fallback if parts for our gender are missing
|
||||
BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart));
|
||||
while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart)
|
||||
{
|
||||
if(!parts[bIt->second])
|
||||
parts[bIt->second] = &*it;
|
||||
++bIt;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart));
|
||||
while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart)
|
||||
{
|
||||
parts[bIt->second] = &*it;
|
||||
++bIt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<const ESM::BodyPart*> &parts = sRaceMapping[thisCombination];
|
||||
const std::vector<const ESM::BodyPart*> &parts = getBodyParts(race, !mNpc->isMale(), mViewMode == VM_FirstPerson, isWerewolf);
|
||||
for(int part = ESM::PRT_Neck; part < ESM::PRT_Count; ++part)
|
||||
{
|
||||
if(mPartPriorities[part] < 1)
|
||||
|
@ -1116,6 +1010,118 @@ void NpcAnimation::updatePtr(const MWWorld::Ptr &updated)
|
|||
mHeadAnimationTime->updatePtr(updated);
|
||||
}
|
||||
|
||||
// Remember body parts so we only have to search through the store once for each race/gender/viewmode combination
|
||||
typedef std::map< std::pair<std::string,int>,std::vector<const ESM::BodyPart*> > RaceMapping;
|
||||
static RaceMapping sRaceMapping;
|
||||
|
||||
const std::vector<const ESM::BodyPart *>& NpcAnimation::getBodyParts(const std::string &race, bool female, bool firstPerson, bool werewolf)
|
||||
{
|
||||
static const int Flag_FirstPerson = 1<<1;
|
||||
static const int Flag_Female = 1<<0;
|
||||
|
||||
int flags = (werewolf ? -1 : 0);
|
||||
if(female)
|
||||
flags |= Flag_Female;
|
||||
if(firstPerson)
|
||||
flags |= Flag_FirstPerson;
|
||||
|
||||
RaceMapping::iterator found = sRaceMapping.find(std::make_pair(race, flags));
|
||||
if (found != sRaceMapping.end())
|
||||
return found->second;
|
||||
else
|
||||
{
|
||||
std::vector<const ESM::BodyPart*>& parts = sRaceMapping[std::make_pair(race, flags)];
|
||||
|
||||
typedef std::multimap<ESM::BodyPart::MeshPart,ESM::PartReferenceType> BodyPartMapType;
|
||||
static BodyPartMapType sBodyPartMap;
|
||||
if(sBodyPartMap.empty())
|
||||
{
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Neck, ESM::PRT_Neck));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Chest, ESM::PRT_Cuirass));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Groin, ESM::PRT_Groin));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_RHand));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_LHand));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_RWrist));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_LWrist));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_RForearm));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_LForearm));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_RUpperarm));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_LUpperarm));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_RFoot));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_LFoot));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_RAnkle));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_LAnkle));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_RKnee));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_LKnee));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_RLeg));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_LLeg));
|
||||
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Tail, ESM::PRT_Tail));
|
||||
}
|
||||
|
||||
parts.resize(ESM::PRT_Count, NULL);
|
||||
|
||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
const MWWorld::Store<ESM::BodyPart> &partStore = store.get<ESM::BodyPart>();
|
||||
for(MWWorld::Store<ESM::BodyPart>::iterator it = partStore.begin(); it != partStore.end(); ++it)
|
||||
{
|
||||
if(werewolf)
|
||||
break;
|
||||
const ESM::BodyPart& bodypart = *it;
|
||||
if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable)
|
||||
continue;
|
||||
if (bodypart.mData.mType != ESM::BodyPart::MT_Skin)
|
||||
continue;
|
||||
|
||||
if (!Misc::StringUtils::ciEqual(bodypart.mRace, race))
|
||||
continue;
|
||||
|
||||
bool partFirstPerson = (bodypart.mId.size() >= 3)
|
||||
&& bodypart.mId[bodypart.mId.size()-3] == '1'
|
||||
&& bodypart.mId[bodypart.mId.size()-2] == 's'
|
||||
&& bodypart.mId[bodypart.mId.size()-1] == 't';
|
||||
if(partFirstPerson != (firstPerson))
|
||||
{
|
||||
if(firstPerson && (bodypart.mData.mPart == ESM::BodyPart::MP_Hand ||
|
||||
bodypart.mData.mPart == ESM::BodyPart::MP_Wrist ||
|
||||
bodypart.mData.mPart == ESM::BodyPart::MP_Forearm ||
|
||||
bodypart.mData.mPart == ESM::BodyPart::MP_Upperarm))
|
||||
{
|
||||
/* Allow 3rd person skins as a fallback for the arms if 1st person is missing. */
|
||||
BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart));
|
||||
while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart)
|
||||
{
|
||||
if(!parts[bIt->second])
|
||||
parts[bIt->second] = &*it;
|
||||
++bIt;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((female) != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female))
|
||||
{
|
||||
// Allow opposite gender's parts as fallback if parts for our gender are missing
|
||||
BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart));
|
||||
while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart)
|
||||
{
|
||||
if(!parts[bIt->second])
|
||||
parts[bIt->second] = &*it;
|
||||
++bIt;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart));
|
||||
while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart)
|
||||
{
|
||||
parts[bIt->second] = &*it;
|
||||
++bIt;
|
||||
}
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
}
|
||||
|
||||
void NpcAnimation::setAccurateAiming(bool enabled)
|
||||
{
|
||||
mAccurateAiming = enabled;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
namespace ESM
|
||||
{
|
||||
struct NPC;
|
||||
struct BodyPart;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
|
@ -150,6 +151,10 @@ public:
|
|||
void setFirstPersonOffset(const osg::Vec3f& offset);
|
||||
|
||||
virtual void updatePtr(const MWWorld::Ptr& updated);
|
||||
|
||||
/// Get a list of body parts that may be used by an NPC of given race and gender.
|
||||
/// @note This is a fixed size list, one list item for each ESM::PartReferenceType, may contain NULL body parts.
|
||||
static const std::vector<const ESM::BodyPart*>& getBodyParts(const std::string& raceId, bool female, bool firstperson, bool werewolf);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue