From 847a28d133a43cdeb1d98ac796e45a5a1a753960 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Fri, 3 Feb 2023 22:14:21 +0200 Subject: [PATCH 01/37] Fix running VC++-project build commands with Rider on Linux --- .../VisualStudio/VCProjectGenerator.cs | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs index deed99bd7..395e3ab54 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs @@ -105,8 +105,9 @@ namespace Flax.Build.Projects.VisualStudio vcProjectFileContent.AppendLine(" MakeFileProj"); if (Version >= VisualStudioVersion.VisualStudio2022) vcProjectFileContent.AppendLine(" false"); + vcProjectFileContent.AppendLine(" ./"); vcProjectFileContent.AppendLine(" "); - + // Default properties vcProjectFileContent.AppendLine(" "); @@ -343,6 +344,32 @@ namespace Flax.Build.Projects.VisualStudio vcUserFileContent.AppendLine(""); + if (platforms.Any(x => x.Target == TargetPlatform.Linux)) + { + // Override MSBuild .targets file with one that runs NMake commands (workaround for Rider on Linux) + var cppTargetsFileContent = new StringBuilder(); + cppTargetsFileContent.AppendLine(""); + cppTargetsFileContent.AppendLine(" "); + cppTargetsFileContent.AppendLine(" "); + cppTargetsFileContent.AppendLine(" "); + cppTargetsFileContent.AppendLine(" "); + cppTargetsFileContent.AppendLine(" "); + cppTargetsFileContent.AppendLine(" "); + cppTargetsFileContent.AppendLine(" "); + cppTargetsFileContent.AppendLine(" "); + cppTargetsFileContent.AppendLine(" "); + cppTargetsFileContent.AppendLine(" "); + cppTargetsFileContent.AppendLine(" "); + cppTargetsFileContent.AppendLine(" $(RootNamespace)$(Configuration.Split('.')[0])"); + cppTargetsFileContent.AppendLine(" $(OutDir)/$(TargetName)$(TargetExt)"); + cppTargetsFileContent.AppendLine(" "); + cppTargetsFileContent.AppendLine(""); + + Utilities.WriteFileIfChanged(Path.Combine(projectDirectory, "Microsoft.Cpp.targets"), cppTargetsFileContent.ToString()); + Utilities.WriteFileIfChanged(Path.Combine(projectDirectory, "Microsoft.Cpp.Default.props"), vcUserFileContent.ToString()); + Utilities.WriteFileIfChanged(Path.Combine(projectDirectory, "Microsoft.Cpp.props"), vcUserFileContent.ToString()); + } + // Save the files Utilities.WriteFileIfChanged(project.Path, vcProjectFileContent.ToString()); Utilities.WriteFileIfChanged(project.Path + ".filters", vcFiltersFileContent.ToString()); From ffbd34c95aeed69929b36d3c42be662b29484182 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Fri, 3 Feb 2023 22:02:57 +0200 Subject: [PATCH 02/37] Improve Rider detection on Linux --- Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp b/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp index e88f3356b..438331e11 100644 --- a/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp +++ b/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp @@ -36,7 +36,7 @@ namespace // Load product info Array productInfoData; const String productInfoPath = directory / TEXT("product-info.json"); - if (File::ReadAllBytes(productInfoPath, productInfoData)) + if (!FileSystem::FileExists(productInfoPath) || File::ReadAllBytes(productInfoPath, productInfoData)) return; rapidjson_flax::Document document; document.Parse((char*)productInfoData.Get(), productInfoData.Count()); @@ -193,6 +193,7 @@ void RiderCodeEditor::FindEditors(Array* output) // TODO: detect Snap installations // TODO: detect by reading the jetbrains-rider.desktop file from ~/.local/share/applications and /usr/share/applications? + SearchDirectory(&installations, TEXT("/usr/share/rider/")); FileSystem::GetChildDirectories(subDirectories, TEXT("/usr/share/rider")); // Default suggested location for standalone installations From cc4864231f614302c85eae359745253f95998eec Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sat, 11 Feb 2023 20:02:36 +0200 Subject: [PATCH 03/37] Use input focus to manage context menu hiding logic --- .../Editor/GUI/ContextMenu/ContextMenuBase.cs | 83 ++++++------------- 1 file changed, 24 insertions(+), 59 deletions(-) diff --git a/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs b/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs index f93e31957..8596ab83b 100644 --- a/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs +++ b/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs @@ -196,7 +196,6 @@ namespace FlaxEditor.GUI.ContextMenu desc.HasSizingFrame = false; OnWindowCreating(ref desc); _window = Platform.CreateWindow(ref desc); - _window.GotFocus += OnWindowGotFocus; _window.LostFocus += OnWindowLostFocus; // Attach to the window @@ -326,48 +325,6 @@ namespace FlaxEditor.GUI.ContextMenu // Nothing to do } - /// - /// Returns true if context menu is in foreground (eg. context window or any child window has user focus or user opened additional popup within this context). - /// - protected virtual bool IsForeground - { - get - { - // Any external popup is focused - foreach (var externalPopup in ExternalPopups) - { - if (externalPopup && externalPopup.IsForegroundWindow) - return true; - } - - // Any context menu window is focused - var anyForeground = false; - var c = this; - while (!anyForeground && c != null) - { - if (c._window != null && c._window.IsForegroundWindow) - anyForeground = true; - c = c._childCM; - } - - return anyForeground; - } - } - - private void OnWindowGotFocus() - { - var child = _childCM; - if (child != null && _window && _window.IsForegroundWindow) - { - // Hide child if user clicked over parent (do it next frame to process other events before - eg. child windows focus loss) - FlaxEngine.Scripting.InvokeOnUpdate(() => - { - if (child == _childCM) - HideChild(); - }); - } - } - private void OnWindowLostFocus() { // Skip for parent menus (child should handle lost of focus) @@ -377,13 +334,33 @@ namespace FlaxEditor.GUI.ContextMenu // Check if user stopped using that popup menu if (_parentCM != null) { - // Focus parent if user clicked over the parent popup - var mouse = _parentCM.PointFromScreen(FlaxEngine.Input.MouseScreenPosition); - if (_parentCM.ContainsPoint(ref mouse)) + if (IsMouseOver) + return; + + // Check if mouse is over any of the parents + ContextMenuBase focusCM = null; + var cm = _parentCM; + while (cm != null) { - _parentCM._window.Focus(); + if (cm.IsMouseOver) + focusCM = cm; + cm = cm._parentCM; + } + + if (focusCM != null) + { + // Focus on the clicked parent and hide any open sub-menus + focusCM.HideChild(); + focusCM._window?.Focus(); + } + else + { + // User clicked outside the context menus, hide the whole context menu tree + TopmostCM.Hide(); } } + else if (!IsMouseOver) + Hide(); } /// @@ -405,18 +382,6 @@ namespace FlaxEditor.GUI.ContextMenu } } - /// - public override void Update(float deltaTime) - { - base.Update(deltaTime); - - // Let root context menu to check if none of the popup windows - if (_parentCM == null && !IsForeground) - { - Hide(); - } - } - /// public override void Draw() { From 6b634322ff871ee99624153718c7422fd4c87483 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 12 Feb 2023 14:10:11 +0200 Subject: [PATCH 04/37] Fix active tooltip preventing TreeNode selection --- Source/Editor/GUI/Tree/TreeNode.cs | 39 ++++++++++++++++++------------ 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/Source/Editor/GUI/Tree/TreeNode.cs b/Source/Editor/GUI/Tree/TreeNode.cs index 54aeedb9a..f2c8e2d6a 100644 --- a/Source/Editor/GUI/Tree/TreeNode.cs +++ b/Source/Editor/GUI/Tree/TreeNode.cs @@ -700,6 +700,8 @@ namespace FlaxEditor.GUI.Tree /// public override bool OnMouseDown(Float2 location, MouseButton button) { + UpdateMouseOverFlags(location); + // Check if mouse hits bar and node isn't a root if (_mouseOverHeader) { @@ -728,6 +730,8 @@ namespace FlaxEditor.GUI.Tree /// public override bool OnMouseUp(Float2 location, MouseButton button) { + UpdateMouseOverFlags(location); + // Clear flag for left button if (button == MouseButton.Left) { @@ -815,21 +819,7 @@ namespace FlaxEditor.GUI.Tree /// public override void OnMouseMove(Float2 location) { - // Cache flags - _mouseOverArrow = HasAnyVisibleChild && ArrowRect.Contains(location); - _mouseOverHeader = new Rectangle(0, 0, Width, _headerHeight - 1).Contains(location); - if (_mouseOverHeader) - { - // Allow non-scrollable controls to stay on top of the header and override the mouse behaviour - for (int i = 0; i < Children.Count; i++) - { - if (!Children[i].IsScrollable && IntersectsChildContent(Children[i], location, out _)) - { - _mouseOverHeader = false; - break; - } - } - } + UpdateMouseOverFlags(location); // Check if start drag and drop if (_isMouseDown && Float2.Distance(_mouseDownPos, location) > 10.0f) @@ -852,6 +842,25 @@ namespace FlaxEditor.GUI.Tree } } + private void UpdateMouseOverFlags(Vector2 location) + { + // Cache flags + _mouseOverArrow = HasAnyVisibleChild && ArrowRect.Contains(location); + _mouseOverHeader = new Rectangle(0, 0, Width, _headerHeight - 1).Contains(location); + if (_mouseOverHeader) + { + // Allow non-scrollable controls to stay on top of the header and override the mouse behaviour + for (int i = 0; i < Children.Count; i++) + { + if (!Children[i].IsScrollable && IntersectsChildContent(Children[i], location, out _)) + { + _mouseOverHeader = false; + break; + } + } + } + } + /// public override void OnMouseLeave() { From e3a96fa7244c8a09f831091531c9338ae5d44ca5 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 12 Feb 2023 14:11:04 +0200 Subject: [PATCH 05/37] Fix tooltip not hiding after clicking on TreeNode --- Source/Engine/UI/GUI/Tooltip.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Engine/UI/GUI/Tooltip.cs b/Source/Engine/UI/GUI/Tooltip.cs index 9180d6d58..5089e0211 100644 --- a/Source/Engine/UI/GUI/Tooltip.cs +++ b/Source/Engine/UI/GUI/Tooltip.cs @@ -179,6 +179,8 @@ namespace FlaxEngine.GUI /// The target. public void OnMouseLeaveControl(Control target) { + if (Visible) + Hide(); _lastTarget = null; } From df000bc99e9ab65210530bb715a6be8c37497e53 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Mon, 13 Feb 2023 20:06:59 +0200 Subject: [PATCH 06/37] Fix linking against C#-only modules (cherry picked from commit 7ccc0b83ff3a5775fc4de0a06f4c099f5514e5ce) --- Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs b/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs index ae6c62c7d..aee48066e 100644 --- a/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs +++ b/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs @@ -799,7 +799,7 @@ namespace Flax.Build moduleOptions.CompileEnv.PreprocessorDefinitions.Add(dependencyModule.BinaryModuleName.ToUpperInvariant() + "_API=" + toolchain.DllImport); var dependencyModuleBuild = buildData.FinReferenceBuildModule(moduleName); - if (dependencyModuleBuild != null) + if (dependencyModuleBuild != null && !string.IsNullOrEmpty(dependencyModuleBuild.NativePath)) { // Link against the referenced binary module if (toolchain.UseImportLibraryWhenLinking) From 123b7f5433599b078710eb8f7800b61e9300b207 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 16 Feb 2023 13:47:43 +0100 Subject: [PATCH 07/37] Fix `Mesh` data downloading to support not yet streamed vertex/index data gather #932 --- Source/Engine/Graphics/Mesh.cs | 28 ++- Source/Engine/Graphics/Models/Mesh.cpp | 165 ++++++++---------- Source/Engine/Graphics/Models/Mesh.h | 2 +- Source/Engine/Graphics/Models/SkinnedMesh.cpp | 146 +++++++--------- Source/Engine/Graphics/Models/SkinnedMesh.h | 2 +- Source/Engine/Graphics/SkinnedMesh.cs | 17 +- 6 files changed, 158 insertions(+), 202 deletions(-) diff --git a/Source/Engine/Graphics/Mesh.cs b/Source/Engine/Graphics/Mesh.cs index d4f693e77..0a986d44d 100644 --- a/Source/Engine/Graphics/Mesh.cs +++ b/Source/Engine/Graphics/Mesh.cs @@ -527,9 +527,8 @@ namespace FlaxEngine /// The gathered data. public Vertex0[] DownloadVertexBuffer0(bool forceGpu = false) { - var vertices = VertexCount; - var result = new Vertex0[vertices]; - if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB0)) + var result = (Vertex0[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex0), (int)InternalBufferType.VB0); + if (result == null) throw new Exception("Failed to download mesh data."); return result; } @@ -541,9 +540,8 @@ namespace FlaxEngine /// The gathered data. public Vertex1[] DownloadVertexBuffer1(bool forceGpu = false) { - var vertices = VertexCount; - var result = new Vertex1[vertices]; - if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB1)) + var result = (Vertex1[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex1), (int)InternalBufferType.VB1); + if (result == null) throw new Exception("Failed to download mesh data."); return result; } @@ -560,10 +558,8 @@ namespace FlaxEngine { if (!HasVertexColors) return null; - - var vertices = VertexCount; - var result = new Vertex2[vertices]; - if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB2)) + var result = (Vertex2[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex2), (int)InternalBufferType.VB2); + if (result == null) throw new Exception("Failed to download mesh data."); return result; } @@ -582,7 +578,7 @@ namespace FlaxEngine var vb1 = DownloadVertexBuffer1(forceGpu); var vb2 = DownloadVertexBuffer2(forceGpu); - var vertices = VertexCount; + var vertices = vb0.Length; var result = new Vertex[vertices]; for (int i = 0; i < vertices; i++) { @@ -618,9 +614,8 @@ namespace FlaxEngine /// The gathered data. public uint[] DownloadIndexBuffer(bool forceGpu = false) { - var triangles = TriangleCount; - var result = new uint[triangles * 3]; - if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB32)) + var result = (uint[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(uint), (int)InternalBufferType.IB32); + if (result == null) throw new Exception("Failed to download mesh data."); return result; } @@ -633,9 +628,8 @@ namespace FlaxEngine /// The gathered data. public ushort[] DownloadIndexBufferUShort(bool forceGpu = false) { - var triangles = TriangleCount; - var result = new ushort[triangles * 3]; - if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB16)) + var result = (ushort[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(ushort), (int)InternalBufferType.IB16); + if (result == null) throw new Exception("Failed to download mesh data."); return result; } diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp index 7b0130874..335b4cb69 100644 --- a/Source/Engine/Graphics/Models/Mesh.cpp +++ b/Source/Engine/Graphics/Models/Mesh.cpp @@ -746,75 +746,11 @@ enum class InternalBufferType IB32 = 4, }; -void ConvertMeshData(Mesh* mesh, InternalBufferType type, MonoArray* resultObj, void* srcData) +MonoArray* Mesh::DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI) { - auto vertices = mesh->GetVertexCount(); - auto triangles = mesh->GetTriangleCount(); - auto indices = triangles * 3; - auto use16BitIndexBuffer = mesh->Use16BitIndexBuffer(); - - void* managedArrayPtr = mono_array_addr_with_size(resultObj, 0, 0); - switch (type) - { - case InternalBufferType::VB0: - { - Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB0ElementType) * vertices); - break; - } - case InternalBufferType::VB1: - { - Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB1ElementType) * vertices); - break; - } - case InternalBufferType::VB2: - { - Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB2ElementType) * vertices); - break; - } - case InternalBufferType::IB16: - { - if (use16BitIndexBuffer) - { - Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint16) * indices); - } - else - { - auto dst = (uint16*)managedArrayPtr; - auto src = (uint32*)srcData; - for (int32 i = 0; i < indices; i++) - { - dst[i] = src[i]; - } - } - break; - } - case InternalBufferType::IB32: - { - if (use16BitIndexBuffer) - { - auto dst = (uint32*)managedArrayPtr; - auto src = (uint16*)srcData; - for (int32 i = 0; i < indices; i++) - { - dst[i] = src[i]; - } - } - else - { - Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint32) * indices); - } - break; - } - } -} - -bool Mesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI) -{ - Mesh* mesh = this; - InternalBufferType type = (InternalBufferType)typeI; + auto mesh = this; + auto type = (InternalBufferType)typeI; auto model = mesh->GetModel(); - ASSERT(model && resultObj); - ScopeLock lock(model->Locker); // Virtual assets always fetch from GPU memory @@ -823,23 +759,7 @@ bool Mesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI) if (!mesh->IsInitialized() && forceGpu) { LOG(Error, "Cannot load mesh data from GPU if it's not loaded."); - return true; - } - if (type == InternalBufferType::IB16 || type == InternalBufferType::IB32) - { - if (mono_array_length(resultObj) != mesh->GetTriangleCount() * 3) - { - LOG(Error, "Invalid buffer size."); - return true; - } - } - else - { - if (mono_array_length(resultObj) != mesh->GetVertexCount()) - { - LOG(Error, "Invalid buffer size."); - return true; - } + return nullptr; } MeshBufferType bufferType; @@ -859,35 +779,96 @@ bool Mesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI) bufferType = MeshBufferType::Index; break; default: - return true; + return nullptr; } BytesContainer data; + int32 dataCount; if (forceGpu) { // Get data from GPU // TODO: support reusing the input memory buffer to perform a single copy from staging buffer to the input CPU buffer auto task = mesh->DownloadDataGPUAsync(bufferType, data); if (task == nullptr) - return true; + return nullptr; task->Start(); model->Locker.Unlock(); if (task->Wait()) { LOG(Error, "Task failed."); - return true; + return nullptr; } model->Locker.Lock(); + + // Extract elements count from result data + switch (bufferType) + { + case MeshBufferType::Index: + dataCount = data.Length() / (Use16BitIndexBuffer() ? sizeof(uint16) : sizeof(uint32)); + break; + case MeshBufferType::Vertex0: + dataCount = data.Length() / sizeof(VB0ElementType); + break; + case MeshBufferType::Vertex1: + dataCount = data.Length() / sizeof(VB1ElementType); + break; + case MeshBufferType::Vertex2: + dataCount = data.Length() / sizeof(VB2ElementType); + break; + } } else { // Get data from CPU - int32 count; - if (DownloadDataCPU(bufferType, data, count)) - return true; + if (DownloadDataCPU(bufferType, data, dataCount)) + return nullptr; } - ConvertMeshData(mesh, type, resultObj, data.Get()); - return false; + // Convert into managed array + MonoArray* result = mono_array_new(mono_domain_get(), mono_type_get_class(mono_reflection_type_get_type(resultType)), dataCount); + void* managedArrayPtr = mono_array_addr_with_size(result, 0, 0); + const int32 elementSize = data.Length() / dataCount; + switch (type) + { + case InternalBufferType::VB0: + case InternalBufferType::VB1: + case InternalBufferType::VB2: + { + Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length()); + break; + } + case InternalBufferType::IB16: + { + if (elementSize == sizeof(uint16)) + { + Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length()); + } + else + { + auto dst = (uint16*)managedArrayPtr; + auto src = (uint32*)data.Get(); + for (int32 i = 0; i < dataCount; i++) + dst[i] = src[i]; + } + break; + } + case InternalBufferType::IB32: + { + if (elementSize == sizeof(uint16)) + { + auto dst = (uint32*)managedArrayPtr; + auto src = (uint16*)data.Get(); + for (int32 i = 0; i < dataCount; i++) + dst[i] = src[i]; + } + else + { + Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length()); + } + break; + } + } + + return result; } #endif diff --git a/Source/Engine/Graphics/Models/Mesh.h b/Source/Engine/Graphics/Models/Mesh.h index ee16c16e3..9b1ab4846 100644 --- a/Source/Engine/Graphics/Models/Mesh.h +++ b/Source/Engine/Graphics/Models/Mesh.h @@ -321,6 +321,6 @@ private: API_FUNCTION(NoProxy) bool UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj); API_FUNCTION(NoProxy) bool UpdateTrianglesUInt(int32 triangleCount, MonoArray* trianglesObj); API_FUNCTION(NoProxy) bool UpdateTrianglesUShort(int32 triangleCount, MonoArray* trianglesObj); - API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI); + API_FUNCTION(NoProxy) MonoArray* DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI); #endif }; diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.cpp b/Source/Engine/Graphics/Models/SkinnedMesh.cpp index 89db8ff8b..f33b8b4fd 100644 --- a/Source/Engine/Graphics/Models/SkinnedMesh.cpp +++ b/Source/Engine/Graphics/Models/SkinnedMesh.cpp @@ -516,64 +516,12 @@ enum class InternalBufferType IB32 = 4, }; -void ConvertMeshData(SkinnedMesh* mesh, InternalBufferType type, MonoArray* resultObj, void* srcData) -{ - auto vertices = mesh->GetVertexCount(); - auto triangles = mesh->GetTriangleCount(); - auto indices = triangles * 3; - auto use16BitIndexBuffer = mesh->Use16BitIndexBuffer(); - - void* managedArrayPtr = mono_array_addr_with_size(resultObj, 0, 0); - switch (type) - { - case InternalBufferType::VB0: - { - Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB0SkinnedElementType) * vertices); - break; - } - case InternalBufferType::IB16: - { - if (use16BitIndexBuffer) - { - Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint16) * indices); - } - else - { - auto dst = (uint16*)managedArrayPtr; - auto src = (uint32*)srcData; - for (int32 i = 0; i < indices; i++) - { - dst[i] = src[i]; - } - } - break; - } - case InternalBufferType::IB32: - { - if (use16BitIndexBuffer) - { - auto dst = (uint32*)managedArrayPtr; - auto src = (uint16*)srcData; - for (int32 i = 0; i < indices; i++) - { - dst[i] = src[i]; - } - } - else - { - Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint32) * indices); - } - break; - } - } -} - -bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI) +MonoArray* SkinnedMesh::DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI) { SkinnedMesh* mesh = this; InternalBufferType type = (InternalBufferType)typeI; auto model = mesh->GetSkinnedModel(); - ASSERT(model && resultObj); + ScopeLock lock(model->Locker); // Virtual assets always fetch from GPU memory forceGpu |= model->IsVirtual(); @@ -581,23 +529,7 @@ bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 type if (!mesh->IsInitialized() && forceGpu) { LOG(Error, "Cannot load mesh data from GPU if it's not loaded."); - return true; - } - if (type == InternalBufferType::IB16 || type == InternalBufferType::IB32) - { - if (mono_array_length(resultObj) != mesh->GetTriangleCount() * 3) - { - LOG(Error, "Invalid buffer size."); - return true; - } - } - else - { - if (mono_array_length(resultObj) != mesh->GetVertexCount()) - { - LOG(Error, "Invalid buffer size."); - return true; - } + return nullptr; } MeshBufferType bufferType; @@ -610,37 +542,89 @@ bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 type case InternalBufferType::IB32: bufferType = MeshBufferType::Index; break; - default: CRASH; - return true; + default: + return nullptr; } BytesContainer data; + int32 dataCount; if (forceGpu) { // Get data from GPU // TODO: support reusing the input memory buffer to perform a single copy from staging buffer to the input CPU buffer auto task = mesh->DownloadDataGPUAsync(bufferType, data); if (task == nullptr) - return true; + return nullptr; task->Start(); model->Locker.Unlock(); if (task->Wait()) { LOG(Error, "Task failed."); - return true; + return nullptr; } model->Locker.Lock(); + + // Extract elements count from result data + switch (bufferType) + { + case MeshBufferType::Index: + dataCount = data.Length() / (Use16BitIndexBuffer() ? sizeof(uint16) : sizeof(uint32)); + break; + case MeshBufferType::Vertex0: + dataCount = data.Length() / sizeof(VB0SkinnedElementType); + break; + } } else { // Get data from CPU - int32 count; - if (DownloadDataCPU(bufferType, data, count)) - return true; + if (DownloadDataCPU(bufferType, data, dataCount)) + return nullptr; } - // Convert into managed memory - ConvertMeshData(mesh, type, resultObj, data.Get()); - return false; + // Convert into managed array + MonoArray* result = mono_array_new(mono_domain_get(), mono_type_get_class(mono_reflection_type_get_type(resultType)), dataCount); + void* managedArrayPtr = mono_array_addr_with_size(result, 0, 0); + const int32 elementSize = data.Length() / dataCount; + switch (type) + { + case InternalBufferType::VB0: + { + Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length()); + break; + } + case InternalBufferType::IB16: + { + if (elementSize == sizeof(uint16)) + { + Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length()); + } + else + { + auto dst = (uint16*)managedArrayPtr; + auto src = (uint32*)data.Get(); + for (int32 i = 0; i < dataCount; i++) + dst[i] = src[i]; + } + break; + } + case InternalBufferType::IB32: + { + if (elementSize == sizeof(uint16)) + { + auto dst = (uint32*)managedArrayPtr; + auto src = (uint16*)data.Get(); + for (int32 i = 0; i < dataCount; i++) + dst[i] = src[i]; + } + else + { + Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length()); + } + break; + } + } + + return result; } #endif diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.h b/Source/Engine/Graphics/Models/SkinnedMesh.h index 8bf957554..57a382cff 100644 --- a/Source/Engine/Graphics/Models/SkinnedMesh.h +++ b/Source/Engine/Graphics/Models/SkinnedMesh.h @@ -199,6 +199,6 @@ private: #if !COMPILE_WITHOUT_CSHARP API_FUNCTION(NoProxy) bool UpdateMeshUInt(MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj); API_FUNCTION(NoProxy) bool UpdateMeshUShort(MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj); - API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI); + API_FUNCTION(NoProxy) MonoArray* DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI); #endif }; diff --git a/Source/Engine/Graphics/SkinnedMesh.cs b/Source/Engine/Graphics/SkinnedMesh.cs index 5998c6a1e..8fb7a83dc 100644 --- a/Source/Engine/Graphics/SkinnedMesh.cs +++ b/Source/Engine/Graphics/SkinnedMesh.cs @@ -274,9 +274,8 @@ namespace FlaxEngine /// The gathered data. public Vertex0[] DownloadVertexBuffer0(bool forceGpu = false) { - var vertices = VertexCount; - var result = new Vertex0[vertices]; - if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB0)) + var result = (Vertex0[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex0), (int)InternalBufferType.VB0); + if (result == null) throw new Exception("Failed to download mesh data."); return result; } @@ -292,7 +291,7 @@ namespace FlaxEngine var vb0 = DownloadVertexBuffer0(forceGpu); - var vertices = VertexCount; + var vertices = vb0.Length; var result = new Vertex[vertices]; for (int i = 0; i < vertices; i++) { @@ -319,9 +318,8 @@ namespace FlaxEngine /// The gathered data. public uint[] DownloadIndexBuffer(bool forceGpu = false) { - var triangles = TriangleCount; - var result = new uint[triangles * 3]; - if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB32)) + var result = (uint[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(uint), (int)InternalBufferType.IB32); + if (result == null) throw new Exception("Failed to download mesh data."); return result; } @@ -334,9 +332,8 @@ namespace FlaxEngine /// The gathered data. public ushort[] DownloadIndexBufferUShort(bool forceGpu = false) { - var triangles = TriangleCount; - var result = new ushort[triangles * 3]; - if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB16)) + var result = (ushort[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(ushort), (int)InternalBufferType.IB16); + if (result == null) throw new Exception("Failed to download mesh data."); return result; } From 969053a2407b271ac3a5fb9a7c28dfd7c1382b48 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 16 Feb 2023 14:32:52 +0100 Subject: [PATCH 08/37] Add `JsonAsset.Save` to fix saving new tag #885 --- .../Editor/CustomEditors/Editors/TagEditor.cs | 4 +- Source/Engine/Content/JsonAsset.cpp | 59 +++++++++- Source/Engine/Content/JsonAsset.h | 11 ++ .../Localization/LocalizedStringTable.cpp | 107 +++++++----------- .../Localization/LocalizedStringTable.h | 12 +- 5 files changed, 105 insertions(+), 88 deletions(-) diff --git a/Source/Editor/CustomEditors/Editors/TagEditor.cs b/Source/Editor/CustomEditors/Editors/TagEditor.cs index 8a4333a9b..948663892 100644 --- a/Source/Editor/CustomEditors/Editors/TagEditor.cs +++ b/Source/Editor/CustomEditors/Editors/TagEditor.cs @@ -174,9 +174,7 @@ namespace FlaxEditor.CustomEditors.Editors for (int i = 0; i < subInputs.Length; i++) { if (string.IsNullOrEmpty(subInputs[i])) - { continue; - } // Check all entered subtags and create any that dont exist for (int j = 0; j <= i; j++) @@ -296,6 +294,7 @@ namespace FlaxEditor.CustomEditors.Editors settingsObj.Tags.Add(tagName); settingsObj.Tags.Sort(); settingsAsset.SetInstance(settingsObj); + settingsAsset.Save(); // Reload editor window to reflect new tag assetWindow?.RefreshAsset(); @@ -417,7 +416,6 @@ namespace FlaxEditor.CustomEditors.Editors { if (!uniqueText) return; - OnAddTagButtonClicked(nameTextBox.Text, tree, nameTextBox, addTagDropPanel, pickerData); }; diff --git a/Source/Engine/Content/JsonAsset.cpp b/Source/Engine/Content/JsonAsset.cpp index 6fdfca74e..2e1dc2f0e 100644 --- a/Source/Engine/Content/JsonAsset.cpp +++ b/Source/Engine/Content/JsonAsset.cpp @@ -37,12 +37,8 @@ String JsonAssetBase::GetData() const if (Data == nullptr) return String::Empty; PROFILE_CPU_NAMED("JsonAsset.GetData"); - - // Get serialized data rapidjson_flax::StringBuffer buffer; - rapidjson_flax::Writer writer(buffer); - Data->Accept(writer); - + OnGetData(buffer); return String((const char*)buffer.GetString(), (int32)buffer.GetSize()); } @@ -83,6 +79,12 @@ bool JsonAssetBase::Init(const StringView& dataTypeName, const StringAnsiView& d return loadAsset() != LoadResult::Ok; } +void JsonAssetBase::OnGetData(rapidjson_flax::StringBuffer& buffer) const +{ + PrettyJsonWriter writerObj(buffer); + Data->Accept(writerObj.GetWriter()); +} + const String& JsonAssetBase::GetPath() const { #if USE_EDITOR @@ -144,6 +146,53 @@ void JsonAssetBase::GetReferences(const StringAnsiView& json, Array& outpu FindIds(document, output); } +bool JsonAssetBase::Save(const StringView& path) +{ + // Validate state + if (WaitForLoaded()) + { + LOG(Error, "Asset loading failed. Cannot save it."); + return true; + } + if (IsVirtual() && path.IsEmpty()) + { + LOG(Error, "To save virtual asset asset you need to specify the target asset path location."); + return true; + } + ScopeLock lock(Locker); + + // Serialize to json file + rapidjson_flax::StringBuffer buffer; + PrettyJsonWriter writerObj(buffer); + JsonWriter& writer = writerObj; + writer.StartObject(); + { + // Json resource header + writer.JKEY("ID"); + writer.Guid(GetID()); + writer.JKEY("TypeName"); + writer.String(DataTypeName); + writer.JKEY("EngineBuild"); + writer.Int(FLAXENGINE_VERSION_BUILD); + + // Json resource data + rapidjson_flax::StringBuffer dataBuffer; + OnGetData(dataBuffer); + writer.JKEY("Data"); + writer.RawValue(dataBuffer.GetString(), (int32)dataBuffer.GetSize()); + } + writer.EndObject(); + + // Save json to file + if (File::WriteAllBytes(path.HasChars() ? path : GetPath(), (byte*)buffer.GetString(), (int32)buffer.GetSize())) + { + LOG(Error, "Cannot save \'{0}\'", ToString()); + return true; + } + + return false; +} + void JsonAssetBase::GetReferences(Array& output) const { if (Data == nullptr) diff --git a/Source/Engine/Content/JsonAsset.h b/Source/Engine/Content/JsonAsset.h index 9fca675ee..ca52ac86b 100644 --- a/Source/Engine/Content/JsonAsset.h +++ b/Source/Engine/Content/JsonAsset.h @@ -72,8 +72,19 @@ public: /// The Json string. /// The output list of object IDs references by the asset (appended, not cleared). API_FUNCTION() static void GetReferences(const StringAnsiView& json, API_PARAM(Out) Array& output); + + /// + /// Saves this asset to the file. Supported only in Editor. + /// + /// The custom asset path to use for the saving. Use empty value to save this asset to its own storage location. Can be used to duplicate asset. Must be specified when saving virtual asset. + /// True if cannot save data, otherwise false. + API_FUNCTION() bool Save(const StringView& path = StringView::Empty); #endif +protected: + // Gets the serialized Json data (from runtime state). + virtual void OnGetData(rapidjson_flax::StringBuffer& buffer) const; + public: // [Asset] const String& GetPath() const override; diff --git a/Source/Engine/Localization/LocalizedStringTable.cpp b/Source/Engine/Localization/LocalizedStringTable.cpp index 63a364e77..9c01736bd 100644 --- a/Source/Engine/Localization/LocalizedStringTable.cpp +++ b/Source/Engine/Localization/LocalizedStringTable.cpp @@ -55,75 +55,6 @@ String LocalizedStringTable::GetPluralString(const String& id, int32 n) const return String::Format(result.GetText(), n); } -#if USE_EDITOR - -bool LocalizedStringTable::Save(const StringView& path) -{ - // Validate state - if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); - return true; - } - if (IsVirtual() && path.IsEmpty()) - { - LOG(Error, "To save virtual asset asset you need to specify the target asset path location."); - return true; - } - - ScopeLock lock(Locker); - - // Serialize data - rapidjson_flax::StringBuffer outputData; - PrettyJsonWriter writerObj(outputData); - JsonWriter& writer = writerObj; - writer.StartObject(); - { - writer.JKEY("Locale"); - writer.String(Locale); - - if (FallbackTable.GetID().IsValid()) - { - writer.JKEY("FallbackTable"); - writer.Guid(FallbackTable.GetID()); - } - - writer.JKEY("Entries"); - writer.StartObject(); - for (auto& e : Entries) - { - writer.Key(e.Key); - if (e.Value.Count() == 1) - { - writer.String(e.Value[0]); - } - else - { - writer.StartArray(); - for (auto& q : e.Value) - writer.String(q); - writer.EndArray(); - } - } - writer.EndObject(); - } - writer.EndObject(); - - // Save asset -#if COMPILE_WITH_ASSETS_IMPORTER - const bool saveResult = CreateJson::Create(path.HasChars() ? path : StringView(GetPath()), outputData, TypeName); - if (saveResult) -#endif - { - LOG(Error, "Cannot save \'{0}\'", ToString()); - return true; - } - - return false; -} - -#endif - Asset::LoadResult LocalizedStringTable::loadAsset() { // Base @@ -170,3 +101,41 @@ void LocalizedStringTable::unload(bool isReloading) FallbackTable = nullptr; Entries.Clear(); } + +void LocalizedStringTable::OnGetData(rapidjson_flax::StringBuffer& buffer) const +{ + PrettyJsonWriter writerObj(buffer); + JsonWriter& writer = writerObj; + writer.StartObject(); + { + writer.JKEY("Locale"); + writer.String(Locale); + + if (FallbackTable.GetID().IsValid()) + { + writer.JKEY("FallbackTable"); + writer.Guid(FallbackTable.GetID()); + } + + writer.JKEY("Entries"); + writer.StartObject(); + for (auto& e : Entries) + { + writer.Key(e.Key); + if (e.Value.Count() == 1) + { + writer.String(e.Value[0]); + } + else + { + writer.StartArray(); + for (auto& q : e.Value) + writer.String(q); + writer.EndArray(); + } + } + writer.EndObject(); + } + writer.EndObject(); +} + diff --git a/Source/Engine/Localization/LocalizedStringTable.h b/Source/Engine/Localization/LocalizedStringTable.h index e52b5cc3f..4024d5d3a 100644 --- a/Source/Engine/Localization/LocalizedStringTable.h +++ b/Source/Engine/Localization/LocalizedStringTable.h @@ -61,19 +61,9 @@ public: /// The localized text. API_FUNCTION() String GetPluralString(const String& id, int32 n) const; -#if USE_EDITOR - - /// - /// Saves this asset to the file. Supported only in Editor. - /// - /// The custom asset path to use for the saving. Use empty value to save this asset to its own storage location. Can be used to duplicate asset. Must be specified when saving virtual asset. - /// True if cannot save data, otherwise false. - API_FUNCTION() bool Save(const StringView& path = StringView::Empty); - -#endif - protected: // [JsonAssetBase] LoadResult loadAsset() override; void unload(bool isReloading) override; + void OnGetData(rapidjson_flax::StringBuffer& buffer) const override; }; From f8aa1cd5f8fdeea9129a7a97c807f75eccf3df4f Mon Sep 17 00:00:00 2001 From: "W2.Wizard" Date: Thu, 16 Feb 2023 15:23:18 +0100 Subject: [PATCH 09/37] Updated transform Gizmos #340 --- Content/Editor/Gizmo/Axis.flax | 3 - Content/Editor/Gizmo/MaterialSphere.flax | 3 + Content/Editor/Gizmo/RotationAxis.flax | 3 + Content/Editor/Gizmo/ScaleAxis.flax | 4 +- Content/Editor/Gizmo/TranslateAxis.flax | 3 - Content/Editor/Gizmo/TranslationAxis.flax | 3 + Content/Editor/Gizmo/WireCircle.flax | 3 - Flax.flaxproj | 2 +- .../Editor/Gizmo/TransformGizmoBase.Draw.cs | 159 +++++++++++------- .../Gizmo/TransformGizmoBase.Selection.cs | 50 ++++-- .../Gizmo/TransformGizmoBase.Settings.cs | 85 +++++----- Source/Engine/Core/Math/BoundingBox.cs | 38 +++++ Source/FlaxEngine.Gen.cs | 4 +- Source/FlaxEngine.Gen.h | 6 +- 14 files changed, 224 insertions(+), 142 deletions(-) delete mode 100644 Content/Editor/Gizmo/Axis.flax create mode 100644 Content/Editor/Gizmo/MaterialSphere.flax create mode 100644 Content/Editor/Gizmo/RotationAxis.flax delete mode 100644 Content/Editor/Gizmo/TranslateAxis.flax create mode 100644 Content/Editor/Gizmo/TranslationAxis.flax delete mode 100644 Content/Editor/Gizmo/WireCircle.flax diff --git a/Content/Editor/Gizmo/Axis.flax b/Content/Editor/Gizmo/Axis.flax deleted file mode 100644 index c2b0a30f0..000000000 --- a/Content/Editor/Gizmo/Axis.flax +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f32f2401c2c6eb05d1674f98950f4d9ff0a9508d42fa25413eba3a49a0be9363 -size 11800 diff --git a/Content/Editor/Gizmo/MaterialSphere.flax b/Content/Editor/Gizmo/MaterialSphere.flax new file mode 100644 index 000000000..bf110acfb --- /dev/null +++ b/Content/Editor/Gizmo/MaterialSphere.flax @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf88f48c5de6b8fb8c7effbbdded9e6f115b1a3ac262d60785987c8f24107dfb +size 567 diff --git a/Content/Editor/Gizmo/RotationAxis.flax b/Content/Editor/Gizmo/RotationAxis.flax new file mode 100644 index 000000000..a743e30a6 --- /dev/null +++ b/Content/Editor/Gizmo/RotationAxis.flax @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d8f319dcd39842cb991a4e8e67e4823c7159a493a1aec757232077e5d56ad9f +size 41685 diff --git a/Content/Editor/Gizmo/ScaleAxis.flax b/Content/Editor/Gizmo/ScaleAxis.flax index 150b1e1dd..8f774c883 100644 --- a/Content/Editor/Gizmo/ScaleAxis.flax +++ b/Content/Editor/Gizmo/ScaleAxis.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:feb61724fc4fd620de5e3cedf6f74485d38aea4f3a88bf44ecdc186424d14b04 -size 3933 +oid sha256:8743967dc27d5839b88dfa1e599cbc9b290427afd6b65b2424ffa5218b330beb +size 40754 diff --git a/Content/Editor/Gizmo/TranslateAxis.flax b/Content/Editor/Gizmo/TranslateAxis.flax deleted file mode 100644 index a97bbc780..000000000 --- a/Content/Editor/Gizmo/TranslateAxis.flax +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:011c8be02f11017c28b300601b19f12c8750b256d0aabe060c519794c4578d41 -size 7757 diff --git a/Content/Editor/Gizmo/TranslationAxis.flax b/Content/Editor/Gizmo/TranslationAxis.flax new file mode 100644 index 000000000..f91e2b18a --- /dev/null +++ b/Content/Editor/Gizmo/TranslationAxis.flax @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a6096ef866920a861ec91f0660999a9ea07b2fbd26bcf52ba2c0112ba5e02336 +size 8915 diff --git a/Content/Editor/Gizmo/WireCircle.flax b/Content/Editor/Gizmo/WireCircle.flax deleted file mode 100644 index 1378ea4f6..000000000 --- a/Content/Editor/Gizmo/WireCircle.flax +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:901ae5ba301bf22697e4f7ced101f97dfe6ef38771f940c0c38e43125157d080 -size 139269 diff --git a/Flax.flaxproj b/Flax.flaxproj index 2553a3727..c3c825910 100644 --- a/Flax.flaxproj +++ b/Flax.flaxproj @@ -3,7 +3,7 @@ "Version": { "Major": 1, "Minor": 5, - "Build": 6336 + "Build": 6337 }, "Company": "Flax", "Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.", diff --git a/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs b/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs index 77a9cb017..0d421a17e 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs @@ -6,44 +6,48 @@ namespace FlaxEditor.Gizmo { public partial class TransformGizmoBase { - private Model _modelTranslateAxis; + // Models + private Model _modelTranslationAxis; private Model _modelScaleAxis; - private Model _modelBox; - private Model _modelCircle; + private Model _modelRotationAxis; + private Model _modelSphere; + private Model _modelCube; + + // Materials private MaterialInstance _materialAxisX; private MaterialInstance _materialAxisY; private MaterialInstance _materialAxisZ; private MaterialInstance _materialAxisFocus; - private MaterialBase _materialWire; - private MaterialBase _materialWireFocus; + private MaterialBase _materialSphere; private void InitDrawing() { - // Load content (but async - don't wait and don't block execution) - _modelTranslateAxis = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/TranslateAxis"); + // Axis Models + _modelTranslationAxis = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/TranslationAxis"); _modelScaleAxis = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/ScaleAxis"); - _modelBox = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/WireBox"); - _modelCircle = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/WireCircle"); + _modelRotationAxis = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/RotationAxis"); + _modelSphere = FlaxEngine.Content.LoadAsyncInternal("Editor/Primitives/Sphere"); + _modelCube = FlaxEngine.Content.LoadAsyncInternal("Editor/Primitives/Cube"); + + // Axis Materials _materialAxisX = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/MaterialAxisX"); _materialAxisY = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/MaterialAxisY"); _materialAxisZ = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/MaterialAxisZ"); _materialAxisFocus = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/MaterialAxisFocus"); - _materialWire = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/MaterialWire"); - _materialWireFocus = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/MaterialWireFocus"); + _materialSphere = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/MaterialSphere"); // Ensure that every asset was loaded - if (_modelTranslateAxis == null || + if (_modelTranslationAxis == null || _modelScaleAxis == null || - _modelBox == null || - _modelCircle == null || + _modelRotationAxis == null || + _modelSphere == null || + _modelCube == null || _materialAxisX == null || _materialAxisY == null || _materialAxisZ == null || _materialAxisFocus == null || - _materialWire == null || - _materialWireFocus == null) + _materialSphere == null) { - // Error Platform.Fatal("Failed to load transform gizmo resources."); } } @@ -58,6 +62,8 @@ namespace FlaxEditor.Gizmo // https://github.com/FlaxEngine/FlaxEngine/issues/680 Matrix m1, m2, m3, mx1; + float boxScale = 300f; + float boxSize = 0.085f; bool isXAxis = _activeAxis == Axis.X || _activeAxis == Axis.XY || _activeAxis == Axis.ZX; bool isYAxis = _activeAxis == Axis.Y || _activeAxis == Axis.XY || _activeAxis == Axis.YZ; bool isZAxis = _activeAxis == Axis.Z || _activeAxis == Axis.YZ || _activeAxis == Axis.ZX; @@ -65,114 +71,137 @@ namespace FlaxEditor.Gizmo renderContext.View.GetWorldMatrix(ref _gizmoWorld, out Matrix world); const float gizmoModelsScale2RealGizmoSize = 0.075f; + Mesh sphereMesh, cubeMesh; switch (_activeMode) { case Mode.Translate: { - if (!_modelTranslateAxis || !_modelTranslateAxis.IsLoaded || !_modelBox || !_modelBox.IsLoaded) + if (!_modelTranslationAxis || !_modelTranslationAxis.IsLoaded || !_modelCube || !_modelCube.IsLoaded || !_modelSphere || !_modelSphere.IsLoaded) break; + var transAxisMesh = _modelTranslationAxis.LODs[0].Meshes[0]; + cubeMesh = _modelCube.LODs[0].Meshes[0]; + sphereMesh = _modelSphere.LODs[0].Meshes[0]; Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3); Matrix.Multiply(ref m3, ref world, out m1); mx1 = m1; mx1.M41 += 0.05f; - var axisMesh = _modelTranslateAxis.LODs[0].Meshes[0]; - var boxMesh = _modelBox.LODs[0].Meshes[0]; - var boxSize = 10.0f; - - // XY plane - m2 = Matrix.Transformation(new Vector3(boxSize, 1.0f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * 0.5f, boxSize * 0.5f, 0.0f)); - Matrix.Multiply(ref m2, ref m1, out m3); - boxMesh.Draw(ref renderContext, _activeAxis == Axis.XY ? _materialWireFocus : _materialWire, ref m3); - - // ZX plane - m2 = Matrix.Transformation(new Vector3(boxSize, 1.0f, boxSize), Quaternion.Identity, new Vector3(boxSize * 0.5f, 0.0f, boxSize * 0.5f)); - Matrix.Multiply(ref m2, ref m1, out m3); - boxMesh.Draw(ref renderContext, _activeAxis == Axis.ZX ? _materialWireFocus : _materialWire, ref m3); - - // YZ plane - m2 = Matrix.Transformation(new Vector3(boxSize, 1.0f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * 0.5f, boxSize * 0.5f)); - Matrix.Multiply(ref m2, ref m1, out m3); - boxMesh.Draw(ref renderContext, _activeAxis == Axis.YZ ? _materialWireFocus : _materialWire, ref m3); // X axis - axisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref mx1); - - // Y axis - Matrix.RotationZ(Mathf.PiOverTwo, out m2); - Matrix.Multiply(ref m2, ref m1, out m3); - axisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m3); - - // Z axis Matrix.RotationY(-Mathf.PiOverTwo, out m2); Matrix.Multiply(ref m2, ref m1, out m3); - axisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3); + transAxisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3); + + // Y axis + Matrix.RotationX(Mathf.PiOverTwo, out m2); + Matrix.Multiply(ref m2, ref m1, out m3); + transAxisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m3); + + // Z axis + Matrix.RotationX(Mathf.Pi, out m2); + Matrix.Multiply(ref m2, ref m1, out m3); + transAxisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3); + + // XY plane + m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f)); + Matrix.Multiply(ref m2, ref m1, out m3); + cubeMesh.Draw(ref renderContext, _activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX, ref m3); + + // ZX plane + m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale)); + Matrix.Multiply(ref m2, ref m1, out m3); + cubeMesh.Draw(ref renderContext, _activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisZ, ref m3); + + // YZ plane + m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale)); + Matrix.Multiply(ref m2, ref m1, out m3); + cubeMesh.Draw(ref renderContext, _activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisY, ref m3); + + // Center sphere + Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2); + Matrix.Multiply(ref m2, ref m1, out m3); + sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3); break; } case Mode.Rotate: { - if (!_modelCircle || !_modelCircle.IsLoaded || !_modelBox || !_modelBox.IsLoaded) + if (!_modelRotationAxis || !_modelRotationAxis.IsLoaded || !_modelSphere || !_modelSphere.IsLoaded) break; - var circleMesh = _modelCircle.LODs[0].Meshes[0]; - var boxMesh = _modelBox.LODs[0].Meshes[0]; - Matrix.Scaling(8.0f, out m3); + var rotationAxisMesh = _modelRotationAxis.LODs[0].Meshes[0]; + sphereMesh = _modelSphere.LODs[0].Meshes[0]; + Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3); Matrix.Multiply(ref m3, ref world, out m1); + mx1 = m1; + mx1.M41 += 0.05f; // X axis Matrix.RotationZ(Mathf.PiOverTwo, out m2); Matrix.Multiply(ref m2, ref m1, out m3); - circleMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3); + rotationAxisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3); // Y axis - circleMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m1); + rotationAxisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m1); // Z axis Matrix.RotationX(-Mathf.PiOverTwo, out m2); Matrix.Multiply(ref m2, ref m1, out m3); - circleMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3); + rotationAxisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3); // Center box - Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3); - Matrix.Multiply(ref m3, ref world, out m1); - Matrix.Scaling(1.0f, out m2); + Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2); Matrix.Multiply(ref m2, ref m1, out m3); - boxMesh.Draw(ref renderContext, isCenter ? _materialWireFocus : _materialWire, ref m3); + sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3); break; } case Mode.Scale: { - if (!_modelScaleAxis || !_modelScaleAxis.IsLoaded || !_modelBox || !_modelBox.IsLoaded) + if (!_modelScaleAxis || !_modelScaleAxis.IsLoaded || !_modelCube || !_modelCube.IsLoaded || !_modelSphere || !_modelSphere.IsLoaded) break; + var scaleAxisMesh = _modelScaleAxis.LODs[0].Meshes[0]; + cubeMesh = _modelCube.LODs[0].Meshes[0]; + sphereMesh = _modelSphere.LODs[0].Meshes[0]; Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3); Matrix.Multiply(ref m3, ref world, out m1); mx1 = m1; mx1.M41 -= 0.05f; - var axisMesh = _modelScaleAxis.LODs[0].Meshes[0]; - var boxMesh = _modelBox.LODs[0].Meshes[0]; - // X axis Matrix.RotationY(-Mathf.PiOverTwo, out m2); Matrix.Multiply(ref m2, ref mx1, out m3); - axisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3); + scaleAxisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3); // Y axis Matrix.RotationX(Mathf.PiOverTwo, out m2); Matrix.Multiply(ref m2, ref m1, out m3); - axisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m3); + scaleAxisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m3); // Z axis Matrix.RotationX(Mathf.Pi, out m2); Matrix.Multiply(ref m2, ref m1, out m3); - axisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3); + scaleAxisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3); + + // XY plane + m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f)); + Matrix.Multiply(ref m2, ref m1, out m3); + cubeMesh.Draw(ref renderContext, _activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX, ref m3); + + // ZX plane + m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale)); + Matrix.Multiply(ref m2, ref m1, out m3); + cubeMesh.Draw(ref renderContext, _activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisZ, ref m3); + + // YZ plane + m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale)); + Matrix.Multiply(ref m2, ref m1, out m3); + cubeMesh.Draw(ref renderContext, _activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisY, ref m3); // Center box - Matrix.Scaling(10.0f, out m2); + Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2); Matrix.Multiply(ref m2, ref m1, out m3); - boxMesh.Draw(ref renderContext, isCenter ? _materialWireFocus : _materialWire, ref m3); + sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3); break; } diff --git a/Source/Editor/Gizmo/TransformGizmoBase.Selection.cs b/Source/Editor/Gizmo/TransformGizmoBase.Selection.cs index 513178f40..86c0a6afe 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.Selection.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.Selection.cs @@ -102,9 +102,15 @@ namespace FlaxEditor.Gizmo closestIntersection = intersection; } + /*// Center + if (CenterBoxRaw.Intersects(ref localRay, out intersection) && intersection > closestIntersection) + { + _activeAxis = Axis.Center; + closestIntersection = intersection; + }*/ + break; } - case Mode.Rotate: { // Circles @@ -124,41 +130,53 @@ namespace FlaxEditor.Gizmo closestIntersection = intersection; } - // Center - /*if (CenterSphere.Intersects(ref ray, out intersection) && intersection < closestintersection) - { - _activeAxis = Axis.Center; - closestintersection = intersection; - }*/ - break; } - case Mode.Scale: { - // Spheres collision - if (ScaleXSphere.Intersects(ref ray, out intersection) && intersection < closestIntersection) + // Boxes collision + if (XAxisBox.Intersects(ref localRay, out intersection) && intersection < closestIntersection) { _activeAxis = Axis.X; closestIntersection = intersection; } - if (ScaleYSphere.Intersects(ref ray, out intersection) && intersection < closestIntersection) + if (YAxisBox.Intersects(ref localRay, out intersection) && intersection < closestIntersection) { _activeAxis = Axis.Y; closestIntersection = intersection; } - if (ScaleZSphere.Intersects(ref ray, out intersection) && intersection < closestIntersection) + if (ZAxisBox.Intersects(ref localRay, out intersection) && intersection < closestIntersection) { _activeAxis = Axis.Z; closestIntersection = intersection; } - // Center - if (CenterBox.Intersects(ref ray, out intersection) && intersection < closestIntersection) + // Quad planes collision + if (closestIntersection >= float.MaxValue) + closestIntersection = float.MinValue; + + if (XYBox.Intersects(ref localRay, out intersection) && intersection > closestIntersection) + { + _activeAxis = Axis.XY; + closestIntersection = intersection; + } + if (XZBox.Intersects(ref localRay, out intersection) && intersection > closestIntersection) + { + _activeAxis = Axis.ZX; + closestIntersection = intersection; + } + if (YZBox.Intersects(ref localRay, out intersection) && intersection > closestIntersection) + { + _activeAxis = Axis.YZ; + closestIntersection = intersection; + } + + /*// Center + if (CenterBoxRaw.Intersects(ref localRay, out intersection) && intersection < closestIntersection) { _activeAxis = Axis.Center; closestIntersection = intersection; - } + }*/ break; } diff --git a/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs b/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs index ec9423475..8415beac3 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs @@ -7,56 +7,53 @@ namespace FlaxEditor.Gizmo { public partial class TransformGizmoBase { - private const float GizmoScaleFactor = 18; - private const float LineLength = 3.0f; - private const float LineOffset = 1.0f; - private const float MultiAxisThickness = 0.05f; - private const float SingleAxisThickness = 0.3f; - private const float ScaleSpheresRadius = 0.7f; - private const float CenterBoxSize = 0.8f; - private const float CenterSphereRadius = 0.1f; - private const float HalfLineOffset = LineOffset / 2; + /// + /// Scale of the gizmo itself + /// + private const float GizmoScaleFactor = 24; - private readonly Vector3[] _translationLineVertices = - { - // -- X Axis -- // index 0 - 5 - new Vector3(HalfLineOffset, 0, 0), - new Vector3(LineLength, 0, 0), - new Vector3(LineOffset, 0, 0), - new Vector3(LineOffset, LineOffset, 0), - new Vector3(LineOffset, 0, 0), - new Vector3(LineOffset, 0, LineOffset), + /// + /// The length of each axis (outwards) + /// + private const float AxisLength = 3.5f; - // -- Y Axis -- // index 6 - 11 - new Vector3(0, HalfLineOffset, 0), - new Vector3(0, LineLength, 0), - new Vector3(0, LineOffset, 0), - new Vector3(LineOffset, LineOffset, 0), - new Vector3(0, LineOffset, 0), - new Vector3(0, LineOffset, LineOffset), + /// + /// Offset to move axis away from center + /// + private const float AxisOffset = 0.8f; - // -- Z Axis -- // index 12 - 17 - new Vector3(0, 0, HalfLineOffset), - new Vector3(0, 0, LineLength), - new Vector3(0, 0, LineOffset), - new Vector3(LineOffset, 0, LineOffset), - new Vector3(0, 0, LineOffset), - new Vector3(0, LineOffset, LineOffset) - }; + /// + /// How thick the axis should be + /// + private const float AxisThickness = 0.3f; - private BoundingBox XAxisBox = new BoundingBox(new Vector3(LineOffset, -SingleAxisThickness, -SingleAxisThickness), new Vector3(LineOffset + LineLength, SingleAxisThickness, SingleAxisThickness)); - private BoundingBox YAxisBox = new BoundingBox(new Vector3(-SingleAxisThickness, LineOffset, -SingleAxisThickness), new Vector3(SingleAxisThickness, LineOffset + LineLength, SingleAxisThickness)); - private BoundingBox ZAxisBox = new BoundingBox(new Vector3(-SingleAxisThickness, -SingleAxisThickness, LineOffset), new Vector3(SingleAxisThickness, SingleAxisThickness, LineOffset + LineLength)); - private BoundingBox XZBox = new BoundingBox(Vector3.Zero, new Vector3(LineOffset, MultiAxisThickness, LineOffset)); - private BoundingBox XYBox = new BoundingBox(Vector3.Zero, new Vector3(LineOffset, LineOffset, MultiAxisThickness)); - private BoundingBox YZBox = new BoundingBox(Vector3.Zero, new Vector3(MultiAxisThickness, LineOffset, LineOffset)); - private BoundingBox CenterBoxRaw = new BoundingBox(new Vector3(-0.5f * CenterBoxSize), new Vector3(0.5f * CenterBoxSize)); - private float RotateRadiusRaw = 4.0f; + /// + /// Center box scale + /// + private const float CenterBoxScale = 0.8f; - private BoundingSphere ScaleXSphere => new BoundingSphere(Vector3.Transform(_translationLineVertices[1], _gizmoWorld), ScaleSpheresRadius * _screenScale); - private BoundingSphere ScaleYSphere => new BoundingSphere(Vector3.Transform(_translationLineVertices[7], _gizmoWorld), ScaleSpheresRadius * _screenScale); - private BoundingSphere ScaleZSphere => new BoundingSphere(Vector3.Transform(_translationLineVertices[13], _gizmoWorld), ScaleSpheresRadius * _screenScale); + /// + /// The inner minimum of the multiscale + /// + private const float InnerExtend = AxisOffset + 0.5f; + + /// + /// The outer maximum of the multiscale + /// + private const float OuterExtend = AxisOffset * 3.5f; + + // Cube with the size AxisThickness, then moves it along the axis (AxisThickness) and finally makes it really long (AxisLength) + private BoundingBox XAxisBox = new BoundingBox(new Vector3(-AxisThickness), new Vector3(AxisThickness)).MakeOffsetted(AxisOffset * Vector3.UnitX).Merge(AxisLength * Vector3.UnitX); + private BoundingBox YAxisBox = new BoundingBox(new Vector3(-AxisThickness), new Vector3(AxisThickness)).MakeOffsetted(AxisOffset * Vector3.UnitY).Merge(AxisLength * Vector3.UnitY); + private BoundingBox ZAxisBox = new BoundingBox(new Vector3(-AxisThickness), new Vector3(AxisThickness)).MakeOffsetted(AxisOffset * Vector3.UnitZ).Merge(AxisLength * Vector3.UnitZ); + + private BoundingBox XZBox = new BoundingBox(new Vector3(InnerExtend, 0, InnerExtend), new Vector3(OuterExtend, 0, OuterExtend)); + private BoundingBox XYBox = new BoundingBox(new Vector3(InnerExtend, InnerExtend, 0), new Vector3(OuterExtend, OuterExtend, 0)); + private BoundingBox YZBox = new BoundingBox(new Vector3(0, InnerExtend, InnerExtend), new Vector3(0, OuterExtend, OuterExtend)); + + private BoundingBox CenterBoxRaw = new BoundingBox(new Vector3(-0.5f * CenterBoxScale), new Vector3(0.5f * CenterBoxScale)); private OrientedBoundingBox CenterBox => new OrientedBoundingBox(CenterBoxRaw) * _gizmoWorld; + private const float RotateRadiusRaw = 4.0f; private Mode _activeMode = Mode.Translate; private Axis _activeAxis = Axis.None; diff --git a/Source/Engine/Core/Math/BoundingBox.cs b/Source/Engine/Core/Math/BoundingBox.cs index da3a2c863..51225d775 100644 --- a/Source/Engine/Core/Math/BoundingBox.cs +++ b/Source/Engine/Core/Math/BoundingBox.cs @@ -419,6 +419,31 @@ namespace FlaxEngine return box; } + /// + /// Constructs a that is as large as the box and point. + /// + /// The box to merge. + /// The point to merge. + /// When the method completes, contains the newly constructed bounding box. + public static void Merge(ref BoundingBox value1, ref Vector3 value2, out BoundingBox result) + { + Vector3.Min(ref value1.Minimum, ref value2, out result.Minimum); + Vector3.Max(ref value1.Maximum, ref value2, out result.Maximum); + } + + /// + /// Constructs a that is as large as the box and point. + /// + /// The point to merge. + /// The newly constructed bounding box. + public BoundingBox Merge(Vector3 value2) + { + BoundingBox result; + Vector3.Min(ref Minimum, ref value2, out result.Minimum); + Vector3.Max(ref Maximum, ref value2, out result.Maximum); + return result; + } + /// /// Transforms bounding box using the given transformation matrix. /// @@ -498,6 +523,19 @@ namespace FlaxEngine result = new BoundingBox(min, max); } + /// + /// Creates the bounding box that is offseted by the given vector. Adds the offset value to minimum and maximum points. + /// + /// The bounds offset. + /// The offsetted bounds. + public BoundingBox MakeOffsetted(Vector3 offset) + { + BoundingBox result; + Vector3.Add(ref Minimum, ref offset, out result.Minimum); + Vector3.Add(ref Maximum, ref offset, out result.Maximum); + return result; + } + /// /// Creates the bounding box that is offseted by the given vector. Adds the offset value to minimum and maximum points. /// diff --git a/Source/FlaxEngine.Gen.cs b/Source/FlaxEngine.Gen.cs index 8b5988063..c068b93b8 100644 --- a/Source/FlaxEngine.Gen.cs +++ b/Source/FlaxEngine.Gen.cs @@ -13,5 +13,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("b8442186-4a70-7c85-704a-857c68060f38")] -[assembly: AssemblyVersion("1.5.6336")] -[assembly: AssemblyFileVersion("1.5.6336")] +[assembly: AssemblyVersion("1.5.6337")] +[assembly: AssemblyFileVersion("1.5.6337")] diff --git a/Source/FlaxEngine.Gen.h b/Source/FlaxEngine.Gen.h index 35a86fa53..897384d9c 100644 --- a/Source/FlaxEngine.Gen.h +++ b/Source/FlaxEngine.Gen.h @@ -3,11 +3,11 @@ #pragma once #define FLAXENGINE_NAME "FlaxEngine" -#define FLAXENGINE_VERSION Version(1, 5, 6336) -#define FLAXENGINE_VERSION_TEXT "1.5.6336" +#define FLAXENGINE_VERSION Version(1, 5, 6337) +#define FLAXENGINE_VERSION_TEXT "1.5.6337" #define FLAXENGINE_VERSION_MAJOR 1 #define FLAXENGINE_VERSION_MINOR 5 -#define FLAXENGINE_VERSION_BUILD 6336 +#define FLAXENGINE_VERSION_BUILD 6337 #define FLAXENGINE_COMPANY "Flax" #define FLAXENGINE_COPYRIGHT "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved." From 4af2b9e2a6574653b46fa045366766d77eccf6e0 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 16 Feb 2023 19:46:13 +0100 Subject: [PATCH 10/37] Fix compilation --- Source/Engine/Localization/LocalizedStringTable.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Source/Engine/Localization/LocalizedStringTable.cpp b/Source/Engine/Localization/LocalizedStringTable.cpp index 9c01736bd..74c9b6774 100644 --- a/Source/Engine/Localization/LocalizedStringTable.cpp +++ b/Source/Engine/Localization/LocalizedStringTable.cpp @@ -2,11 +2,10 @@ #include "LocalizedStringTable.h" #include "Engine/Serialization/JsonTools.h" +#include "Engine/Serialization/JsonWriters.h" #include "Engine/Serialization/SerializationFwd.h" #include "Engine/Content/Factories/JsonAssetFactory.h" #if USE_EDITOR -#include "Engine/ContentImporters/CreateJson.h" -#include "Engine/Serialization/JsonWriters.h" #include "Engine/Threading/Threading.h" #include "Engine/Core/Log.h" #endif From 4b08cd3fd7bfa214313036290270a898b936cbf7 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 16 Feb 2023 20:08:53 +0100 Subject: [PATCH 11/37] Fix compilation warning --- Source/Engine/Platform/Base/StringUtilsBase.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Source/Engine/Platform/Base/StringUtilsBase.cpp b/Source/Engine/Platform/Base/StringUtilsBase.cpp index d005f8a04..ce895bfa4 100644 --- a/Source/Engine/Platform/Base/StringUtilsBase.cpp +++ b/Source/Engine/Platform/Base/StringUtilsBase.cpp @@ -537,8 +537,7 @@ String StringUtils::GetZZString(const Char* str) if (*end == '\0') end++; } - const int len = end - str; - return String(str, len); + return String(str, (int32)(end - str)); } #undef STRING_UTILS_ITOSTR_BUFFER_SIZE From 7dc83b5472a20008bdf42e4ba2f170df786d1384 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 16 Feb 2023 22:59:31 +0100 Subject: [PATCH 12/37] Fix compilation warning --- Source/Engine/Content/JsonAsset.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Content/JsonAsset.cpp b/Source/Engine/Content/JsonAsset.cpp index 2e1dc2f0e..1f0e914f2 100644 --- a/Source/Engine/Content/JsonAsset.cpp +++ b/Source/Engine/Content/JsonAsset.cpp @@ -184,7 +184,7 @@ bool JsonAssetBase::Save(const StringView& path) writer.EndObject(); // Save json to file - if (File::WriteAllBytes(path.HasChars() ? path : GetPath(), (byte*)buffer.GetString(), (int32)buffer.GetSize())) + if (File::WriteAllBytes(path.HasChars() ? path : StringView(GetPath()), (byte*)buffer.GetString(), (int32)buffer.GetSize())) { LOG(Error, "Cannot save \'{0}\'", ToString()); return true; From 2ea468d5daecc0f47a690b690e7fcdeddfcc2490 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 17 Feb 2023 01:01:32 +0100 Subject: [PATCH 13/37] Ignore constant error due to missing Game Settings in Editor (log once) --- Source/Engine/Core/Config/GameSettings.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Core/Config/GameSettings.cpp b/Source/Engine/Core/Config/GameSettings.cpp index 4d135ebb5..8de9bce1e 100644 --- a/Source/Engine/Core/Config/GameSettings.cpp +++ b/Source/Engine/Core/Config/GameSettings.cpp @@ -22,7 +22,7 @@ #include "Engine/Engine/Globals.h" #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Streaming/StreamingSettings.h" -#if FLAX_TESTS +#if FLAX_TESTS || USE_EDITOR #include "Engine/Platform/FileSystem.h" #endif @@ -91,6 +91,19 @@ GameSettings* GameSettings::Get() // Silence missing GameSettings during test run before Editor creates it (not important) if (!FileSystem::FileExists(assetPath)) return nullptr; +#endif +#if USE_EDITOR + // Log once missing GameSettings in Editor + if (!FileSystem::FileExists(assetPath)) + { + static bool LogOnce = true; + if (LogOnce) + { + LogOnce = false; + LOG(Error, "Missing file game settings asset ({0}\)", assetPath); + } + return nullptr; + } #endif GameSettingsAsset = Content::LoadAsync(assetPath); if (GameSettingsAsset == nullptr) From d5cdbdb808e5d0d46f6dcc4e60ac7f2dcaeecb50 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 17 Feb 2023 01:13:23 +0100 Subject: [PATCH 14/37] Fix typo 2ea468d5daecc0f47a690b690e7fcdeddfcc2490 --- Source/Engine/Core/Config/GameSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Core/Config/GameSettings.cpp b/Source/Engine/Core/Config/GameSettings.cpp index 8de9bce1e..c64fc0d4e 100644 --- a/Source/Engine/Core/Config/GameSettings.cpp +++ b/Source/Engine/Core/Config/GameSettings.cpp @@ -100,7 +100,7 @@ GameSettings* GameSettings::Get() if (LogOnce) { LogOnce = false; - LOG(Error, "Missing file game settings asset ({0}\)", assetPath); + LOG(Error, "Missing file game settings asset ({0})", assetPath); } return nullptr; } From 74bdcf074946f7ad76858f8c85b4741b49d7be93 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Thu, 16 Feb 2023 19:08:24 -0600 Subject: [PATCH 15/37] Fix not serializing post FX script fields. --- Source/Engine/Graphics/PostProcessEffect.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/Engine/Graphics/PostProcessEffect.h b/Source/Engine/Graphics/PostProcessEffect.h index a8355ed8e..2e444c0ea 100644 --- a/Source/Engine/Graphics/PostProcessEffect.h +++ b/Source/Engine/Graphics/PostProcessEffect.h @@ -17,23 +17,24 @@ struct RenderContext; /// API_CLASS(Abstract) class FLAXENGINE_API PostProcessEffect : public Script { + API_AUTO_SERIALIZATION(); DECLARE_SCRIPTING_TYPE(PostProcessEffect); public: /// /// Effect rendering location within rendering pipeline. /// - API_FIELD() PostProcessEffectLocation Location = PostProcessEffectLocation::Default; + API_FIELD(Attributes="EditorDisplay(\"Post Process Effect\"), ExpandGroups") PostProcessEffectLocation Location = PostProcessEffectLocation::Default; /// /// True whether use a single render target as both input and output. Use this if your effect doesn't need to copy the input buffer to the output but can render directly to the single texture. Can be used to optimize game performance. /// - API_FIELD() bool UseSingleTarget = false; + API_FIELD(Attributes="EditorDisplay(\"Post Process Effect\")") bool UseSingleTarget = false; /// /// Effect rendering order. Post effects are sorted before rendering (from the lowest order to the highest order). /// - API_FIELD() int32 Order = 0; + API_FIELD(Attributes="EditorDisplay(\"Post Process Effect\")") int32 Order = 0; public: /// From ec8df18ee4ebc2175c36b03f3186186955959627 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 17 Feb 2023 02:17:25 +0100 Subject: [PATCH 16/37] Remove not important warning --- Source/Engine/Content/Storage/FlaxStorage.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Source/Engine/Content/Storage/FlaxStorage.cpp b/Source/Engine/Content/Storage/FlaxStorage.cpp index fd964daaf..8608a34f6 100644 --- a/Source/Engine/Content/Storage/FlaxStorage.cpp +++ b/Source/Engine/Content/Storage/FlaxStorage.cpp @@ -560,12 +560,8 @@ bool FlaxStorage::Load() bool FlaxStorage::Reload() { - // Check if wasn't already loaded if (!IsLoaded()) - { - LOG(Warning, "{0} isn't loaded.", ToString()); return false; - } OnReloading(this); From 2338e03554d8d30938f274d2beb8f294547ee953 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 17 Feb 2023 10:31:49 +0100 Subject: [PATCH 17/37] Fix crash when unbinding from `Delegate` from other thread during invocation Caused by `callee` being invalid thus it's better to read function pointer again to ensure that both are valid before calling function. --- Source/Engine/Core/Delegate.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Source/Engine/Core/Delegate.h b/Source/Engine/Core/Delegate.h index ffb78dfeb..21a4374ea 100644 --- a/Source/Engine/Core/Delegate.h +++ b/Source/Engine/Core/Delegate.h @@ -617,12 +617,11 @@ public: FunctionType* bindings = (FunctionType*)Platform::AtomicRead((intptr volatile*)&_ptr); for (intptr i = 0; i < size; i++) { - auto function = (StubSignature)Platform::AtomicRead((intptr volatile*)&bindings[i]._function); - if (function != nullptr) - { - auto callee = (void*)Platform::AtomicRead((intptr volatile*)&bindings[i]._callee); + auto function = (StubSignature)Platform::AtomicRead((intptr volatile*)&bindings->_function); + auto callee = (void*)Platform::AtomicRead((intptr volatile*)&bindings->_callee); + if (function != nullptr && function == (StubSignature)Platform::AtomicRead((intptr volatile*)&bindings->_function)) function(callee, Forward(params)...); - } + ++bindings; } } }; From 8b050cf87e437a43f127e927dc67f650d326c3f2 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 17 Feb 2023 11:08:12 +0100 Subject: [PATCH 18/37] Use `D3D11_MAP_FLAG_DO_NOT_WAIT` only from main thread (worker threads can wait for data) #942 --- Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.cpp | 5 +++-- Source/Engine/ShadowsOfMordor/Builder.BuildCache.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.cpp index e3ff0befe..5c98bf579 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.cpp @@ -19,7 +19,8 @@ GPUBufferView* GPUBufferDX11::View() const void* GPUBufferDX11::Map(GPUResourceMapMode mode) { - if (!IsInMainThread()) + const bool isMainThread = IsInMainThread(); + if (!isMainThread) _device->Locker.Lock(); ASSERT(!_mapped); @@ -31,7 +32,7 @@ void* GPUBufferDX11::Map(GPUResourceMapMode mode) { case GPUResourceMapMode::Read: mapType = D3D11_MAP_READ; - if (_desc.Usage == GPUResourceUsage::StagingReadback) + if (_desc.Usage == GPUResourceUsage::StagingReadback && isMainThread) mapFlags = D3D11_MAP_FLAG_DO_NOT_WAIT; break; case GPUResourceMapMode::Write: diff --git a/Source/Engine/ShadowsOfMordor/Builder.BuildCache.cpp b/Source/Engine/ShadowsOfMordor/Builder.BuildCache.cpp index fb3ed6b2c..e2d19980c 100644 --- a/Source/Engine/ShadowsOfMordor/Builder.BuildCache.cpp +++ b/Source/Engine/ShadowsOfMordor/Builder.BuildCache.cpp @@ -103,7 +103,7 @@ void ShadowsOfMordor::Builder::SceneBuildCache::UpdateLightmaps() // Download buffer data if (lightmapEntry.LightmapData->DownloadData(ImportLightmapTextureData)) { - LOG(Warning, "Cannot download LightmapData."); + LOG(Error, "Cannot download LightmapData."); return; } From aa1a0ea4a2e8bef32493413c720c7d0740cb4160 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 17 Feb 2023 11:27:41 +0100 Subject: [PATCH 19/37] Fix `Flipbook` material node bug when frames X was different than Y --- .../Tools/MaterialGenerator/MaterialGenerator.Textures.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp index 103101bec..7edd9a43f 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp @@ -637,8 +637,8 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value) // Write operations auto framesCount = writeLocal(VariantType::Float, String::Format(TEXT("{0}.x * {1}.y"), framesXY.Value, framesXY.Value), node); - frame = writeLocal(VariantType::Float, String::Format(TEXT("fmod(floor({0}), {1})"), frame.Value, framesCount.Value), node); - auto framesXYInv = writeOperation2(node, Value::One, framesXY, '/'); + frame = writeLocal(VariantType::Float, String::Format(TEXT("fmod({0}, {1})"), frame.Value, framesCount.Value), node); + auto framesXYInv = writeOperation2(node, Value::One.AsFloat2(), framesXY, '/'); auto frameY = writeLocal(VariantType::Float, String::Format(TEXT("abs({0} * {1}.y - (floor({2} * {3}.x) + {0} * 1))"), invertY.Value, framesXY.Value, frame.Value, framesXYInv.Value), node); auto frameX = writeLocal(VariantType::Float, String::Format(TEXT("abs({0} * {1}.x - (({2} - {1}.x * floor({2} * {3}.x)) + {0} * 1))"), invertX.Value, framesXY.Value, frame.Value, framesXYInv.Value), node); value = writeLocal(VariantType::Float2, String::Format(TEXT("({3} + float2({0}, {1})) * {2}"), frameX.Value, frameY.Value, framesXYInv.Value, uv.Value), node); From 5dc63da4bf4e1f9aedd3ba513da422af103a21f2 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 17 Feb 2023 16:19:10 +0100 Subject: [PATCH 20/37] Fix crash if texture is missing #942 --- Source/Engine/Level/Scene/Lightmap.cpp | 2 +- Source/Engine/Level/Scene/Lightmap.h | 4 ++-- Source/Engine/ShadowsOfMordor/Builder.Charts.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Level/Scene/Lightmap.cpp b/Source/Engine/Level/Scene/Lightmap.cpp index f2d11e0c5..c8b83febf 100644 --- a/Source/Engine/Level/Scene/Lightmap.cpp +++ b/Source/Engine/Level/Scene/Lightmap.cpp @@ -103,7 +103,7 @@ void Lightmap::EnsureSize(int32 size) #if COMPILE_WITH_ASSETS_IMPORTER Guid id = Guid::New(); - LOG(Info, "Cannot load lightmap {0} ({1}:{2}). Creating new one.", id, _index, textureIndex); + LOG(Info, "Cannot load lightmap ({1}:{2}). Creating new one with ID={0}.", id, _index, textureIndex); String assetPath; _manager->GetCachedLightmapPath(&assetPath, _index, textureIndex); diff --git a/Source/Engine/Level/Scene/Lightmap.h b/Source/Engine/Level/Scene/Lightmap.h index ef43428c7..3129dbd25 100644 --- a/Source/Engine/Level/Scene/Lightmap.h +++ b/Source/Engine/Level/Scene/Lightmap.h @@ -48,7 +48,7 @@ public: /// Gets attached texture objects /// /// Lightmaps textures array - void GetTextures(GPUTexture* lightmaps[]) const + void GetTextures(GPUTexture* lightmaps[3]) const { lightmaps[0] = _textures[0] ? _textures[0]->GetTexture() : nullptr; lightmaps[1] = _textures[1] ? _textures[1]->GetTexture() : nullptr; @@ -59,7 +59,7 @@ public: /// Gets attached texture objects /// /// Lightmaps textures array - void GetTextures(Texture* lightmaps[]) const + void GetTextures(Texture* lightmaps[3]) const { lightmaps[0] = _textures[0].Get(); lightmaps[1] = _textures[1].Get(); diff --git a/Source/Engine/ShadowsOfMordor/Builder.Charts.cpp b/Source/Engine/ShadowsOfMordor/Builder.Charts.cpp index ccd9f1d0e..f6ecfca00 100644 --- a/Source/Engine/ShadowsOfMordor/Builder.Charts.cpp +++ b/Source/Engine/ShadowsOfMordor/Builder.Charts.cpp @@ -152,7 +152,7 @@ void ShadowsOfMordor::Builder::updateLightmaps() { auto texture = textures[textureIndex]; GPUDevice::Instance->Locker.Unlock(); - if (texture->WaitForLoaded()) + if (!texture || texture->WaitForLoaded()) { LOG(Error, "Lightmap load failed."); return; From 679757942fc76c18e8b6edadef295024f3d495ce Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 17 Feb 2023 16:28:48 +0100 Subject: [PATCH 21/37] Fix GPU Buffer Map/Unmap pair to prevent stall if map fails on DX11 #942 --- Source/Engine/Graphics/GPUBuffer.cpp | 3 --- Source/Engine/Graphics/GPUBuffer.h | 1 + .../GraphicsDevice/DirectX/DX11/GPUBufferDX11.cpp | 13 +++++++------ Source/Engine/Particles/ParticlesSimulation.cpp | 13 ++++++++----- .../Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp | 2 +- Source/Engine/ShadowsOfMordor/Builder.Charts.cpp | 2 +- Source/Engine/ShadowsOfMordor/Builder.cpp | 1 + 7 files changed, 19 insertions(+), 16 deletions(-) diff --git a/Source/Engine/Graphics/GPUBuffer.cpp b/Source/Engine/Graphics/GPUBuffer.cpp index a38c88dd0..6aaa939b3 100644 --- a/Source/Engine/Graphics/GPUBuffer.cpp +++ b/Source/Engine/Graphics/GPUBuffer.cpp @@ -377,12 +377,9 @@ void GPUBuffer::SetData(const void* data, uint32 size) Log::ArgumentOutOfRangeException(TEXT("Buffer.SetData")); return; } - void* mapped = Map(GPUResourceMapMode::Write); if (!mapped) - { return; - } Platform::MemoryCopy(mapped, data, size); Unmap(); } diff --git a/Source/Engine/Graphics/GPUBuffer.h b/Source/Engine/Graphics/GPUBuffer.h index 8a5418570..4d14124b3 100644 --- a/Source/Engine/Graphics/GPUBuffer.h +++ b/Source/Engine/Graphics/GPUBuffer.h @@ -190,6 +190,7 @@ public: /// /// Gets a CPU pointer to the resource by mapping its contents. Denies the GPU access to that resource. /// + /// Always call Unmap if the returned pointer is valid to release resources. /// The map operation mode. /// The pointer of the mapped CPU buffer with resource data or null if failed. API_FUNCTION() virtual void* Map(GPUResourceMapMode mode) = 0; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.cpp index 5c98bf579..b83ab6a08 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.cpp @@ -48,18 +48,19 @@ void* GPUBufferDX11::Map(GPUResourceMapMode mode) const HRESULT result = _device->GetIM()->Map(_resource, 0, mapType, mapFlags, &map); if (result != DXGI_ERROR_WAS_STILL_DRAWING) LOG_DIRECTX_RESULT(result); + _mapped = map.pData != nullptr; + if (!_mapped && !isMainThread) + _device->Locker.Unlock(); + return map.pData; } void GPUBufferDX11::Unmap() { - if (_mapped) - { - _mapped = false; - _device->GetIM()->Unmap(_resource, 0); - } - + ASSERT(_mapped); + _mapped = false; + _device->GetIM()->Unmap(_resource, 0); if (!IsInMainThread()) _device->Locker.Unlock(); } diff --git a/Source/Engine/Particles/ParticlesSimulation.cpp b/Source/Engine/Particles/ParticlesSimulation.cpp index 2d52a7f76..c68862925 100644 --- a/Source/Engine/Particles/ParticlesSimulation.cpp +++ b/Source/Engine/Particles/ParticlesSimulation.cpp @@ -104,15 +104,18 @@ int32 ParticleSystemInstance::GetParticlesCount() const if (GPUParticlesCountReadback && GPUParticlesCountReadback->IsAllocated()) { auto data = static_cast(GPUParticlesCountReadback->Map(GPUResourceMapMode::Read)); - for (const auto& emitter : Emitters) + if (data) { - if (emitter.Buffer && emitter.Buffer->Mode == ParticlesSimulationMode::GPU && emitter.Buffer->GPU.HasValidCount) + for (const auto& emitter : Emitters) { - result += *data; + if (emitter.Buffer && emitter.Buffer->Mode == ParticlesSimulationMode::GPU && emitter.Buffer->GPU.HasValidCount) + { + result += *data; + } + ++data; } - ++data; + GPUParticlesCountReadback->Unmap(); } - GPUParticlesCountReadback->Unmap(); } else if (Emitters.HasItems()) { diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp index 5d87858b6..860c1b285 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp @@ -689,8 +689,8 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co objectsBufferCapacity = counter; notReady = false; } + _culledObjectsSizeBuffer->Unmap(); } - _culledObjectsSizeBuffer->Unmap(); // Allow to be ready if the buffer was already used if (notReady && surfaceAtlasData.CulledObjectsBuffer && surfaceAtlasData.CulledObjectsBuffer->IsAllocated()) diff --git a/Source/Engine/ShadowsOfMordor/Builder.Charts.cpp b/Source/Engine/ShadowsOfMordor/Builder.Charts.cpp index f6ecfca00..bd9974bc2 100644 --- a/Source/Engine/ShadowsOfMordor/Builder.Charts.cpp +++ b/Source/Engine/ShadowsOfMordor/Builder.Charts.cpp @@ -152,7 +152,7 @@ void ShadowsOfMordor::Builder::updateLightmaps() { auto texture = textures[textureIndex]; GPUDevice::Instance->Locker.Unlock(); - if (!texture || texture->WaitForLoaded()) + if (texture == nullptr || texture->WaitForLoaded()) { LOG(Error, "Lightmap load failed."); return; diff --git a/Source/Engine/ShadowsOfMordor/Builder.cpp b/Source/Engine/ShadowsOfMordor/Builder.cpp index ccf956d47..1ce6670d8 100644 --- a/Source/Engine/ShadowsOfMordor/Builder.cpp +++ b/Source/Engine/ShadowsOfMordor/Builder.cpp @@ -276,6 +276,7 @@ void ShadowsOfMordor::Builder::saveState() context->Flush(); Platform::Sleep(10); void* mapped = lightmapDataStaging->Map(GPUResourceMapMode::Read); + ASSERT(mapped); stream->WriteInt32(lightmapDataSize); stream->WriteBytes(mapped, lightmapDataSize); lightmapDataStaging->Unmap(); From 05cb02aa0987e901b4bf5b1758bf6a051839b6d7 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 17 Feb 2023 20:44:23 +0100 Subject: [PATCH 22/37] Improve #936 for ExternalPopups and preserve odl impl on Windows --- .../Editor/GUI/ContextMenu/ContextMenuBase.cs | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs b/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs index 8596ab83b..27d47345d 100644 --- a/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs +++ b/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs @@ -1,3 +1,7 @@ +#if PLATFORM_WINDOWS +#define USE_IS_FOREGROUND +#else +#endif // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System.Collections.Generic; @@ -196,6 +200,7 @@ namespace FlaxEditor.GUI.ContextMenu desc.HasSizingFrame = false; OnWindowCreating(ref desc); _window = Platform.CreateWindow(ref desc); + _window.GotFocus += OnWindowGotFocus; _window.LostFocus += OnWindowLostFocus; // Attach to the window @@ -325,6 +330,49 @@ namespace FlaxEditor.GUI.ContextMenu // Nothing to do } +#if USE_IS_FOREGROUND + /// + /// Returns true if context menu is in foreground (eg. context window or any child window has user focus or user opened additional popup within this context). + /// + protected virtual bool IsForeground + { + get + { + // Any external popup is focused + foreach (var externalPopup in ExternalPopups) + { + if (externalPopup && externalPopup.IsForegroundWindow) + return true; + } + + // Any context menu window is focused + var anyForeground = false; + var c = this; + while (!anyForeground && c != null) + { + if (c._window != null && c._window.IsForegroundWindow) + anyForeground = true; + c = c._childCM; + } + + return anyForeground; + } + } + + private void OnWindowGotFocus() + { + var child = _childCM; + if (child != null && _window && _window.IsForegroundWindow) + { + // Hide child if user clicked over parent (do it next frame to process other events before - eg. child windows focus loss) + FlaxEngine.Scripting.InvokeOnUpdate(() => + { + if (child == _childCM) + HideChild(); + }); + } + } + private void OnWindowLostFocus() { // Skip for parent menus (child should handle lost of focus) @@ -332,11 +380,39 @@ namespace FlaxEditor.GUI.ContextMenu return; // Check if user stopped using that popup menu + if (_parentCM != null) + { + // Focus parent if user clicked over the parent popup + var mouse = _parentCM.PointFromScreen(FlaxEngine.Input.MouseScreenPosition); + if (_parentCM.ContainsPoint(ref mouse)) + { + _parentCM._window.Focus(); + } + } + } +#else + private void OnWindowGotFocus() + { + } + + private void OnWindowLostFocus() + { + // Skip for parent menus (child should handle lost of focus) + if (_childCM != null) + return; + if (_parentCM != null) { if (IsMouseOver) return; + // Check if any external popup is focused + foreach (var externalPopup in ExternalPopups) + { + if (externalPopup && externalPopup.IsFocused) + return; + } + // Check if mouse is over any of the parents ContextMenuBase focusCM = null; var cm = _parentCM; @@ -360,8 +436,11 @@ namespace FlaxEditor.GUI.ContextMenu } } else if (!IsMouseOver) + { Hide(); + } } +#endif /// public override bool IsMouseOver @@ -382,6 +461,20 @@ namespace FlaxEditor.GUI.ContextMenu } } +#if USE_IS_FOREGROUND + /// + public override void Update(float deltaTime) + { + base.Update(deltaTime); + + // Let root context menu to check if none of the popup windows + if (_parentCM == null && !IsForeground) + { + Hide(); + } + } +#endif + /// public override void Draw() { From d3578380e2f984315ab49725d1bf6e9f6e5e5388 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 17 Feb 2023 21:47:33 +0100 Subject: [PATCH 23/37] Update build number --- Flax.flaxproj | 2 +- Source/FlaxEngine.Gen.cs | 4 ++-- Source/FlaxEngine.Gen.h | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Flax.flaxproj b/Flax.flaxproj index c3c825910..ffcbf68e0 100644 --- a/Flax.flaxproj +++ b/Flax.flaxproj @@ -3,7 +3,7 @@ "Version": { "Major": 1, "Minor": 5, - "Build": 6337 + "Build": 6338 }, "Company": "Flax", "Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.", diff --git a/Source/FlaxEngine.Gen.cs b/Source/FlaxEngine.Gen.cs index c068b93b8..f0864ad71 100644 --- a/Source/FlaxEngine.Gen.cs +++ b/Source/FlaxEngine.Gen.cs @@ -13,5 +13,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("b8442186-4a70-7c85-704a-857c68060f38")] -[assembly: AssemblyVersion("1.5.6337")] -[assembly: AssemblyFileVersion("1.5.6337")] +[assembly: AssemblyVersion("1.5.6338")] +[assembly: AssemblyFileVersion("1.5.6338")] diff --git a/Source/FlaxEngine.Gen.h b/Source/FlaxEngine.Gen.h index 897384d9c..bbebf5113 100644 --- a/Source/FlaxEngine.Gen.h +++ b/Source/FlaxEngine.Gen.h @@ -3,11 +3,11 @@ #pragma once #define FLAXENGINE_NAME "FlaxEngine" -#define FLAXENGINE_VERSION Version(1, 5, 6337) -#define FLAXENGINE_VERSION_TEXT "1.5.6337" +#define FLAXENGINE_VERSION Version(1, 5, 6338) +#define FLAXENGINE_VERSION_TEXT "1.5.6338" #define FLAXENGINE_VERSION_MAJOR 1 #define FLAXENGINE_VERSION_MINOR 5 -#define FLAXENGINE_VERSION_BUILD 6337 +#define FLAXENGINE_VERSION_BUILD 6338 #define FLAXENGINE_COMPANY "Flax" #define FLAXENGINE_COPYRIGHT "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved." From f77063f6154a62edd541981c7b33029a1454e935 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Fri, 17 Feb 2023 21:10:19 +0200 Subject: [PATCH 24/37] Include thirdparty files in the includes cache --- .../Tools/Flax.Build/Build/NativeCpp/IncludesCache.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Source/Tools/Flax.Build/Build/NativeCpp/IncludesCache.cs b/Source/Tools/Flax.Build/Build/NativeCpp/IncludesCache.cs index 7f223df6a..51872df44 100644 --- a/Source/Tools/Flax.Build/Build/NativeCpp/IncludesCache.cs +++ b/Source/Tools/Flax.Build/Build/NativeCpp/IncludesCache.cs @@ -342,6 +342,16 @@ namespace Flax.Build.NativeCpp } } + // Relative to ThirdParty includes for library includes + if (!isValid && isLibraryInclude) + { + includedFilePath = Path.Combine(Globals.Root, "Source", "ThirdParty", includedFile); + if (FileExists(includedFilePath)) + { + isValid = true; + } + } + if (!isValid) { // Invalid include From ffd5c8fd53df37e0bfd051197636ab2a933ad43f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 18 Feb 2023 00:09:30 +0100 Subject: [PATCH 25/37] Fix crash on D3D10 --- Source/Engine/Renderer/Renderer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index 584ab6b45..edac958bc 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -406,7 +406,10 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont // Get the light accumulation buffer auto outputFormat = renderContext.Buffers->GetOutputFormat(); - auto tempDesc = GPUTextureDescription::New2D(renderContext.Buffers->GetWidth(), renderContext.Buffers->GetHeight(), outputFormat, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::UnorderedAccess); + auto tempFlags = GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget; + if (GPUDevice::Instance->Limits.HasCompute) + tempFlags |= GPUTextureFlags::UnorderedAccess; + auto tempDesc = GPUTextureDescription::New2D(renderContext.Buffers->GetWidth(), renderContext.Buffers->GetHeight(), outputFormat, tempFlags); auto lightBuffer = RenderTargetPool::Get(tempDesc); RENDER_TARGET_POOL_SET_NAME(lightBuffer, "LightBuffer"); From 3ddaa6da1a8bfebc71105141a0c3ed65b236bd49 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sat, 18 Feb 2023 07:47:49 -0600 Subject: [PATCH 26/37] fix issue of child context menu hiding when de-hovered then re-hovered. Fixed issue of clicking on child cm hiding child. --- .../GUI/ContextMenu/ContextMenuChildMenu.cs | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/Source/Editor/GUI/ContextMenu/ContextMenuChildMenu.cs b/Source/Editor/GUI/ContextMenu/ContextMenuChildMenu.cs index 0256d2bee..7af36fae0 100644 --- a/Source/Editor/GUI/ContextMenu/ContextMenuChildMenu.cs +++ b/Source/Editor/GUI/ContextMenu/ContextMenuChildMenu.cs @@ -55,8 +55,6 @@ namespace FlaxEditor.GUI.ContextMenu /// public override void OnMouseEnter(Float2 location) { - base.OnMouseEnter(location); - // Skip if has no children if (ContextMenu.HasChildren == false) return; @@ -66,8 +64,28 @@ namespace FlaxEditor.GUI.ContextMenu if (parentContextMenu == ContextMenu) return; + if (ContextMenu.IsOpened) + return; + + base.OnMouseEnter(location); + // Hide parent CM popups and set itself as child parentContextMenu.ShowChild(ContextMenu, PointToParent(ParentContextMenu, new Float2(Width, 0))); } + + /// + public override bool OnMouseUp(Float2 location, MouseButton button) + { + // Skip if already shown + var parentContextMenu = ParentContextMenu; + if (parentContextMenu == ContextMenu) + return true; + if (ContextMenu.IsOpened) + return true; + + // Hide parent CM popups and set itself as child + parentContextMenu.ShowChild(ContextMenu, PointToParent(ParentContextMenu, new Float2(Width, 0))); + return base.OnMouseUp(location, button); + } } } From f0061e07b4a1d677232d68d961ca804070b7ef98 Mon Sep 17 00:00:00 2001 From: PrecisionRender Date: Fri, 17 Feb 2023 21:44:20 -0600 Subject: [PATCH 27/37] Update scroll speed to feel less sluggish --- Source/Engine/UI/GUI/Panels/ScrollBar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/UI/GUI/Panels/ScrollBar.cs b/Source/Engine/UI/GUI/Panels/ScrollBar.cs index f28d7d4cb..f21c05ab5 100644 --- a/Source/Engine/UI/GUI/Panels/ScrollBar.cs +++ b/Source/Engine/UI/GUI/Panels/ScrollBar.cs @@ -23,7 +23,7 @@ namespace FlaxEngine.GUI // Scrolling - private float _clickChange = 20, _scrollChange = 30; + private float _clickChange = 20, _scrollChange = 75; private float _minimum, _maximum = 100; private float _value, _targetValue; private readonly Orientation _orientation; From 8327866205a3f7993b3f5043d26933b13adedc54 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 18 Feb 2023 17:05:41 +0100 Subject: [PATCH 28/37] Expose `ScrollSpeedWheel` and `ScrollSpeedClick` for scroll bar editing #946 --- Source/Engine/UI/GUI/Panels/ScrollBar.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Source/Engine/UI/GUI/Panels/ScrollBar.cs b/Source/Engine/UI/GUI/Panels/ScrollBar.cs index f21c05ab5..d91a88adf 100644 --- a/Source/Engine/UI/GUI/Panels/ScrollBar.cs +++ b/Source/Engine/UI/GUI/Panels/ScrollBar.cs @@ -146,6 +146,24 @@ namespace FlaxEngine.GUI } } + /// + /// Gets or sets the speed for the scroll on mouse wheel. + /// + public float ScrollSpeedWheel + { + get => _scrollChange; + set => _scrollChange = value; + } + + /// + /// Gets or sets the speed for the scroll on mouse click. + /// + public float ScrollSpeedClick + { + get => _clickChange; + set => _clickChange = value; + } + /// /// Gets the value slow down. /// From e644b652893f48be34e551bd189476c39dc73683 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 18 Feb 2023 18:25:40 +0100 Subject: [PATCH 29/37] Fix potential rare issues with material shader constants containing invalid data --- Source/Engine/Graphics/Materials/MaterialShader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Engine/Graphics/Materials/MaterialShader.cpp b/Source/Engine/Graphics/Materials/MaterialShader.cpp index e0d3d610c..0d428c706 100644 --- a/Source/Engine/Graphics/Materials/MaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/MaterialShader.cpp @@ -231,6 +231,7 @@ bool MaterialShader::Load(MemoryReadStream& shaderCacheStream, const MaterialInf _cb = nullptr; } _cbData.Resize(cbSize, false); + Platform::MemoryClear(_cbData.Get(), cbSize); } // Initialize the material based on type (create pipeline states and setup) From fe97429df892b2c004064a24a060a96d547378c6 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 18 Feb 2023 22:23:59 +0100 Subject: [PATCH 30/37] Minor fix --- Source/Shaders/GI/DDGI.shader | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Shaders/GI/DDGI.shader b/Source/Shaders/GI/DDGI.shader index 1c7b577b2..e90155960 100644 --- a/Source/Shaders/GI/DDGI.shader +++ b/Source/Shaders/GI/DDGI.shader @@ -160,9 +160,9 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID) uint sdfCascade = GetGlobalSDFCascade(GlobalSDF, probePosition); float4 CachedProbeOffsets[64]; // TODO: test performance diff when using shared memory and larger thread group (is it worth it?) - for(uint x = 0; x < 4; x++) - for(uint y = 0; y < 4; y++) - for(uint z = 0; z < 4; z++) + for (uint x = 0; x < 4; x++) + for (uint y = 0; y < 4; y++) + for (uint z = 0; z < 4; z++) { float3 offset = Remap(float3(x, y, z), 0, 3, -0.5f, 0.5f) * relocateLimit; float offsetSdf = SampleGlobalSDFCascade(GlobalSDF, GlobalSDFTex, probeBasePosition + offset, sdfCascade); @@ -273,7 +273,7 @@ void CS_TraceRays(uint3 DispatchThreadId : SV_DispatchThreadID) float4 probeData = LoadDDGIProbeData(DDGI, ProbesData, CascadeIndex, probeIndex); uint probeState = DecodeDDGIProbeState(probeData); uint probeRaysCount = GetProbeRaysCount(DDGI, probeState); - if (probeState == DDGI_PROBE_STATE_INACTIVE || probeRaysCount < rayIndex) + if (probeState == DDGI_PROBE_STATE_INACTIVE || rayIndex >= probeRaysCount) return; // Skip disabled probes or if current thread's ray is unused float3 probePosition = DecodeDDGIProbePosition(DDGI, probeData, CascadeIndex, probeIndex, probeCoords); float3 probeRayDirection = GetProbeRayDirection(DDGI, rayIndex); From 7a5d84a216c05f7557b1f25af2fe1e2684cc282b Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 18 Feb 2023 23:15:50 +0100 Subject: [PATCH 31/37] Fix Global SDF objects culling into chunks to correctly match world geometry --- Content/Shaders/GI/DDGI.flax | 4 ++-- Content/Shaders/GlobalSignDistanceField.flax | 4 ++-- .../Engine/Renderer/GlobalSignDistanceFieldPass.cpp | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Content/Shaders/GI/DDGI.flax b/Content/Shaders/GI/DDGI.flax index 6b387f70b..106d6d772 100644 --- a/Content/Shaders/GI/DDGI.flax +++ b/Content/Shaders/GI/DDGI.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d851e919211c073ac83ba5e9e2c75529164c588ea1ace8eca858995643f5744a -size 23686 +oid sha256:74e29de6dbadea44168350c430d7f75719448987bc2f1d0b063dbfb73aaa0780 +size 23690 diff --git a/Content/Shaders/GlobalSignDistanceField.flax b/Content/Shaders/GlobalSignDistanceField.flax index e013618f3..18f653f86 100644 --- a/Content/Shaders/GlobalSignDistanceField.flax +++ b/Content/Shaders/GlobalSignDistanceField.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3e12440d4fcc78a0d7e07da6584efcc95750046db500d0aff2dc9a41360aac36 -size 11798 +oid sha256:2c8aa181a814d69b15ffec6493a71a6f42ae816ce04f7803cff2d5073b4b3c4f +size 11790 diff --git a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp index 993b0c4b7..f7d5fd5a5 100644 --- a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp +++ b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp @@ -549,8 +549,8 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex _cascadeIndex = cascadeIndex; _sdfData = &sdfData; const float objectMargin = _voxelSize * GLOBAL_SDF_RASTERIZE_CHUNK_MARGIN; - _sdfDataOriginMax = sdfData.Origin - objectMargin; - _sdfDataOriginMax = sdfData.Origin + objectMargin; + _sdfDataOriginMin = -sdfData.Origin - objectMargin; + _sdfDataOriginMax = -sdfData.Origin + objectMargin; { PROFILE_CPU_NAMED("Draw"); BoundingBox cascadeBoundsWorld = cascadeBounds.MakeOffsetted(sdfData.Origin); @@ -958,9 +958,9 @@ void GlobalSignDistanceFieldPass::RasterizeModelSDF(Actor* actor, const ModelBas { // Setup object data BoundingBox objectBoundsCascade; - Vector3::Clamp(objectBounds.Minimum - _sdfDataOriginMin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Minimum); + Vector3::Clamp(objectBounds.Minimum + _sdfDataOriginMin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Minimum); Vector3::Subtract(objectBoundsCascade.Minimum, _cascadeBounds.Minimum, objectBoundsCascade.Minimum); - Vector3::Clamp(objectBounds.Maximum - _sdfDataOriginMax, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Maximum); + Vector3::Clamp(objectBounds.Maximum + _sdfDataOriginMax, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Maximum); Vector3::Subtract(objectBoundsCascade.Maximum, _cascadeBounds.Minimum, objectBoundsCascade.Maximum); const Int3 objectChunkMin(objectBoundsCascade.Minimum / _chunkSize); const Int3 objectChunkMax(objectBoundsCascade.Maximum / _chunkSize); @@ -1019,9 +1019,9 @@ void GlobalSignDistanceFieldPass::RasterizeHeightfield(Actor* actor, GPUTexture* { // Setup object data BoundingBox objectBoundsCascade; - Vector3::Clamp(objectBounds.Minimum - _sdfDataOriginMin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Minimum); + Vector3::Clamp(objectBounds.Minimum + _sdfDataOriginMin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Minimum); Vector3::Subtract(objectBoundsCascade.Minimum, _cascadeBounds.Minimum, objectBoundsCascade.Minimum); - Vector3::Clamp(objectBounds.Maximum - _sdfDataOriginMax, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Maximum); + Vector3::Clamp(objectBounds.Maximum + _sdfDataOriginMax, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Maximum); Vector3::Subtract(objectBoundsCascade.Maximum, _cascadeBounds.Minimum, objectBoundsCascade.Maximum); const Int3 objectChunkMin(objectBoundsCascade.Minimum / _chunkSize); const Int3 objectChunkMax(objectBoundsCascade.Maximum / _chunkSize); From dc04d3dc0b3186a1aafaaa4c1eac9130945721af Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 19 Feb 2023 11:25:37 +0100 Subject: [PATCH 32/37] Restore `Actor.Tag` property as deprecated for backwards compatibility Regression from a570d6d1781755917d986b901f6f12984b5eac80 --- Source/Engine/Level/Actor.cpp | 15 +++++++++++++++ Source/Engine/Level/Actor.h | 13 +++++++++++++ 2 files changed, 28 insertions(+) diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp index 73ef072b3..2ec3231d6 100644 --- a/Source/Engine/Level/Actor.cpp +++ b/Source/Engine/Level/Actor.cpp @@ -471,6 +471,21 @@ bool Actor::HasTag(const StringView& tag) const return Tags.Contains(tag); } +PRAGMA_DISABLE_DEPRECATION_WARNINGS + +const String& Actor::GetTag() const +{ + return Tags.Count() != 0 ? Tags[0].ToString() : String::Empty; +} + +void Actor::SetTag(const StringView& value) +{ + const Tag tag = Tags::Get(value); + Tags.Set(&tag, 1); +} + +PRAGMA_ENABLE_DEPRECATION_WARNINGS + void Actor::SetLayer(int32 layerIndex) { layerIndex = Math::Clamp(layerIndex, 0, 31); diff --git a/Source/Engine/Level/Actor.h b/Source/Engine/Level/Actor.h index 38bd629a5..2888b7d49 100644 --- a/Source/Engine/Level/Actor.h +++ b/Source/Engine/Level/Actor.h @@ -130,6 +130,19 @@ public: /// The tag to check. API_FUNCTION() bool HasTag(const StringView& tag) const; + /// + /// Gets the name of the tag. + /// [Deprecated in v1.5] + /// + API_PROPERTY(Attributes="HideInEditor, NoSerialize, NoAnimate") + DEPRECATED const String& GetTag() const; + + /// + /// Sets the name of the tag. + /// [Deprecated in v1.5] + /// + API_PROPERTY() DEPRECATED void SetTag(const StringView& value); + /// /// Gets the actor name. /// From 5a7f678e4d3b8f74daa92b56bd512041b0e3c2f3 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 19 Feb 2023 11:25:46 +0100 Subject: [PATCH 33/37] Add `Actor.AddTag` utility --- Source/Engine/Level/Actor.cpp | 5 +++++ Source/Engine/Level/Actor.h | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp index 2ec3231d6..1c2f1768e 100644 --- a/Source/Engine/Level/Actor.cpp +++ b/Source/Engine/Level/Actor.cpp @@ -471,6 +471,11 @@ bool Actor::HasTag(const StringView& tag) const return Tags.Contains(tag); } +void Actor::AddTag(const Tag& tag) +{ + Tags.AddUnique(tag); +} + PRAGMA_DISABLE_DEPRECATION_WARNINGS const String& Actor::GetTag() const diff --git a/Source/Engine/Level/Actor.h b/Source/Engine/Level/Actor.h index 2888b7d49..c1d038783 100644 --- a/Source/Engine/Level/Actor.h +++ b/Source/Engine/Level/Actor.h @@ -130,6 +130,12 @@ public: /// The tag to check. API_FUNCTION() bool HasTag(const StringView& tag) const; + /// + /// Adds a tag to the actor + /// + /// The tag to add. + API_FUNCTION() void AddTag(const Tag& tag); + /// /// Gets the name of the tag. /// [Deprecated in v1.5] From 0d813aee900f1368aee791739295bfae756127e9 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 19 Feb 2023 13:36:45 +0100 Subject: [PATCH 34/37] Possible fix for deprecation warning --- Source/Engine/Networking/NetworkConfig.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Networking/NetworkConfig.h b/Source/Engine/Networking/NetworkConfig.h index 794ae74a3..d875c49b4 100644 --- a/Source/Engine/Networking/NetworkConfig.h +++ b/Source/Engine/Networking/NetworkConfig.h @@ -36,7 +36,7 @@ API_STRUCT(Namespace="FlaxEngine.Networking") struct FLAXENGINE_API NetworkConfi /// [Deprecated in v1.3] /// API_FIELD() - DEPRECATED NetworkDriverType NetworkDriverType = NetworkDriverType::ENet; + DEPRECATED NetworkDriverType NetworkDriverType; /// /// The network driver instance (implements INetworkDriver) that will be used to create and manage the peer, send and receive messages. @@ -81,4 +81,12 @@ API_STRUCT(Namespace="FlaxEngine.Networking") struct FLAXENGINE_API NetworkConfi /// API_FIELD() uint16 MessagePoolSize = 2048; + + PRAGMA_DISABLE_DEPRECATION_WARNINGS + /// Ctor. + NetworkConfig() + { + NetworkDriverType = NetworkDriverType::ENet; + } + PRAGMA_ENABLE_DEPRECATION_WARNINGS }; From 9429be08307b952dd2930f90687c30571c2c2b1f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 19 Feb 2023 14:35:47 +0100 Subject: [PATCH 35/37] Fix compilation warnings --- Source/Engine/Graphics/RenderView.h | 8 ++++++++ Source/Engine/Networking/NetworkReplicator.cpp | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Graphics/RenderView.h b/Source/Engine/Graphics/RenderView.h index 52e317a51..a50bbfae0 100644 --- a/Source/Engine/Graphics/RenderView.h +++ b/Source/Engine/Graphics/RenderView.h @@ -253,6 +253,14 @@ public: } public: + // Ignore deprecation warnings in defaults + PRAGMA_DISABLE_DEPRECATION_WARNINGS + RenderView(); + RenderView(const RenderView& other) = default; + RenderView(RenderView&& other) = default; + RenderView& operator=(const RenderView& other) = default; + PRAGMA_ENABLE_DEPRECATION_WARNINGS + // Set up view with custom params // @param viewProjection View * Projection matrix void SetUp(const Matrix& viewProjection); diff --git a/Source/Engine/Networking/NetworkReplicator.cpp b/Source/Engine/Networking/NetworkReplicator.cpp index 4e0d7f339..7ab1a7c4f 100644 --- a/Source/Engine/Networking/NetworkReplicator.cpp +++ b/Source/Engine/Networking/NetworkReplicator.cpp @@ -1381,7 +1381,7 @@ void NetworkInternal::OnNetworkMessageObjectSpawn(NetworkEvent& event, NetworkCl // Reuse parent object as prefab instance prefabInstance = parentActor; } - else if (parentActor = Scripting::TryFindObject(rootItem.ParentId)) + else if ((parentActor = Scripting::TryFindObject(rootItem.ParentId))) { // Try to find that spawned prefab (eg. prefab with networked script was spawned before so now we need to link it) for (Actor* child : parentActor->Children) From 55d721f4257b93cfe7abdaa06153198f4f0ff724 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 19 Feb 2023 14:40:35 +0100 Subject: [PATCH 36/37] Fix typo --- Source/Engine/Graphics/RenderView.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Graphics/RenderView.h b/Source/Engine/Graphics/RenderView.h index a50bbfae0..5cfe06a8d 100644 --- a/Source/Engine/Graphics/RenderView.h +++ b/Source/Engine/Graphics/RenderView.h @@ -255,7 +255,7 @@ public: public: // Ignore deprecation warnings in defaults PRAGMA_DISABLE_DEPRECATION_WARNINGS - RenderView(); + RenderView() = default; RenderView(const RenderView& other) = default; RenderView(RenderView&& other) = default; RenderView& operator=(const RenderView& other) = default; From b6aa38569f1e61aaa42181b301abd7c7b20bda8a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 19 Feb 2023 14:59:25 +0100 Subject: [PATCH 37/37] Fix app image exporting to favor CPU data and prevent issues --- Source/Editor/Utilities/EditorUtilities.cpp | 23 ++++++++++++--------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Source/Editor/Utilities/EditorUtilities.cpp b/Source/Editor/Utilities/EditorUtilities.cpp index 7e7aad25c..3fba14859 100644 --- a/Source/Editor/Utilities/EditorUtilities.cpp +++ b/Source/Editor/Utilities/EditorUtilities.cpp @@ -543,19 +543,22 @@ bool EditorUtilities::GetTexture(const Guid& textureId, TextureData& textureData } else { - // TODO: disable streaming for a texture or set max quality override - int32 waits = 1000; - const auto targetResidency = texture->StreamingTexture()->GetMaxResidency(); - ASSERT(targetResidency > 0); - while (targetResidency != texture->StreamingTexture()->GetCurrentResidency() && waits-- > 0) + const bool useGPU = texture->IsVirtual(); + if (useGPU) { - Platform::Sleep(10); + int32 waits = 1000; + const auto targetResidency = texture->StreamingTexture()->GetMaxResidency(); + ASSERT(targetResidency > 0); + while (targetResidency != texture->StreamingTexture()->GetCurrentResidency() && waits-- > 0) + { + Platform::Sleep(10); + } + + // Get texture data from GPU + if (!texture->GetTexture()->DownloadData(textureData)) + return false; } - // Get texture data from GPU - if (!texture->GetTexture()->DownloadData(textureData)) - return false; - // Get texture data from asset if (!texture->GetTextureData(textureData)) return false;