From daf3671233eef6272ec4544f68d69669ad5b957e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 16 Apr 2024 14:38:12 +0200 Subject: [PATCH] Fix model tool importing to use temp file only for Assimp --- .../Tools/ModelTool/ModelTool.Assimp.cpp | 10 +++-- .../ModelTool/ModelTool.AutodeskFbxSdk.cpp | 4 +- .../Tools/ModelTool/ModelTool.OpenFBX.cpp | 6 +-- Source/Engine/Tools/ModelTool/ModelTool.cpp | 39 +++---------------- Source/Engine/Tools/ModelTool/ModelTool.h | 6 +-- Source/Engine/Utilities/AnsiPathTempFile.h | 37 ++++++++++++++++++ 6 files changed, 58 insertions(+), 44 deletions(-) create mode 100644 Source/Engine/Utilities/AnsiPathTempFile.h diff --git a/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp b/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp index 91b1de48f..1b04092be 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp @@ -9,6 +9,7 @@ #include "Engine/Platform/FileSystem.h" #include "Engine/Platform/File.h" #include "Engine/Tools/TextureTool/TextureTool.h" +#include "Engine/Utilities/AnsiPathTempFile.h" // Import Assimp library // Source: https://github.com/assimp/assimp @@ -157,7 +158,7 @@ struct AssimpImporterData Array Bones; Dictionary> MeshIndexToNodeIndex; - AssimpImporterData(const char* path, const ModelTool::Options& options) + AssimpImporterData(const StringView& path, const ModelTool::Options& options) : Path(path) , Options(options) { @@ -735,7 +736,7 @@ void ImportAnimation(int32 index, ModelData& data, AssimpImporterData& importerD } } -bool ModelTool::ImportDataAssimp(const char* path, ModelData& data, Options& options, String& errorMsg) +bool ModelTool::ImportDataAssimp(const String& path, ModelData& data, Options& options, String& errorMsg) { static bool AssimpInited = false; if (!AssimpInited) @@ -784,7 +785,10 @@ bool ModelTool::ImportDataAssimp(const char* path, ModelData& data, Options& opt context.AssimpImporter.SetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true); // Import file - context.Scene = context.AssimpImporter.ReadFile(path, flags); + { + AnsiPathTempFile tempFile(path); + context.Scene = context.AssimpImporter.ReadFile(tempFile.Path.Get(), flags); + } if (context.Scene == nullptr) { LOG_STR(Warning, String(context.AssimpImporter.GetErrorString())); diff --git a/Source/Engine/Tools/ModelTool/ModelTool.AutodeskFbxSdk.cpp b/Source/Engine/Tools/ModelTool/ModelTool.AutodeskFbxSdk.cpp index 29b49952b..1ea6a22ad 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.AutodeskFbxSdk.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.AutodeskFbxSdk.cpp @@ -816,7 +816,7 @@ void BakeTransforms(FbxScene* scene) scene->GetRootNode()->ConvertPivotAnimationRecursive(nullptr, FbxNode::eDestinationPivot, frameRate, false); } -bool ModelTool::ImportDataAutodeskFbxSdk(const char* path, ImportedModelData& data, Options& options, String& errorMsg) +bool ModelTool::ImportDataAutodeskFbxSdk(const String& path, ImportedModelData& data, Options& options, String& errorMsg) { ScopeLock lock(FbxSdkManager::Locker); @@ -836,7 +836,7 @@ bool ModelTool::ImportDataAutodeskFbxSdk(const char* path, ImportedModelData& da auto ios = FbxSdkManager::Manager->GetIOSettings(); ios->SetBoolProp(IMP_FBX_MODEL, importMeshes); ios->SetBoolProp(IMP_FBX_ANIMATION, importAnimations); - if (!importer->Initialize(path, -1, ios)) + if (!importer->Initialize(StringAnsi(path), -1, ios)) { errorMsg = String::Format(TEXT("Failed to initialize FBX importer. {0}"), String(importer->GetStatus().GetErrorString())); return false; diff --git a/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp b/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp index c8f8f8102..5bf9ef7d8 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp @@ -103,7 +103,7 @@ struct OpenFbxImporterData Array Materials; Array ImportedMaterials; - OpenFbxImporterData(const char* path, const ModelTool::Options& options, ofbx::IScene* scene) + OpenFbxImporterData(const String& path, const ModelTool::Options& options, ofbx::IScene* scene) : Scene(scene) , ScenePtr(scene) , Path(path) @@ -1114,11 +1114,11 @@ static Float3 FbxVectorFromAxisAndSign(int axis, int sign) return { 0.f, 0.f, 0.f }; } -bool ModelTool::ImportDataOpenFBX(const char* path, ModelData& data, Options& options, String& errorMsg) +bool ModelTool::ImportDataOpenFBX(const String& path, ModelData& data, Options& options, String& errorMsg) { // Import file Array fileData; - if (File::ReadAllBytes(String(path), fileData)) + if (File::ReadAllBytes(path, fileData)) { errorMsg = TEXT("Cannot load file."); return true; diff --git a/Source/Engine/Tools/ModelTool/ModelTool.cpp b/Source/Engine/Tools/ModelTool/ModelTool.cpp index 47476140c..fc2298993 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.cpp @@ -471,64 +471,37 @@ bool ModelTool::ImportData(const String& path, ModelData& data, Options& options options.MergeMeshes = false; // Meshes merging doesn't make sense when we want to import each mesh individually // TODO: maybe we could update meshes merger to collapse meshes within the same name if splitting is enabled? - // Validate path - // Note: Assimp/Autodesk supports only ANSI characters in imported file path - StringAnsi importPath; - String tmpPath; - if (path.IsANSI() == false) - { - // Use temporary file - LOG(Warning, "Model Tool doesn't support importing files from paths using non ASNI characters. Using temporary file."); - FileSystem::GetTempFilePath(tmpPath); - if (tmpPath.IsANSI() == false || FileSystem::CopyFile(tmpPath, path)) - { - errorMsg = TEXT("Path with non ANSI characters is invalid."); - return true; - } - importPath = tmpPath.ToStringAnsi(); - } - else - { - importPath = path.ToStringAnsi(); - } - // Call importing backend #if (USE_AUTODESK_FBX_SDK || USE_OPEN_FBX) && USE_ASSIMP if (path.EndsWith(TEXT(".fbx"), StringSearchCase::IgnoreCase)) { #if USE_AUTODESK_FBX_SDK - if (ImportDataAutodeskFbxSdk(importPath.Get(), data, options, errorMsg)) + if (ImportDataAutodeskFbxSdk(path, data, options, errorMsg)) return true; #elif USE_OPEN_FBX - if (ImportDataOpenFBX(importPath.Get(), data, options, errorMsg)) + if (ImportDataOpenFBX(path, data, options, errorMsg)) return true; #endif } else { - if (ImportDataAssimp(importPath.Get(), data, options, errorMsg)) + if (ImportDataAssimp(path, data, options, errorMsg)) return true; } #elif USE_ASSIMP - if (ImportDataAssimp(importPath.Get(), data, options, errorMsg)) + if (ImportDataAssimp(path, data, options, errorMsg)) return true; #elif USE_AUTODESK_FBX_SDK - if (ImportDataAutodeskFbxSdk(importPath.Get(), data, options, errorMsg)) + if (ImportDataAutodeskFbxSdk(path, data, options, errorMsg)) return true; #elif USE_OPEN_FBX - if (ImportDataOpenFBX(importPath.Get(), data, options, errorMsg)) + if (ImportDataOpenFBX(path, data, options, errorMsg)) return true; #else LOG(Error, "Compiled without model importing backend."); return true; #endif - // Remove temporary file - if (tmpPath.HasChars() && FileSystem::FileExists(tmpPath)) - { - FileSystem::DeleteFile(tmpPath); - } - // Remove namespace prefixes from the nodes names { for (auto& node : data.Nodes) diff --git a/Source/Engine/Tools/ModelTool/ModelTool.h b/Source/Engine/Tools/ModelTool/ModelTool.h index 96d1ae6c0..ed1736214 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.h +++ b/Source/Engine/Tools/ModelTool/ModelTool.h @@ -386,13 +386,13 @@ public: private: static void CalculateBoneOffsetMatrix(const Array& nodes, Matrix& offsetMatrix, int32 nodeIndex); #if USE_ASSIMP - static bool ImportDataAssimp(const char* path, ModelData& data, Options& options, String& errorMsg); + static bool ImportDataAssimp(const String& path, ModelData& data, Options& options, String& errorMsg); #endif #if USE_AUTODESK_FBX_SDK - static bool ImportDataAutodeskFbxSdk(const char* path, ModelData& data, Options& options, String& errorMsg); + static bool ImportDataAutodeskFbxSdk(const String& path, ModelData& data, Options& options, String& errorMsg); #endif #if USE_OPEN_FBX - static bool ImportDataOpenFBX(const char* path, ModelData& data, Options& options, String& errorMsg); + static bool ImportDataOpenFBX(const String& path, ModelData& data, Options& options, String& errorMsg); #endif #endif }; diff --git a/Source/Engine/Utilities/AnsiPathTempFile.h b/Source/Engine/Utilities/AnsiPathTempFile.h new file mode 100644 index 000000000..b8165fe1e --- /dev/null +++ b/Source/Engine/Utilities/AnsiPathTempFile.h @@ -0,0 +1,37 @@ +// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Core/Types/String.h" +#include "Engine/Platform/FileSystem.h" + +// Small utility that uses temporary file to properly handle non-ANSI paths for 3rd party libs. +struct AnsiPathTempFile +{ + StringAnsi Path; + String TempPath; + bool Temp; + + AnsiPathTempFile(const String& path) + { + if (path.IsANSI() == false) + { + // Use temporary file + FileSystem::GetTempFilePath(TempPath); + if (TempPath.IsANSI() && !FileSystem::CopyFile(TempPath, path)) + { + Path = TempPath.ToStringAnsi(); + return; + } + TempPath.Clear(); + } + Path = path.ToStringAnsi(); + } + + ~AnsiPathTempFile() + { + // Cleanup temporary file after use + if (TempPath.HasChars()) + FileSystem::DeleteFile(TempPath); + } +};