diff --git a/Source/Editor/Content/Import/ModelImportEntry.cs b/Source/Editor/Content/Import/ModelImportEntry.cs index bbb384562..a29036c88 100644 --- a/Source/Editor/Content/Import/ModelImportEntry.cs +++ b/Source/Editor/Content/Import/ModelImportEntry.cs @@ -1,5 +1,6 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. +using System; using System.Collections.Generic; using FlaxEditor.CustomEditors.Editors; using FlaxEditor.Scripting; diff --git a/Source/Editor/Managed/ManagedEditor.Internal.cpp b/Source/Editor/Managed/ManagedEditor.Internal.cpp index bed9cfb5c..49a25f4e7 100644 --- a/Source/Editor/Managed/ManagedEditor.Internal.cpp +++ b/Source/Editor/Managed/ManagedEditor.Internal.cpp @@ -118,7 +118,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_IsDevInstance() #if COMPILE_WITH_DEV_ENV return true; #else - return false; + return false; #endif } @@ -151,7 +151,7 @@ DEFINE_INTERNAL_CALL(int32) EditorInternal_ReadOutputLogs(MArray** outMessages, int64* outLogTimesPtr = MCore::Array::GetAddress(*outLogTimes); while (count < maxCount && ptr != end) { - auto type = (byte)*(int32*)ptr; + auto type = (byte) * (int32*)ptr; ptr += 4; auto time = *(int64*)ptr; @@ -321,7 +321,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_SaveJsonAsset(MString* outputPathObj, const StringView dataObjChars = MCore::String::GetChars(dataObj); const StringAsANSI<> data(dataObjChars.Get(), dataObjChars.Length()); const StringAnsiView dataAnsi(data.Get(), data.Length()); - + const StringView dataTypeNameObjChars = MCore::String::GetChars(dataTypeNameObj); const StringAsANSI<> dataTypeName(dataTypeNameObjChars.Get(), dataTypeNameObjChars.Length()); const StringAnsiView dataTypeNameAnsi(dataTypeName.Get(), dataTypeName.Length()); @@ -338,7 +338,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CanExport(MString* pathObj) return AssetsExportingManager::CanExport(path); #else - return false; + return false; #endif } @@ -355,7 +355,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_Export(MString* inputPathObj, MString* return AssetsExportingManager::Export(inputPath, outputFolder); #else - return false; + return false; #endif } @@ -413,8 +413,8 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CookMeshCollision(MString* pathObj, Co arg.ConvexVertexLimit = convexVertexLimit; return CreateCollisionData::CookMeshCollision(path, arg); #else - LOG(Warning, "Collision cooking is disabled."); - return true; + LOG(Warning, "Collision cooking is disabled."); + return true; #endif } @@ -427,7 +427,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_GetCollisionWires(CollisionData* colli const int32 linesCount = debugLines.Count() / 2; MCore::GC::WriteRef(triangles, (MObject*)MCore::Array::New(Float3::TypeInitializer.GetClass(), debugLines.Count())); - MCore::GC::WriteRef(indices, (MObject*)MCore::Array::New( MCore::TypeCache::Int32, linesCount * 3)); + MCore::GC::WriteRef(indices, (MObject*)MCore::Array::New(MCore::TypeCache::Int32, linesCount * 3)); // Use one triangle per debug line Platform::MemoryCopy(MCore::Array::GetAddress(*triangles), debugLines.Get(), debugLines.Count() * sizeof(Float3)); @@ -522,7 +522,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_RunVisualScriptBreakpointLoopTick(floa continue; switch (e.Type) { - // Keyboard events + // Keyboard events case InputDevice::EventType::Char: window->OnCharInput(e.CharData.Char); break; @@ -532,7 +532,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_RunVisualScriptBreakpointLoopTick(floa case InputDevice::EventType::KeyUp: window->OnKeyUp(e.KeyData.Key); break; - // Mouse events + // Mouse events case InputDevice::EventType::MouseDown: window->OnMouseDown(window->ScreenToClient(e.MouseData.Position), e.MouseData.Button); break; @@ -585,7 +585,7 @@ DEFINE_INTERNAL_CALL(MArray*) EditorInternal_GetVisualScriptLocals(int* localsCo const int32 count = stack->Scope->Parameters.Length() + stack->Scope->ReturnedValues.Count(); const MClass* mclass = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEditor.Editor+VisualScriptLocal"); ASSERT(mclass); - result = MCore::Array::New( mclass, count); + result = MCore::Array::New(mclass, count); VisualScriptLocalManaged local; local.NodeId = MAX_uint32; if (stack->Scope->Parameters.Length() != 0) @@ -642,7 +642,7 @@ DEFINE_INTERNAL_CALL(MArray*) EditorInternal_GetVisualScriptStackFrames(int* sta } const MClass* mclass = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEditor.Editor+VisualScriptStackFrame"); ASSERT(mclass); - result = MCore::Array::New( mclass, count); + result = MCore::Array::New(mclass, count); VisualScriptStackFrameManaged* resultPtr = MCore::Array::GetAddress(result); s = stack; count = 0; diff --git a/Source/Engine/Content/Asset.h b/Source/Engine/Content/Asset.h index 2d2ba4b3f..0ecc6db3f 100644 --- a/Source/Engine/Content/Asset.h +++ b/Source/Engine/Content/Asset.h @@ -246,3 +246,4 @@ public: // Don't include Content.h but just Load method extern FLAXENGINE_API Asset* LoadAsset(const Guid& id, const ScriptingTypeHandle& type); +extern FLAXENGINE_API Asset* LoadAsset(const StringView& path, const ScriptingTypeHandle& type); diff --git a/Source/Engine/Content/Content.cpp b/Source/Engine/Content/Content.cpp index 6aecd1778..4ad97ebc2 100644 --- a/Source/Engine/Content/Content.cpp +++ b/Source/Engine/Content/Content.cpp @@ -28,6 +28,7 @@ #if ENABLE_ASSETS_DISCOVERY #include "Engine/Core/Collections/HashSet.h" #endif +#include TimeSpan Content::AssetsUpdateInterval = TimeSpan::FromMilliseconds(500); TimeSpan Content::AssetsUnloadInterval = TimeSpan::FromSeconds(10); @@ -447,6 +448,11 @@ FLAXENGINE_API Asset* LoadAsset(const Guid& id, const ScriptingTypeHandle& type) return Content::LoadAsync(id, type); } +FLAXENGINE_API Asset* LoadAsset(const StringView& path, const ScriptingTypeHandle& type) +{ + return Content::LoadAsync(path, type); +} + Asset* Content::LoadAsync(const StringView& path, MClass* type) { CHECK_RETURN(type, nullptr); diff --git a/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp b/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp index 1eb9e1f27..37b3f45a8 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp @@ -542,6 +542,7 @@ bool ProcessMesh(ImportedModelData& result, OpenFbxImporterData& data, const ofb else aMaterial = aMesh->getMaterial(0); } + mesh.MaterialSlotIndex = data.AddMaterial(result, aMaterial); // Vertex positions diff --git a/Source/Engine/Tools/ModelTool/ModelTool.cpp b/Source/Engine/Tools/ModelTool/ModelTool.cpp index f2dfd6927..13fc753af 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.cpp @@ -30,6 +30,7 @@ #include "Engine/Tools/TextureTool/TextureTool.h" #include "Engine/ContentImporters/AssetsImportingManager.h" #include "Engine/ContentImporters/CreateMaterial.h" +#include "Engine/ContentImporters/CreateMaterialInstance.h" #include "Engine/ContentImporters/CreateCollisionData.h" #include "Engine/Serialization/Serialization.h" #include "Editor/Utilities/EditorUtilities.h" @@ -498,11 +499,11 @@ bool ModelTool::ImportData(const String& path, ImportedModelData& data, Options& if (ImportDataAssimp(importPath.Get(), data, options, errorMsg)) return true; #elif USE_AUTODESK_FBX_SDK - if (ImportDataAutodeskFbxSdk(importPath.Get(), data, options, errorMsg)) - return true; + if (ImportDataAutodeskFbxSdk(importPath.Get(), data, options, errorMsg)) + return true; #elif USE_OPEN_FBX - if (ImportDataOpenFBX(importPath.Get(), data, options, errorMsg)) - return true; + if (ImportDataOpenFBX(importPath.Get(), data, options, errorMsg)) + return true; #else LOG(Error, "Compiled without model importing backend."); return true; @@ -615,62 +616,62 @@ bool ModelTool::ImportData(const String& path, ImportedModelData& data, Options& bool SortDepths(const Pair& a, const Pair& b) { - return a.First < b.First; + return a.First < b.First; } void CreateLinearListFromTree(Array& nodes, Array& mapping) { // Customized breadth first tree algorithm (each node has no direct reference to the children so we build the cache for the nodes depth level) - const int32 count = nodes.Count(); - Array> depths(count); // Pair.First = Depth, Pair.Second = Node Index - depths.SetSize(count); - depths.Set(-1); - for (int32 i = 0; i < count; i++) - { - // Skip evaluated nodes - if (depths[i].First != -1) - continue; + const int32 count = nodes.Count(); + Array> depths(count); // Pair.First = Depth, Pair.Second = Node Index + depths.SetSize(count); + depths.Set(-1); + for (int32 i = 0; i < count; i++) + { + // Skip evaluated nodes + if (depths[i].First != -1) + continue; - // Find the first node with calculated depth and get the distance to it - int32 end = i; - int32 lastDepth; - int32 relativeDepth = 0; - do - { - lastDepth = depths[end].First; - end = nodes[end].ParentIndex; - relativeDepth++; - } while (end != -1 && lastDepth == -1); + // Find the first node with calculated depth and get the distance to it + int32 end = i; + int32 lastDepth; + int32 relativeDepth = 0; + do + { + lastDepth = depths[end].First; + end = nodes[end].ParentIndex; + relativeDepth++; + } while (end != -1 && lastDepth == -1); - // Set the depth (second item is the node index) - depths[i] = MakePair(lastDepth + relativeDepth, i); - } - for (int32 i = 0; i < count; i++) - { - // Strange divide by 2 but works - depths[i].First = depths[i].First >> 1; - } + // Set the depth (second item is the node index) + depths[i] = MakePair(lastDepth + relativeDepth, i); + } + for (int32 i = 0; i < count; i++) + { + // Strange divide by 2 but works + depths[i].First = depths[i].First >> 1; + } - // Order nodes by depth O(n*log(n)) - depths.Sort(SortDepths); + // Order nodes by depth O(n*log(n)) + depths.Sort(SortDepths); - // Extract nodes mapping O(n^2) - mapping.EnsureCapacity(count, false); - mapping.SetSize(count); - for (int32 i = 0; i < count; i++) - { - int32 newIndex = -1; - for (int32 j = 0; j < count; j++) - { - if (depths[j].Second == i) - { - newIndex = j; - break; - } - } - ASSERT(newIndex != -1); - mapping[i] = newIndex; - } + // Extract nodes mapping O(n^2) + mapping.EnsureCapacity(count, false); + mapping.SetSize(count); + for (int32 i = 0; i < count; i++) + { + int32 newIndex = -1; + for (int32 j = 0; j < count; j++) + { + if (depths[j].Second == i) + { + newIndex = j; + break; + } + } + ASSERT(newIndex != -1); + mapping[i] = newIndex; + } } #endif @@ -938,7 +939,7 @@ bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options& op case TextureEntry::TypeHint::Normals: textureOptions.Type = TextureFormatType::NormalMap; break; - default: ; + default:; } AssetsImportingManager::ImportIfEdited(texture.FilePath, assetPath, texture.AssetID, &textureOptions); #endif @@ -973,24 +974,47 @@ bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options& op importedFileNames.Add(filename); #if COMPILE_WITH_ASSETS_IMPORTER auto assetPath = autoImportOutput / filename + ASSET_FILES_EXTENSION_WITH_DOT; - CreateMaterial::Options materialOptions; - materialOptions.Diffuse.Color = material.Diffuse.Color; - if (material.Diffuse.TextureIndex != -1) - materialOptions.Diffuse.Texture = data.Textures[material.Diffuse.TextureIndex].AssetID; - materialOptions.Diffuse.HasAlphaMask = material.Diffuse.HasAlphaMask; - materialOptions.Emissive.Color = material.Emissive.Color; - if (material.Emissive.TextureIndex != -1) - materialOptions.Emissive.Texture = data.Textures[material.Emissive.TextureIndex].AssetID; - materialOptions.Opacity.Value = material.Opacity.Value; - if (material.Opacity.TextureIndex != -1) - materialOptions.Opacity.Texture = data.Textures[material.Opacity.TextureIndex].AssetID; - if (material.Normals.TextureIndex != -1) - materialOptions.Normals.Texture = data.Textures[material.Normals.TextureIndex].AssetID; - if (material.TwoSided || material.Diffuse.HasAlphaMask) - materialOptions.Info.CullMode = CullMode::TwoSided; - if (!Math::IsOne(material.Opacity.Value) || material.Opacity.TextureIndex != -1) - materialOptions.Info.BlendMode = MaterialBlendMode::Transparent; - AssetsImportingManager::Create(AssetsImportingManager::CreateMaterialTag, assetPath, material.AssetID, &materialOptions); + if (options.ImportMaterialsAsInstances) + { + AssetsImportingManager::Create(AssetsImportingManager::CreateMaterialInstanceTag, assetPath, material.AssetID); + MaterialInstance* materialInstance = (MaterialInstance*) LoadAsset(assetPath, MaterialInstance::TypeInitializer); + if (materialInstance->WaitForLoaded()) + { + LOG(Error, "Failed to load material instance after creation. ({0})", assetPath); + return true; + } + + MaterialBase* materialInstanceOf = (MaterialBase*) LoadAsset(options.InstanceToImportAs, MaterialBase::TypeInitializer); + if (materialInstanceOf->WaitForLoaded()) + { + LOG(Error, "Failed to load material to create an instance of. ({0})", options.InstanceToImportAs); + return true; + } + + materialInstance->SetBaseMaterial(materialInstanceOf); + materialInstance->Save(); + } + else + { + CreateMaterial::Options materialOptions; + materialOptions.Diffuse.Color = material.Diffuse.Color; + if (material.Diffuse.TextureIndex != -1) + materialOptions.Diffuse.Texture = data.Textures[material.Diffuse.TextureIndex].AssetID; + materialOptions.Diffuse.HasAlphaMask = material.Diffuse.HasAlphaMask; + materialOptions.Emissive.Color = material.Emissive.Color; + if (material.Emissive.TextureIndex != -1) + materialOptions.Emissive.Texture = data.Textures[material.Emissive.TextureIndex].AssetID; + materialOptions.Opacity.Value = material.Opacity.Value; + if (material.Opacity.TextureIndex != -1) + materialOptions.Opacity.Texture = data.Textures[material.Opacity.TextureIndex].AssetID; + if (material.Normals.TextureIndex != -1) + materialOptions.Normals.Texture = data.Textures[material.Normals.TextureIndex].AssetID; + if (material.TwoSided || material.Diffuse.HasAlphaMask) + materialOptions.Info.CullMode = CullMode::TwoSided; + if (!Math::IsOne(material.Opacity.Value) || material.Opacity.TextureIndex != -1) + materialOptions.Info.BlendMode = MaterialBlendMode::Transparent; + AssetsImportingManager::Create(AssetsImportingManager::CreateMaterialTag, assetPath, material.AssetID, &materialOptions); + } #endif } @@ -1364,24 +1388,24 @@ bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options& op #if USE_SKELETON_NODES_SORTING // Sort skeleton nodes and bones hierarchy (parents first) - // Then it can be used with a simple linear loop update - { - const int32 nodesCount = data.Skeleton.Nodes.Count(); - const int32 bonesCount = data.Skeleton.Bones.Count(); - Array mapping; - CreateLinearListFromTree(data.Skeleton.Nodes, mapping); - for (int32 i = 0; i < nodesCount; i++) - { - auto& node = data.Skeleton.Nodes[i]; - node.ParentIndex = mapping[node.ParentIndex]; - } - for (int32 i = 0; i < bonesCount; i++) - { - auto& bone = data.Skeleton.Bones[i]; - bone.NodeIndex = mapping[bone.NodeIndex]; - } - } - reorder_nodes_and_test_it_out! + // Then it can be used with a simple linear loop update + { + const int32 nodesCount = data.Skeleton.Nodes.Count(); + const int32 bonesCount = data.Skeleton.Bones.Count(); + Array mapping; + CreateLinearListFromTree(data.Skeleton.Nodes, mapping); + for (int32 i = 0; i < nodesCount; i++) + { + auto& node = data.Skeleton.Nodes[i]; + node.ParentIndex = mapping[node.ParentIndex]; + } + for (int32 i = 0; i < bonesCount; i++) + { + auto& bone = data.Skeleton.Bones[i]; + bone.NodeIndex = mapping[bone.NodeIndex]; + } + } + reorder_nodes_and_test_it_out! #endif } else if (options.Type == ModelType::Animation) diff --git a/Source/Engine/Tools/ModelTool/ModelTool.h b/Source/Engine/Tools/ModelTool/ModelTool.h index 985bd3ccc..992a929ca 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.h +++ b/Source/Engine/Tools/ModelTool/ModelTool.h @@ -11,6 +11,7 @@ #include "Engine/Graphics/Models/ModelData.h" #include "Engine/Graphics/Models/SkeletonData.h" #include "Engine/Animations/AnimationData.h" +#include class JsonWriter; diff --git a/Source/ThirdParty/OpenFBX/ofbx.h b/Source/ThirdParty/OpenFBX/ofbx.h index 7066659e3..87dd5999f 100644 --- a/Source/ThirdParty/OpenFBX/ofbx.h +++ b/Source/ThirdParty/OpenFBX/ofbx.h @@ -1,4 +1,5 @@ #pragma once +#include namespace ofbx