From b1450f38274e5de4f372f2aed141f617ac65249e Mon Sep 17 00:00:00 2001 From: Tazpn <tazpn@users.sourceforge.net> Date: Mon, 18 Sep 2006 03:16:58 +0000 Subject: [PATCH] 0.2.5 ----- o Exporter - Rewrote animation export dialogs and procedures to write files similar to Civilation exporter. - Removed seperate *.kf and merged with *.nif like Civ4 - Fixed issues with NiStencilProperty (via niflib) for Morrowind - Add option to optionally export accum nodes - Add options for exporting skin partition in different ways - Expose the Auto detect parameter to allow game to be saved o Importer - Add option to ignore root - Expose the Time Tag and Key Note params on nif dialog - Expose the Auto detect parameter to allow game to be saved --- MaxNifPlugins_Readme.txt | 18 +- NifCommon/AnimKey.cpp | 41 +- NifCommon/AnimKey.h | 12 + NifCommon/NifCommon_VC80.vcproj | 12 +- NifExport/Animation.cpp | 602 +++++++++++++++++++++++++---- NifExport/Coll.cpp | 7 +- NifExport/Config.cpp | 23 +- NifExport/DllEntry.cpp | 2 +- NifExport/Exporter.cpp | 27 +- NifExport/Exporter.h | 37 +- NifExport/KfExport.cpp | 2 +- NifExport/Mesh.cpp | 83 ++-- NifExport/NifExport.cpp | 171 +++++++- NifExport/NifExport.rc | 108 ++++-- NifExport/NifExport_VC80.vcproj | 292 +------------- NifExport/Strips.cpp | 3 +- NifExport/Util.cpp | 25 +- NifExport/pch.h | 11 +- NifExport/resource.h | 21 +- NifFurniture/NifFurniture.rc | 8 +- NifImport/ImportAnimation.cpp | 231 ++++++----- NifImport/MaxNifImport.rc | 73 ++-- NifImport/MaxNifImport_VC80.vcproj | 24 +- NifImport/NIFImport.cpp | 10 +- NifImport/NIFImporter.h | 8 + NifImport/NifDialog.cpp | 13 +- NifImport/resource.h | 3 + NifProps/NifProps.rc | 8 +- 28 files changed, 1243 insertions(+), 632 deletions(-) diff --git a/MaxNifPlugins_Readme.txt b/MaxNifPlugins_Readme.txt index 355c3fd..cdc748b 100644 --- a/MaxNifPlugins_Readme.txt +++ b/MaxNifPlugins_Readme.txt @@ -1,4 +1,4 @@ - MaxPlugins 0.2.4 + MaxPlugins 0.2.5 ================ @@ -27,6 +27,22 @@ Change log ---------- + 0.2.5 + ----- + o Exporter + - Rewrote animation export dialogs and procedures to write files + similar to Civilation exporter. + - Removed seperate *.kf and merged with *.nif like Civ4 + - Fixed issues with NiStencilProperty (via niflib) for Morrowind + - Add option to optionally export accum nodes + - Add options for exporting skin partition in different ways + - Expose the Auto detect parameter to allow game to be saved + + o Importer + - Add option to ignore root + - Expose the Time Tag and Key Note params on nif dialog + - Expose the Auto detect parameter to allow game to be saved + 0.2.4 ----- o Exporter diff --git a/NifCommon/AnimKey.cpp b/NifCommon/AnimKey.cpp index 8caa4ac..30fdbb0 100644 --- a/NifCommon/AnimKey.cpp +++ b/NifCommon/AnimKey.cpp @@ -321,6 +321,44 @@ template<> void MergeKey<ITCBRotKey>(ITCBRotKey& lhs, ITCBRotKey& rhs) { lhs.val = Quat(lhs.val) * Quat(rhs.val); } + +template<> FloatKey InterpKey<FloatKey>(Control *subCtrl, TimeValue time, float timeOff) { + FloatKey rKey; + memset(&rKey, 0, sizeof(rKey)); + rKey.time = timeOff + FrameToTime(time); + Interval valid; valid.SetEmpty(); + if (subCtrl->SuperClassID() == SClass_ID(CTRL_SCALE_CLASS_ID) ) { + ScaleValue s; + subCtrl->GetValue(time, &s, valid, CTRL_ABSOLUTE); + rKey.data = Average(s.s); + } else { + subCtrl->GetValue(time, &rKey.data, valid, CTRL_ABSOLUTE); + } + return rKey; +} + +template<> QuatKey InterpKey<QuatKey>(Control *subCtrl, TimeValue time, float timeOff) { + QuatKey rKey; + memset(&rKey, 0, sizeof(rKey)); + rKey.time = timeOff + FrameToTime(time); + Interval valid; valid.SetEmpty(); + Quat q; + subCtrl->GetValue(time, &q, valid, CTRL_ABSOLUTE); + rKey.data = TOQUAT(q, true); + return rKey; +} + +template<> Vector3Key InterpKey<Vector3Key>(Control *subCtrl, TimeValue time, float timeOff) { + Vector3Key rKey; + memset(&rKey, 0, sizeof(rKey)); + rKey.time = timeOff + FrameToTime(time); + Interval valid; valid.SetEmpty(); + Point3 p; + subCtrl->GetValue(time, &p, valid, CTRL_ABSOLUTE); + rKey.data = TOVECTOR3(p); + return rKey; +} + float GetValue(Vector3& value, V3T type) { switch (type) { @@ -364,7 +402,6 @@ Vector3Key& CopyKey( Vector3Key& dst, FloatKey& src, V3T type) return dst; } - void SplitKeys(vector<Vector3Key>&keys, vector<FloatKey>&xkeys, vector<FloatKey>&ykeys, vector<FloatKey>&zkeys) { int n = keys.size(); @@ -435,3 +472,5 @@ bool GetTranslationKeys(Control *c, vector<Vector3Key> keys, const vector<float> } return false; } + + diff --git a/NifCommon/AnimKey.h b/NifCommon/AnimKey.h index 7766ab9..bd549a6 100644 --- a/NifCommon/AnimKey.h +++ b/NifCommon/AnimKey.h @@ -70,6 +70,11 @@ 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); +// Interpolated Keys +template<typename T> T InterpKey(Control *subCtrl, TimeValue time, float timeOff); +template<> FloatKey InterpKey<FloatKey>(Control *subCtrl, TimeValue time, float timeOff); +template<> QuatKey InterpKey<QuatKey>(Control *subCtrl, TimeValue time, float timeOff); +template<> Vector3Key InterpKey<Vector3Key>(Control *subCtrl, TimeValue time, float timeOff); template<typename T> void MergeKey(T& lhs, T& rhs) { lhs.val += rhs.val; @@ -142,13 +147,20 @@ inline int GetKeys(Control *subCtrl, vector<T>& keys, Interval range) float timeOffset = -FrameToTime(range.Start()); int n = ikeys->GetNumKeys(); keys.reserve(n); + bool hasStart = false, hasEnd = false; 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)) { + hasStart |= (range.Start() == key->time); + hasEnd |= (range.End() == key->time); keys.push_back( MapKey<T>(*key, timeOffset) ); } } + if (keys.size() > 0) { + if (!hasStart) keys.insert(keys.begin(), InterpKey<T>(subCtrl, range.Start(), timeOffset) ); + if (!hasEnd) keys.push_back(InterpKey<T>(subCtrl, range.End(), timeOffset) ); + } return keys.size(); } return 0; diff --git a/NifCommon/NifCommon_VC80.vcproj b/NifCommon/NifCommon_VC80.vcproj index 62f60d5..4da6b70 100644 --- a/NifCommon/NifCommon_VC80.vcproj +++ b/NifCommon/NifCommon_VC80.vcproj @@ -41,7 +41,7 @@ <Tool Name="VCCLCompilerTool" AdditionalOptions="/FI"$(ProjectDir)pch.h"" - AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib" + AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib\include" PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_USE_MATH_DEFINES" ExceptionHandling="2" RuntimeLibrary="0" @@ -107,7 +107,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/FI"$(ProjectDir)pch.h"" Optimization="0" - AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib" + AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib\include" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_USE_MATH_DEFINES" MinimalRebuild="true" ExceptionHandling="2" @@ -175,7 +175,7 @@ <Tool Name="VCCLCompilerTool" AdditionalOptions="/FI"$(ProjectDir)pch.h"" - AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib" + AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib\include" PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_USE_MATH_DEFINES;USE_BIPED" ExceptionHandling="2" RuntimeLibrary="0" @@ -241,7 +241,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/FI"$(ProjectDir)pch.h"" Optimization="0" - AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib" + AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib\include" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_USE_MATH_DEFINES;USE_BIPED" MinimalRebuild="true" ExceptionHandling="2" @@ -309,7 +309,7 @@ <Tool Name="VCCLCompilerTool" AdditionalOptions="/FI"$(ProjectDir)pch.h"" - AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib" + AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib\include" PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_USE_MATH_DEFINES;USE_BIPED" ExceptionHandling="2" RuntimeLibrary="0" @@ -375,7 +375,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/FI"$(ProjectDir)pch.h"" Optimization="0" - AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib" + AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib\include" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_USE_MATH_DEFINES;USE_BIPED" MinimalRebuild="true" ExceptionHandling="2" diff --git a/NifExport/Animation.cpp b/NifExport/Animation.cpp index 70eaba4..1066a9c 100644 --- a/NifExport/Animation.cpp +++ b/NifExport/Animation.cpp @@ -13,11 +13,12 @@ HISTORY: #include "pch.h" #include <IFrameTagManager.h> #include <notetrck.h> - +#include <set> #include "NifExport.h" #include "AnimKey.h" #include <obj/NiControllerSequence.h> +#include <obj/NiControllerManager.h> #include <obj/NiInterpolator.h> #include <obj/NiTransformInterpolator.h> #include <obj/NiTransformData.h> @@ -28,6 +29,8 @@ HISTORY: #include <obj/NiKeyframeData.h> #include <obj/NiStringPalette.h> #include <obj/NiBSplineCompTransformInterpolator.h> +#include <obj/NiDefaultAVObjectPalette.h> +#include <obj/NiMultiTargetTransformController.h> using namespace Niflib; const Class_ID IPOS_CONTROL_CLASS_ID = Class_ID(0x118f7e02,0xffee238a); @@ -45,26 +48,152 @@ struct AnimationExport INode * findTrackedNode(INode *root); bool doExport(NiControllerSequenceRef seq); + bool doExport(NiControllerManagerRef ctrl, INode *node); bool exportController(INode *node); Control *GetTMController(INode* node); + NiTimeControllerRef exportController(INode *node, Interval range, bool setTM ); + bool GetTextKeys(INode *node, vector<StringKey>& textKeys); Exporter ≠ Interval range; NiControllerSequenceRef seq; + + set<NiAVObjectRef> objRefs; + map<NiControllerSequenceRef, Interval> ranges; }; +bool GetTextKeys(INode *node, vector<StringKey>& textKeys, Interval range) +{ + // Populate Text keys and Sequence information from note tracks + if (Exporter::mUseTimeTags) { + if (IFrameTagManager *tagMgr = (IFrameTagManager*)GetCOREInterface(FRAMETAGMANAGER_INTERFACE)) { + int n = tagMgr->GetTagCount(); + for (int i = 0; i<n; i++) { + UINT id = tagMgr->GetTagID(i); + TimeValue t = tagMgr->GetTimeByID(id, FALSE); + TSTR name = tagMgr->GetNameByID(id); + + StringKey strkey; + strkey.time = FrameToTime( Interval(range.Start(), t).Duration()-1 ); + strkey.data = name; + textKeys.push_back(strkey); + } + } + } else { + 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; + + range.SetStart( key->time ); + for (stringlist::iterator itr = args.begin(); itr != args.end(); ++itr) { + if (strmatch("-name", *itr)) { + if (++itr == args.end()) break; + } + } + } else if ( wildmatch("end*", key->note) ) { + range.SetEnd( key->time ); + stop = true; + } + StringKey strkey; + strkey.time = FrameToTime( Interval(range.Start(), key->time).Duration()-1 ); + strkey.data = key->note; + textKeys.push_back(strkey); + } + } + } + } + } + } + return !textKeys.empty(); +} + +void Exporter::InitializeTimeController(NiTimeControllerRef ctrl, NiNodeRef parent) +{ + ctrl->SetFrequency(1.0f); + ctrl->SetStartTime(FloatINF); + ctrl->SetStopTime(FloatNegINF); + ctrl->SetPhase(0.0f); + ctrl->SetFlags(0x0C); + ctrl->SetTarget( parent ); + parent->AddController(DynamicCast<NiTimeController>(ctrl)); +} + +NiNodeRef Exporter::createAccumNode(NiNodeRef parent, INode *node) +{ + NiNodeRef accumNode; + bool isTracked = isNodeTracked(node); + if (!Exporter::mAllowAccum || !isTracked) + { + accumNode = parent; + } + else + { + accumNode = getNode( FormatString("%s NonAccum", node->GetName()) ); + accumNode->SetLocalTransform(Matrix44::IDENTITY); + parent->AddChild(DynamicCast<NiAVObject>(accumNode)); + } + + // add multi target controller to parent if exporting with animation + if ( mExportType == NIF_WO_KF ){ + + if ( Exporter::mAllowAccum && isTracked ) { + // transfer controllers to accum + list<NiTimeControllerRef> ctlrs = parent->GetControllers(); + for (list<NiTimeControllerRef>::iterator it = ctlrs.begin(); it != ctlrs.end(); ++it) { + parent->RemoveController(*it); + accumNode->AddController(*it); + } + } + + } else if ( Exporter::mExportType != Exporter::NIF_WO_ANIM ) + { + // NiMultiTargetTransformController causes crashes in old formats + if (Exporter::mNifVersionInt >= VER_10_0_1_0) + { + NiMultiTargetTransformControllerRef ctrl = new NiMultiTargetTransformController(); + vector<NiNodeRef> children; + getChildNodes(node, children); + ctrl->SetExtraTargets(children); + Exporter::InitializeTimeController(ctrl, parent); + } + NiControllerManagerRef mgr = new NiControllerManager(); + Exporter::InitializeTimeController(mgr, parent); + + // Export Animation now + doAnimExport(mgr, node); + } + return accumNode; +} Exporter::Result Exporter::doAnimExport(NiControllerSequenceRef root) { AnimationExport animExporter(*this); - return animExporter.doExport(root) ? Exporter::Ok : Exporter::Abort ; } -//NiControllerSequenceRef makeSequence(TimeValue start, TimeValue end); -INode * AnimationExport::findTrackedNode(INode *node) +Exporter::Result Exporter::doAnimExport(NiControllerManagerRef mgr, INode *node) { - // locate START in note track before assuming all is well - if (node->HasNoteTracks()) { + AnimationExport animExporter(*this); + return animExporter.doExport(mgr, node) ? Exporter::Ok : Exporter::Abort ; +} + +bool Exporter::isNodeTracked(INode *node) +{ + if (Exporter::mUseTimeTags) { + // Assume only one top level node has animation + if (mI->GetRootNode() == node->GetParentNode() && isNodeKeyed(node)) { + return true; + } + } + else 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) ) { @@ -73,7 +202,7 @@ INode * AnimationExport::findTrackedNode(INode *node) for (int j=0, m=defNT->keys.Count(); j<m; ++j) { NoteKey* key = defNT->keys[j]; if (wildmatch("start*", key->note)) { - return node; + return true; } } } @@ -81,6 +210,75 @@ INode * AnimationExport::findTrackedNode(INode *node) } } } + return false; +} + + +static bool HasKeys(Control *c) +{ + bool rv = false; + if (c != NULL) + { + if (c->IsColorController()) + return false; + + if (IKeyControl *ikeys = GetKeyControlInterface(c)){ + if (ikeys->GetNumKeys() > 0) + return true; + } + if (Control *sc = c->GetWController()) { + if (sc != c && HasKeys(sc)) + return true; + } + if (Control *sc = c->GetXController()) { + if (sc != c && HasKeys(sc)) + return true; + } + if (Control *sc = c->GetYController()) { + if (sc != c && HasKeys(sc)) + return true; + } + if (Control *sc = c->GetZController()) { + if (sc != c && HasKeys(sc)) + return true; + } + if (Control *sc = c->GetRotationController()) { + if (sc != c && HasKeys(sc)) + return true; + } + if (Control *sc = c->GetPositionController()) { + if (sc != c && HasKeys(sc)) + return true; + } + if (Control *sc = c->GetScaleController()) { + if (sc != c && HasKeys(sc)) + return true; + } + } + return false; +} + +bool Exporter::isNodeKeyed(INode *node) { + if (node->HasNoteTracks()) { + return true; + } + if (node->NumKeys() > 0) { + return true; + } + if (Control *tmCont = node->GetTMController()) { + if (HasKeys(tmCont)) + return true; + } + return false; +} + + +INode * AnimationExport::findTrackedNode(INode *node) +{ + if (ne.isNodeTracked(node)) + return node; + + // locate START in note track before assuming all is well for (int i=0; i < node->NumberOfChildren(); ++i ){ if ( INode *root = findTrackedNode( node->GetChildNode(i) ) ) { return root; @@ -111,38 +309,54 @@ bool AnimationExport::doExport(NiControllerSequenceRef seq) 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); + if (Exporter::mUseTimeTags) { + if (IFrameTagManager *tagMgr = (IFrameTagManager*)GetCOREInterface(FRAMETAGMANAGER_INTERFACE)) { + int n = tagMgr->GetTagCount(); + for (int i = 0; i<n; i++) { + UINT id = tagMgr->GetTagID(i); + TimeValue t = tagMgr->GetTimeByID(id, FALSE); + TSTR name = tagMgr->GetNameByID(id); + + StringKey strkey; + strkey.time = FrameToTime( Interval(range.Start(), t).Duration()-1 ); + strkey.data = name; + textKeys.push_back(strkey); + } + } + } else { + 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; } - } 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); } - StringKey strkey; - strkey.time = FrameToTime( Interval(range.Start(), key->time).Duration()-1 ); - strkey.data = key->note; - textKeys.push_back(strkey); } } } @@ -155,24 +369,191 @@ bool AnimationExport::doExport(NiControllerSequenceRef seq) bool ok = exportController(node); // Handle NonAccum - if (ok) + if (ok && Exporter::mAllowAccum) { 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)); + if (Exporter::mNifVersionInt >= VER_10_2_0_0) + { + 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); + 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; } +bool AnimationExport::doExport(NiControllerManagerRef mgr, INode *node) +{ + int start = 0; + NiDefaultAVObjectPaletteRef objPal = new NiDefaultAVObjectPalette(); + mgr->SetObjectPalette(objPal); + + + vector<NiControllerSequenceRef> seqs; + vector<StringKey> textKeys; + NiControllerSequenceRef curSeq; + + // Populate Text keys and Sequence information from note tracks + if (Exporter::mUseTimeTags) { + if (IFrameTagManager *tagMgr = (IFrameTagManager*)GetCOREInterface(FRAMETAGMANAGER_INTERFACE)) { + + curSeq = new NiControllerSequence(); + curSeq->SetStartTime(FloatINF); + curSeq->SetStopTime(FloatINF); + curSeq->SetFrequency(1.0f); + curSeq->SetCycleType( CYCLE_CLAMP ); + curSeq->SetTargetName( node->GetName() ); + seqs.push_back(curSeq); + this->range.SetInstant(0); + curSeq->SetStartTime(0.0f); + + int n = tagMgr->GetTagCount(); + for (int i = 0; i<n; i++) { + UINT id = tagMgr->GetTagID(i); + TimeValue t = tagMgr->GetTimeByID(id, FALSE); + TSTR name = tagMgr->GetNameByID(id); + + if (t < range.Start()) + range.SetStart(t); + + if (t > range.End()) + range.SetEnd( t ); + + StringKey strkey; + strkey.time = FrameToTime( Interval(range.Start(), t).Duration()-1 ); + strkey.data = name; + textKeys.push_back(strkey); + } + NiTextKeyExtraDataRef textKeyData = new NiTextKeyExtraData(); + curSeq->SetTextKey(textKeyData); + textKeyData->SetKeys(textKeys); + + curSeq->SetStopTime( FrameToTime( range.Duration()-1 ) ); + this->ranges[curSeq] = range; + curSeq = NULL; + } + + } else { + + int nTracks = node->NumNoteTracks(); + + // Populate Text keys and Sequence information from note tracks + for (int i=0; i<nTracks; ++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)) { + stringlist args = TokenizeCommandLine(key->note, true); + textKeys.clear(); + + curSeq = new NiControllerSequence(); + curSeq->SetStartTime(FloatINF); + curSeq->SetStopTime(FloatINF); + curSeq->SetFrequency(1.0f); + curSeq->SetCycleType( CYCLE_CLAMP ); + curSeq->SetTargetName( node->GetName() ); + seqs.push_back(curSeq); + this->range.SetInstant(0); + + curSeq->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; + curSeq->SetName(*itr); + } else if (strmatch("-loop", *itr)) { + curSeq->SetCycleType(CYCLE_LOOP); + } + } + } + + StringKey strkey; + strkey.time = FrameToTime( Interval(range.Start(), key->time).Duration()-1 ); + strkey.data = key->note; + textKeys.push_back(strkey); + + if ( wildmatch("end*", key->note) ) { + range.SetEnd( key->time ); + + // add accumulated text keys to sequence + if (curSeq != NULL) { + curSeq->SetStopTime( FrameToTime( range.Duration()-1 ) ); + + this->ranges[curSeq] = range; + + NiTextKeyExtraDataRef textKeyData = new NiTextKeyExtraData(); + curSeq->SetTextKey(textKeyData); + textKeyData->SetKeys(textKeys); + textKeys.clear(); + curSeq = NULL; + } + } + } + } + } + } + } + } + + for (vector<NiControllerSequenceRef>::iterator itr = seqs.begin(); itr != seqs.end(); ++itr) + { + // Hold temporary value + this->seq = (*itr); + + //this->range.SetStart( TimeToFrame(seq->GetStartTime()) ); + //this->range.SetEnd( TimeToFrame(seq->GetStopTime()) ); + + this->range = this->ranges[this->seq]; + + // Now let the fun begin. + bool ok = exportController(node); + + // Handle NonAccum + if (ok && Exporter::mAllowAccum) + { + NiNodeRef ninode = ne.getNode( FormatString("%s NonAccum", node->GetName()) ); + objRefs.insert( StaticCast<NiAVObject>(ninode) ); + + if (Exporter::mNifVersionInt >= VER_10_2_0_0) + { + 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); + + // now remove temporary controller + ninode->RemoveController(StaticCast<NiTimeController>(control)); + } + } + } + + // Set objects with animation + vector<NiAVObjectRef> objs; + objs.insert(objs.end(), objRefs.begin(), objRefs.end()); + objPal->SetObjs(objs); + + mgr->SetControllerSequences(seqs); + + return true; +} + Control *AnimationExport::GetTMController(INode *n) { @@ -191,11 +572,28 @@ Control *AnimationExport::GetTMController(INode *n) return c; } +NiTimeControllerRef Exporter::CreateController(INode *node, Interval range) +{ + AnimationExport ae(*this); + if ( NiTimeControllerRef tc = ae.exportController(node, range, false) ) { + if (Exporter::mExportType == Exporter::NIF_WO_KF && isNodeTracked(node)) { + NiNodeRef ninode = getNode(node->GetName()); + vector<StringKey> textKeys; + if (GetTextKeys(node, textKeys, range)) { + NiTextKeyExtraDataRef textKeyData = new NiTextKeyExtraData(); + ninode->AddExtraData(StaticCast<NiExtraData>(textKeyData), Exporter::mNifVersionInt); + textKeyData->SetKeys(textKeys); + } + } + return tc; + } + return NiTimeControllerRef(); +} -bool AnimationExport::exportController(INode *node) +NiTimeControllerRef AnimationExport::exportController(INode *node, Interval range, bool setTM ) { - bool ok = true; bool skip = false; + NiTimeControllerRef timeControl; // Primary recursive decent routine @@ -217,23 +615,54 @@ bool AnimationExport::exportController(INode *node) { Interval validity; validity.SetEmpty(); Matrix3 tm = node->GetObjTMAfterWSM(range.Start()); - Matrix3 pm = Inverse(node->GetParentTM(range.Start())); - tm *= pm; + if (INode *parent = node->GetParentNode()) { + Matrix3 pm = Inverse(parent->GetObjTMAfterWSM(range.Start())); + tm *= pm; + } - NiNodeRef ninode = new NiNode(); - ninode->SetName(node->GetName()); + bool keepData = false; - //Vector3 trans(FloatNegINF, FloatNegINF, FloatNegINF); - //Quaternion rot(FloatNegINF, FloatNegINF, FloatNegINF, FloatNegINF); - Vector3 trans = TOVECTOR3(tm.GetTrans()); - Quaternion rot = TOQUAT( Quat(tm), true ); + // Set default transform to NaN except for root node + Vector3 trans(FloatNegINF, FloatNegINF, FloatNegINF); + Quaternion rot(FloatNegINF, FloatNegINF, FloatNegINF, FloatNegINF); float scale = FloatNegINF; - bool keepData = false; + //Vector3 trans = TOVECTOR3(tm.GetTrans()); + //Quaternion rot = TOQUAT( Quat(tm), true ); - NiTransformControllerRef control = new NiTransformController(); - NiTransformInterpolatorRef interp = new NiTransformInterpolator(); - ninode->AddController(StaticCast<NiTimeController>(control)); - control->SetInterpolator(StaticCast<NiInterpolator>(interp)); + NiNodeRef ninode = ne.getNode( node->GetName() ); + if (setTM) { + trans = TOVECTOR3(tm.GetTrans()); + rot = TOQUAT( Quat(tm), true ); + } + + NiKeyframeDataRef data; + + if (Exporter::mNifVersionInt < VER_10_2_0_0) + { + NiKeyframeControllerRef control = new NiKeyframeController(); + Exporter::InitializeTimeController(control, ninode); + data = new NiKeyframeData(); + control->SetData(data); + timeControl = StaticCast<NiTimeController>(control); + } + else + { + NiTransformControllerRef control = new NiTransformController(); + Exporter::InitializeTimeController(control, ninode); + + NiTransformInterpolatorRef interp = new NiTransformInterpolator(); + data = new NiTransformData(); + control->SetInterpolator(StaticCast<NiInterpolator>(interp)); + + interp->SetTranslation(trans); + interp->SetScale(scale); + interp->SetRotation(rot); + interp->SetData(data); + + timeControl = StaticCast<NiTimeController>(control); + } + timeControl->SetStartTime( 0.0f ); + timeControl->SetStopTime( FrameToTime( range.Duration()-1 ) ); //if (validity.InInterval(range)) //{ @@ -245,8 +674,6 @@ bool AnimationExport::exportController(INode *node) //} //else { - NiTransformDataRef data = new NiTransformData(); - if (Control *c = tmCont->GetPositionController()) { int nkeys = 0; @@ -334,6 +761,7 @@ bool AnimationExport::exportController(INode *node) nkeys += GetKeys<QuatKey, IBezQuatKey>(c, keys, range); data->SetQuatRotateKeys(keys); } else if (c->ClassID() == Class_ID(EULER_CONTROL_CLASS_ID,0)) { + data->SetRotateType(XYZ_ROTATION_KEY); if (Control *x = c->GetXController()){ vector<FloatKey> keys; if (x->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { @@ -351,7 +779,7 @@ bool AnimationExport::exportController(INode *node) } data->SetXRotateKeys(keys); } - if (Control *y = c->GetXController()) { + if (Control *y = c->GetYController()) { vector<FloatKey> keys; if (y->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { nkeys += GetKeys<FloatKey, ILinFloatKey>(y, keys, range); @@ -422,21 +850,49 @@ bool AnimationExport::exportController(INode *node) //scale = Average(GetScale(tm)); } } + // only add transform data object if data actually is present - if (keepData) { - interp->SetData(data); + if (!keepData) { + ninode->RemoveController(timeControl); + timeControl = NULL; + } else { + objRefs.insert( StaticCast<NiAVObject>(ninode) ); } - 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); } } } + return timeControl; +} + +bool AnimationExport::exportController(INode *node) +{ + bool ok = true; + + bool keepTM = false; + if (seq->GetTargetName() == node->GetName()) { + keepTM = true; + } + + NiTimeControllerRef control = exportController( node, range, keepTM ); + if (control != NULL) + { + NiSingleInterpolatorControllerRef interpControl = DynamicCast<NiSingleInterpolatorController>(control); + if (interpControl) { + // Get Priority from node + float priority; + npGetProp(node, NP_ANM_PRI, priority, Exporter::mDefaultPriority); + seq->AddInterpolator(StaticCast<NiSingleInterpolatorController>(control), priority); + } + else + { + seq->AddController(control); + } + + NiObjectNETRef target = control->GetTarget(); + // now remove temporary controller + target->RemoveController(StaticCast<NiTimeController>(control)); + } + for (int i=0, n=node->NumberOfChildren(); ok && i<n; ++i) { INode *child = node->GetChildNode(i); diff --git a/NifExport/Coll.cpp b/NifExport/Coll.cpp index 230687f..39a4c81 100755 --- a/NifExport/Coll.cpp +++ b/NifExport/Coll.cpp @@ -463,9 +463,10 @@ bhkSphereRepShapeRef Exporter::makeTriStripsShape(INode *node, const Matrix3& tm for (int i=0; i<mesh->getNumFaces(); i++) addFace(tris, verts, vnorms, i, vi, mesh, sm); - TriStrips strips; - strippify(strips, verts, vnorms, tris); - NiTriStripsDataRef data = makeTriStripsData(strips); + //TriStrips strips; + //strippify(strips, verts, vnorms, tris); + //NiTriStripsDataRef data = makeTriStripsData(strips); + NiTriStripsDataRef data = new NiTriStripsData(tris, false); data->SetVertices(verts); data->SetNormals(vnorms); diff --git a/NifExport/Config.cpp b/NifExport/Config.cpp index 1ff4721..0bc19ce 100755 --- a/NifExport/Config.cpp +++ b/NifExport/Config.cpp @@ -68,6 +68,17 @@ void Exporter::writeConfig(Interface *i) SetIniValue(NifExportSection, "SkeletonOnly", mSkeletonOnly, iniName); SetIniValue(NifExportSection, "Cameras", mExportCameras, iniName); SetIniValue(NifExportSection, "GenerateBoneCollision", mGenerateBoneCollision, iniName); + + SetIniValue(NifExportSection, "ExportTransforms", mExportTransforms, iniName); + SetIniValue<int>(NifExportSection, "ExportType", mExportType, iniName); + SetIniValue<float>(KfExportSection, "Priority", mDefaultPriority, iniName); + + SetIniValue(NifExportSection, "MultiplePartitions", mMultiplePartitions, iniName); + SetIniValue<int>(NifExportSection, "BonesPerVertex", mBonesPerVertex, iniName); + SetIniValue<int>(KfExportSection, "BonesPerPartition", mBonesPerPartition, iniName); + SetIniValue(NifExportSection, "UseTimeTags", mUseTimeTags, iniName); + + SetIniValue(NifExportSection, "AllowAccum", mAllowAccum, iniName); } } @@ -123,7 +134,17 @@ void Exporter::readConfig(Interface *i) mSkeletonOnly = GetIniValue(NifExportSection, "SkeletonOnly", false, iniName); mExportCameras = GetIniValue(NifExportSection, "Cameras", false, iniName); mGenerateBoneCollision = GetIniValue(NifExportSection, "GenerateBoneCollision", false, iniName); - + + mExportTransforms = GetIniValue(KfExportSection, "Transforms", true, iniName); + mDefaultPriority = GetIniValue<float>(KfExportSection, "Priority", 0.0f, iniName); + mExportType = ExportType(GetIniValue<int>(NifExportSection, "ExportType", NIF_WO_ANIM, iniName)); + + mMultiplePartitions = GetIniValue(NifExportSection, "MultiplePartitions", false, iniName); + mBonesPerVertex = GetIniValue<int>(NifExportSection, "BonesPerVertex", 4, iniName); + mBonesPerPartition = GetIniValue<int>(KfExportSection, "BonesPerPartition", 20, iniName); + + mUseTimeTags = GetIniValue(NifExportSection, "UseTimeTags", false, iniName); + mAllowAccum = GetIniValue(NifExportSection, "AllowAccum", true, iniName); } } diff --git a/NifExport/DllEntry.cpp b/NifExport/DllEntry.cpp index 8907fa3..2443ecc 100755 --- a/NifExport/DllEntry.cpp +++ b/NifExport/DllEntry.cpp @@ -60,7 +60,7 @@ __declspec( dllexport ) const TCHAR* LibDescription() //TODO: Must change this number when adding a new class __declspec( dllexport ) int LibNumberClasses() { - return 2; + return 1; } // This function returns the number of plug-in classes this DLL diff --git a/NifExport/Exporter.cpp b/NifExport/Exporter.cpp index 8bdf74b..829eb69 100755 --- a/NifExport/Exporter.cpp +++ b/NifExport/Exporter.cpp @@ -25,12 +25,20 @@ bool Exporter::mRemoveUnreferencedBones=false; bool Exporter::mSortNodesToEnd=false; string Exporter::mGameName = "User"; string Exporter::mNifVersion = "20.0.0.5"; +int Exporter::mNifVersionInt = VER_20_0_0_5; 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::ExportType Exporter::mExportType = NIF_WO_ANIM; +bool Exporter::mMultiplePartitions=false; +int Exporter::mBonesPerVertex = 4; +int Exporter::mBonesPerPartition = 20; +bool Exporter::mUseTimeTags = false; +bool Exporter::mAutoDetect = true; +bool Exporter::mAllowAccum = true; Exporter::Exporter(Interface *i, AppSettings *appSettings) : mI(i), mAppSettings(appSettings) @@ -45,6 +53,10 @@ Exporter::Result Exporter::doExport(NiNodeRef &root, INode *node) int nifVersion = GetVersion(Exporter::mNifVersion); mIsBethesda = (nifVersion == VER_20_0_0_5 || nifVersion == VER_20_0_0_4) && (Exporter::mNifUserVersion == 11); + if (mUseTimeTags && nifVersion >= VER_20_0_0_4) { + throw runtime_error("Time tag sequences are not supported for version 20.0.0.4 or higher."); + } + CalcBoundingBox(node, mBoundingBox); if (mSkeletonOnly && mIsBethesda) @@ -145,10 +157,17 @@ Exporter::Result Exporter::exportNodes(NiNodeRef &parent, INode *node) } else if (!mSkeletonOnly) { - newParent = (mExportExtraNodes) ? makeNode(nodeParent, node, local) : nodeParent; - - Result result; - result = exportMesh(newParent, node, t); + if (mExportType != NIF_WO_ANIM && isNodeTracked(node)) { + // Create Node + Accum if has Start Track + newParent = createAccumNode( makeNode(nodeParent, node, local) , node); + } else if ( mExportExtraNodes || (mExportType != NIF_WO_ANIM && isNodeKeyed(node) ) ) { + // Create node if using Extra Nodes or if exporting with anim and node has key values + newParent = makeNode(nodeParent, node, local); + } else { + // Else dont create a node + newParent = nodeParent; + } + Result result = exportMesh(newParent, node, t); if (result != Ok) return result; } diff --git a/NifExport/Exporter.h b/NifExport/Exporter.h index 8d5b2f0..365b5d3 100755 --- a/NifExport/Exporter.h +++ b/NifExport/Exporter.h @@ -1,12 +1,19 @@ #ifndef __EXPORTER_H__ #define __EXPORTER_H__ +namespace Niflib +{ + class NiTimeController; + class NiControllerManager; + class NiControllerSequence; +} using namespace Niflib; class BitmapTex; class AppSettings; class StdMat2; + class Exporter { @@ -20,6 +27,17 @@ public: Skip }; + enum ExportType + { + NIF_WO_ANIM = 0, + NIF_WO_KF = 1, + SINGLE_KF_WITH_NIF = 2, + SINGLE_KF_WO_NIF = 3, + MULTI_KF_WITH_NIF = 4, + MULTI_KF_WO_NIF = 5, + NIF_WITH_MGR = 6, + }; + // Callback for post-processing instructions struct NiCallback { @@ -52,13 +70,20 @@ public: static bool mSortNodesToEnd; static string mGameName; static string mNifVersion; + static int mNifVersionInt; static int mNifUserVersion; static bool mSkeletonOnly; static bool mExportCameras; static bool mGenerateBoneCollision; - static bool mExportTransforms; static float mDefaultPriority; + static ExportType mExportType; + static bool mMultiplePartitions; + static int mBonesPerVertex; + static int mBonesPerPartition; + static bool mUseTimeTags; + static bool mAutoDetect; + static bool mAllowAccum; Exporter(Interface *i, AppSettings *appSettings); @@ -103,6 +128,7 @@ public: typedef std::map<int, FaceGroup> FaceGroups; typedef std::map<string, NiNodeRef> NodeMap; typedef std::list<NiCallback*> CallbackList; + typedef std::list<Ref<NiNode> > NodeList; Interface *mI; NiNodeRef mNiRoot; @@ -111,6 +137,7 @@ public: CallbackList mPostExportCallbacks; bool mIsBethesda; Box3 mBoundingBox; + NodeList mAnimationRoots; Result exportNodes(NiNodeRef &root, INode *node); Result exportCollision(NiNodeRef &root, INode *node); @@ -184,6 +211,11 @@ public: /* animation export */ Result doAnimExport(Ref<NiControllerSequence> root); + Result doAnimExport(Ref<NiControllerManager> ctrl, INode *node); + bool isNodeTracked(INode *node); + bool isNodeKeyed(INode *node); + Ref<NiTimeController> CreateController(INode *node, Interval range); + static void InitializeTimeController(Ref<NiTimeController> ctrl, NiNodeRef parent); /* misc export */ bool exportUPB(NiNodeRef &root, INode *node); @@ -191,6 +223,9 @@ public: void sortNodes(NiNodeRef node); NiNodeRef exportBone(NiNodeRef parent, INode *node); Result exportLight(NiNodeRef root, INode *node, GenLight* light); + void getChildNodes(INode *node, vector<NiNodeRef>&list); + + NiNodeRef createAccumNode(NiNodeRef parent, INode *node); }; #endif diff --git a/NifExport/KfExport.cpp b/NifExport/KfExport.cpp index 4102b0c..795136f 100644 --- a/NifExport/KfExport.cpp +++ b/NifExport/KfExport.cpp @@ -82,7 +82,7 @@ static BOOL CALLBACK KfExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam 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)); + SetDlgItemText(hWnd, IDC_ED_PRIORITY, FormatText("%.1f", Exporter::mDefaultPriority)); string selection = Exporter::mGameName; string version = Exporter::mNifVersion; diff --git a/NifExport/Mesh.cpp b/NifExport/Mesh.cpp index 5ed4f0b..1601f41 100755 --- a/NifExport/Mesh.cpp +++ b/NifExport/Mesh.cpp @@ -27,7 +27,6 @@ Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue Mesh *mesh = &tri->GetMesh(); - // Note that calling setVCDisplayData will clear things like normals so we set this up first vector<Color4> vertColors; if (mVertexColors) @@ -35,8 +34,7 @@ Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue bool hasvc = false; if (mesh->mapSupport(MAP_ALPHA)) { - mesh->setVCDisplayData(MAP_ALPHA); - int n = mesh->getNumVertCol(); + mesh->setVCDisplayData(MAP_ALPHA); int n = mesh->getNumVertCol(); if (n > vertColors.size()) vertColors.assign(n, Color4(1.0f, 1.0f, 1.0f, 1.0f)); VertColor *vertCol = mesh->vertColArray; @@ -133,15 +131,13 @@ NiTriBasedGeomRef Exporter::makeMesh(NiNodeRef &parent, Mtl *mtl, FaceGroup &grp if (exportStrips) { shape = new NiTriStrips(); - data = new NiTriStripsData(); + data = new NiTriStripsData(grp.faces); } else { shape = new NiTriShape(); - data = new NiTriShapeData(); + data = new NiTriShapeData(grp.faces); } - - data->SetTriangles(grp.faces); - data->SetVertices(grp.verts); - data->SetNormals(grp.vnorms); + data->SetVertices(grp.verts); + data->SetNormals(grp.vnorms); if (grp.uvs.size() > 0) { @@ -285,6 +281,9 @@ struct SkinInstance : public Exporter::NiCallback // Bone to weight map BoneWeightList boneWeights; + Matrix3 bone_init_tm; + Matrix3 node_init_tm; + SkinInstance(Exporter *Owner) : owner(Owner) {} virtual ~SkinInstance() {} virtual Exporter::Result execute(); @@ -319,6 +318,9 @@ bool Exporter::makeSkin(NiTriBasedGeomRef shape, INode *node, FaceGroup &grp, Ti SkinInstance* si = new SkinInstance(this); mPostExportCallbacks.push_back(si); + skin->GetSkinInitTM(node, si->bone_init_tm, false); + skin->GetSkinInitTM(node, si->node_init_tm, true); + si->shape = shape; // Get bone references (may not actually exist in proper structure at this time) @@ -369,26 +371,29 @@ bool Exporter::makeSkin(NiTriBasedGeomRef shape, INode *node, FaceGroup &grp, Ti Exporter::Result SkinInstance::execute() { - shape->BindSkin(boneList); + shape->BindSkin(boneList, false); uint bone = 0; for (BoneWeightList::iterator bitr = boneWeights.begin(); bitr != boneWeights.end(); ++bitr, ++bone) { shape->SetBoneWeights(bone, (*bitr)); } - shape->GenHardwareSkinInfo(); + if (Exporter::mMultiplePartitions) + shape->GenHardwareSkinInfo(Exporter::mBonesPerPartition, Exporter::mBonesPerVertex); + else + shape->GenHardwareSkinInfo(0, 0); + + //NiSkinInstanceRef skinInst = shape->GetSkinInstance(); + //NiSkinDataRef skinData = skinInst->GetSkinData(); + //Matrix44 tm = skinData->GetOverallTransform(); + //Matrix3 otm = TOMATRIX3(tm); + //Matrix3 stm = TOMATRIX3(shape->GetLocalTransform()); + //Matrix3 btm = Inverse(bone_init_tm) * stm; + + //Matrix3 asdf = btm * otm; + //skinData->SetOverallTransform(TOMATRIX4(btm)); + return Exporter::Ok; } -static void InitializeTimeController(NiTimeControllerRef ctrl, NiNodeRef parent) -{ - ctrl->SetFrequency(1.0f); - ctrl->SetStartTime(FloatINF); - ctrl->SetStopTime(FloatNegINF); - ctrl->SetPhase(0.0f); - ctrl->SetFlags(0x0C); - ctrl->SetTarget( parent ); - parent->AddController(DynamicCast<NiTimeController>(ctrl)); -} - static void FillBoneController(Exporter* exporter, NiBSBoneLODControllerRef boneCtrl, INode *node) { for (int i=0; i<node->NumberOfChildren(); i++) @@ -552,25 +557,35 @@ NiNodeRef Exporter::exportBone(NiNodeRef parent, INode *node) } } + if (mExportType != NIF_WO_ANIM && isNodeTracked(node)) { + NiNodeRef accumNode = createAccumNode(newParent, node); - if (wildmatch("Bip??", node->GetName())) - { - NiNodeRef accumNode = new NiNode(); - accumNode->SetName(FormatString("%s NonAccum", node->GetName())); - accumNode->SetLocalTransform(Matrix44::IDENTITY); - newParent->AddChild(DynamicCast<NiAVObject>(accumNode)); - - // Transfer + // Transfer collision object to accum and create blend on accum if (mIsBethesda) { InitializeTimeController(new bhkBlendController(), accumNode); accumNode->SetCollisionObject(newParent->GetCollisionObject()); newParent->SetCollisionObject( NiCollisionObjectRef() ); - } - InitializeTimeController(new NiTransformController(), accumNode); - + } newParent = accumNode; + } else if (wildmatch("Bip??", node->GetName())) { + newParent = createAccumNode(newParent, node); + } + } + else // normal handling + { + // Check for Accum Root using + if (mExportType == NIF_WO_KF) + { + // Add controllers + if (Exporter::mAllowAccum) { + newParent = createAccumNode(newParent, node); + } + } + else if (mExportType != NIF_WO_ANIM && isNodeTracked(node)) + { + newParent = createAccumNode(newParent, node); } } return newParent; -} \ No newline at end of file +} diff --git a/NifExport/NifExport.cpp b/NifExport/NifExport.cpp index 4a7be3b..ee83d42 100755 --- a/NifExport/NifExport.cpp +++ b/NifExport/NifExport.cpp @@ -2,6 +2,9 @@ #include "AppSettings.h" #include "niutils.h" #include <io.h> +#include "obj/NiControllerManager.h" +#include "obj/NiTimeController.h" +#include "obj/NiControllerSequence.h" using namespace Niflib; @@ -15,6 +18,8 @@ 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") @@ -55,7 +60,7 @@ class NifExportClassDesc : public ClassDesc2 static NifExportClassDesc NifExportDesc; ClassDesc2* GetNifExportDesc() { return &NifExportDesc; } - +extern list<NiObjectRef> GetAllObjectsByType( NiObjectRef const & root, const Type & type ); @@ -88,14 +93,13 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA CheckDlgButton(hWnd, IDC_CHK_REMAP, Exporter::mRemapIndices); CheckDlgButton(hWnd, IDC_CHK_EXTRA, Exporter::mExportExtraNodes); - CheckDlgButton(hWnd, IDC_CHK_SKIN, Exporter::mExportSkin); CheckDlgButton(hWnd, IDC_CHK_UPB, Exporter::mUserPropBuffer); CheckDlgButton(hWnd, IDC_CHK_HIER, Exporter::mFlattenHierarchy); CheckDlgButton(hWnd, IDC_CHK_REM_BONES, Exporter::mRemoveUnreferencedBones); CheckDlgButton(hWnd, IDC_CHK_SORTNODES, Exporter::mSortNodesToEnd); CheckDlgButton(hWnd, IDC_CHK_SKEL_ONLY, Exporter::mSkeletonOnly); CheckDlgButton(hWnd, IDC_CHK_CAMERA, Exporter::mExportCameras); - CheckDlgButton(hWnd, IDC_CHK_BONE_COLL, Exporter::mGenerateBoneCollision); + CheckDlgButton(hWnd, IDC_CHK_BONE_COLL, Exporter::mGenerateBoneCollision); string selection = Exporter::mGameName; string version = Exporter::mNifVersion; @@ -105,6 +109,30 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA 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())); + CheckDlgButton(hWnd, IDC_CHK_AUTO_DETECT, Exporter::mAutoDetect); + + // Populate Type options + SendDlgItemMessage(hWnd, IDC_CBO_ANIM_TYPE, CB_ADDSTRING, Exporter::NIF_WO_ANIM, LPARAM("NIF w/o Anim")); + SendDlgItemMessage(hWnd, IDC_CBO_ANIM_TYPE, CB_ADDSTRING, Exporter::NIF_WO_KF, LPARAM("NIF with Anim")); + SendDlgItemMessage(hWnd, IDC_CBO_ANIM_TYPE, CB_ADDSTRING, Exporter::SINGLE_KF_WITH_NIF, LPARAM("Single KF with NIF")); + SendDlgItemMessage(hWnd, IDC_CBO_ANIM_TYPE, CB_ADDSTRING, Exporter::SINGLE_KF_WO_NIF, LPARAM("Single KF w/o NIF")); + SendDlgItemMessage(hWnd, IDC_CBO_ANIM_TYPE, CB_ADDSTRING, Exporter::MULTI_KF_WITH_NIF, LPARAM("Multi KF with NIF")); + SendDlgItemMessage(hWnd, IDC_CBO_ANIM_TYPE, CB_ADDSTRING, Exporter::MULTI_KF_WO_NIF, LPARAM("Multi KF w/o NIF")); + SendDlgItemMessage(hWnd, IDC_CBO_ANIM_TYPE, CB_ADDSTRING, Exporter::NIF_WITH_MGR, LPARAM("NIF w/ Manager")); + + SendDlgItemMessage(hWnd, IDC_CBO_ANIM_TYPE, CB_SETCURSEL, WPARAM(Exporter::mExportType), 0); + + CheckDlgButton(hWnd, IDC_CHK_TRANSFORMS2, Exporter::mExportTransforms); + SetDlgItemText(hWnd, IDC_ED_PRIORITY2, FormatText("%.1f", Exporter::mDefaultPriority)); + CheckDlgButton(hWnd, IDC_CHK_USE_TIME_TAGS, Exporter::mUseTimeTags); + + // Skin + CheckDlgButton(hWnd, IDC_CHK_SKIN, Exporter::mExportSkin); + CheckDlgButton(hWnd, IDC_CHK_SKINPART, Exporter::mMultiplePartitions); + SetDlgItemText(hWnd, IDC_ED_BONES_PART, FormatText("%d", Exporter::mBonesPerPartition)); + SetDlgItemText(hWnd, IDC_ED_BONES_VERTEX, FormatText("%d", Exporter::mBonesPerVertex)); + + CheckDlgButton(hWnd, IDC_CHK_ALLOW_ACCUM, Exporter::mAllowAccum); TSTR tmp; tmp.printf("%.4f", Exporter::mWeldThresh); @@ -147,7 +175,6 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA Exporter::mRemapIndices = IsDlgButtonChecked(hWnd, IDC_CHK_REMAP); Exporter::mExportExtraNodes = IsDlgButtonChecked(hWnd, IDC_CHK_EXTRA); - Exporter::mExportSkin = IsDlgButtonChecked(hWnd, IDC_CHK_SKIN); Exporter::mUserPropBuffer = IsDlgButtonChecked(hWnd, IDC_CHK_UPB); Exporter::mFlattenHierarchy = IsDlgButtonChecked(hWnd, IDC_CHK_HIER); Exporter::mRemoveUnreferencedBones = IsDlgButtonChecked(hWnd, IDC_CHK_REM_BONES); @@ -155,13 +182,30 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA Exporter::mSkeletonOnly = IsDlgButtonChecked(hWnd, IDC_CHK_SKEL_ONLY); Exporter::mExportCameras = IsDlgButtonChecked(hWnd, IDC_CHK_CAMERA); Exporter::mGenerateBoneCollision = IsDlgButtonChecked(hWnd, IDC_CHK_BONE_COLL); - + + Exporter::mExportTransforms = IsDlgButtonChecked(hWnd, IDC_CHK_TRANSFORMS2); + Exporter::mUseTimeTags = IsDlgButtonChecked(hWnd, IDC_CHK_USE_TIME_TAGS); + + Exporter::mExportType = Exporter::ExportType(SendDlgItemMessage(hWnd, IDC_CBO_ANIM_TYPE, CB_GETCURSEL, 0, 0)); + GetDlgItemText(hWnd, IDC_ED_PRIORITY2, tmp, MAX_PATH); + Exporter::mDefaultPriority = atof(tmp); + GetDlgItemText(hWnd, IDC_ED_TEXPREFIX, tmp, MAX_PATH); Exporter::mTexPrefix = tmp; GetDlgItemText(hWnd, IDC_ED_WELDTHRESH, tmp, MAX_PATH); Exporter::mWeldThresh = atof(tmp); + Exporter::mAllowAccum = IsDlgButtonChecked(hWnd, IDC_CHK_ALLOW_ACCUM); + + // Skin + Exporter::mExportSkin = IsDlgButtonChecked(hWnd, IDC_CHK_SKIN); + Exporter::mMultiplePartitions = IsDlgButtonChecked(hWnd, IDC_CHK_SKINPART); + GetDlgItemText(hWnd, IDC_ED_BONES_PART, tmp, MAX_PATH); + Exporter::mBonesPerPartition = atoi(tmp); + GetDlgItemText(hWnd, IDC_ED_BONES_VERTEX, tmp, MAX_PATH); + Exporter::mBonesPerVertex = atoi(tmp); + GetDlgItemText(hWnd, IDC_CB_GAME, tmp, MAX_PATH); if (AppSettings *appSettings = FindAppSetting(tmp)) { @@ -171,6 +215,7 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA GetDlgItemText(hWnd, IDC_CB_USER_VERSION, tmp, MAX_PATH); Exporter::mNifUserVersion = strtol(tmp, &end, 0); } + Exporter::mAutoDetect = IsDlgButtonChecked(hWnd, IDC_CHK_AUTO_DETECT); EndDialog(hWnd, imp->mDlgResult=IDOK); close = true; @@ -217,7 +262,21 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA //--- NifExport ------------------------------------------------------- NifExport::NifExport() { - + 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); } NifExport::~NifExport() @@ -227,12 +286,17 @@ NifExport::~NifExport() int NifExport::ExtCount() { - return 1; + return 2; } const TCHAR *NifExport::Ext(int n) { - return _T("nif"); + switch (n) + { + case 0: return _T("KF"); + case 1: return _T("NIF"); + } + return NULL; } const TCHAR *NifExport::LongDesc() @@ -242,7 +306,7 @@ const TCHAR *NifExport::LongDesc() const TCHAR *NifExport::ShortDesc() { - return _T("Gamebryo File"); + return shortDescription; } const TCHAR *NifExport::AuthorName() @@ -285,6 +349,10 @@ int NifExport::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL { try { + TCHAR path[MAX_PATH]; + GetFullPathName(name, MAX_PATH, path, NULL); + PathRenameExtension(path, ".nif"); + // read application settings AppSettings::Initialize(i); @@ -304,10 +372,11 @@ int NifExport::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL AppSettings *appSettings = NULL; if (iniNameIsValid) { - string fname = name; + string fname = path; // 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")) { + Exporter::mAutoDetect = true; // Scan Root paths for (AppSettingsMap::iterator itr = TheAppSettings.begin(), end = TheAppSettings.end(); itr != end; ++itr){ if ((*itr).IsFileInRootPaths(fname)) { @@ -316,6 +385,7 @@ int NifExport::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL } } } else { + Exporter::mAutoDetect = false; appSettings = FindAppSetting(curapp); } } @@ -340,12 +410,18 @@ int NifExport::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL appSettings = FindAppSetting(Exporter::mGameName); if (appSettings == NULL && !TheAppSettings.empty()) appSettings = &TheAppSettings.front(); + + if (Exporter::mAutoDetect){ + SetIniValue<string>(NifExportSection, "CurrentApp", "AUTO", iniName); + } else { + SetIniValue<string>(NifExportSection, "CurrentApp", appSettings->Name, iniName); + } + appSettings->NiVersion = Exporter::mNifVersion; appSettings->NiUserVersion = Exporter::mNifUserVersion; appSettings->WriteSettings(i); } - int nifVersion = VER_20_0_0_5; int nifUserVer = Exporter::mNifUserVersion; @@ -355,6 +431,17 @@ int NifExport::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL if (!IsVersionSupported(nifVersion)) throw exception(FormatString("Version '%s' is not a supported version.").c_str()); } + Exporter::mNifVersionInt = nifVersion; + + Exporter::ExportType exportType = Exporter::mExportType; + + // Hack so MW exports cleaner. Basically write tree without NiControllerManager + if ( nifVersion <= VER_10_0_1_0 + && (Exporter::mExportType != Exporter::NIF_WO_ANIM && Exporter::mExportType != Exporter::NIF_WITH_MGR) + ) + { + Exporter::mExportType = Exporter::NIF_WO_KF; + } Exporter::mSelectedOnly = (options&SCENE_EXPORT_SELECTED) != 0; Exporter exp(i, appSettings); @@ -365,7 +452,67 @@ int NifExport::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL if (result!=Exporter::Ok) throw exception("Unknown error."); - WriteNifTree(name, NiObjectRef(root), nifVersion, nifUserVer); + if (exportType == Exporter::NIF_WO_ANIM || exportType == Exporter::NIF_WITH_MGR) + { + WriteNifTree(path, NiObjectRef(root), nifVersion, nifUserVer); + } + else + { + Niflib::ExportOptions export_type = EXPORT_NIF; + switch (exportType) { + case Exporter::SINGLE_KF_WITH_NIF: export_type = EXPORT_NIF_KF; break; + case Exporter::SINGLE_KF_WO_NIF: export_type = EXPORT_KF; break; + case Exporter::MULTI_KF_WITH_NIF: export_type = EXPORT_NIF_KF_MULTI; break; + case Exporter::MULTI_KF_WO_NIF: export_type = EXPORT_KF_MULTI; break; + } + + Niflib::NifGame game = KF_MW; + if (nifVersion <= VER_4_0_0_2) { + game = KF_MW; + } else if (nifVersion <= VER_20_0_0_4) { + game = KF_DAOC; + } else { + game = KF_CIV4; + } + + // + //if (nifVersion <= VER_10_0_1_0) { + + // // Now search and locate newer timeframe controllers and convert to keyframecontrollers + // list<NiObjectRef> mgrs = GetAllObjectsByType( root, NiControllerManager::TypeConst() ); + // for ( list<NiObjectRef>::iterator it = mgrs.begin(); it != mgrs.end(); ++it) { + // if (NiControllerManagerRef mgr = DynamicCast<NiControllerManager>(*it)) { + // NiObjectNETRef target = mgr->GetTarget(); + // target->RemoveController( StaticCast<NiTimeController>(mgr) ); + // vector<NiControllerSequenceRef> seqs = mgr->GetControllerSequences(); + // for (vector<NiControllerSequenceRef>::iterator itr = seqs.begin(); itr != seqs.end(); ++itr) { + // NiControllerSequenceRef seq = (*itr); + // MergeNifTrees(DynamicCast<NiNode>(target), seq, nifVersion, nifUserVer); + // } + // } + // } + //} + + WriteFileGroup(path, StaticCast<NiObject>(root), nifVersion, nifUserVer, export_type, game); +/* + for (NodeList::iterator itr = mAnimationRoots.begin(); itr != mAnimationRoots.end(); ++itr){ + list<NiTimeControllerRef> ctlrs = (*itr)->GetControllers(); + if ( NiControllerManagerRef mgr = SelectFirstObjectOfType<NiControllerManager>( ctlrs ) ) { + (*itr)->RemoveController( mgr ); + + vector<NiControllerSequenceRef> seqs = mgr->GetControllerSequences(); + WriteNifTree() + } + } + + if (mExportType == SINGLE_KF_WITH_NIF || mExportType == MULTI_KF_WITH_NIF) + { + GetFullPathName(name, MAX_PATH, path, NULL); + PathRenameExtension(path, ".nif"); + WriteNifTree(path, NiObjectRef(root), nifVersion, nifUserVer); + } +*/ + } } catch (exception &e) diff --git a/NifExport/NifExport.rc b/NifExport/NifExport.rc index e9f8667..c9eb4b7 100755 --- a/NifExport/NifExport.rc +++ b/NifExport/NifExport.rc @@ -98,44 +98,59 @@ BEGIN 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 +IDD_NIF_PANEL DIALOGEX 0, 0, 229, 291 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_TOOLWINDOW CAPTION "Export Nif" FONT 8, "MS Sans Serif", 0, 0, 0x1 BEGIN - GROUPBOX "Export:",IDC_STATIC,7,7,81,107 - CONTROL "&Hidden Nodes",IDC_CHK_HIDDEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,17,67,10 - CONTROL "Co&llision",IDC_CHK_COLL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,29,67,10 - CONTROL "&Vertex Colors",IDC_CHK_VCOLORS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,41,67,10 - CONTROL "Skin Modifier",IDC_CHK_SKIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,53,67,10 - CONTROL "&Animation",IDC_CHK_ANIMATION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,65,67,10 - CONTROL "Furniture &Markers",IDC_CHK_FURN,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,14,101,67,10 - CONTROL "&Lights",IDC_CHK_LIGHTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,77,67,10 - CONTROL "Cameras",IDC_CHK_CAMERA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,89,67,10 - GROUPBOX "Behaviors:",IDC_STATIC,94,7,104,107 - CONTROL "Generate &Strips",IDC_CHK_STRIPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,17,88,10 - CONTROL "Extra Nodes on Mesh",IDC_CHK_EXTRA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,28,88,11 - CONTROL "Add User Prop Buffer",IDC_CHK_UPB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,40,88,11 - CONTROL "Flatten Hierarchy",IDC_CHK_HIER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,52,88,10 - CONTROL "Remove Extra Bones",IDC_CHK_REM_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,64,88,10 - CONTROL "Sort Nodes",IDC_CHK_SORTNODES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,76,88,10 - CONTROL "&Remap Indices",IDC_CHK_REMAP,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,102,100,88,10 - CONTROL "Skeleton Only",IDC_CHK_SKEL_ONLY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,88,71,10 - LTEXT "Default Texture &Prefix:",IDC_STATIC,7,127,71,8 - EDITTEXT IDC_ED_TEXPREFIX,7,138,190,12,ES_AUTOHSCROLL - LTEXT "Game",IDC_STATIC,7,154,66,8 - COMBOBOX IDC_CB_GAME,7,165,105,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Version",IDC_STATIC,117,154,39,8 - EDITTEXT IDC_CB_VERSION,117,165,45,12,ES_AUTOHSCROLL - LTEXT "User",IDC_STATIC,167,154,25,8 - EDITTEXT IDC_CB_USER_VERSION,167,165,30,12,ES_AUTOHSCROLL - DEFPUSHBUTTON "&Export",IDOK,5,182,34,14 - PUSHBUTTON "&Cancel",IDCANCEL,45,182,33,14 - LTEXT "http://www.niftools.org",IDC_LBL_LINK,103,182,95,14,SS_NOTIFY | SS_CENTERIMAGE - EDITTEXT IDC_ED_WELDTHRESH,185,118,11,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | WS_DISABLED - LTEXT "Auto-&Weld",IDC_LBL_WELDTHRESH,175,118,8,8,NOT WS_VISIBLE | WS_DISABLED - CONTROL "Gen. Bone Collision",IDC_CHK_BONE_COLL,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,100,118,73,10 + GROUPBOX "General Options",IDC_STATIC,4,7,220,60 + LTEXT "Game",IDC_STATIC,10,16,66,8 + COMBOBOX IDC_CB_GAME,10,25,105,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Version",IDC_STATIC,118,16,39,8 + EDITTEXT IDC_CB_VERSION,118,25,41,12,ES_AUTOHSCROLL + LTEXT "User",IDC_STATIC,163,16,25,8 + EDITTEXT IDC_CB_USER_VERSION,162,25,22,12,ES_AUTOHSCROLL + CONTROL "Auto Detect",IDC_CHK_AUTO_DETECT,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,188,23,35,16 + LTEXT "Default Texture &Prefix:",IDC_STATIC,10,40,71,8 + EDITTEXT IDC_ED_TEXPREFIX,9,50,208,12,ES_AUTOHSCROLL + GROUPBOX "Export:",IDC_STATIC,4,70,220,50 + CONTROL "&Hidden Nodes",IDC_CHK_HIDDEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,81,67,10 + CONTROL "Skeleton Only",IDC_CHK_SKEL_ONLY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,93,82,10 + CONTROL "Co&llision",IDC_CHK_COLL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,105,67,10 + CONTROL "Cameras",IDC_CHK_CAMERA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,120,82,67,10 + CONTROL "&Lights",IDC_CHK_LIGHTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,120,93,67,10 + CONTROL "Furniture &Markers",IDC_CHK_FURN,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,120,105,67,10 + GROUPBOX "Mesh:",IDC_STATIC,4,123,108,73 + CONTROL "Generate &Strips",IDC_CHK_STRIPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,134,82,10 + CONTROL "Extra Nodes on Mesh",IDC_CHK_EXTRA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,145,82,11 + CONTROL "Flatten Hierarchy",IDC_CHK_HIER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,158,82,10 + CONTROL "Remove Extra Bones",IDC_CHK_REM_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,169,82,10 + CONTROL "&Vertex Colors",IDC_CHK_VCOLORS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,181,67,10 + GROUPBOX "Skin Modifier",IDC_STATIC,116,123,108,73 + CONTROL "Export Skin Modifier",IDC_CHK_SKIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,119,134,93,10 + LTEXT "Bones Per Vertex:",IDC_LBL_BONES_VERTEX,120,174,63,8 + EDITTEXT IDC_ED_BONES_VERTEX,195,173,24,12,ES_AUTOHSCROLL + LTEXT "Bones Per Partition:",IDC_LBL_BONES_PART,130,160,62,8 + EDITTEXT IDC_ED_BONES_PART,195,158,24,12,ES_AUTOHSCROLL + CONTROL "Gen. Bone Collision",IDC_CHK_BONE_COLL,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,151,7,73,10 + CONTROL "&Remap Indices",IDC_CHK_REMAP,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,152,7,72,10 + GROUPBOX "Animation",IDC_GRP_ANIMATION,4,196,108,68 + COMBOBOX IDC_CBO_ANIM_TYPE,7,207,85,69,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Transforms",IDC_CHK_TRANSFORMS2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,9,223,67,10 + LTEXT "Priority:",IDC_LBL_PRIORITY2,9,249,23,8 + EDITTEXT IDC_ED_PRIORITY2,37,248,55,12,ES_AUTOHSCROLL + GROUPBOX "Miscellaneous:",IDC_STATIC,115,196,109,68 + CONTROL "Add User Prop Buffer",IDC_CHK_UPB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,125,209,82,11 + CONTROL "Sort Nodes",IDC_CHK_SORTNODES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,125,222,82,10 + LTEXT "Auto-&Weld",IDC_LBL_WELDTHRESH,125,249,47,8,NOT WS_VISIBLE | WS_DISABLED + EDITTEXT IDC_ED_WELDTHRESH,179,247,43,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | WS_DISABLED + DEFPUSHBUTTON "&Export",IDOK,5,270,34,14 + PUSHBUTTON "&Cancel",IDCANCEL,45,270,33,14 + LTEXT "http://www.niftools.org",IDC_LBL_LINK,148,270,76,14,SS_NOTIFY | SS_CENTERIMAGE + CONTROL "Enable Multiple Partitions",IDC_CHK_SKINPART,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,119,147,93,10 + CONTROL "Use Time Tags",IDC_CHK_USE_TIME_TAGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,9,235,96,10 + CONTROL "Add Accum Nodes",IDC_CHK_ALLOW_ACCUM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,125,235,82,10 END @@ -157,10 +172,10 @@ BEGIN IDD_NIF_PANEL, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 198 + LEFTMARGIN, 4 + RIGHTMARGIN, 224 TOPMARGIN, 7 - BOTTOMMARGIN, 196 + BOTTOMMARGIN, 284 END END #endif // APSTUDIO_INVOKED @@ -172,8 +187,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,2,4,0 - PRODUCTVERSION 0,2,4,0 + FILEVERSION 0,2,5,0 + PRODUCTVERSION 0,2,5,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -189,12 +204,12 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "3ds Max Nif Exporter" - VALUE "FileVersion", "0, 2, 4, 0" + VALUE "FileVersion", "0, 2, 5, 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, 4, 0" + VALUE "ProductVersion", "0, 2, 5, 0" END END BLOCK "VarFileInfo" @@ -204,6 +219,19 @@ BEGIN END +///////////////////////////////////////////////////////////////////////////// +// +// Dialog Info +// + +IDD_NIF_PANEL DLGINIT +BEGIN + IDC_CBO_ANIM_TYPE, 0x403, 15, 0 +0x494e, 0x2046, 0x6977, 0x6874, 0x4e20, 0x206f, 0x464b, "\000" + 0 +END + + ///////////////////////////////////////////////////////////////////////////// // // String Table diff --git a/NifExport/NifExport_VC80.vcproj b/NifExport/NifExport_VC80.vcproj index e1997b4..3693d6d 100644 --- a/NifExport/NifExport_VC80.vcproj +++ b/NifExport/NifExport_VC80.vcproj @@ -53,7 +53,7 @@ EnableIntrinsicFunctions="true" FavorSizeOrSpeed="1" OmitFramePointers="true" - AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib;..\NifCommon" + AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib\include;..\NifCommon" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS" StringPooling="true" ExceptionHandling="2" @@ -81,7 +81,7 @@ <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib niflib.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib" OutputFile="c:\3dsmax8\plugins\NifExport.dle" LinkIncremental="1" SuppressStartupBanner="true" @@ -155,7 +155,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/LD /FI"$(ProjectDir)pch.h" /Zm200" Optimization="0" - AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib;..\NifCommon" + AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib\include;..\NifCommon" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS" StringPooling="true" MinimalRebuild="true" @@ -183,7 +183,7 @@ <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib niflibd.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib" OutputFile="c:\3dsmax8\plugins\NifExport.dle" LinkIncremental="2" SuppressStartupBanner="true" @@ -252,7 +252,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/LD /FI"$(ProjectDir)pch.h" /Zm200" Optimization="0" - AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib;..\NifCommon" + AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib\include;..\NifCommon" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS" StringPooling="true" MinimalRebuild="true" @@ -280,7 +280,7 @@ <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib niflibd.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib" OutputFile="c:\3dsmax6\plugins\NifExport.dle" LinkIncremental="2" SuppressStartupBanner="true" @@ -355,7 +355,7 @@ EnableIntrinsicFunctions="true" FavorSizeOrSpeed="1" OmitFramePointers="true" - AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib;..\NifCommon" + AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib\include;..\NifCommon" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS" StringPooling="true" ExceptionHandling="2" @@ -383,7 +383,7 @@ <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib niflib.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib" OutputFile="c:\3dsmax6\plugins\NifExport.dle" LinkIncremental="1" SuppressStartupBanner="true" @@ -463,7 +463,7 @@ EnableIntrinsicFunctions="true" FavorSizeOrSpeed="1" OmitFramePointers="true" - AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib;..\NifCommon" + AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib\include;..\NifCommon" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS" StringPooling="true" ExceptionHandling="2" @@ -491,7 +491,7 @@ <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib niflib.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib" OutputFile="c:\3dsmax7\plugins\NifExport.dle" LinkIncremental="1" SuppressStartupBanner="true" @@ -565,7 +565,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/LD /FI"$(ProjectDir)pch.h" /Zm200" Optimization="0" - AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib;..\NifCommon" + AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib\include;..\NifCommon" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS" StringPooling="true" MinimalRebuild="true" @@ -593,7 +593,7 @@ <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib niflibd.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib" OutputFile="c:\3dsmax7\plugins\NifExport.dle" LinkIncremental="2" SuppressStartupBanner="true" @@ -743,230 +743,6 @@ RelativePath="Util.cpp" > </File> - <Filter - Name="NvTriStrip" - > - <File - RelativePath="NvTriStrip\NvTriStrip.cpp" - > - <FileConfiguration - Name="Release - Max 8|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Debug - Max 8|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Debug - Max 6|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Release - Max 6|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Release - Max 7|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Debug - Max 7|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - </File> - <File - RelativePath="NvTriStrip\NvTriStripObjects.cpp" - > - <FileConfiguration - Name="Release - Max 8|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Debug - Max 8|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Debug - Max 6|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Release - Max 6|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Release - Max 7|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Debug - Max 7|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - </File> - <File - RelativePath="NvTriStrip\VertexCache.cpp" - > - <FileConfiguration - Name="Release - Max 8|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Debug - Max 8|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Debug - Max 6|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Release - Max 6|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Release - Max 7|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Debug - Max 7|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - </File> - </Filter> - <Filter - Name="TriStripper" - > - <File - RelativePath=".\TriStripper\connectivity_graph.cpp" - > - </File> - <File - RelativePath=".\TriStripper\policy.cpp" - > - </File> - <File - RelativePath="TriStripper\tri_stripper.cpp" - > - <FileConfiguration - Name="Release - Max 8|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Debug - Max 8|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Debug - Max 6|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Release - Max 6|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Release - Max 7|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - <FileConfiguration - Name="Debug - Max 7|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="0" - /> - </FileConfiguration> - </File> - </Filter> </Filter> <Filter Name="Header Files" @@ -988,50 +764,6 @@ RelativePath=".\resource.h" > </File> - <Filter - Name="NvTriStrip" - > - <File - RelativePath="NvTriStrip\NvTriStrip.h" - > - </File> - <File - RelativePath="NvTriStrip\NvTriStripObjects.h" - > - </File> - <File - RelativePath="NvTriStrip\VertexCache.h" - > - </File> - </Filter> - <Filter - Name="TriStripper" - > - <File - RelativePath=".\TriStripper\detail\cache_simulator.h" - > - </File> - <File - RelativePath=".\TriStripper\detail\connectivity_graph.h" - > - </File> - <File - RelativePath=".\TriStripper\detail\graph_array.h" - > - </File> - <File - RelativePath=".\TriStripper\detail\heap_array.h" - > - </File> - <File - RelativePath=".\TriStripper\detail\policy.h" - > - </File> - <File - RelativePath=".\TriStripper\detail\types.h" - > - </File> - </Filter> </Filter> <Filter Name="Resource Files" diff --git a/NifExport/Strips.cpp b/NifExport/Strips.cpp index 7ca4f35..a69a666 100755 --- a/NifExport/Strips.cpp +++ b/NifExport/Strips.cpp @@ -1,5 +1,6 @@ #include "pch.h" +/* using namespace triangle_stripper; void Exporter::strippify(TriStrips &strips, vector<Vector3> &verts, vector<Vector3> &norms, const Triangles &tris) @@ -69,7 +70,7 @@ void Exporter::strippify(TriStrips &strips, vector<Vector3> &verts, vector<Vecto strips.push_back(strip); } } - +*/ void Exporter::strippify(FaceGroup &grp) { TriStrips &strips = grp.strips; diff --git a/NifExport/Util.cpp b/NifExport/Util.cpp index 4c16184..6dd1534 100755 --- a/NifExport/Util.cpp +++ b/NifExport/Util.cpp @@ -4,6 +4,7 @@ #include <obj/NiPointLight.h> #include <obj/NiDirectionalLight.h> #include <obj/NiSpotLight.h> +#include <obj/NiTimeController.h> bool Exporter::TMNegParity(const Matrix3 &m) { @@ -66,9 +67,12 @@ Matrix3 Exporter::getTransform(INode *node, TimeValue t, bool local) Matrix3 tm = node->GetObjTMAfterWSM(t); if (local) { - Matrix3 pm = node->GetParentTM(t); - pm.Invert(); - tm *= pm; + INode *parent = node->GetParentNode(); + if (parent != NULL) { + Matrix3 pm = parent->GetObjTMAfterWSM(t); + pm.Invert(); + tm *= pm; + } } return tm; } @@ -125,6 +129,10 @@ NiNodeRef Exporter::makeNode(NiNodeRef &parent, INode *maxNode, bool local) exportUPB(node, maxNode); + // Normal Embedded Animation + if (mExportType == NIF_WO_KF) + CreateController(maxNode, mI->GetAnimRange()); + parent->AddChild(DynamicCast<NiAVObject>(node)); return node; } @@ -412,3 +420,14 @@ void Exporter::CalcBoundingSphere(INode *node, Point3 center, float& radius, int } } + + +void Exporter::getChildNodes(INode *node, vector<NiNodeRef>& list) +{ + for (int i=0; i<node->NumberOfChildren(); i++) + { + INode * child = node->GetChildNode(i); + list.push_back( getNode(child->GetName()) ); + getChildNodes(child, list); + } +} diff --git a/NifExport/pch.h b/NifExport/pch.h index a965e1c..d697250 100755 --- a/NifExport/pch.h +++ b/NifExport/pch.h @@ -39,10 +39,13 @@ #include "obj/bhkRigidBodyT.h" // undef macros for tristripper -#undef max -#undef min -#include "NvTriStrip/NvTriStrip.h" -#include "TriStripper/tri_stripper.h" +//#undef max +//#undef min +#include "../NvTriStrip/NvTriStrip.h" +//#include "TriStripper/detail/types.h" +//#include "TriStripper/detail/policy.h" +//#include "TriStripper/detail/cache_simulator.h" +//#include "TriStripper/tri_stripper.h" #include "NifPlugins.h" #include "Exporter.h" diff --git a/NifExport/resource.h b/NifExport/resource.h index 3d67a7f..75ae168 100755 --- a/NifExport/resource.h +++ b/NifExport/resource.h @@ -33,6 +33,7 @@ #define IDC_CB_USER_VERSION 1016 #define IDC_CHK_SKIN 1017 #define IDC_CHK_ANIMATION 1018 +#define IDC_LBL_PRIORITY2 1018 #define IDC_CHK_EXTRA 1019 #define IDC_CHK_UPB 1020 #define IDC_CHK_HIER 1021 @@ -43,7 +44,21 @@ #define IDC_CHK_SKEL_ONLY2 1026 #define IDC_CHK_BONE_COLL 1026 #define IDC_CHK_TRANSFORMS 1026 -#define IDC_EDIT1 1027 +#define IDC_CHK_TRANSFORMS2 1027 +#define IDC_GRP_ANIMATION 1028 +#define IDC_ED_PRIORITY2 1029 +#define IDC_CBO_ACCUM 1030 +#define IDC_CHK_USE_TIME_TAGS 1030 +#define IDC_CBO_ANIM_TYPE 1031 +#define IDC_CHECK1 1032 +#define IDC_CHK_AUTO_DETECT 1032 +#define IDC_CHK_SORTNODES2 1033 +#define IDC_CHK_ALLOW_ACCUM 1033 +#define IDC_LBL_BONES_VERTEX 1034 +#define IDC_ED_BONES_VERTEX 1035 +#define IDC_LBL_BONES_PART 1036 +#define IDC_ED_BONES_PART 1037 +#define IDC_CHK_SKINPART 1038 #define IDC_COLOR 1456 #define IDC_EDIT 1490 #define IDC_SPIN 1496 @@ -52,9 +67,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1028 +#define _APS_NEXT_CONTROL_VALUE 1033 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/NifFurniture/NifFurniture.rc b/NifFurniture/NifFurniture.rc index 3c75f27..84545f4 100755 --- a/NifFurniture/NifFurniture.rc +++ b/NifFurniture/NifFurniture.rc @@ -107,8 +107,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,2,4,0 - PRODUCTVERSION 0,2,4,0 + FILEVERSION 0,2,5,0 + PRODUCTVERSION 0,2,5,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, 4, 0" + VALUE "FileVersion", "0, 2, 5, 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, 4, 0" + VALUE "ProductVersion", "0, 2, 5, 0" END END BLOCK "VarFileInfo" diff --git a/NifImport/ImportAnimation.cpp b/NifImport/ImportAnimation.cpp index 5849460..e86545c 100644 --- a/NifImport/ImportAnimation.cpp +++ b/NifImport/ImportAnimation.cpp @@ -286,78 +286,65 @@ static FPValue myAddNewNoteKey(Value* noteTrack, int frame) return retVal; } -bool KFMImporter::ImportAnimation() +bool NifImporter::AddNoteTracks(float time, string name, string target, NiTextKeyExtraDataRef textKeyData, bool loop) { - bool ok = false; - int curFrame = 0; - // Read Kf files - - AnimationImport ai(*this); - - float time = 0.0f; - for(vector<NiControllerSequenceRef>::iterator itr = kf.begin(); itr != kf.end(); ++itr){ - - float minTime = 1e+35f; - float maxTime = 0.0f; - - NiControllerSequenceRef cntr = (*itr); - float start = cntr->GetStartTime(); - float stop = cntr->GetStopTime(); - float total = (stop - start); + vector<StringKey> textKeys = textKeyData->GetKeys(); + if (!textKeys.empty()) { - vector<ControllerLink> links = cntr->GetControllerData(); - - NiTextKeyExtraDataRef textKeyData = cntr->GetTextKeyExtraData(); - vector<StringKey> textKeys = textKeyData->GetKeys(); - if (!textKeys.empty()) { + Interval range = gi->GetAnimRange(); + for (vector<StringKey>::iterator itr=textKeys.begin(); itr != textKeys.end(); ++itr) { + TimeValue t = TimeToFrame(time + (*itr).time); + if (t < range.Start()) + range.SetStart(t); + if (t > range.End()) + range.SetEnd(t); + } + gi->SetAnimRange(range); - if (addNoteTracks) { - string target = cntr->GetTargetName(); - if ( INode *n = gi->GetINodeByName(target.c_str()) ) { + if (addNoteTracks && (wildmatch("start*", textKeys.front().data)) ) { + 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; - } + 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; + 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); } + if (!hasName) { + if (name.empty()) + name = FormatString("EMPTY_SEQUENCE_AT_%df", int(t * FramesPerSecond / TicksPerFrame) ); + args.push_back("-name"); + args.push_back(name); + } + if (!hasLoop && 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 += + TSTR script; + script += "fn getActorManager obj = (\n" " local nt = undefined\n" " n = numNoteTracks obj\n" @@ -374,58 +361,86 @@ bool KFMImporter::ImportAnimation() " Key.value = tag\n" ")\n"; - 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); - - 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); + 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); + + 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 (!hasLoop && ct == CYCLE_LOOP) { - args.push_back("-loop"); - } - - string line = JoinCommandLine(args); - script += FormatText("addNoteKey nt (%d/ticksPerFrame) \"%s\"\n", t, line.c_str()); - } else { - script += FormatText("addNoteKey nt (%d/ticksPerFrame) \"%s\"\n", t, (*itr).data.c_str()); + } + 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"); } - //NoteKey *key = new NoteKey(TimeToFrame(time + (*itr).time), (*itr).data.c_str(), 0); - //nt->keys.Append(1, &key); + string line = JoinCommandLine(args); + script += FormatText("addNoteKey nt (%d/ticksPerFrame) \"%s\"\n", t, line.c_str()); + } else { + script += FormatText("addNoteKey nt (%d/ticksPerFrame) \"%s\"\n", t, (*itr).data.c_str()); } - ExecuteMAXScriptScript(script, TRUE, NULL); -#endif + + //NoteKey *key = new NoteKey(TimeToFrame(time + (*itr).time), (*itr).data.c_str(), 0); + //nt->keys.Append(1, &key); } + ExecuteMAXScriptScript(script, TRUE, NULL); +#endif } + } - if (addTimeTags) { - if (IFrameTagManager *tagMgr = (IFrameTagManager*)GetCOREInterface(FRAMETAGMANAGER_INTERFACE)) { - for (vector<StringKey>::iterator itr=textKeys.begin(); itr != textKeys.end(); ++itr) { - tagMgr->CreateNewTag(const_cast<TCHAR*>((*itr).data.c_str()), TimeToFrame(time + (*itr).time), 0, FALSE); - } + if (addTimeTags) { + if (IFrameTagManager *tagMgr = (IFrameTagManager*)GetCOREInterface(FRAMETAGMANAGER_INTERFACE)) { + for (vector<StringKey>::iterator itr=textKeys.begin(); itr != textKeys.end(); ++itr) { + tagMgr->CreateNewTag(const_cast<TCHAR*>((*itr).data.c_str()), TimeToFrame(time + (*itr).time), 0, FALSE); } } } + return true; + } + return false; +} + +bool KFMImporter::ImportAnimation() +{ + bool ok = false; + int curFrame = 0; + // Read Kf files + + AnimationImport ai(*this); + + float time = 0.0f; + for(vector<NiControllerSequenceRef>::iterator itr = kf.begin(); itr != kf.end(); ++itr){ + + float minTime = 1e+35f; + float maxTime = 0.0f; + + NiControllerSequenceRef cntr = (*itr); + float start = cntr->GetStartTime(); + float stop = cntr->GetStopTime(); + float total = (stop - start); + + vector<ControllerLink> links = cntr->GetControllerData(); + + NiTextKeyExtraDataRef textKeyData = cntr->GetTextKeyExtraData(); + AddNoteTracks( time, cntr->GetName(), cntr->GetTargetName(), textKeyData, (CYCLE_LOOP == cntr->GetCycleType()) ); + for (vector<ControllerLink>::iterator lnk=links.begin(); lnk != links.end(); ++lnk) { string name = (*lnk).targetName; @@ -589,7 +604,11 @@ bool AnimationImport::AddValues(NiObjectNETRef nref) if (NULL == c) return false; - float time = FramesIncrement; + if (NiTextKeyExtraDataRef keydata = SelectFirstObjectOfType<NiTextKeyExtraData>(nref->GetExtraData())) { + ni.AddNoteTracks(0.0f, string(), nref->GetName(), keydata, false); + } + + float time = 0.0f; list< NiTimeControllerRef > clist = nref->GetControllers(); if (NiTransformControllerRef tc = SelectFirstObjectOfType<NiTransformController>(clist)) { if (NiTransformInterpolatorRef interp = tc->GetInterpolator()) { diff --git a/NifImport/MaxNifImport.rc b/NifImport/MaxNifImport.rc index 6ca1950..b46336f 100644 --- a/NifImport/MaxNifImport.rc +++ b/NifImport/MaxNifImport.rc @@ -26,38 +26,45 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // Dialog // -IDD_NIF_PANEL DIALOGEX 0, 0, 218, 193 +IDD_NIF_PANEL DIALOGEX 0, 0, 211, 257 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,105 - 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 "&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 - 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 "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 - 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 + GROUPBOX "General Options:",IDC_STATIC,7,7,197,33 + LTEXT "Game:",IDC_STATIC,11,20,31,8 + COMBOBOX IDC_CB_GAME,37,18,123,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Auto Detect",IDC_CHK_AUTO_DETECT,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,167,16,35,16 + GROUPBOX "Import:",IDC_STATIC,7,44,94,65 + CONTROL "&Lights",IDC_CHK_LIGHTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,57,67,10 + CONTROL "Cameras",IDC_CHK_CAMERA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,70,67,10 + CONTROL "Co&llision",IDC_CHK_COLL,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,14,82,67,10 + CONTROL "Furniture &Markers",IDC_CHK_FURN,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,14,94,67,10 + GROUPBOX "Geometry:",IDC_STATIC,105,44,99,65 + CONTROL "Vertex &Colors",IDC_CHK_VCOLORS,"Button",BS_AUTO3STATE | WS_TABSTOP,110,55,67,10 + CONTROL "S&kin Modifier",IDC_CHK_SKIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,67,67,10 + CONTROL "Auto Sm&ooth Mesh",IDC_CHK_AUTOSMOOTH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,79,76,11 + CONTROL "Remove &Illegal Faces",IDC_CHK_ILLEGAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,92,80,11 + GROUPBOX "Animation:",IDC_STATIC,7,114,94,61 + CONTROL "Import &Animation",IDC_CHK_ANIMATION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,125,67,10 + CONTROL "Clear Animation",IDC_CHK_CLEARANIM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,137,73,10 + CONTROL "Add Key Notes",IDC_CHK_KEYNOTES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,149,72,10 + CONTROL "Add Time Tags",IDC_CHK_TIMETAGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,162,72,10 + GROUPBOX "Miscellaneous:",IDC_STATIC,104,114,100,61 + CONTROL "Flip U&V",IDC_CHK_FLIP_UV,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,126,47,10 + CONTROL "&Render Textures in View",IDC_CHK_SHOW_TEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,137,88,10 + CONTROL "Ignore User Prop Buffers",IDC_CHK_UPB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,149,89,10 + GROUPBOX "Skeleton:",IDC_STATIC,7,177,197,56 + CONTROL "Import &Skeleton",IDC_CHK_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,189,67,10 + CONTROL "Remove &Unused Bones",IDC_CHK_REM_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,202,88,10 + CONTROL "Use &Biped",IDC_CHK_BIPED,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,110,189,87,10 + EDITTEXT IDC_ED_SKELETON,12,215,170,12,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_BTN_BROWSE,184,215,16,13 + DEFPUSHBUTTON "&Import",IDOK,5,236,34,14 + PUSHBUTTON "&Cancel",IDCANCEL,45,236,33,14 + LTEXT "http://www.niftools.org",IDC_LBL_LINK,122,236,78,14,SS_NOTIFY | SS_CENTERIMAGE + CONTROL "Ignore Root Node",IDC_CHK_IGNORE_ROOT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,109,161,89,10 END IDD_KF_PANEL DIALOGEX 0, 0, 118, 99 @@ -87,9 +94,9 @@ BEGIN IDD_NIF_PANEL, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 211 + RIGHTMARGIN, 204 TOPMARGIN, 7 - BOTTOMMARGIN, 186 + BOTTOMMARGIN, 250 END IDD_KF_PANEL, DIALOG @@ -135,8 +142,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,2,4,0 - PRODUCTVERSION 0,2,4,0 + FILEVERSION 0,2,5,0 + PRODUCTVERSION 0,2,5,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -152,12 +159,12 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "3ds Max Nif Importer" - VALUE "FileVersion", "0, 2, 4, 0" + VALUE "FileVersion", "0, 2, 5, 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, 4, 0" + VALUE "ProductVersion", "0, 2, 5, 0" END END BLOCK "VarFileInfo" diff --git a/NifImport/MaxNifImport_VC80.vcproj b/NifImport/MaxNifImport_VC80.vcproj index 93ff0e2..1fa3a16 100644 --- a/NifImport/MaxNifImport_VC80.vcproj +++ b/NifImport/MaxNifImport_VC80.vcproj @@ -49,7 +49,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/LD " InlineFunctionExpansion="2" - AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib;..\NifCommon" + AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib\include;..\NifCommon" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_USE_MATH_DEFINES" StringPooling="true" ExceptionHandling="2" @@ -76,7 +76,7 @@ <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib bmm.lib niflib.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib bmm.lib " OutputFile="C:\3dsmax6\plugins\MaxNifImport.dli" LinkIncremental="1" SuppressStartupBanner="true" @@ -150,7 +150,7 @@ AdditionalOptions="/LD /Zm200" Optimization="0" InlineFunctionExpansion="2" - AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib;..\NifCommon" + AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib\include;..\NifCommon" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_USE_MATH_DEFINES;USE_UNSUPPORTED_CODE" GeneratePreprocessedFile="0" MinimalRebuild="true" @@ -178,7 +178,7 @@ <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib bmm.lib niflibd.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib bmm.lib " OutputFile="C:\3dsmax6\plugins\MaxNifImport.dli" LinkIncremental="2" SuppressStartupBanner="true" @@ -251,7 +251,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/LD " InlineFunctionExpansion="2" - AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib;..\NifCommon" + AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib\include;..\NifCommon" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_USE_MATH_DEFINES;USE_BIPED" StringPooling="true" ExceptionHandling="2" @@ -278,7 +278,7 @@ <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib bmm.lib niflib.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib bmm.lib " OutputFile="C:\3dsmax7\plugins\MaxNifImport.dli" LinkIncremental="1" SuppressStartupBanner="true" @@ -352,7 +352,7 @@ AdditionalOptions="/LD " Optimization="0" InlineFunctionExpansion="2" - AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib;..\NifCommon" + AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib\include;..\NifCommon" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_USE_MATH_DEFINES;USE_UNSUPPORTED_CODE;USE_BIPED" GeneratePreprocessedFile="0" ExceptionHandling="2" @@ -378,7 +378,7 @@ <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib bmm.lib niflibd.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib bmm.lib " OutputFile="C:\3dsmax7\plugins\MaxNifImport.dli" LinkIncremental="2" SuppressStartupBanner="true" @@ -451,7 +451,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/LD " InlineFunctionExpansion="2" - AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib;..\NifCommon" + AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib\include;..\NifCommon" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_USE_MATH_DEFINES;USE_BIPED" StringPooling="true" ExceptionHandling="2" @@ -478,7 +478,7 @@ <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib bmm.lib niflib.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib bmm.lib " OutputFile="C:\3dsmax8\plugins\MaxNifImport.dli" LinkIncremental="1" SuppressStartupBanner="true" @@ -552,7 +552,7 @@ AdditionalOptions="/LD /Zm200" Optimization="0" InlineFunctionExpansion="2" - AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib;..\NifCommon" + AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib\include;..\NifCommon" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_USE_MATH_DEFINES;USE_UNSUPPORTED_CODE;USE_BIPED" GeneratePreprocessedFile="0" MinimalRebuild="true" @@ -580,7 +580,7 @@ <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib bmm.lib niflibd.lib" + AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib shlwapi.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib bmm.lib " OutputFile="C:\3dsmax8\plugins\MaxNifImport.dli" LinkIncremental="2" SuppressStartupBanner="true" diff --git a/NifImport/NIFImport.cpp b/NifImport/NIFImport.cpp index cb52375..3647785 100644 --- a/NifImport/NIFImport.cpp +++ b/NifImport/NIFImport.cpp @@ -117,6 +117,7 @@ void NifImporter::LoadIniSettings() appSettings = NULL; string curapp = GetIniValue<string>(NifImportSection, "CurrentApp", "AUTO"); if (0 == _tcsicmp(curapp.c_str(), "AUTO")) { + autoDetect = true; // Scan Root paths for (AppSettingsMap::iterator itr = TheAppSettings.begin(), end = TheAppSettings.end(); itr != end; ++itr){ if ((*itr).IsFileInRootPaths(this->name)) { @@ -125,6 +126,7 @@ void NifImporter::LoadIniSettings() } } } else { + autoDetect = false; appSettings = FindAppSetting(curapp); } if (appSettings == NULL && !TheAppSettings.empty()){ @@ -148,6 +150,7 @@ void NifImporter::LoadIniSettings() useCiv4Shader = GetIniValue(NifImportSection, "UseCiv4Shader", true); mergeNonAccum = GetIniValue(NifImportSection, "MergeNonAccum", true); importUPB = GetIniValue(NifImportSection, "ImportUPB", true); + ignoreRootNode = GetIniValue(NifImportSection, "IgnoreRootNode", true); // Biped importBones = GetIniValue(BipedImportSection, "ImportBones", true); @@ -212,12 +215,17 @@ void NifImporter::SaveIniSettings() SetIniValue(NifImportSection, "RemoveIllegalFaces", removeIllegalFaces); SetIniValue(NifImportSection, "RemoveDegenerateFaces", removeDegenerateFaces); SetIniValue(NifImportSection, "ImportUPB", importUPB); + SetIniValue(NifImportSection, "IgnoreRootNode", ignoreRootNode); SetIniValue(BipedImportSection, "ImportBones", importBones); SetIniValue(BipedImportSection, "RemoveUnusedImportedBones", removeUnusedImportedBones); SetIniValue(AnimImportSection, "EnableAnimations", enableAnimations); SetIniValue(AnimImportSection, "ClearAnimation", clearAnimation); + SetIniValue(AnimImportSection, "AddNoteTracks", addNoteTracks); + SetIniValue(AnimImportSection, "AddTimeTags", addTimeTags); + + SetIniValue<string>(NifImportSection, "CurrentApp", autoDetect ? "AUTO" : appSettings->Name ); } INode *NifImporter::GetNode(Niflib::NiNodeRef node) @@ -269,7 +277,7 @@ bool NifImporter::DoImport() NiNodeRef rootNode = root; if (importBones) { - if (strmatch(rootNode->GetName(), "Scene Root")) + if (ignoreRootNode || strmatch(rootNode->GetName(), "Scene Root")) ImportBones(DynamicCast<NiNode>(rootNode->GetChildren())); else ImportBones(rootNode); diff --git a/NifImport/NIFImporter.h b/NifImport/NIFImporter.h index 6d47202..dbc191c 100644 --- a/NifImport/NIFImporter.h +++ b/NifImport/NIFImporter.h @@ -17,6 +17,11 @@ HISTORY: #include "BaseImporter.h" #include "IniSection.h" +namespace Niflib +{ + class NiTextKeyExtraData; +} + // NIF Importer class NifImporter : public BaseImporter//, public IniFileSection { @@ -61,6 +66,8 @@ public: stringlist dummyNodeMatches; bool convertBillboardsToDummyNodes; bool uncontrolledDummies; + bool ignoreRootNode; + bool autoDetect; // Animation related Settings bool replaceTCBRotationWithBezier; @@ -131,6 +138,7 @@ public: bool ImportAnimation(); void ClearAnimation(); void ClearAnimation(INode *node); + bool AddNoteTracks(float time, string name, string target, Niflib::Ref<Niflib::NiTextKeyExtraData> textKeyData, bool loop); protected: diff --git a/NifImport/NifDialog.cpp b/NifImport/NifDialog.cpp index 4a36f87..4940baa 100644 --- a/NifImport/NifDialog.cpp +++ b/NifImport/NifDialog.cpp @@ -55,15 +55,18 @@ static BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wP 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_KEYNOTES, imp->addNoteTracks); + CheckDlgButton(hWnd, IDC_CHK_TIMETAGS, imp->addTimeTags); + CheckDlgButton(hWnd, IDC_CHK_IGNORE_ROOT, imp->ignoreRootNode); CheckDlgButton(hWnd, IDC_CHK_BIPED, imp->useBiped); - CheckDlgButton(hWnd, IDC_CHK_UPB, !imp->importUPB); - + 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) 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())); + CheckDlgButton(hWnd, IDC_CHK_AUTO_DETECT, imp->autoDetect); SHAutoComplete(GetDlgItem(hWnd, IDC_ED_SKELETON), SHACF_FILESYSTEM); if (imp->HasSkeleton() && imp->appSettings && imp->importSkeleton) { @@ -109,13 +112,17 @@ static BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wP 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->addNoteTracks = IsDlgButtonChecked(hWnd, IDC_CHK_KEYNOTES) ? true : false; + imp->addTimeTags = IsDlgButtonChecked(hWnd, IDC_CHK_TIMETAGS) ? true : false; imp->useBiped = IsDlgButtonChecked(hWnd, IDC_CHK_BIPED) ? true : false; imp->importUPB = IsDlgButtonChecked(hWnd, IDC_CHK_UPB) ? false : true; - + imp->ignoreRootNode = IsDlgButtonChecked(hWnd, IDC_CHK_IGNORE_ROOT) ? true : false; + GetDlgItemText(hWnd, IDC_CB_GAME, tmp, MAX_PATH); if (AppSettings *appSettings = FindAppSetting(tmp)) { imp->appSettings = appSettings; } + imp->autoDetect = IsDlgButtonChecked(hWnd, IDC_CHK_AUTO_DETECT) ? true : false; GetDlgItemText(hWnd, IDC_ED_SKELETON, tmp, MAX_PATH); imp->skeleton = tmp; diff --git a/NifImport/resource.h b/NifImport/resource.h index 22c9238..066ecaf 100644 --- a/NifImport/resource.h +++ b/NifImport/resource.h @@ -27,7 +27,10 @@ #define IDC_CHK_VCOLORS 1012 #define IDC_CHK_SHOW_TEX 1013 #define IDC_CB_GAME 1014 +#define IDC_CHK_IGNORE_ROOT 1015 #define IDC_CB_USER_VERSION 1016 +#define IDC_CHK_LIGHTS2 1016 +#define IDC_CHK_AUTO_DETECT 1016 #define IDC_CHK_SKIN 1017 #define IDC_CHK_ANIMATION 1018 #define IDC_CHK_AUTOSMOOTH 1019 diff --git a/NifProps/NifProps.rc b/NifProps/NifProps.rc index 68b5abc..7bf0c0e 100755 --- a/NifProps/NifProps.rc +++ b/NifProps/NifProps.rc @@ -359,8 +359,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,2,4,0 - PRODUCTVERSION 0,2,4,0 + FILEVERSION 0,2,5,0 + PRODUCTVERSION 0,2,5,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -376,12 +376,12 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "3ds Max Nif Reactor Properites Plugin" - VALUE "FileVersion", "0, 2, 4, 0" + VALUE "FileVersion", "0, 2, 5, 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, 4, 0" + VALUE "ProductVersion", "0, 2, 5, 0" END END BLOCK "VarFileInfo" -- GitLab