From f6103df3213067c2a9b241bbb3c7e0dac0d8d4fc Mon Sep 17 00:00:00 2001 From: Tazpn <tazpn@users.sourceforge.net> Date: Sun, 27 Aug 2006 20:20:39 +0000 Subject: [PATCH] Commits for 0.2.2. Mostly normals and animation related. --- MaxNifPlugins_Readme.txt | 14 +- MaxNifTools.ini | 4 + NifCommon/AnimKey.cpp | 357 +++++++++++++++++++++++++ NifCommon/AnimKey.h | 163 ++++++++++++ NifCommon/NifCommon_VC80.vcproj | 8 + NifCommon/niutils.cpp | 4 +- NifCommon/niutils.h | 11 +- NifExport/Animation.cpp | 261 ++++++++++++++++++ NifExport/DllEntry.cpp | 8 +- NifExport/Exporter.h | 6 +- NifExport/KfExport.cpp | 148 +++++++++++ NifExport/NifExport.cpp | 4 +- NifExport/NifExport_VC80.vcproj | 8 + NifImport/ImportAnimation.cpp | 458 ++++++++++++-------------------- NifImport/ImportSkeleton.cpp | 25 +- NifImport/KFImporter.cpp | 5 + NifImport/KFMImporter.cpp | 6 + NifImport/MaxNifImport.h | 2 +- NifImport/MaxNifImport.rc | 39 +-- NifImport/NIFImport.cpp | 9 +- NifImport/NIFImporter.h | 4 + NifImport/NifDialog.cpp | 3 + 22 files changed, 1220 insertions(+), 327 deletions(-) create mode 100644 NifCommon/AnimKey.cpp create mode 100644 NifCommon/AnimKey.h create mode 100644 NifExport/Animation.cpp create mode 100644 NifExport/KfExport.cpp diff --git a/MaxNifPlugins_Readme.txt b/MaxNifPlugins_Readme.txt index cfbd87c..b853f3e 100644 --- a/MaxNifPlugins_Readme.txt +++ b/MaxNifPlugins_Readme.txt @@ -18,8 +18,8 @@ Additional Notes ---------------- - Set the layer value to "NonCollidable", if you want to be able to walk through - your objects, while still being able to activate them. + Set the layer value to "NonCollidable", if you want to be able to walk + through your objects, while still being able to activate them. If your collision mesh comes out deformed, go to the utilities tab, choose "Reset XForm" and click "Reset Selected". This should fix it. @@ -27,20 +27,24 @@ Change log ---------- - 0.2.1 + 0.2.2 ----- o Exporter - Fix Export of Normal values o Importer - Fix Import of Normal values + - Change Import of Bones to merge NonAccum nodes with parent + - Change Import of Animation to merge NonAccum nodes with parent node + - Add Option to Clear Animation on Import 0.2.1 ----- o Exporter - Replace the Tri Stripper with a new version. o The old version had some bugs which came when compiled with VS 2005. - - Fix issues with transforms on exporting with extra nodes and for collision meshes + - Fix issues with transforms on exporting with extra nodes and for + collision meshes 0.2 ----- @@ -55,8 +59,6 @@ o Exporter - Upgraded to Visual Studio 2005 - Dropped registry support in favor of INI file. - - Dropped Official Max6 support because I do not have Max 6 to compile it - o Try editing the MaxNifTools.ini and setting the MaxSDKVersion to 0x17700d00 - Fixed issue with importing glossiness setting on textures. - Fixed issues with export of vertex color. Alpha map is now exported as part of the normal color map. diff --git a/MaxNifTools.ini b/MaxNifTools.ini index 74969fd..e63efe1 100644 --- a/MaxNifTools.ini +++ b/MaxNifTools.ini @@ -72,6 +72,8 @@ EnableSkinSupport=1 EnableCollision=1 ; Vertex Color Support mode. (0-Disable; 1-Bake into mesh; 2-Use VertexPaint Modifier) Default:1 VertexColorMode=1 +; Merge NonAccum transforms into base node. Default: 1 +MergeNonAccum=1 [BipedImport] ; Top level bone import setting. Default:1 @@ -113,6 +115,8 @@ RequireMultipleKeys=1 ReplaceTCBRotationWithBezier=1 ; Apply the overall transform to skin and bones. Default: 1 ApplyOverallTransformToSkinAndBones=1 +; Clear Animation on Import. Default: 1 +ClearAnimation=1 [Collision] ; Scale Factor when blowing up bhk Shapes diff --git a/NifCommon/AnimKey.cpp b/NifCommon/AnimKey.cpp new file mode 100644 index 0000000..f5fcfdc --- /dev/null +++ b/NifCommon/AnimKey.cpp @@ -0,0 +1,357 @@ +/********************************************************************** +*< +FILE: AnimKey.h + +DESCRIPTION: Animation Key Import Routines + +CREATED BY: tazpn (Theo) + +HISTORY: + +*> Copyright (c) 2006, All Rights Reserved. +**********************************************************************/ +#include "pch.h" +// Max Headers +#include <Max.h> +#include <control.h> +// Niflib Headers +#include <niflib.h> +#include <Key.h> + +#include "AnimKey.h" +#include "niutils.h" + + +const Class_ID IPOS_CONTROL_CLASS_ID = Class_ID(0x118f7e02,0xffee238a); +enum { + IPOS_X_REF = 0, + IPOS_Y_REF = 1, + IPOS_Z_REF = 2, + IPOS_W_REF = 3, +}; + +template <typename T, typename U> +T& InitLinKey(T& rKey, U& key, float time) +{ + rKey.time = TimeToFrame(time + key.time); + rKey.flags = 0; + return rKey; +} + +template <typename T, typename U> +T& InitFromLinKey(T& rKey, U& key, float time) +{ + rKey.time = time + FrameToTime(key.time); + return rKey; +} + +template <typename T, typename U> +T& InitBezKey(T& rKey, U& key, float time) +{ + rKey.time = TimeToFrame(time + key.time); + rKey.flags = 0; + SetInTanType(rKey.flags,BEZKEY_FLAT); + SetOutTanType(rKey.flags,BEZKEY_FLAT); + return rKey; +} + + +template <typename T, typename U> +T& InitFromBezKey(T& rKey, U& key, float time) +{ + rKey.time = time + FrameToTime(key.time); + return rKey; +} + +template <typename T, typename U> +inline T& InitTCBKey(T& rKey, U& key, float time) +{ + rKey.time = TimeToFrame(time + key.time); + rKey.tens = key.tension; + rKey.cont = key.continuity; + rKey.bias = key.bias; + rKey.easeIn = 0.0f; + rKey.easeOut = 0.0f; + return rKey; +} + +template <typename T, typename U> +inline T& InitFromTCBKey(T& rKey, U& key, float time) +{ + rKey.time = time + FrameToTime(key.time); + rKey.tension = key.tens; + rKey.continuity = key.cont; + rKey.bias = key.bias; + return rKey; +} + +// Specialized Linear Mappings + +template<> +ILinFloatKey MapKey<ILinFloatKey,FloatKey>(FloatKey& key, float time) +{ + ILinFloatKey rKey; + rKey.val = key.data; + return InitLinKey(rKey, key, time); +} + +template<> +ILinRotKey MapKey<ILinRotKey, QuatKey>(QuatKey& key, float time) +{ + ILinRotKey rKey; + rKey.val = TOQUAT(key.data, true); + return InitLinKey(rKey, key, time); +} + +template<> +ILinScaleKey MapKey<ILinScaleKey, FloatKey>(FloatKey& key, float time) +{ + ILinScaleKey rKey; + rKey.val.s.Set(key.data, key.data, key.data); + rKey.val.q.Identity(); + return InitLinKey(rKey, key, time); +} + +template<> +ILinPoint3Key MapKey<ILinPoint3Key, Vector3Key>(Vector3Key& key, float time) +{ + ILinPoint3Key rKey; + rKey.val = TOPOINT3(key.data); + return InitLinKey(rKey, key, time); +} + + +// Specialized Linear Mappings + +template<> +FloatKey MapKey<FloatKey, ILinFloatKey>(ILinFloatKey& key, float time) +{ + FloatKey rKey; + rKey.data = key.val; + return InitFromLinKey(rKey, key, time); +} + + +// Specialized Bezier/Hybrid mappings + +template<> +IBezFloatKey MapKey<IBezFloatKey, FloatKey>(FloatKey& key, float time) +{ + IBezFloatKey rKey; + rKey.val = key.data; + rKey.intan = key.forward_tangent; + rKey.outtan = key.backward_tangent; + return InitBezKey(rKey, key, time); +} + +template<> +IBezPoint3Key MapKey<IBezPoint3Key, Vector3Key>(Vector3Key& key, float time) +{ + IBezPoint3Key rKey; + rKey.val = TOPOINT3(key.data); + rKey.intan = TOPOINT3(key.forward_tangent); + rKey.outtan = TOPOINT3(key.backward_tangent); + return InitBezKey(rKey, key, time); +} + + +template<> +IBezQuatKey MapKey<IBezQuatKey, QuatKey>(QuatKey& key, float time) +{ + IBezQuatKey rKey; + rKey.val = TOQUAT(key.data, true); + return InitBezKey(rKey, key, time); +} + +template<> +IBezScaleKey MapKey<IBezScaleKey, FloatKey>(FloatKey& key, float time) +{ + IBezScaleKey rKey; + rKey.val.s.Set(key.data, key.data, key.data); + rKey.val.q.Identity(); + return InitBezKey(rKey, key, time); +} + +// Specialized Linear Mappings + +template<> +FloatKey MapKey<FloatKey, IBezFloatKey>(IBezFloatKey& key, float time) +{ + FloatKey rKey; + rKey.data = key.val; + rKey.forward_tangent = key.intan; + rKey.backward_tangent = key.outtan; + return InitFromBezKey(rKey, key, time); +} + +// Specialized TCB Mappings + +template<> +ITCBFloatKey MapKey<ITCBFloatKey, FloatKey>(FloatKey& key, float time) +{ + ITCBFloatKey rKey; + rKey.val = key.data; + return InitTCBKey(rKey, key, time); +} + +template<> +ITCBRotKey MapKey<ITCBRotKey, QuatKey>(QuatKey& key, float time) +{ + ITCBRotKey rKey; + rKey.val = TOQUAT(key.data, true); + InitTCBKey(rKey, key, time); + rKey.flags = TCBKEY_QUATVALID; + return rKey; +} + +template<> +ITCBPoint3Key MapKey<ITCBPoint3Key, Vector3Key>(Vector3Key& key, float time) +{ + ITCBPoint3Key rKey; + rKey.val = TOPOINT3(key.data); + return InitTCBKey(rKey, key, time); +} + +template<> +ITCBScaleKey MapKey<ITCBScaleKey, FloatKey>(FloatKey& key, float time) +{ + ITCBScaleKey rKey; + rKey.val.s.Set(key.data, key.data, key.data); + rKey.val.q.Identity(); + return InitTCBKey(rKey, key, time); +} + +template<> +FloatKey MapKey<FloatKey, ITCBFloatKey>(ITCBFloatKey& key, float time) +{ + FloatKey rKey; + rKey.data = key.val; + return InitFromTCBKey(rKey, key, time); +} + +template<> void MergeKey<ILinRotKey>(ILinRotKey& lhs, ILinRotKey& rhs) { + lhs.val *= rhs.val; +} + +template<> void MergeKey<IBezQuatKey>(IBezQuatKey& lhs, IBezQuatKey& rhs) { + lhs.val *= rhs.val; +} + +template<> void MergeKey<ITCBRotKey>(ITCBRotKey& lhs, ITCBRotKey& rhs) { + lhs.val = Quat(lhs.val) * Quat(rhs.val); +} + +float GetValue(Vector3& value, V3T type) +{ + switch (type) { + case V3T_X: return value.x; + case V3T_Y: return value.y; + case V3T_Z: return value.z; + } + return 0.0f; +} + +void SetValue(Vector3& v, float value, V3T type) +{ + switch (type) { + case V3T_X: v.x = value; break; + case V3T_Y: v.y = value; break; + case V3T_Z: v.z = value; break; + } +} + +FloatKey& CopyKey( FloatKey& dst, Vector3Key& src, V3T type) +{ + dst.time = src.time; + dst.bias = src.bias; + dst.continuity = src.continuity; + dst.tension = src.tension; + dst.backward_tangent = GetValue(src.backward_tangent, type); + dst.forward_tangent = GetValue(src.forward_tangent, type); + dst.data = GetValue(src.data, type); + return dst; +} + +Vector3Key& CopyKey( Vector3Key& dst, FloatKey& src, V3T type) +{ + dst.time = src.time; + dst.bias = src.bias; + dst.continuity = src.continuity; + dst.tension = src.tension; + SetValue(dst.backward_tangent, src.backward_tangent, type); + SetValue(dst.forward_tangent, src.forward_tangent, type); + SetValue(dst.data, src.data, type); + return dst; +} + + +void SplitKeys(vector<Vector3Key>&keys, vector<FloatKey>&xkeys, vector<FloatKey>&ykeys, vector<FloatKey>&zkeys) +{ + int n = keys.size(); + xkeys.resize(n), ykeys.resize(n), zkeys.resize(n); + for (int i=0,n=keys.size(); i<n; ++i) { + Vector3Key& key = keys[i]; + CopyKey(xkeys[i], key, V3T_X), CopyKey(ykeys[i], key, V3T_Y), CopyKey(zkeys[i], key, V3T_Z); + } +} + +void JoinKeys(vector<Vector3Key>&keys, vector<FloatKey>&xkeys, vector<FloatKey>&ykeys, vector<FloatKey>&zkeys) +{ + int n = xkeys.size(); + keys.resize(n); + for (int i=0; i<n; ++i) { + Vector3Key& key = keys[i]; + CopyKey(key, xkeys[i], V3T_X), CopyKey(key, ykeys[i], V3T_Y), CopyKey(key, zkeys[i], V3T_Z); + } +} + +bool GetTranslationKeys(Control *c, vector<Vector3Key> keys, const vector<float>& times, float timeOffset) +{ + // separate xyz + if (c->ClassID() == IPOS_CONTROL_CLASS_ID) + { + KeyType kType = QUADRATIC_KEY; + vector<FloatKey> xkeys, ykeys, zkeys; + + if (Control *x = c->GetXController()){ + if (x->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + kType = LINEAR_KEY; + GetKeys<FloatKey, ILinFloatKey>(x, xkeys, /*times,*/ timeOffset); + } else if (x->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + kType = QUADRATIC_KEY; + GetKeys<FloatKey, IBezFloatKey>(x, xkeys, /*times,*/ timeOffset); + } else if (x->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + kType = TBC_KEY; + GetKeys<FloatKey, ITCBFloatKey>(x, xkeys, /*times,*/ timeOffset); + } else { + kType = QUADRATIC_KEY; + GetKeys<FloatKey, IBezFloatKey>(x, xkeys, /*times,*/ timeOffset); + } + } + if (Control *y = c->GetYController()){ + if (y->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + GetKeys<FloatKey, ILinFloatKey>(y, ykeys, /*times,*/ timeOffset); + } else if (y->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + GetKeys<FloatKey, IBezFloatKey>(y, ykeys, /*times,*/ timeOffset); + } else if (y->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + GetKeys<FloatKey, ITCBFloatKey>(y, ykeys, /*times,*/ timeOffset); + } else { + GetKeys<FloatKey, IBezFloatKey>(y, ykeys, /*times,*/ timeOffset); + } + } + if (Control *z = c->GetZController()){ + if (z->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + GetKeys<FloatKey, ILinFloatKey>(z, zkeys, /*times,*/ timeOffset); + } else if (z->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + GetKeys<FloatKey, IBezFloatKey>(z, zkeys, /*times,*/ timeOffset); + } else if (z->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + GetKeys<FloatKey, ITCBFloatKey>(z, zkeys, /*times,*/ timeOffset); + } else { + GetKeys<FloatKey, IBezFloatKey>(z, zkeys, /*times,*/ timeOffset); + } + } + JoinKeys(keys, xkeys, ykeys, zkeys); + return true; + } + return false; +} diff --git a/NifCommon/AnimKey.h b/NifCommon/AnimKey.h new file mode 100644 index 0000000..507bcea --- /dev/null +++ b/NifCommon/AnimKey.h @@ -0,0 +1,163 @@ +/********************************************************************** +*< +FILE: AnimKey.h + +DESCRIPTION: Animation Key Import Routines + +CREATED BY: tazpn (Theo) + +HISTORY: + +*> Copyright (c) 2006, All Rights Reserved. +**********************************************************************/ +// Max Headers +#include <Max.h> +#include <tab.h> + +// Niflib Headers +#include <niflib.h> +#include <Key.h> +using namespace Niflib; + +const float FramesPerSecond = 30.0f; +const float FramesIncrement = 1.0f/30.0f; +const int TicksPerFrame = GetTicksPerFrame(); + +inline TimeValue TimeToFrame(float t) { + return TimeValue(t * FramesPerSecond * TicksPerFrame); +} +inline float FrameToTime(TimeValue t) { + return float(t) / (FramesPerSecond * TicksPerFrame); +} + +typedef Key<float> FloatKey; +typedef Key<Quaternion> QuatKey; +typedef Key<Vector3> Vector3Key; + + +template<typename T, typename U> T MapKey(U& key, float time); + +// Specialized Linear Mappings +template<> ILinFloatKey MapKey<ILinFloatKey,FloatKey>(FloatKey& key, float time); +template<> ILinRotKey MapKey<ILinRotKey, QuatKey>(QuatKey& key, float time); +template<> ILinScaleKey MapKey<ILinScaleKey, FloatKey>(FloatKey& key, float time); +template<> ILinPoint3Key MapKey<ILinPoint3Key, Vector3Key>(Vector3Key& key, float time); + +template<> FloatKey MapKey<FloatKey, ILinFloatKey>(ILinFloatKey& key, float time); +template<> QuatKey MapKey<QuatKey, ILinRotKey>(ILinRotKey& key, float time); +template<> FloatKey MapKey<FloatKey, ILinScaleKey>(ILinScaleKey& key, float time); +template<> Vector3Key MapKey<Vector3Key, ILinPoint3Key>(ILinPoint3Key& key, float time); + +// Specialized Bezier/Hybrid mappings +template<> IBezFloatKey MapKey<IBezFloatKey, FloatKey>(FloatKey& key, float time); +template<> IBezPoint3Key MapKey<IBezPoint3Key, Vector3Key>(Vector3Key& key, float time); +template<> IBezQuatKey MapKey<IBezQuatKey, QuatKey>(QuatKey& key, float time); +template<> IBezScaleKey MapKey<IBezScaleKey, FloatKey>(FloatKey& key, float time); + +template<> FloatKey MapKey<FloatKey, IBezFloatKey>(IBezFloatKey& key, float time); +template<> QuatKey MapKey<QuatKey, IBezQuatKey>(IBezQuatKey& key, float time); +template<> FloatKey MapKey<FloatKey, IBezScaleKey>(IBezScaleKey& key, float time); +template<> Vector3Key MapKey<Vector3Key, IBezPoint3Key>(IBezPoint3Key& key, float time); + +// Specialized TCB mappings +template<> ITCBFloatKey MapKey<ITCBFloatKey, FloatKey>(FloatKey& key, float time); +template<> ITCBRotKey MapKey<ITCBRotKey, QuatKey>(QuatKey& key, float time); +template<> ITCBPoint3Key MapKey<ITCBPoint3Key, Vector3Key>(Vector3Key& key, float time); +template<> ITCBScaleKey MapKey<ITCBScaleKey, FloatKey>(FloatKey& key, float time); + +template<> FloatKey MapKey<FloatKey, ITCBFloatKey>(ITCBFloatKey& key, float time); +template<> QuatKey MapKey<QuatKey, ITCBRotKey>(ITCBRotKey& key, float time); +template<> FloatKey MapKey<FloatKey, ITCBScaleKey>(ITCBScaleKey& key, float time); +template<> Vector3Key MapKey<Vector3Key, ITCBPoint3Key>(ITCBPoint3Key& key, float time); + + +template<typename T> void MergeKey(T& lhs, T& rhs) { + lhs.val += rhs.val; +} + +//template<> void MergeKey<ILinFloatKey>(ILinFloatKey& lhs, ILinFloatKey& rhs); +template<> void MergeKey<ILinRotKey>(ILinRotKey& lhs, ILinRotKey& rhs); +//template<> void MergeKey<ILinScaleKey>(ILinScaleKey& lhs, ILinScaleKey& rhs); +//template<> void MergeKey<ILinPoint3Key>(ILinPoint3Key& lhs, ILinPoint3Key& rhs); + +//template<> void MergeKey<IBezFloatKey>(IBezFloatKey& lhs, IBezFloatKey& rhs); +template<> void MergeKey<IBezQuatKey>(IBezQuatKey& lhs, IBezQuatKey& rhs); +//template<> void MergeKey<IBezPoint3Key>(IBezPoint3Key& lhs, IBezPoint3Key& rhs); +//template<> void MergeKey<IBezScaleKey>(IBezScaleKey& lhs, IBezScaleKey& rhs); + +//template<> void MergeKey<ITCBFloatKey>(ITCBFloatKey& lhs, ITCBFloatKey& rhs); +template<> void MergeKey<ITCBRotKey>(ITCBRotKey& lhs, ITCBRotKey& rhs); +//template<> void MergeKey<ITCBPoint3Key>(ITCBPoint3Key& lhs, ITCBPoint3Key& rhs); +//template<> void MergeKey<ITCBScaleKey>(ITCBScaleKey& lhs, ITCBScaleKey& rhs); + +template<typename T> void MergeKey(IKeyControl *keys, T& key) +{ + for (int i=0, n=keys->GetNumKeys(); i<n; ++i) + { + T tmp; keys->GetKey(i, &tmp); + if (tmp.time == key.time) { + MergeKey(tmp, key); + keys->SetKey(i, &tmp); + return; + } + } + keys->AppendKey(&key); +} + +template<typename T, typename U> +inline void SetKeys(Control *subCtrl, vector<U>& keys, float time) +{ + if (subCtrl && !keys.empty()){ + if (IKeyControl *ikeys = GetKeyControlInterface(subCtrl)){ + ikeys->SetNumKeys(keys.size()); + for (int i=0,n=keys.size(); i<n; ++i) { + ikeys->SetKey(i, &MapKey<T>(keys[i], time)); + } + ikeys->SortKeys(); + } + } +} + +template<typename T, typename U> +inline void GetKeys(Control *subCtrl, vector<T>& keys, float time) +{ + if (IKeyControl *ikeys = GetKeyControlInterface(subCtrl)){ + int n = ikeys->GetKeySize(); + keys.reserve(n); + for (int i=0; i<n; ++i){ + U key; + ikeys->GetKey(i, &key); + keys.push_back( MapKey<T>(key, time) ); + } + } +} + +template<typename T, typename U> +inline void MergeKeys(Control *subCtrl, vector<U>& keys, float time) +{ + if (subCtrl && !keys.empty()){ + if (IKeyControl *ikeys = GetKeyControlInterface(subCtrl)){ + if (ikeys->GetNumKeys() == 0){ + SetKeys<T,U>(subCtrl, keys, time); + } else { + for (int i=0,n=keys.size(); i<n; ++i) { + MergeKey(ikeys, MapKey<T>(keys[i], time)); + } + ikeys->SortKeys(); + } + } + } +} + +enum V3T +{ + V3T_X, V3T_Y, V3T_Z +}; +extern float GetValue(Vector3& value, V3T type); +extern FloatKey& CopyKey( FloatKey& dst, Vector3Key& src, V3T type); +extern void SplitKeys(vector<Vector3Key>&keys, vector<FloatKey>&xkeys, vector<FloatKey>&ykeys, vector<FloatKey>&zkeys); +extern void JoinKeys(vector<Vector3Key>&keys, vector<FloatKey>&xkeys, vector<FloatKey>&ykeys, vector<FloatKey>&zkeys); + +typedef Key<string> KeyTextValue; + +bool GetTranslationKeys(Control *c, vector<Vector3Key> keys, const vector<float>& times, float timeOffset=0.0f); diff --git a/NifCommon/NifCommon_VC80.vcproj b/NifCommon/NifCommon_VC80.vcproj index d8d7fc7..6026cbc 100644 --- a/NifCommon/NifCommon_VC80.vcproj +++ b/NifCommon/NifCommon_VC80.vcproj @@ -426,6 +426,10 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + <File + RelativePath=".\AnimKey.cpp" + > + </File> <File RelativePath=".\AppSettings.cpp" > @@ -500,6 +504,10 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + <File + RelativePath=".\AnimKey.h" + > + </File> <File RelativePath=".\AppSettings.h" > diff --git a/NifCommon/niutils.cpp b/NifCommon/niutils.cpp index f6e0b75..fc7b014 100644 --- a/NifCommon/niutils.cpp +++ b/NifCommon/niutils.cpp @@ -327,7 +327,9 @@ void PosRotScaleNode(INode *n, Matrix3& m3, PosRotScale prs, TimeValue t) { Point3 p = m3.GetTrans(); Quat q = m3; - PosRotScaleNode(n, p, q, 1.0f, prs, t); + Matrix3 stm = m3 * Inverse(m3); + float s = (sqrt(stm.GetRow(0)[0]) + sqrt(stm.GetRow(1)[1]) + sqrt(stm.GetRow(1)[1])) / 3.0f; + PosRotScaleNode(n, p, q, s, prs, t); } // Set Position and Rotation on a standard controller will need to handle bipeds diff --git a/NifCommon/niutils.h b/NifCommon/niutils.h index 7d0d913..adc19d0 100644 --- a/NifCommon/niutils.h +++ b/NifCommon/niutils.h @@ -230,6 +230,7 @@ enum PosRotScale extern void PosRotScaleNode(INode *n, Point3 p, Quat& q, float s, PosRotScale prs = prsDefault, TimeValue t = 0); extern void PosRotScaleNode(Control *c, Point3 p, Quat& q, float s, PosRotScale prs = prsDefault, TimeValue t = 0); extern void PosRotScaleNode(INode *n, Matrix3& m3, PosRotScale prs = prsDefault, TimeValue t = 0); +extern void PosRotScaleNode(Control *c, Matrix3& m3, PosRotScale prs = prsDefault, TimeValue t = 0); extern Matrix3 GetNodeLocalTM(INode *n, TimeValue t = 0); extern Niflib::NiNodeRef FindNodeByName( const vector<Niflib::NiNodeRef>& blocks, const string& name ); @@ -286,12 +287,16 @@ static inline Niflib::Vector3 TOVECTOR3(const Point3& v){ static inline Quat TOQUAT(const Niflib::Quaternion& q, bool inverse = false){ Quat qt(q.x, q.y, q.z, q.w); - return (inverse) ? qt.Inverse() : qt; + return (inverse && q.w != FloatNegINF) ? qt.Inverse() : qt; } static inline Quat TOQUAT(const Niflib::QuaternionXYZW& q, bool inverse = false){ Quat qt(q.x, q.y, q.z, q.w); - return (inverse) ? qt.Inverse() : qt; + return (inverse && q.w != FloatNegINF) ? qt.Inverse() : qt; +} + +static inline Niflib::Quaternion TOQUAT(const Quat& q, bool inverse = false){ + return (inverse && q.w != FloatNegINF) ? TOQUAT(q.Inverse(), false) : Niflib::Quaternion(q.w, q.x, q.y, q.z); } static inline Niflib::QuaternionXYZW TOQUATXYZW(const Niflib::Quaternion& q){ @@ -308,7 +313,7 @@ static inline Niflib::QuaternionXYZW TOQUATXYZW(const Quat& q){ static inline AngAxis TOANGAXIS(const Niflib::Quaternion& q, bool inverse = false){ Quat qt(q.x, q.y, q.z, q.w); - if (inverse) qt.Invert(); + if (inverse && q.w != FloatNegINF) qt.Invert(); return AngAxis(q.x, q.y, q.z, q.w); } diff --git a/NifExport/Animation.cpp b/NifExport/Animation.cpp new file mode 100644 index 0000000..f550c0e --- /dev/null +++ b/NifExport/Animation.cpp @@ -0,0 +1,261 @@ +/********************************************************************** +*< +FILE: ImportAnimation.cpp + +DESCRIPTION: Animation Import Routines + +CREATED BY: tazpn (Theo) + +HISTORY: + +*> Copyright (c) 2006, All Rights Reserved. +**********************************************************************/ +#include "pch.h" +#include "NifExport.h" +#include "AnimKey.h" + +#include <obj/NiControllerSequence.h> +#include <obj/NiInterpolator.h> +#include <obj/NiTransformInterpolator.h> +#include <obj/NiTransformData.h> +#include <obj/NiTimeController.h> +#include <obj/NiTransformController.h> +#include <obj/NiTextKeyExtraData.h> +#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); +enum { + IPOS_X_REF = 0, + IPOS_Y_REF = 1, + IPOS_Z_REF = 2, + IPOS_W_REF = 3, +}; + +struct AnimationExport +{ + AnimationExport(Exporter& parent) : ne(parent) {} + + bool doExport(); + bool exportController(INode *node, NiControllerSequenceRef seq); + Control *GetTMController(INode* node); + + Exporter ≠ +}; + +bool Exporter::doAnimExport() +{ + AnimationExport animExporter(*this); + return animExporter.doExport(); + + return true; +} +//NiControllerSequenceRef makeSequence(TimeValue start, TimeValue end); + +bool AnimationExport::doExport() +{ + INode *root = ne.mI->GetRootNode(); + NiControllerSequenceRef seq = new NiControllerSequence(); + seq->SetStartTime(0.0f); + seq->SetStopTime(0.0f); + seq->SetFrequency(1.0f); + seq->SetCycleType( NiControllerSequence::CYCLE_CLAMP ); + seq->SetTargetName("Bip01"); + + return true; +} + + +Control *AnimationExport::GetTMController(INode *n) +{ + Control *c = n->GetTMController(); + if (NULL == c) + return NULL; + +#ifdef USE_BIPED + // ignore bipeds for now. + if ( (c->ClassID() == BIPSLAVE_CONTROL_CLASS_ID) + ||(c->ClassID() == BIPBODY_CONTROL_CLASS_ID) + ||(c->ClassID() == FOOTPRINT_CLASS_ID)) + return NULL; +#endif + + return c; +} + + +bool AnimationExport::exportController(INode *node, NiControllerSequenceRef seq) +{ + bool ok = true; + int nKeys = node->NumKeys(); + if (nKeys >= 0) + { + float timeOffset = 0.0f; + NiKeyframeDataRef data = new NiKeyframeData(); + if (Control *tmCont = GetTMController(node)) + { + if (Control *c = tmCont->GetPositionController()) + { + // separate xyz + if (c->ClassID() == IPOS_CONTROL_CLASS_ID) + { + KeyType kType = QUADRATIC_KEY; + vector<FloatKey> xkeys, ykeys, zkeys; + + if (Control *x = c->GetXController()){ + if (x->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + kType = LINEAR_KEY; + GetKeys<FloatKey, ILinFloatKey>(x, xkeys, timeOffset); + } else if (x->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + kType = QUADRATIC_KEY; + GetKeys<FloatKey, IBezFloatKey>(x, xkeys, timeOffset); + } else if (x->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + kType = TBC_KEY; + GetKeys<FloatKey, ITCBFloatKey>(x, xkeys, timeOffset); + } else { + kType = QUADRATIC_KEY; + GetKeys<FloatKey, IBezFloatKey>(x, xkeys, timeOffset); + } + } + if (Control *y = c->GetYController()){ + if (y->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + GetKeys<FloatKey, ILinFloatKey>(y, ykeys, timeOffset); + } else if (y->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + GetKeys<FloatKey, IBezFloatKey>(y, ykeys, timeOffset); + } else if (y->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + GetKeys<FloatKey, ITCBFloatKey>(y, ykeys, timeOffset); + } else { + GetKeys<FloatKey, IBezFloatKey>(y, ykeys, timeOffset); + } + } + if (Control *z = c->GetZController()){ + if (z->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + GetKeys<FloatKey, ILinFloatKey>(z, zkeys, timeOffset); + } else if (z->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + GetKeys<FloatKey, IBezFloatKey>(z, zkeys, timeOffset); + } else if (z->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + GetKeys<FloatKey, ITCBFloatKey>(z, zkeys, timeOffset); + } else { + GetKeys<FloatKey, IBezFloatKey>(z, zkeys, timeOffset); + } + } + vector<Vector3Key> keys; + JoinKeys(keys, xkeys, ykeys, zkeys); + data->SetTranslateType(kType); + data->SetTranslateKeys(keys); + + } else { + //if (c->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + // data->SetRotateType(LINEAR_KEY); + // GetKeys<FloatKey, ILinFloatKey>(z, zkeys, timeOffset); + //} else if (c->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + // data->SetZRotateType(QUADRATIC_KEY); + // GetKeys<FloatKey, IBezFloatKey>(z, zkeys, timeOffset); + //} else if (c->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + // data->SetZRotateType(TBC_KEY); + // GetKeys<FloatKey, ITCBFloatKey>(z, zkeys, timeOffset); + //} else { + // data->SetZRotateType(QUADRATIC_KEY); + // GetKeys<FloatKey, IBezFloatKey>(z, zkeys, timeOffset); + //} + } + } + + //// rotations + //if (Control *c = tmCont->GetPositionController()) + //{ + // // separate xyz + // if (c->ClassID() == IPOS_CONTROL_CLASS_ID) + // { + // if (Control *x = c->GetXController()){ + // if (x->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + // data->SetXRotateType(LINEAR_KEY); + // GetKeys<FloatKey, ILinFloatKey>(x, xkeys, timeOffset); + // } else if (x->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + // data->SetXRotateType(QUADRATIC_KEY); + // GetKeys<FloatKey, IBezFloatKey>(x, xkeys, timeOffset); + // } else if (x->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + // data->SetXRotateType(TBC_KEY); + // GetKeys<FloatKey, ITCBFloatKey>(x, xkeys, timeOffset); + // } else { + // data->SetXRotateType(QUADRATIC_KEY); + // GetKeys<FloatKey, IBezFloatKey>(x, xkeys, timeOffset); + // } + // data->SetXRotateKeys(xkeys); + // } + // if (Control *y = c->GetYController()){ + // KeyType kType = LINEAR_KEY; + // vector<FloatKey> ykeys; + // if (y->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + // data->SetYRotateType(LINEAR_KEY); + // GetKeys<FloatKey, ILinFloatKey>(y, ykeys, timeOffset); + // } else if (y->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + // data->SetYRotateType(QUADRATIC_KEY); + // GetKeys<FloatKey, IBezFloatKey>(y, ykeys, timeOffset); + // } else if (y->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + // data->SetYRotateType(TBC_KEY); + // GetKeys<FloatKey, ITCBFloatKey>(y, ykeys, timeOffset); + // } else { + // data->SetYRotateType(QUADRATIC_KEY); + // GetKeys<FloatKey, IBezFloatKey>(y, ykeys, timeOffset); + // } + // data->SetYRotateKeys(ykeys); + // } + // if (Control *z = c->GetZController()){ + // KeyType kType = LINEAR_KEY; + // vector<FloatKey> zkeys; + // if (z->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + // data->SetZRotateType(LINEAR_KEY); + // GetKeys<FloatKey, ILinFloatKey>(z, zkeys, timeOffset); + // } else if (z->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + // data->SetZRotateType(QUADRATIC_KEY); + // GetKeys<FloatKey, IBezFloatKey>(z, zkeys, timeOffset); + // } else if (z->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + // data->SetZRotateType(TBC_KEY); + // GetKeys<FloatKey, ITCBFloatKey>(z, zkeys, timeOffset); + // } else { + // data->SetZRotateType(QUADRATIC_KEY); + // GetKeys<FloatKey, IBezFloatKey>(z, zkeys, timeOffset); + // } + // data->SetZRotateKeys(zkeys); + // } + // } else { + // if (c->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + // data->SetRotateType(LINEAR_KEY); + // GetKeys<FloatKey, ILinFloatKey>(z, zkeys, timeOffset); + // } else if (c->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + // data->SetZRotateType(QUADRATIC_KEY); + // GetKeys<FloatKey, IBezFloatKey>(z, zkeys, timeOffset); + // } else if (c->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + // data->SetZRotateType(TBC_KEY); + // GetKeys<FloatKey, ITCBFloatKey>(z, zkeys, timeOffset); + // } else { + // data->SetZRotateType(QUADRATIC_KEY); + // GetKeys<FloatKey, IBezFloatKey>(z, zkeys, timeOffset); + // } + // } + //} + + } + //Class_ID c->ClassID() + //if (Control *subCtrl = MakePositionXYZ(c, Class_ID(LININTERP_FLOAT_CLASS_ID,0))) { + + //NiKeyframeDataRef data = new NiKeyframeData(); + //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) ); + } + for (int i=0, n=node->NumberOfChildren(); ok && i<n; ++i) + { + INode *child = node->GetChildNode(i); + ok |= exportController(child, seq); + } + return ok; +} \ No newline at end of file diff --git a/NifExport/DllEntry.cpp b/NifExport/DllEntry.cpp index 3d0f8fa..0e7e3aa 100755 --- a/NifExport/DllEntry.cpp +++ b/NifExport/DllEntry.cpp @@ -2,6 +2,7 @@ #include "niutils.h" extern ClassDesc2* GetNifExportDesc(); +extern ClassDesc2* GetKfExportDesc(); static void InitializeLibSettings(); HINSTANCE hInstance; @@ -59,7 +60,11 @@ __declspec( dllexport ) const TCHAR* LibDescription() //TODO: Must change this number when adding a new class __declspec( dllexport ) int LibNumberClasses() { - return 1; +#if _DEBUG + return 2; +#else + return 1; +#endif } // This function returns the number of plug-in classes this DLL @@ -67,6 +72,7 @@ __declspec( dllexport ) ClassDesc* LibClassDesc(int i) { switch(i) { case 0: return GetNifExportDesc(); + case 1: return GetKfExportDesc(); default: return 0; } } diff --git a/NifExport/Exporter.h b/NifExport/Exporter.h index e73a5a4..36a4bfd 100755 --- a/NifExport/Exporter.h +++ b/NifExport/Exporter.h @@ -73,8 +73,7 @@ public: // reads config from registry static void readConfig(Interface *i); -private: - +public: typedef vector<unsigned short> TriStrip; typedef list<TriStrip> TriStrips; typedef vector<Triangle> Triangles; @@ -168,6 +167,9 @@ private: bool makeSkin(NiTriBasedGeomRef shape, INode *node, FaceGroup &grp, TimeValue t); bool exportSkin(); + /* animation export */ + bool doAnimExport(); + /* misc export */ bool exportUPB(NiNodeRef &root, INode *node); bool removeUnreferencedBones(NiNodeRef node); diff --git a/NifExport/KfExport.cpp b/NifExport/KfExport.cpp new file mode 100644 index 0000000..52c73e2 --- /dev/null +++ b/NifExport/KfExport.cpp @@ -0,0 +1,148 @@ +#include "pch.h" +#include "AppSettings.h" +#include "niutils.h" +#include <io.h> + +using namespace Niflib; + +#define KFEXPORT_CLASS_ID Class_ID(0xa57ff0a4, 0xa0374ffc) + +static LPCTSTR KfExportSection = TEXT("MaxKfExport"); + +class KfExport : public SceneExport +{ +public: + + static HWND hParams; + int mDlgResult; + TSTR iniFileName; + TSTR shortDescription; + + int ExtCount(); // Number of extensions supported + const TCHAR *Ext(int n); // Extension #n (i.e. "3DS") + const TCHAR *LongDesc(); // Long ASCII description (i.e. "Autodesk 3D Studio File") + const TCHAR *ShortDesc(); // Short ASCII description (i.e. "3D Studio") + const TCHAR *AuthorName(); // ASCII Author name + const TCHAR *CopyrightMessage(); // ASCII Copyright message + const TCHAR *OtherMessage1(); // Other message #1 + const TCHAR *OtherMessage2(); // Other message #2 + unsigned int Version(); // Version number * 100 (i.e. v3.01 = 301) + void ShowAbout(HWND hWnd); // Show DLL's "About..." box + + BOOL SupportsOptions(int ext, DWORD options); + int DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts=FALSE, DWORD options=0); + + KfExport(); + ~KfExport(); +}; + + + +class KfExportClassDesc : public ClassDesc2 +{ +public: + int IsPublic() { return TRUE; } + void *Create(BOOL loading = FALSE) { return new KfExport(); } + const TCHAR *ClassName() { return GetString(IDS_CLASS_NAME); } + SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; } + Class_ID ClassID() { return KFEXPORT_CLASS_ID; } + const TCHAR *Category() { return GetString(IDS_CATEGORY); } + + const TCHAR *InternalName() { return _T("KfExport"); } // returns fixed parsable name (scripter-visible name) + HINSTANCE HInstance() { return hInstance; } // returns owning module handle + + +}; + +static KfExportClassDesc KfExportDesc; +ClassDesc2* GetKfExportDesc() { return &KfExportDesc; } + + +//--- KfExport ------------------------------------------------------- +KfExport::KfExport() +{ + Interface *gi = GetCOREInterface(); + TCHAR iniName[MAX_PATH]; + if (gi) { + LPCTSTR pluginDir = gi->GetDir(APP_PLUGCFG_DIR); + PathCombine(iniName, pluginDir, "MaxNifTools.ini"); + } else { + GetModuleFileName(NULL, iniName, _countof(iniName)); + if (LPTSTR fname = PathFindFileName(iniName)) + fname = NULL; + PathAddBackslash(iniName); + PathAppend(iniName, "plugcfg"); + PathAppend(iniName, "MaxNifTools.ini"); + } + iniFileName = iniName; + shortDescription = GetIniValue<TSTR>("System", "ShortDescription", "Netimmerse/Gamebryo", iniFileName); +} + +KfExport::~KfExport() +{ + +} + +int KfExport::ExtCount() +{ + return 1; +} + +const TCHAR *KfExport::Ext(int n) +{ + return _T("kf"); +} + +const TCHAR *KfExport::LongDesc() +{ + return _T("Gamebryo File"); +} + +const TCHAR *KfExport::ShortDesc() +{ + return shortDescription; +} + +const TCHAR *KfExport::AuthorName() +{ + return _T("Theo / The Niftools Team"); +} + +const TCHAR *KfExport::CopyrightMessage() +{ + return _T("http://niftools.sourceforge.net"); +} + +const TCHAR *KfExport::OtherMessage1() +{ + return _T("http://niftools.sourceforge.net"); +} + +const TCHAR *KfExport::OtherMessage2() +{ + return _T("http://niftools.sourceforge.net"); +} + +unsigned int KfExport::Version() +{ + return Exporter::mVersion; +} + +void KfExport::ShowAbout(HWND hWnd) +{ + +} + +BOOL KfExport::SupportsOptions(int ext, DWORD options) +{ + return TRUE; +} + + +int KfExport::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL suppressPrompts, DWORD options) +{ + // read application settings + AppSettings::Initialize(i); + + return TRUE; +} \ No newline at end of file diff --git a/NifExport/NifExport.cpp b/NifExport/NifExport.cpp index 2605160..17d12bd 100755 --- a/NifExport/NifExport.cpp +++ b/NifExport/NifExport.cpp @@ -231,12 +231,12 @@ const TCHAR *NifExport::Ext(int n) const TCHAR *NifExport::LongDesc() { - return _T("Gambryo File"); + return _T("Gamebryo File"); } const TCHAR *NifExport::ShortDesc() { - return _T("Gambryo File"); + return _T("Gamebryo File"); } const TCHAR *NifExport::AuthorName() diff --git a/NifExport/NifExport_VC80.vcproj b/NifExport/NifExport_VC80.vcproj index feda5c8..e1997b4 100644 --- a/NifExport/NifExport_VC80.vcproj +++ b/NifExport/NifExport_VC80.vcproj @@ -637,6 +637,10 @@ Name="Source Files" Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" > + <File + RelativePath=".\Animation.cpp" + > + </File> <File RelativePath="Coll.cpp" > @@ -653,6 +657,10 @@ RelativePath="Exporter.cpp" > </File> + <File + RelativePath=".\KfExport.cpp" + > + </File> <File RelativePath="Mesh.cpp" > diff --git a/NifImport/ImportAnimation.cpp b/NifImport/ImportAnimation.cpp index 9307e84..f4c21f9 100644 --- a/NifImport/ImportAnimation.cpp +++ b/NifImport/ImportAnimation.cpp @@ -35,209 +35,7 @@ enum { IPOS_W_REF = 3, }; -const float FramesPerSecond = 30.0f; -const float FramesIncrement = 1.0f/30.0f; - -const int TicksPerFrame = GetTicksPerFrame(); - -inline TimeValue TimeToFrame(float t) { - return TimeValue(t * FramesPerSecond * TicksPerFrame); -} - -typedef Key<float> FloatKey; -typedef Key<Quaternion> QuatKey; -typedef Key<Vector3> Vector3Key; - - -template<typename T, typename U> -inline T MapKey(U& key, float time); - - -template <typename T, typename U> -inline T& InitLinKey(T& rKey, U& key, float time) -{ - rKey.time = TimeToFrame(time + key.time); - rKey.flags = 0; - return rKey; -} -template<> -inline ILinFloatKey MapKey<ILinFloatKey,FloatKey>(FloatKey& key, float time) -{ - ILinFloatKey rKey; - rKey.val = key.data; - return InitLinKey(rKey, key, time); -} - -template<> -inline ILinRotKey MapKey<ILinRotKey, QuatKey>(QuatKey& key, float time) -{ - ILinRotKey rKey; - rKey.val = TOQUAT(key.data, true); - return InitLinKey(rKey, key, time); -} - -template<> -inline ILinScaleKey MapKey<ILinScaleKey, FloatKey>(FloatKey& key, float time) -{ - ILinScaleKey rKey; - rKey.val.s.Set(key.data, key.data, key.data); - rKey.val.q.Identity(); - return InitLinKey(rKey, key, time); -} - -template<> -inline ILinPoint3Key MapKey<ILinPoint3Key, Vector3Key>(Vector3Key& key, float time) -{ - ILinPoint3Key rKey; - rKey.val = TOPOINT3(key.data); - return InitLinKey(rKey, key, time); -} - - -template <typename T, typename U> -inline T& InitBezKey(T& rKey, U& key, float time) -{ - rKey.time = TimeToFrame(time + key.time); - rKey.flags = 0; - SetInTanType(rKey.flags,BEZKEY_FLAT); - SetOutTanType(rKey.flags,BEZKEY_FLAT); - return rKey; -} -template<> -inline IBezFloatKey MapKey<IBezFloatKey, FloatKey>(FloatKey& key, float time) -{ - IBezFloatKey rKey; - rKey.val = key.data; - rKey.intan = key.forward_tangent; - rKey.outtan = key.backward_tangent; - return InitBezKey(rKey, key, time); -} - -template<> -inline IBezPoint3Key MapKey<IBezPoint3Key, Vector3Key>(Vector3Key& key, float time) -{ - IBezPoint3Key rKey; - rKey.val = TOPOINT3(key.data); - rKey.intan = TOPOINT3(key.forward_tangent); - rKey.outtan = TOPOINT3(key.backward_tangent); - return InitBezKey(rKey, key, time); -} - - -template<> -inline IBezQuatKey MapKey<IBezQuatKey, QuatKey>(QuatKey& key, float time) -{ - IBezQuatKey rKey; - rKey.val = TOQUAT(key.data, true); - return InitBezKey(rKey, key, time); -} - -template<> -inline IBezScaleKey MapKey<IBezScaleKey, FloatKey>(FloatKey& key, float time) -{ - IBezScaleKey rKey; - rKey.val.s.Set(key.data, key.data, key.data); - rKey.val.q.Identity(); - return InitBezKey(rKey, key, time); -} - -template <typename T, typename U> -inline T& InitTCBKey(T& rKey, U& key, float time) -{ - rKey.time = TimeToFrame(time + key.time); - rKey.tens = key.tension; - rKey.cont = key.continuity; - rKey.bias = key.bias; - rKey.easeIn = 0.0f; - rKey.easeOut = 0.0f; - return rKey; -} - -template<> -inline ITCBFloatKey MapKey<ITCBFloatKey, FloatKey>(FloatKey& key, float time) -{ - ITCBFloatKey rKey; - rKey.val = key.data; - return InitTCBKey(rKey, key, time); -} - -template<> -inline ITCBRotKey MapKey<ITCBRotKey, QuatKey>(QuatKey& key, float time) -{ - ITCBRotKey rKey; - rKey.val = TOQUAT(key.data, true); - InitTCBKey(rKey, key, time); - rKey.flags = TCBKEY_QUATVALID; - return rKey; -} - -template<> -inline ITCBPoint3Key MapKey<ITCBPoint3Key, Vector3Key>(Vector3Key& key, float time) -{ - ITCBPoint3Key rKey; - rKey.val = TOPOINT3(key.data); - return InitTCBKey(rKey, key, time); -} - -template<> -inline ITCBScaleKey MapKey<ITCBScaleKey, FloatKey>(FloatKey& key, float time) -{ - ITCBScaleKey rKey; - rKey.val.s.Set(key.data, key.data, key.data); - rKey.val.q.Identity(); - return InitTCBKey(rKey, key, time); -} - -template<typename T, typename U> -inline void SetKeys(Control *subCtrl, vector<U>& keys, float time) -{ - if (subCtrl && !keys.empty()){ - if (IKeyControl *ikeys = GetKeyControlInterface(subCtrl)){ - ikeys->SetNumKeys(keys.size()); - for (int i=0,n=keys.size(); i<n; ++i) { - ikeys->SetKey(i, &MapKey<T>(keys[i], time)); - } - } - } -} - -enum V3T -{ - V3T_X, V3T_Y, V3T_Z -}; -inline float GetValue(Vector3& value, V3T type) -{ - switch (type) { - case V3T_X: return value.x; - case V3T_Y: return value.y; - case V3T_Z: return value.z; - } - return 0.0f; -} - -FloatKey& CopyKey( FloatKey& dst, Vector3Key& src, V3T type) -{ - dst.time = src.time; - dst.bias = src.bias; - dst.continuity = src.continuity; - dst.tension = src.tension; - dst.backward_tangent = GetValue(src.backward_tangent, type); - dst.forward_tangent = GetValue(src.forward_tangent, type); - dst.data = GetValue(src.data, type); - return dst; -} - -void SplitKeys(vector<Vector3Key>&keys, vector<FloatKey>&xkeys, vector<FloatKey>&ykeys, vector<FloatKey>&zkeys) -{ - int n = keys.size(); - xkeys.resize(n), ykeys.resize(n), zkeys.resize(n); - for (int i=0,n=keys.size(); i<n; ++i) { - Vector3Key& key = keys[i]; - CopyKey(xkeys[i], key, V3T_X), CopyKey(ykeys[i], key, V3T_Y), CopyKey(zkeys[i], key, V3T_Z); - } -} - -typedef Key<string> KeyTextValue; +#include "AnimKey.h" struct AnimationImport { @@ -257,6 +55,9 @@ struct AnimationImport Control* MakeScale(Control *tmCont, Class_ID clsid); Control* GetTMController(const string& name); + Matrix3 GetTM(const string& name, TimeValue t = 0); + + bool GetTransformData(ControllerLink& lnk, string name, NiKeyframeDataRef& outData, Point3& p, Quat& q, float& s); }; bool NifImporter::ImportAnimation() @@ -272,6 +73,54 @@ bool NifImporter::ImportAnimation() return ai.AddValues(DynamicCast<NiObjectNET>(rootNode->GetChildren())); } +static vector<ControllerLink>::iterator FindLink(string name, vector<ControllerLink>& links) +{ + for (vector<ControllerLink>::iterator lnk=links.begin(); lnk != links.end(); ) + { + string target = (*lnk).targetName; + if (target.empty()) { + NiStringPaletteRef strings = lnk->stringPalette; + target = strings->GetSubStr((*lnk).nodeNameOffset); + } + if (target == name) { + return lnk; + } + } + return links.end(); +} + +static void ClearAnimation(Control *c) +{ + if (c != NULL) + { + if (c->IsColorController()) + return; + + if (IKeyControl *ikeys = GetKeyControlInterface(c)){ + ikeys->SetNumKeys(0); + } + ClearAnimation(c->GetWController()); + ClearAnimation(c->GetXController()); + ClearAnimation(c->GetYController()); + ClearAnimation(c->GetZController()); + ClearAnimation(c->GetRotationController()); + ClearAnimation(c->GetPositionController()); + ClearAnimation(c->GetScaleController()); + } +} + +void NifImporter::ClearAnimation(INode *node) +{ + if (node != NULL) + { + node->DeleteKeys(TRACK_DOALL); + ::ClearAnimation(node->GetTMController()); + for (int i=0, n=node->NumberOfChildren(); i<n; ++i){ + ClearAnimation(node->GetChildNode(i)); + } + } +} + bool KFMImporter::ImportAnimation() { bool ok = false; @@ -280,7 +129,7 @@ bool KFMImporter::ImportAnimation() AnimationImport ai(*this); - float time = FramesIncrement; + float time = 0.0f; for(vector<NiControllerSequenceRef>::iterator itr = kf.begin(); itr != kf.end(); ++itr){ float minTime = 1e+35f; @@ -288,8 +137,9 @@ bool KFMImporter::ImportAnimation() NiControllerSequenceRef cntr = (*itr); vector<ControllerLink> links = cntr->GetControllerData(); - for (vector<ControllerLink>::iterator lnk=links.begin(); lnk != links.end(); ++lnk){ + for (vector<ControllerLink>::iterator lnk=links.begin(); lnk != links.end(); ++lnk) + { string name = (*lnk).targetName; if (name.empty()) { NiStringPaletteRef strings = lnk->stringPalette; @@ -298,6 +148,12 @@ bool KFMImporter::ImportAnimation() if (name.empty()) continue; + // I realize this is not the best way to do this but it works for some files + if (mergeNonAccum && wildmatch("* NonAccum", name)) + { + name = name.substr(0, name.length() - 9); + } + Control *c = ai.GetTMController(name); if (NULL == c) continue; @@ -305,79 +161,96 @@ bool KFMImporter::ImportAnimation() float start = cntr->GetStartTime(); float stop = cntr->GetStopTime(); float total = (stop - start); - if ((*lnk).interpolator){ - if (NiTransformInterpolatorRef interp = (*lnk).interpolator) { - - // Set initial conditions - Point3 p = TOPOINT3(interp->GetTranslation()); - Quat q = TOQUAT(interp->GetRotation(), true); - float s = interp->GetScale(); - PosRotScaleNode(c, p, q, s, prsDefault, 0); - - if (NiTransformDataRef data = interp->GetData()){ - 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; - - // Set initial conditions - Point3 p = TOPOINT3(interp->GetTranslation()); - Quat q = TOQUAT(interp->GetRotation(), true); - float s = interp->GetScale(); - PosRotScaleNode(c, p, q, s, prsDefault, 0); - - 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()) { - // Set initial conditions - Point3 p = TOPOINT3(interp->GetTranslation()); - Quat q = TOQUAT(interp->GetRotation(), true); - float s = interp->GetScale(); - PosRotScaleNode(c, p, q, s, prsDefault, 0); - - if (NiTransformDataRef data = interp->GetData()){ - 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 data = kfc->GetData()) { - if (ai.AddValues(c, data, time)) { - minTime = min(minTime, start); - maxTime = max(maxTime, stop); - ok = true; - } - } + + NiKeyframeDataRef data; + Point3 p; Quat q; float s; + if (ai.GetTransformData(*lnk, name, data, p, q, s)) { + PosRotScaleNode(c, p, q, s, prsDefault, 0); + 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; } + + if (time != 0.0f) + { + Interval range(0, TimeToFrame(time)); + gi->SetAnimRange(range); + } + return ok; } +bool AnimationImport::GetTransformData(ControllerLink& lnk, string name, NiKeyframeDataRef& outData, Point3& p, Quat& q, float& s) +{ + Control *c = GetTMController(name); + if (NULL == c) + return false; + + if (lnk.interpolator){ + if (NiTransformInterpolatorRef interp = lnk.interpolator) { + if (NiTransformDataRef data = interp->GetData()){ + outData = StaticCast<NiKeyframeData>(data); + + // Set initial conditions + p = TOPOINT3(interp->GetTranslation()); + q = TOQUAT(interp->GetRotation(), true); + s = interp->GetScale(); + return true; + } + } else if (NiBSplineCompTransformInterpolatorRef interp = lnk.interpolator) { + int npoints = interp->GetNumControlPt(); + + if (npoints > 3) + { + NiKeyframeDataRef data = CreateBlock("NiKeyframeData"); + data->SetRotateType(QUADRATIC_KEY); + data->SetTranslateType(QUADRATIC_KEY); + data->SetScaleType(QUADRATIC_KEY); + data->SetTranslateKeys( interp->SampleTranslateKeys(npoints, 3) ); + data->SetQuatRotateKeys( interp->SampleQuatRotateKeys(npoints, 3) ); + data->SetScaleKeys( interp->SampleScaleKeys(npoints, 3) ); + + outData = data; + + p = TOPOINT3(interp->GetTranslation()); + q = TOQUAT(interp->GetRotation(), true); + s = interp->GetScale(); + return true; + } + } + } else if (lnk.controller) { + if (NiTransformControllerRef tc = DynamicCast<NiTransformController>(lnk.controller)) { + if (NiTransformInterpolatorRef interp = tc->GetInterpolator()) { + if (NiTransformDataRef data = interp->GetData()){ + outData = StaticCast<NiKeyframeData>(data); + + p = TOPOINT3(interp->GetTranslation()); + q = TOQUAT(interp->GetRotation(), true); + s = interp->GetScale(); + return true; + } + } + } else if (NiKeyframeControllerRef kfc = DynamicCast<NiKeyframeController>(lnk.controller)) { + if (NiKeyframeDataRef data = kfc->GetData()) { + outData = data; + // values will not be used in transforms + p = Point3(FloatNegINF, FloatNegINF, FloatNegINF); + q = Quat(FloatNegINF, FloatNegINF, FloatNegINF, FloatNegINF); + s = FloatNegINF; + return true; + } + } + } + return false; +} + + Control *AnimationImport::GetTMController(const string& name) { INode *n = ni.gi->GetINodeByName(name.c_str()); @@ -399,6 +272,15 @@ Control *AnimationImport::GetTMController(const string& name) return c; } +Matrix3 AnimationImport::GetTM(const string& name, TimeValue t) +{ + INode *n = ni.gi->GetINodeByName(name.c_str()); + if (NULL == n) + return Matrix3(true); + + return n->GetObjTMAfterWSM(t); +} + vector<KeyTextValue> AnimationImport::BuildKeyValues(NiObjectNETRef nref) { if (NiTextKeyExtraDataRef keydata = SelectFirstObjectOfType<NiTextKeyExtraData>(nref->GetExtraData())) @@ -470,9 +352,9 @@ bool AnimationImport::AddValues(Control *c, NiKeyframeDataRef data, float time) if (Control *subCtrl = MakePositionXYZ(c, Class_ID(LININTERP_FLOAT_CLASS_ID,0))) { vector<FloatKey> xkeys, ykeys, zkeys; SplitKeys(posKeys, xkeys, ykeys, zkeys); - SetKeys<ILinFloatKey, FloatKey>(subCtrl->GetXController(), xkeys, time); - SetKeys<ILinFloatKey, FloatKey>(subCtrl->GetYController(), ykeys, time); - SetKeys<ILinFloatKey, FloatKey>(subCtrl->GetZController(), zkeys, time); + MergeKeys<ILinFloatKey, FloatKey>(subCtrl->GetXController(), xkeys, time); + MergeKeys<ILinFloatKey, FloatKey>(subCtrl->GetYController(), ykeys, time); + MergeKeys<ILinFloatKey, FloatKey>(subCtrl->GetZController(), zkeys, time); } break; @@ -481,9 +363,9 @@ bool AnimationImport::AddValues(Control *c, NiKeyframeDataRef data, float time) if (Control *subCtrl = MakePositionXYZ(c, Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))) { vector<FloatKey> xkeys, ykeys, zkeys; SplitKeys(posKeys, xkeys, ykeys, zkeys); - SetKeys<IBezFloatKey, FloatKey>(subCtrl->GetXController(), xkeys, time); - SetKeys<IBezFloatKey, FloatKey>(subCtrl->GetYController(), ykeys, time); - SetKeys<IBezFloatKey, FloatKey>(subCtrl->GetZController(), zkeys, time); + MergeKeys<IBezFloatKey, FloatKey>(subCtrl->GetXController(), xkeys, time); + MergeKeys<IBezFloatKey, FloatKey>(subCtrl->GetYController(), ykeys, time); + MergeKeys<IBezFloatKey, FloatKey>(subCtrl->GetZController(), zkeys, time); } break; @@ -491,9 +373,9 @@ bool AnimationImport::AddValues(Control *c, NiKeyframeDataRef data, float time) if (Control *subCtrl = MakePositionXYZ(c, Class_ID(TCBINTERP_FLOAT_CLASS_ID,0))) { vector<FloatKey> xkeys, ykeys, zkeys; SplitKeys(posKeys, xkeys, ykeys, zkeys); - SetKeys<ITCBFloatKey, FloatKey>(subCtrl->GetXController(), xkeys, time); - SetKeys<ITCBFloatKey, FloatKey>(subCtrl->GetYController(), ykeys, time); - SetKeys<ITCBFloatKey, FloatKey>(subCtrl->GetZController(), zkeys, time); + MergeKeys<ITCBFloatKey, FloatKey>(subCtrl->GetXController(), xkeys, time); + MergeKeys<ITCBFloatKey, FloatKey>(subCtrl->GetYController(), ykeys, time); + MergeKeys<ITCBFloatKey, FloatKey>(subCtrl->GetZController(), zkeys, time); } break; } @@ -503,21 +385,21 @@ bool AnimationImport::AddValues(Control *c, NiKeyframeDataRef data, float time) { case LINEAR_KEY: if (Control *subCtrl = MakeRotation(c, Class_ID(LININTERP_ROTATION_CLASS_ID,0), Class_ID(LININTERP_FLOAT_CLASS_ID,0))) { - SetKeys<ILinRotKey, QuatKey>(subCtrl, quatKeys, time); + MergeKeys<ILinRotKey, QuatKey>(subCtrl, quatKeys, time); } break; case QUADRATIC_KEY: if (Control *subCtrl = MakeRotation(c, Class_ID(HYBRIDINTERP_ROTATION_CLASS_ID,0), Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))) { - SetKeys<IBezQuatKey, QuatKey>(subCtrl, quatKeys, time); + MergeKeys<IBezQuatKey, QuatKey>(subCtrl, quatKeys, time); } break; case XYZ_ROTATION_KEY: if (Control *subCtrl = MakeRotation(c, Class_ID(EULER_CONTROL_CLASS_ID,0), Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))) { - SetKeys<IBezFloatKey, FloatKey>(subCtrl->GetXController(), xKeys, time); - SetKeys<IBezFloatKey, FloatKey>(subCtrl->GetYController(), yKeys, time); - SetKeys<IBezFloatKey, FloatKey>(subCtrl->GetZController(), zKeys, time); + MergeKeys<IBezFloatKey, FloatKey>(subCtrl->GetXController(), xKeys, time); + MergeKeys<IBezFloatKey, FloatKey>(subCtrl->GetYController(), yKeys, time); + MergeKeys<IBezFloatKey, FloatKey>(subCtrl->GetZController(), zKeys, time); } break; @@ -525,11 +407,11 @@ bool AnimationImport::AddValues(Control *c, NiKeyframeDataRef data, float time) if (ni.replaceTCBRotationWithBezier) { // TCB simply is not working for me. Better off with Bezier as a workaround if (Control *subCtrl = MakeRotation(c, Class_ID(HYBRIDINTERP_ROTATION_CLASS_ID,0), Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))) { - SetKeys<IBezQuatKey, QuatKey>(subCtrl, quatKeys, time); + MergeKeys<IBezQuatKey, QuatKey>(subCtrl, quatKeys, time); } } else { if (Control *subCtrl = MakeRotation(c, Class_ID(TCBINTERP_ROTATION_CLASS_ID,0), Class_ID(TCBINTERP_FLOAT_CLASS_ID,0))) { - SetKeys<ITCBRotKey, QuatKey>(subCtrl, quatKeys, time); + MergeKeys<ITCBRotKey, QuatKey>(subCtrl, quatKeys, time); } } break; @@ -539,18 +421,18 @@ bool AnimationImport::AddValues(Control *c, NiKeyframeDataRef data, float time) { case LINEAR_KEY: if (Control *subCtrl = MakeScale(c, Class_ID(LININTERP_SCALE_CLASS_ID,0))) { - SetKeys<ILinScaleKey, FloatKey>(subCtrl, sclKeys, time); + MergeKeys<ILinScaleKey, FloatKey>(subCtrl, sclKeys, time); } break; case QUADRATIC_KEY: case XYZ_ROTATION_KEY: if (Control *subCtrl = MakeScale(c, Class_ID(HYBRIDINTERP_SCALE_CLASS_ID,0))) { - SetKeys<IBezScaleKey, FloatKey>(subCtrl, sclKeys, time); + MergeKeys<IBezScaleKey, FloatKey>(subCtrl, sclKeys, time); } break; case TBC_KEY: if (Control *subCtrl = MakeScale(c, Class_ID(TCBINTERP_SCALE_CLASS_ID,0))) { - SetKeys<ITCBScaleKey, FloatKey>(subCtrl, sclKeys, time); + MergeKeys<ITCBScaleKey, FloatKey>(subCtrl, sclKeys, time); } break; } diff --git a/NifImport/ImportSkeleton.cpp b/NifImport/ImportSkeleton.cpp index dfc2eb0..7fd2520 100644 --- a/NifImport/ImportSkeleton.cpp +++ b/NifImport/ImportSkeleton.cpp @@ -553,6 +553,7 @@ void NifImporter::ImportBones(NiNodeRef node, bool recurse) BuildControllerRefList(node, ctrlCount); string name = node->GetName(); + vector<NiAVObjectRef> children = node->GetChildren(); vector<NiNodeRef> childNodes = DynamicCast<NiNode>(children); @@ -560,10 +561,25 @@ void NifImporter::ImportBones(NiNodeRef node, bool recurse) if (cType == NiAVObject::CT_BOUNDINGBOX && children.empty() && name=="Bounding Box") return; + // Do all node manipulations here NiNodeRef parent = node->GetParent(); + Matrix44 m4 = node->GetWorldTransform(); + float len = node->GetLocalTranslation().Magnitude(); + + // Remove NonAccum nodes and merge into primary bone + if (mergeNonAccum && wildmatch("* NonAccum", name) && parent) + { + string realname = name.substr(0, name.length() - 9); + if (strmatch(realname, parent->GetName())) + { + Matrix44 tm = parent->GetLocalTransform() * node->GetLocalTransform(); + name = realname; + len += tm.GetTranslation().Magnitude(); + parent = parent->GetParent(); + } + } PosRotScale prs = prsDefault; - Matrix44 m4 = node->GetWorldTransform(); Vector3 pos; Matrix33 rot; float scale; m4.Decompose(pos, rot, scale); @@ -584,7 +600,6 @@ void NifImporter::ImportBones(NiNodeRef node, bool recurse) } else if (parent) { - float len = node->GetLocalTranslation().Magnitude(); ppos = pos + Vector3(len/3.0f, 0.0f, 0.0f); } Point3 pp(ppos.x, ppos.y, ppos.z); @@ -617,7 +632,11 @@ void NifImporter::ImportBones(NiNodeRef node, bool recurse) { if (parent) { - if (INode *pn = gi->GetINodeByName(parent->GetName().c_str())) + string parentname = parent->GetName(); + if (mergeNonAccum && wildmatch("* NonAccum", parentname)) { + parentname = parentname.substr(0, parentname.length() - 9); + } + if (INode *pn = gi->GetINodeByName(parentname.c_str())) pn->AttachChild(bone, 1); } } diff --git a/NifImport/KFImporter.cpp b/NifImport/KFImporter.cpp index a27f131..44d73da 100644 --- a/NifImport/KFImporter.cpp +++ b/NifImport/KFImporter.cpp @@ -31,5 +31,10 @@ void KFImporter::ReadBlocks() bool KFImporter::DoImport() { + if (clearAnimation) + { + ClearAnimation(gi->GetRootNode()); + } + return ImportAnimation(); } diff --git a/NifImport/KFMImporter.cpp b/NifImport/KFMImporter.cpp index bc801be..3b63d88 100644 --- a/NifImport/KFMImporter.cpp +++ b/NifImport/KFMImporter.cpp @@ -81,6 +81,12 @@ bool KFMImporter::DoImport() BaseClass::DoImport(); } } + + if (clearAnimation) + { + ClearAnimation(gi->GetRootNode()); + } + return ImportAnimation(); //return BaseClass::DoImport(); } diff --git a/NifImport/MaxNifImport.h b/NifImport/MaxNifImport.h index 30ff9e2..782ff5b 100644 --- a/NifImport/MaxNifImport.h +++ b/NifImport/MaxNifImport.h @@ -26,7 +26,7 @@ #ifdef USE_BIPED # include <cs/BipedApi.h> #endif -#include <scenetraversal.h> +//#include <scenetraversal.h> #include <plugapi.h> #include <triobj.h> #include <bitmap.h> diff --git a/NifImport/MaxNifImport.rc b/NifImport/MaxNifImport.rc index cdfac9b..41eb813 100644 --- a/NifImport/MaxNifImport.rc +++ b/NifImport/MaxNifImport.rc @@ -26,34 +26,35 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // Dialog // -IDD_PANEL DIALOGEX 0, 0, 206, 158 +IDD_PANEL DIALOGEX 0, 0, 206, 171 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_TOOLWINDOW CAPTION "Import Nif" FONT 8, "MS Sans Serif", 0, 0, 0x1 BEGIN - GROUPBOX "Import:",IDC_STATIC,7,6,81,81 + GROUPBOX "Import:",IDC_STATIC,7,6,81,92 CONTROL "&Skeleton",IDC_CHK_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,16,67,10 - CONTROL "Skin Modifier",IDC_CHK_SKIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,27,67,10 - CONTROL "&Vertex Colors",IDC_CHK_VCOLORS,"Button",BS_AUTO3STATE | WS_TABSTOP,14,38,67,10 + CONTROL "S&kin Modifier",IDC_CHK_SKIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,27,67,10 + CONTROL "Vertex &Colors",IDC_CHK_VCOLORS,"Button",BS_AUTO3STATE | WS_TABSTOP,14,38,67,10 CONTROL "Co&llision",IDC_CHK_COLL,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,14,62,67,10 CONTROL "&Animation",IDC_CHK_ANIMATION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,50,67,10 CONTROL "Furniture &Markers",IDC_CHK_FURN,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,14,73,67,10 - GROUPBOX "Behaviors:",IDC_STATIC,94,6,101,81 - CONTROL "Flip UV",IDC_CHK_FLIP_UV,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,16,88,10 + GROUPBOX "Behaviors:",IDC_STATIC,94,6,101,92 + CONTROL "Flip U&V",IDC_CHK_FLIP_UV,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,16,88,10 CONTROL "&Render Textures in View",IDC_CHK_SHOW_TEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,27,88,10 - CONTROL "&Auto Smooth Mesh",IDC_CHK_AUTOSMOOTH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,38,88,11 - CONTROL "Remove Illegal Faces",IDC_CHK_ILLEGAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,50,88,11 - CONTROL "Remove Unused Bones",IDC_CHK_REM_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,62,88,10 - CONTROL "&Use Biped",IDC_CHK_BIPED,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,102,73,87,10 - LTEXT "Skeleton:",IDC_STC_SKELETON,7,107,31,8 - EDITTEXT IDC_ED_SKELETON,7,119,171,12,ES_AUTOHSCROLL - PUSHBUTTON "...",IDC_BTN_BROWSE,180,119,19,13 - LTEXT "Game:",IDC_STATIC,7,93,31,8 - COMBOBOX IDC_CB_GAME,47,91,131,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - DEFPUSHBUTTON "&Import",IDOK,5,137,34,14 - PUSHBUTTON "&Cancel",IDCANCEL,45,137,33,14 - LTEXT "http://niftools.sourceforge.net",IDC_LBL_LINK,93,137,95,14,SS_NOTIFY | SS_CENTERIMAGE + CONTROL "Auto Sm&ooth Mesh",IDC_CHK_AUTOSMOOTH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,38,88,11 + CONTROL "Remove &Illegal Faces",IDC_CHK_ILLEGAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,50,88,11 + CONTROL "Remove &Unused Bones",IDC_CHK_REM_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,62,88,10 + CONTROL "Use &Biped",IDC_CHK_BIPED,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,102,84,87,10 + LTEXT "Skeleton:",IDC_STC_SKELETON,7,121,31,8 + EDITTEXT IDC_ED_SKELETON,7,133,171,12,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_BTN_BROWSE,180,133,19,13 + LTEXT "Game:",IDC_STATIC,7,107,31,8 + COMBOBOX IDC_CB_GAME,47,105,131,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "&Import",IDOK,5,150,34,14 + PUSHBUTTON "&Cancel",IDCANCEL,45,150,33,14 + LTEXT "http://niftools.sourceforge.net",IDC_LBL_LINK,93,150,95,14,SS_NOTIFY | SS_CENTERIMAGE + CONTROL "Clear Animation",IDC_CHK_CLEARANIM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,73,88,10 END @@ -70,7 +71,7 @@ BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 199 TOPMARGIN, 7 - BOTTOMMARGIN, 151 + BOTTOMMARGIN, 164 END END #endif // APSTUDIO_INVOKED diff --git a/NifImport/NIFImport.cpp b/NifImport/NIFImport.cpp index c728fed..872417e 100644 --- a/NifImport/NIFImport.cpp +++ b/NifImport/NIFImport.cpp @@ -144,6 +144,7 @@ void NifImporter::LoadIniSettings() enableCollision = GetIniValue(NifImportSection, "EnableCollision", true); vertexColorMode = GetIniValue<int>(NifImportSection, "VertexColorMode", 1); useCiv4Shader = GetIniValue(NifImportSection, "UseCiv4Shader", true); + mergeNonAccum = GetIniValue(NifImportSection, "MergeNonAccum", true); // Biped importBones = GetIniValue(BipedImportSection, "ImportBones", true); @@ -168,6 +169,7 @@ void NifImporter::LoadIniSettings() enableAnimations = GetIniValue(AnimImportSection, "EnableAnimations", true); requireMultipleKeys = GetIniValue(AnimImportSection, "RequireMultipleKeys", true); applyOverallTransformToSkinAndBones = GetIniValue(AnimImportSection, "ApplyOverallTransformToSkinAndBones", true); + clearAnimation = GetIniValue(AnimImportSection, "ClearAnimation", true); // Collision bhkScaleFactor = GetIniValue<float>(CollisionSection, "bhkScaleFactor", 7.0f); @@ -203,9 +205,10 @@ void NifImporter::SaveIniSettings() SetIniValue(NifImportSection, "RemoveDegenerateFaces", removeDegenerateFaces); SetIniValue(BipedImportSection, "ImportBones", importBones); - SetIniValue(BipedImportSection, "RemoveUnusedImportedBones", removeUnusedImportedBones); + SetIniValue(BipedImportSection, "RemoveUnusedImportedBones", removeUnusedImportedBones); SetIniValue(AnimImportSection, "EnableAnimations", enableAnimations); + SetIniValue(BipedImportSection, "ClearAnimation", clearAnimation); } INode *NifImporter::GetNode(Niflib::NiNodeRef node) @@ -321,6 +324,10 @@ bool NifImporter::DoImport() } } + if (clearAnimation) + { + ClearAnimation(gi->GetRootNode()); + } // Kick of animation import ImportAnimation(); diff --git a/NifImport/NIFImporter.h b/NifImport/NIFImporter.h index 4f61b1d..1d1bb84 100644 --- a/NifImport/NIFImporter.h +++ b/NifImport/NIFImporter.h @@ -33,6 +33,7 @@ public: bool enableCollision; int vertexColorMode; bool useCiv4Shader; + bool mergeNonAccum; // Biped/Bones related settings bool importBones; @@ -63,6 +64,7 @@ public: bool enableAnimations; bool requireMultipleKeys; bool applyOverallTransformToSkinAndBones; + bool clearAnimation; // Collision settings float bhkScaleFactor; @@ -118,6 +120,8 @@ public: // Animation Helpers bool ImportAnimation(); + void ClearAnimation(INode *node); + protected: NifImporter(); diff --git a/NifImport/NifDialog.cpp b/NifImport/NifDialog.cpp index 8294625..2a9629e 100644 --- a/NifImport/NifDialog.cpp +++ b/NifImport/NifDialog.cpp @@ -51,6 +51,8 @@ BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LP CheckDlgButton(hWnd, IDC_CHK_AUTOSMOOTH, imp->enableAutoSmooth); CheckDlgButton(hWnd, IDC_CHK_ILLEGAL, imp->removeIllegalFaces); CheckDlgButton(hWnd, IDC_CHK_REM_BONES, imp->removeUnusedImportedBones); + CheckDlgButton(hWnd, IDC_CHK_CLEARANIM, imp->clearAnimation); + CheckDlgButton(hWnd, IDC_CHK_BIPED, imp->useBiped); string selection = (imp->appSettings) ? imp->appSettings->Name : "User"; @@ -99,6 +101,7 @@ BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LP imp->removeDegenerateFaces = imp->removeIllegalFaces = IsDlgButtonChecked(hWnd, IDC_CHK_ILLEGAL) ? true : false; imp->removeUnusedImportedBones = IsDlgButtonChecked(hWnd, IDC_CHK_REM_BONES) ? true : false; + imp->clearAnimation = IsDlgButtonChecked(hWnd, IDC_CHK_CLEARANIM) ? true : false; imp->useBiped = IsDlgButtonChecked(hWnd, IDC_CHK_BIPED) ? true : false; GetDlgItemText(hWnd, IDC_CB_GAME, tmp, MAX_PATH); -- GitLab