From 6eb5601dd4abd85199a467500a36a9d9c47f06a2 Mon Sep 17 00:00:00 2001 From: Tazpn <tazpn@users.sourceforge.net> Date: Mon, 11 Sep 2006 02:56:26 +0000 Subject: [PATCH] 0.2.4 ----- o Exporter - Add animation export. o Importer - Add option to ignore UPB buffers. * Useful in preventing LOD Bone warnings from the Civ4 Exporter - Fixed problem with Animation Note Tracks not being cleared - Fixed issue with BSpline animation when too much data was present * Specifically the Civ4 Leaderheads now import animation very well - Import Animation Priority into user prop buffer o NifProps Utility - Added Animation Priority - Removed unused Globals --- MaxNifPlugins_Readme.txt | 19 +- NifCommon/AnimKey.cpp | 84 +++++- NifCommon/AnimKey.h | 25 +- NifCommon/NifPlugins.h | 4 + NifCommon/niutils.h | 8 + NifExport/Animation.cpp | 509 +++++++++++++++++++++++----------- NifExport/Config.cpp | 28 ++ NifExport/DllEntry.cpp | 6 +- NifExport/Exporter.cpp | 2 + NifExport/Exporter.h | 9 +- NifExport/KfExport.cpp | 229 ++++++++++++++- NifExport/MtlTex.cpp | 16 +- NifExport/NifExport.cpp | 111 ++++---- NifExport/NifExport.rc | 48 +++- NifExport/resource.h | 10 +- NifFurniture/NifFurniture.rc | 8 +- NifImport/ImportAnimation.cpp | 58 +++- NifImport/ImportSkeleton.cpp | 3 + NifImport/MaxNifImport.cpp | 20 +- NifImport/MaxNifImport.rc | 33 +-- NifImport/NIFImport.cpp | 2 + NifImport/NIFImporter.h | 1 + NifImport/NifDialog.cpp | 3 + NifImport/resource.h | 1 + NifProps/NifProps.cpp | 49 +++- NifProps/NifProps.rc | 40 ++- NifProps/resource.h | 29 +- 27 files changed, 1041 insertions(+), 314 deletions(-) diff --git a/MaxNifPlugins_Readme.txt b/MaxNifPlugins_Readme.txt index 810cd27..355c3fd 100644 --- a/MaxNifPlugins_Readme.txt +++ b/MaxNifPlugins_Readme.txt @@ -1,4 +1,4 @@ - MaxPlugins 0.2.3 + MaxPlugins 0.2.4 ================ @@ -27,6 +27,23 @@ Change log ---------- + 0.2.4 + ----- + o Exporter + - Add animation export. + + o Importer + - Add option to ignore UPB buffers. + * Useful in preventing LOD Bone warnings from the Civ4 Exporter + - Fixed problem with Animation Note Tracks not being cleared + - Fixed issue with BSpline animation when too much data was present + * Specifically the Civ4 Leaderheads now import animation very well + - Import Animation Priority into user prop buffer + + o NifProps Utility + - Added Animation Priority + - Removed unused Globals + 0.2.3 ----- o Exporter diff --git a/NifCommon/AnimKey.cpp b/NifCommon/AnimKey.cpp index f5fcfdc..8caa4ac 100644 --- a/NifCommon/AnimKey.cpp +++ b/NifCommon/AnimKey.cpp @@ -131,6 +131,30 @@ FloatKey MapKey<FloatKey, ILinFloatKey>(ILinFloatKey& key, float time) return InitFromLinKey(rKey, key, time); } +template<> +Vector3Key MapKey<Vector3Key, ILinPoint3Key>(ILinPoint3Key& key, float time) +{ + Vector3Key rKey; + rKey.data = TOVECTOR3(key.val); + return InitFromLinKey(rKey, key, time); +} + +template<> +QuatKey MapKey<QuatKey, ILinRotKey>(ILinRotKey& key, float time) +{ + QuatKey rKey; + rKey.data = TOQUAT(key.val, true); + return InitFromLinKey(rKey, key, time); +} + +template<> +FloatKey MapKey<FloatKey, ILinScaleKey>(ILinScaleKey& key, float time) +{ + FloatKey rKey; + rKey.data = (key.val[0] + key.val[1] + key.val[2]) / 3.0f; + return InitFromLinKey(rKey, key, time); +} + // Specialized Bezier/Hybrid mappings @@ -154,7 +178,6 @@ IBezPoint3Key MapKey<IBezPoint3Key, Vector3Key>(Vector3Key& key, float time) return InitBezKey(rKey, key, time); } - template<> IBezQuatKey MapKey<IBezQuatKey, QuatKey>(QuatKey& key, float time) { @@ -172,7 +195,7 @@ IBezScaleKey MapKey<IBezScaleKey, FloatKey>(FloatKey& key, float time) return InitBezKey(rKey, key, time); } -// Specialized Linear Mappings +// Specialized Bezier/Hybrid Mappings template<> FloatKey MapKey<FloatKey, IBezFloatKey>(IBezFloatKey& key, float time) @@ -184,6 +207,37 @@ FloatKey MapKey<FloatKey, IBezFloatKey>(IBezFloatKey& key, float time) return InitFromBezKey(rKey, key, time); } +template<> +Vector3Key MapKey<Vector3Key, IBezPoint3Key>(IBezPoint3Key& key, float time) +{ + Vector3Key rKey; + rKey.data = TOVECTOR3(key.val); + rKey.forward_tangent = TOVECTOR3(key.intan); + rKey.backward_tangent = TOVECTOR3(key.outtan); + return InitFromBezKey(rKey, key, time); +} + +template<> +QuatKey MapKey<QuatKey, IBezQuatKey>(IBezQuatKey& key, float time) +{ + QuatKey rKey; + rKey.data = TOQUAT(key.val, true); + //rKey.forward_tangent = TOQUAT(key.intan, true); + //rKey.backward_tangent = TOQUAT(key.outtan, true); + return InitFromBezKey(rKey, key, time); +} + +template<> +FloatKey MapKey<FloatKey, IBezScaleKey>(IBezScaleKey& key, float time) +{ + FloatKey rKey; + rKey.data = Average(key.val.s); + rKey.forward_tangent = Average(key.intan); + rKey.backward_tangent = Average(key.outtan); + return InitFromBezKey(rKey, key, time); +} + + // Specialized TCB Mappings template<> @@ -229,6 +283,32 @@ FloatKey MapKey<FloatKey, ITCBFloatKey>(ITCBFloatKey& key, float time) return InitFromTCBKey(rKey, key, time); } +template<> +Vector3Key MapKey<Vector3Key, ITCBPoint3Key>(ITCBPoint3Key& key, float time) +{ + Vector3Key rKey; + rKey.data = TOVECTOR3(key.val); + return InitFromTCBKey(rKey, key, time); +} + +template<> +QuatKey MapKey<QuatKey, ITCBRotKey>(ITCBRotKey& key, float time) +{ + QuatKey rKey; + rKey.data = TOQUAT(key.val, true); + return InitFromTCBKey(rKey, key, time); +} + +template<> +FloatKey MapKey<FloatKey, ITCBScaleKey>(ITCBScaleKey& key, float time) +{ + FloatKey rKey; + rKey.data = Average(key.val.s); + return InitFromTCBKey(rKey, key, time); +} + +// Merge Keys + template<> void MergeKey<ILinRotKey>(ILinRotKey& lhs, ILinRotKey& rhs) { lhs.val *= rhs.val; } diff --git a/NifCommon/AnimKey.h b/NifCommon/AnimKey.h index 1cb3462..7766ab9 100644 --- a/NifCommon/AnimKey.h +++ b/NifCommon/AnimKey.h @@ -120,17 +120,38 @@ inline void SetKeys(Control *subCtrl, vector<U>& keys, float time) } template<typename T, typename U> -inline void GetKeys(Control *subCtrl, vector<T>& keys, float time) +inline int GetKeys(Control *subCtrl, vector<T>& keys, float time) { if (IKeyControl *ikeys = GetKeyControlInterface(subCtrl)){ - int n = ikeys->GetKeySize(); + int n = ikeys->GetNumKeys(); keys.reserve(n); for (int i=0; i<n; ++i){ AnyKey buf; U *key = reinterpret_cast<U*>((IKey*)buf); ikeys->GetKey(i, key); keys.push_back( MapKey<T>(*key, time) ); } + return keys.size(); } + return 0; +} + +template<typename T, typename U> +inline int GetKeys(Control *subCtrl, vector<T>& keys, Interval range) +{ + if (IKeyControl *ikeys = GetKeyControlInterface(subCtrl)){ + float timeOffset = -FrameToTime(range.Start()); + int n = ikeys->GetNumKeys(); + keys.reserve(n); + for (int i=0; i<n; ++i){ + AnyKey buf; U *key = reinterpret_cast<U*>((IKey*)buf); + ikeys->GetKey(i, key); + if (range.InInterval(key->time)) { + keys.push_back( MapKey<T>(*key, timeOffset) ); + } + } + return keys.size(); + } + return 0; } template<typename T, typename U> diff --git a/NifCommon/NifPlugins.h b/NifCommon/NifPlugins.h index ca1239c..0090584 100644 --- a/NifCommon/NifPlugins.h +++ b/NifCommon/NifPlugins.h @@ -39,6 +39,8 @@ using Niflib::Vector3; #define NP_FRN_POS _T("np_frn_pos") +#define NP_ANM_PRI _T("np_anm_pri") + /* default values */ #define NP_DEFAULT_HVK_MATERIAL 9 #define NP_DEFAULT_HVK_LAYER 1 @@ -50,6 +52,8 @@ using Niflib::Vector3; #define NP_DEFAULT_HVK_MOTION_SYSTEM 7 #define NP_DEFAULT_HVK_QUALITY_TYPE 1 +#define NP_DEFAULT_ANM_PRI 0.0f + #define NP_DEFAULT_FRN_MARKER_TYPE NP_FRN_SLEEP_LEFT /* other constants */ diff --git a/NifCommon/niutils.h b/NifCommon/niutils.h index 2af7484..2942059 100644 --- a/NifCommon/niutils.h +++ b/NifCommon/niutils.h @@ -351,6 +351,14 @@ static inline Point3 GetScale(const Matrix3& mtx){ return Point3( fabs(mtx.GetRow(0)[0]), fabs(mtx.GetRow(1)[1]), fabs(mtx.GetRow(2)[2]) ); } +static inline float Average(const Point3& val) { + return (val[0] + val[1] + val[2]) / 3.0f; +} + +static inline float Average(const Niflib::Vector3& val) { + return (val.x + val.y + val.z) / 3.0f; +} + template <typename U, typename T> inline Niflib::Ref<U> SelectFirstObjectOfType( vector<Niflib::Ref<T> > const & objs ) { for (vector<Niflib::Ref<T> >::const_iterator itr = objs.begin(), end = objs.end(); itr != end; ++itr) { diff --git a/NifExport/Animation.cpp b/NifExport/Animation.cpp index 8b79945..70eaba4 100644 --- a/NifExport/Animation.cpp +++ b/NifExport/Animation.cpp @@ -11,6 +11,9 @@ HISTORY: *> Copyright (c) 2006, All Rights Reserved. **********************************************************************/ #include "pch.h" +#include <IFrameTagManager.h> +#include <notetrck.h> + #include "NifExport.h" #include "AnimKey.h" @@ -39,33 +42,135 @@ struct AnimationExport { AnimationExport(Exporter& parent) : ne(parent) {} - bool doExport(); - bool exportController(INode *node, NiControllerSequenceRef seq); + INode * findTrackedNode(INode *root); + + bool doExport(NiControllerSequenceRef seq); + bool exportController(INode *node); Control *GetTMController(INode* node); Exporter ≠ + Interval range; + NiControllerSequenceRef seq; }; -bool Exporter::doAnimExport() +Exporter::Result Exporter::doAnimExport(NiControllerSequenceRef root) { AnimationExport animExporter(*this); - return animExporter.doExport(); - return true; + return animExporter.doExport(root) ? Exporter::Ok : Exporter::Abort ; } //NiControllerSequenceRef makeSequence(TimeValue start, TimeValue end); -bool AnimationExport::doExport() +INode * AnimationExport::findTrackedNode(INode *node) { - INode *root = ne.mI->GetRootNode(); - NiControllerSequenceRef seq = new NiControllerSequence(); - seq->SetStartTime(0.0f); - seq->SetStopTime(0.0f); + // locate START in note track before assuming all is well + if (node->HasNoteTracks()) { + for (int i=0, n=node->NumNoteTracks(); i<n; ++i) { + if ( NoteTrack *nt = node->GetNoteTrack(i) ) { + if ( nt->ClassID() == Class_ID(NOTETRACK_CLASS_ID,0) ) { + DefNoteTrack *defNT = (DefNoteTrack *)nt; + if ( defNT->NumKeys() > 0 ) { + for (int j=0, m=defNT->keys.Count(); j<m; ++j) { + NoteKey* key = defNT->keys[j]; + if (wildmatch("start*", key->note)) { + return node; + } + } + } + } + } + } + } + for (int i=0; i < node->NumberOfChildren(); ++i ){ + if ( INode *root = findTrackedNode( node->GetChildNode(i) ) ) { + return root; + } + } + return NULL; +} + +bool AnimationExport::doExport(NiControllerSequenceRef seq) +{ + INode *node = findTrackedNode(ne.mI->GetRootNode()); + if (node == NULL) + throw runtime_error("No Actor Roots have been selected in the Animation Manager. Cannot continue."); + + this->seq = seq; + + vector<StringKey> textKeys; + + this->range.SetInstant(0); + + seq->SetStartTime(FloatINF); + seq->SetStopTime(FloatINF); seq->SetFrequency(1.0f); seq->SetCycleType( CYCLE_CLAMP ); - seq->SetTargetName("Bip01"); - - return true; + seq->SetTargetName( node->GetName() ); + + NiTextKeyExtraDataRef textKeyData = new NiTextKeyExtraData(); + seq->SetTextKey(textKeyData); + + // Populate Text keys and Sequence information from note tracks + for (int i=0, n=node->NumNoteTracks(); i<n; ++i) { + if ( NoteTrack *nt = node->GetNoteTrack(i) ) { + if ( nt->ClassID() == Class_ID(NOTETRACK_CLASS_ID,0) ) { + DefNoteTrack *defNT = (DefNoteTrack *)nt; + if ( defNT->NumKeys() > 0 ) { + bool stop = false; + for (int j=0, m=defNT->keys.Count(); j<m && !stop; ++j) { + NoteKey* key = defNT->keys[j]; + + if (wildmatch("start*", key->note)) { + stringlist args = TokenizeCommandLine(key->note, true); + if (args.empty()) continue; + + seq->SetStartTime(0.0f); + range.SetStart( key->time ); + for (stringlist::iterator itr = args.begin(); itr != args.end(); ++itr) { + if (strmatch("-name", *itr)) { + if (++itr == args.end()) break; + seq->SetName(*itr); + } else if (strmatch("-loop", *itr)) { + seq->SetCycleType(CYCLE_LOOP); + } + } + } else if ( wildmatch("end*", key->note) ) { + range.SetEnd( key->time ); + seq->SetStopTime( FrameToTime( range.Duration()-1 ) ); + stop = true; + } + StringKey strkey; + strkey.time = FrameToTime( Interval(range.Start(), key->time).Duration()-1 ); + strkey.data = key->note; + textKeys.push_back(strkey); + } + } + } + } + } + textKeyData->SetKeys(textKeys); + + // Now let the fun begin. + + bool ok = exportController(node); + + // Handle NonAccum + if (ok) + { + NiNodeRef ninode = new NiNode(); + ninode->SetName(FormatString("%s NonAccum", node->GetName())); + + NiTransformControllerRef control = new NiTransformController(); + NiTransformInterpolatorRef interp = new NiTransformInterpolator(); + ninode->AddController(StaticCast<NiTimeController>(control)); + control->SetInterpolator(StaticCast<NiInterpolator>(interp)); + + interp->SetTranslation( Vector3(0.0f, 0.0f, 0.0f) ); + interp->SetScale( 1.0f ); + interp->SetRotation( Quaternion(1.0f, 0.0f, 0.0f, 0.0f) ); + seq->AddInterpolator(StaticCast<NiSingleInterpolatorController>(control), Exporter::mDefaultPriority); + } + return ok; } @@ -87,175 +192,255 @@ Control *AnimationExport::GetTMController(INode *n) } -bool AnimationExport::exportController(INode *node, NiControllerSequenceRef seq) +bool AnimationExport::exportController(INode *node) { bool ok = true; - int nKeys = node->NumKeys(); - if (nKeys >= 0) + bool skip = false; + + // Primary recursive decent routine + + ObjectState os = node->EvalWorldState(range.Start()); + + if (!Exporter::mExportCameras && os.obj && os.obj->SuperClassID()==CAMERA_CLASS_ID) + { + skip = true; + } + else if (!Exporter::mExportLights && os.obj && os.obj->SuperClassID()==LIGHT_CLASS_ID) + { + skip = true; + } + + if (!skip && Exporter::mExportTransforms) { - float timeOffset = 0.0f; - NiKeyframeDataRef data = new NiKeyframeData(); + float timeOffset = -FrameToTime(range.Start()); if (Control *tmCont = GetTMController(node)) { - if (Control *c = tmCont->GetPositionController()) + Interval validity; validity.SetEmpty(); + Matrix3 tm = node->GetObjTMAfterWSM(range.Start()); + Matrix3 pm = Inverse(node->GetParentTM(range.Start())); + tm *= pm; + + NiNodeRef ninode = new NiNode(); + ninode->SetName(node->GetName()); + + //Vector3 trans(FloatNegINF, FloatNegINF, FloatNegINF); + //Quaternion rot(FloatNegINF, FloatNegINF, FloatNegINF, FloatNegINF); + Vector3 trans = TOVECTOR3(tm.GetTrans()); + Quaternion rot = TOQUAT( Quat(tm), true ); + float scale = FloatNegINF; + bool keepData = false; + + NiTransformControllerRef control = new NiTransformController(); + NiTransformInterpolatorRef interp = new NiTransformInterpolator(); + ninode->AddController(StaticCast<NiTimeController>(control)); + control->SetInterpolator(StaticCast<NiInterpolator>(interp)); + + //if (validity.InInterval(range)) + //{ + // // Valid for entire interval. i.e. no changes + // interp->SetTranslation( TOVECTOR3(tm.GetTrans()) ); + // interp->SetScale( Average(GetScale(tm)) ); + // interp->SetRotation( TOQUAT( Quat(tm) ) ); + // seq->AddInterpolator(StaticCast<NiSingleInterpolatorController>(control)); + //} + //else { - // 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); + NiTransformDataRef data = new NiTransformData(); + + if (Control *c = tmCont->GetPositionController()) + { + int nkeys = 0; + // 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; + nkeys += GetKeys<FloatKey, ILinFloatKey>(x, xkeys, range); + } else if (x->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + kType = QUADRATIC_KEY; + nkeys += GetKeys<FloatKey, IBezFloatKey>(x, xkeys, range); + } else if (x->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + kType = TBC_KEY; + nkeys += GetKeys<FloatKey, ITCBFloatKey>(x, xkeys, range); + } else { + kType = QUADRATIC_KEY; + nkeys += GetKeys<FloatKey, IBezFloatKey>(x, xkeys, range); + } } - } - 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); + if (Control *y = c->GetYController()){ + if (y->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + nkeys += GetKeys<FloatKey, ILinFloatKey>(y, ykeys, range); + } else if (y->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + nkeys += GetKeys<FloatKey, IBezFloatKey>(y, ykeys, range); + } else if (y->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + nkeys += GetKeys<FloatKey, ITCBFloatKey>(y, ykeys, range); + } else { + nkeys += GetKeys<FloatKey, IBezFloatKey>(y, ykeys, range); + } + } + if (Control *z = c->GetZController()){ + if (z->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + nkeys += GetKeys<FloatKey, ILinFloatKey>(z, zkeys, range); + } else if (z->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + nkeys += GetKeys<FloatKey, IBezFloatKey>(z, zkeys, range); + } else if (z->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + nkeys += GetKeys<FloatKey, ITCBFloatKey>(z, zkeys, range); + } else { + nkeys += GetKeys<FloatKey, IBezFloatKey>(z, zkeys, range); + } + } + vector<Vector3Key> keys; + JoinKeys(keys, xkeys, ykeys, zkeys); + data->SetTranslateType(kType); + data->SetTranslateKeys(keys); + } else { + vector<Vector3Key> keys; + if (c->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + data->SetTranslateType(LINEAR_KEY); + nkeys += GetKeys<Vector3Key, ILinPoint3Key>(c, keys, range); + } else if (c->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + data->SetTranslateType(QUADRATIC_KEY); + nkeys += GetKeys<Vector3Key, IBezPoint3Key>(c, keys, range); + } else if (c->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + data->SetTranslateType(TBC_KEY); + nkeys += GetKeys<Vector3Key, ITCBPoint3Key>(c, keys, range); } else { - GetKeys<FloatKey, IBezFloatKey>(y, ykeys, timeOffset); + data->SetTranslateType(QUADRATIC_KEY); + nkeys += GetKeys<Vector3Key, IBezPoint3Key>(c, keys, range); } + data->SetTranslateKeys(keys); } - 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); + if (nkeys != 0) { // if no changes set the base transform + keepData = true; + //trans = TOVECTOR3(tm.GetTrans()); + } + } + + // Rotations + if (Control *c = tmCont->GetRotationController()) + { + int nkeys = 0; + if (c->ClassID() == Class_ID(LININTERP_ROTATION_CLASS_ID,0)) { + vector<QuatKey> keys; + data->SetRotateType(LINEAR_KEY); + nkeys += GetKeys<QuatKey, ILinRotKey>(c, keys, range); + data->SetQuatRotateKeys(keys); + } else if (c->ClassID() == Class_ID(HYBRIDINTERP_ROTATION_CLASS_ID,0)) { + vector<QuatKey> keys; + data->SetRotateType(QUADRATIC_KEY); + nkeys += GetKeys<QuatKey, IBezQuatKey>(c, keys, range); + data->SetQuatRotateKeys(keys); + } else if (c->ClassID() == Class_ID(EULER_CONTROL_CLASS_ID,0)) { + if (Control *x = c->GetXController()){ + vector<FloatKey> keys; + if (x->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + nkeys += GetKeys<FloatKey, ILinFloatKey>(x, keys, range); + data->SetXRotateType(LINEAR_KEY); + } else if (x->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + nkeys += GetKeys<FloatKey, IBezFloatKey>(x, keys, range); + data->SetXRotateType(QUADRATIC_KEY); + } else if (x->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + nkeys += GetKeys<FloatKey, ITCBFloatKey>(x, keys, range); + data->SetXRotateType(TBC_KEY); + } else { + nkeys += GetKeys<FloatKey, IBezFloatKey>(x, keys, range); + data->SetXRotateType(QUADRATIC_KEY); + } + data->SetXRotateKeys(keys); + } + if (Control *y = c->GetXController()) { + vector<FloatKey> keys; + if (y->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + nkeys += GetKeys<FloatKey, ILinFloatKey>(y, keys, range); + data->SetYRotateType(LINEAR_KEY); + } else if (y->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + nkeys += GetKeys<FloatKey, IBezFloatKey>(y, keys, range); + data->SetYRotateType(QUADRATIC_KEY); + } else if (y->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + nkeys += GetKeys<FloatKey, ITCBFloatKey>(y, keys, range); + data->SetYRotateType(TBC_KEY); + } else { + nkeys += GetKeys<FloatKey, IBezFloatKey>(y, keys, range); + data->SetYRotateType(QUADRATIC_KEY); + } + data->SetYRotateKeys(keys); + } + if (Control *z = c->GetZController()) { + vector<FloatKey> keys; + if (z->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + nkeys += GetKeys<FloatKey, ILinFloatKey>(z, keys, range); + data->SetZRotateType(LINEAR_KEY); + } else if (z->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + nkeys += GetKeys<FloatKey, IBezFloatKey>(z, keys, range); + data->SetZRotateType(QUADRATIC_KEY); + } else if (z->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + nkeys += GetKeys<FloatKey, ITCBFloatKey>(z, keys, range); + data->SetZRotateType(TBC_KEY); + } else { + nkeys += GetKeys<FloatKey, IBezFloatKey>(z, keys, range); + data->SetZRotateType(QUADRATIC_KEY); + } + data->SetZRotateKeys(keys); } + } else if (c->ClassID() == Class_ID(TCBINTERP_ROTATION_CLASS_ID,0)) { + vector<QuatKey> keys; + data->SetRotateType(TBC_KEY); + nkeys += GetKeys<QuatKey, ITCBRotKey>(c, keys, range); + data->SetQuatRotateKeys(keys); + } + if (nkeys != 0) { // if no changes set the base transform + keepData = true; + //rot = TOQUAT( Quat(tm) ); } - 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); - // } - // } - //} + // Scale + if (Control *c = tmCont->GetScaleController()) + { + int nkeys = 0; + if (c->ClassID() == Class_ID(LININTERP_SCALE_CLASS_ID,0)) { + vector<FloatKey> keys; + data->SetScaleType(LINEAR_KEY); + nkeys += GetKeys<FloatKey, ILinFloatKey>(c, keys, range); + data->SetScaleKeys(keys); + } else if (c->ClassID() == Class_ID(HYBRIDINTERP_SCALE_CLASS_ID,0)) { + vector<FloatKey> keys; + data->SetScaleType(QUADRATIC_KEY); + nkeys += GetKeys<FloatKey, IBezFloatKey>(c, keys, range); + data->SetScaleKeys(keys); + } else if (c->ClassID() == Class_ID(TCBINTERP_SCALE_CLASS_ID,0)) { + vector<FloatKey> keys; + data->SetScaleType(TBC_KEY); + nkeys += GetKeys<FloatKey, ITCBFloatKey>(c, keys, range); + data->SetScaleKeys(keys); + } + if (nkeys != 0) { // if no changes set the base transform + keepData = true; + //scale = Average(GetScale(tm)); + } + } + // only add transform data object if data actually is present + if (keepData) { + interp->SetData(data); + } + interp->SetTranslation(trans); + interp->SetScale(scale); + interp->SetRotation(rot); + // Get Priority from node + float priority; + npGetProp(node, NP_ANM_PRI, priority, Exporter::mDefaultPriority); + seq->AddInterpolator(StaticCast<NiSingleInterpolatorController>(control), priority); + } } - //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); + ok |= exportController(child); } return ok; } \ No newline at end of file diff --git a/NifExport/Config.cpp b/NifExport/Config.cpp index ea3262b..1ff4721 100755 --- a/NifExport/Config.cpp +++ b/NifExport/Config.cpp @@ -5,6 +5,7 @@ #define REGPATH "Software\\NifTools\\MaxPlugins" static LPCTSTR NifExportSection = TEXT("MaxNifExport"); +static LPCTSTR KfExportSection = TEXT("KfExport"); void regSet(HKEY hKey, const char *value, float f); void regSet(HKEY hKey, const char *value, bool b); @@ -127,6 +128,33 @@ void Exporter::readConfig(Interface *i) } +void Exporter::readKfConfig(Interface *i) +{ + TCHAR iniName[MAX_PATH]; + LPCTSTR pluginDir = i->GetDir(APP_PLUGCFG_DIR); + PathCombine(iniName, pluginDir, "MaxNifTools.ini"); + + mExportHidden = GetIniValue(KfExportSection, "IncludeHidden", false, iniName); + mExportLights = GetIniValue(KfExportSection, "Lights", false, iniName); + mExportCameras = GetIniValue(KfExportSection, "Cameras", false, iniName); + mExportTransforms = GetIniValue(KfExportSection, "Transforms", true, iniName); + mDefaultPriority = GetIniValue<float>(KfExportSection, "Priority", 0.0f, iniName); +} + +void Exporter::writeKfConfig(Interface *i) +{ + TCHAR iniName[MAX_PATH]; + LPCTSTR pluginDir = i->GetDir(APP_PLUGCFG_DIR); + PathCombine(iniName, pluginDir, "MaxNifTools.ini"); + + SetIniValue(KfExportSection, "IncludeHidden", mExportHidden, iniName); + SetIniValue(KfExportSection, "Lights", mExportLights, iniName); + SetIniValue(KfExportSection, "Cameras", mExportCameras, iniName); + SetIniValue(KfExportSection, "Transforms", mExportTransforms, iniName); + SetIniValue<float>(KfExportSection, "Priority", mDefaultPriority, iniName); +} + + void regSet(HKEY hKey, const char *value, float f) { DWORD dw = *((DWORD*)&f); diff --git a/NifExport/DllEntry.cpp b/NifExport/DllEntry.cpp index 0e7e3aa..8907fa3 100755 --- a/NifExport/DllEntry.cpp +++ b/NifExport/DllEntry.cpp @@ -60,11 +60,7 @@ __declspec( dllexport ) const TCHAR* LibDescription() //TODO: Must change this number when adding a new class __declspec( dllexport ) int LibNumberClasses() { -#if _DEBUG - return 2; -#else - return 1; -#endif + return 2; } // This function returns the number of plug-in classes this DLL diff --git a/NifExport/Exporter.cpp b/NifExport/Exporter.cpp index a13f1df..8bdf74b 100755 --- a/NifExport/Exporter.cpp +++ b/NifExport/Exporter.cpp @@ -29,6 +29,8 @@ int Exporter::mNifUserVersion = 0; bool Exporter::mSkeletonOnly=false; bool Exporter::mExportCameras=false; bool Exporter::mGenerateBoneCollision=false; +bool Exporter::mExportTransforms=true; +float Exporter::mDefaultPriority=0.0f; Exporter::Exporter(Interface *i, AppSettings *appSettings) : mI(i), mAppSettings(appSettings) diff --git a/NifExport/Exporter.h b/NifExport/Exporter.h index 44dd7b7..8d5b2f0 100755 --- a/NifExport/Exporter.h +++ b/NifExport/Exporter.h @@ -57,6 +57,9 @@ public: static bool mExportCameras; static bool mGenerateBoneCollision; + static bool mExportTransforms; + static float mDefaultPriority; + Exporter(Interface *i, AppSettings *appSettings); Result doExport(NiNodeRef &root, INode *node); @@ -70,11 +73,15 @@ public: static void writeConfig(INode *node); // writes config to registry static void writeConfig(Interface *i); + // writes config to registry + static void writeKfConfig(Interface *i); // reads config from root node static void readConfig(INode *node); // reads config from registry static void readConfig(Interface *i); + // reads config from registry + static void readKfConfig(Interface *i); public: typedef vector<unsigned short> TriStrip; @@ -176,7 +183,7 @@ public: bool exportSkin(); /* animation export */ - bool doAnimExport(); + Result doAnimExport(Ref<NiControllerSequence> root); /* misc export */ bool exportUPB(NiNodeRef &root, INode *node); diff --git a/NifExport/KfExport.cpp b/NifExport/KfExport.cpp index c865cc3..4102b0c 100644 --- a/NifExport/KfExport.cpp +++ b/NifExport/KfExport.cpp @@ -2,12 +2,12 @@ #include "AppSettings.h" #include "niutils.h" #include <io.h> - +#include "obj/NiControllerSequence.h" using namespace Niflib; #define KFEXPORT_CLASS_ID Class_ID(0xa57ff0a4, 0xa0374ffc) -static LPCTSTR KfExportSection = TEXT("MaxKfExport"); +static LPCTSTR KfExportSection = TEXT("KfExport"); class KfExport : public SceneExport { @@ -43,12 +43,12 @@ 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); } + const TCHAR *ClassName() { return GetString(IDS_KF_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) + const TCHAR *InternalName() { return _T("_KfExport"); } // returns fixed parsable name (scripter-visible name) HINSTANCE HInstance() { return hInstance; } // returns owning module handle @@ -58,6 +58,128 @@ static KfExportClassDesc KfExportDesc; ClassDesc2* GetKfExportDesc() { return &KfExportDesc; } +static BOOL CALLBACK KfExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { + static KfExport *imp = NULL; + + switch (message) + { + case WM_INITDIALOG: + { + // Append file version to dialog + TSTR fileVersion = GetFileVersion(NULL); + if (!fileVersion.isNull()) { + char buffer[256]; + GetWindowText(hWnd, buffer, _countof(buffer)); + _tcscat(buffer, TEXT(" ")); + _tcscat(buffer, fileVersion); + SetWindowText(hWnd, buffer); + } + + imp = (KfExport *)lParam; + CenterWindow(hWnd,GetParent(hWnd)); + + CheckDlgButton(hWnd, IDC_CHK_HIDDEN, Exporter::mExportHidden); + CheckDlgButton(hWnd, IDC_CHK_LIGHTS, Exporter::mExportLights); + CheckDlgButton(hWnd, IDC_CHK_CAMERA, Exporter::mExportCameras); + CheckDlgButton(hWnd, IDC_CHK_TRANSFORMS, Exporter::mExportTransforms); + SetDlgItemText(hWnd, IDC_ED_PRIORITY, FormatText("%.4f", Exporter::mDefaultPriority)); + + string selection = Exporter::mGameName; + string version = Exporter::mNifVersion; + string userVer = FormatString("%d", Exporter::mNifUserVersion); + for (AppSettingsMap::iterator itr = TheAppSettings.begin(), end = TheAppSettings.end(); itr != end; ++itr) + SendDlgItemMessage(hWnd, IDC_CB_GAME, CB_ADDSTRING, 0, LPARAM(itr->Name.c_str())); + SendDlgItemMessage(hWnd, IDC_CB_GAME, CB_SELECTSTRING, WPARAM(-1), LPARAM(selection.c_str())); + SendDlgItemMessage(hWnd, IDC_CB_VERSION, WM_SETTEXT, 0, LPARAM(version.c_str())); + SendDlgItemMessage(hWnd, IDC_CB_USER_VERSION, WM_SETTEXT, 0, LPARAM(userVer.c_str())); + + imp->mDlgResult = IDCANCEL; + } + return TRUE; + + case WM_CLOSE: + EndDialog(hWnd, imp->mDlgResult); + return TRUE; + + case WM_COMMAND: + if (HIWORD(wParam) == BN_CLICKED) + { + char tmp[MAX_PATH], *end; + bool close = false; + switch (LOWORD(wParam)) + { + case IDOK: + // Validity Check + GetDlgItemText(hWnd, IDC_CB_VERSION, tmp, MAX_PATH); + if (tmp[0] != 0) + { + int nifVersion = GetVersion(tmp); + if (!IsVersionSupported(nifVersion)) + { + MessageBox(hWnd, FormatString("Version '%s' is not a supported version.", tmp).c_str(), "NifExport", MB_OK|MB_ICONSTOP); + return FALSE; + } + } + + Exporter::mExportHidden = IsDlgButtonChecked(hWnd, IDC_CHK_HIDDEN); + Exporter::mExportLights = IsDlgButtonChecked(hWnd, IDC_CHK_LIGHTS); + Exporter::mExportCameras = IsDlgButtonChecked(hWnd, IDC_CHK_CAMERA); + Exporter::mExportTransforms = IsDlgButtonChecked(hWnd, IDC_CHK_TRANSFORMS); + + GetDlgItemText(hWnd, IDC_ED_PRIORITY, tmp, MAX_PATH); + Exporter::mDefaultPriority = atof(tmp); + + GetDlgItemText(hWnd, IDC_CB_GAME, tmp, MAX_PATH); + if (AppSettings *appSettings = FindAppSetting(tmp)) + { + Exporter::mGameName = appSettings->Name; + GetDlgItemText(hWnd, IDC_CB_VERSION, tmp, MAX_PATH); + Exporter::mNifVersion = tmp; + GetDlgItemText(hWnd, IDC_CB_USER_VERSION, tmp, MAX_PATH); + Exporter::mNifUserVersion = strtol(tmp, &end, 0); + } + + EndDialog(hWnd, imp->mDlgResult=IDOK); + close = true; + break; + + case IDCANCEL: + EndDialog(hWnd, imp->mDlgResult=IDCANCEL); + close = true; + break; + } + + if (close) + SendMessage(hWnd, WM_CLOSE, 0, 0); + } + else if (HIWORD(wParam) == STN_CLICKED) + { + if (LOWORD(wParam) == IDC_LBL_LINK) + { + ShellExecute(hWnd, "open", "http://www.niftools.org", + NULL, NULL, SW_SHOWDEFAULT); + } + } + else if (HIWORD(wParam) == CBN_SELCHANGE) + { + if (LOWORD(wParam) == IDC_CB_GAME) + { + char tmp[MAX_PATH]; + GetDlgItemText(hWnd, IDC_CB_GAME, tmp, MAX_PATH); + if (AppSettings *appSettings = FindAppSetting(tmp)) + { + string version = appSettings->NiVersion; + string userVer = FormatString("%d", appSettings->NiUserVersion); + SendDlgItemMessage(hWnd, IDC_CB_VERSION, WM_SETTEXT, 0, LPARAM(version.c_str())); + SendDlgItemMessage(hWnd, IDC_CB_USER_VERSION, WM_SETTEXT, 0, LPARAM(userVer.c_str())); + } + } + } + break; + } + return FALSE; +} + //--- KfExport ------------------------------------------------------- KfExport::KfExport() { @@ -141,8 +263,103 @@ BOOL KfExport::SupportsOptions(int ext, DWORD options) int KfExport::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL suppressPrompts, DWORD options) { - // read application settings - AppSettings::Initialize(i); + try + { + // read application settings + AppSettings::Initialize(i); + + TCHAR iniName[MAX_PATH]; + LPCTSTR pluginDir = i->GetDir(APP_PLUGCFG_DIR); + PathCombine(iniName, pluginDir, "MaxNifTools.ini"); + bool iniNameIsValid = (-1 != _taccess(iniName, 0)); + + // read config from registry + Exporter::readKfConfig(i); + + AppSettings *appSettings = NULL; + if (iniNameIsValid) + { + string fname = name; + // Locate which application to use. If Auto, find first app where this file appears in the root path list + string curapp = GetIniValue<string>(KfExportSection, "CurrentApp", "AUTO", iniName); + if (0 == _tcsicmp(curapp.c_str(), "AUTO")) { + // Scan Root paths + for (AppSettingsMap::iterator itr = TheAppSettings.begin(), end = TheAppSettings.end(); itr != end; ++itr){ + if ((*itr).IsFileInRootPaths(fname)) { + appSettings = &(*itr); + break; + } + } + } else { + appSettings = FindAppSetting(curapp); + } + } + if (appSettings == NULL && !TheAppSettings.empty()) + appSettings = &TheAppSettings.front(); + + Exporter::mGameName = appSettings->Name; + Exporter::mNifVersion = appSettings->NiVersion; + Exporter::mNifUserVersion = appSettings->NiUserVersion; + + if(!suppressPrompts) + { + if (DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_KF_PANEL), GetActiveWindow(), KfExportOptionsDlgProc, (LPARAM)this) != IDOK) + return true; + + // write config to registry + Exporter::writeKfConfig(i); + + // write config to root node + Exporter::writeConfig(i->GetRootNode()); + + // Update the current app version + appSettings = FindAppSetting(Exporter::mGameName); + if (appSettings == NULL && !TheAppSettings.empty()) + appSettings = &TheAppSettings.front(); + appSettings->NiVersion = Exporter::mNifVersion; + appSettings->NiUserVersion = Exporter::mNifUserVersion; + appSettings->WriteSettings(i); + } + + int nifVersion = VER_20_0_0_5; + int nifUserVer = Exporter::mNifUserVersion; + + if (!Exporter::mNifVersion.empty()) + { + nifVersion = GetVersion(Exporter::mNifVersion); + if (!IsVersionSupported(nifVersion)) + throw exception(FormatString("Version '%s' is not a supported version.").c_str()); + } + + Exporter::mSelectedOnly = (options&SCENE_EXPORT_SELECTED) != 0; + Exporter exp(i, appSettings); + + Ref<NiControllerSequence> root = new NiControllerSequence(); + + TCHAR fname[MAX_PATH]; + _tcscpy(fname, PathFindFileName(name)); + PathRemoveExtension(fname); + root->SetName(fname); + + Exporter::Result result = exp.doAnimExport(root); + + if (result!=Exporter::Ok) + throw exception("Unknown error."); + + WriteNifTree(name, StaticCast<NiObject>(root), nifVersion, nifUserVer); + } + + catch (exception &e) + { + MessageBox(NULL, e.what(), "Export Error", MB_OK); + return true; + } + + catch (...) + { + MessageBox(NULL, "Unknown error.", "Export Error", MB_OK); + return true; + } return TRUE; } \ No newline at end of file diff --git a/NifExport/MtlTex.cpp b/NifExport/MtlTex.cpp index 75b4089..9465d63 100755 --- a/NifExport/MtlTex.cpp +++ b/NifExport/MtlTex.cpp @@ -136,16 +136,16 @@ void Exporter::makeMaterial(NiAVObjectRef &parent, Mtl *mtl) if (smtl->SupportsShaders()) { if (Shader *s = smtl->GetShader()) { if (smtl->GetWire()){ - NiWireframePropertyRef wireProp = CreateNiObject<NiWireframeProperty>(); + NiWireframePropertyRef wireProp = new NiWireframeProperty(); wireProp->SetFlags(1); parent->AddProperty(wireProp); } if (smtl->GetTwoSided()){ - NiStencilPropertyRef stencil = CreateNiObject<NiStencilProperty>(); - stencil->SetStencilFunction(4); + NiStencilPropertyRef stencil = new NiStencilProperty(); + stencil->SetStencilFunction(TEST_GREATER); stencil->SetStencilEnabled(false); - stencil->SetPassAction(3); - stencil->SetDrawMode(3); + stencil->SetPassAction(ACTION_INCREMENT); + stencil->SetDrawMode(DRAW_BOTH); parent->AddProperty(stencil); } if (smtl->IsFaceted()) { @@ -343,10 +343,10 @@ bool Exporter::exportCiv4Shader(NiAVObjectRef parent, Mtl* mtl) } if (smtl->GetTwoSided()){ NiStencilPropertyRef stencil = CreateNiObject<NiStencilProperty>(); - stencil->SetStencilFunction(4); + stencil->SetStencilFunction(TEST_GREATER); stencil->SetStencilEnabled(false); - stencil->SetPassAction(3); - stencil->SetDrawMode(3); + stencil->SetPassAction(ACTION_INCREMENT); + stencil->SetDrawMode(DRAW_BOTH); parent->AddProperty(stencil); } if (smtl->IsFaceted()) { diff --git a/NifExport/NifExport.cpp b/NifExport/NifExport.cpp index c434a04..4a7be3b 100755 --- a/NifExport/NifExport.cpp +++ b/NifExport/NifExport.cpp @@ -7,7 +7,7 @@ using namespace Niflib; #define NifExport_CLASS_ID Class_ID(0xa57ff0a4, 0xa0374ffb) -static LPCTSTR NifExportSection = TEXT("MaxNifExport"); +LPCTSTR NifExportSection = TEXT("MaxNifExport"); class NifExport : public SceneExport { @@ -41,7 +41,7 @@ class NifExportClassDesc : public ClassDesc2 public: int IsPublic() { return TRUE; } void *Create(BOOL loading = FALSE) { return new NifExport(); } - const TCHAR *ClassName() { return GetString(IDS_CLASS_NAME); } + const TCHAR *ClassName() { return GetString(IDS_NIF_CLASS_NAME); } SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; } Class_ID ClassID() { return NifExport_CLASS_ID; } const TCHAR *Category() { return GetString(IDS_CATEGORY); } @@ -283,68 +283,69 @@ BOOL NifExport::SupportsOptions(int ext, DWORD options) int NifExport::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL suppressPrompts, DWORD options) { - // read application settings - AppSettings::Initialize(i); - - TCHAR iniName[MAX_PATH]; - LPCTSTR pluginDir = i->GetDir(APP_PLUGCFG_DIR); - PathCombine(iniName, pluginDir, "MaxNifTools.ini"); - bool iniNameIsValid = (-1 != _taccess(iniName, 0)); - - // Set whether Config should use registry or not - Exporter::mUseRegistry = !iniNameIsValid || GetIniValue<bool>(NifExportSection, "UseRegistry", false, iniName); - // read config from registry - Exporter::readConfig(i); - // read config from root node - Exporter::readConfig(i->GetRootNode()); - - // locate the "default" app setting - AppSettings *appSettings = NULL; - if (iniNameIsValid) - { - string fname = name; - // Locate which application to use. If Auto, find first app where this file appears in the root path list - string curapp = GetIniValue<string>(NifExportSection, "CurrentApp", "AUTO", iniName); - if (0 == _tcsicmp(curapp.c_str(), "AUTO")) { - // Scan Root paths - for (AppSettingsMap::iterator itr = TheAppSettings.begin(), end = TheAppSettings.end(); itr != end; ++itr){ - if ((*itr).IsFileInRootPaths(fname)) { - appSettings = &(*itr); - break; + try + { + // read application settings + AppSettings::Initialize(i); + + TCHAR iniName[MAX_PATH]; + LPCTSTR pluginDir = i->GetDir(APP_PLUGCFG_DIR); + PathCombine(iniName, pluginDir, "MaxNifTools.ini"); + bool iniNameIsValid = (-1 != _taccess(iniName, 0)); + + // Set whether Config should use registry or not + Exporter::mUseRegistry = !iniNameIsValid || GetIniValue<bool>(NifExportSection, "UseRegistry", false, iniName); + // read config from registry + Exporter::readConfig(i); + // read config from root node + Exporter::readConfig(i->GetRootNode()); + + // locate the "default" app setting + AppSettings *appSettings = NULL; + if (iniNameIsValid) + { + string fname = name; + // Locate which application to use. If Auto, find first app where this file appears in the root path list + string curapp = GetIniValue<string>(NifExportSection, "CurrentApp", "AUTO", iniName); + if (0 == _tcsicmp(curapp.c_str(), "AUTO")) { + // Scan Root paths + for (AppSettingsMap::iterator itr = TheAppSettings.begin(), end = TheAppSettings.end(); itr != end; ++itr){ + if ((*itr).IsFileInRootPaths(fname)) { + appSettings = &(*itr); + break; + } } + } else { + appSettings = FindAppSetting(curapp); } - } else { - appSettings = FindAppSetting(curapp); } - } - if (appSettings == NULL && !TheAppSettings.empty()) - appSettings = &TheAppSettings.front(); + if (appSettings == NULL && !TheAppSettings.empty()) + appSettings = &TheAppSettings.front(); - if(!suppressPrompts) - { Exporter::mGameName = appSettings->Name; Exporter::mNifVersion = appSettings->NiVersion; Exporter::mNifUserVersion = appSettings->NiUserVersion; - if (DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_PANEL), GetActiveWindow(), NifExportOptionsDlgProc, (LPARAM)this) != IDOK) - return true; - - // write config to registry - Exporter::writeConfig(i); - // write config to root node - Exporter::writeConfig(i->GetRootNode()); - - // Update the current app version - appSettings = FindAppSetting(Exporter::mGameName); - if (appSettings == NULL && !TheAppSettings.empty()) - appSettings = &TheAppSettings.front(); - appSettings->NiVersion = Exporter::mNifVersion; - appSettings->NiUserVersion = Exporter::mNifUserVersion; - appSettings->WriteSettings(i); - } + if(!suppressPrompts) + { + if (DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_NIF_PANEL), GetActiveWindow(), NifExportOptionsDlgProc, (LPARAM)this) != IDOK) + return true; + + // write config to registry + Exporter::writeConfig(i); + // write config to root node + Exporter::writeConfig(i->GetRootNode()); + + // Update the current app version + appSettings = FindAppSetting(Exporter::mGameName); + if (appSettings == NULL && !TheAppSettings.empty()) + appSettings = &TheAppSettings.front(); + appSettings->NiVersion = Exporter::mNifVersion; + appSettings->NiUserVersion = Exporter::mNifUserVersion; + appSettings->WriteSettings(i); + } + - try - { int nifVersion = VER_20_0_0_5; int nifUserVer = Exporter::mNifUserVersion; diff --git a/NifExport/NifExport.rc b/NifExport/NifExport.rc index 5c6fc3a..e9f8667 100755 --- a/NifExport/NifExport.rc +++ b/NifExport/NifExport.rc @@ -73,7 +73,32 @@ END // Dialog // -IDD_PANEL DIALOGEX 0, 0, 205, 203 +IDD_KF_PANEL DIALOGEX 0, 0, 205, 130 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_TOOLWINDOW +CAPTION "Export KF" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Export:",IDC_STATIC,7,7,81,66 + CONTROL "&Hidden Nodes",IDC_CHK_HIDDEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,17,67,10 + CONTROL "Transforms",IDC_CHK_TRANSFORMS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,31,67,10 + CONTROL "&Lights",IDC_CHK_LIGHTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,44,67,10 + CONTROL "Cameras",IDC_CHK_CAMERA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,58,67,10 + GROUPBOX "Behaviors:",IDC_STATIC,94,7,104,66 + LTEXT "Priority:",IDC_LBL_PRIORITY,104,24,37,8 + EDITTEXT IDC_ED_PRIORITY,145,22,39,12,ES_AUTOHSCROLL + LTEXT "Game",IDC_STATIC,7,78,66,8 + COMBOBOX IDC_CB_GAME,7,89,105,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Version",IDC_STATIC,117,78,39,8 + EDITTEXT IDC_CB_VERSION,117,89,45,12,ES_AUTOHSCROLL + LTEXT "User",IDC_STATIC,167,78,25,8 + EDITTEXT IDC_CB_USER_VERSION,167,89,30,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "&Export",IDOK,5,109,34,14 + PUSHBUTTON "&Cancel",IDCANCEL,45,109,33,14 + LTEXT "http://www.niftools.org",IDC_LBL_LINK,103,109,95,14,SS_NOTIFY | SS_CENTERIMAGE +END + +IDD_NIF_PANEL DIALOGEX 0, 0, 205, 203 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_TOOLWINDOW CAPTION "Export Nif" @@ -122,7 +147,15 @@ END #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN - IDD_PANEL, DIALOG + IDD_KF_PANEL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 198 + TOPMARGIN, 7 + BOTTOMMARGIN, 123 + END + + IDD_NIF_PANEL, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 198 @@ -139,8 +172,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,2,3,0 - PRODUCTVERSION 0,2,3,0 + FILEVERSION 0,2,4,0 + PRODUCTVERSION 0,2,4,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -156,12 +189,12 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "3ds Max Nif Exporter" - VALUE "FileVersion", "0, 2, 3, 0" + VALUE "FileVersion", "0, 2, 4, 0" VALUE "InternalName", "NifExport.dle" VALUE "LegalCopyright", "Copyright (c) 2006, NIF File Format Library and Tools\r\nAll rights reserved." VALUE "OriginalFilename", "NifExport.dle" VALUE "ProductName", "3ds Max Nif Exporter" - VALUE "ProductVersion", "0, 2, 3, 0" + VALUE "ProductVersion", "0, 2, 4, 0" END END BLOCK "VarFileInfo" @@ -178,9 +211,10 @@ END STRINGTABLE BEGIN - IDS_CLASS_NAME "Nif Exporter" + IDS_NIF_CLASS_NAME "Niftools NIF Exporter" IDS_PARAMS "Parameters" IDS_SPIN "Spin" + IDS_KF_CLASS_NAME "Niftools KF Exporter" END #endif // English (U.S.) resources diff --git a/NifExport/resource.h b/NifExport/resource.h index 2aeda38..3d67a7f 100755 --- a/NifExport/resource.h +++ b/NifExport/resource.h @@ -5,9 +5,13 @@ #define IDS_LIBDESCRIPTION 1 #define IDS_CATEGORY 2 #define IDS_CLASS_NAME 3 +#define IDS_NIF_CLASS_NAME 3 #define IDS_PARAMS 4 #define IDS_SPIN 5 +#define IDS_KF_CLASS_NAME 6 #define IDD_PANEL 101 +#define IDD_NIF_PANEL 101 +#define IDD_KF_PANEL 102 #define IDC_CLOSEBUTTON 1000 #define IDC_DOSTUFF 1000 #define IDC_CHK_HIDDEN 1003 @@ -18,8 +22,10 @@ #define IDC_ED_WELDTHRESH 1008 #define IDC_LBL_WELDTHRESH 1009 #define IDC_CHK_COLL 1010 +#define IDC_ED_PRIORITY 1010 #define IDC_LBL_LINK 1011 #define IDC_CHK_VCOLORS 1012 +#define IDC_LBL_PRIORITY 1012 #define IDC_CHK_REMAP 1013 #define IDC_CB_GAME 1014 #define IDC_CB_VERSION 1015 @@ -36,6 +42,8 @@ #define IDC_CHK_CAMERA 1025 #define IDC_CHK_SKEL_ONLY2 1026 #define IDC_CHK_BONE_COLL 1026 +#define IDC_CHK_TRANSFORMS 1026 +#define IDC_EDIT1 1027 #define IDC_COLOR 1456 #define IDC_EDIT 1490 #define IDC_SPIN 1496 @@ -46,7 +54,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1025 +#define _APS_NEXT_CONTROL_VALUE 1028 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/NifFurniture/NifFurniture.rc b/NifFurniture/NifFurniture.rc index ce1e6e6..3c75f27 100755 --- a/NifFurniture/NifFurniture.rc +++ b/NifFurniture/NifFurniture.rc @@ -107,8 +107,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,2,3,0 - PRODUCTVERSION 0,2,3,0 + FILEVERSION 0,2,4,0 + PRODUCTVERSION 0,2,4,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -124,12 +124,12 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "3ds Max Nif Furniture Plugin" - VALUE "FileVersion", "0, 2, 3, 0" + VALUE "FileVersion", "0, 2, 4, 0" VALUE "InternalName", "NifFurniture.dlu" VALUE "LegalCopyright", "Copyright (c) 2006, NIF File Format Library and Tools\r\nAll rights reserved." VALUE "OriginalFilename", "NifFurniture.dlu" VALUE "ProductName", "3ds Max Nif Furniture Plugin" - VALUE "ProductVersion", "0, 2, 3, 0" + VALUE "ProductVersion", "0, 2, 4, 0" END END BLOCK "VarFileInfo" diff --git a/NifImport/ImportAnimation.cpp b/NifImport/ImportAnimation.cpp index 72ee9f4..5849460 100644 --- a/NifImport/ImportAnimation.cpp +++ b/NifImport/ImportAnimation.cpp @@ -18,6 +18,7 @@ HISTORY: #include "KFMImporter.h" #include "KFImporter.h" #include "AnimKey.h" +#include "NifPlugins.h" #include <obj/NiInterpolator.h> #include <obj/NiTransformInterpolator.h> #include <obj/NiTransformData.h> @@ -136,11 +137,20 @@ void NifImporter::ClearAnimation(INode *node) { if (node != NULL) { + if (node->HasNoteTracks()){ + for (int i = node->NumNoteTracks()-1; i>=0; --i ){ + if (NoteTrack *nt = node->GetNoteTrack(i)) + node->DeleteNoteTrack(nt, TRUE); + } + } node->DeleteKeys(TRACK_DOALL); ::ClearAnimation(node->GetTMController()); for (int i=0, n=node->NumberOfChildren(); i<n; ++i){ ClearAnimation(node->GetChildNode(i)); } + + // Clear animation priority + node->SetUserPropFloat(NP_ANM_PRI, 0.0f); } } void NifImporter::ClearAnimation() @@ -304,7 +314,48 @@ bool KFMImporter::ImportAnimation() if (addNoteTracks) { string target = cntr->GetTargetName(); if ( INode *n = gi->GetINodeByName(target.c_str()) ) { +#if 1 + DefNoteTrack* nt = (DefNoteTrack*)NewDefaultNoteTrack(); + n->AddNoteTrack(nt); + + for (vector<StringKey>::iterator itr=textKeys.begin(); itr != textKeys.end(); ++itr) { + TimeValue t = TimeToFrame(time + (*itr).time); + + if (wildmatch("start*", (*itr).data)){ + stringlist args = TokenizeCommandLine((*itr).data.c_str(), true); + if (args.empty()) continue; + bool hasName = false; + bool hasLoop = false; + CycleType ct = cntr->GetCycleType(); + for (stringlist::iterator itr = args.begin(); itr != args.end(); ++itr) { + if (strmatch("-name", *itr)) { + if (++itr == args.end()) break; + hasName = true; + } else if (strmatch("-loop", *itr)) { + hasLoop = true; + } + } + if (!hasName) { + string name = cntr->GetName(); + if (name.empty()) + name = FormatString("EMPTY_SEQUENCE_AT_%df", int(t * FramesPerSecond / TicksPerFrame) ); + args.push_back("-name"); + args.push_back(name); + } + if (!hasLoop && ct == CYCLE_LOOP) { + args.push_back("-loop"); + } + string line = JoinCommandLine(args); + NoteKey *key = new NoteKey(t, line.c_str(), 0); + nt->keys.Append(1, &key); + } else { + NoteKey *key = new NoteKey(t, (*itr).data.c_str(), 0); + nt->keys.Append(1, &key); + } + } + +#else TSTR script; script += "fn getActorManager obj = (\n" @@ -326,7 +377,7 @@ bool KFMImporter::ImportAnimation() script += FormatText("nt = getActorManager $'%s'\n", target.c_str()); for (vector<StringKey>::iterator itr=textKeys.begin(); itr != textKeys.end(); ++itr) { - TimeValue t = TimeToFrame(time + (*itr).time) + 1; + TimeValue t = TimeToFrame(time + (*itr).time); if (wildmatch("start*", (*itr).data)){ stringlist args = TokenizeCommandLine((*itr).data.c_str(), true); @@ -363,6 +414,7 @@ bool KFMImporter::ImportAnimation() //nt->keys.Append(1, &key); } ExecuteMAXScriptScript(script, TRUE, NULL); +#endif } } @@ -396,6 +448,10 @@ bool KFMImporter::ImportAnimation() INode *n = gi->GetINodeByName(name.c_str()); + if ((*lnk).priority_ != 0.0f) { + npSetProp(n, NP_ANM_PRI, (*lnk).priority_); + } + NiKeyframeDataRef data; Point3 p; Quat q; float s; if (ai.GetTransformData(*lnk, name, data, p, q, s)) { diff --git a/NifImport/ImportSkeleton.cpp b/NifImport/ImportSkeleton.cpp index 0649cb4..1d8cfc5 100644 --- a/NifImport/ImportSkeleton.cpp +++ b/NifImport/ImportSkeleton.cpp @@ -686,6 +686,9 @@ void NifImporter::ImportBones(NiNodeRef node, bool recurse) bool NifImporter::ImportUPB(INode *node, Niflib::NiNodeRef block) { + if (!importUPB) + return false; + bool ok = false; if (node && block) { diff --git a/NifImport/MaxNifImport.cpp b/NifImport/MaxNifImport.cpp index dcb5407..acd3970 100644 --- a/NifImport/MaxNifImport.cpp +++ b/NifImport/MaxNifImport.cpp @@ -203,20 +203,16 @@ int MaxNifImport::DoImport(const TCHAR *filename,ImpInterface *i, Interface *gi, return FALSE; ok = importer.DoImport(); } + } + catch (exception &e) + { + MessageBox(NULL, e.what(), "Import Error", MB_OK); + return TRUE; } - catch( exception & e ) + catch (...) { - e=e; - ok = false; - } - catch( exception * e ) - { - e=e; - ok = false; - } - catch( ... ) - { - ok = false; + MessageBox(NULL, "Unknown error.", "Import Error", MB_OK); + return TRUE; } return ok ? TRUE : FALSE; } diff --git a/NifImport/MaxNifImport.rc b/NifImport/MaxNifImport.rc index 158f7c5..6ca1950 100644 --- a/NifImport/MaxNifImport.rc +++ b/NifImport/MaxNifImport.rc @@ -36,27 +36,28 @@ BEGIN CONTROL "&Skeleton",IDC_CHK_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,16,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,86,67,10 CONTROL "&Animation",IDC_CHK_ANIMATION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,50,67,10 + CONTROL "&Lights",IDC_CHK_LIGHTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,62,67,10 + CONTROL "Cameras",IDC_CHK_CAMERA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,74,67,10 + CONTROL "Co&llision",IDC_CHK_COLL,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,14,86,67,10 CONTROL "Furniture &Markers",IDC_CHK_FURN,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,14,97,67,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 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 + CONTROL "Clear Animation",IDC_CHK_CLEARANIM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,73,88,10 + CONTROL "Ignore User Prop Buffers",IDC_CHK_UPB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,86,89,10 + GROUPBOX "Behaviors:",IDC_STATIC,94,6,101,105 + CONTROL "Use &Biped",IDC_CHK_BIPED,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,102,98,87,10 + LTEXT "Game:",IDC_STATIC,7,129,31,8 + COMBOBOX IDC_CB_GAME,47,127,131,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP LTEXT "Skeleton:",IDC_STC_SKELETON,7,143,31,8 EDITTEXT IDC_ED_SKELETON,7,155,171,12,ES_AUTOHSCROLL PUSHBUTTON "...",IDC_BTN_BROWSE,192,155,19,13 - LTEXT "Game:",IDC_STATIC,7,129,31,8 - COMBOBOX IDC_CB_GAME,47,127,131,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP DEFPUSHBUTTON "&Import",IDOK,5,172,34,14 PUSHBUTTON "&Cancel",IDCANCEL,45,172,33,14 LTEXT "http://www.niftools.org",IDC_LBL_LINK,93,172,95,14,SS_NOTIFY | SS_CENTERIMAGE - CONTROL "Clear Animation",IDC_CHK_CLEARANIM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,73,88,10 - CONTROL "&Lights",IDC_CHK_LIGHTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,62,67,10 - CONTROL "Cameras",IDC_CHK_CAMERA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,74,67,10 END IDD_KF_PANEL DIALOGEX 0, 0, 118, 99 @@ -66,12 +67,12 @@ CAPTION "Import KF" FONT 8, "MS Sans Serif", 0, 0, 0x1 BEGIN GROUPBOX "Import:",-1,7,6,104,51 - DEFPUSHBUTTON "&Import",IDOK,5,78,34,14 - PUSHBUTTON "&Cancel",IDCANCEL,45,78,33,14 - LTEXT "http://www.niftools.org",IDC_LBL_LINK,7,61,95,14,SS_NOTIFY | SS_CENTERIMAGE CONTROL "Clear Animation",IDC_CHK_CLEARANIM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,18,72,10 CONTROL "Add Key Notes",IDC_CHK_KEYNOTES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,31,72,10 CONTROL "Add Time Tags",IDC_CHK_TIMETAGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,44,72,10 + LTEXT "http://www.niftools.org",IDC_LBL_LINK,7,61,95,14,SS_NOTIFY | SS_CENTERIMAGE + DEFPUSHBUTTON "&Import",IDOK,5,78,34,14 + PUSHBUTTON "&Cancel",IDCANCEL,45,78,33,14 END @@ -134,8 +135,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,2,3,0 - PRODUCTVERSION 0,2,3,0 + FILEVERSION 0,2,4,0 + PRODUCTVERSION 0,2,4,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -151,12 +152,12 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "3ds Max Nif Importer" - VALUE "FileVersion", "0, 2, 3, 0" + VALUE "FileVersion", "0, 2, 4, 0" VALUE "InternalName", "MaxNifImport.dli" VALUE "LegalCopyright", "Copyright (c) 2006, NIF File Format Library and Tools\r\nAll rights reserved." VALUE "OriginalFilename", "MaxNifImport.dli" VALUE "ProductName", "3ds Max Nif Importer" - VALUE "ProductVersion", "0, 2, 3, 0" + VALUE "ProductVersion", "0, 2, 4, 0" END END BLOCK "VarFileInfo" @@ -175,7 +176,7 @@ STRINGTABLE BEGIN IDS_LIBDESCRIPTION "Importer for NIF files" IDS_CATEGORY "NifTools" - IDS_CLASS_NAME "MaxNifImport" + IDS_CLASS_NAME "Niftools_Nif_Importer" IDS_PARAMS "Parameters" IDS_SPIN "Spin" END diff --git a/NifImport/NIFImport.cpp b/NifImport/NIFImport.cpp index 001a36d..cb52375 100644 --- a/NifImport/NIFImport.cpp +++ b/NifImport/NIFImport.cpp @@ -147,6 +147,7 @@ void NifImporter::LoadIniSettings() vertexColorMode = GetIniValue<int>(NifImportSection, "VertexColorMode", 1); useCiv4Shader = GetIniValue(NifImportSection, "UseCiv4Shader", true); mergeNonAccum = GetIniValue(NifImportSection, "MergeNonAccum", true); + importUPB = GetIniValue(NifImportSection, "ImportUPB", true); // Biped importBones = GetIniValue(BipedImportSection, "ImportBones", true); @@ -210,6 +211,7 @@ void NifImporter::SaveIniSettings() SetIniValue(NifImportSection, "EnableAutoSmooth", enableAutoSmooth); SetIniValue(NifImportSection, "RemoveIllegalFaces", removeIllegalFaces); SetIniValue(NifImportSection, "RemoveDegenerateFaces", removeDegenerateFaces); + SetIniValue(NifImportSection, "ImportUPB", importUPB); SetIniValue(BipedImportSection, "ImportBones", importBones); SetIniValue(BipedImportSection, "RemoveUnusedImportedBones", removeUnusedImportedBones); diff --git a/NifImport/NIFImporter.h b/NifImport/NIFImporter.h index 087328b..6d47202 100644 --- a/NifImport/NIFImporter.h +++ b/NifImport/NIFImporter.h @@ -36,6 +36,7 @@ public: bool mergeNonAccum; bool enableLights; bool enableCameras; + bool importUPB; // Biped/Bones related settings bool importBones; diff --git a/NifImport/NifDialog.cpp b/NifImport/NifDialog.cpp index 2bf1152..4a36f87 100644 --- a/NifImport/NifDialog.cpp +++ b/NifImport/NifDialog.cpp @@ -57,6 +57,8 @@ static BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wP CheckDlgButton(hWnd, IDC_CHK_CLEARANIM, imp->clearAnimation); CheckDlgButton(hWnd, IDC_CHK_BIPED, imp->useBiped); + CheckDlgButton(hWnd, IDC_CHK_UPB, !imp->importUPB); + string selection = (imp->appSettings) ? imp->appSettings->Name : "User"; for (AppSettingsMap::iterator itr = TheAppSettings.begin(), end = TheAppSettings.end(); itr != end; ++itr) @@ -108,6 +110,7 @@ static BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wP 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; + imp->importUPB = IsDlgButtonChecked(hWnd, IDC_CHK_UPB) ? false : true; GetDlgItemText(hWnd, IDC_CB_GAME, tmp, MAX_PATH); if (AppSettings *appSettings = FindAppSetting(tmp)) { diff --git a/NifImport/resource.h b/NifImport/resource.h index a608a76..22c9238 100644 --- a/NifImport/resource.h +++ b/NifImport/resource.h @@ -21,6 +21,7 @@ #define IDC_ED_SKELETON 1006 #define IDC_CHK_BIPED 1007 #define IDC_CHK_LIGHTS 1008 +#define IDC_CHK_UPB 1009 #define IDC_CHK_COLL 1010 #define IDC_LBL_LINK 1011 #define IDC_CHK_VCOLORS 1012 diff --git a/NifProps/NifProps.cpp b/NifProps/NifProps.cpp index 62b11ae..af0afb2 100755 --- a/NifProps/NifProps.cpp +++ b/NifProps/NifProps.cpp @@ -27,11 +27,13 @@ public: void selectionChanged(); - BOOL dlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + BOOL dlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + BOOL dlgAnimProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); private: - HWND mPanel; + HWND mPanel; + HWND mAnimPanel; IUtil *mIU; Interface *mIP; INode *mNode; @@ -44,7 +46,7 @@ private: NpComboBox mCbMotionSystem; NpComboBox mCbQualityType; - void enableGUI(BOOL object, BOOL hvk); + void enableGUI(BOOL object, BOOL hvk, BOOL anim); }; static NifProps plugin; @@ -74,7 +76,12 @@ ClassDesc2* GetNifPropsDesc() { return &NifPropsDesc; } static BOOL CALLBACK NifPropsDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { - return plugin.dlgProc(hWnd, msg, wParam, lParam); + return plugin.dlgProc(hWnd, msg, wParam, lParam); +} + +static BOOL CALLBACK NifAnimPropsDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + return plugin.dlgAnimProc(hWnd, msg, wParam, lParam); } @@ -86,6 +93,7 @@ NifProps::NifProps() mIU = NULL; mIP = NULL; mPanel = NULL; + mAnimPanel = NULL; } NifProps::~NifProps() @@ -163,6 +171,17 @@ void NifProps::BeginEditParams(Interface *ip, IUtil *iu) str++; } + + //mAnimPanel = ip->AddRollupPage( + // hInstance, + // MAKEINTRESOURCE(IDD_ANIM_PANEL), + // NifAnimPropsDlgProc, + // GetString(IDS_ANIM_PARAMS), + // 0); + + mSpins[IDC_SP_ANIM_PRIORITY] = + SetupFloatSpinner(mPanel, IDC_SP_ANIM_PRIORITY, IDC_ED_ANIM_PRIORITY, 0, 255, 25, .1f); + selectionChanged(); } @@ -179,7 +198,7 @@ void NifProps::EndEditParams(Interface *ip,IUtil *iu) mNode = NULL; } -void NifProps::enableGUI(BOOL obj, BOOL hvk) +void NifProps::enableGUI(BOOL obj, BOOL hvk, BOOL anim) { EnableWindow(GetDlgItem(mPanel, IDC_GRP_OBJECT), obj); EnableWindow(GetDlgItem(mPanel, IDC_CHK_ISCOLL), obj); @@ -190,8 +209,11 @@ void NifProps::enableGUI(BOOL obj, BOOL hvk) EnableWindow(GetDlgItem(mPanel, IDC_LBL_LAYER), hvk); EnableWindow(GetDlgItem(mPanel, IDC_CB_LAYER), hvk); */ - for (int i=IDC_HVK_BEGIN; i<=IDC_HVK_END; i++) - EnableWindow(GetDlgItem(mPanel, i), hvk); + for (int i=IDC_HVK_BEGIN; i<=IDC_HVK_END; i++) + EnableWindow(GetDlgItem(mPanel, i), hvk); + + for (int i=IDC_ANIM_BEGIN; i<=IDC_ANIM_END; i++) + EnableWindow(GetDlgItem(mPanel, i), anim); } void NifProps::SelectionSetChanged(Interface *ip, IUtil *iu) @@ -205,7 +227,7 @@ void NifProps::selectionChanged() if (numSel <= 0) { mNode = NULL; - enableGUI(false, false); + enableGUI(false, false, false); return; } @@ -213,7 +235,7 @@ void NifProps::selectionChanged() INode *nodeSel = mIP->GetSelNode(0); bool isColl = npIsCollision(nodeSel); - enableGUI(singleSel, singleSel && isColl); + enableGUI(singleSel, singleSel && isColl, true); mNode = singleSel?nodeSel:NULL; if (!singleSel) @@ -262,6 +284,9 @@ void NifProps::selectionChanged() mSpins[IDC_SP_MAX_LINEAR_VELOCITY]->SetValue(maxlinvel, TRUE); mSpins[IDC_SP_MAX_ANGULAR_VELOCITY]->SetValue(maxangvel, TRUE); + float priority; + npGetProp(nodeSel, NP_ANM_PRI, priority, NP_DEFAULT_ANM_PRI); + mSpins[IDC_SP_ANIM_PRIORITY]->SetValue(priority, TRUE); } @@ -383,6 +408,12 @@ BOOL NifProps::dlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) case IDC_SP_PENETRATION_DEPTH: npSetProp(mNode, NP_HVK_PENETRATION_DEPTH, mSpins[IDC_SP_PENETRATION_DEPTH]->GetFVal()); break; + + case IDC_SP_ANIM_PRIORITY: + for (int i=0, n=mIP->GetSelNodeCount(); i<n; ++i) { + npSetProp(mIP->GetSelNode(i), NP_ANM_PRI, mSpins[IDC_SP_ANIM_PRIORITY]->GetFVal()); + } + break; } break; diff --git a/NifProps/NifProps.rc b/NifProps/NifProps.rc index a070ca4..68b5abc 100755 --- a/NifProps/NifProps.rc +++ b/NifProps/NifProps.rc @@ -73,7 +73,7 @@ END // Dialog // -IDD_PANEL DIALOGEX 0, 0, 107, 401 +IDD_PANEL DIALOGEX 0, 0, 107, 360 STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE FONT 8, "MS Sans Serif", 0, 0, 0x0 BEGIN @@ -84,11 +84,6 @@ BEGIN GROUPBOX "Havok",IDC_GRP_HAVOK,5,39,95,285,WS_DISABLED GROUPBOX "Object",IDC_GRP_OBJECT,5,5,95,32 CONTROL "Is Collision Mesh",IDC_CHK_ISCOLL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,18,80,10 - GROUPBOX "Global",IDC_STATIC,5,329,95,65,WS_DISABLED - EDITTEXT IDC_ED_BSXFLAGS,13,352,80,12,ES_AUTOHSCROLL | WS_DISABLED - CONTROL "BSXFlags",IDC_LBL_BSXFLAGS,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_DISABLED | WS_GROUP,13,340,80,8 - EDITTEXT IDC_ED_STRINGSEXTRA,13,374,80,12,ES_AUTOHSCROLL | WS_DISABLED - CONTROL "Strings Extra Data",IDC_LBL_STRINGSEXTRA,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_DISABLED | WS_GROUP,13,365,80,8 CONTROL "Center",IDC_LBL_CENTER,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_DISABLED | WS_GROUP,12,98,31,8 CONTROL "Mass",IDC_LBL_MASS,"Static",SS_LEFTNOWORDWRAP | WS_DISABLED | WS_GROUP,12,124,28,8 CONTROL "Friction",IDC_LBL_FRICTION,"Static",SS_LEFTNOWORDWRAP | WS_DISABLED | WS_GROUP,42,124,28,8 @@ -124,6 +119,20 @@ BEGIN LTEXT "Penetration\r\nDepth",IDC_LBL_PENETRATION_DEPTH,12,229,40,16,WS_DISABLED CONTROL "",IDC_ED_PENETRATION_DEPTH,"CustEdit",WS_DISABLED | WS_TABSTOP,12,249,35,10 CONTROL "",IDC_SP_PENETRATION_DEPTH,"SpinnerControl",WS_DISABLED,45,249,7,10 + GROUPBOX "Animation",IDC_GRP_ANIMATION,7,325,95,28 + LTEXT "Priority:",IDC_STATIC,10,338,24,8 + CONTROL "",IDC_ED_ANIM_PRIORITY,"CustEdit",WS_DISABLED | WS_TABSTOP,39,337,20,10 + CONTROL "",IDC_SP_ANIM_PRIORITY,"SpinnerControl",WS_DISABLED,57,337,7,10 +END + +IDD_ANIM_PANEL DIALOGEX 0, 0, 107, 41 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + GROUPBOX "Animation",IDC_GRP_ANIMATION,5,5,95,28 + LTEXT "Priority:",IDC_STATIC,8,18,24,8 + CONTROL "",IDC_ED_ANIM_PRIORITY,"CustEdit",WS_DISABLED | WS_TABSTOP,37,17,20,10 + CONTROL "",IDC_SP_ANIM_PRIORITY,"SpinnerControl",WS_DISABLED,55,17,7,10 END @@ -140,7 +149,15 @@ BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 100 TOPMARGIN, 7 - BOTTOMMARGIN, 394 + BOTTOMMARGIN, 353 + END + + IDD_ANIM_PANEL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 100 + TOPMARGIN, 7 + BOTTOMMARGIN, 34 END END #endif // APSTUDIO_INVOKED @@ -342,8 +359,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,2,3,0 - PRODUCTVERSION 0,2,3,0 + FILEVERSION 0,2,4,0 + PRODUCTVERSION 0,2,4,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -359,12 +376,12 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "3ds Max Nif Reactor Properites Plugin" - VALUE "FileVersion", "0, 2, 3, 0" + VALUE "FileVersion", "0, 2, 4, 0" VALUE "InternalName", "NifProps.dlu" VALUE "LegalCopyright", "Copyright (c) 2006, NIF File Format Library and Tools\r\nAll rights reserved." VALUE "OriginalFilename", "NifProps.dlu" VALUE "ProductName", "3ds Max Nif Reactor Properites Plugin" - VALUE "ProductVersion", "0, 2, 3, 0" + VALUE "ProductVersion", "0, 2, 4, 0" END END BLOCK "VarFileInfo" @@ -386,6 +403,7 @@ BEGIN IDS_CLASS_NAME "NifProps" IDS_PARAMS "Parameters" IDS_SPIN "Spin" + IDS_ANIM_PARAMS "Animation" END #endif // English (U.S.) resources diff --git a/NifProps/resource.h b/NifProps/resource.h index d9cfbe8..fc3cc8a 100755 --- a/NifProps/resource.h +++ b/NifProps/resource.h @@ -7,15 +7,17 @@ #define IDS_CLASS_NAME 3 #define IDS_PARAMS 4 #define IDS_SPIN 5 +#define IDS_ANIM_PARAMS 6 #define IDD_PANEL 101 -#define IDC_LBL_BSXFLAGS 1001 -#define IDC_ED_BSXFLAGS 1002 -#define IDC_ED_STRINGSEXTRA 1003 -#define IDC_LBL_STRINGSEXTRA 1004 +#define IDD_ANIM_PANEL 102 +#define IDC_LBL_BSXFLAGS 1001 +#define IDC_ED_BSXFLAGS 1002 +#define IDC_ED_STRINGSEXTRA 1003 +#define IDC_LBL_STRINGSEXTRA 1004 #define IDC_GRP_OBJECT 1005 #define IDC_CHK_ISCOLL 1006 #define IDC_GRP_HAVOK 1007 -#define IDC_HVK_BEGIN IDC_GRP_HAVOK +#define IDC_HVK_BEGIN 1007 #define IDC_LBL_MATERIAL 1008 #define IDC_CB_MATERIAL 1009 #define IDC_LBL_LAYER 1010 @@ -51,11 +53,16 @@ #define IDC_LBL_ANGULAR_DAMPING 1517 #define IDC_ED_ANGULAR_DAMPING 1518 #define IDC_SP_ANGULAR_DAMPING 1519 -#define IDC_LBL_MOTION_SYSTEM 1520 -#define IDC_CB_MOTION_SYSTEM 1521 -#define IDC_LBL_QUALITY_TYPE 1522 -#define IDC_CB_QUALITY_TYPE 1523 -#define IDC_HVK_END IDC_CB_QUALITY_TYPE +#define IDC_LBL_MOTION_SYSTEM 1520 +#define IDC_CB_MOTION_SYSTEM 1521 +#define IDC_LBL_QUALITY_TYPE 1522 +#define IDC_CB_QUALITY_TYPE 1523 +#define IDC_HVK_END 1523 +#define IDC_ANIM_BEGIN 1600 +#define IDC_GRP_ANIMATION 1600 +#define IDC_ED_ANIM_PRIORITY 1601 +#define IDC_SP_ANIM_PRIORITY 1602 +#define IDC_ANIM_END 1602 // Next default values for new objects // @@ -63,7 +70,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1035 +#define _APS_NEXT_CONTROL_VALUE 1700 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif -- GitLab