diff --git a/MaxNifPlugins_Readme.txt b/MaxNifPlugins_Readme.txt index cfbd87c8b703a002d1d47f59a2dc6f3692e4e583..b853f3e943de7165a5c7832431114b88e9ef7bbc 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 74969fd1f1d11fa9352dab75f19d5d87182c6f4a..e63efe16c4aba8548ac1021a6d3d207833a07ff3 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 0000000000000000000000000000000000000000..f5fcfdc44bc4edbedac4d12d0d27c70f4f810232 --- /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 0000000000000000000000000000000000000000..507bceaa75947257275448602763c4e62df9592e --- /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 d8d7fc716fcd9875706ccd7b194dbcfe9aee1078..6026cbccd7dadecbce0e0b0f5ea4d707eea28b99 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 f6e0b75f433f7da0f505a7abfbcdcc19574befbc..fc7b014a92900668a70e347a064969b4098606f2 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 7d0d91397451c1b3333ce7aa42f0ed0f2a4d1040..adc19d0fefb1ae21073a949c58c53a0455c686bf 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 0000000000000000000000000000000000000000..f550c0ecb59afbe979054b392ece73290fd66f44 --- /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 3d0f8fad0569996db48f4cec1a1b8d941defcd5f..0e7e3aa41240323708f514992bc56e1e06930ca8 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 e73a5a4a163ca4774b1babc677131467ef4e2f54..36a4bfd64fc522188aa58cf8bab3b8a3559a96e8 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 0000000000000000000000000000000000000000..52c73e237afad85223dfb145b36da6e8e0174db3 --- /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 26051600b07b974c6498c8782ea47f01f4ff7e15..17d12bdddf40f7653e4138257ddb58874b6fba54 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 feda5c82534e8cca2aad0cf732653b53a1de33e5..e1997b4f727ae3659f13f70fb9c4d97a32ef3d48 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 9307e84af31e007e901db9da469638c18d7e2250..f4c21f9a536cf683d6564d10a63f6681fde7a9b4 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 dfc2eb05d1b15c09de9ba895eba9f855fe68f60b..7fd252017a592d69086c18459edd286e5fd037b7 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 a27f1317ddbaaf47fb502df65aa37d8fa3668275..44d73da9ae922e226848f2ef5abde8ba0c377383 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 bc801be00a7803cd50c377229c810fc03fb712b0..3b63d88e914430bb29f6d2377ef2141bfa5cd2ef 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 30ff9e2ac3fad10698610d7bcd82288b58335930..782ff5be4cefc0d922ce6494e5c947ccbaf1ee38 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 cdfac9b42f5367162db4fb0d3d31d83d88d57bbe..41eb813649dece069041b4f3ad72728ac68d579b 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 c728fed2ccba49f28f21c5dc739b2101a96a0a2a..872417ed3bf0d38ce7f518fd87b4d462c979f901 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 4f61b1d82f2bc0349ad6b62726e813cd483b4488..1d1bb84a626973a6cfb8e5bf60c71a79360d5c61 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 8294625a2e5578e8ab2ce43dd57d907bd55e5d19..2a9629edb88f6d0dc6be471e00662f70227af8d4 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);