diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f3ecbd6a5..fd7aeac1d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -37,6 +37,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(Ogre::Vector3::ZERO) , mLastPosition(0.0f) + , mCurrentControllers(NULL) , mCurrentKeys(NULL) , mCurrentAnim(NULL) , mCurrentTime(0.0f) @@ -68,6 +69,7 @@ void Animation::setAnimationSources(const std::vector &names) return; Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + mCurrentControllers = &mObjectList.mControllers; mCurrentAnim = NULL; mCurrentKeys = NULL; mAnimVelocity = 0.0f; @@ -78,6 +80,7 @@ void Animation::setAnimationSources(const std::vector &names) destroyObjectList(sceneMgr, mAnimationSources[i]); mAnimationSources.clear(); + Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) @@ -90,7 +93,7 @@ void Animation::setAnimationSources(const std::vector &names) mAnimationSources.pop_back(); continue; } - const NifOgre::ObjectList &objects = mAnimationSources.back(); + NifOgre::ObjectList &objects = mAnimationSources.back(); for(size_t i = 0;i < objects.mControllers.size();i++) { @@ -104,7 +107,13 @@ void Animation::setAnimationSources(const std::vector &names) dstval->setNode(bone); } - Ogre::Entity *ent = mAnimationSources.back().mSkelBase; + for(size_t i = 0;i < objects.mControllers.size();i++) + { + if(objects.mControllers[i].getSource().isNull()) + objects.mControllers[i].setSource(ctrlval); + } + + Ogre::Entity *ent = objects.mSkelBase; Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(ent->getSkeleton()->getName()); Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) @@ -167,6 +176,7 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model if(mObjectList.mControllers[i].getSource().isNull()) mObjectList.mControllers[i].setSource(ctrlval); } + mCurrentControllers = &mObjectList.mControllers; } @@ -441,12 +451,13 @@ void Animation::play(const std::string &groupname, const std::string &start, con try { bool found = false; /* Look in reverse; last-inserted source has priority. */ - for(std::vector::const_reverse_iterator iter(mAnimationSources.rbegin());iter != mAnimationSources.rend();iter++) + for(std::vector::reverse_iterator iter(mAnimationSources.rbegin());iter != mAnimationSources.rend();iter++) { if(iter->mSkelBase->hasAnimationState(groupname)) { mCurrentAnim = iter->mSkelBase->getSkeleton()->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; + mCurrentControllers = &iter->mControllers; mAnimVelocity = 0.0f; if(mNonAccumRoot) @@ -495,8 +506,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(!handleEvent(time, evt)) break; } - for(size_t i = 0;i < mObjectList.mControllers.size();i++) - mObjectList.mControllers[i].update(); + for(size_t i = 0;i < mCurrentControllers->size();i++) + (*mCurrentControllers)[i].update(); return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 22ab9fc7e..aee139bd6 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -49,6 +49,7 @@ protected: std::vector mAnimationSources; + std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::Animation *mCurrentAnim; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index a0aefaccc..e7bf820b8 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -169,6 +169,101 @@ public: typedef DefaultFunction Function; }; +class KeyframeController +{ +public: + class Value : public NodeTargetValue + { + private: + Nif::QuaternionKeyList mRotations; + Nif::Vector3KeyList mTranslations; + Nif::FloatKeyList mScales; + + public: + Value(Ogre::Node *target, const Nif::NiKeyframeData *data) + : NodeTargetValue(target) + , mRotations(data->mRotations) + , mTranslations(data->mTranslations) + , mScales(data->mScales) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 0.0f; + } + + virtual void setValue(Ogre::Real time) + { + if(mRotations.mKeys.size() > 0) + { + if(time <= mRotations.mKeys.front().mTime) + mNode->setOrientation(mRotations.mKeys.front().mValue); + else if(time >= mRotations.mKeys.back().mTime) + mNode->setOrientation(mRotations.mKeys.back().mValue); + else + { + Nif::QuaternionKeyList::VecType::const_iterator iter(mRotations.mKeys.begin()+1); + for(;iter != mRotations.mKeys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::QuaternionKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + mNode->setOrientation(Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue)); + break; + } + } + } + if(mTranslations.mKeys.size() > 0) + { + if(time <= mTranslations.mKeys.front().mTime) + mNode->setPosition(mTranslations.mKeys.front().mValue); + else if(time >= mTranslations.mKeys.back().mTime) + mNode->setPosition(mTranslations.mKeys.back().mValue); + else + { + Nif::Vector3KeyList::VecType::const_iterator iter(mTranslations.mKeys.begin()+1); + for(;iter != mTranslations.mKeys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::Vector3KeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + mNode->setPosition(last->mValue + ((iter->mValue - last->mValue)*a)); + break; + } + } + } + if(mScales.mKeys.size() > 0) + { + if(time <= mScales.mKeys.front().mTime) + mNode->setScale(Ogre::Vector3(mScales.mKeys.front().mValue)); + else if(time >= mScales.mKeys.back().mTime) + mNode->setScale(Ogre::Vector3(mScales.mKeys.back().mValue)); + else + { + Nif::FloatKeyList::VecType::const_iterator iter(mScales.mKeys.begin()+1); + for(;iter != mScales.mKeys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::FloatKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + mNode->setScale(Ogre::Vector3(last->mValue + ((iter->mValue - last->mValue)*a))); + break; + } + } + } + } + }; + + typedef DefaultFunction Function; +}; + class UVController { public: @@ -1546,6 +1641,18 @@ class NIFObjectLoader : Ogre::ManualResourceLoader objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } + else if(ctrl->recType == Nif::RC_NiKeyframeController) + { + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } ctrl = ctrl->next; }