From 6d5169cf33d59643d38095ba4d37613441973199 Mon Sep 17 00:00:00 2001
From: Tazpn <tazpn@users.sourceforge.net>
Date: Sat, 8 Jul 2006 14:27:13 +0000
Subject: [PATCH] Fix Animation support and add bsplines and kf files.

---
 NifImport/ImportAnimation.cpp | 93 +++++++++++++++++++++++++----------
 NifImport/KFImporter.cpp      | 35 +++++++++++++
 NifImport/KFImporter.h        | 34 +++++++++++++
 NifImport/KFMImporter.cpp     | 25 +++++++++-
 NifImport/KFMImporter.h       |  1 +
 NifImport/MaxNifImport.cpp    | 24 +++++----
 NifImport/MaxNifImport.vcproj | 10 +++-
 NifImport/MaxNifTools.ini     |  4 +-
 8 files changed, 187 insertions(+), 39 deletions(-)
 create mode 100644 NifImport/KFImporter.cpp
 create mode 100644 NifImport/KFImporter.h

diff --git a/NifImport/ImportAnimation.cpp b/NifImport/ImportAnimation.cpp
index c239048..1afe253 100644
--- a/NifImport/ImportAnimation.cpp
+++ b/NifImport/ImportAnimation.cpp
@@ -14,6 +14,7 @@ HISTORY:
 #include "MaxNifImport.h"
 #include "NIFImporter.h"
 #include "KFMImporter.h"
+#include "KFImporter.h"
 #include <obj/NiInterpolator.h>
 #include <obj/NiTransformInterpolator.h>
 #include <obj/NiTransformData.h>
@@ -23,7 +24,7 @@ HISTORY:
 #include <obj/NiKeyframeController.h>
 #include <obj/NiKeyframeData.h>
 #include <obj/NiStringPalette.h>
-
+#include <obj/NiBSplineCompTransformInterpolator.h>
 using namespace Niflib;
 
 const Class_ID IPOS_CONTROL_CLASS_ID = Class_ID(0x118f7e02,0xffee238a);
@@ -71,7 +72,7 @@ template<>
 inline ILinRotKey MapKey<ILinRotKey, QuatKey>(QuatKey& key, float time)
 {
    ILinRotKey rKey;
-   rKey.val = TOQUAT(key.data);
+   rKey.val = TOQUAT(key.data, true);
    return InitLinKey(rKey, key, time);
 }
 
@@ -127,7 +128,7 @@ template<>
 inline IBezQuatKey MapKey<IBezQuatKey, QuatKey>(QuatKey& key, float time)
 {
    IBezQuatKey rKey;
-   rKey.val = TOQUAT(key.data);
+   rKey.val = TOQUAT(key.data, true);
    return InitBezKey(rKey, key, time);
 }
 
@@ -164,7 +165,7 @@ template<>
 inline ITCBRotKey MapKey<ITCBRotKey, QuatKey>(QuatKey& key, float time)
 {
    ITCBRotKey rKey;
-   rKey.val = TOQUAT(key.data);
+   rKey.val = TOQUAT(key.data, true);
    InitTCBKey(rKey, key, time);
    rKey.flags = TCBKEY_QUATVALID;
    return rKey;
@@ -250,6 +251,7 @@ struct AnimationImport
 
    bool AddValues(Control *c, NiKeyframeDataRef data, float time);
 
+   Control* MakePosition(Control *tmCont, Class_ID clsid);
    Control* MakePositionXYZ(Control *tmCont, Class_ID clsid);
    Control* MakeRotation(Control *tmCont, Class_ID rotClsid, Class_ID rollClsid);
    Control* MakeScale(Control *tmCont, Class_ID clsid);
@@ -265,8 +267,9 @@ bool NifImporter::ImportAnimation()
    if (nodes.empty())
       return false;
 
+   NiNodeRef rootNode = root;
    AnimationImport ai(*this);
-   return ai.AddValues(DynamicCast<NiObjectNET>(nodes[0]->GetChildren()));
+   return ai.AddValues(DynamicCast<NiObjectNET>(rootNode->GetChildren()));
 }
 
 bool KFMImporter::ImportAnimation()
