diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ff09c7aef..41b86317e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -18,12 +18,14 @@ #include #include +#include #include // KeyframeHolder #include #include +#include #include #include #include @@ -1378,6 +1380,9 @@ namespace MWRender void injectCustomBones(osg::ref_ptr& node, const std::string& model, Resource::ResourceSystem* resourceSystem) { + if (model.empty()) + return; + const std::map& index = resourceSystem->getVFS()->getIndex(); std::string animationPath = model; @@ -1405,14 +1410,7 @@ namespace MWRender } } - enum InjectType - { - None, - Model, - ModelWithFallback - }; - - osg::ref_ptr getModelInstance(Resource::ResourceSystem* resourceSystem, const std::string& model, bool baseonly, InjectType inject) + osg::ref_ptr getModelInstance(Resource::ResourceSystem* resourceSystem, const std::string& model, bool baseonly, bool inject, const std::string& defaultSkeleton) { Resource::SceneManager* sceneMgr = resourceSystem->getSceneManager(); if (baseonly) @@ -1424,11 +1422,11 @@ namespace MWRender { osg::ref_ptr created = sceneMgr->getInstance(model); - if (inject == InjectType::ModelWithFallback) - injectCustomBones(created, "meshes\\xbase_anim.nif", resourceSystem); - - if (inject != InjectType::None) + if (inject) + { + injectCustomBones(created, defaultSkeleton, resourceSystem); injectCustomBones(created, model, resourceSystem); + } SceneUtil::CleanObjectRootVisitor removeDrawableVisitor; created->accept(removeDrawableVisitor); @@ -1445,11 +1443,11 @@ namespace MWRender { osg::ref_ptr created = sceneMgr->getInstance(model); - if (inject == InjectType::ModelWithFallback) - injectCustomBones(created, "meshes\\xbase_anim.nif", resourceSystem); - - if (inject != InjectType::None) + if (inject) + { + injectCustomBones(created, defaultSkeleton, resourceSystem); injectCustomBones(created, model, resourceSystem); + } return created; } @@ -1475,17 +1473,44 @@ namespace MWRender mAccumCtrl = nullptr; static const bool useAdditionalSources = Settings::Manager::getBool ("use additional anim sources", "Game"); - InjectType inject = useAdditionalSources && mPtr.getClass().isActor() ? InjectType::Model : InjectType::None; - if (inject != InjectType::None && isCreature) + std::string defaultSkeleton; + bool inject = false; + + if (useAdditionalSources && mPtr.getClass().isActor()) { - MWWorld::LiveCellRef *ref = mPtr.get(); - if(ref->mBase->mFlags & ESM::Creature::Bipedal) - inject = InjectType::ModelWithFallback; + if (isCreature) + { + MWWorld::LiveCellRef *ref = mPtr.get(); + if(ref->mBase->mFlags & ESM::Creature::Bipedal) + { + defaultSkeleton = "meshes\\xbase_anim.nif"; + inject = true; + } + } + else + { + inject = true; + MWWorld::LiveCellRef *ref = mPtr.get(); + if (!ref->mBase->mModel.empty()) + { + // If NPC has a custom animation model attached, we should inject bones from default skeleton for given race and gender as well + // Since it is a quite rare case, there should not be a noticable performance loss + // Note: consider that player and werewolves have no custom animation files attached for now + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.get().find(ref->mBase->mRace); + + bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; + bool isFemale = !ref->mBase->isMale(); + + defaultSkeleton = SceneUtil::getActorSkeleton(false, isFemale, isBeast, false); + defaultSkeleton = Misc::ResourceHelpers::correctActorModelPath(defaultSkeleton, mResourceSystem->getVFS()); + } + } } if (!forceskeleton) { - osg::ref_ptr created = getModelInstance(mResourceSystem, model, baseonly, inject); + osg::ref_ptr created = getModelInstance(mResourceSystem, model, baseonly, inject, defaultSkeleton); mInsert->addChild(created); mObjectRoot = created->asGroup(); if (!mObjectRoot) @@ -1501,7 +1526,7 @@ namespace MWRender } else { - osg::ref_ptr created = getModelInstance(mResourceSystem, model, baseonly, inject); + osg::ref_ptr created = getModelInstance(mResourceSystem, model, baseonly, inject, defaultSkeleton); osg::ref_ptr skel = dynamic_cast(created.get()); if (!skel) {