From 59137d93c99bdd9795a0dd0be7d3e9d4e63a2bb0 Mon Sep 17 00:00:00 2001
From: Chris Robinson <chris.kcat@gmail.com>
Date: Mon, 22 Apr 2013 03:24:02 -0700
Subject: [PATCH] Partially handle NiGeomMorpherController

The morphs aren't actually applied yet, but the Ogre controller is set up so
all that has to be done is to implement the setValue method.
---
 components/nifogre/mesh.cpp          | 14 +++++++++
 components/nifogre/ogrenifloader.cpp | 45 +++++++++++++++++++++++++++-
 components/nifogre/skeleton.cpp      |  3 +-
 3 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp
index c0a7af5c3..851160de2 100644
--- a/components/nifogre/mesh.cpp
+++ b/components/nifogre/mesh.cpp
@@ -116,6 +116,20 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape
     std::vector<Ogre::Vector3> srcNorms = data->normals;
     Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC;
     bool vertShadowBuffer = false;
+
+    if(!shape->controller.empty())
+    {
+        Nif::ControllerPtr ctrl = shape->controller;
+        do {
+            if(ctrl->recType == Nif::RC_NiGeomMorpherController)
+            {
+                vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY;
+                vertShadowBuffer = true;
+                break;
+            }
+        } while(!(ctrl=ctrl->next).empty());
+    }
+
     if(skin != NULL)
     {
         vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY;
diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp
index dc6bb8d24..942b3858a 100644
--- a/components/nifogre/ogrenifloader.cpp
+++ b/components/nifogre/ogrenifloader.cpp
@@ -293,7 +293,7 @@ public:
         }
 
     public:
-        Value(const Ogre::MaterialPtr &material, Nif::NiUVData *data)
+        Value(const Ogre::MaterialPtr &material, const Nif::NiUVData *data)
           : mMaterial(material)
           , mUTrans(data->mKeyList[0])
           , mVTrans(data->mKeyList[1])
@@ -363,6 +363,36 @@ public:
     typedef DefaultFunction Function;
 };
 
+class GeomMorpherController
+{
+public:
+    class Value : public Ogre::ControllerValue<Ogre::Real>
+    {
+    private:
+        Ogre::SubEntity *mSubEntity;
+        std::vector<Nif::NiMorphData::MorphData> mMorphs;
+
+    public:
+        Value(Ogre::SubEntity *subent, const Nif::NiMorphData *data)
+          : mSubEntity(subent)
+          , mMorphs(data->mMorphs)
+        { }
+
+        virtual Ogre::Real getValue() const
+        {
+            // Should not be called
+            return 0.0f;
+        }
+
+        virtual void setValue(Ogre::Real value)
+        {
+            // TODO: Implement
+        }
+    };
+
+    typedef DefaultFunction Function;
+};
+
 
 /** Object creator for NIFs. This is the main class responsible for creating
  * "live" Ogre objects (entities, particle systems, controllers, etc) from
@@ -429,6 +459,19 @@ class NIFObjectLoader
 
                 objectlist.mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
             }
+            else if(ctrl->recType == Nif::RC_NiGeomMorpherController)
+            {
+                const Nif::NiGeomMorpherController *geom = static_cast<const Nif::NiGeomMorpherController*>(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::ControllerFunctionRealPtr func(OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay)));
+
+                objectlist.mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
+            }
             ctrl = ctrl->next;
         }
     }
diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp
index 1809212a7..1306d037c 100644
--- a/components/nifogre/skeleton.cpp
+++ b/components/nifogre/skeleton.cpp
@@ -179,7 +179,8 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node,
             ctrls.push_back(static_cast<const Nif::NiKeyframeController*>(ctrl.getPtr()));
         else if(!(ctrl->recType == Nif::RC_NiParticleSystemController ||
                   ctrl->recType == Nif::RC_NiVisController ||
-                  ctrl->recType == Nif::RC_NiUVController
+                  ctrl->recType == Nif::RC_NiUVController ||
+                  ctrl->recType == Nif::RC_NiGeomMorpherController
                   ))
             warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName());
         ctrl = ctrl->next;