@@ -274,12 +277,15 @@ bool KFMImporter::ImportAnimation()
    bool ok = false;
    int curFrame = 0;
    // Read Kf files
-#ifdef USE_UNSUPPORTED_CODE
+
    AnimationImport ai(*this);
 
-   float time = 0.0f;
+   float time = FramesIncrement;
    for(vector<NiControllerSequenceRef>::iterator itr = kf.begin(); itr != kf.end(); ++itr){
 
+      float minTime = 1e+35f;
+      float maxTime = 0.0f;
+
       NiControllerSequenceRef cntr = (*itr);
       vector<ControllerLink> links = cntr->GetControllerData();
       for (vector<ControllerLink>::iterator lnk=links.begin(); lnk != links.end(); ++lnk){
@@ -298,31 +304,58 @@ bool KFMImporter::ImportAnimation()
 
          float start = cntr->GetStartTime();
          float stop = cntr->GetStopTime();
+         float total = (stop - start);
          if ((*lnk).interpolator){
             if (NiTransformInterpolatorRef interp = (*lnk).interpolator) {
                if (NiTransformDataRef data = interp->GetData()){
-                  ok |= ai.AddValues(c, data, time);
-                  time += (stop-start) + FramesIncrement; // round to nearest 10f ?
+                  if (ai.AddValues(c, data, time)) {
+                     minTime = min(minTime, start);
+                     maxTime = max(maxTime, stop);
+                     ok = true;
+                  }
+               }
+            } else if (NiBSplineCompTransformInterpolatorRef interp = (*lnk).interpolator) {
+               int npoints = total * 60.0f;
+
+               NiKeyframeDataRef data = CreateBlock("NiKeyframeData");
+               data->SetRotateType(QUADRATIC_KEY);
+               data->SetTranslateType(QUADRATIC_KEY);
+               data->SetScaleType(QUADRATIC_KEY);
+               data->SetTranslateKeys( interp->SampleTranslateKeys(npoints, 4) );
+               data->SetQuatRotateKeys( interp->SampleQuatRotateKeys(npoints, 4) );
+               data->SetScaleKeys( interp->SampleScaleKeys(npoints, 4) );
+
+               if (ai.AddValues(c, data, time)) {
+                  minTime = min(minTime, start);
+                  maxTime = max(maxTime, stop);
+                  ok = true;
                }
             }
          } else if ((*lnk).controller) {
             if (NiTransformControllerRef tc = DynamicCast<NiTransformController>((*lnk).controller)) {
                if (NiTransformInterpolatorRef interp = tc->GetInterpolator()) {
                   if (NiTransformDataRef data = interp->GetData()){
-                     ok |= ai.AddValues(c, data, time);
-                     time += (stop-start) + FramesIncrement; // round to nearest 10f ?
+                     if (ai.AddValues(c, data, time)) {
+                        minTime = min(minTime, start);
+                        maxTime = max(maxTime, stop);
+                        ok = true;
+                     }
                   }
                }
             } else if (NiKeyframeControllerRef kfc = DynamicCast<NiKeyframeController>((*lnk).controller)) {
-               if (NiKeyframeDataRef kfData = kfc->GetData()) {
-                  ok |= ai.AddValues(c, kfData, time);
-                  time += (stop-start) + FramesIncrement; // round to nearest 10f ?
+               if (NiKeyframeDataRef data = kfc->GetData()) {
+                  if (ai.AddValues(c, data, time)) {
+                     minTime = min(minTime, start);
+                     maxTime = max(maxTime, stop);
+                     ok = true;
+                  }
                }
             }
          }
       }
+      if (maxTime > minTime && maxTime > 0.0f)
+         time += (maxTime-minTime) + FramesIncrement;
    }
-#endif
    return ok;
 }
 
@@ -371,7 +404,7 @@ bool AnimationImport::AddValues(NiObjectNETRef nref)
    if (NULL == c)
       return false;
 
