From 59f1d4b0476579146f358b827d4ca060f4b0a76f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 09:44:10 -0700 Subject: [PATCH] Add support for NiUVController on meshes --- apps/openmw/mwrender/animation.cpp | 5 +- components/nifogre/ogrenifloader.cpp | 120 ++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 00196c9d4..2b980320d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -133,7 +133,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); for(size_t i = 0;i < mEntityList.mControllers.size();i++) - mEntityList.mControllers[i].setSource(ctrlval); + { + if(mEntityList.mControllers[i].getSource().isNull()) + mEntityList.mControllers[i].setSource(ctrlval); + } } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 06296ddee..1e42fed37 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -139,6 +140,105 @@ public: }; }; +class UVController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::MaterialPtr mMaterial; + Nif::FloatKeyList mUTrans; + Nif::FloatKeyList mVTrans; + Nif::FloatKeyList mUScale; + Nif::FloatKeyList mVScale; + + static float lookupValue(float time, const Nif::FloatKeyList &keys) + { + Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()); + for(;iter != keys.mKeys.end();iter++) + { + if(iter->mTime > time) + continue; + Nif::FloatKeyList::VecType::const_iterator next(iter+1); + if(next == keys.mKeys.end()) + return iter->mValue; + float a = (time-iter->mTime) / (next->mTime-iter->mTime); + return iter->mValue + ((next->mValue - iter->mValue)*a); + } + return 0.0f; + } + + public: + Value(const Ogre::MaterialPtr &material, Nif::NiUVData *data) + : mMaterial(material) + , mUTrans(data->mKeyList[0]) + , mVTrans(data->mKeyList[1]) + , mUScale(data->mKeyList[2]) + , mVScale(data->mKeyList[3]) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 1.0f; + } + + virtual void setValue(Ogre::Real value) + { + float uTrans = lookupValue(value, mUTrans); + float vTrans = lookupValue(value, mVTrans); + float uScale = lookupValue(value, mUScale); + float vScale = lookupValue(value, mVScale); + if(uScale == 0.0f) uScale = 1.0f; + if(vScale == 0.0f) vScale = 1.0f; + + Ogre::Material::TechniqueIterator techs = mMaterial->getTechniqueIterator(); + while(techs.hasMoreElements()) + { + Ogre::Technique *tech = techs.getNext(); + Ogre::Technique::PassIterator passes = tech->getPassIterator(); + while(passes.hasMoreElements()) + { + Ogre::Pass *pass = passes.getNext(); + Ogre::TextureUnitState *tex = pass->getTextureUnitState(0); + tex->setTextureScroll(uTrans, vTrans); + tex->setTextureScale(uScale, vScale); + } + } + } + }; + + class Function : public Ogre::ControllerFunction + { + private: + float mFrequency; + float mPhase; + float mStartTime; + float mStopTime; + + public: + Function(const Nif::NiUVController *ctrl) + : Ogre::ControllerFunction(false) + , mFrequency(ctrl->frequency) + , mPhase(ctrl->phase) + , mStartTime(ctrl->timeStart) + , mStopTime(ctrl->timeStop) + { + mDeltaCount = mPhase; + while(mDeltaCount < mStartTime) + mDeltaCount += (mStopTime-mStartTime); + } + + virtual Ogre::Real calculate(Ogre::Real value) + { + mDeltaCount += value; + mDeltaCount = std::fmod(mDeltaCount+(value*mFrequency) - mStartTime, + mStopTime - mStartTime) + mStartTime; + return mDeltaCount; + } + }; +}; + // Helper class that computes the bounding box and of a mesh class BoundsFinder @@ -409,7 +509,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro if(ctrl->recType == Nif::RC_NiKeyframeController) ctrls.push_back(static_cast(ctrl.getPtr())); else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || - ctrl->recType == Nif::RC_NiVisController + ctrl->recType == Nif::RC_NiVisController || + ctrl->recType == Nif::RC_NiUVController )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; @@ -1429,6 +1530,23 @@ class NIFMeshLoader : Ogre::ManualResourceLoader entities.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); } } + + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiUVController) + { + const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); + + const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); + Ogre::ControllerValueRealPtr srcval(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv)); + + entities.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + ctrl = ctrl->next; + } } if(node->recType == Nif::RC_NiAutoNormalParticles ||