diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index ca92f62d49..ef4fbbe8df 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -116,6 +116,7 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; bool vertShadowBuffer = false; + bool geomMorpherController = false; if(!shape->controller.empty()) { Nif::ControllerPtr ctrl = shape->controller; @@ -124,6 +125,7 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape { vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; vertShadowBuffer = true; + geomMorpherController = true; break; } } while(!(ctrl=ctrl->next).empty()); @@ -347,6 +349,11 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest)) mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest); } + + // Create a dummy vertex animation track if there's a geom morpher controller + // This is required to make Ogre create the buffers we will use for software vertex animation + if (srcVerts.size() && geomMorpherController) + mesh->createAnimation("dummy", 0)->createVertexTrack(1, sub->vertexData, Ogre::VAT_MORPH); } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index a530d060d2..ec24089b88 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -385,12 +385,35 @@ public: private: Ogre::SubEntity *mSubEntity; std::vector mMorphs; + std::vector mValues; + + std::vector mVertices; + + static float interpKey(const Nif::FloatKeyList::VecType &keys, float time) + { + if(time <= keys.front().mTime) + return keys.front().mValue; + + Nif::FloatKeyList::VecType::const_iterator iter(keys.begin()+1); + for(;iter != keys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::FloatKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return last->mValue + ((iter->mValue - last->mValue)*a); + } + return keys.back().mValue; + } public: Value(Ogre::SubEntity *subent, const Nif::NiMorphData *data) : mSubEntity(subent) , mMorphs(data->mMorphs) - { } + { + mValues.resize(mMorphs.size()-1, 0.f); + } virtual Ogre::Real getValue() const { @@ -398,9 +421,63 @@ public: return 0.0f; } - virtual void setValue(Ogre::Real value) + virtual void setValue(Ogre::Real time) { - // TODO: Implement + if (mMorphs.size() <= 1) + return; + +#if OGRE_DOUBLE_PRECISION +#error "This code needs to be rewritten for double precision mode" +#endif + + Ogre::VertexData* data = mSubEntity->_getSoftwareVertexAnimVertexData(); + + const Ogre::VertexElement* posElem = + data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION); + + Ogre::HardwareVertexBufferSharedPtr vbuf = + data->vertexBufferBinding->getBuffer(posElem->getSource()); + + bool needToUpdate = false; + int i=0; + for (std::vector::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i) + { + float val = 0; + if (!it->mData.mKeys.empty()) + val = interpKey(it->mData.mKeys, time); + val = std::max(0.f, std::min(1.f, val)); + + if (val != mValues[i]) + needToUpdate = true; + mValues[i] = val; + } + if (!needToUpdate) + return; + + // The first morph key always contains the original positions + mVertices = mMorphs[0].mVertices; + + i = 0; + for (std::vector::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i) + { + float val = mValues[i]; + + if (it->mVertices.size() != mMorphs[0].mVertices.size()) + continue; + + if (val != 0) + { + for (unsigned int v=0; vmVertices[v] * val; + } + } + + if (mVertices.size() * sizeof(float)*3 != vbuf->getSizeInBytes()) + return; + + vbuf->writeData(0, vbuf->getSizeInBytes(), &mVertices[0]); + + mSubEntity->_markBuffersUsedForAnimation(); } }; @@ -480,11 +557,10 @@ class NIFObjectLoader { const Nif::NiGeomMorpherController *geom = static_cast(ctrl.getPtr()); - Ogre::SubEntity *subent = entity->getSubEntity(0); Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value(subent, geom->data.getPtr())); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value(entity->getSubEntity(0), geom->data.getPtr())); GeomMorpherController::Function* function = OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); objectlist.mMaxControllerLength = std::max(function->mStopTime, objectlist.mMaxControllerLength);