-   float time = 0.0f;
+   float time = FramesIncrement;
    list< NiTimeControllerRef > clist = nref->GetControllers();
    if (NiTransformControllerRef tc = SelectFirstObjectOfType<NiTransformController>(clist)) {
       if (NiTransformInterpolatorRef interp = tc->GetInterpolator()) {
@@ -544,20 +577,28 @@ Control* AnimationImport::MakeScale(Control *tmCont, Class_ID clsid)
    return NULL;
 }
 
-Control* AnimationImport::MakePositionXYZ(Control *tmCont, Class_ID clsid)
+Control* AnimationImport::MakePosition(Control *tmCont, Class_ID clsid)
 {
    Interface *ip = ni.gi;
-   if (Control *c = tmCont->GetPositionController()){
-      // First make the controller and XYZ Independent position controller, then fix individuals
-      if (c->ClassID()!= IPOS_CONTROL_CLASS_ID) {
-         if (Control *tmp = (Control*)ip->CreateInstance(CTRL_POSITION_CLASS_ID, IPOS_CONTROL_CLASS_ID)) {
-            if (!tmCont->SetPositionController(tmp)) {
-               tmp->DeleteThis();
-            } else {
-               c = tmp;
-            }
+   if (Control *c = tmCont->GetPositionController()) {
+      if (c->ClassID()!=clsid) {
+         if (Control *tmpCtrl = (Control*)ip->CreateInstance(CTRL_POSITION_CLASS_ID, clsid)){
+            if (!tmCont->SetPositionController(tmpCtrl))
+               tmpCtrl->DeleteThis();
+            else
+               c = tmpCtrl;
          }
       }
+      return c;
+   }
+   return NULL;
+}
+
+Control* AnimationImport::MakePositionXYZ(Control *tmCont, Class_ID clsid)
+{
+   Interface *ip = ni.gi;
+   // First make the controller and XYZ Independent position controller, then fix individuals
+   if (Control *c = MakePosition(tmCont, IPOS_CONTROL_CLASS_ID)){
       if (Control *x = c->GetXController()){
          if (x->ClassID()!= clsid) {
             if (Control *tmp = (Control*)ip->CreateInstance(CTRL_FLOAT_CLASS_ID, clsid))
diff --git a/NifImport/KFImporter.cpp b/NifImport/KFImporter.cpp
new file mode 100644
index 0000000..a27f131
--- /dev/null
+++ b/NifImport/KFImporter.cpp
@@ -0,0 +1,35 @@
+#include "StdAfx.h"
+#include "KFImporter.h"
+#include <kfm.h>
+#include "gen/ControllerLink.h"
+using namespace Niflib;
+
+KFImporter::KFImporter(const TCHAR *Name,ImpInterface *I,Interface *GI, BOOL SuppressPrompts)
+   : BaseClass()
+{
+   BaseInit(Name, I, GI, SuppressPrompts);
+}
+
+KFImporter::~KFImporter(void)
+{
+}
+
+void KFImporter::ReadBlocks()
+{
+   try
+   {
+      kf = DynamicCast<NiControllerSequence>(ReadNifList(name.c_str()));
+      BuildNodes();
+   }
+   catch (std::exception&)
+   {
+   }
+   catch (...) 
+   {
+   }
+}
+
+bool KFImporter::DoImport()
+{
+   return ImportAnimation();
+}
diff --git a/NifImport/KFImporter.h b/NifImport/KFImporter.h
new file mode 100644
index 0000000..4022ea1
--- /dev/null
+++ b/NifImport/KFImporter.h
@@ -0,0 +1,34 @@
+/**********************************************************************
+*<
+FILE: KFImporter.h
+
+DESCRIPTION:	KF Importer helper class 
+
+CREATED BY: tazpn (Theo)
+
+HISTORY: 
+
+*>	Copyright (c) 2006, All Rights Reserved.
+**********************************************************************/
+#ifndef _KFIMPORTER_H_
+#define _KFIMPORTER_H_
+
+#pragma once
+#include "NIFImporter.h"
+#include "KFMImporter.h"
+#include "niutils.h"
+#include "obj/NiControllerSequence.h"
+
+class KFImporter : public KFMImporter
+{
+   typedef KFMImporter BaseClass;
+public:
+   KFImporter(const TCHAR *Name,ImpInterface *I,Interface *GI, BOOL SuppressPrompts);
+   ~KFImporter(void);
+
+   void ReadBlocks();
+   virtual bool DoImport();
+};
+
+
+#endif 
\ No newline at end of file
diff --git a/NifImport/KFMImporter.cpp b/NifImport/KFMImporter.cpp
index dcdc4ef..bc801be 100644
--- a/NifImport/KFMImporter.cpp
+++ b/NifImport/KFMImporter.cpp
@@ -10,6 +10,10 @@ KFMImporter::KFMImporter(const TCHAR *Name,ImpInterface *I,Interface *GI, BOOL S
    BaseInit(Name, I, GI, SuppressPrompts);
 }
 
+KFMImporter::KFMImporter()
+{
+}
+
 KFMImporter::~KFMImporter(void)
 {
 }
@@ -26,6 +30,10 @@ void KFMImporter::ReadBlocks()
          GetFullPathName(name.c_str(), MAX_PATH, buffer, NULL);
          PathRemoveFileSpec(buffer);
 #ifdef USE_UNSUPPORTED_CODE
+         string nif_filename = path + '\\' + kfm.nif_filename;
+         if (_taccess(nif_filename.c_str(), 0) != -1)
+            root = ReadNifTree(nif_filename);
+
          //root = kfm.MergeActions(string(buffer));
          BuildNodes();
 
@@ -38,9 +46,12 @@ void KFMImporter::ReadBlocks()
                if (action_filename != last_file) {
                    ctrllist = DynamicCast<NiControllerSequence>(ReadNifList(action_filename));
                }
-               if ((*it).unk_int2 && (*it).unk_int2 <= ctrllist.size()) {
+               if (((*it).unk_int2 && (*it).unk_int2 <= ctrllist.size())) {
                   if (NiControllerSequenceRef ctrlSeq = ctrllist[(*it).unk_int2-1])
                      kf.push_back(ctrlSeq);
+               } else if (!(*it).unk_int2 && ctrllist.size() == 1) {
+                  if (NiControllerSequenceRef ctrlSeq = ctrllist[0])
+                     kf.push_back(ctrlSeq);
                }
             }
          }
@@ -58,6 +69,18 @@ void KFMImporter::ReadBlocks()
 bool KFMImporter::DoImport()
 {
    // might check if blocks exist and if not go ahead and import nif.
+   if (root)
+   {
+      int n = nodes.size();
+      int m = 0;
+      for (vector<NiNodeRef>::iterator itr = nodes.begin(), end = nodes.end(); itr != end; ++itr) {
+         if (INode *p = gi->GetINodeByName((*itr)->GetName().c_str()))
+            m++;
+      }
+      if (m != n) {
+         BaseClass::DoImport();
+      }
+   }
    return ImportAnimation();
    //return BaseClass::DoImport();
 }
diff --git a/NifImport/KFMImporter.h b/NifImport/KFMImporter.h
index 241f706..f07aa80 100644
--- a/NifImport/KFMImporter.h
+++ b/NifImport/KFMImporter.h
@@ -23,6 +23,7 @@ class KFMImporter : public NifImporter
    typedef NifImporter BaseClass;
 public:
    KFMImporter(const TCHAR *Name,ImpInterface *I,Interface *GI, BOOL SuppressPrompts);
+   KFMImporter();
    ~KFMImporter(void);
 
    void ReadBlocks();
diff --git a/NifImport/MaxNifImport.cpp b/NifImport/MaxNifImport.cpp
index aa456df..40f861f 100644
--- a/NifImport/MaxNifImport.cpp
+++ b/NifImport/MaxNifImport.cpp
@@ -13,6 +13,7 @@
 #include "stdafx.h"
 #include "MaxNifImport.h"
 #include "KFMImporter.h"
+#include "KFImporter.h"
 using namespace Niflib;
 
 #define MaxNifImport_CLASS_ID	Class_ID(0x794ac1c1, 0x8b4c64c7)
@@ -130,9 +131,9 @@ MaxNifImport::~MaxNifImport()
 int MaxNifImport::ExtCount()
 {
 #ifdef USE_UNSUPPORTED_CODE
-	return 2;
+	return 3;
 #else
-   return 1;
+   return 2;
 #endif
 }
 
@@ -141,7 +142,8 @@ const TCHAR *MaxNifImport::Ext(int n)
    switch (n)
    {
    case 0: return _T("NIF");
-   case 1: return _T("KFM");
+   case 1: return _T("KF");
+   case 2: return _T("KFM");
    }
    return _T("");	
 }
@@ -222,21 +224,25 @@ int MaxNifImport::DoImport(const TCHAR *filename,ImpInterface *i, Interface *gi,
 
       LPCTSTR ext = PathFindExtension(filename);
 
-      if (_tcsicmp(ext, ".KFM") == 0)
+      if (_tcsicmp(ext, ".NIF") == 0)
+      {
+         NifImporter importer(filename, i, gi, suppressPrompts);
+         if (!importer.isValid())
+            return FALSE;
+         ok = importer.DoImport();
+      }
+      else if (_tcsicmp(ext, ".KFM") == 0)
       {
          KFMImporter importer(filename, i, gi, suppressPrompts);
          if (!importer.isValid())
             return FALSE;
-
          ok = importer.DoImport();
-
       }
-      else
+      else if (_tcsicmp(ext, ".KF") == 0)
       {
-         NifImporter importer(filename, i, gi, suppressPrompts);
+         KFImporter importer(filename, i, gi, suppressPrompts);
          if (!importer.isValid())
             return FALSE;
-
          ok = importer.DoImport();
       }
    }
diff --git a/NifImport/MaxNifImport.vcproj b/NifImport/MaxNifImport.vcproj
index 561006e..ace67d6 100644
--- a/NifImport/MaxNifImport.vcproj
+++ b/NifImport/MaxNifImport.vcproj
@@ -154,7 +154,7 @@
 				AdditionalOptions="/LD "
 				Optimization="0"
 				AdditionalIncludeDirectories=""
-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_USE_MATH_DEFINES"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_USE_MATH_DEFINES;USE_UNSUPPORTED_CODE"
 				GeneratePreprocessedFile="0"
 				ExceptionHandling="2"
 				RuntimeLibrary="1"
@@ -234,6 +234,10 @@
 				RelativePath=".\DllEntry.cpp"
 				>
 			</File>
+			<File
+				RelativePath=".\KFImporter.cpp"
+				>
+			</File>
 			<File
 				RelativePath=".\MaxNifImport.def"
 				>
@@ -263,6 +267,10 @@
 			Name="Header Files"
 			Filter="h;hpp;hxx;hm;inl"
 			>
+			<File
+				RelativePath=".\KFImporter.h"
+				>
+			</File>
 			<File
 				RelativePath=".\niutils.h"
 				>
diff --git a/NifImport/MaxNifTools.ini b/NifImport/MaxNifTools.ini
index 0259437..4ec1a55 100644
--- a/NifImport/MaxNifTools.ini
+++ b/NifImport/MaxNifTools.ini
@@ -43,8 +43,8 @@ BipedAngle=90.0
 BipedAnkleAttach=0.2
 ; Use Triangle Pelvis.  Default: 0
 BipedTrianglePelvis=0
-; Remove unused bones from the biped on import of a mesh. Default: 1
-RemoveUnusedImportedBones=1
+; Remove unused bones from the biped on import of a mesh. Default: 0
+RemoveUnusedImportedBones=0
 ; Minimum Bone Width / Maximum Bone Width / Ratio of Width to Length
 MinBoneWidth=0.001
 MaxBoneWidth=0.1
-- 
GitLab