From 2044252221575c49e4df5559f04bb21b42e1743a Mon Sep 17 00:00:00 2001 From: Tazpn <tazpn@users.sourceforge.net> Date: Sun, 24 Jun 2007 17:05:26 +0000 Subject: [PATCH] More Geomorph related changes --- NifCommon/nimorph.cpp | 545 ++++++++++++++++++++++++++++++++++ NifCommon/niutils.cpp | 42 --- NifCommon/niutils.h | 9 + NifExport/Animation.cpp | 34 +++ NifExport/Exporter.cpp | 2 + NifExport/Exporter.h | 2 + NifExport/Util.cpp | 19 +- NifImport/ImportAnimation.cpp | 179 +---------- NifPlugins_VC80.vcproj | 4 + 9 files changed, 616 insertions(+), 220 deletions(-) create mode 100644 NifCommon/nimorph.cpp diff --git a/NifCommon/nimorph.cpp b/NifCommon/nimorph.cpp new file mode 100644 index 0000000..9904715 --- /dev/null +++ b/NifCommon/nimorph.cpp @@ -0,0 +1,545 @@ +/********************************************************************** +*< +FILE: NIUtils.cpp + +DESCRIPTION: NifImporter Utilities + +CREATED BY: tazpn (Theo) + +HISTORY: + +*> Copyright (c) 2006, All Rights Reserved. +**********************************************************************/ +#include "pch.h" +#include "niutils.h" +#include <string.h> +#include <ctype.h> +#include <locale.h> +#include <malloc.h> +#include <sstream> +#include <modstack.h> +#include <iparamb2.h> +#include <iskin.h> +#include "../NifProps/bhkRigidBodyInterface.h" + +#ifdef USE_BIPED +# include <cs/BipedApi.h> +# include <cs/OurExp.h> +#endif +#include "maxscrpt\Strings.h" +#include "maxscrpt\Parser.h" + +using namespace std; +using namespace Niflib; + +Modifier *GetMorpherModifier(INode* node) +{ + const Class_ID MORPHERMODIFIER_CLASS_ID(0x17bb6854, 0xa5cba2a3); + + Object* pObj = node->GetObjectRef(); + if (!pObj) return NULL; + while (pObj->SuperClassID() == GEN_DERIVOB_CLASS_ID) + { + IDerivedObject* pDerObj = (IDerivedObject *)(pObj); + int Idx = 0; + while (Idx < pDerObj->NumModifiers()) + { + // Get the modifier. + Modifier* mod = pDerObj->GetModifier(Idx); + if (mod->ClassID() == MORPHERMODIFIER_CLASS_ID) + { + return mod; + } + Idx++; + } + pObj = pDerObj->GetObjRef(); + } + return NULL; +} + +Modifier *CreateMorpherModifier(INode* node) +{ + const Class_ID MORPHERMODIFIER_CLASS_ID(0x17bb6854, 0xa5cba2a3); + + Modifier *mod = GetMorpherModifier(node); + if (mod == NULL) + { + IDerivedObject *dobj = CreateDerivedObject(node->GetObjectRef()); + mod = (Modifier*) CreateInstance(OSM_CLASS_ID, MORPHERMODIFIER_CLASS_ID); + dobj->SetAFlag(A_LOCK_TARGET); + dobj->AddModifier(mod); + dobj->ClearAFlag(A_LOCK_TARGET); + node->SetObjectRef(dobj); + } + return mod; +} + +// CallMaxscript +// Send the string to maxscript +// +void MorpherBuildFromNode(Modifier* mod, int index, INode *target) +{ + // Magic initialization stuff for maxscript. + static bool script_initialized = false; + if (!script_initialized) { + init_MAXScript(); + script_initialized = TRUE; + } + init_thread_locals(); + push_alloc_frame(); + six_value_locals(name, fn, mod, index, target, result); + save_current_frames(); + trace_back_active = FALSE; + + try { + // Create the name of the maxscript function we want. + // and look it up in the global names + vl.name = Name::intern(_T("WM3_MC_BuildFromNode")); + vl.fn = globals->get(vl.name); + + // For some reason we get a global thunk back, so lets + // check the cell which should point to the function. + // Just in case if it points to another global thunk + // try it again. + while (vl.fn != NULL && is_globalthunk(vl.fn)) + vl.fn = static_cast<GlobalThunk*>(vl.fn)->cell; + while (vl.fn != NULL && is_constglobalthunk(vl.fn)) + vl.fn = static_cast<ConstGlobalThunk*>(vl.fn)->cell; + + // Now we should have a MAXScriptFunction, which we can + // call to do the actual conversion. If we didn't + // get a MAXScriptFunction, we can't convert. + if (vl.fn != NULL && vl.fn->tag == class_tag(Primitive)) { + Value* args[3]; + + // Ok. WM3_MC_BuildFromNode takes three parameters + args[0] = vl.mod = MAXModifier::intern(mod); // The original material + args[1] = vl.index = Integer::intern(index); + args[2] = vl.target = MAXNode::intern(target); + + // Call the function and save the result. + vl.result = static_cast<Primitive*>(vl.fn)->apply(args, 3); + } + } catch (...) { + clear_error_source_data(); + restore_current_frames(); + MAXScript_signals = 0; + if (progress_bar_up) + MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; + } + + // Magic Max Script stuff to clear the frame and locals. + pop_value_locals(); + pop_alloc_frame(); +} + +TSTR MorpherGetName(Modifier* mod, int index) +{ + // Magic initialization stuff for maxscript. + static bool script_initialized = false; + if (!script_initialized) { + init_MAXScript(); + script_initialized = TRUE; + } + init_thread_locals(); + push_alloc_frame(); + six_value_locals(name, fn, mod, index, value, result); + save_current_frames(); + trace_back_active = FALSE; + TSTR string; + try { + // Create the name of the maxscript function we want. + // and look it up in the global names + vl.name = Name::intern(_T("WM3_MC_GetName")); + vl.fn = globals->get(vl.name); + + // For some reason we get a global thunk back, so lets + // check the cell which should point to the function. + // Just in case if it points to another global thunk + // try it again. + while (vl.fn != NULL && is_globalthunk(vl.fn)) + vl.fn = static_cast<GlobalThunk*>(vl.fn)->cell; + while (vl.fn != NULL && is_constglobalthunk(vl.fn)) + vl.fn = static_cast<ConstGlobalThunk*>(vl.fn)->cell; + + // Now we should have a MAXScriptFunction, which we can + // call to do the actual conversion. If we didn't + // get a MAXScriptFunction, we can't convert. + // class_tag(MAXScriptFunction) + if (vl.fn != NULL && vl.fn->tag == class_tag(Primitive)) { + Value* args[2]; + + // Ok. WM3_MC_BuildFromNode takes three parameters + args[0] = vl.mod = MAXModifier::intern(mod); // The original material + args[1] = vl.index = Integer::intern(index); + + // Call the function and save the result. + vl.result = static_cast<Primitive*>(vl.fn)->apply(args, 2); + if (vl.result->tag == class_tag(String)) { + string = vl.result->to_string(); + } + } + } catch (...) { + clear_error_source_data(); + restore_current_frames(); + MAXScript_signals = 0; + if (progress_bar_up) + MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; + } + + // Magic Max Script stuff to clear the frame and locals. + pop_value_locals(); + pop_alloc_frame(); + return string; +} + +void MorpherSetName(Modifier* mod, int index, TSTR& name) +{ + // Magic initialization stuff for maxscript. + static bool script_initialized = false; + if (!script_initialized) { + init_MAXScript(); + script_initialized = TRUE; + } + init_thread_locals(); + push_alloc_frame(); + six_value_locals(name, fn, mod, index, value, result); + save_current_frames(); + trace_back_active = FALSE; + String* value = new String(name); + + try { + // Create the name of the maxscript function we want. + // and look it up in the global names + vl.name = Name::intern(_T("WM3_MC_SetName")); + vl.fn = globals->get(vl.name); + + // For some reason we get a global thunk back, so lets + // check the cell which should point to the function. + // Just in case if it points to another global thunk + // try it again. + while (vl.fn != NULL && is_globalthunk(vl.fn)) + vl.fn = static_cast<GlobalThunk*>(vl.fn)->cell; + while (vl.fn != NULL && is_constglobalthunk(vl.fn)) + vl.fn = static_cast<ConstGlobalThunk*>(vl.fn)->cell; + + // Now we should have a MAXScriptFunction, which we can + // call to do the actual conversion. If we didn't + // get a MAXScriptFunction, we can't convert. + // class_tag(MAXScriptFunction) + if (vl.fn != NULL && vl.fn->tag == class_tag(Primitive)) { + Value* args[3]; + + // Ok. WM3_MC_BuildFromNode takes three parameters + args[0] = vl.mod = MAXModifier::intern(mod); // The original material + args[1] = vl.index = Integer::intern(index); + args[2] = vl.value = value; + + // Call the function and save the result. + vl.result = static_cast<Primitive*>(vl.fn)->apply(args, 3); + } + } catch (...) { + value->collect(); + clear_error_source_data(); + restore_current_frames(); + MAXScript_signals = 0; + if (progress_bar_up) + MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; + } + + // Magic Max Script stuff to clear the frame and locals. + pop_value_locals(); + pop_alloc_frame(); +} + +void MorpherRebuild(Modifier* mod, int index) +{ + // Magic initialization stuff for maxscript. + static bool script_initialized = false; + if (!script_initialized) { + init_MAXScript(); + script_initialized = TRUE; + } + init_thread_locals(); + push_alloc_frame(); + five_value_locals(name, fn, mod, index, result); + save_current_frames(); + trace_back_active = FALSE; + try { + // Create the name of the maxscript function we want. + // and look it up in the global names + vl.name = Name::intern(_T("WM3_MC_Rebuild")); + vl.fn = globals->get(vl.name); + + // For some reason we get a global thunk back, so lets + // check the cell which should point to the function. + // Just in case if it points to another global thunk + // try it again. + while (vl.fn != NULL && is_globalthunk(vl.fn)) + vl.fn = static_cast<GlobalThunk*>(vl.fn)->cell; + while (vl.fn != NULL && is_constglobalthunk(vl.fn)) + vl.fn = static_cast<ConstGlobalThunk*>(vl.fn)->cell; + + // Now we should have a MAXScriptFunction, which we can + // call to do the actual conversion. If we didn't + // get a MAXScriptFunction, we can't convert. + // class_tag(MAXScriptFunction) + if (vl.fn != NULL && vl.fn->tag == class_tag(Primitive)) { + Value* args[2]; + + // Ok. WM3_MC_BuildFromNode takes three parameters + args[0] = vl.mod = MAXModifier::intern(mod); // The original material + args[1] = vl.index = Integer::intern(index); + + // Call the function and save the result. + vl.result = static_cast<Primitive*>(vl.fn)->apply(args, 2); + } + } catch (...) { + clear_error_source_data(); + restore_current_frames(); + MAXScript_signals = 0; + if (progress_bar_up) + MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; + } + + // Magic Max Script stuff to clear the frame and locals. + pop_value_locals(); + pop_alloc_frame(); +} + +bool MorpherIsActive(Modifier* mod, int index) +{ + bool retval = false; + // Magic initialization stuff for maxscript. + static bool script_initialized = false; + if (!script_initialized) { + init_MAXScript(); + script_initialized = TRUE; + } + init_thread_locals(); + push_alloc_frame(); + five_value_locals(name, fn, mod, index, result); + save_current_frames(); + trace_back_active = FALSE; + try { + // Create the name of the maxscript function we want. + // and look it up in the global names + vl.name = Name::intern(_T("WM3_MC_IsActive")); + vl.fn = globals->get(vl.name); + + // For some reason we get a global thunk back, so lets + // check the cell which should point to the function. + // Just in case if it points to another global thunk + // try it again. + while (vl.fn != NULL && is_globalthunk(vl.fn)) + vl.fn = static_cast<GlobalThunk*>(vl.fn)->cell; + while (vl.fn != NULL && is_constglobalthunk(vl.fn)) + vl.fn = static_cast<ConstGlobalThunk*>(vl.fn)->cell; + + // Now we should have a MAXScriptFunction, which we can + // call to do the actual conversion. If we didn't + // get a MAXScriptFunction, we can't convert. + // class_tag(MAXScriptFunction) + if (vl.fn != NULL && vl.fn->tag == class_tag(Primitive)) { + Value* args[2]; + + // Ok. WM3_MC_BuildFromNode takes three parameters + args[0] = vl.mod = MAXModifier::intern(mod); // The original material + args[1] = vl.index = Integer::intern(index); + + // Call the function and save the result. + vl.result = static_cast<Primitive*>(vl.fn)->apply(args, 2); + if (vl.result->tag == class_tag(Boolean)) + retval = vl.result->to_bool(); + } + } catch (...) { + clear_error_source_data(); + restore_current_frames(); + MAXScript_signals = 0; + if (progress_bar_up) + MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; + } + + // Magic Max Script stuff to clear the frame and locals. + pop_value_locals(); + pop_alloc_frame(); + return retval; +} + +bool MorpherHasData(Modifier* mod, int index) +{ + bool retval = false; + // Magic initialization stuff for maxscript. + static bool script_initialized = false; + if (!script_initialized) { + init_MAXScript(); + script_initialized = TRUE; + } + init_thread_locals(); + push_alloc_frame(); + five_value_locals(name, fn, mod, index, result); + save_current_frames(); + trace_back_active = FALSE; + try { + // Create the name of the maxscript function we want. + // and look it up in the global names + vl.name = Name::intern(_T("WM3_MC_HasData")); + vl.fn = globals->get(vl.name); + + // For some reason we get a global thunk back, so lets + // check the cell which should point to the function. + // Just in case if it points to another global thunk + // try it again. + while (vl.fn != NULL && is_globalthunk(vl.fn)) + vl.fn = static_cast<GlobalThunk*>(vl.fn)->cell; + while (vl.fn != NULL && is_constglobalthunk(vl.fn)) + vl.fn = static_cast<ConstGlobalThunk*>(vl.fn)->cell; + + // Now we should have a MAXScriptFunction, which we can + // call to do the actual conversion. If we didn't + // get a MAXScriptFunction, we can't convert. + // class_tag(MAXScriptFunction) + if (vl.fn != NULL && vl.fn->tag == class_tag(Primitive)) { + Value* args[2]; + + // Ok. WM3_MC_BuildFromNode takes three parameters + args[0] = vl.mod = MAXModifier::intern(mod); // The original material + args[1] = vl.index = Integer::intern(index); + + // Call the function and save the result. + vl.result = static_cast<Primitive*>(vl.fn)->apply(args, 2); + if (vl.result->tag == class_tag(Boolean)) + retval = vl.result->to_bool(); + } + } catch (...) { + clear_error_source_data(); + restore_current_frames(); + MAXScript_signals = 0; + if (progress_bar_up) + MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; + } + + // Magic Max Script stuff to clear the frame and locals. + pop_value_locals(); + pop_alloc_frame(); + return retval; +} + +int MorpherNumProgMorphs(Modifier* mod, int index) +{ + int retval = 0; + // Magic initialization stuff for maxscript. + static bool script_initialized = false; + if (!script_initialized) { + init_MAXScript(); + script_initialized = TRUE; + } + init_thread_locals(); + push_alloc_frame(); + five_value_locals(name, fn, mod, index, result); + save_current_frames(); + trace_back_active = FALSE; + try { + // Create the name of the maxscript function we want. + // and look it up in the global names + vl.name = Name::intern(_T("WM3_MC_HasData")); + vl.fn = globals->get(vl.name); + + // For some reason we get a global thunk back, so lets + // check the cell which should point to the function. + // Just in case if it points to another global thunk + // try it again. + while (vl.fn != NULL && is_globalthunk(vl.fn)) + vl.fn = static_cast<GlobalThunk*>(vl.fn)->cell; + while (vl.fn != NULL && is_constglobalthunk(vl.fn)) + vl.fn = static_cast<ConstGlobalThunk*>(vl.fn)->cell; + + // Now we should have a MAXScriptFunction, which we can + // call to do the actual conversion. If we didn't + // get a MAXScriptFunction, we can't convert. + // class_tag(MAXScriptFunction) + if (vl.fn != NULL && vl.fn->tag == class_tag(Primitive)) { + Value* args[2]; + + // Ok. WM3_MC_BuildFromNode takes three parameters + args[0] = vl.mod = MAXModifier::intern(mod); // The original material + args[1] = vl.index = Integer::intern(index); + + // Call the function and save the result. + vl.result = static_cast<Primitive*>(vl.fn)->apply(args, 2); + if (vl.result->tag == class_tag(Integer)) + retval = vl.result->to_int(); + } + } catch (...) { + clear_error_source_data(); + restore_current_frames(); + MAXScript_signals = 0; + if (progress_bar_up) + MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; + } + + // Magic Max Script stuff to clear the frame and locals. + pop_value_locals(); + pop_alloc_frame(); + return retval; +} + +INode *MorpherGetProgMorph(Modifier* mod, int index, int morphIdx) +{ + INode *retval = 0; + // Magic initialization stuff for maxscript. + static bool script_initialized = false; + if (!script_initialized) { + init_MAXScript(); + script_initialized = TRUE; + } + init_thread_locals(); + push_alloc_frame(); + six_value_locals(name, fn, mod, index, midx, result); + save_current_frames(); + trace_back_active = FALSE; + try { + // Create the name of the maxscript function we want. + // and look it up in the global names + vl.name = Name::intern(_T("WM3_MC_HasData")); + vl.fn = globals->get(vl.name); + + // For some reason we get a global thunk back, so lets + // check the cell which should point to the function. + // Just in case if it points to another global thunk + // try it again. + while (vl.fn != NULL && is_globalthunk(vl.fn)) + vl.fn = static_cast<GlobalThunk*>(vl.fn)->cell; + while (vl.fn != NULL && is_constglobalthunk(vl.fn)) + vl.fn = static_cast<ConstGlobalThunk*>(vl.fn)->cell; + + // Now we should have a MAXScriptFunction, which we can + // call to do the actual conversion. If we didn't + // get a MAXScriptFunction, we can't convert. + // class_tag(MAXScriptFunction) + if (vl.fn != NULL && vl.fn->tag == class_tag(Primitive)) { + Value* args[3]; + + // Ok. WM3_MC_BuildFromNode takes three parameters + args[0] = vl.mod = MAXModifier::intern(mod); // The original material + args[1] = vl.index = Integer::intern(index); + args[2] = vl.midx = Integer::intern(morphIdx); + + // Call the function and save the result. + vl.result = static_cast<Primitive*>(vl.fn)->apply(args, 3); + if (vl.result->tag == class_tag(MAXNode)) + retval = vl.result->to_node(); + } + } catch (...) { + clear_error_source_data(); + restore_current_frames(); + MAXScript_signals = 0; + if (progress_bar_up) + MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; + } + + // Magic Max Script stuff to clear the frame and locals. + pop_value_locals(); + pop_alloc_frame(); + return retval; +} \ No newline at end of file diff --git a/NifCommon/niutils.cpp b/NifCommon/niutils.cpp index ade1713..f1f6362 100644 --- a/NifCommon/niutils.cpp +++ b/NifCommon/niutils.cpp @@ -1184,45 +1184,3 @@ Matrix3 GetLocalTM(INode *node) return node->GetNodeTM(0); } } - -Modifier *GetMorpherModifier(INode* node) -{ - const Class_ID MORPHERMODIFIER_CLASS_ID(0x17bb6854, 0xa5cba2a3); - - Object* pObj = node->GetObjectRef(); - if (!pObj) return NULL; - while (pObj->SuperClassID() == GEN_DERIVOB_CLASS_ID) - { - IDerivedObject* pDerObj = (IDerivedObject *)(pObj); - int Idx = 0; - while (Idx < pDerObj->NumModifiers()) - { - // Get the modifier. - Modifier* mod = pDerObj->GetModifier(Idx); - if (mod->ClassID() == MORPHERMODIFIER_CLASS_ID) - { - return mod; - } - Idx++; - } - pObj = pDerObj->GetObjRef(); - } - return NULL; -} - -Modifier *CreateMorpherModifier(INode* node) -{ - const Class_ID MORPHERMODIFIER_CLASS_ID(0x17bb6854, 0xa5cba2a3); - - Modifier *mod = GetMorpherModifier(node); - if (mod == NULL) - { - IDerivedObject *dobj = CreateDerivedObject(node->GetObjectRef()); - mod = (Modifier*) CreateInstance(OSM_CLASS_ID, MORPHERMODIFIER_CLASS_ID); - dobj->SetAFlag(A_LOCK_TARGET); - dobj->AddModifier(mod); - dobj->ClearAFlag(A_LOCK_TARGET); - node->SetObjectRef(dobj); - } - return mod; -} diff --git a/NifCommon/niutils.h b/NifCommon/niutils.h index feef397..b9ef787 100644 --- a/NifCommon/niutils.h +++ b/NifCommon/niutils.h @@ -430,7 +430,16 @@ void GetIniFileName(char *iniName); Matrix3 GetLocalTM(INode *node); +// Morph related routines in nimorph.cpp extern Modifier *GetMorpherModifier(INode* node); extern Modifier *CreateMorpherModifier(INode* node); +extern void MorpherBuildFromNode(Modifier* mod, int index, INode *target); +extern void MorpherSetName(Modifier* mod, int index, TSTR& name); +extern void MorpherRebuild(Modifier* mod, int index); +extern TSTR MorpherGetName(Modifier* mod, int index); +extern bool MorpherIsActive(Modifier* mod, int index); +extern bool MorpherHasData(Modifier* mod, int index); +extern int MorpherNumProgMorphs(Modifier* mod, int index); +extern INode *MorpherGetProgMorph(Modifier* mod, int index, int morphIdx); #endif // _NIUTILS_H_ \ No newline at end of file diff --git a/NifExport/Animation.cpp b/NifExport/Animation.cpp index c6a07f1..8a5af4d 100644 --- a/NifExport/Animation.cpp +++ b/NifExport/Animation.cpp @@ -36,6 +36,11 @@ HISTORY: #include <obj/NiBSplineCompTransformInterpolator.h> #include <obj/NiDefaultAVObjectPalette.h> #include <obj/NiMultiTargetTransformController.h> +#include <obj/NiGeomMorpherController.h> +#include <obj/NiMorphData.h> +#include <obj/NiBSplineCompFloatInterpolator.h> +#include <obj/NiFloatInterpolator.h> +#include <obj/NiFloatData.h> using namespace Niflib; const Class_ID IPOS_CONTROL_CLASS_ID = Class_ID(0x118f7e02,0xffee238a); @@ -241,6 +246,35 @@ bool Exporter::isNodeTracked(INode *node) return false; } +Exporter::Result Exporter::scanForAnimation(INode *node) +{ + if (NULL == node) + return Exporter::Skip; + + // Ideally check for Morph: targets +#if VERSION_3DSMAX >= ((8000<<16)+(15<<8)+0) // Version 8+ + if (Modifier * mod = GetMorpherModifier(node)){ + int idx = -1; + for (int i=1; i<=100; ++i) { + if (MorpherIsActive(mod, i) && MorpherHasData(mod, i)) { + TSTR str = MorpherGetName(mod, i); + int nodes = MorpherNumProgMorphs(mod, i); + for (int j=1; j<=nodes; j++) + { + if (INode *morph = MorpherGetProgMorph(mod, i, j)) + { + markAsHandled(morph); + } + } + } + } + } + for (int i=0; i<node->NumberOfChildren(); i++) { + scanForIgnore(node->GetChildNode(i)); + } +#endif + return Exporter::Ok; +} static bool HasKeys(Control *c) { diff --git a/NifExport/Exporter.cpp b/NifExport/Exporter.cpp index 6580fb8..ac68da3 100755 --- a/NifExport/Exporter.cpp +++ b/NifExport/Exporter.cpp @@ -113,7 +113,9 @@ Exporter::Result Exporter::doExport(NiNodeRef &root, INode *node) } // Always Scan for Collision Nodes first + scanForIgnore(node); scanForCollision(node); + scanForAnimation(node); mNiRoot = root; if (mSelectedOnly) { diff --git a/NifExport/Exporter.h b/NifExport/Exporter.h index b729c6d..feb1b66 100755 --- a/NifExport/Exporter.h +++ b/NifExport/Exporter.h @@ -169,6 +169,8 @@ public: bool isCollision(INode *node); bool isHandled(INode *node); bool markAsHandled(INode* node); + Result scanForAnimation(INode* node); + Result scanForIgnore(INode *node); /* utility functions */ Mtl *getMaterial(INode *node, int subMtl); diff --git a/NifExport/Util.cpp b/NifExport/Util.cpp index 0a1c6c0..4e25720 100755 --- a/NifExport/Util.cpp +++ b/NifExport/Util.cpp @@ -609,4 +609,21 @@ void Exporter::sortVector3(vector<Vector3>& vector) void Exporter::sortFloat4(vector<Float4>& vector) { std::stable_sort(vector.begin(), vector.end(), SortVectorEquivalence()); -} \ No newline at end of file +} + +Exporter::Result Exporter::scanForIgnore(INode *node) +{ + if (NULL == node) + return Exporter::Skip; + + BOOL ignore = FALSE; + if (node->GetUserPropBool("np_ignore", ignore)) + { + markAsHandled(node); + } + for (int i=0; i<node->NumberOfChildren(); i++) { + scanForIgnore(node->GetChildNode(i)); + } + return Exporter::Ok; +} + diff --git a/NifImport/ImportAnimation.cpp b/NifImport/ImportAnimation.cpp index 737961b..0459234 100644 --- a/NifImport/ImportAnimation.cpp +++ b/NifImport/ImportAnimation.cpp @@ -105,10 +105,6 @@ struct AnimationImport bool ImportGeoMorph(INode *n, NiGeomMorpherControllerRef ctrl, float time); INode* CreateGeoMesh(const vector<Vector3>& verts, const vector<Triangle>& tris, Matrix3& tm, INode *parent); - - void MorpherBuildFromNode(Modifier* mod, int index, INode *target); - void MorpherSetName(Modifier* mod, int index, TSTR& name); - void MorpherRebuild(Modifier* mod, int index); }; bool NifImporter::ImportAnimation() @@ -550,7 +546,7 @@ bool KFMImporter::ImportAnimation() { int idx = -1; for (int i=1; i<=100; ++i) { - if (strmatch(var2, mod->SubAnimName(i))) { + if (strmatch(var2, MorpherGetName(mod, i))) { idx = i; break; } @@ -1131,6 +1127,7 @@ INode *AnimationImport::CreateGeoMesh( tnode->SetPrimaryVisibility(FALSE); tnode->SetSecondaryVisibility(FALSE); tnode->SetWireColor( RGB(0,255,0) ); + tnode->SetUserPropBool("np_ignore", TRUE); returnNode = node->GetINode(); @@ -1141,175 +1138,3 @@ INode *AnimationImport::CreateGeoMesh( return returnNode; } -// CallMaxscript -// Send the string to maxscript -// -void AnimationImport::MorpherBuildFromNode(Modifier* mod, int index, INode *target) -{ - // Magic initialization stuff for maxscript. - static bool script_initialized = false; - if (!script_initialized) { - init_MAXScript(); - script_initialized = TRUE; - } - init_thread_locals(); - push_alloc_frame(); - six_value_locals(name, fn, mod, index, target, result); - save_current_frames(); - trace_back_active = FALSE; - - try { - // Create the name of the maxscript function we want. - // and look it up in the global names - vl.name = Name::intern(_T("WM3_MC_BuildFromNode")); - vl.fn = globals->get(vl.name); - - // For some reason we get a global thunk back, so lets - // check the cell which should point to the function. - // Just in case if it points to another global thunk - // try it again. - while (vl.fn != NULL && is_globalthunk(vl.fn)) - vl.fn = static_cast<GlobalThunk*>(vl.fn)->cell; - while (vl.fn != NULL && is_constglobalthunk(vl.fn)) - vl.fn = static_cast<ConstGlobalThunk*>(vl.fn)->cell; - - // Now we should have a MAXScriptFunction, which we can - // call to do the actual conversion. If we didn't - // get a MAXScriptFunction, we can't convert. - if (vl.fn != NULL && vl.fn->tag == class_tag(Primitive)) { - Value* args[3]; - - // Ok. WM3_MC_BuildFromNode takes three parameters - args[0] = vl.mod = MAXModifier::intern(mod); // The original material - args[1] = vl.index = Integer::intern(index); - args[2] = vl.target = MAXNode::intern(target); - - // Call the function and save the result. - vl.result = static_cast<Primitive*>(vl.fn)->apply(args, 3); - } - } catch (...) { - clear_error_source_data(); - restore_current_frames(); - MAXScript_signals = 0; - if (progress_bar_up) - MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; - } - - // Magic Max Script stuff to clear the frame and locals. - pop_value_locals(); - pop_alloc_frame(); -} - -void AnimationImport::MorpherSetName(Modifier* mod, int index, TSTR& name) -{ - // Magic initialization stuff for maxscript. - static bool script_initialized = false; - if (!script_initialized) { - init_MAXScript(); - script_initialized = TRUE; - } - init_thread_locals(); - push_alloc_frame(); - six_value_locals(name, fn, mod, index, value, result); - save_current_frames(); - trace_back_active = FALSE; - String* value = new String(name); - - try { - // Create the name of the maxscript function we want. - // and look it up in the global names - vl.name = Name::intern(_T("WM3_MC_SetName")); - vl.fn = globals->get(vl.name); - - // For some reason we get a global thunk back, so lets - // check the cell which should point to the function. - // Just in case if it points to another global thunk - // try it again. - while (vl.fn != NULL && is_globalthunk(vl.fn)) - vl.fn = static_cast<GlobalThunk*>(vl.fn)->cell; - while (vl.fn != NULL && is_constglobalthunk(vl.fn)) - vl.fn = static_cast<ConstGlobalThunk*>(vl.fn)->cell; - - // Now we should have a MAXScriptFunction, which we can - // call to do the actual conversion. If we didn't - // get a MAXScriptFunction, we can't convert. - // class_tag(MAXScriptFunction) - if (vl.fn != NULL && vl.fn->tag == class_tag(Primitive)) { - Value* args[3]; - - // Ok. WM3_MC_BuildFromNode takes three parameters - args[0] = vl.mod = MAXModifier::intern(mod); // The original material - args[1] = vl.index = Integer::intern(index); - args[2] = vl.value = value; - - // Call the function and save the result. - vl.result = static_cast<Primitive*>(vl.fn)->apply(args, 3); - } - } catch (...) { - value->collect(); - clear_error_source_data(); - restore_current_frames(); - MAXScript_signals = 0; - if (progress_bar_up) - MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; - } - - // Magic Max Script stuff to clear the frame and locals. - pop_value_locals(); - pop_alloc_frame(); -} - -void AnimationImport::MorpherRebuild(Modifier* mod, int index) -{ - // Magic initialization stuff for maxscript. - static bool script_initialized = false; - if (!script_initialized) { - init_MAXScript(); - script_initialized = TRUE; - } - init_thread_locals(); - push_alloc_frame(); - five_value_locals(name, fn, mod, index, result); - save_current_frames(); - trace_back_active = FALSE; - try { - // Create the name of the maxscript function we want. - // and look it up in the global names - vl.name = Name::intern(_T("WM3_MC_Rebuild")); - vl.fn = globals->get(vl.name); - - // For some reason we get a global thunk back, so lets - // check the cell which should point to the function. - // Just in case if it points to another global thunk - // try it again. - while (vl.fn != NULL && is_globalthunk(vl.fn)) - vl.fn = static_cast<GlobalThunk*>(vl.fn)->cell; - while (vl.fn != NULL && is_constglobalthunk(vl.fn)) - vl.fn = static_cast<ConstGlobalThunk*>(vl.fn)->cell; - - // Now we should have a MAXScriptFunction, which we can - // call to do the actual conversion. If we didn't - // get a MAXScriptFunction, we can't convert. - // class_tag(MAXScriptFunction) - if (vl.fn != NULL && vl.fn->tag == class_tag(Primitive)) { - Value* args[2]; - - // Ok. WM3_MC_BuildFromNode takes three parameters - args[0] = vl.mod = MAXModifier::intern(mod); // The original material - args[1] = vl.index = Integer::intern(index); - - // Call the function and save the result. - vl.result = static_cast<Primitive*>(vl.fn)->apply(args, 2); - } - } catch (...) { - clear_error_source_data(); - restore_current_frames(); - MAXScript_signals = 0; - if (progress_bar_up) - MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; - } - - // Magic Max Script stuff to clear the frame and locals. - pop_value_locals(); - pop_alloc_frame(); -} diff --git a/NifPlugins_VC80.vcproj b/NifPlugins_VC80.vcproj index d127259..e351957 100644 --- a/NifPlugins_VC80.vcproj +++ b/NifPlugins_VC80.vcproj @@ -5113,6 +5113,10 @@ RelativePath=".\NifCommon\NifQHull.cpp" > </File> + <File + RelativePath=".\NifCommon\nimorph.cpp" + > + </File> <File RelativePath=".\NifCommon\niutils.cpp" > -- GitLab