1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-04-01 21:06:43 +00:00

Use accurate bone lookups for attaching objects

NIFs don't requires nodes to have unique names, which means looking up a
bone by name may get the wrong one. Instead, use a NifIndex:BoneHandle
map to make sure we can get the proper bone from a given Nif::Node.
This commit is contained in:
Chris Robinson 2013-04-06 08:15:12 -07:00
parent 95730cc127
commit e0da265972

View file

@ -380,7 +380,6 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk)
return textkeys; return textkeys;
} }
void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector<Nif::NiKeyframeController const*> &ctrls, Ogre::Bone *parent=NULL) void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector<Nif::NiKeyframeController const*> &ctrls, Ogre::Bone *parent=NULL)
{ {
Ogre::Bone *bone; Ogre::Bone *bone;
@ -389,6 +388,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro
else else
bone = skel->createBone(); bone = skel->createBone();
if(parent) parent->addChild(bone); if(parent) parent->addChild(bone);
mNifToOgreHandleMap[node->recIndex] = bone->getHandle();
bone->setOrientation(node->trafo.rotation); bone->setOrientation(node->trafo.rotation);
bone->setPosition(node->trafo.pos); bone->setPosition(node->trafo.pos);
@ -439,6 +439,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro
} }
} }
// Lookup to retrieve an Ogre bone handle for a given Nif record index
std::map<int,int> mNifToOgreHandleMap;
typedef std::map<std::string,NIFSkeletonLoader> LoaderMap; typedef std::map<std::string,NIFSkeletonLoader> LoaderMap;
static LoaderMap sLoaders; static LoaderMap sLoaders;
@ -569,6 +571,20 @@ static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::stri
return skelMgr.create(name, group, true, &sLoaders[name]); return skelMgr.create(name, group, true, &sLoaders[name]);
} }
// Looks up an Ogre Bone handle ID from a NIF's record index. Should only be
// used when the bone name is insufficient as this is a relatively slow lookup
static int lookupOgreBoneHandle(const std::string &nifname, int idx)
{
LoaderMap::const_iterator loader = sLoaders.find(nifname);
if(loader != sLoaders.end())
{
std::map<int,int>::const_iterator entry = loader->second.mNifToOgreHandleMap.find(idx);
if(entry != loader->second.mNifToOgreHandleMap.end())
return entry->second;
}
throw std::runtime_error("Invalid NIF record lookup ("+nifname+", index "+Ogre::StringConverter::toString(idx)+")");
}
}; };
NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders;
@ -1285,7 +1301,11 @@ class NIFMeshLoader : Ogre::ManualResourceLoader
createParticleEmitterAffectors(partsys, partctrl); createParticleEmitterAffectors(partsys, partctrl);
if(!partctrl->emitter.empty() && !partsys->isAttached()) if(!partctrl->emitter.empty() && !partsys->isAttached())
entitybase->attachObjectToBone(partctrl->emitter->name, partsys); {
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, partctrl->emitter->recIndex);
Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid);
entitybase->attachObjectToBone(trgtbone->getName(), partsys);
}
} }
ctrl = ctrl->next; ctrl = ctrl->next;
} }
@ -1362,10 +1382,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader
{ {
const Nif::NiVisController *vis = static_cast<const Nif::NiVisController*>(ctrl.getPtr()); const Nif::NiVisController *vis = static_cast<const Nif::NiVisController*>(ctrl.getPtr());
const Nif::Named *target = dynamic_cast<const Nif::Named*>(ctrl->target.getPtr()); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex);
if(!target) target = node; Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(trgtid);
Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(target->name);
Ogre::SharedPtr<Ogre::ControllerValue<Ogre::Real> > srcval; /* Filled in later */ Ogre::SharedPtr<Ogre::ControllerValue<Ogre::Real> > srcval; /* Filled in later */
Ogre::SharedPtr<Ogre::ControllerValue<Ogre::Real> > dstval(OGRE_NEW VisController::Value(trgtbone)); Ogre::SharedPtr<Ogre::ControllerValue<Ogre::Real> > dstval(OGRE_NEW VisController::Value(trgtbone));
Ogre::SharedPtr<Ogre::ControllerFunction<Ogre::Real> > func(OGRE_NEW VisController::Function(vis->data.getPtr())); Ogre::SharedPtr<Ogre::ControllerFunction<Ogre::Real> > func(OGRE_NEW VisController::Function(vis->data.getPtr()));
@ -1405,7 +1423,11 @@ class NIFMeshLoader : Ogre::ManualResourceLoader
if(entity->hasSkeleton()) if(entity->hasSkeleton())
entity->shareSkeletonInstanceWith(entities.mSkelBase); entity->shareSkeletonInstanceWith(entities.mSkelBase);
else else
entities.mSkelBase->attachObjectToBone(shape->name, entity); {
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, shape->recIndex);
Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(trgtid);
entities.mSkelBase->attachObjectToBone(trgtbone->getName(), entity);
}
} }
} }