From 1e3829fcd3ff6fab504bf33e438a6029f2588037 Mon Sep 17 00:00:00 2001 From: Lukas Cone Date: Sun, 20 Sep 2020 23:11:56 +0200 Subject: [PATCH] Release v1.5 --- 3rd_party/RevilLib | 2 +- CHANGELOG | 34 ++++++++ CMakeLists.txt | 18 ++--- README.md | 9 ++- src/DllEntry.cpp | 6 +- src/MTFImport.cpp | 133 ++++++++++++++++++++++--------- src/REEngineImport.cpp | 175 +++++++++++++++++++++++++++++------------ src/RevilMax.cpp | 21 ++++- src/RevilMax.h | 3 + src/RevilMax.rc | Bin 6426 -> 7080 bytes src/resource.h | 6 +- 11 files changed, 298 insertions(+), 109 deletions(-) create mode 100644 CHANGELOG diff --git a/3rd_party/RevilLib b/3rd_party/RevilLib index 1edcade..84d56a8 160000 --- a/3rd_party/RevilLib +++ b/3rd_party/RevilLib @@ -1 +1 @@ -Subproject commit 1edcadea24ece083e668f065df33a969ee088c4e +Subproject commit 84d56a8487af10a83acad65a900ac02e6f884428 diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..5611b64 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,34 @@ +v1.5 +- Removed 32bit support. +- Added support for 2021. +- Added ability to load Additive animations. +- Added ability to suppress logging of missing bones. +- Added asset caching for faster loading. +- Fixed few crash problems. +- Added catch handling for non-critical errors. +- Fixed reference pose from -1 frame to -1 tick. + +v1.4 +- Added support for RE7. +- More fixes. + +v1.3 +- Fixed positions for mot78 formats. #6 +- Fixed frame distribution for Big Endian LMT formats. +- Fixed crash when loading pose animations. #3 +- Minor crash fixes. +- Added some missing codecs. + +v1.2 +- Added support for LMT loading. +- Added support for motlist99, mot78 formats. +- RE motion formats are now properly sampled. +- Added resample option (animation will be resampled to current scene FPS) +- Added option to load all animations at once (ranges will be printed into listener, units are ticks). + +v1.1 +- Fixed wrong frame distribution where resulting animations were slightly faster. +- Maxscript listener will now show whenever plugin tries to print any information and from now on, user will be always informed properly. User no longer needs to open listener manually. + +v1 +- Initial release. diff --git a/CMakeLists.txt b/CMakeLists.txt index cbf1f5b..3b60b27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 3.3) -project(RevilMax VERSION 1.4) +project(RevilMax VERSION 1.5) -set (RevilLibLibraryPath ../RevilLib_${CMAKE_GENERATOR_PLATFORM}) +set (RevilLibLibraryPath ../RevilLib) add_subdirectory(3rd_party/RevilLib ${RevilLibLibraryPath}) include(${PRECORE_SOURCE_DIR}/cmake/3dsmax.cmake) @@ -18,20 +18,16 @@ build_target( src/RevilMax.rc ${MAX_EX_DIR}/win/About.rc LINKS - gdiplus bmm core RevilLib flt mesh maxutil maxscrpt paramblk2 geom - DEFINITIONS - ${MaxDefinitions} + gdiplus bmm core RevilLib flt mesh maxutil maxscrpt paramblk2 geom MaxSDKTarget INCLUDES - ${MaxSDK}/include 3rd_party/RevilLib/include - ${PRECORE_SOURCE_DIR} - LINK_DIRS - ${MaxSDKLibrariesPath} AUTHOR "Lukas Cone" - DESCR "3DS Max Plugin for formats used by RE engines" + DESCR "3DS Max Plugin for formats used by RE Engine/MTF" NAME "RevilLib" START_YEAR 2019 PROPERTIES SUFFIX .dlu ${MaxProperties} -) \ No newline at end of file +) + +set_precore_sources(directory_scanner) diff --git a/README.md b/README.md index c511c30..d3f9993 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # RevilMax + RevilMax is RE Engine and MT Framework importer for 3ds Max. Buildable under VS2015.\ -Supported 3ds max versions: **2010 - 2020**\ +Supported 3ds max versions (x64 only): **2010 - 2021**\ Tested on 3ds max versions: **2017** ## Building @@ -8,15 +9,17 @@ Tested on 3ds max versions: **2017** Head to the [Building a 3ds max CMake projects](https://github.com/PredatorCZ/PreCore/wiki/Building-a-3ds-max-CMake-projects) wiki page. ## Installation + ### [Latest Release](https://github.com/PredatorCZ/RevilMax/releases/) + Move corresponding .dlu located in correct version folder into ***%3ds max installation directory%/plugins***. \ Versions must match!\ Additionally plugin will require **Visual C++ Redistributable for Visual Studio 2015** to be installed in order to work. - ## License + This plugin is available under GPL v3 license. (See LICENSE.md) This plugin uses following libraries: -* RevilLib, Copyright (c) 2017-2019 Lukas Cone +* RevilLib, Copyright (c) 2017-2020 Lukas Cone diff --git a/src/DllEntry.cpp b/src/DllEntry.cpp index 8832661..02b9468 100644 --- a/src/DllEntry.cpp +++ b/src/DllEntry.cpp @@ -18,7 +18,7 @@ */ #include "RevilMax.h" -#include "datas/MasterPrinter.hpp" +#include "datas/master_printer.hpp" #include #if VERSION_3DSMAX_B == VERSION_3DSMAX_E(2010) @@ -55,7 +55,9 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, ULONG fdwReason, // This function returns a string that describes the DLL and where the user // could purchase the DLL if they don't have it. -__declspec(dllexport) const TCHAR *LibDescription() { return _T(RevilMax_DESC); } +__declspec(dllexport) const TCHAR *LibDescription() { + return _T(RevilMax_DESC); +} // This function returns the number of plug-in classes this DLL // TODO: Must change this number when adding a new class diff --git a/src/MTFImport.cpp b/src/MTFImport.cpp index fec6ac4..fb9f5e9 100644 --- a/src/MTFImport.cpp +++ b/src/MTFImport.cpp @@ -19,7 +19,7 @@ #include "datas/reflector.hpp" #include "RevilMax.h" -#include "datas/masterprinter.hpp" +#include "datas/master_printer.hpp" #include "lmt.hpp" #include #include @@ -95,9 +95,11 @@ const TCHAR *MTFImport::LongDesc() { return _T("MT Framework Import"); } const TCHAR *MTFImport::ShortDesc() { return _T("MT Framework Import"); } -const TCHAR *MTFImport::AuthorName() { return _T(RevilMax_AUTHOR); } +const TCHAR *MTFImport::AuthorName() { return _T("Lukas Cone"); } -const TCHAR *MTFImport::CopyrightMessage() { return _T(RevilMax_COPYRIGHT); } +const TCHAR *MTFImport::CopyrightMessage() { + return _T(RevilMax_COPYRIGHT "Lukas Cone"); +} const TCHAR *MTFImport::OtherMessage1() { return _T(""); } @@ -107,8 +109,7 @@ unsigned int MTFImport::Version() { return REVILMAX_VERSIONINT; } void MTFImport::ShowAbout(HWND hWnd) { ShowAboutDLG(hWnd); } -struct LMTNode { - DECLARE_REFLECTOR; +struct LMTNode : ReflectorInterface { union { struct { Vector r1, r2, r3, r4; @@ -525,7 +526,7 @@ TimeValue MTFImport::LoadMotion(const uni::Motion &mot, TimeValue startTime) { const float aDuration = mot.Duration(); TimeValue numTicks = SecToTicks(aDuration); - TimeValue ticksPerFrame = GetTicksPerFrame(); + const TimeValue ticksPerFrame = GetTicksPerFrame(); TimeValue overlappingTicks = numTicks % ticksPerFrame; if (overlappingTicks > (ticksPerFrame / 2)) @@ -538,7 +539,7 @@ TimeValue MTFImport::LoadMotion(const uni::Motion &mot, TimeValue startTime) { Times frameTimesTicks; for (TimeValue v = aniRange.Start(); v <= aniRange.End(); - v += GetTicksPerFrame()) { + v += ticksPerFrame) { frameTimes.push_back(TicksToSec(v - startTime)); frameTimesTicks.push_back(v); } @@ -547,14 +548,14 @@ TimeValue MTFImport::LoadMotion(const uni::Motion &mot, TimeValue startTime) { std::vector scaleTracks; for (auto &t : mot) { - const size_t boneID = t.BoneIndex(); + const size_t boneID = t->BoneIndex(); LMTNode *lNode = iBoneScanner.LookupNode(boneID); if (!lNode) continue; - if (t.TrackType() == uni::MotionTrack::TrackType_e::Scale) - scaleTracks.emplace_back(lNode->nde, &t); + if (t->TrackType() == uni::MotionTrack::TrackType_e::Scale) + scaleTracks.emplace_back(lNode->nde, t.get()); /*if (t.BoneType()) printline("Bone: " << es::ToUTF8(lNode->nde->GetName()) @@ -572,13 +573,16 @@ TimeValue MTFImport::LoadMotion(const uni::Motion &mot, TimeValue startTime) { iBoneScanner.RescanBones(); iBoneScanner.RestoreBasePose(startTime); + const bool additive = flags[IDC_CH_ADDITIVE_checked]; for (auto &t : mot) { - const size_t boneID = t.BoneIndex(); + const size_t boneID = t->BoneIndex(); LMTNode *lNode = iBoneScanner.LookupNode(boneID); if (!lNode) { - printwarning("[MTF] Couldn't find LMTBone: " << boneID); + if (!flags[IDC_CH_NOLOGBONES_checked]) { + printwarning("[MTF] Couldn't find LMTBone: " << boneID); + } continue; } @@ -586,21 +590,27 @@ TimeValue MTFImport::LoadMotion(const uni::Motion &mot, TimeValue startTime) { !flags[IDC_CH_DISABLEIK_checked] ? lNode->GetNode() : lNode->nde; Control *cnt = fNode->GetTMController(); - switch (t.TrackType()) { + switch (t->TrackType()) { case uni::MotionTrack::TrackType_e::Position: { Control *posCnt = cnt->GetPositionController(); + Point3 additivum; + + if (additive) { + posCnt->GetValue(-1, &additivum, FOREVER); + } AnimateOn(); for (int i = 0; i < numFrames; i++) { Vector4A16 cVal; - t.GetValue(cVal, frameTimes[i]); + t->GetValue(cVal, frameTimes[i]); cVal *= IDC_EDIT_SCALE_value; Point3 kVal = reinterpret_cast(cVal); - if (fNode->GetParentNode()->IsRootNode()) + if (fNode->GetParentNode()->IsRootNode() && !additive) kVal = corMat.PointTransform(kVal); + kVal += additivum; posCnt->SetValue(frameTimesTicks[i], &kVal); } @@ -609,19 +619,25 @@ TimeValue MTFImport::LoadMotion(const uni::Motion &mot, TimeValue startTime) { } case uni::MotionTrack::TrackType_e::Rotation: { Control *rotCnt = cnt->GetRotationController(); + Quat additivum; + + if (additive) { + rotCnt->GetValue(-1, &additivum, FOREVER); + } AnimateOn(); for (int i = 0; i < numFrames; i++) { Vector4A16 cVal; - t.GetValue(cVal, frameTimes[i]); + t->GetValue(cVal, frameTimes[i]); Quat kVal = reinterpret_cast(cVal).Conjugate(); - if (fNode->GetParentNode()->IsRootNode()) { + if (fNode->GetParentNode()->IsRootNode() && !additive) { Matrix3 cMat; cMat.SetRotate(kVal); kVal = cMat * corMat; } + kVal += additivum; rotCnt->SetValue(frameTimesTicks[i], &kVal); } @@ -647,22 +663,43 @@ TimeValue MTFImport::LoadMotion(const uni::Motion &mot, TimeValue startTime) { return aniRange.End() + ticksPerFrame; } +void SwapLocale(); +static struct { + LMT asset; + TSTRING filename; +} lmtCache; + int MTFImport::DoImport(const TCHAR *fileName, ImpInterface * /*importerInt*/, - Interface * /*ip*/, BOOL suppressPrompts) { - REGISTER_CLASSES(LMTNode); - char *oldLocale = setlocale(LC_NUMERIC, NULL); - setlocale(LC_NUMERIC, "en-US"); + Interface * /*ip*/, BOOL suppressPrompts) try { + SwapLocale(); TSTRING _filename = fileName; LMT mainAsset; - if (mainAsset.Load(std::to_string(fileName).c_str(), true)) - return FALSE; + auto UpdateCache = [&](LMT &in) { + if (!flags[IDC_CH_NO_CACHE_checked]) { + lmtCache.asset = std::move(in); + } else { + lmtCache.filename.clear(); + } + }; + + if (lmtCache.filename == _filename) { + mainAsset = std::move(lmtCache.asset); + } else { + if (mainAsset.Load(std::to_string(fileName).c_str(), true)) { + SwapLocale(); + return FALSE; + } + + auto destroy = std::move(lmtCache.asset); + lmtCache.filename = _filename; + } int curMotionID = 0; for (auto &m : mainAsset) { - if (&m) + if (m) motionNames.push_back(ToTSTRING(curMotionID)); else motionNames.push_back(_T("--[Empty]--")); @@ -672,9 +709,13 @@ int MTFImport::DoImport(const TCHAR *fileName, ImpInterface * /*importerInt*/, instanceDialogType = DLGTYPE_LMT; - if (!suppressPrompts) - if (!SpawnDialog()) + if (!suppressPrompts) { + if (!SpawnDialog()) { + UpdateCache(mainAsset); + SwapLocale(); return TRUE; + } + } GetCOREInterface()->ClearNodeSelection(); @@ -687,10 +728,13 @@ int MTFImport::DoImport(const TCHAR *fileName, ImpInterface * /*importerInt*/, SetFrameRate(frameRate); if (flags[IDC_RD_ANISEL_checked]) { - uni::Motion *mot = mainAsset.At(IDC_CB_MOTION_index); + auto mot = mainAsset.At(IDC_CB_MOTION_index); - if (!mot) + if (!mot) { + UpdateCache(mainAsset); + SwapLocale(); return FALSE; + } mot->FrameRate(frameRate); LoadMotion(*mot, 0); @@ -698,15 +742,21 @@ int MTFImport::DoImport(const TCHAR *fileName, ImpInterface * /*importerInt*/, TimeValue lastTime = 0; int i = 0; - printline("Sequencer not found, dumping animation ranges:"); + printline("Sequencer not found, dumping animation ranges (in tick units):"); for (auto &a : mainAsset) { - a.FrameRate(frameRate); - TimeValue nextTime = LoadMotion(a, lastTime); + if (!a) { + i++; + continue; + } + + a->FrameRate(frameRate); + + TimeValue nextTime = LoadMotion(*a.get(), lastTime); printer << std::to_string(motionNames[i]) << ": " << lastTime << ", " << nextTime; - LMTAnimation &_a = static_cast(a); + const auto &_a = static_cast(*a.get()); if (_a.LoopFrame() > 0) printer << ", loopFrame: " << SecToTicks(_a.LoopFrame() / frameRate); @@ -720,10 +770,23 @@ int MTFImport::DoImport(const TCHAR *fileName, ImpInterface * /*importerInt*/, } iBoneScanner.RescanBones(); - iBoneScanner.RestoreBasePose(-GetTicksPerFrame()); + iBoneScanner.RestoreBasePose(-1); iBoneScanner.RestoreIKChains(); + UpdateCache(mainAsset); + SwapLocale(); - setlocale(LC_NUMERIC, oldLocale); - + return TRUE; +} catch (const std::exception &e) { + lmtCache.filename.clear(); + SwapLocale(); + auto msg = ToTSTRING(e.what()); + MessageBox(GetActiveWindow(), msg.data(), _T("Exception thrown!"), + MB_ICONERROR | MB_OK); + return TRUE; +} catch (...) { + lmtCache.filename.clear(); + SwapLocale(); + MessageBox(GetActiveWindow(), _T("Unhandled exception has been thrown!"), + _T("Exception thrown!"), MB_ICONERROR | MB_OK); return TRUE; } diff --git a/src/REEngineImport.cpp b/src/REEngineImport.cpp index 5e8f99d..0f90cca 100644 --- a/src/REEngineImport.cpp +++ b/src/REEngineImport.cpp @@ -18,7 +18,7 @@ */ #include "RevilMax.h" -#include "datas/masterprinter.hpp" +#include "datas/master_printer.hpp" #include "datas/tchar.hpp" #include "re_asset.hpp" #include "uni/motion.hpp" @@ -52,8 +52,8 @@ class REEngineImport : public SceneImport, RevilMax { std::unordered_map nodes; - void LoadSkeleton(uni::Skeleton *skel, TimeValue startTime = 0); - TimeValue LoadMotion(uni::Motion *mot, TimeValue startTime = 0); + void LoadSkeleton(const uni::Skeleton *skel, TimeValue startTime = 0); + TimeValue LoadMotion(const uni::Motion *mot, TimeValue startTime = 0); }; class : public ClassDesc2 { @@ -104,10 +104,10 @@ const TCHAR *REEngineImport::LongDesc() { return _T("RE Engine Import"); } const TCHAR *REEngineImport::ShortDesc() { return _T("RE Engine Import"); } -const TCHAR *REEngineImport::AuthorName() { return _T(RevilMax_AUTHOR); } +const TCHAR *REEngineImport::AuthorName() { return _T("Lukas Cone"); } const TCHAR *REEngineImport::CopyrightMessage() { - return _T(RevilMax_COPYRIGHT); + return _T(RevilMax_COPYRIGHT "Lukas Cone"); } const TCHAR *REEngineImport::OtherMessage1() { return _T(""); } @@ -118,12 +118,19 @@ unsigned int REEngineImport::Version() { return REVILMAX_VERSIONINT; } void REEngineImport::ShowAbout(HWND hWnd) { ShowAboutDLG(hWnd); } -void REEngineImport::LoadSkeleton(uni::Skeleton *skel, TimeValue startTime) { +void REEngineImport::LoadSkeleton(const uni::Skeleton *skel, + TimeValue startTime) { for (auto &b : *skel) { - TSTRING boneName = ToTSTRING(b.Name()); + TSTRING boneName = ToTSTRING(b->Name()); INode *node = GetCOREInterface()->GetINodeByName(boneName.c_str()); if (!node) { + if (flags[IDC_CH_ADDITIVE_checked]) { + if (!flags[IDC_CH_NOLOGBONES_checked]) { + printerror("Cannot find bone: " << b->Name()); + } + continue; + } Object *obj = static_cast( CreateInstance(HELPER_CLASS_ID, Class_ID(DUMMY_CLASS_ID, 0))); node = GetCOREInterface()->CreateObjectNode(obj); @@ -132,23 +139,25 @@ void REEngineImport::LoadSkeleton(uni::Skeleton *skel, TimeValue startTime) { node->SetName(ToBoneName(boneName)); } - auto boneTM = b.Transform(); - boneTM.Transpose(); + uni::RTSValue boneTM; + b->GetTM(boneTM); - Matrix3 nodeTM = { - reinterpret_cast(boneTM.r1), - reinterpret_cast(boneTM.r2), - reinterpret_cast(boneTM.r3), - reinterpret_cast(boneTM.r4 * IDC_EDIT_SCALE_value), - }; + Matrix3 nodeTM; + nodeTM.SetRotate( + reinterpret_cast(boneTM.rotation.QConjugate())); + nodeTM.SetTranslate(reinterpret_cast(boneTM.translation * + IDC_EDIT_SCALE_value)); - auto parentBone = b.Parent(); + auto parentBone = b->Parent(); - if (parentBone) { + if (parentBone && !flags[IDC_CH_ADDITIVE_checked]) { INode *pNode = nodes[parentBone->Index()]; pNode->AttachChild(node); - nodeTM *= pNode->GetNodeTM(startTime); + } else if (flags[IDC_CH_ADDITIVE_checked]) { + Matrix3 pMat = node->GetParentTM(-1); + pMat.Invert(); + nodeTM = node->GetNodeTM(-1) * pMat; } else { nodeTM *= corMat; } @@ -169,21 +178,26 @@ void REEngineImport::LoadSkeleton(uni::Skeleton *skel, TimeValue startTime) { Class_ID(LININTERP_SCALE_CLASS_ID, 0)) cnt->SetScaleController((Control *)CreateInstance( CTRL_SCALE_CLASS_ID, Class_ID(LININTERP_SCALE_CLASS_ID, 0))); + AnimateOn(); - node->SetNodeTM(startTime, nodeTM); + SetXFormPacket packet(nodeTM); + node->GetTMController()->SetValue(startTime, &packet); + node->GetTMController()->SetValue(-1, &packet); AnimateOff(); - node->SetUserPropString(_T("BoneHash"), ToTSTRING(b.Index()).c_str()); - nodes[b.Index()] = node; + + node->SetUserPropString(_T("BoneHash"), ToTSTRING(b->Index()).c_str()); + nodes[b->Index()] = node; } } -TimeValue REEngineImport::LoadMotion(uni::Motion *mot, TimeValue startTime) { +TimeValue REEngineImport::LoadMotion(const uni::Motion *mot, + TimeValue startTime) { if (!flags[IDC_CH_RESAMPLE_checked]) SetFrameRate(mot->FrameRate()); const float aDuration = mot->Duration(); TimeValue numTicks = SecToTicks(aDuration); - TimeValue ticksPerFrame = GetTicksPerFrame(); + const TimeValue ticksPerFrame = GetTicksPerFrame(); TimeValue overlappingTicks = numTicks % ticksPerFrame; if (overlappingTicks > (ticksPerFrame / 2)) @@ -196,7 +210,7 @@ TimeValue REEngineImport::LoadMotion(uni::Motion *mot, TimeValue startTime) { std::vector frameTimesTicks; for (TimeValue v = aniRange.Start(); v <= aniRange.End(); - v += GetTicksPerFrame()) { + v += ticksPerFrame) { frameTimes.push_back(TicksToSec(v - startTime)); frameTimesTicks.push_back(v); } @@ -210,13 +224,13 @@ TimeValue REEngineImport::LoadMotion(uni::Motion *mot, TimeValue startTime) { size_t numFrames = frameTimes.size(); for (auto &v : *mot) { - if (!nodes.count(v.BoneIndex())) + if (!nodes.count(v->BoneIndex())) continue; - INode *node = nodes[v.BoneIndex()]; + INode *node = nodes[v->BoneIndex()]; Control *cnt = node->GetTMController(); - switch (v.TrackType()) { + switch (v->TrackType()) { case uni::MotionTrack::Position: { Control *posControl = cnt->GetPositionController(); @@ -224,7 +238,7 @@ TimeValue REEngineImport::LoadMotion(uni::Motion *mot, TimeValue startTime) { for (int i = 0; i < numFrames; i++) { Vector4A16 cVal; - v.GetValue(cVal, frameTimes[i]); + v->GetValue(cVal, frameTimes[i]); cVal *= IDC_EDIT_SCALE_value; Point3 kVal = reinterpret_cast(cVal); @@ -245,7 +259,7 @@ TimeValue REEngineImport::LoadMotion(uni::Motion *mot, TimeValue startTime) { for (int i = 0; i < numFrames; i++) { Vector4A16 cVal; - v.GetValue(cVal, frameTimes[i]); + v->GetValue(cVal, frameTimes[i]); Quat kVal = reinterpret_cast(cVal).Conjugate(); if (node->GetParentNode()->IsRootNode()) { @@ -268,7 +282,7 @@ TimeValue REEngineImport::LoadMotion(uni::Motion *mot, TimeValue startTime) { for (int i = 0; i < numFrames; i++) { Vector4A16 cVal; - v.GetValue(cVal, frameTimes[i]); + v->GetValue(cVal, frameTimes[i]); Point3 kVal = reinterpret_cast(cVal); if (node->GetParentNode()->IsRootNode()) @@ -289,36 +303,74 @@ TimeValue REEngineImport::LoadMotion(uni::Motion *mot, TimeValue startTime) { return aniRange.End() + ticksPerFrame; } +void SwapLocale() { + static char *oldLocale = nullptr; + + if (oldLocale) { + setlocale(LC_NUMERIC, oldLocale); + oldLocale = nullptr; + } else { + oldLocale = setlocale(LC_NUMERIC, nullptr); + setlocale(LC_NUMERIC, "en-US"); + } +} + +static struct { + std::unique_ptr asset; + TSTRING filename; +} areCache; + int REEngineImport::DoImport(const TCHAR *fileName, ImpInterface * /*importerInt*/, Interface * /*ip*/, - BOOL suppressPrompts) { - char *oldLocale = setlocale(LC_NUMERIC, NULL); - setlocale(LC_NUMERIC, "en-US"); + BOOL suppressPrompts) try { + SwapLocale(); + TSTRING _filename = fileName; + std::unique_ptr mainAsset; + + auto UpdateCache = [&](std::unique_ptr &in) { + if (!flags[IDC_CH_NO_CACHE_checked]) { + areCache.asset = std::move(in); + } else { + areCache.filename.clear(); + } + }; - std::unique_ptr mainAsset( - REAsset::Load(std::to_string(fileName).c_str())); + if (areCache.filename == _filename) { + mainAsset = std::move(areCache.asset); + } else { + mainAsset = std::unique_ptr( + REAsset::Load(std::to_string(_filename).c_str(), true)); - if (!mainAsset) - return FALSE; + if (!mainAsset) { + SwapLocale(); + return FALSE; + } + auto destroy = std::move(areCache.asset); + areCache.filename = _filename; + } uni::List *motionList = dynamic_cast(mainAsset.get()); uni::List *skelList = dynamic_cast(mainAsset.get()); - uni::Motion *cMotion = nullptr; - uni::Skeleton *skel = skelList->Size() == 1 ? skelList->At(0) : nullptr; + uni::Element cMotion; + auto skel = skelList->Size() == 1 ? skelList->At(0) : nullptr; if (motionList && motionList->Size()) { for (auto &m : *motionList) { - motionNames.emplace_back(ToTSTRING(m.Name())); + motionNames.emplace_back(ToTSTRING(m->Name())); } - if (!suppressPrompts) - if (!SpawnDialog()) + if (!suppressPrompts) { + if (!SpawnDialog()) { + UpdateCache(mainAsset); + SwapLocale(); return TRUE; + } + } if (flags[IDC_RD_ANISEL_checked]) { - cMotion = motionList->At(IDC_CB_MOTION_index); + cMotion = std::move(motionList->At(IDC_CB_MOTION_index)); if (!skel && skelList->Size()) { skel = skelList->At(IDC_CB_MOTION_index); @@ -327,16 +379,17 @@ int REEngineImport::DoImport(const TCHAR *fileName, TimeValue lastTime = 0; int i = 0; - printline("Sequencer not found, dumping animation ranges:"); + printline( + "Sequencer not found, dumping animation ranges (in tick units):"); for (auto &m : *motionList) { if (skelList->Size()) { - uni::Skeleton *_skel = skel ? skel : skelList->At(i); + auto _skel = skel ? std::move(skel) : skelList->At(i); - LoadSkeleton(_skel, lastTime); + LoadSkeleton(_skel.get(), lastTime); } - TimeValue nextTime = LoadMotion(&m, lastTime); + TimeValue nextTime = LoadMotion(m.get(), lastTime); printer << std::to_string(motionNames[i]) << ": " << lastTime << ", " << nextTime >> 1; @@ -344,29 +397,47 @@ int REEngineImport::DoImport(const TCHAR *fileName, i++; } - setlocale(LC_NUMERIC, oldLocale); + SwapLocale(); + UpdateCache(mainAsset); return TRUE; } } if (!cMotion) { - cMotion = dynamic_cast(mainAsset.get()); + cMotion = std::move(decltype(cMotion){ + dynamic_cast(mainAsset.get()), false}); } if (!cMotion) { MessageBox(GetActiveWindow(), _T("Could't find any defined classes within file."), _T("Undefined file."), MB_ICONSTOP); + SwapLocale(); + UpdateCache(mainAsset); return TRUE; } if (skel) { - LoadSkeleton(skel); + LoadSkeleton(skel.get()); } - LoadMotion(cMotion); + LoadMotion(cMotion.get()); - setlocale(LC_NUMERIC, oldLocale); + SwapLocale(); + UpdateCache(mainAsset); return TRUE; +} catch (const std::exception &e) { + areCache.filename.clear(); + SwapLocale(); + auto msg = ToTSTRING(e.what()); + MessageBox(GetActiveWindow(), msg.data(), _T("Exception thrown!"), + MB_ICONERROR | MB_OK); + return TRUE; +} catch (...) { + areCache.filename.clear(); + SwapLocale(); + MessageBox(GetActiveWindow(), _T("Unhandled exception has been thrown!"), + _T("Exception thrown!"), MB_ICONERROR | MB_OK); + return TRUE; } diff --git a/src/RevilMax.cpp b/src/RevilMax.cpp index ae5ec0d..444c4b9 100644 --- a/src/RevilMax.cpp +++ b/src/RevilMax.cpp @@ -18,7 +18,7 @@ */ #include "RevilMax.h" -#include "datas/DirectoryScanner.hpp" +#include "datas/directory_scanner.hpp" #include "resource.h" #include <3dsmaxport.h> #include @@ -29,7 +29,7 @@ extern HINSTANCE hInstance; const TCHAR _name[] = _T("Revil Tool"); -const TCHAR _info[] = _T("\n" RevilMax_COPYRIGHT "\nVersion " RevilMax_VERSION); +const TCHAR _info[] = _T("\n" RevilMax_COPYRIGHT "Lukas Cone\nVersion " RevilMax_VERSION); const TCHAR _license[] = _T("Revil Tool uses RevilLib, Copyright(C) 2017-2020 Lukas Cone."); const TCHAR _homePage[] = @@ -59,6 +59,9 @@ void RevilMax::LoadCFG() { GetCFGChecked(IDC_RD_ANISEL); GetCFGChecked(IDC_RD_ANIALL); GetCFGChecked(IDC_CH_RESAMPLE); + GetCFGChecked(IDC_CH_ADDITIVE); + GetCFGChecked(IDC_CH_NO_CACHE); + GetCFGChecked(IDC_CH_NOLOGBONES); GetCFGEnabled(IDC_CB_MOTION); } @@ -72,6 +75,9 @@ void RevilMax::SaveCFG() { SetCFGChecked(IDC_RD_ANISEL); SetCFGChecked(IDC_RD_ANIALL); SetCFGChecked(IDC_CH_RESAMPLE); + SetCFGChecked(IDC_CH_ADDITIVE); + SetCFGChecked(IDC_CH_NO_CACHE); + SetCFGChecked(IDC_CH_NOLOGBONES); SetCFGEnabled(IDC_CB_MOTION); } @@ -198,6 +204,15 @@ static INT_PTR CALLBACK DialogCallbacks(HWND hWnd, UINT message, WPARAM wParam, MSGCheckbox(IDC_CH_RESAMPLE); break; + MSGCheckbox(IDC_CH_ADDITIVE); + break; + + MSGCheckbox(IDC_CH_NO_CACHE); + break; + + MSGCheckbox(IDC_CH_NOLOGBONES); + break; + MSGCheckbox(IDC_CH_DISABLEIK); break; @@ -247,4 +262,4 @@ static INT_PTR CALLBACK DialogCallbacks(HWND hWnd, UINT message, WPARAM wParam, int RevilMax::SpawnDialog() { return DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_REMOTION_IMPORT), GetActiveWindow(), DialogCallbacks, (LPARAM)this); -} \ No newline at end of file +} diff --git a/src/RevilMax.h b/src/RevilMax.h index 9718977..9c57608 100644 --- a/src/RevilMax.h +++ b/src/RevilMax.h @@ -59,7 +59,10 @@ class RevilMax { IDConfigBool(IDC_RD_ANIALL), IDConfigBool(IDC_RD_ANISEL), IDConfigBool(IDC_CH_RESAMPLE), + IDConfigBool(IDC_CH_ADDITIVE), IDConfigBool(IDC_CH_DISABLEIK), + IDConfigBool(IDC_CH_NO_CACHE), + IDConfigBool(IDC_CH_NOLOGBONES), IDConfigVisible(IDC_CB_MOTION), }; diff --git a/src/RevilMax.rc b/src/RevilMax.rc index f8250620f37eebb16b507fc4ce97a20cd960853d..f50c7bcc74fda193e4bcaaeaeedb822f0ed9441e 100644 GIT binary patch delta 483 zcmZvZJxc>Y5Qg6~(R|$HEAgipCDLWT z&qjv2YAuxMBWXvw5}*&QCYiJrJqz^8OnQmFi<&Isx@w#@$nQojk`i9MXw8u9dJZ$c~`@qtTo^63Fl~rFha?B~Gd`Rd(^$*DQCKU|Jgoyf+2E s!@ec*s<=}h*!`d0Dq9hY>`N%1JaB@ZZVtNl6l)Ighw=}3Gh^TWU+G$7Z~y=R delta 205 zcmZ2sKFerB1qZVwgW={{j?Ikh#tb?P<_t!Y*K$ct=HgeHT*76*ZVnggWj10km~6|v zlids`X2xJS`6IvZWC5N@V7>{1A(YQD`2ddvSj-e?)_