diff --git a/MaxNifPlugins_Readme.txt b/MaxNifPlugins_Readme.txt index 355c3fd2cac45cd83b2163b74e350f3dc2877487..cdc748b693785f6b571da56cb8d80a71034c5936 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 8caa4ac15022d18669288e865b1cd846395b7785..30fdbb0cf629e0cb32b08cebd679390b3e4ecf95 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 7766ab9a82cd60adbfa67b1e36cf622f499d1084..bd549a61f095ad9feaf7662b5475b777e6872c19 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 62f60d5fa8bf3df7256f397632ac1b8faa4e8fdd..4da6b708b3a0495532a809fbd8bd1478508bf654 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 70eaba44f9a15c6b00a1ab3c3d45e0a7bb27e986..1066a9c1093b3b307a351f96eab78e99b3ad5364 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 230687f5dc0bf9a625efc2346ca5429d9f489723..39a4c81feddab0d3de873233bf178d270dfe61a4 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 1ff47215a3f811c63ea53af2a3b1720566b5400f..0bc19ce38b3290d82d6abd389599f91fb1ea7fc2 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 8907fa30db1f0a35a8ab4ad4837e92ad3c4bb885..2443ecc1128bc0613c1b6981a115d3e6708ba191 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 8bdf74b283dc387b0a24605022d2d300ceb9700d..829eb695bdc5232daa4ef822301ce480d026af01 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 8d5b2f0dfaf90b39abe09b808d948aaa7a36e233..365b5d35aada61c4d621713ed9a423477b4888a7 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 4102b0c8e651f3511caf265f32f1dff1de80dfe4..795136fd360904b9ed992a8051833b1bc319ea7b 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 5ed4f0b981edd113885236b58c39e30d23b8a1ed..1601f417f6240e5c97575efb81c19a83cd38826e 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 4a7be3b46dcf171409aa11ef92ceb10ffda3f6cd..ee83d42c9622572a5a9e725653ad67db0e088434 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 e9f8667ef76badcbcc0debc9b014428f172e567a..c9eb4b768211a5802817a5b9e6fe3f3d953219ff 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 e1997b4f727ae3659f13f70fb9c4d97a32ef3d48..3693d6dfd2f7cbb366c0eb0b6f75822dc05f1785 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 7ca4f350a6f5b75da98ca927bcb1eaede3a5f649..a69a666bd87683b735c34910a294edeed6b68467 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 4c161845b722d49fae0b71c8d0ba9aefc559a309..6dd15345265f84ad5105f6ee20980af7a677330f 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 a965e1cc70218e5c7655f8f7efff909fd2b0f183..d697250272c056e7484c56bef7af72f173428eb5 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 3d67a7f977ff854f1ab41c0ba34a65177ff3043a..75ae16849ebed96cfab43eb1e9776a0e7b26d5e4 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 3c75f27838963c2b7681050ae1b370c57ee8180b..84545f4dbd180b9e1649b1c3705e7567c342f763 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 58494607f163373e7991f65ffd03946a173b3287..e86545c229da6f7f7b369a48679ebcf8ce8cee7f 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 6ca19508c6329bf51f5241e622a9db3dd1ccbcda..b46336ffd8137720ed66642f1ab73a5b7a30b0e3 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 93ff0e2604c2dfbf7bb02493d56e7076d3e45144..1fa3a1679139016fc4c35adda079972f5dbc8b0d 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 cb52375cb6d692979d4ffa47116b8b558e91a5ee..36477856fa53ea28598e1cc09af3fbc37fe8eced 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 6d472028309dade4451d3ae70617d89c9130bb44..dbc191cb1cdb4774a7d4db7e66e0fb491b246c49 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 4a36f8779db996420c8327b8c413b6a0ce578117..4940baaa28e60eb465e39a11ed18e80b8d151227 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 22c9238e83a9422022be341a1ddf40d92b7d6bbf..066ecafac85cced43878275e8ca8f77aaa908cf8 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 68b5abcad3841198bf8997669839975917c566ce..7bf0c0e928ab59e26a861022014b0c53956da7ba 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"