From 02c333c720db2caad6862d72f3f9a1ff6b9b6802 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sat, 19 Apr 2025 02:38:29 +0300 Subject: [PATCH 01/77] Use double vector types in camera view matrix calculations --- Source/Engine/Core/Math/Double4x4.h | 3 +++ Source/Engine/Core/Math/Matrix.cpp | 31 +++++++++++++++++++++++++++ Source/Engine/Level/Actors/Camera.cpp | 16 ++++++++------ 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/Source/Engine/Core/Math/Double4x4.h b/Source/Engine/Core/Math/Double4x4.h index b7c06e5c5..b8a20bf67 100644 --- a/Source/Engine/Core/Math/Double4x4.h +++ b/Source/Engine/Core/Math/Double4x4.h @@ -93,6 +93,9 @@ public: // Calculates the inverse of the specified matrix. static void Invert(const Double4x4& value, Double4x4& result); + // Creates a left-handed, look-at matrix. + static void LookAt(const Double3& eye, const Double3& target, const Double3& up, Double4x4& result); + // Calculates the product of two matrices. static void Multiply(const Double4x4& left, const Double4x4& right, Double4x4& result); diff --git a/Source/Engine/Core/Math/Matrix.cpp b/Source/Engine/Core/Math/Matrix.cpp index 87d73ff59..dea1d77d2 100644 --- a/Source/Engine/Core/Math/Matrix.cpp +++ b/Source/Engine/Core/Math/Matrix.cpp @@ -1001,6 +1001,37 @@ void Double4x4::Invert(const Double4x4& value, Double4x4& result) result.M44 = +d44 * det; } +void Double4x4::LookAt(const Double3& eye, const Double3& target, const Double3& up, Double4x4& result) +{ + Double3 xaxis, yaxis, zaxis; + Double3::Subtract(target, eye, zaxis); + zaxis.Normalize(); + Double3::Cross(up, zaxis, xaxis); + xaxis.Normalize(); + Double3::Cross(zaxis, xaxis, yaxis); + + result.M11 = xaxis.X; + result.M21 = xaxis.Y; + result.M31 = xaxis.Z; + + result.M12 = yaxis.X; + result.M22 = yaxis.Y; + result.M32 = yaxis.Z; + + result.M13 = zaxis.X; + result.M23 = zaxis.Y; + result.M33 = zaxis.Z; + + result.M14 = 0.0f; + result.M24 = 0.0f; + result.M34 = 0.0f; + + result.M41 = -Double3::Dot(xaxis, eye); + result.M42 = -Double3::Dot(yaxis, eye); + result.M43 = -Double3::Dot(zaxis, eye); + result.M44 = 1.0f; +} + void Double4x4::Multiply(const Double4x4& left, const Double4x4& right, Double4x4& result) { result.M11 = left.M11 * right.M11 + left.M12 * right.M21 + left.M13 * right.M31 + left.M14 * right.M41; diff --git a/Source/Engine/Level/Actors/Camera.cpp b/Source/Engine/Level/Actors/Camera.cpp index 9f33d0907..6a54d88f3 100644 --- a/Source/Engine/Level/Actors/Camera.cpp +++ b/Source/Engine/Level/Actors/Camera.cpp @@ -3,6 +3,7 @@ #include "Camera.h" #include "Engine/Level/SceneObjectsFactory.h" #include "Engine/Core/Math/Matrix.h" +#include "Engine/Core/Math/Double4x4.h" #include "Engine/Core/Math/Viewport.h" #include "Engine/Content/Assets/Model.h" #include "Engine/Content/Content.h" @@ -302,12 +303,15 @@ void Camera::GetMatrices(Matrix& view, Matrix& projection, const Viewport& viewp } // Create view matrix - const Float3 direction = GetDirection(); - const Float3 position = _transform.Translation - origin; - const Float3 target = position + direction; - Float3 up; - Float3::Transform(Float3::Up, GetOrientation(), up); - Matrix::LookAt(position, target, up, view); + const Vector3 direction = Vector3::Transform(Vector3::Forward, GetOrientation()); + const Vector3 position = _transform.Translation - origin; + const Vector3 target = position + direction; + + Vector3 up; + Vector3::Transform(Vector3::Up, GetOrientation(), up); + Real4x4 viewResult; + Real4x4::LookAt(position, target, up, viewResult); + view = Matrix(viewResult); } #if USE_EDITOR From a2ff6e5c24a761d213a9ce5e4734f1d4defbdd15 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 22 Apr 2025 11:02:53 +0200 Subject: [PATCH 02/77] Fix missing `BoundsScale` usage on `AnimatedModel` --- Source/Engine/Level/Actors/AnimatedModel.cpp | 2 +- Source/Engine/Level/Actors/AnimatedModel.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index af40a5458..7863578c6 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -766,7 +766,7 @@ void AnimatedModel::UpdateBounds() // Apply margin based on model dimensions const Vector3 modelBoxSize = modelBox.GetSize(); const Vector3 center = box.GetCenter(); - const Vector3 sizeHalf = Vector3::Max(box.GetSize() + modelBoxSize * 0.2f, modelBoxSize) * 0.5f; + const Vector3 sizeHalf = Vector3::Max(box.GetSize() + modelBoxSize * 0.2f, modelBoxSize) * (0.5f * BoundsScale); _box = BoundingBox(center - sizeHalf, center + sizeHalf); } else diff --git a/Source/Engine/Level/Actors/AnimatedModel.h b/Source/Engine/Level/Actors/AnimatedModel.h index ff84125fc..89124cb87 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.h +++ b/Source/Engine/Level/Actors/AnimatedModel.h @@ -96,7 +96,7 @@ public: bool PerBoneMotionBlur = true; /// - /// If true, animation speed will be affected by the global time scale parameter. + /// If true, animation speed will be affected by the global timescale parameter. /// API_FIELD(Attributes="EditorOrder(30), DefaultValue(true), EditorDisplay(\"Skinned Model\")") bool UseTimeScale = true; @@ -108,7 +108,7 @@ public: bool UpdateWhenOffscreen = false; /// - /// The animation update delta time scale. Can be used to speed up animation playback or create slow motion effect. + /// The animation update delta timescale. Can be used to speed up animation playback or create slow motion effect. /// API_FIELD(Attributes="EditorOrder(45), EditorDisplay(\"Skinned Model\")") float UpdateSpeed = 1.0f; @@ -120,7 +120,7 @@ public: AnimationUpdateMode UpdateMode = AnimationUpdateMode::Auto; /// - /// The master scale parameter for the actor bounding box. Helps reducing mesh flickering effect on screen edges. + /// The master scale parameter for the actor bounding box. Helps to reduce mesh flickering effect on screen edges. /// API_FIELD(Attributes="EditorOrder(60), DefaultValue(1.5f), Limit(0), EditorDisplay(\"Skinned Model\")") float BoundsScale = 1.5f; @@ -388,7 +388,7 @@ public: API_FUNCTION() void PauseSlotAnimation(const StringView& slotName, Animation* anim); /// - /// Checks if the any animation playback is active on the any slot in Anim Graph (not paused). + /// Checks if any animation playback is active on any slot in Anim Graph (not paused). /// API_FUNCTION() bool IsPlayingSlotAnimation(); From f9e9f26e9747ebd03130b9e359dfa45f87bf1b21 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 22 Apr 2025 11:04:09 +0200 Subject: [PATCH 03/77] Remove leftover debug log from bindings generator --- Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs index fd3f3810b..54329634f 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs @@ -1629,8 +1629,6 @@ namespace Flax.Build.Bindings } else originalType = type = GenerateCSharpNativeToManaged(buildData, marshalType, structureInfo); - if (apiType != null && apiType.MarshalAs != null) - Log.Error("marshal as into type: " + type); structContents.Append(structIndent).Append("public "); string internalTypeMarshaller = ""; if (marshalType.IsArray && (fieldInfo.NoArray || structureInfo.IsPod)) From caf0251a9c0fcf5c07b8602b3bdc2e5d75da613a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 22 Apr 2025 12:00:35 +0200 Subject: [PATCH 04/77] Fix bug in CustomEditorWindow usage #3392 --- Source/Editor/CustomEditorWindow.cs | 2 +- Source/Editor/CustomEditors/CustomEditorPresenter.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/Editor/CustomEditorWindow.cs b/Source/Editor/CustomEditorWindow.cs index 72c28234d..f28a844ef 100644 --- a/Source/Editor/CustomEditorWindow.cs +++ b/Source/Editor/CustomEditorWindow.cs @@ -33,8 +33,8 @@ namespace FlaxEditor private void Set(CustomEditorWindow value) { _customEditor = value; - _presenter.Select(value); _presenter.OverrideEditor = value; + _presenter.Select(value); } /// diff --git a/Source/Editor/CustomEditors/CustomEditorPresenter.cs b/Source/Editor/CustomEditors/CustomEditorPresenter.cs index f441d2928..62db53cab 100644 --- a/Source/Editor/CustomEditors/CustomEditorPresenter.cs +++ b/Source/Editor/CustomEditors/CustomEditorPresenter.cs @@ -132,6 +132,8 @@ namespace FlaxEditor.CustomEditors get => _overrideEditor; set { + if (_overrideEditor == value) + return; _overrideEditor = value; RebuildLayout(); } @@ -200,7 +202,6 @@ namespace FlaxEditor.CustomEditors protected override void Deinitialize() { Editor = null; - _overrideEditor = null; base.Deinitialize(); } From 9ae1867c9e344aaf7d8271ae5d80eed69189eca8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 22 Apr 2025 12:08:10 +0200 Subject: [PATCH 05/77] Fix crash when rendering bloom or lens flares in too small viewport --- Source/Engine/Renderer/PostProcessingPass.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Source/Engine/Renderer/PostProcessingPass.cpp b/Source/Engine/Renderer/PostProcessingPass.cpp index 734699511..9192c8ca4 100644 --- a/Source/Engine/Renderer/PostProcessingPass.cpp +++ b/Source/Engine/Renderer/PostProcessingPass.cpp @@ -276,11 +276,10 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, int32 h2 = h1 >> 1; int32 h4 = h2 >> 1; int32 h8 = h4 >> 1; - int32 bloomMipCount = CalculateBloomMipCount(w1, h1); // Ensure to have valid data and if at least one effect should be applied - if (!(useBloom || useToneMapping || useCameraArtifacts) || checkIfSkipPass() || w8 == 0 || h8 == 0) + if (!(useBloom || useToneMapping || useCameraArtifacts) || checkIfSkipPass() || w8 <= 1 || h8 <= 1) { // Resources are missing. Do not perform rendering. Just copy raw frame context->SetViewportAndScissors((float)output->Width(), (float)output->Height()); From 4f3fbe89f2f313dd35630fa3e6afcad879d67d5a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 22 Apr 2025 12:32:36 +0200 Subject: [PATCH 06/77] Cleanup code to share it for engine service profile event formatting --- Source/Engine/Engine/EngineService.cpp | 35 +++++++++++++++----------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/Source/Engine/Engine/EngineService.cpp b/Source/Engine/Engine/EngineService.cpp index 265509e6a..433cf089f 100644 --- a/Source/Engine/Engine/EngineService.cpp +++ b/Source/Engine/Engine/EngineService.cpp @@ -37,6 +37,21 @@ DEFINE_ENGINE_SERVICE_EVENT(LateFixedUpdate); DEFINE_ENGINE_SERVICE_EVENT(Draw); DEFINE_ENGINE_SERVICE_EVENT_INVERTED(BeforeExit); +#if TRACY_ENABLE + +StringView FillEventNameBuffer(Char* buffer, StringView name, StringView postfix) +{ + int32 size = 0; + for (int32 j = 0; j < name.Length(); j++) + if (name[j] != ' ') + buffer[size++] = name[j]; + Platform::MemoryCopy(buffer + size, postfix.Get(), (postfix.Length() + 1) * sizeof(Char)); + size += postfix.Length(); + return StringView(buffer, size); +} + +#endif + EngineService::EngineServicesArray& EngineService::GetServices() { static EngineServicesArray Services; @@ -78,14 +93,9 @@ void EngineService::OnInit() const StringView name(service->Name); #if TRACY_ENABLE ZoneScoped; - int32 nameBufferLength = 0; Char nameBuffer[100]; - for (int32 j = 0; j < name.Length(); j++) - if (name[j] != ' ') - nameBuffer[nameBufferLength++] = name[j]; - Platform::MemoryCopy(nameBuffer + nameBufferLength, TEXT("::Init"), 7 * sizeof(Char)); - nameBufferLength += 7; - ZoneName(nameBuffer, nameBufferLength); + StringView zoneName = FillEventNameBuffer(nameBuffer, name, StringView(TEXT("::Init"), 6)); + ZoneName(zoneName.Get(), zoneName.Length()); #endif LOG(Info, "Initialize {0}...", name); service->IsInitialized = true; @@ -114,15 +124,10 @@ void EngineService::OnDispose() { #if TRACY_ENABLE ZoneScoped; - const StringView name(service->Name); - int32 nameBufferLength = 0; Char nameBuffer[100]; - for (int32 j = 0; j < name.Length(); j++) - if (name[j] != ' ') - nameBuffer[nameBufferLength++] = name[j]; - Platform::MemoryCopy(nameBuffer + nameBufferLength, TEXT("::Dispose"), 10 * sizeof(Char)); - nameBufferLength += 10; - ZoneName(nameBuffer, nameBufferLength); + const StringView name(service->Name); + StringView zoneName = FillEventNameBuffer(nameBuffer, name, StringView(TEXT("::Dispose"), 9)); + ZoneName(zoneName.Get(), zoneName.Length()); #endif service->IsInitialized = false; service->Dispose(); From d77024bbf1f4c9cadb777b36b1ce3ebabf348396 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 22 Apr 2025 16:16:46 +0200 Subject: [PATCH 07/77] Fix crash when existing engine while content streaming is active --- Source/Engine/Content/Asset.cpp | 21 +++++++------------ .../Content/Loading/Tasks/LoadAssetDataTask.h | 4 ++++ .../Graphics/Textures/StreamingTexture.cpp | 12 ++++++----- Source/Engine/Threading/Task.cpp | 4 ++-- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/Source/Engine/Content/Asset.cpp b/Source/Engine/Content/Asset.cpp index c128a33a0..0d5391482 100644 --- a/Source/Engine/Content/Asset.cpp +++ b/Source/Engine/Content/Asset.cpp @@ -467,11 +467,13 @@ void Asset::CancelStreaming() { // Cancel loading task but go over asset locker to prevent case if other load threads still loads asset while it's reimported on other thread Locker.Lock(); - auto loadTask = (ContentLoadTask*)Platform::AtomicRead(&_loadingTask); + auto loadingTask = (ContentLoadTask*)Platform::AtomicRead(&_loadingTask); Locker.Unlock(); - if (loadTask) + if (loadingTask) { - loadTask->Cancel(); + Platform::AtomicStore(&_loadingTask, 0); + LOG(Warning, "Cancel loading task for \'{0}\'", ToString()); + loadingTask->Cancel(); } } @@ -632,18 +634,11 @@ void Asset::onUnload_MainThread() ASSERT(IsInMainThread()); + // Cancel any streaming before calling OnUnloaded event + CancelStreaming(); + // Send event OnUnloaded(this); - - // Check if is during loading - auto loadingTask = (ContentLoadTask*)Platform::AtomicRead(&_loadingTask); - if (loadingTask != nullptr) - { - // Cancel loading - Platform::AtomicStore(&_loadingTask, 0); - LOG(Warning, "Cancel loading task for \'{0}\'", ToString()); - loadingTask->Cancel(); - } } #if USE_EDITOR diff --git a/Source/Engine/Content/Loading/Tasks/LoadAssetDataTask.h b/Source/Engine/Content/Loading/Tasks/LoadAssetDataTask.h index de0c503bf..5c9ab5604 100644 --- a/Source/Engine/Content/Loading/Tasks/LoadAssetDataTask.h +++ b/Source/Engine/Content/Loading/Tasks/LoadAssetDataTask.h @@ -34,6 +34,10 @@ public: public: // [ContentLoadTask] + String ToString() const override + { + return String::Format(TEXT("Load Asset Data Task ({}, {}, {})"), (int32)GetState(), _chunks, _asset ? _asset->GetPath() : String::Empty); + } bool HasReference(Object* obj) const override { return obj == _asset; diff --git a/Source/Engine/Graphics/Textures/StreamingTexture.cpp b/Source/Engine/Graphics/Textures/StreamingTexture.cpp index 4d1e8bb14..87378ef9d 100644 --- a/Source/Engine/Graphics/Textures/StreamingTexture.cpp +++ b/Source/Engine/Graphics/Textures/StreamingTexture.cpp @@ -322,15 +322,17 @@ class StreamTextureMipTask : public GPUUploadTextureMipTask { private: StreamingTexture* _streamingTexture; + Task* _rootTask; FlaxStorage::LockData _dataLock; public: - StreamTextureMipTask(StreamingTexture* texture, int32 mipIndex) + StreamTextureMipTask(StreamingTexture* texture, int32 mipIndex, Task* rootTask) : GPUUploadTextureMipTask(texture->GetTexture(), mipIndex, Span(nullptr, 0), 0, 0, false) , _streamingTexture(texture) + , _rootTask(rootTask ? rootTask : this) , _dataLock(_streamingTexture->GetOwner()->LockData()) { - _streamingTexture->_streamingTasks.Add(this); + _streamingTexture->_streamingTasks.Add(_rootTask); _texture.Released.Bind(this); } @@ -341,7 +343,7 @@ private: if (_streamingTexture) { ScopeLock lock(_streamingTexture->GetOwner()->GetOwnerLocker()); - _streamingTexture->_streamingTasks.Remove(this); + _streamingTexture->_streamingTasks.Remove(_rootTask); _streamingTexture = nullptr; } } @@ -393,7 +395,7 @@ protected: if (_streamingTexture) { ScopeLock lock(_streamingTexture->GetOwner()->GetOwnerLocker()); - _streamingTexture->_streamingTasks.Remove(this); + _streamingTexture->_streamingTasks.Remove(_rootTask); _streamingTexture = nullptr; } @@ -443,7 +445,7 @@ Task* StreamingTexture::CreateStreamingTask(int32 residency) // Add upload data task const int32 allocatedMipIndex = TotalIndexToTextureMipIndex(mipIndex); - task = New(this, allocatedMipIndex); + task = New(this, allocatedMipIndex, result); if (result) result->ContinueWith(task); else diff --git a/Source/Engine/Threading/Task.cpp b/Source/Engine/Threading/Task.cpp index b4bd5f025..cd36619c9 100644 --- a/Source/Engine/Threading/Task.cpp +++ b/Source/Engine/Threading/Task.cpp @@ -208,8 +208,8 @@ void Task::OnCancel() if (IsRunning()) { // Wait for it a little bit - const double timeout = 2000.0; - LOG(Warning, "Cannot cancel \'{0}\' because it's still running, waiting for end with timeout: {1} ms", ToString(), timeout); + constexpr double timeout = 10000.0; // 10s + LOG(Warning, "Cannot cancel \'{0}\' because it's still running, waiting for end with timeout: {1}ms", ToString(), timeout); Wait(timeout); } From cfef93134ec0bd897b84d34089593effe4965234 Mon Sep 17 00:00:00 2001 From: alsed Date: Tue, 22 Apr 2025 17:16:12 -0400 Subject: [PATCH 08/77] Added Fedora instructions in Readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index c4d6e7298..67e955c43 100644 --- a/README.md +++ b/README.md @@ -46,9 +46,11 @@ Follow the instructions below to compile and run the engine from source. * Install Visual Studio Code * Install .NET 8 or 9 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)) * Ubuntu: `sudo apt install dotnet-sdk-8.0` + * Fedora: `sudo dnf install dotnet-sdk-8.0` * Arch: `sudo pacman -S dotnet-sdk-8.0 dotnet-runtime-8.0 dotnet-targeting-pack-8.0 dotnet-host` * Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/)) * Ubuntu: `sudo apt install vulkan-sdk` + * Fedora: `sudo dnf install vulkan-headers vulkan-tools vulkan-validation-layers spirv-tools` * Arch: `sudo pacman -S spirv-tools vulkan-headers vulkan-tools vulkan-validation-layers` * Install Git with LFS * Ubuntu: `sudo apt-get install git git-lfs` @@ -56,11 +58,14 @@ Follow the instructions below to compile and run the engine from source. * `git-lfs install` * Install the required packages: * Ubuntu: `sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev zlib1g-dev` + * Fedora: `sudo dnf install libX11-devel libXcursor-devel libXinerama-devel ghc-zlib-devel` * Arch: `sudo pacman -S base-devel libx11 libxcursor libxinerama zlib` * Install Clang compiler (version 6 or later): * Ubuntu: `sudo apt-get install clang lldb lld` + * Fedora: `sudo dnf install clang llvm lldb lld` * Arch: `sudo pacman -S clang lldb lld` * Clone the repository (with LFS) + * git-lfs clone https://github.com/FlaxEngine/FlaxEngine.git * Run `./GenerateProjectFiles.sh` * Open workspace with Visual Code * Build and run (configuration and task named `Flax|Editor.Linux.Development|x64`) From 992b08025fa92d3aca7a01ab23e82ab159a0a343 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 22 Apr 2025 23:28:21 +0200 Subject: [PATCH 09/77] Attempt to fix game cooking regression from ef188d06c4a3572eee72a1cdd2032b8c7438e149 --- Source/Engine/Graphics/Async/GPUTask.h | 8 ++++++++ Source/Engine/Graphics/Async/GPUTasksContext.cpp | 9 +++------ Source/Engine/Graphics/Async/GPUTasksManager.cpp | 3 +-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Source/Engine/Graphics/Async/GPUTask.h b/Source/Engine/Graphics/Async/GPUTask.h index d32b4a10a..261eda6f7 100644 --- a/Source/Engine/Graphics/Async/GPUTask.h +++ b/Source/Engine/Graphics/Async/GPUTask.h @@ -67,6 +67,14 @@ public: return _type; } + /// + /// Gets work synchronization start point + /// + FORCE_INLINE GPUSyncPoint GetSyncStart() const + { + return _syncPoint; + } + /// /// Gets work finish synchronization point /// diff --git a/Source/Engine/Graphics/Async/GPUTasksContext.cpp b/Source/Engine/Graphics/Async/GPUTasksContext.cpp index 887ee54be..4ef85c68a 100644 --- a/Source/Engine/Graphics/Async/GPUTasksContext.cpp +++ b/Source/Engine/Graphics/Async/GPUTasksContext.cpp @@ -36,7 +36,7 @@ GPUTasksContext::~GPUTasksContext() if (task->GetSyncPoint() <= _currentSyncPoint && task->GetState() != TaskState::Finished) { if (!Engine::IsRequestingExit) - LOG(Warning, "{0} has been canceled before a sync", task->ToString()); + LOG(Warning, "'{0}' has been canceled before a sync", task->ToString()); task->CancelSync(); } } @@ -51,18 +51,15 @@ void GPUTasksContext::Run(GPUTask* task) ASSERT(task != nullptr); task->Execute(this); - if (task->IsSyncing()) + if (task->GetSyncStart() != 0) _tasksSyncing.Add(task); } void GPUTasksContext::OnCancelSync(GPUTask* task) { - ASSERT(task != nullptr); - _tasksSyncing.Remove(task); - if (!Engine::IsRequestingExit) - LOG(Warning, "{0} has been canceled before a sync", task->ToString()); + LOG(Warning, "'{0}' has been canceled before a sync", task->ToString()); } void GPUTasksContext::OnFrameBegin() diff --git a/Source/Engine/Graphics/Async/GPUTasksManager.cpp b/Source/Engine/Graphics/Async/GPUTasksManager.cpp index e393d96ef..3c41f9da8 100644 --- a/Source/Engine/Graphics/Async/GPUTasksManager.cpp +++ b/Source/Engine/Graphics/Async/GPUTasksManager.cpp @@ -51,10 +51,9 @@ void GPUTask::Enqueue() void GPUTask::OnCancel() { // Check if task is waiting for sync (very likely situation) - if (IsSyncing()) + if (IsSyncing() && _context) { // Task has been performed but is waiting for a CPU/GPU sync so we have to cancel that - ASSERT(_context != nullptr); _context->OnCancelSync(this); _context = nullptr; } From f0bcc7056351188873aef77b67b88f68e082eec2 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 22 Apr 2025 23:44:34 +0200 Subject: [PATCH 10/77] Attempt to fix game cooking regression from ef188d06c4a3572eee72a1cdd2032b8c7438e149 --- Source/Engine/Graphics/Async/GPUTasksContext.cpp | 2 +- Source/Engine/Graphics/Async/GPUTasksContext.h | 2 +- Source/Engine/Graphics/Async/GPUTasksManager.cpp | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/Engine/Graphics/Async/GPUTasksContext.cpp b/Source/Engine/Graphics/Async/GPUTasksContext.cpp index 4ef85c68a..fe2198865 100644 --- a/Source/Engine/Graphics/Async/GPUTasksContext.cpp +++ b/Source/Engine/Graphics/Async/GPUTasksContext.cpp @@ -51,7 +51,7 @@ void GPUTasksContext::Run(GPUTask* task) ASSERT(task != nullptr); task->Execute(this); - if (task->GetSyncStart() != 0) + //if (task->GetSyncStart() != 0) _tasksSyncing.Add(task); } diff --git a/Source/Engine/Graphics/Async/GPUTasksContext.h b/Source/Engine/Graphics/Async/GPUTasksContext.h index 9afb9b575..57c4673e7 100644 --- a/Source/Engine/Graphics/Async/GPUTasksContext.h +++ b/Source/Engine/Graphics/Async/GPUTasksContext.h @@ -18,7 +18,7 @@ protected: CriticalSection _locker; GPUSyncPoint _currentSyncPoint; int32 _totalTasksDoneCount = 0; - Array> _tasksSyncing; + Array _tasksSyncing; public: /// diff --git a/Source/Engine/Graphics/Async/GPUTasksManager.cpp b/Source/Engine/Graphics/Async/GPUTasksManager.cpp index 3c41f9da8..d7c9b6f76 100644 --- a/Source/Engine/Graphics/Async/GPUTasksManager.cpp +++ b/Source/Engine/Graphics/Async/GPUTasksManager.cpp @@ -51,11 +51,12 @@ void GPUTask::Enqueue() void GPUTask::OnCancel() { // Check if task is waiting for sync (very likely situation) - if (IsSyncing() && _context) + if (IsSyncing()) { // Task has been performed but is waiting for a CPU/GPU sync so we have to cancel that _context->OnCancelSync(this); _context = nullptr; + SetState(TaskState::Canceled); } // Base From e5b7e58a07560db2e5961bfbaead6fb0475e3245 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 25 Apr 2025 17:11:36 -0500 Subject: [PATCH 11/77] Fix newly created skeleton mask from being able to be opened. --- Source/Engine/ContentImporters/CreateSkeletonMask.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/ContentImporters/CreateSkeletonMask.h b/Source/Engine/ContentImporters/CreateSkeletonMask.h index 3a88d4ca3..d785a789f 100644 --- a/Source/Engine/ContentImporters/CreateSkeletonMask.h +++ b/Source/Engine/ContentImporters/CreateSkeletonMask.h @@ -22,7 +22,7 @@ public: static CreateAssetResult Create(CreateAssetContext& context) { // Base - IMPORT_SETUP(SkeletonMask, 1); + IMPORT_SETUP(SkeletonMask, 2); // Chunk 0 if (context.AllocateChunk(0)) From bbc221086abab1a9491bf698de2229a4a18440ba Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 25 Apr 2025 17:55:07 -0500 Subject: [PATCH 12/77] Fix GUI input when edit GUI option is false and game is being played. --- Source/Editor/Windows/GameWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/Windows/GameWindow.cs b/Source/Editor/Windows/GameWindow.cs index 02d4b8351..b117eaa3d 100644 --- a/Source/Editor/Windows/GameWindow.cs +++ b/Source/Editor/Windows/GameWindow.cs @@ -292,7 +292,7 @@ namespace FlaxEditor.Windows private class GameRoot : UIEditorRoot { internal bool Editable = true; - public override bool EnableInputs => !Time.GamePaused && Editor.IsPlayMode && Editable; + public override bool EnableInputs => !Time.GamePaused && (Editor.IsPlayMode || Editable); public override bool EnableSelecting => (!Editor.IsPlayMode || Time.GamePaused) && Editable; public override TransformGizmo TransformGizmo => Editor.Instance.MainTransformGizmo; } From 9d527ab4a6326f1fc15b9c68e93886bb29ad0c7c Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 25 Apr 2025 20:36:53 -0500 Subject: [PATCH 13/77] Remove editable from check for enabling inputs for game window GUI. --- Source/Editor/Windows/GameWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/Windows/GameWindow.cs b/Source/Editor/Windows/GameWindow.cs index b117eaa3d..f738a7a8c 100644 --- a/Source/Editor/Windows/GameWindow.cs +++ b/Source/Editor/Windows/GameWindow.cs @@ -292,7 +292,7 @@ namespace FlaxEditor.Windows private class GameRoot : UIEditorRoot { internal bool Editable = true; - public override bool EnableInputs => !Time.GamePaused && (Editor.IsPlayMode || Editable); + public override bool EnableInputs => !Time.GamePaused && Editor.IsPlayMode; public override bool EnableSelecting => (!Editor.IsPlayMode || Time.GamePaused) && Editable; public override TransformGizmo TransformGizmo => Editor.Instance.MainTransformGizmo; } From 4b387d040db1199840830633c544805ea0fe2c97 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sat, 26 Apr 2025 07:07:27 -0500 Subject: [PATCH 14/77] Fix spelling on Additive Blend node tooltip. --- Source/Editor/Surface/Archetypes/Animation.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/Animation.cs b/Source/Editor/Surface/Archetypes/Animation.cs index 43a699bf3..88004c75d 100644 --- a/Source/Editor/Surface/Archetypes/Animation.cs +++ b/Source/Editor/Surface/Archetypes/Animation.cs @@ -573,11 +573,11 @@ namespace FlaxEditor.Surface.Archetypes "Blend animation poses (with additive mode)" + "\n" + "\nNote: " + - "\nOrder of nodes matters, because Additive animation is appplayed on top of curent frame." + + "\nOrder of nodes matters, because Additive animation is applied on top of current frame." + "\n" + "\nTip for blender users:" + - "\nInside NLA the the order is bottom (first node in flax) to the top (last node in flax)" + - "\n​u need to place it in this order to get correct resoults", + "\nInside NLA the the order is bottom (first node in flax) to the top (last node in flax)." + + "\nYou need to place animations in this order to get correct results.", Flags = NodeFlags.AnimGraph, Size = new Float2(170, 80), DefaultValues = new object[] From 1ab05b620a006263440c76d2f27b54b187c199a9 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sat, 26 Apr 2025 07:08:49 -0500 Subject: [PATCH 15/77] Another small grammer mistake. --- Source/Editor/Surface/Archetypes/Animation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/Surface/Archetypes/Animation.cs b/Source/Editor/Surface/Archetypes/Animation.cs index 88004c75d..f71f50596 100644 --- a/Source/Editor/Surface/Archetypes/Animation.cs +++ b/Source/Editor/Surface/Archetypes/Animation.cs @@ -573,7 +573,7 @@ namespace FlaxEditor.Surface.Archetypes "Blend animation poses (with additive mode)" + "\n" + "\nNote: " + - "\nOrder of nodes matters, because Additive animation is applied on top of current frame." + + "\nThe order of the nodes is important, because additive animation is applied on top of current frame." + "\n" + "\nTip for blender users:" + "\nInside NLA the the order is bottom (first node in flax) to the top (last node in flax)." + From 059fe98c67e52f64e9d105eb84a26e10b9e74b0d Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sat, 26 Apr 2025 07:38:18 -0500 Subject: [PATCH 16/77] Fix scroll bars not updating when dragging. --- Source/Engine/UI/GUI/Panels/Panel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/UI/GUI/Panels/Panel.cs b/Source/Engine/UI/GUI/Panels/Panel.cs index 1ffae12f8..01c3bb61d 100644 --- a/Source/Engine/UI/GUI/Panels/Panel.cs +++ b/Source/Engine/UI/GUI/Panels/Panel.cs @@ -689,7 +689,7 @@ namespace FlaxEngine.GUI } viewOffset.Y = Mathf.Clamp(viewOffset.Y, VScrollBar.Minimum, VScrollBar.Maximum); - VScrollBar.Value = viewOffset.Y; + VScrollBar.TargetValue = viewOffset.Y; } if (HScrollBar != null && HScrollBar.Enabled && width > MinSize) @@ -704,7 +704,7 @@ namespace FlaxEngine.GUI } viewOffset.X = Mathf.Clamp(viewOffset.X, HScrollBar.Minimum, HScrollBar.Maximum); - HScrollBar.Value = viewOffset.X; + HScrollBar.TargetValue = viewOffset.X; } viewOffset *= -1; From 2ea3cde2035e2a3115001cf703525c75fab84209 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Sat, 26 Apr 2025 16:33:49 +0200 Subject: [PATCH 17/77] add search operator tooltip to prefab editor search bar somewhat of a follow up to #3300 --- Source/Editor/Windows/Assets/PrefabWindow.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Editor/Windows/Assets/PrefabWindow.cs b/Source/Editor/Windows/Assets/PrefabWindow.cs index aa78c06a2..1b2ca48bc 100644 --- a/Source/Editor/Windows/Assets/PrefabWindow.cs +++ b/Source/Editor/Windows/Assets/PrefabWindow.cs @@ -160,6 +160,7 @@ namespace FlaxEditor.Windows.Assets AnchorPreset = AnchorPresets.HorizontalStretchMiddle, Parent = headerPanel, Bounds = new Rectangle(4, 4, headerPanel.Width - 8, 18), + TooltipText = "Search the prefab.\n\nYou can prefix your search with different search operators:\ns: -> Actor with script of type\na: -> Actor type\nc: -> Control type", }; _searchBox.TextChanged += OnSearchBoxTextChanged; From 6fe6ba20fbe9de503c6058757eb76b82e5890815 Mon Sep 17 00:00:00 2001 From: Zode Date: Sat, 26 Apr 2025 21:40:12 +0300 Subject: [PATCH 18/77] Fix profiler memory propagation --- Source/Editor/Windows/Profiler/CPU.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/Windows/Profiler/CPU.cs b/Source/Editor/Windows/Profiler/CPU.cs index 811c34600..d034a058b 100644 --- a/Source/Editor/Windows/Profiler/CPU.cs +++ b/Source/Editor/Windows/Profiler/CPU.cs @@ -492,7 +492,7 @@ namespace FlaxEditor.Windows.Profiler { break; } - subEventsMemoryTotal += sub.ManagedMemoryAllocation + e.NativeMemoryAllocation; + subEventsMemoryTotal += sub.ManagedMemoryAllocation + sub.NativeMemoryAllocation; } string name = e.Name.Replace("::", "."); From e568e6e17b49213108c668f0aaee1d23e94ee9d1 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Thu, 1 May 2025 19:15:43 +0200 Subject: [PATCH 19/77] improve import path ui --- .../Dedicated/ModelPrefabEditor.cs | 3 ++- Source/Editor/Utilities/Utils.cs | 20 +++++++++---------- .../Editor/Windows/Assets/AnimationWindow.cs | 3 ++- .../Editor/Windows/Assets/AudioClipWindow.cs | 7 +++++-- .../Windows/Assets/CubeTextureWindow.cs | 7 ++++--- .../Editor/Windows/Assets/ModelBaseWindow.cs | 11 +++++----- .../Windows/Assets/SpriteAtlasWindow.cs | 5 +++-- Source/Editor/Windows/Assets/TextureWindow.cs | 3 ++- 8 files changed, 33 insertions(+), 26 deletions(-) diff --git a/Source/Editor/CustomEditors/Dedicated/ModelPrefabEditor.cs b/Source/Editor/CustomEditors/Dedicated/ModelPrefabEditor.cs index 65b39962b..f57548258 100644 --- a/Source/Editor/CustomEditors/Dedicated/ModelPrefabEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ModelPrefabEditor.cs @@ -54,7 +54,8 @@ public class ModelPrefabEditor : GenericEditor } // Creates the import path UI - Utilities.Utils.CreateImportPathUI(layout, modelPrefab.ImportPath, false); + var group = layout.Group("Import Path"); + Utilities.Utils.CreateImportPathUI(group, modelPrefab.ImportPath, false); var button = layout.Button("Reimport", "Reimports the source asset as prefab."); _reimportButton = button.Button; diff --git a/Source/Editor/Utilities/Utils.cs b/Source/Editor/Utilities/Utils.cs index b4666b213..ad2ee87a2 100644 --- a/Source/Editor/Utilities/Utils.cs +++ b/Source/Editor/Utilities/Utils.cs @@ -402,33 +402,31 @@ namespace FlaxEditor.Utilities /// /// Creates an Import path ui that show the asset import path and adds a button to show the folder in the file system. /// - /// The parent layout container. + /// The parent group element. /// The asset item to get the import path of. - public static void CreateImportPathUI(CustomEditors.LayoutElementsContainer parentLayout, Content.BinaryAssetItem assetItem) + public static void CreateImportPathUI(CustomEditors.Elements.GroupElement group, Content.BinaryAssetItem assetItem) { assetItem.GetImportPath(out var path); - CreateImportPathUI(parentLayout, path); + CreateImportPathUI(group, path); } /// /// Creates an Import path ui that show the import path and adds a button to show the folder in the file system. /// - /// The parent layout container. + /// The parent group element. /// The import path. /// Whether to use an initial layout space of 5 for separation. - public static void CreateImportPathUI(CustomEditors.LayoutElementsContainer parentLayout, string path, bool useInitialSpacing = true) + public static void CreateImportPathUI(CustomEditors.Elements.GroupElement group, string path, bool useInitialSpacing = true) { if (!string.IsNullOrEmpty(path)) { if (useInitialSpacing) - parentLayout.Space(5); - parentLayout.Label("Import Path:").Label.TooltipText = "Source asset path (can be relative or absolute to the project)"; - var textBox = parentLayout.TextBox().TextBox; - textBox.TooltipText = "Path is not editable here."; + group.Space(0); + var textBox = group.TextBox().TextBox; + textBox.TooltipText = "Source asset path. Can be relative or absolute to the project. Path is not editable here."; textBox.IsReadOnly = true; textBox.Text = path; - parentLayout.Space(2); - var button = parentLayout.Button(Constants.ShowInExplorer).Button; + var button = group.Button(Constants.ShowInExplorer).Button; button.Clicked += () => FileSystem.ShowFileExplorer(Path.GetDirectoryName(path)); } } diff --git a/Source/Editor/Windows/Assets/AnimationWindow.cs b/Source/Editor/Windows/Assets/AnimationWindow.cs index 1235bf62d..41fdfde65 100644 --- a/Source/Editor/Windows/Assets/AnimationWindow.cs +++ b/Source/Editor/Windows/Assets/AnimationWindow.cs @@ -231,7 +231,8 @@ namespace FlaxEditor.Windows.Assets group.Object(importSettingsValues); // Creates the import path UI - Utilities.Utils.CreateImportPathUI(layout, proxy.Window.Item as BinaryAssetItem); + group = layout.Group("Import Path"); + Utilities.Utils.CreateImportPathUI(group, proxy.Window.Item as BinaryAssetItem); layout.Space(5); var reimportButton = layout.Button("Reimport"); diff --git a/Source/Editor/Windows/Assets/AudioClipWindow.cs b/Source/Editor/Windows/Assets/AudioClipWindow.cs index 1c15ee96f..250a7eb77 100644 --- a/Source/Editor/Windows/Assets/AudioClipWindow.cs +++ b/Source/Editor/Windows/Assets/AudioClipWindow.cs @@ -6,6 +6,7 @@ using FlaxEditor.Content.Import; using FlaxEditor.CustomEditors; using FlaxEditor.CustomEditors.Editors; using FlaxEditor.GUI; +using FlaxEditor.Scripting; using FlaxEditor.Viewport.Previews; using FlaxEngine; using FlaxEngine.GUI; @@ -76,7 +77,8 @@ namespace FlaxEditor.Windows.Assets { public override void Initialize(LayoutElementsContainer layout) { - var window = ((PropertiesProxy)Values[0])._window; + var proxy = ((PropertiesProxy)Values[0]); + var window = proxy._window; if (window == null) { layout.Label("Loading...", TextAlignment.Center); @@ -101,7 +103,8 @@ namespace FlaxEditor.Windows.Assets base.Initialize(layout); // Creates the import path UI - Utilities.Utils.CreateImportPathUI(layout, window.Item as BinaryAssetItem); + var pathGroup = layout.Group("Import Path"); + Utilities.Utils.CreateImportPathUI(pathGroup, window.Item as BinaryAssetItem); layout.Space(5); var reimportButton = layout.Button("Reimport"); diff --git a/Source/Editor/Windows/Assets/CubeTextureWindow.cs b/Source/Editor/Windows/Assets/CubeTextureWindow.cs index c27061630..c4d7ab053 100644 --- a/Source/Editor/Windows/Assets/CubeTextureWindow.cs +++ b/Source/Editor/Windows/Assets/CubeTextureWindow.cs @@ -55,10 +55,11 @@ namespace FlaxEditor.Windows.Assets base.Initialize(layout); // Creates the import path UI - Utilities.Utils.CreateImportPathUI(layout, window.Item as BinaryAssetItem); + var pathGroup = layout.Group("Import Path"); + Utilities.Utils.CreateImportPathUI(pathGroup, window.Item as BinaryAssetItem); - layout.Space(5); - var reimportButton = layout.Button("Reimport"); + pathGroup.Space(5); + var reimportButton = pathGroup.Button("Reimport"); reimportButton.Button.Clicked += () => ((PropertiesProxy)Values[0]).Reimport(); } } diff --git a/Source/Editor/Windows/Assets/ModelBaseWindow.cs b/Source/Editor/Windows/Assets/ModelBaseWindow.cs index 3431dfd7f..216dede67 100644 --- a/Source/Editor/Windows/Assets/ModelBaseWindow.cs +++ b/Source/Editor/Windows/Assets/ModelBaseWindow.cs @@ -754,17 +754,18 @@ namespace FlaxEditor.Windows.Assets if (Utilities.Utils.OnAssetProperties(layout, proxy.Asset)) return; - var group = layout.Group("Import Settings"); + var importSettingsGroup = layout.Group("Import Settings"); var importSettingsField = typeof(ImportPropertiesProxyBase).GetField(nameof(ImportSettings), BindingFlags.NonPublic | BindingFlags.Instance); var importSettingsValues = new ValueContainer(new ScriptMemberInfo(importSettingsField)) { proxy.ImportSettings }; - group.Object(importSettingsValues); + importSettingsGroup.Object(importSettingsValues); + importSettingsGroup.Space(3); // Creates the import path UI - Utilities.Utils.CreateImportPathUI(layout, proxy.Window.Item as BinaryAssetItem); + var group = layout.Group("Import Path"); + Utilities.Utils.CreateImportPathUI(group, proxy.Window.Item as BinaryAssetItem); - layout.Space(5); - var reimportButton = group.Button("Reimport"); + var reimportButton = importSettingsGroup.Button("Reimport"); reimportButton.Button.Clicked += () => ((ImportPropertiesProxyBase)Values[0]).Reimport(); } } diff --git a/Source/Editor/Windows/Assets/SpriteAtlasWindow.cs b/Source/Editor/Windows/Assets/SpriteAtlasWindow.cs index 44016e57a..94deb18c0 100644 --- a/Source/Editor/Windows/Assets/SpriteAtlasWindow.cs +++ b/Source/Editor/Windows/Assets/SpriteAtlasWindow.cs @@ -119,9 +119,10 @@ namespace FlaxEditor.Windows.Assets } base.Initialize(layout); - + // Creates the import path UI - Utilities.Utils.CreateImportPathUI(layout, proxy._window.Item as BinaryAssetItem); + var group = layout.Group("Import Path"); + Utilities.Utils.CreateImportPathUI(group, proxy._window.Item as BinaryAssetItem); layout.Space(5); var reimportButton = layout.Button("Reimport"); diff --git a/Source/Editor/Windows/Assets/TextureWindow.cs b/Source/Editor/Windows/Assets/TextureWindow.cs index 06c6120ad..865099aea 100644 --- a/Source/Editor/Windows/Assets/TextureWindow.cs +++ b/Source/Editor/Windows/Assets/TextureWindow.cs @@ -143,7 +143,8 @@ namespace FlaxEditor.Windows.Assets base.Initialize(layout); // Creates the import path UI - Utilities.Utils.CreateImportPathUI(layout, proxy._window.Item as BinaryAssetItem); + var group = layout.Group("Import Path"); + Utilities.Utils.CreateImportPathUI(group, proxy._window.Item as BinaryAssetItem); // Reimport layout.Space(5); From b1b36ea1a3b729c888ef8d31e53d6360a5039fce Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Thu, 1 May 2025 22:29:37 +0200 Subject: [PATCH 20/77] move rigidbody info to dedicated info group in Properties Panel --- Source/Editor/CustomEditors/Dedicated/RigidBodyEditor.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Editor/CustomEditors/Dedicated/RigidBodyEditor.cs b/Source/Editor/CustomEditors/Dedicated/RigidBodyEditor.cs index 6537c0c59..31a429dd1 100644 --- a/Source/Editor/CustomEditors/Dedicated/RigidBodyEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/RigidBodyEditor.cs @@ -93,7 +93,8 @@ namespace FlaxEditor.CustomEditors.Dedicated // Add info box if (IsSingleObject && Values[0] is RigidBody && Editor.IsPlayMode) { - _infoLabel = layout.Label(string.Empty).Label; + var group = layout.Group("Info"); + _infoLabel = group.Label(string.Empty).Label; _infoLabel.AutoHeight = true; } } From b0048d6540f923b431e0f1145c4293292fd6aa4a Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Thu, 1 May 2025 22:32:28 +0200 Subject: [PATCH 21/77] add margin around info label --- Source/Editor/CustomEditors/Dedicated/RigidBodyEditor.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Editor/CustomEditors/Dedicated/RigidBodyEditor.cs b/Source/Editor/CustomEditors/Dedicated/RigidBodyEditor.cs index 31a429dd1..53dade508 100644 --- a/Source/Editor/CustomEditors/Dedicated/RigidBodyEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/RigidBodyEditor.cs @@ -1,6 +1,7 @@ // Copyright (c) Wojciech Figat. All rights reserved. using System.Collections.Generic; +using System.Reflection.Emit; using FlaxEditor.CustomEditors.GUI; using FlaxEngine; using FlaxEngine.GUI; @@ -96,6 +97,7 @@ namespace FlaxEditor.CustomEditors.Dedicated var group = layout.Group("Info"); _infoLabel = group.Label(string.Empty).Label; _infoLabel.AutoHeight = true; + _infoLabel.Margin = new Margin(3); } } } From 9a4d3a56a335f1fa90ed363ad0f1ceda964bc881 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Fri, 2 May 2025 13:30:49 +0300 Subject: [PATCH 22/77] Fix slow Tree expansion/collapsion with large amount of tree nodes --- Source/Editor/GUI/Tree/Tree.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Source/Editor/GUI/Tree/Tree.cs b/Source/Editor/GUI/Tree/Tree.cs index 02a9f47cb..e6add00cc 100644 --- a/Source/Editor/GUI/Tree/Tree.cs +++ b/Source/Editor/GUI/Tree/Tree.cs @@ -40,6 +40,7 @@ namespace FlaxEditor.GUI.Tree private readonly bool _supportMultiSelect; private Margin _margin; private bool _autoSize = true; + private bool _deferLayoutUpdate = false; /// /// The TreeNode that is being dragged over. This could have a value when not dragging. @@ -353,9 +354,25 @@ namespace FlaxEditor.GUI.Tree BulkSelectUpdateExpanded(false); } + /// + public override void PerformLayout(bool force = false) + { + if (_isLayoutLocked && !force) + return; + + // In case the tree was fully expanded or collapsed along its children, avoid calculating the layout multiple times for each child + _deferLayoutUpdate = true; + } + /// public override void Update(float deltaTime) { + if (_deferLayoutUpdate) + { + base.PerformLayout(); + _deferLayoutUpdate = false; + } + var node = SelectedNode; // Check if has focus and if any node is focused and it isn't a root From f5ad8566ebf22d48805cd643f29fe766d60a7121 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Fri, 2 May 2025 13:29:01 +0200 Subject: [PATCH 23/77] make path creation method more generalized --- Source/Editor/Utilities/Utils.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Source/Editor/Utilities/Utils.cs b/Source/Editor/Utilities/Utils.cs index ad2ee87a2..7c7d3d2d2 100644 --- a/Source/Editor/Utilities/Utils.cs +++ b/Source/Editor/Utilities/Utils.cs @@ -402,31 +402,31 @@ namespace FlaxEditor.Utilities /// /// Creates an Import path ui that show the asset import path and adds a button to show the folder in the file system. /// - /// The parent group element. + /// The parent layout element. /// The asset item to get the import path of. - public static void CreateImportPathUI(CustomEditors.Elements.GroupElement group, Content.BinaryAssetItem assetItem) + public static void CreateImportPathUI(CustomEditors.LayoutElementsContainer parentLayout, Content.BinaryAssetItem assetItem) { assetItem.GetImportPath(out var path); - CreateImportPathUI(group, path); + CreateImportPathUI(parentLayout, path); } /// /// Creates an Import path ui that show the import path and adds a button to show the folder in the file system. /// - /// The parent group element. + /// The parent layout element. /// The import path. /// Whether to use an initial layout space of 5 for separation. - public static void CreateImportPathUI(CustomEditors.Elements.GroupElement group, string path, bool useInitialSpacing = true) + public static void CreateImportPathUI(CustomEditors.LayoutElementsContainer parentLayout, string path, bool useInitialSpacing = true) { if (!string.IsNullOrEmpty(path)) { if (useInitialSpacing) - group.Space(0); - var textBox = group.TextBox().TextBox; + parentLayout.Space(0); + var textBox = parentLayout.TextBox().TextBox; textBox.TooltipText = "Source asset path. Can be relative or absolute to the project. Path is not editable here."; textBox.IsReadOnly = true; textBox.Text = path; - var button = group.Button(Constants.ShowInExplorer).Button; + var button = parentLayout.Button(Constants.ShowInExplorer).Button; button.Clicked += () => FileSystem.ShowFileExplorer(Path.GetDirectoryName(path)); } } From 2a5aed6c1500264be2ffc48bfd6952926c2ef595 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 2 May 2025 21:58:02 -0500 Subject: [PATCH 24/77] Fix trying to add scene to actor group. --- Source/Editor/Modules/SceneEditingModule.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Modules/SceneEditingModule.cs b/Source/Editor/Modules/SceneEditingModule.cs index 5c9d88f15..3c7130615 100644 --- a/Source/Editor/Modules/SceneEditingModule.cs +++ b/Source/Editor/Modules/SceneEditingModule.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using FlaxEditor.Actions; using FlaxEditor.SceneGraph; +using FlaxEditor.SceneGraph.Actors; using FlaxEngine; namespace FlaxEditor.Modules @@ -561,7 +562,8 @@ namespace FlaxEditor.Modules public void CreateParentForSelectedActors() { List selection = Editor.SceneEditing.Selection; - var actors = selection.Where(x => x is ActorNode).Select(x => ((ActorNode)x).Actor); + // Get Actors but skip scene node + var actors = selection.Where(x => x is ActorNode and not SceneNode).Select(x => ((ActorNode)x).Actor); var actorsCount = actors.Count(); if (actorsCount == 0) return; From dfe177447cf001fa9e19ae2d21a9a619665c67c7 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Sat, 3 May 2025 22:11:38 +0200 Subject: [PATCH 25/77] add auto selecting first item in item list context menu if no selection --- Source/Editor/GUI/ItemsListContextMenu.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Source/Editor/GUI/ItemsListContextMenu.cs b/Source/Editor/GUI/ItemsListContextMenu.cs index bf425a46b..82699e55c 100644 --- a/Source/Editor/GUI/ItemsListContextMenu.cs +++ b/Source/Editor/GUI/ItemsListContextMenu.cs @@ -611,6 +611,16 @@ namespace FlaxEditor.GUI OnClickItem(focusedItem); return true; } + else + { + // Select first item if no item is focused (most likely to be the best result), saves the user from pressing arrow down first + var visibleItems = GetVisibleItems(); + if (visibleItems.Count > 0) + { + OnClickItem(visibleItems[0]); + return true; + } + } break; } From 559d17e6c36db15a26f18271ad0312a09d1fc25f Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 4 May 2025 15:05:46 +0300 Subject: [PATCH 26/77] Reduce allocations in text rendering related functions --- Source/Engine/Render2D/Font.cpp | 8 ++++---- Source/Engine/Render2D/Font.h | 14 +++++++------- Source/Engine/Render2D/Render2D.cpp | 2 +- Source/Engine/UI/TextRender.cpp | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Source/Engine/Render2D/Font.cpp b/Source/Engine/Render2D/Font.cpp index 737cf7106..cf478abda 100644 --- a/Source/Engine/Render2D/Font.cpp +++ b/Source/Engine/Render2D/Font.cpp @@ -119,7 +119,7 @@ void Font::Invalidate() _characters.Clear(); } -void Font::ProcessText(const StringView& text, Array& outputLines, const TextLayoutOptions& layout) +void Font::ProcessText(const StringView& text, Array>& outputLines, const TextLayoutOptions& layout) { int32 textLength = text.Length(); if (textLength == 0) @@ -311,7 +311,7 @@ Float2 Font::MeasureText(const StringView& text, const TextLayoutOptions& layout return Float2::Zero; // Process text - Array lines; + Array> lines; ProcessText(text, lines, layout); // Calculate bounds @@ -332,7 +332,7 @@ int32 Font::HitTestText(const StringView& text, const Float2& location, const Te return 0; // Process text - Array lines; + Array> lines; ProcessText(text, lines, layout); ASSERT(lines.HasItems()); float scale = layout.Scale / FontManager::FontScale; @@ -417,7 +417,7 @@ Float2 Font::GetCharPosition(const StringView& text, int32 index, const TextLayo } // Process text - Array lines; + Array> lines; ProcessText(text, lines, layout); ASSERT(lines.HasItems()); float scale = layout.Scale / FontManager::FontScale; diff --git a/Source/Engine/Render2D/Font.h b/Source/Engine/Render2D/Font.h index 4f8e3a347..fc40cc16c 100644 --- a/Source/Engine/Render2D/Font.h +++ b/Source/Engine/Render2D/Font.h @@ -344,7 +344,7 @@ public: /// The input text. /// The layout properties. /// The output lines list. - void ProcessText(const StringView& text, Array& outputLines, API_PARAM(Ref) const TextLayoutOptions& layout); + void ProcessText(const StringView& text, Array>& outputLines, API_PARAM(Ref) const TextLayoutOptions& layout); /// /// Processes text to get cached lines for rendering. @@ -352,9 +352,9 @@ public: /// The input text. /// The layout properties. /// The output lines list. - API_FUNCTION() Array ProcessText(const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout) + API_FUNCTION() Array> ProcessText(const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout) { - Array lines; + Array> lines; ProcessText(text, lines, layout); return lines; } @@ -366,9 +366,9 @@ public: /// The input text range (substring range of the input text parameter). /// The layout properties. /// The output lines list. - API_FUNCTION() Array ProcessText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout) + API_FUNCTION() Array> ProcessText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout) { - Array lines; + Array> lines; ProcessText(textRange.Substring(text), lines, layout); return lines; } @@ -378,7 +378,7 @@ public: /// /// The input text. /// The output lines list. - API_FUNCTION() FORCE_INLINE Array ProcessText(const StringView& text) + API_FUNCTION() FORCE_INLINE Array> ProcessText(const StringView& text) { return ProcessText(text, TextLayoutOptions()); } @@ -389,7 +389,7 @@ public: /// The input text. /// The input text range (substring range of the input text parameter). /// The output lines list. - API_FUNCTION() FORCE_INLINE Array ProcessText(const StringView& text, API_PARAM(Ref) const TextRange& textRange) + API_FUNCTION() FORCE_INLINE Array> ProcessText(const StringView& text, API_PARAM(Ref) const TextRange& textRange) { return ProcessText(textRange.Substring(text), TextLayoutOptions()); } diff --git a/Source/Engine/Render2D/Render2D.cpp b/Source/Engine/Render2D/Render2D.cpp index 285428f7a..057265aae 100644 --- a/Source/Engine/Render2D/Render2D.cpp +++ b/Source/Engine/Render2D/Render2D.cpp @@ -194,7 +194,7 @@ namespace // Drawing Array DrawCalls; - Array Lines; + Array> Lines; Array Lines2; bool IsScissorsRectEmpty; bool IsScissorsRectEnabled; diff --git a/Source/Engine/UI/TextRender.cpp b/Source/Engine/UI/TextRender.cpp index 232354155..bc7b88647 100644 --- a/Source/Engine/UI/TextRender.cpp +++ b/Source/Engine/UI/TextRender.cpp @@ -176,7 +176,7 @@ void TextRender::UpdateLayout() int32 kerning; // Perform layout - Array lines; + Array> lines; font->ProcessText(text, lines, _layoutOptions); // Prepare buffers capacity From d8059c3db3c1851b1218e7c5284471b86b0b5300 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Sun, 4 May 2025 20:08:12 +0200 Subject: [PATCH 27/77] disable create file dialog create button if asset can't be created --- Source/Editor/Content/Create/CreateFileEntry.cs | 5 +++++ Source/Editor/Content/Create/CreateFilesDialog.cs | 8 +++++--- .../Editor/Content/Create/ParticleEmitterCreateEntry.cs | 3 +++ Source/Editor/Content/Create/PrefabCreateEntry.cs | 5 +++++ Source/Editor/Content/Create/SettingsCreateEntry.cs | 2 ++ Source/Editor/Content/Create/VisualScriptCreateEntry.cs | 3 +++ Source/Editor/Content/Proxy/JsonAssetProxy.cs | 3 +++ Source/Editor/Windows/Assets/CollisionDataWindow.cs | 2 ++ 8 files changed, 28 insertions(+), 3 deletions(-) diff --git a/Source/Editor/Content/Create/CreateFileEntry.cs b/Source/Editor/Content/Create/CreateFileEntry.cs index da2779b98..3346bd2ab 100644 --- a/Source/Editor/Content/Create/CreateFileEntry.cs +++ b/Source/Editor/Content/Create/CreateFileEntry.cs @@ -13,6 +13,11 @@ namespace FlaxEditor.Content.Create /// public string ResultUrl { get; } + /// + /// Gets or sets wether a file can be created based on the current settings. + /// + public abstract bool CanBeCreated { get; } + /// /// Gets a value indicating whether this entry has settings to modify. /// diff --git a/Source/Editor/Content/Create/CreateFilesDialog.cs b/Source/Editor/Content/Create/CreateFilesDialog.cs index ef5f2d58b..a49aac52a 100644 --- a/Source/Editor/Content/Create/CreateFilesDialog.cs +++ b/Source/Editor/Content/Create/CreateFilesDialog.cs @@ -60,7 +60,8 @@ namespace FlaxEditor.Content.Create Text = "Create", AnchorPreset = AnchorPresets.BottomRight, Offsets = new Margin(-ButtonsWidth - ButtonsMargin, ButtonsWidth, -ButtonsHeight - ButtonsMargin, ButtonsHeight), - Parent = this + Parent = this, + Enabled = entry.CanBeCreated, }; createButton.Clicked += OnSubmit; var cancelButton = new Button @@ -68,7 +69,7 @@ namespace FlaxEditor.Content.Create Text = "Cancel", AnchorPreset = AnchorPresets.BottomRight, Offsets = new Margin(-ButtonsWidth - ButtonsMargin - ButtonsWidth - ButtonsMargin, ButtonsWidth, -ButtonsHeight - ButtonsMargin, ButtonsHeight), - Parent = this + Parent = this, }; cancelButton.Clicked += OnCancel; @@ -77,7 +78,7 @@ namespace FlaxEditor.Content.Create { AnchorPreset = AnchorPresets.HorizontalStretchTop, Offsets = new Margin(2, 2, infoLabel.Bottom + 2, EditorHeight), - Parent = this + Parent = this, }; // Settings editor @@ -87,6 +88,7 @@ namespace FlaxEditor.Content.Create _dialogSize = new Float2(TotalWidth, panel.Bottom); _settingsEditor.Select(_entry.Settings); + _settingsEditor.Modified += () => createButton.Enabled = _entry.CanBeCreated; } /// diff --git a/Source/Editor/Content/Create/ParticleEmitterCreateEntry.cs b/Source/Editor/Content/Create/ParticleEmitterCreateEntry.cs index a862c3370..b64f7b1d0 100644 --- a/Source/Editor/Content/Create/ParticleEmitterCreateEntry.cs +++ b/Source/Editor/Content/Create/ParticleEmitterCreateEntry.cs @@ -12,6 +12,9 @@ namespace FlaxEditor.Content.Create /// public class ParticleEmitterCreateEntry : CreateFileEntry { + /// + public override bool CanBeCreated => true; + /// /// Types of the emitter templates that can be created. /// diff --git a/Source/Editor/Content/Create/PrefabCreateEntry.cs b/Source/Editor/Content/Create/PrefabCreateEntry.cs index db187e37f..2ddfccfde 100644 --- a/Source/Editor/Content/Create/PrefabCreateEntry.cs +++ b/Source/Editor/Content/Create/PrefabCreateEntry.cs @@ -14,6 +14,8 @@ namespace FlaxEditor.Content.Create /// public class PrefabCreateEntry : CreateFileEntry { + public override bool CanBeCreated => _options.RootActorType != null; + /// /// The create options. /// @@ -73,6 +75,9 @@ namespace FlaxEditor.Content.Create /// public class WidgetCreateEntry : CreateFileEntry { + /// + public override bool CanBeCreated => _options.RootControlType != null; + /// /// The create options. /// diff --git a/Source/Editor/Content/Create/SettingsCreateEntry.cs b/Source/Editor/Content/Create/SettingsCreateEntry.cs index fd43f43e0..bdeeeadf0 100644 --- a/Source/Editor/Content/Create/SettingsCreateEntry.cs +++ b/Source/Editor/Content/Create/SettingsCreateEntry.cs @@ -17,6 +17,8 @@ namespace FlaxEditor.Content.Create /// internal class SettingsCreateEntry : CreateFileEntry { + public override bool CanBeCreated => _options.Type != null; + internal class Options { [Tooltip("The settings type.")] diff --git a/Source/Editor/Content/Create/VisualScriptCreateEntry.cs b/Source/Editor/Content/Create/VisualScriptCreateEntry.cs index 768db6310..b74eb6ab2 100644 --- a/Source/Editor/Content/Create/VisualScriptCreateEntry.cs +++ b/Source/Editor/Content/Create/VisualScriptCreateEntry.cs @@ -11,6 +11,9 @@ namespace FlaxEditor.Content.Create /// public class VisualScriptCreateEntry : CreateFileEntry { + /// + public override bool CanBeCreated => _options.BaseClass != null; + /// /// The create options. /// diff --git a/Source/Editor/Content/Proxy/JsonAssetProxy.cs b/Source/Editor/Content/Proxy/JsonAssetProxy.cs index b71c044b5..2d5f20b47 100644 --- a/Source/Editor/Content/Proxy/JsonAssetProxy.cs +++ b/Source/Editor/Content/Proxy/JsonAssetProxy.cs @@ -65,6 +65,9 @@ namespace FlaxEditor.Content /// public class GenericJsonCreateEntry : CreateFileEntry { + /// + public override bool CanBeCreated => _options.Type != null; + /// /// The create options. /// diff --git a/Source/Editor/Windows/Assets/CollisionDataWindow.cs b/Source/Editor/Windows/Assets/CollisionDataWindow.cs index 5158f6046..3f265eea9 100644 --- a/Source/Editor/Windows/Assets/CollisionDataWindow.cs +++ b/Source/Editor/Windows/Assets/CollisionDataWindow.cs @@ -102,6 +102,8 @@ namespace FlaxEditor.Windows.Assets private class CookData : CreateFileEntry { + public override bool CanBeCreated => true; + public PropertiesProxy Proxy; public CollisionDataType Type; public ModelBase Model; From 388eb654a50c9a4d6748855235e89437683ce8fb Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Mon, 5 May 2025 09:58:36 +0200 Subject: [PATCH 28/77] update doc comment to reflect get only parameter --- Source/Editor/Content/Create/CreateFileEntry.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/Content/Create/CreateFileEntry.cs b/Source/Editor/Content/Create/CreateFileEntry.cs index 3346bd2ab..d2940b040 100644 --- a/Source/Editor/Content/Create/CreateFileEntry.cs +++ b/Source/Editor/Content/Create/CreateFileEntry.cs @@ -14,7 +14,7 @@ namespace FlaxEditor.Content.Create public string ResultUrl { get; } /// - /// Gets or sets wether a file can be created based on the current settings. + /// Gets a value indicating wether a file can be created based on the current settings. /// public abstract bool CanBeCreated { get; } From 08a86066d0096f63c7d513b81eb409ec00f9588f Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Mon, 5 May 2025 13:24:01 +0200 Subject: [PATCH 29/77] add window shortcuts --- Source/Editor/Modules/UIModule.cs | 24 +++---- Source/Editor/Options/InputOptions.cs | 92 ++++++++++++++++++++++++++- Source/Editor/Utilities/Utils.cs | 1 - Source/Editor/Windows/EditorWindow.cs | 68 ++++++++++++++++++++ 4 files changed, 170 insertions(+), 15 deletions(-) diff --git a/Source/Editor/Modules/UIModule.cs b/Source/Editor/Modules/UIModule.cs index da9eaf89a..19a0c1142 100644 --- a/Source/Editor/Modules/UIModule.cs +++ b/Source/Editor/Modules/UIModule.cs @@ -628,19 +628,19 @@ namespace FlaxEditor.Modules MenuWindow = MainMenu.AddButton("Window"); cm = MenuWindow.ContextMenu; cm.VisibleChanged += OnMenuWindowVisibleChanged; - cm.AddButton("Content", Editor.Windows.ContentWin.FocusOrShow); - cm.AddButton("Scene", Editor.Windows.SceneWin.FocusOrShow); - cm.AddButton("Toolbox", Editor.Windows.ToolboxWin.FocusOrShow); - cm.AddButton("Properties", Editor.Windows.PropertiesWin.FocusOrShow); - cm.AddButton("Game", Editor.Windows.GameWin.FocusOrShow); - cm.AddButton("Editor", Editor.Windows.EditWin.FocusOrShow); - cm.AddButton("Debug Log", Editor.Windows.DebugLogWin.FocusOrShow); - cm.AddButton("Output Log", Editor.Windows.OutputLogWin.FocusOrShow); - cm.AddButton("Graphics Quality", Editor.Windows.GraphicsQualityWin.FocusOrShow); - cm.AddButton("Game Cooker", Editor.Windows.GameCookerWin.FocusOrShow); + cm.AddButton("Content", inputOptions.ContentWindow,Editor.Windows.ContentWin.FocusOrShow); + cm.AddButton("Scene", inputOptions.SceneWindow, Editor.Windows.SceneWin.FocusOrShow); + cm.AddButton("Toolbox", inputOptions.ToolboxWindow, Editor.Windows.ToolboxWin.FocusOrShow); + cm.AddButton("Properties", inputOptions.PropertiesWindow, Editor.Windows.PropertiesWin.FocusOrShow); + cm.AddButton("Game", inputOptions.GameWindow, Editor.Windows.GameWin.FocusOrShow); + cm.AddButton("Editor", inputOptions.EditorWindow, Editor.Windows.EditWin.FocusOrShow); + cm.AddButton("Debug Log", inputOptions.DebugLogWindow, Editor.Windows.DebugLogWin.FocusOrShow); + cm.AddButton("Output Log", inputOptions.OutputLogWindow, Editor.Windows.OutputLogWin.FocusOrShow); + cm.AddButton("Graphics Quality", inputOptions.GraphicsQualityWindow, Editor.Windows.GraphicsQualityWin.FocusOrShow); + cm.AddButton("Game Cooker", inputOptions.GameCookerWindow, Editor.Windows.GameCookerWin.FocusOrShow); cm.AddButton("Profiler", inputOptions.ProfilerWindow, Editor.Windows.ProfilerWin.FocusOrShow); - cm.AddButton("Content Search", Editor.ContentFinding.ShowSearch); - cm.AddButton("Visual Script Debugger", Editor.Windows.VisualScriptDebuggerWin.FocusOrShow); + cm.AddButton("Content Search", inputOptions.ContentSearchWindow, Editor.ContentFinding.ShowSearch); + cm.AddButton("Visual Script Debugger", inputOptions.VisualScriptDebuggerWindow, Editor.Windows.VisualScriptDebuggerWin.FocusOrShow); cm.AddSeparator(); cm.AddButton("Save window layout", Editor.Windows.SaveLayout); _menuWindowApplyWindowLayout = cm.AddChildMenu("Window layouts"); diff --git a/Source/Editor/Options/InputOptions.cs b/Source/Editor/Options/InputOptions.cs index 5168e03d0..d6854352d 100644 --- a/Source/Editor/Options/InputOptions.cs +++ b/Source/Editor/Options/InputOptions.cs @@ -33,6 +33,25 @@ namespace FlaxEditor.Options OpenPrefab, } + /// + /// Play Mode shortcuts availability in play mode. + /// + public enum PlayModeShortcutAvailability + { + /// + /// None of the window shortcuts will be available in play mode. + /// + None, + /// + /// Only the profiler window shortcut will be available in play mode. + /// + ProfilerOnly, + /// + /// All window shortcuts will be available in play mode. + /// + All, + } + /// /// Input editor options data container. /// @@ -40,6 +59,16 @@ namespace FlaxEditor.Options [HideInEditor] public sealed class InputOptions { + /// + /// TODO. + /// + public static bool WindowShortcutsAvaliable => !Editor.IsPlayMode || Editor.Instance.Options.Options.Input.PlayModeWindowShortcutAvaliability == PlayModeShortcutAvailability.All; + + /// + /// TODO. + /// + public static bool ProfilerShortcutAvaliable => WindowShortcutsAvaliable || Editor.Instance.Options.Options.Input.PlayModeWindowShortcutAvaliability == PlayModeShortcutAvailability.ProfilerOnly; + #region Common [DefaultValue(typeof(InputBinding), "Ctrl+S")] @@ -230,9 +259,9 @@ namespace FlaxEditor.Options #region Profiler - [DefaultValue(typeof(InputBinding), "None")] + [DefaultValue(typeof(InputBinding), "Ctrl+Alpha7")] [EditorDisplay("Profiler", "Open Profiler Window"), EditorOrder(630)] - public InputBinding ProfilerWindow = new InputBinding(KeyboardKeys.None); + public InputBinding ProfilerWindow = new InputBinding(KeyboardKeys.Alpha7, KeyboardKeys.Control); [DefaultValue(typeof(InputBinding), "None")] [EditorDisplay("Profiler", "Start/Stop Profiler"), EditorOrder(631)] @@ -375,5 +404,64 @@ namespace FlaxEditor.Options public SceneNodeDoubleClick DoubleClickSceneNode = SceneNodeDoubleClick.Expand; #endregion + + #region Windows + + /// + /// Gets or sets a value indicating what window shortcuts will be available during play mode. + /// + [DefaultValue(PlayModeShortcutAvailability.ProfilerOnly)] + [EditorDisplay("Windows", "Avaliability in Play Mode"), EditorOrder(3000)] + public PlayModeShortcutAvailability PlayModeWindowShortcutAvaliability { get; set; } = PlayModeShortcutAvailability.ProfilerOnly; + + [DefaultValue(typeof(InputBinding), "Ctrl+Alpha5")] + [EditorDisplay("Windows"), EditorOrder(3010)] + public InputBinding ContentWindow = new InputBinding(KeyboardKeys.Alpha5, KeyboardKeys.Control); + + [DefaultValue(typeof(InputBinding), "Ctrl+Alpha4")] + [EditorDisplay("Windows"), EditorOrder(3020)] + public InputBinding SceneWindow = new InputBinding(KeyboardKeys.Alpha4, KeyboardKeys.Control); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Windows"), EditorOrder(3030)] + public InputBinding ToolboxWindow = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "Ctrl+Alpha3")] + [EditorDisplay("Windows"), EditorOrder(3040)] + public InputBinding PropertiesWindow = new InputBinding(KeyboardKeys.Alpha3, KeyboardKeys.Control); + + [DefaultValue(typeof(InputBinding), "Ctrl+Alpha2")] + [EditorDisplay("Windows"), EditorOrder(3050)] + public InputBinding GameWindow = new InputBinding(KeyboardKeys.Alpha2, KeyboardKeys.Control); + + [DefaultValue(typeof(InputBinding), "Ctrl+Alpha1")] + [EditorDisplay("Windows"), EditorOrder(3060)] + public InputBinding EditorWindow = new InputBinding(KeyboardKeys.Alpha1, KeyboardKeys.Control); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Windows"), EditorOrder(3070)] + public InputBinding DebugLogWindow = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Windows"), EditorOrder(3080)] + public InputBinding OutputLogWindow = new InputBinding(KeyboardKeys.C, KeyboardKeys.Control, KeyboardKeys.Shift); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Windows"), EditorOrder(3090)] + public InputBinding GraphicsQualityWindow = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Windows"), EditorOrder(4000)] + public InputBinding GameCookerWindow = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Windows"), EditorOrder(4010)] + public InputBinding ContentSearchWindow = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Windows"), EditorOrder(4020)] + public InputBinding VisualScriptDebuggerWindow = new InputBinding(KeyboardKeys.None); + + #endregion } } diff --git a/Source/Editor/Utilities/Utils.cs b/Source/Editor/Utilities/Utils.cs index b4666b213..26769b826 100644 --- a/Source/Editor/Utilities/Utils.cs +++ b/Source/Editor/Utilities/Utils.cs @@ -1505,7 +1505,6 @@ namespace FlaxEditor.Utilities inputActions.Add(options => options.BuildNav, Editor.Instance.BuildNavMesh); inputActions.Add(options => options.BuildSDF, Editor.Instance.BuildAllMeshesSDF); inputActions.Add(options => options.TakeScreenshot, Editor.Instance.Windows.TakeScreenshot); - inputActions.Add(options => options.ProfilerWindow, () => Editor.Instance.Windows.ProfilerWin.FocusOrShow()); #if USE_PROFILER inputActions.Add(options => options.ProfilerStartStop, () => { diff --git a/Source/Editor/Windows/EditorWindow.cs b/Source/Editor/Windows/EditorWindow.cs index f96ab0a78..f61f5cce6 100644 --- a/Source/Editor/Windows/EditorWindow.cs +++ b/Source/Editor/Windows/EditorWindow.cs @@ -2,6 +2,7 @@ using System; using FlaxEditor.Content; +using FlaxEditor.Options; using FlaxEngine; using FlaxEngine.GUI; using DockWindow = FlaxEditor.GUI.Docking.DockWindow; @@ -49,6 +50,73 @@ namespace FlaxEditor.Windows } }); + // Set up editor window shortcuts + InputActions.Add(options => options.ContentWindow, () => + { + if (InputOptions.WindowShortcutsAvaliable) + Editor.Windows.ContentWin.FocusOrShow(); + }); + InputActions.Add(options => options.SceneWindow, () => + { + if (InputOptions.WindowShortcutsAvaliable) + Editor.Windows.SceneWin.FocusOrShow(); + }); + InputActions.Add(options => options.ToolboxWindow, () => + { + if (InputOptions.WindowShortcutsAvaliable) + Editor.Windows.ToolboxWin.FocusOrShow(); + }); + InputActions.Add(options => options.PropertiesWindow, () => + { + if (InputOptions.WindowShortcutsAvaliable) + Editor.Windows.PropertiesWin.FocusOrShow(); + }); + InputActions.Add(options => options.GameWindow, () => + { + if (InputOptions.WindowShortcutsAvaliable) + Editor.Windows.GameWin.FocusOrShow(); + }); + InputActions.Add(options => options.EditorWindow, () => + { + if (InputOptions.WindowShortcutsAvaliable) + Editor.Windows.EditWin.FocusOrShow(); + }); + InputActions.Add(options => options.DebugLogWindow, () => + { + if (InputOptions.WindowShortcutsAvaliable) + Editor.Windows.DebugLogWin.FocusOrShow(); + }); + InputActions.Add(options => options.OutputLogWindow, () => + { + if (InputOptions.WindowShortcutsAvaliable) + Editor.Windows.OutputLogWin.FocusOrShow(); + }); + InputActions.Add(options => options.GraphicsQualityWindow, () => + { + if (InputOptions.WindowShortcutsAvaliable) + Editor.Windows.GraphicsQualityWin.FocusOrShow(); + }); + InputActions.Add(options => options.GameCookerWindow, () => + { + if (InputOptions.WindowShortcutsAvaliable) + Editor.Windows.GameCookerWin.FocusOrShow(); + }); + InputActions.Add(options => options.ProfilerWindow, () => + { + if (InputOptions.ProfilerShortcutAvaliable) + Editor.Windows.ProfilerWin.FocusOrShow(); + }); + InputActions.Add(options => options.ContentFinder, () => + { + if (InputOptions.WindowShortcutsAvaliable) + Editor.ContentFinding.ShowSearch(); + }); + InputActions.Add(options => options.VisualScriptDebuggerWindow, () => + { + if (InputOptions.WindowShortcutsAvaliable) + Editor.Windows.VisualScriptDebuggerWin.FocusOrShow(); + }); + // Register Editor.Windows.OnWindowAdd(this); } From 5b618b4f310450fddfac135857fdbf5d7c151939 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Mon, 5 May 2025 13:24:21 +0200 Subject: [PATCH 30/77] add icons to more commonly used editor windows --- Source/Editor/Windows/EditGameWindow.cs | 1 + Source/Editor/Windows/GameWindow.cs | 1 + Source/Editor/Windows/OutputLogWindow.cs | 1 + Source/Editor/Windows/PropertiesWindow.cs | 1 + Source/Editor/Windows/SceneTreeWindow.cs | 1 + Source/Editor/Windows/ToolboxWindow.cs | 1 + 6 files changed, 6 insertions(+) diff --git a/Source/Editor/Windows/EditGameWindow.cs b/Source/Editor/Windows/EditGameWindow.cs index 3600acbee..888dd4250 100644 --- a/Source/Editor/Windows/EditGameWindow.cs +++ b/Source/Editor/Windows/EditGameWindow.cs @@ -140,6 +140,7 @@ namespace FlaxEditor.Windows : base(editor, true, ScrollBars.None) { Title = "Editor"; + Icon = editor.Icons.Grid32; // Create viewport Viewport = new MainEditorGizmoViewport(editor) diff --git a/Source/Editor/Windows/GameWindow.cs b/Source/Editor/Windows/GameWindow.cs index f738a7a8c..4db3bcf0f 100644 --- a/Source/Editor/Windows/GameWindow.cs +++ b/Source/Editor/Windows/GameWindow.cs @@ -305,6 +305,7 @@ namespace FlaxEditor.Windows : base(editor, true, ScrollBars.None) { Title = "Game"; + Icon = editor.Icons.Play64; AutoFocus = true; var task = MainRenderTask.Instance; diff --git a/Source/Editor/Windows/OutputLogWindow.cs b/Source/Editor/Windows/OutputLogWindow.cs index b087947dc..cba0ba8d9 100644 --- a/Source/Editor/Windows/OutputLogWindow.cs +++ b/Source/Editor/Windows/OutputLogWindow.cs @@ -482,6 +482,7 @@ namespace FlaxEditor.Windows : base(editor, true, ScrollBars.None) { Title = "Output Log"; + Icon = editor.Icons.Info64; ClipChildren = false; FlaxEditor.Utilities.Utils.SetupCommonInputActions(this); diff --git a/Source/Editor/Windows/PropertiesWindow.cs b/Source/Editor/Windows/PropertiesWindow.cs index 87474fc3a..5ca2d3f53 100644 --- a/Source/Editor/Windows/PropertiesWindow.cs +++ b/Source/Editor/Windows/PropertiesWindow.cs @@ -66,6 +66,7 @@ namespace FlaxEditor.Windows : base(editor, true, ScrollBars.Vertical) { Title = "Properties"; + Icon = editor.Icons.Build64; AutoFocus = true; Presenter = new CustomEditorPresenter(editor.Undo, null, this); diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs index e0c9e0068..8ab07e9c4 100644 --- a/Source/Editor/Windows/SceneTreeWindow.cs +++ b/Source/Editor/Windows/SceneTreeWindow.cs @@ -48,6 +48,7 @@ namespace FlaxEditor.Windows : base(editor, true, ScrollBars.None) { Title = "Scene"; + Icon = editor.Icons.Globe32; // Scene searching query input box var headerPanel = new ContainerControl diff --git a/Source/Editor/Windows/ToolboxWindow.cs b/Source/Editor/Windows/ToolboxWindow.cs index 81f7b94d4..3c9c605a4 100644 --- a/Source/Editor/Windows/ToolboxWindow.cs +++ b/Source/Editor/Windows/ToolboxWindow.cs @@ -455,6 +455,7 @@ namespace FlaxEditor.Windows : base(editor, true, ScrollBars.None) { Title = "Toolbox"; + Icon = editor.Icons.Toolbox96; FlaxEditor.Utilities.Utils.SetupCommonInputActions(this); } From 87787cb5bf8fa00df232189b96b071eeeb0ad1a2 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Mon, 5 May 2025 15:15:32 +0200 Subject: [PATCH 31/77] replace Todo doc comments --- Source/Editor/Options/InputOptions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Editor/Options/InputOptions.cs b/Source/Editor/Options/InputOptions.cs index d6854352d..18025633b 100644 --- a/Source/Editor/Options/InputOptions.cs +++ b/Source/Editor/Options/InputOptions.cs @@ -60,12 +60,12 @@ namespace FlaxEditor.Options public sealed class InputOptions { /// - /// TODO. + /// Gets a value based on the current settings that indicates wether window shortcuts will be avaliable during play mode. /// public static bool WindowShortcutsAvaliable => !Editor.IsPlayMode || Editor.Instance.Options.Options.Input.PlayModeWindowShortcutAvaliability == PlayModeShortcutAvailability.All; /// - /// TODO. + /// Gets a value based on the current settings that indicates wether the profiler window shortcut will be avaliable during play mode. /// public static bool ProfilerShortcutAvaliable => WindowShortcutsAvaliable || Editor.Instance.Options.Options.Input.PlayModeWindowShortcutAvaliability == PlayModeShortcutAvailability.ProfilerOnly; From 6be193bfbf2425115fcc5386c4d88f372bb09a41 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Fri, 9 May 2025 11:39:40 +0200 Subject: [PATCH 32/77] fix tooltip --- Source/Editor/Options/InputOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/Options/InputOptions.cs b/Source/Editor/Options/InputOptions.cs index 18025633b..2a173d49c 100644 --- a/Source/Editor/Options/InputOptions.cs +++ b/Source/Editor/Options/InputOptions.cs @@ -34,7 +34,7 @@ namespace FlaxEditor.Options } /// - /// Play Mode shortcuts availability in play mode. + /// Shortcut availability in play mode. /// public enum PlayModeShortcutAvailability { From 8ce4d94a96662989671305105a0421cb665379cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20=C5=BBurawik?= Date: Fri, 9 May 2025 17:04:41 +0200 Subject: [PATCH 33/77] Refactor .NET version detection error reporting --- .../Flax.Build/Build/DotNet/DotNetSdk.cs | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs index aff928ad2..bf3c61f7e 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs @@ -283,8 +283,10 @@ namespace Flax.Build Log.Verbose($"Found the following .NET SDK versions: {string.Join(", ", dotnetSdkVersions)}"); Log.Verbose($"Found the following .NET runtime versions: {string.Join(", ", dotnetRuntimeVersions)}"); + string configuredDotnetVersion = Configuration.Dotnet; var dotnetSdkVersion = GetVersion(dotnetSdkVersions); var dotnetRuntimeVersion = GetVersion(dotnetRuntimeVersions); + if (!string.IsNullOrEmpty(dotnetSdkVersion) && !string.IsNullOrEmpty(dotnetRuntimeVersion) && ParseVersion(dotnetRuntimeVersion).Major > ParseVersion(dotnetSdkVersion).Major) { // Make sure the reference assemblies are not newer than the SDK itself @@ -296,21 +298,24 @@ namespace Flax.Build } while (!string.IsNullOrEmpty(dotnetRuntimeVersion) && ParseVersion(dotnetRuntimeVersion).Major > ParseVersion(dotnetSdkVersion).Major); } - var minVer = string.IsNullOrEmpty(Configuration.Dotnet) ? MinimumVersion.ToString() : Configuration.Dotnet; if (string.IsNullOrEmpty(dotnetSdkVersion)) { - if (dotnetSdkVersions.Any()) - Log.Warning($"Unsupported .NET SDK versions found: {string.Join(", ", dotnetSdkVersions)}. Minimum version required is .NET {minVer}."); - else - Log.Warning($"Missing .NET SDK. Minimum version required is .NET {minVer}."); + string installedVersionsText = dotnetSdkVersions.Any() + ? $"{string.Join(", ", dotnetSdkVersions)}" + : "None"; + Log.Warning(!string.IsNullOrEmpty(configuredDotnetVersion) + ? $"Configured .NET SDK '{configuredDotnetVersion}' not found. Installed versions: {installedVersionsText}." + : $"No compatible .NET SDK found within the supported range: .NET {MinimumVersion.ToString()} - {MaximumVersion.ToString()}. Installed versions: {installedVersionsText}."); return; } if (string.IsNullOrEmpty(dotnetRuntimeVersion)) { - if (dotnetRuntimeVersions.Any()) - Log.Warning($"Unsupported .NET runtime versions found: {string.Join(", ", dotnetRuntimeVersions)}. Minimum version required is .NET {minVer}."); - else - Log.Warning($"Missing .NET runtime. Minimum version required is .NET {minVer}."); + string installedRuntimeVersionsText = dotnetRuntimeVersions.Any() + ? $"{string.Join(", ", dotnetRuntimeVersions)}" + : "None"; + Log.Warning(!string.IsNullOrEmpty(configuredDotnetVersion) + ? $"Configured .NET runtime version '{configuredDotnetVersion}' not found. Installed versions: {installedRuntimeVersionsText}." + : $"No compatible .NET runtime found within the supported range: .NET {MinimumVersion.ToString()} - {MaximumVersion.ToString()}. Installed versions: {installedRuntimeVersionsText}."); return; } RootPath = dotnetPath; From 943864004fcc19d416b6f654a0eb72b76dff8fc5 Mon Sep 17 00:00:00 2001 From: alsed Date: Fri, 9 May 2025 15:17:20 -0400 Subject: [PATCH 34/77] Update README.md removed spirv-tools, since Flax build it during compilation. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 67e955c43..32b8bc42c 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,8 @@ Follow the instructions below to compile and run the engine from source. * Arch: `sudo pacman -S dotnet-sdk-8.0 dotnet-runtime-8.0 dotnet-targeting-pack-8.0 dotnet-host` * Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/)) * Ubuntu: `sudo apt install vulkan-sdk` - * Fedora: `sudo dnf install vulkan-headers vulkan-tools vulkan-validation-layers spirv-tools` - * Arch: `sudo pacman -S spirv-tools vulkan-headers vulkan-tools vulkan-validation-layers` + * Fedora: `sudo dnf install vulkan-headers vulkan-tools vulkan-validation-layers` + * Arch: `sudo pacman -S vulkan-headers vulkan-tools vulkan-validation-layers` * Install Git with LFS * Ubuntu: `sudo apt-get install git git-lfs` * Arch: `sudo pacman -S git git-lfs` From 212bd7a011aabb6c3c331a6caaae8353ee1570cf Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Mon, 12 May 2025 20:11:08 +0200 Subject: [PATCH 35/77] adjust width of terrain related nodes and node elements --- Source/Editor/Surface/Archetypes/Material.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/Material.cs b/Source/Editor/Surface/Archetypes/Material.cs index 831ce8d9a..37d6801a4 100644 --- a/Source/Editor/Surface/Archetypes/Material.cs +++ b/Source/Editor/Surface/Archetypes/Material.cs @@ -607,14 +607,14 @@ namespace FlaxEditor.Surface.Archetypes Title = "Terrain Layer Weight", Description = "Terrain layer weight mask used for blending terrain layers", Flags = NodeFlags.MaterialGraph, - Size = new Float2(220, 30), + Size = new Float2(200, 30), DefaultValues = new object[] { 0, }, Elements = new[] { - NodeElementArchetype.Factory.ComboBox(0, 0, 70.0f, 0, LayersAndTagsSettings.GetCurrentTerrainLayers()), + NodeElementArchetype.Factory.ComboBox(0, 0, 175.0f, 0, LayersAndTagsSettings.GetCurrentTerrainLayers()), NodeElementArchetype.Factory.Output(0, "", typeof(float), 0), } }, From fa4e56a32a2abfaaa6cce675807d524182caa080 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Mon, 12 May 2025 20:26:33 +0200 Subject: [PATCH 36/77] unify zoom behavior when zooming in and out --- Source/Editor/Surface/VisjectSurface.Input.cs | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/Source/Editor/Surface/VisjectSurface.Input.cs b/Source/Editor/Surface/VisjectSurface.Input.cs index e49bbc047..95610b73c 100644 --- a/Source/Editor/Surface/VisjectSurface.Input.cs +++ b/Source/Editor/Surface/VisjectSurface.Input.cs @@ -369,24 +369,14 @@ namespace FlaxEditor.Surface } // Change scale (disable scaling during selecting nodes) - if (IsMouseOver && !_leftMouseDown && !IsPrimaryMenuOpened) + if (IsMouseOver && !_leftMouseDown && !_rightMouseDown && !IsPrimaryMenuOpened) { var nextViewScale = ViewScale + delta * 0.1f; - if (delta > 0 && !_rightMouseDown) - { - // Scale towards mouse when zooming in - var nextCenterPosition = ViewPosition + location / ViewScale; - ViewScale = nextViewScale; - ViewPosition = nextCenterPosition - (location / ViewScale); - } - else - { - // Scale while keeping center position when zooming out or when dragging view - var viewCenter = ViewCenterPosition; - ViewScale = nextViewScale; - ViewCenterPosition = viewCenter; - } + // Scale towards/ away from mouse when zooming in/ out + var nextCenterPosition = ViewPosition + location / ViewScale; + ViewScale = nextViewScale; + ViewPosition = nextCenterPosition - (location / ViewScale); return true; } From 0b20a5342e819092acea94b5698123315b157a47 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Tue, 13 May 2025 16:00:16 +0200 Subject: [PATCH 37/77] add info on docs source being available to readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c4d6e7298..36c562006 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Flax Engine is a high quality modern 3D game engine written in C++ and C#. From stunning graphics to powerful scripts, it's designed for fast workflow with many ready-to-use features waiting for you right now. To learn more see the website ([www.flaxengine.com](https://flaxengine.com)). -This repository contains full source code of the Flax Engine (excluding NDA-protected platforms support). Anyone is welcome to contribute or use the modified source in Flax-based games. +This repository contains full source code of the Flax Engine (excluding NDA-protected platforms support). Documentation source is also available in a separate repository. Anyone is welcome to contribute or use the modified source in Flax-based games. # Development From 6be815820974f79bbd683f6b0723bb53ada0ec29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20=C5=BBurawik?= Date: Sun, 11 May 2025 14:34:31 +0200 Subject: [PATCH 38/77] Fix timeout calculation in Task::Wait --- Source/Engine/Threading/Task.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Engine/Threading/Task.cpp b/Source/Engine/Threading/Task.cpp index cd36619c9..601079e85 100644 --- a/Source/Engine/Threading/Task.cpp +++ b/Source/Engine/Threading/Task.cpp @@ -40,7 +40,7 @@ void Task::Cancel() bool Task::Wait(double timeoutMilliseconds) const { PROFILE_CPU(); - double startTime = Platform::GetTimeSeconds() * 0.001; + const double startTime = Platform::GetTimeSeconds(); // TODO: no active waiting! use a semaphore! @@ -54,7 +54,7 @@ bool Task::Wait(double timeoutMilliseconds) const // Wait for child if has if (_continueWith) { - auto spendTime = Platform::GetTimeSeconds() * 0.001 - startTime; + const auto spendTime = (Platform::GetTimeSeconds() - startTime) * 1000.0; return _continueWith->Wait(timeoutMilliseconds - spendTime); } @@ -66,7 +66,7 @@ bool Task::Wait(double timeoutMilliseconds) const return true; Platform::Sleep(1); - } while (timeoutMilliseconds <= 0.0 || Platform::GetTimeSeconds() * 0.001 - startTime < timeoutMilliseconds); + } while (timeoutMilliseconds <= 0.0 || (Platform::GetTimeSeconds() - startTime) * 1000.0 < timeoutMilliseconds); // Timeout reached! LOG(Warning, "\'{0}\' has timed out. Wait time: {1} ms", ToString(), timeoutMilliseconds); From 483a33996f68c227078a6d6531e18a87f6533795 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Thu, 15 May 2025 11:43:38 +0200 Subject: [PATCH 39/77] fix atan2 to use default box value --- Source/Engine/Visject/ShaderGraph.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Visject/ShaderGraph.cpp b/Source/Engine/Visject/ShaderGraph.cpp index 3ce197a18..ef4f53cf9 100644 --- a/Source/Engine/Visject/ShaderGraph.cpp +++ b/Source/Engine/Visject/ShaderGraph.cpp @@ -372,8 +372,8 @@ void ShaderGenerator::ProcessGroupMath(Box* box, Node* node, Value& value) // Atan2 case 41: { - Value v1 = tryGetValue(node->GetBox(0), Value::Zero); - Value v2 = tryGetValue(node->GetBox(1), Value::Zero); + Value v1 = tryGetValue(node->GetBox(0), 0, Value::Zero); + Value v2 = tryGetValue(node->GetBox(1), 1, Value::Zero); value = writeFunction2(node, v1, v2, TEXT("atan2")); break; } From c24ecaaab1adcc4168fde42626f5320c727c2bcb Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Thu, 15 May 2025 19:27:48 +0200 Subject: [PATCH 40/77] fix crammed color grading editor value boxes --- Source/Editor/CustomEditors/Editors/ColorTrackball.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/CustomEditors/Editors/ColorTrackball.cs b/Source/Editor/CustomEditors/Editors/ColorTrackball.cs index d0259102d..5e6010b95 100644 --- a/Source/Editor/CustomEditors/Editors/ColorTrackball.cs +++ b/Source/Editor/CustomEditors/Editors/ColorTrackball.cs @@ -27,7 +27,7 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - float trackBallSize = 80.0f; + float trackBallSize = 100f; float margin = 4.0f; // Panel From 8bb5655b2fe27174e7a9cb81e631e4553112cd7a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 16 May 2025 20:22:52 +0200 Subject: [PATCH 41/77] Fix error when using invalid camera ray --- Source/Engine/Level/Actors/Camera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Level/Actors/Camera.cpp b/Source/Engine/Level/Actors/Camera.cpp index 9851b21b0..ef8bd812a 100644 --- a/Source/Engine/Level/Actors/Camera.cpp +++ b/Source/Engine/Level/Actors/Camera.cpp @@ -239,7 +239,7 @@ Ray Camera::ConvertMouseToRay(const Float2& mousePosition, const Viewport& viewp viewport.Unproject(farPoint, ivp, farPoint); Vector3 dir = Vector3::Normalize(farPoint - nearPoint); - if (dir.IsZero()) + if (dir.IsZero() || dir.IsNanOrInfinity()) return Ray::Identity; return Ray(nearPoint, dir); } From ec2957bf386e3dce178cfd8c36ea2c9fc3dced94 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 16 May 2025 20:23:16 +0200 Subject: [PATCH 42/77] Fix memory leak on sequential mesh buffers update #3449 --- Source/Engine/Graphics/Models/MeshBase.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Engine/Graphics/Models/MeshBase.cpp b/Source/Engine/Graphics/Models/MeshBase.cpp index 315d01251..a5ce8b8d0 100644 --- a/Source/Engine/Graphics/Models/MeshBase.cpp +++ b/Source/Engine/Graphics/Models/MeshBase.cpp @@ -475,6 +475,12 @@ bool MeshBase::Init(uint32 vertices, uint32 triangles, const Array(vertices, triangles, (const Float3*)vbData[0], (const uint32*)ibData); #endif + // Free old buffers + SAFE_DELETE_GPU_RESOURCE(_vertexBuffers[0]); + SAFE_DELETE_GPU_RESOURCE(_vertexBuffers[2]); + SAFE_DELETE_GPU_RESOURCE(_vertexBuffers[3]); + SAFE_DELETE_GPU_RESOURCE(_indexBuffer); + // Initialize _vertexBuffers[0] = vertexBuffer0; _vertexBuffers[1] = vertexBuffer1; From 9ba1c4c33858ae5cc873e2b1f8e0ed345b3af23f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 16 May 2025 20:24:01 +0200 Subject: [PATCH 43/77] Fix typo in ec2957bf386e3dce178cfd8c36ea2c9fc3dced94 --- Source/Engine/Graphics/Models/MeshBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Graphics/Models/MeshBase.cpp b/Source/Engine/Graphics/Models/MeshBase.cpp index a5ce8b8d0..62e65ee61 100644 --- a/Source/Engine/Graphics/Models/MeshBase.cpp +++ b/Source/Engine/Graphics/Models/MeshBase.cpp @@ -477,8 +477,8 @@ bool MeshBase::Init(uint32 vertices, uint32 triangles, const Array Date: Sun, 18 May 2025 16:28:16 +0200 Subject: [PATCH 44/77] add shortcuts for viewflags and debug view modes --- Source/Editor/Options/InputOptions.cs | 192 ++++++++++++++++++++++- Source/Editor/Viewport/EditorViewport.cs | 153 ++++++++++++------ 2 files changed, 294 insertions(+), 51 deletions(-) diff --git a/Source/Editor/Options/InputOptions.cs b/Source/Editor/Options/InputOptions.cs index 5168e03d0..b3cc93326 100644 --- a/Source/Editor/Options/InputOptions.cs +++ b/Source/Editor/Options/InputOptions.cs @@ -356,22 +356,206 @@ namespace FlaxEditor.Options #endregion + #region Debug Views + + [DefaultValue(typeof(InputBinding), "Alt+Alpha4")] + [EditorDisplay("Debug Views"), EditorOrder(2000)] + public InputBinding Default = new InputBinding(KeyboardKeys.Alpha4, KeyboardKeys.Alt); + + [DefaultValue(typeof(InputBinding), "Alt+Alpha3")] + [EditorDisplay("Debug Views"), EditorOrder(2010)] + public InputBinding Unlit = new InputBinding(KeyboardKeys.Alpha3, KeyboardKeys.Alt); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Debug Views"), EditorOrder(2020)] + public InputBinding NoPostFX = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "Alt+Alpha2")] + [EditorDisplay("Debug Views"), EditorOrder(2030)] + public InputBinding Wireframe = new InputBinding(KeyboardKeys.Alpha2, KeyboardKeys.Alt); + + [DefaultValue(typeof(InputBinding), "Alt+Alpha5")] + [EditorDisplay("Debug Views"), EditorOrder(2040)] + public InputBinding LightBuffer = new InputBinding(KeyboardKeys.Alpha5, KeyboardKeys.Alt); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Debug Views"), EditorOrder(2050)] + public InputBinding ReflectionsBuffer = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Debug Views"), EditorOrder(2060)] + public InputBinding DepthBuffer = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Debug Views"), EditorOrder(2070)] + public InputBinding MotionVectors = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Debug Views"), EditorOrder(2080)] + public InputBinding LightmapUVDensity = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Debug Views"), EditorOrder(2090)] + public InputBinding VertexColors = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "Alt+Alpha1")] + [EditorDisplay("Debug Views"), EditorOrder(2100)] + public InputBinding PhysicsColliders = new InputBinding(KeyboardKeys.Alpha1, KeyboardKeys.Alt); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Debug Views"), EditorOrder(2110)] + public InputBinding LODPreview = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Debug Views"), EditorOrder(2120)] + public InputBinding MaterialComplexity = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Debug Views"), EditorOrder(2130)] + public InputBinding QuadOverdraw = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Debug Views"), EditorOrder(2140)] + public InputBinding GloablSDF = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Debug Views"), EditorOrder(2150)] + public InputBinding GlobalSurfaceAtlas = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Debug Views"), EditorOrder(2160)] + public InputBinding GlobalIllumination = new InputBinding(KeyboardKeys.None); + + #endregion + + #region View Flags + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3000)] + public InputBinding AntiAliasing = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3010)] + public InputBinding Shadows = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha7")] + [EditorDisplay("View Flags"), EditorOrder(3020)] + public InputBinding EditorSprites = new InputBinding(KeyboardKeys.Alpha7, KeyboardKeys.Control, KeyboardKeys.Shift); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3030)] + public InputBinding Reflections = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3040)] + public InputBinding ScreenSpaceReflections = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3050)] + public InputBinding AmbientOcclusion = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha6")] + [EditorDisplay("View Flags", "Global Illumination"), EditorOrder(3060)] + public InputBinding GlobalIlluminationViewFlag = new InputBinding(KeyboardKeys.Alpha6, KeyboardKeys.Control, KeyboardKeys.Shift); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3070)] + public InputBinding DirectionalLights = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3080)] + public InputBinding PointLights = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3090)] + public InputBinding SpotLights = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3100)] + public InputBinding SkyLights = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3110)] + public InputBinding Sky = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3120)] + public InputBinding Fog = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3130)] + public InputBinding SpecularLight = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3140)] + public InputBinding Decals = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha3")] + [EditorDisplay("View Flags"), EditorOrder(3150)] + public InputBinding CustomPostProcess = new InputBinding(KeyboardKeys.Alpha3, KeyboardKeys.Control, KeyboardKeys.Shift); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3160)] + public InputBinding Bloom = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3170)] + public InputBinding ToneMapping = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha2")] + [EditorDisplay("View Flags"), EditorOrder(3180)] + public InputBinding EyeAdaptation = new InputBinding(KeyboardKeys.Alpha2, KeyboardKeys.Control, KeyboardKeys.Shift); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3190)] + public InputBinding CameraArtifacts = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3200)] + public InputBinding LensFlares = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3210)] + public InputBinding DepthOfField = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3220)] + public InputBinding MotionBlur = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("View Flags"), EditorOrder(3230)] + public InputBinding ContactShadows = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha1")] + [EditorDisplay("View Flags"), EditorOrder(3240)] + public InputBinding PhysicsDebug = new InputBinding(KeyboardKeys.Alpha1, KeyboardKeys.Control, KeyboardKeys.Shift); + + [DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha5")] + [EditorDisplay("View Flags"), EditorOrder(3250)] + public InputBinding LightsDebug = new InputBinding(KeyboardKeys.Alpha5, KeyboardKeys.Control, KeyboardKeys.Shift); + + [DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha4")] + [EditorDisplay("View Flags"), EditorOrder(3260)] + public InputBinding DebugDraw = new InputBinding(KeyboardKeys.Alpha4, KeyboardKeys.Control, KeyboardKeys.Shift); + + #endregion + #region Interface [DefaultValue(typeof(InputBinding), "Ctrl+W")] - [EditorDisplay("Interface"), EditorOrder(2000)] + [EditorDisplay("Interface"), EditorOrder(3500)] public InputBinding CloseTab = new InputBinding(KeyboardKeys.W, KeyboardKeys.Control); [DefaultValue(typeof(InputBinding), "Ctrl+Tab")] - [EditorDisplay("Interface"), EditorOrder(2010)] + [EditorDisplay("Interface"), EditorOrder(3510)] public InputBinding NextTab = new InputBinding(KeyboardKeys.Tab, KeyboardKeys.Control); [DefaultValue(typeof(InputBinding), "Shift+Ctrl+Tab")] - [EditorDisplay("Interface"), EditorOrder(2020)] + [EditorDisplay("Interface"), EditorOrder(3520)] public InputBinding PreviousTab = new InputBinding(KeyboardKeys.Tab, KeyboardKeys.Control, KeyboardKeys.Shift); [DefaultValue(SceneNodeDoubleClick.Expand)] - [EditorDisplay("Interface"), EditorOrder(2030)] + [EditorDisplay("Interface"), EditorOrder(3530)] public SceneNodeDoubleClick DoubleClickSceneNode = SceneNodeDoubleClick.Expand; #endregion diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs index eaf243726..b2bf0f64e 100644 --- a/Source/Editor/Viewport/EditorViewport.cs +++ b/Source/Editor/Viewport/EditorViewport.cs @@ -910,7 +910,7 @@ namespace FlaxEditor.Viewport for (int i = 0; i < ViewFlagsValues.Length; i++) { var v = ViewFlagsValues[i]; - var button = viewFlags.AddButton(v.Name); + var button = viewFlags.AddButton(v.Name, v.InputBinding.ToString()); button.CloseMenuOnClick = false; button.Tag = v.Mode; } @@ -959,7 +959,7 @@ namespace FlaxEditor.Viewport } else { - var button = debugView.AddButton(v.Name); + var button = debugView.AddButton(v.Name, v.InputBinding.ToString()); button.CloseMenuOnClick = false; button.Tag = v.Mode; } @@ -1005,16 +1005,64 @@ namespace FlaxEditor.Viewport #endregion View mode widget } + // Viewpoints InputActions.Add(options => options.ViewpointTop, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Top").Orientation))); InputActions.Add(options => options.ViewpointBottom, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Bottom").Orientation))); InputActions.Add(options => options.ViewpointFront, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Front").Orientation))); InputActions.Add(options => options.ViewpointBack, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Back").Orientation))); InputActions.Add(options => options.ViewpointRight, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Right").Orientation))); InputActions.Add(options => options.ViewpointLeft, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Left").Orientation))); + // Editor camera InputActions.Add(options => options.CameraToggleRotation, () => _isVirtualMouseRightDown = !_isVirtualMouseRightDown); InputActions.Add(options => options.CameraIncreaseMoveSpeed, () => AdjustCameraMoveSpeed(1)); InputActions.Add(options => options.CameraDecreaseMoveSpeed, () => AdjustCameraMoveSpeed(-1)); InputActions.Add(options => options.ToggleOrthographic, () => OnOrthographicModeToggled(null)); + // Debug views + InputActions.Add(options => options.Default, () => Task.ViewMode = ViewMode.Default); + InputActions.Add(options => options.Unlit, () => Task.ViewMode = ViewMode.Unlit); + InputActions.Add(options => options.NoPostFX, () => Task.ViewMode = ViewMode.NoPostFx); + InputActions.Add(options => options.Wireframe, () => Task.ViewMode = ViewMode.Wireframe); + InputActions.Add(options => options.LightBuffer, () => Task.ViewMode = ViewMode.LightBuffer); + InputActions.Add(options => options.ReflectionsBuffer, () => Task.ViewMode = ViewMode.Reflections); + InputActions.Add(options => options.DepthBuffer, () => Task.ViewMode = ViewMode.Depth); + InputActions.Add(options => options.MotionVectors, () => Task.ViewMode = ViewMode.MotionVectors); + InputActions.Add(options => options.LightmapUVDensity, () => Task.ViewMode = ViewMode.LightmapUVsDensity); + InputActions.Add(options => options.VertexColors, () => Task.ViewMode = ViewMode.VertexColors); + InputActions.Add(options => options.PhysicsColliders, () => Task.ViewMode = ViewMode.PhysicsColliders); + InputActions.Add(options => options.LODPreview, () => Task.ViewMode = ViewMode.LODPreview); + InputActions.Add(options => options.MaterialComplexity, () => Task.ViewMode = ViewMode.MaterialComplexity); + InputActions.Add(options => options.QuadOverdraw, () => Task.ViewMode = ViewMode.QuadOverdraw); + InputActions.Add(options => options.GloablSDF, () => Task.ViewMode = ViewMode.GlobalSDF); + InputActions.Add(options => options.GlobalSurfaceAtlas, () => Task.ViewMode = ViewMode.GlobalSurfaceAtlas); + InputActions.Add(options => options.GlobalIllumination, () => Task.ViewMode = ViewMode.GlobalIllumination); + // View flags + InputActions.Add(options => options.AntiAliasing, () => Task.ViewFlags ^= ViewFlags.AntiAliasing); + InputActions.Add(options => options.Shadows, () => Task.ViewFlags ^= ViewFlags.Shadows); + InputActions.Add(options => options.EditorSprites, () => Task.ViewFlags ^= ViewFlags.EditorSprites); + InputActions.Add(options => options.Reflections, () => Task.ViewFlags ^= ViewFlags.Reflections); + InputActions.Add(options => options.ScreenSpaceReflections, () => Task.ViewFlags ^= ViewFlags.SSR); + InputActions.Add(options => options.AmbientOcclusion, () => Task.ViewFlags ^= ViewFlags.AO); + InputActions.Add(options => options.GlobalIllumination, () => Task.ViewFlags ^= ViewFlags.GI); + InputActions.Add(options => options.DirectionalLights, () => Task.ViewFlags ^= ViewFlags.DirectionalLights); + InputActions.Add(options => options.PointLights, () => Task.ViewFlags ^= ViewFlags.PointLights); + InputActions.Add(options => options.SpotLights, () => Task.ViewFlags ^= ViewFlags.SpotLights); + InputActions.Add(options => options.SkyLights, () => Task.ViewFlags ^= ViewFlags.SkyLights); + InputActions.Add(options => options.Sky, () => Task.ViewFlags ^= ViewFlags.Sky); + InputActions.Add(options => options.Fog, () => Task.ViewFlags ^= ViewFlags.Fog); + InputActions.Add(options => options.SpecularLight, () => Task.ViewFlags ^= ViewFlags.SpecularLight); + InputActions.Add(options => options.Decals, () => Task.ViewFlags ^= ViewFlags.Decals); + InputActions.Add(options => options.CustomPostProcess, () => Task.ViewFlags ^= ViewFlags.CustomPostProcess); + InputActions.Add(options => options.Bloom, () => Task.ViewFlags ^= ViewFlags.Bloom); + InputActions.Add(options => options.ToneMapping, () => Task.ViewFlags ^= ViewFlags.ToneMapping); + InputActions.Add(options => options.EyeAdaptation, () => Task.ViewFlags ^= ViewFlags.EyeAdaptation); + InputActions.Add(options => options.CameraArtifacts, () => Task.ViewFlags ^= ViewFlags.CameraArtifacts); + InputActions.Add(options => options.LensFlares, () => Task.ViewFlags ^= ViewFlags.LensFlares); + InputActions.Add(options => options.DepthOfField, () => Task.ViewFlags ^= ViewFlags.DepthOfField); + InputActions.Add(options => options.MotionBlur, () => Task.ViewFlags ^= ViewFlags.MotionBlur); + InputActions.Add(options => options.ContactShadows, () => Task.ViewFlags ^= ViewFlags.ContactShadows); + InputActions.Add(options => options.PhysicsDebug, () => Task.ViewFlags ^= ViewFlags.PhysicsDebug); + InputActions.Add(options => options.LightsDebug, () => Task.ViewFlags ^= ViewFlags.LightsDebug); + InputActions.Add(options => options.DebugDraw, () => Task.ViewFlags ^= ViewFlags.DebugDraw); // Link for task event task.Begin += OnRenderBegin; @@ -1933,8 +1981,17 @@ namespace FlaxEditor.Viewport { public readonly string Name; public readonly ViewMode Mode; + public readonly InputBinding InputBinding; public readonly ViewModeOptions[] Options; + public ViewModeOptions(ViewMode mode, string name, InputBinding inputBinding) + { + Mode = mode; + Name = name; + InputBinding = inputBinding; + Options = null; + } + public ViewModeOptions(ViewMode mode, string name) { Mode = mode; @@ -1952,13 +2009,13 @@ namespace FlaxEditor.Viewport private static readonly ViewModeOptions[] ViewModeValues = { - new ViewModeOptions(ViewMode.Default, "Default"), - new ViewModeOptions(ViewMode.Unlit, "Unlit"), - new ViewModeOptions(ViewMode.NoPostFx, "No PostFx"), - new ViewModeOptions(ViewMode.Wireframe, "Wireframe"), - new ViewModeOptions(ViewMode.LightBuffer, "Light Buffer"), - new ViewModeOptions(ViewMode.Reflections, "Reflections Buffer"), - new ViewModeOptions(ViewMode.Depth, "Depth Buffer"), + new ViewModeOptions(ViewMode.Default, "Default", Editor.Instance.Options.Options.Input.Default), + new ViewModeOptions(ViewMode.Unlit, "Unlit", Editor.Instance.Options.Options.Input.Unlit), + new ViewModeOptions(ViewMode.NoPostFx, "No PostFx", Editor.Instance.Options.Options.Input.NoPostFX), + new ViewModeOptions(ViewMode.Wireframe, "Wireframe", Editor.Instance.Options.Options.Input.Wireframe), + new ViewModeOptions(ViewMode.LightBuffer, "Light Buffer", Editor.Instance.Options.Options.Input.LightBuffer), + new ViewModeOptions(ViewMode.Reflections, "Reflections Buffer", Editor.Instance.Options.Options.Input.ReflectionsBuffer), + new ViewModeOptions(ViewMode.Depth, "Depth Buffer", Editor.Instance.Options.Options.Input.DepthBuffer), new ViewModeOptions("GBuffer", new[] { new ViewModeOptions(ViewMode.Diffuse, "Diffuse"), @@ -1972,16 +2029,16 @@ namespace FlaxEditor.Viewport new ViewModeOptions(ViewMode.Normals, "Normals"), new ViewModeOptions(ViewMode.AmbientOcclusion, "Ambient Occlusion"), }), - new ViewModeOptions(ViewMode.MotionVectors, "Motion Vectors"), - new ViewModeOptions(ViewMode.LightmapUVsDensity, "Lightmap UVs Density"), - new ViewModeOptions(ViewMode.VertexColors, "Vertex Colors"), - new ViewModeOptions(ViewMode.PhysicsColliders, "Physics Colliders"), - new ViewModeOptions(ViewMode.LODPreview, "LOD Preview"), - new ViewModeOptions(ViewMode.MaterialComplexity, "Material Complexity"), - new ViewModeOptions(ViewMode.QuadOverdraw, "Quad Overdraw"), - new ViewModeOptions(ViewMode.GlobalSDF, "Global SDF"), - new ViewModeOptions(ViewMode.GlobalSurfaceAtlas, "Global Surface Atlas"), - new ViewModeOptions(ViewMode.GlobalIllumination, "Global Illumination"), + new ViewModeOptions(ViewMode.MotionVectors, "Motion Vectors", Editor.Instance.Options.Options.Input.MotionVectors), + new ViewModeOptions(ViewMode.LightmapUVsDensity, "Lightmap UVs Density", Editor.Instance.Options.Options.Input.LightmapUVDensity), + new ViewModeOptions(ViewMode.VertexColors, "Vertex Colors", Editor.Instance.Options.Options.Input.VertexColors), + new ViewModeOptions(ViewMode.PhysicsColliders, "Physics Colliders", Editor.Instance.Options.Options.Input.PhysicsColliders), + new ViewModeOptions(ViewMode.LODPreview, "LOD Preview", Editor.Instance.Options.Options.Input.LODPreview), + new ViewModeOptions(ViewMode.MaterialComplexity, "Material Complexity", Editor.Instance.Options.Options.Input.MaterialComplexity), + new ViewModeOptions(ViewMode.QuadOverdraw, "Quad Overdraw", Editor.Instance.Options.Options.Input.QuadOverdraw), + new ViewModeOptions(ViewMode.GlobalSDF, "Global SDF", Editor.Instance.Options.Options.Input.GloablSDF), + new ViewModeOptions(ViewMode.GlobalSurfaceAtlas, "Global Surface Atlas", Editor.Instance.Options.Options.Input.GlobalSurfaceAtlas), + new ViewModeOptions(ViewMode.GlobalIllumination, "Global Illumination", Editor.Instance.Options.Options.Input.GlobalIllumination), }; private void WidgetViewModeShowHideClicked(ContextMenuButton button) @@ -2014,43 +2071,45 @@ namespace FlaxEditor.Viewport { public readonly ViewFlags Mode; public readonly string Name; + public readonly InputBinding InputBinding; - public ViewFlagOptions(ViewFlags mode, string name) + public ViewFlagOptions(ViewFlags mode, string name, InputBinding inputBinding) { Mode = mode; Name = name; + InputBinding = inputBinding; } } private static readonly ViewFlagOptions[] ViewFlagsValues = { - new ViewFlagOptions(ViewFlags.AntiAliasing, "Anti Aliasing"), - new ViewFlagOptions(ViewFlags.Shadows, "Shadows"), - new ViewFlagOptions(ViewFlags.EditorSprites, "Editor Sprites"), - new ViewFlagOptions(ViewFlags.Reflections, "Reflections"), - new ViewFlagOptions(ViewFlags.SSR, "Screen Space Reflections"), - new ViewFlagOptions(ViewFlags.AO, "Ambient Occlusion"), - new ViewFlagOptions(ViewFlags.GI, "Global Illumination"), - new ViewFlagOptions(ViewFlags.DirectionalLights, "Directional Lights"), - new ViewFlagOptions(ViewFlags.PointLights, "Point Lights"), - new ViewFlagOptions(ViewFlags.SpotLights, "Spot Lights"), - new ViewFlagOptions(ViewFlags.SkyLights, "Sky Lights"), - new ViewFlagOptions(ViewFlags.Sky, "Sky"), - new ViewFlagOptions(ViewFlags.Fog, "Fog"), - new ViewFlagOptions(ViewFlags.SpecularLight, "Specular Light"), - new ViewFlagOptions(ViewFlags.Decals, "Decals"), - new ViewFlagOptions(ViewFlags.CustomPostProcess, "Custom Post Process"), - new ViewFlagOptions(ViewFlags.Bloom, "Bloom"), - new ViewFlagOptions(ViewFlags.ToneMapping, "Tone Mapping"), - new ViewFlagOptions(ViewFlags.EyeAdaptation, "Eye Adaptation"), - new ViewFlagOptions(ViewFlags.CameraArtifacts, "Camera Artifacts"), - new ViewFlagOptions(ViewFlags.LensFlares, "Lens Flares"), - new ViewFlagOptions(ViewFlags.DepthOfField, "Depth of Field"), - new ViewFlagOptions(ViewFlags.MotionBlur, "Motion Blur"), - new ViewFlagOptions(ViewFlags.ContactShadows, "Contact Shadows"), - new ViewFlagOptions(ViewFlags.PhysicsDebug, "Physics Debug"), - new ViewFlagOptions(ViewFlags.LightsDebug, "Lights Debug"), - new ViewFlagOptions(ViewFlags.DebugDraw, "Debug Draw"), + new ViewFlagOptions(ViewFlags.AntiAliasing, "Anti Aliasing", Editor.Instance.Options.Options.Input.AntiAliasing), + new ViewFlagOptions(ViewFlags.Shadows, "Shadows", Editor.Instance.Options.Options.Input.Shadows), + new ViewFlagOptions(ViewFlags.EditorSprites, "Editor Sprites", Editor.Instance.Options.Options.Input.EditorSprites), + new ViewFlagOptions(ViewFlags.Reflections, "Reflections", Editor.Instance.Options.Options.Input.Reflections), + new ViewFlagOptions(ViewFlags.SSR, "Screen Space Reflections", Editor.Instance.Options.Options.Input.ScreenSpaceReflections), + new ViewFlagOptions(ViewFlags.AO, "Ambient Occlusion", Editor.Instance.Options.Options.Input.AmbientOcclusion), + new ViewFlagOptions(ViewFlags.GI, "Global Illumination", Editor.Instance.Options.Options.Input.GlobalIlluminationViewFlag), + new ViewFlagOptions(ViewFlags.DirectionalLights, "Directional Lights", Editor.Instance.Options.Options.Input.DirectionalLights), + new ViewFlagOptions(ViewFlags.PointLights, "Point Lights", Editor.Instance.Options.Options.Input.PointLights), + new ViewFlagOptions(ViewFlags.SpotLights, "Spot Lights", Editor.Instance.Options.Options.Input.SpotLights), + new ViewFlagOptions(ViewFlags.SkyLights, "Sky Lights", Editor.Instance.Options.Options.Input.SkyLights), + new ViewFlagOptions(ViewFlags.Sky, "Sky", Editor.Instance.Options.Options.Input.Sky), + new ViewFlagOptions(ViewFlags.Fog, "Fog", Editor.Instance.Options.Options.Input.Fog), + new ViewFlagOptions(ViewFlags.SpecularLight, "Specular Light", Editor.Instance.Options.Options.Input.SpecularLight), + new ViewFlagOptions(ViewFlags.Decals, "Decals", Editor.Instance.Options.Options.Input.Decals), + new ViewFlagOptions(ViewFlags.CustomPostProcess, "Custom Post Process", Editor.Instance.Options.Options.Input.CustomPostProcess), + new ViewFlagOptions(ViewFlags.Bloom, "Bloom", Editor.Instance.Options.Options.Input.Bloom), + new ViewFlagOptions(ViewFlags.ToneMapping, "Tone Mapping", Editor.Instance.Options.Options.Input.ToneMapping), + new ViewFlagOptions(ViewFlags.EyeAdaptation, "Eye Adaptation", Editor.Instance.Options.Options.Input.EyeAdaptation), + new ViewFlagOptions(ViewFlags.CameraArtifacts, "Camera Artifacts", Editor.Instance.Options.Options.Input.CameraArtifacts), + new ViewFlagOptions(ViewFlags.LensFlares, "Lens Flares", Editor.Instance.Options.Options.Input.LensFlares), + new ViewFlagOptions(ViewFlags.DepthOfField, "Depth of Field", Editor.Instance.Options.Options.Input.DepthOfField), + new ViewFlagOptions(ViewFlags.MotionBlur, "Motion Blur", Editor.Instance.Options.Options.Input.MotionBlur), + new ViewFlagOptions(ViewFlags.ContactShadows, "Contact Shadows", Editor.Instance.Options.Options.Input.ContactShadows), + new ViewFlagOptions(ViewFlags.PhysicsDebug, "Physics Debug", Editor.Instance.Options.Options.Input.PhysicsDebug), + new ViewFlagOptions(ViewFlags.LightsDebug, "Lights Debug", Editor.Instance.Options.Options.Input.LightsDebug), + new ViewFlagOptions(ViewFlags.DebugDraw, "Debug Draw", Editor.Instance.Options.Options.Input.DebugDraw), }; private void WidgetViewFlagsShowHide(Control cm) From 5b2a966ac6204cc8b401414bacc5a3737bc5c3c8 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 23 May 2025 10:37:30 -0500 Subject: [PATCH 45/77] Fix animation preview bounds scale. --- Source/Editor/Viewport/Previews/AnimatedModelPreview.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs index 995f510a9..a678e868a 100644 --- a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs +++ b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs @@ -185,7 +185,7 @@ namespace FlaxEditor.Viewport.Previews { UseTimeScale = false, UpdateWhenOffscreen = true, - BoundsScale = 100.0f, + BoundsScale = 1.0f, UpdateMode = AnimatedModel.AnimationUpdateMode.Manual, }; Task.AddCustomActor(_previewModel); From 436697601599bb3a3ba20ef4b918c38731819fb3 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 23 May 2025 13:27:01 -0500 Subject: [PATCH 46/77] Add better prefab diff viewing naming for actors --- .../CustomEditors/Dedicated/ActorEditor.cs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs index 062aeeedd..8c238c060 100644 --- a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs @@ -257,8 +257,17 @@ namespace FlaxEditor.CustomEditors.Dedicated // Actor or Script else if (editor.Values[0] is SceneObject sceneObject) { - node.TextColor = sceneObject.HasPrefabLink ? FlaxEngine.GUI.Style.Current.ProgressNormal : FlaxEngine.GUI.Style.Current.BackgroundSelected; - node.Text = Utilities.Utils.GetPropertyNameUI(sceneObject.GetType().Name); + if (editor.Values.Info != ScriptMemberInfo.Null) + { + if (editor.Values.GetAttributes().FirstOrDefault(x => x is EditorDisplayAttribute) is EditorDisplayAttribute editorDisplayAttribute && !string.IsNullOrEmpty(editorDisplayAttribute.Name)) + node.Text = $"{Utilities.Utils.GetPropertyNameUI(editorDisplayAttribute.Name)} ({Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name)})"; + else + node.Text = $"{Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name)}"; + } + else if (sceneObject is Actor actor) + node.Text = $"{actor.Name} ({Utilities.Utils.GetPropertyNameUI(sceneObject.GetType().Name)})"; + else + node.Text = Utilities.Utils.GetPropertyNameUI(sceneObject.GetType().Name); } // Array Item else if (editor.ParentEditor is CollectionEditor) @@ -268,7 +277,12 @@ namespace FlaxEditor.CustomEditors.Dedicated // Common type else if (editor.Values.Info != ScriptMemberInfo.Null) { - node.Text = Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name); + if (editor.Values.GetAttributes().FirstOrDefault(x => x is EditorDisplayAttribute) is EditorDisplayAttribute editorDisplayAttribute + && !string.IsNullOrEmpty(editorDisplayAttribute.Name) + && !editorDisplayAttribute.Name.Contains("_inline")) + node.Text = $"{Utilities.Utils.GetPropertyNameUI(editorDisplayAttribute.Name)} ({Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name)})"; + else + node.Text = Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name); } // Custom type else if (editor.Values[0] != null) From ae9622d271277a07c1c78c9e7519f54d02d0e7f8 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 23 May 2025 13:29:05 -0500 Subject: [PATCH 47/77] Re-add colors back in for nodes. --- Source/Editor/CustomEditors/Dedicated/ActorEditor.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs index 8c238c060..77619712f 100644 --- a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs @@ -257,6 +257,7 @@ namespace FlaxEditor.CustomEditors.Dedicated // Actor or Script else if (editor.Values[0] is SceneObject sceneObject) { + node.TextColor = sceneObject.HasPrefabLink ? FlaxEngine.GUI.Style.Current.ProgressNormal : FlaxEngine.GUI.Style.Current.BackgroundSelected; if (editor.Values.Info != ScriptMemberInfo.Null) { if (editor.Values.GetAttributes().FirstOrDefault(x => x is EditorDisplayAttribute) is EditorDisplayAttribute editorDisplayAttribute && !string.IsNullOrEmpty(editorDisplayAttribute.Name)) From 464929860530396920dee23e9a3f779c6143937c Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 23 May 2025 14:06:21 -0500 Subject: [PATCH 48/77] Dont allow setting prefab root name from scene instance. --- Source/Editor/CustomEditors/Dedicated/ActorEditor.cs | 2 +- Source/Editor/Modules/PrefabsModule.cs | 5 +++++ Source/Engine/Level/Prefabs/Prefab.Apply.cpp | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs index 062aeeedd..20acdf149 100644 --- a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs @@ -316,7 +316,7 @@ namespace FlaxEditor.CustomEditors.Dedicated var childEditor = editor.ChildrenEditors[i]; // Special case for root actor transformation (can be applied only in Prefab editor, not in Level) - if (isActorEditorInLevel && childEditor.Values.Info.Name is "LocalPosition" or "LocalOrientation" or "LocalScale") + if (isActorEditorInLevel && childEditor.Values.Info.Name is "LocalPosition" or "LocalOrientation" or "LocalScale" or "Name") continue; var child = ProcessDiff(childEditor, !isScriptEditorWithRefValue); diff --git a/Source/Editor/Modules/PrefabsModule.cs b/Source/Editor/Modules/PrefabsModule.cs index d1b254200..617202062 100644 --- a/Source/Editor/Modules/PrefabsModule.cs +++ b/Source/Editor/Modules/PrefabsModule.cs @@ -255,12 +255,17 @@ namespace FlaxEditor.Modules // When applying changes to prefab from actor in level ignore it's root transformation (see ActorEditor.ProcessDiff) var originalTransform = instance.LocalTransform; + var originalName = instance.Name; if (instance.IsPrefabRoot && instance.HasScene) + { instance.LocalTransform = prefab.GetDefaultInstance().Transform; + instance.Name = prefab.GetDefaultInstance().Name; + } // Call backend var failed = PrefabManager.Internal_ApplyAll(FlaxEngine.Object.GetUnmanagedPtr(instance)); instance.LocalTransform = originalTransform; + instance.Name = originalName; if (failed) throw new Exception("Failed to apply the prefab. See log to learn more."); diff --git a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp index 0df0723a2..4409ae161 100644 --- a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp +++ b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp @@ -1090,7 +1090,7 @@ bool Prefab::ApplyAllInternal(Actor* targetActor, bool linkTargetActorObjectToPr root = dynamic_cast(sceneObjects.Value->At(targetActorIdx)); } - // Try using the first actor without a parent as a new ro0t + // Try using the first actor without a parent as a new root for (int32 i = 1; i < sceneObjects->Count(); i++) { SceneObject* obj = sceneObjects.Value->At(i); From 21ae2d5d40337d5f263b19366552eb83e8dae2ef Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 23 May 2025 14:44:53 -0500 Subject: [PATCH 49/77] Focus Actor position if no Actor bounding box. --- Source/Editor/Editor.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index 394f907d9..c6ead7a76 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -1031,6 +1031,8 @@ namespace FlaxEditor { Internal_GetEditorBoxWithChildren(FlaxEngine.Object.GetUnmanagedPtr(actor), out var box); BoundingSphere.FromBox(ref box, out sphere); + if (sphere == BoundingSphere.Empty) + sphere = new BoundingSphere(actor.Position, sphere.Radius); sphere.Radius = Math.Max(sphere.Radius, 15.0f); } else From e606c35093272ec121fa518bb989d9c44ada11e2 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 23 May 2025 16:23:22 -0500 Subject: [PATCH 50/77] Add node tree to show changes to whole prefab. --- .../CustomEditors/Dedicated/ActorEditor.cs | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs index 77619712f..3830ef14a 100644 --- a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs @@ -376,20 +376,46 @@ namespace FlaxEditor.CustomEditors.Dedicated return result; } + private TreeNode CreateDiffTree(Actor actor, CustomEditorPresenter presenter, LayoutElementsContainer layout) + { + var actorNode = Editor.Instance.Scene.GetActorNode(actor); + ValueContainer vc = new ValueContainer(ScriptMemberInfo.Null); + vc.SetType(new ScriptType(actorNode.EditableObject.GetType())); + vc.Add(actorNode.EditableObject); + var editor = CustomEditorsUtil.CreateEditor(vc, null, false); + editor.Initialize(presenter, layout, vc); + var node = ProcessDiff(editor, false); + layout.ClearLayout(); + foreach (var child in actor.Children) + { + var childNode = CreateDiffTree(child, presenter, layout); + if (childNode == null) + continue; + if (node == null) + node = CreateDiffNode(editor); + node.AddChild(childNode); + } + return node; + } + private void ViewChanges(Control target, Float2 targetLocation) { // Build a tree out of modified properties - var rootNode = ProcessDiff(this, false); - + var thisActor = (Actor)Values[0]; + var rootActor = thisActor.IsPrefabRoot ? thisActor : thisActor.GetPrefabRoot(); + var presenter = new CustomEditorPresenter(null); + var layout = new CustomElementsContainer(); + var rootNode = CreateDiffTree(rootActor, presenter, layout); + // Skip if no changes detected - if (rootNode == null || rootNode.ChildrenCount == 0) + if (rootNode == null) { var cm1 = new ContextMenu(); cm1.AddButton("No changes detected"); cm1.Show(target, targetLocation); return; } - + // Create context menu var cm = new PrefabDiffContextMenu(); cm.Tree.AddChild(rootNode); From 545a43de323ed7f7484aae2ec85c866ebb97dc48 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 23 May 2025 16:50:55 -0500 Subject: [PATCH 51/77] Add drawing root tree lines except for in scene and prefab tree. --- Source/Editor/GUI/Tree/Tree.cs | 5 +++++ Source/Editor/GUI/Tree/TreeNode.cs | 4 ++-- Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs | 1 + Source/Editor/Windows/SceneTreeWindow.cs | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Source/Editor/GUI/Tree/Tree.cs b/Source/Editor/GUI/Tree/Tree.cs index 02a9f47cb..6cc050c0a 100644 --- a/Source/Editor/GUI/Tree/Tree.cs +++ b/Source/Editor/GUI/Tree/Tree.cs @@ -66,6 +66,11 @@ namespace FlaxEditor.GUI.Tree /// Gets the first selected node or null. /// public TreeNode SelectedNode => Selection.Count > 0 ? Selection[0] : null; + + /// + /// Allow nodes to Draw the root tree line. + /// + public bool DrawRootTreeLine = true; /// /// Gets or sets the margin for the child tree nodes. diff --git a/Source/Editor/GUI/Tree/TreeNode.cs b/Source/Editor/GUI/Tree/TreeNode.cs index eb7f345cf..bed32e797 100644 --- a/Source/Editor/GUI/Tree/TreeNode.cs +++ b/Source/Editor/GUI/Tree/TreeNode.cs @@ -762,7 +762,7 @@ namespace FlaxEditor.GUI.Tree { TreeNode parentNode = Parent as TreeNode; bool thisNodeIsLast = false; - while (parentNode != null && parentNode != ParentTree.Children[0]) + while (parentNode != null && (parentNode != ParentTree.Children[0] || _tree.DrawRootTreeLine)) { float bottomOffset = 0; float topOffset = 0; @@ -773,7 +773,7 @@ namespace FlaxEditor.GUI.Tree if (thisNodeIsLast && parentNode.Children.Count == 1) bottomOffset = topOffset != 0 ? 4 : 2; - if (Parent == parentNode && this == Parent.Children[Parent.Children.Count - 1] && !_opened) + if (Parent == parentNode && this == Parent.Children[^1] && !_opened) { thisNodeIsLast = true; bottomOffset = topOffset != 0 ? 4 : 2; diff --git a/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs b/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs index 95e6b7a46..24854afb9 100644 --- a/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs +++ b/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs @@ -56,6 +56,7 @@ namespace FlaxEditor.Windows.Assets public PrefabTree() : base(true) { + DrawRootTreeLine = false; } } diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs index e0c9e0068..605471ff4 100644 --- a/Source/Editor/Windows/SceneTreeWindow.cs +++ b/Source/Editor/Windows/SceneTreeWindow.cs @@ -84,6 +84,7 @@ namespace FlaxEditor.Windows { Margin = new Margin(0.0f, 0.0f, -16.0f, _sceneTreePanel.ScrollBarsSize), // Hide root node IsScrollable = true, + DrawRootTreeLine = false, }; _tree.AddChild(root.TreeNode); _tree.SelectedChanged += Tree_OnSelectedChanged; From 2e996c8e91ed2a4c389dc640f8c87fb02ed7f1c1 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 23 May 2025 17:11:45 -0500 Subject: [PATCH 52/77] Remove redundant call to scene. Fixes error in prefab node filtering. --- Source/Editor/SceneGraph/GUI/ActorTreeNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs b/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs index bf3f4b830..5f56e918a 100644 --- a/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs +++ b/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs @@ -320,7 +320,7 @@ namespace FlaxEditor.SceneGraph.GUI if (noFilter && actor != null) { // Pick the correct id when inside a prefab window. - var id = actor.HasPrefabLink && actor.Scene.Scene == null ? actor.PrefabObjectID : actor.ID; + var id = actor.HasPrefabLink && actor.Scene == null ? actor.PrefabObjectID : actor.ID; isExpanded = Editor.Instance.ProjectCache.IsExpandedActor(ref id); } From 9753e579c18e54253d4d62bf44eddb4b6330c53e Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 23 May 2025 18:16:48 -0500 Subject: [PATCH 53/77] Check for Game window before usage to avoid errors in trying to unplay. --- Source/Editor/Modules/SimulationModule.cs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Source/Editor/Modules/SimulationModule.cs b/Source/Editor/Modules/SimulationModule.cs index 4b0951b5f..fb1fb61d1 100644 --- a/Source/Editor/Modules/SimulationModule.cs +++ b/Source/Editor/Modules/SimulationModule.cs @@ -306,19 +306,21 @@ namespace FlaxEditor.Modules public override void OnPlayEnd() { var gameWin = Editor.Windows.GameWin; - - switch (gameWin.FocusOnPlayOption) + if (gameWin != null) { - case Options.InterfaceOptions.PlayModeFocus.None: break; - case Options.InterfaceOptions.PlayModeFocus.GameWindow: break; - case Options.InterfaceOptions.PlayModeFocus.GameWindowThenRestore: - if (_previousWindow != null && !_previousWindow.IsDisposing) + switch (gameWin.FocusOnPlayOption) { - if (!Editor.Windows.GameWin.ParentDockPanel.ContainsTab(_previousWindow)) - break; - _previousWindow.Focus(); + case Options.InterfaceOptions.PlayModeFocus.None: break; + case Options.InterfaceOptions.PlayModeFocus.GameWindow: break; + case Options.InterfaceOptions.PlayModeFocus.GameWindowThenRestore: + if (_previousWindow != null && !_previousWindow.IsDisposing) + { + if (!Editor.Windows.GameWin.ParentDockPanel.ContainsTab(_previousWindow)) + break; + _previousWindow.Focus(); + } + break; } - break; } Editor.UI.UncheckPauseButton(); From ae9ded504d94c393aaf5ab207b2b49dad7fcea7c Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 23 May 2025 23:21:45 -0500 Subject: [PATCH 54/77] Add utility for if in play mode that returns true for shipped applications. --- Source/Engine/Engine/Engine.cpp | 9 +++++++++ Source/Engine/Engine/Engine.h | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/Source/Engine/Engine/Engine.cpp b/Source/Engine/Engine/Engine.cpp index 385a05554..fba8b5f18 100644 --- a/Source/Engine/Engine/Engine.cpp +++ b/Source/Engine/Engine/Engine.cpp @@ -442,6 +442,15 @@ bool Engine::IsEditor() #endif } +bool Engine::IsPlayMode() +{ +#if USE_EDITOR + return Editor::IsPlayMode; +#else + return true; +#endif +} + int32 Engine::GetFramesPerSecond() { return EngineImpl::Fps; diff --git a/Source/Engine/Engine/Engine.h b/Source/Engine/Engine/Engine.h index e8b6fef2c..1af16a930 100644 --- a/Source/Engine/Engine/Engine.h +++ b/Source/Engine/Engine/Engine.h @@ -178,6 +178,11 @@ public: /// API_PROPERTY() static bool IsEditor(); + /// + /// Returns whether the editor is in play mode or will always return true in a shipped applications. + /// + API_PROPERTY() static bool IsPlayMode(); + /// /// Gets the amount of frames rendered during last second known as Frames Per Second. User scripts updates or fixed updates for physics may run at a different frequency than scene rendering. Use this property to get an accurate amount of frames rendered during the last second. /// From e00f552baf36baa76fb7177d5b8990116def8899 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 30 May 2025 00:39:20 +0200 Subject: [PATCH 55/77] Fix missing xml comment --- Source/Editor/Content/Create/PrefabCreateEntry.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Editor/Content/Create/PrefabCreateEntry.cs b/Source/Editor/Content/Create/PrefabCreateEntry.cs index 2ddfccfde..90cca263d 100644 --- a/Source/Editor/Content/Create/PrefabCreateEntry.cs +++ b/Source/Editor/Content/Create/PrefabCreateEntry.cs @@ -14,6 +14,7 @@ namespace FlaxEditor.Content.Create /// public class PrefabCreateEntry : CreateFileEntry { + /// public override bool CanBeCreated => _options.RootActorType != null; /// From 294dd3d363d8dd93823131b2eec7b9dc96127598 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 30 May 2025 00:42:55 +0200 Subject: [PATCH 56/77] Fix json guid parsing to check for correct hex characters #3476 --- Source/Engine/Serialization/JsonTools.cpp | 17 +++++++++-------- Source/Engine/Serialization/JsonTools.h | 8 ++++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Source/Engine/Serialization/JsonTools.cpp b/Source/Engine/Serialization/JsonTools.cpp index 25ce8ff5b..e60a424b8 100644 --- a/Source/Engine/Serialization/JsonTools.cpp +++ b/Source/Engine/Serialization/JsonTools.cpp @@ -28,13 +28,13 @@ void ChangeIds(rapidjson_flax::Value& obj, rapidjson_flax::Document& document, c else if (obj.IsString() && obj.GetStringLength() == 32) { auto value = JsonTools::GetGuid(obj); - if (mapping.TryGet(value, value)) + if (value.IsValid() && mapping.TryGet(value, value)) { // Unoptimized version: //obj.SetString(value.ToString(Guid::FormatType::N).ToSTD().c_str(), 32, document.GetAllocator()); // Optimized version: - char buffer[32] = + static char buffer[32] = { // @formatter:off '0','0','0','0','0','0','0','0','0','0', @@ -255,9 +255,8 @@ BoundingBox JsonTools::GetBoundingBox(const Value& value) Guid JsonTools::GetGuid(const Value& value) { - if (!value.IsString()) + if (!value.IsString() || value.GetStringLength() != 32) return Guid::Empty; - CHECK_RETURN(value.GetStringLength() == 32, Guid::Empty); // Split const char* a = value.GetString(); @@ -267,10 +266,12 @@ Guid JsonTools::GetGuid(const Value& value) // Parse Guid result; - StringUtils::ParseHex(a, 8, &result.A); - StringUtils::ParseHex(b, 8, &result.B); - StringUtils::ParseHex(c, 8, &result.C); - StringUtils::ParseHex(d, 8, &result.D); + bool failed = StringUtils::ParseHex(a, 8, &result.A); + failed |= StringUtils::ParseHex(b, 8, &result.B); + failed |= StringUtils::ParseHex(c, 8, &result.C); + failed |= StringUtils::ParseHex(d, 8, &result.D); + if (failed) + return Guid::Empty; return result; } diff --git a/Source/Engine/Serialization/JsonTools.h b/Source/Engine/Serialization/JsonTools.h index 0e1e3850f..0e807c784 100644 --- a/Source/Engine/Serialization/JsonTools.h +++ b/Source/Engine/Serialization/JsonTools.h @@ -214,7 +214,7 @@ public: const auto member = node.FindMember(name); if (member != node.MemberEnd() && member->value.IsInt()) { - result = member->value.GetInt(); + result = (byte)member->value.GetInt(); } } @@ -232,7 +232,7 @@ public: const auto member = node.FindMember(name); if (member != node.MemberEnd() && member->value.IsInt()) { - result = member->value.GetInt(); + result = (uint32)member->value.GetInt(); } } @@ -241,7 +241,7 @@ public: const auto member = node.FindMember(name); if (member != node.MemberEnd() && member->value.IsInt()) { - result = member->value.GetInt(); + result = (int16)member->value.GetInt(); } } @@ -250,7 +250,7 @@ public: const auto member = node.FindMember(name); if (member != node.MemberEnd() && member->value.IsInt()) { - result = member->value.GetInt(); + result = (uint16)member->value.GetInt(); } } From b58aaccc53c1754d097f4d0bce1f37ec02d9926e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 30 May 2025 00:46:09 +0200 Subject: [PATCH 57/77] Fix missing Physics Colliders view if Debug Draw is disabled #3498 --- Source/Engine/Renderer/Renderer.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index 26f3a636e..7fd12ba73 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -237,6 +237,12 @@ void Renderer::Render(SceneRenderTask* task) | ViewFlags::ContactShadows | ViewFlags::DepthOfField); } + + // Force Debug Draw usage in some specific views that depend on it + if (renderContext.View.Mode == ViewMode::PhysicsColliders) + { + renderContext.View.Flags |= ViewFlags::DebugDraw; + } #endif // Perform the actual rendering From b065e6c989f5102f3064993eb88e87bb06d0322e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 30 May 2025 11:15:47 +0200 Subject: [PATCH 58/77] Fix regression from 294dd3d363d8dd93823131b2eec7b9dc96127598 --- Source/Engine/Serialization/JsonTools.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Serialization/JsonTools.cpp b/Source/Engine/Serialization/JsonTools.cpp index e60a424b8..32d229a08 100644 --- a/Source/Engine/Serialization/JsonTools.cpp +++ b/Source/Engine/Serialization/JsonTools.cpp @@ -34,7 +34,7 @@ void ChangeIds(rapidjson_flax::Value& obj, rapidjson_flax::Document& document, c //obj.SetString(value.ToString(Guid::FormatType::N).ToSTD().c_str(), 32, document.GetAllocator()); // Optimized version: - static char buffer[32] = + char buffer[32] = { // @formatter:off '0','0','0','0','0','0','0','0','0','0', From 08ed5ae483a74a1177bd3911c5dac4494f6630b8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 30 May 2025 11:16:17 +0200 Subject: [PATCH 59/77] Add `SCOPE_EXIT` macro and use it in prefab tests to cleanup assets on test fail --- Source/Engine/Core/ScopeExit.h | 36 +++++++++++++++++++++++++++++ Source/Engine/Tests/TestMain.cpp | 4 ++-- Source/Engine/Tests/TestPrefabs.cpp | 27 +++++++++++----------- 3 files changed, 52 insertions(+), 15 deletions(-) create mode 100644 Source/Engine/Core/ScopeExit.h diff --git a/Source/Engine/Core/ScopeExit.h b/Source/Engine/Core/ScopeExit.h new file mode 100644 index 000000000..37068a2ff --- /dev/null +++ b/Source/Engine/Core/ScopeExit.h @@ -0,0 +1,36 @@ +// Copyright (c) Wojciech Figat. All rights reserved. + +#pragma once + +#include "Core.h" + +template +struct ScopeExit +{ + explicit ScopeExit(FuncType&& func) + : _func((FuncType&&)func) + { + } + + ~ScopeExit() + { + _func(); + } + +private: + FuncType _func; +}; + +namespace THelpers +{ + struct ScopeExitInternal + { + template + ScopeExit operator*(FuncType&& func) + { + return ScopeExit((FuncType&&)func); + } + }; +} + +#define SCOPE_EXIT const auto CONCAT_MACROS(__scopeExit, __LINE__) = THelpers::ScopeExitInternal() * [&]() diff --git a/Source/Engine/Tests/TestMain.cpp b/Source/Engine/Tests/TestMain.cpp index a490f6d1c..88db6144c 100644 --- a/Source/Engine/Tests/TestMain.cpp +++ b/Source/Engine/Tests/TestMain.cpp @@ -44,9 +44,9 @@ void TestsRunnerService::Update() LOG(Info, "Running Flax Tests..."); const int result = Catch::Session().run(); if (result == 0) - LOG(Info, "Result: {0}", result); + LOG(Info, "Flax Tests result: {0}", result); else - LOG(Error, "Result: {0}", result); + LOG(Error, "Flax Tests result: {0}", result); Log::Logger::WriteFloor(); Engine::RequestExit(result); } diff --git a/Source/Engine/Tests/TestPrefabs.cpp b/Source/Engine/Tests/TestPrefabs.cpp index a265a9d93..5e19a5fa0 100644 --- a/Source/Engine/Tests/TestPrefabs.cpp +++ b/Source/Engine/Tests/TestPrefabs.cpp @@ -3,6 +3,7 @@ #include "Engine/Content/Content.h" #include "Engine/Content/AssetReference.h" #include "Engine/Core/Log.h" +#include "Engine/Core/ScopeExit.h" #include "Engine/Level/Actor.h" #include "Engine/Level/Actors/EmptyActor.h" #include "Engine/Level/Actors/DirectionalLight.h" @@ -27,6 +28,7 @@ TEST_CASE("Prefabs") // Create Prefab B with two children attached to the root AssetReference prefabB = Content::CreateVirtualAsset(); REQUIRE(prefabB); + SCOPE_EXIT{ Content::DeleteAsset(prefabB); }; Guid id; Guid::Parse("665bb01c49a3370f14a023b5395de261", id); prefabB->ChangeID(id); @@ -55,6 +57,7 @@ TEST_CASE("Prefabs") // Create Prefab A with nested Prefab B attached to the root AssetReference prefabA = Content::CreateVirtualAsset(); REQUIRE(prefabA); + SCOPE_EXIT{ Content::DeleteAsset(prefabA); }; Guid::Parse("02524a044184af56b6c664a0f98bd761", id); prefabA->ChangeID(id); auto prefabAInit = prefabA->Init(Prefab::TypeName, @@ -123,8 +126,6 @@ TEST_CASE("Prefabs") // Cleanup instanceA->DeleteObject(); instanceB->DeleteObject(); - Content::DeleteAsset(prefabA); - Content::DeleteAsset(prefabB); } SECTION("Test Adding Object in Nested Prefab") { @@ -133,6 +134,7 @@ TEST_CASE("Prefabs") // Create Prefab B with just root object AssetReference prefabB = Content::CreateVirtualAsset(); REQUIRE(prefabB); + SCOPE_EXIT{ Content::DeleteAsset(prefabB); }; Guid id; Guid::Parse("25dbe4b0416be0777a6ce59e8788b10f", id); prefabB->ChangeID(id); @@ -149,6 +151,7 @@ TEST_CASE("Prefabs") // Create Prefab A with two nested Prefab B attached to the root AssetReference prefabA = Content::CreateVirtualAsset(); REQUIRE(prefabA); + SCOPE_EXIT{ Content::DeleteAsset(prefabA); }; Guid::Parse("4cb744714f746e31855f41815612d14b", id); prefabA->ChangeID(id); auto prefabAInit = prefabA->Init(Prefab::TypeName, @@ -243,8 +246,6 @@ TEST_CASE("Prefabs") // Cleanup instanceA->DeleteObject(); instanceB->DeleteObject(); - Content::DeleteAsset(prefabA); - Content::DeleteAsset(prefabB); } SECTION("Test Syncing Changes In Nested Prefab Instance") { @@ -253,6 +254,7 @@ TEST_CASE("Prefabs") // Create TestActor prefab with just root object AssetReference testActorPrefab = Content::CreateVirtualAsset(); REQUIRE(testActorPrefab); + SCOPE_EXIT{ Content::DeleteAsset(testActorPrefab); }; Guid id; Guid::Parse("7691e981482f2a486e10cfae149e07d3", id); testActorPrefab->ChangeID(id); @@ -269,6 +271,7 @@ TEST_CASE("Prefabs") // Create NestedActor prefab that inherits from TestActor prefab AssetReference nestedActorPrefab = Content::CreateVirtualAsset(); REQUIRE(nestedActorPrefab); + SCOPE_EXIT{ Content::DeleteAsset(nestedActorPrefab); }; Guid::Parse("1d521df4465ad849e274748c6d14b703", id); nestedActorPrefab->ChangeID(id); auto nestedActorPrefabInit = nestedActorPrefab->Init(Prefab::TypeName, @@ -328,8 +331,6 @@ TEST_CASE("Prefabs") // Cleanup nestedActor->DeleteObject(); testActor->DeleteObject(); - Content::DeleteAsset(nestedActorPrefab); - Content::DeleteAsset(testActorPrefab); } SECTION("Test Loading Nested Prefab After Changing Root") { @@ -338,6 +339,7 @@ TEST_CASE("Prefabs") // Create base prefab with 3 objects AssetReference prefabBase = Content::CreateVirtualAsset(); REQUIRE(prefabBase); + SCOPE_EXIT{ Content::DeleteAsset(prefabBase); }; Guid id; Guid::Parse("2b3334524c696dcfa93cabacd2a4f404", id); prefabBase->ChangeID(id); @@ -366,6 +368,7 @@ TEST_CASE("Prefabs") // Create nested prefab but with 'old' state where root object is different AssetReference prefabNested = Content::CreateVirtualAsset(); REQUIRE(prefabNested); + SCOPE_EXIT{ Content::DeleteAsset(prefabNested); }; Guid::Parse("a71447e947cbd2deea018a8377636ce6", id); prefabNested->ChangeID(id); auto prefabNestedInit = prefabNested->Init(Prefab::TypeName, @@ -411,8 +414,6 @@ TEST_CASE("Prefabs") // Cleanup instanceNested->DeleteObject(); instanceBase->DeleteObject(); - Content::DeleteAsset(prefabNested); - Content::DeleteAsset(prefabBase); } SECTION("Test Loading Nested Prefab After Changing and Deleting Root") { @@ -421,6 +422,7 @@ TEST_CASE("Prefabs") // Create base prefab with 1 object AssetReference prefabBase = Content::CreateVirtualAsset(); REQUIRE(prefabBase); + SCOPE_EXIT{ Content::DeleteAsset(prefabBase); }; Guid id; Guid::Parse("3b3334524c696dcfa93cabacd2a4f404", id); prefabBase->ChangeID(id); @@ -455,6 +457,7 @@ TEST_CASE("Prefabs") // Create nested prefab but with 'old' state where root object is different AssetReference prefabNested1 = Content::CreateVirtualAsset(); REQUIRE(prefabNested1); + SCOPE_EXIT{ Content::DeleteAsset(prefabNested1); }; Guid::Parse("671447e947cbd2deea018a8377636ce6", id); prefabNested1->ChangeID(id); auto prefabNestedInit1 = prefabNested1->Init(Prefab::TypeName, @@ -491,6 +494,7 @@ TEST_CASE("Prefabs") // Create nested prefab but with 'old' state where root object is different and doesn't exist anymore AssetReference prefabNested2 = Content::CreateVirtualAsset(); REQUIRE(prefabNested2); + SCOPE_EXIT{ Content::DeleteAsset(prefabNested2); }; Guid::Parse("b71447e947cbd2deea018a8377636ce6", id); prefabNested2->ChangeID(id); auto prefabNestedInit2 = prefabNested2->Init(Prefab::TypeName, @@ -555,9 +559,6 @@ TEST_CASE("Prefabs") instanceNested2->DeleteObject(); instanceNested1->DeleteObject(); instanceBase->DeleteObject(); - Content::DeleteAsset(prefabNested2); - Content::DeleteAsset(prefabNested1); - Content::DeleteAsset(prefabBase); } SECTION("Test Applying Prefab Change To Object References") { @@ -566,6 +567,7 @@ TEST_CASE("Prefabs") // Create Prefab AssetReference prefab = Content::CreateVirtualAsset(); REQUIRE(prefab); + SCOPE_EXIT{ Content::DeleteAsset(prefab); }; Guid id; Guid::Parse("690e55514cd6fdc2a269429a2bf84133", id); prefab->ChangeID(id); @@ -612,7 +614,6 @@ TEST_CASE("Prefabs") // Cleanup instanceA->DeleteObject(); instanceB->DeleteObject(); - Content::DeleteAsset(prefab); } SECTION("Test Applying Prefab With Missing Nested Prefab") { @@ -637,6 +638,7 @@ TEST_CASE("Prefabs") // Create Prefab A with nested Prefab B attached to the root AssetReference prefabA = Content::CreateVirtualAsset(); REQUIRE(prefabA); + SCOPE_EXIT{ Content::DeleteAsset(prefabA); }; Guid::Parse("4cb744714f746e31855f41815612d14b", id); prefabA->ChangeID(id); auto prefabAInit = prefabA->Init(Prefab::TypeName, @@ -685,7 +687,6 @@ TEST_CASE("Prefabs") instanceA->DeleteObject(); instanceB->DeleteObject(); instanceC->DeleteObject(); - Content::DeleteAsset(prefabA); } } From 14fcc593c7bd46d0d7b909cc1167bd09138acde2 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 30 May 2025 15:28:56 +0200 Subject: [PATCH 60/77] Fix various margins and spacings between UI elements in Editor to be consistent --- .../CustomEditors/CustomEditorPresenter.cs | 4 +- .../CustomEditors/Dedicated/ActorEditor.cs | 4 +- .../Dedicated/AudioSourceEditor.cs | 2 +- .../CustomEditors/Dedicated/ClothEditor.cs | 2 +- .../Dedicated/LocalizationSettingsEditor.cs | 4 ++ .../Dedicated/ModelPrefabEditor.cs | 2 +- .../Dedicated/ParticleEffectEditor.cs | 2 +- .../CustomEditors/Dedicated/RagdollEditor.cs | 4 +- .../Dedicated/SceneAnimationPlayerEditor.cs | 2 +- .../Dedicated/UIControlEditor.cs | 2 +- .../Editors/ActorTransformEditor.cs | 30 ++++---- .../CustomEditors/Editors/CollectionEditor.cs | 8 +-- .../CustomEditors/Editors/ColorTrackball.cs | 2 +- .../CustomEditors/Editors/QuaternionEditor.cs | 2 +- .../CustomEditors/Editors/Vector2Editor.cs | 6 +- .../CustomEditors/Editors/Vector3Editor.cs | 6 +- .../CustomEditors/Editors/Vector4Editor.cs | 6 +- .../CustomEditors/Editors/VersionEditor.cs | 2 +- .../Elements/Container/GroupElement.cs | 3 +- .../CustomEditors/GUI/PropertiesList.cs | 37 ++++++---- .../CustomEditors/LayoutElementsContainer.cs | 11 +++ .../SceneGraph/Actors/VideoPlayerEditor.cs | 2 +- Source/Editor/Utilities/Constants.cs | 2 + Source/Editor/Utilities/Utils.cs | 5 +- .../Editor/Windows/Assets/ModelBaseWindow.cs | 1 - Source/Editor/Windows/Assets/ModelWindow.cs | 2 +- .../Windows/Assets/VisualScriptWindow.cs | 2 +- Source/Engine/UI/GUI/Panels/DropPanel.cs | 42 ++++++++--- .../Engine/UI/GUI/Panels/UniformGridPanel.cs | 72 ++++++------------- 29 files changed, 143 insertions(+), 126 deletions(-) diff --git a/Source/Editor/CustomEditors/CustomEditorPresenter.cs b/Source/Editor/CustomEditors/CustomEditorPresenter.cs index 62db53cab..a518d92a1 100644 --- a/Source/Editor/CustomEditors/CustomEditorPresenter.cs +++ b/Source/Editor/CustomEditors/CustomEditorPresenter.cs @@ -81,6 +81,8 @@ namespace FlaxEditor.CustomEditors Offsets = Margin.Zero; Pivot = Float2.Zero; IsScrollable = true; + Spacing = Utilities.Constants.UIMargin; + Margin = new Margin(Utilities.Constants.UIMargin); } /// @@ -95,7 +97,7 @@ namespace FlaxEditor.CustomEditors { FlaxEditor.Editor.LogWarning(ex); - // Refresh layout on errors to reduce lgo spam + // Refresh layout on errors to reduce log spam _presenter.BuildLayout(); } diff --git a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs index 062aeeedd..60bc033ee 100644 --- a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs @@ -71,14 +71,14 @@ namespace FlaxEditor.CustomEditors.Dedicated // Display prefab UI (when displaying object inside Prefab Window then display only nested prefabs) prefab.GetNestedObject(ref prefabObjectId, out var nestedPrefabId, out var nestedPrefabObjectId); var nestedPrefab = FlaxEngine.Content.Load(nestedPrefabId); - var panel = layout.CustomContainer(); + var panel = layout.UniformGrid(); panel.CustomControl.Height = 20.0f; panel.CustomControl.SlotsVertically = 1; if (Presenter == Editor.Instance.Windows.PropertiesWin.Presenter || nestedPrefab) { var targetPrefab = nestedPrefab ?? prefab; panel.CustomControl.SlotsHorizontally = 3; - + // Selecting actor prefab asset var selectPrefab = panel.Button("Select Prefab"); selectPrefab.Button.Clicked += () => diff --git a/Source/Editor/CustomEditors/Dedicated/AudioSourceEditor.cs b/Source/Editor/CustomEditors/Dedicated/AudioSourceEditor.cs index 4f18baa84..1ddc1c144 100644 --- a/Source/Editor/CustomEditors/Dedicated/AudioSourceEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/AudioSourceEditor.cs @@ -28,7 +28,7 @@ namespace FlaxEditor.CustomEditors.Dedicated _infoLabel = playbackGroup.Label(string.Empty).Label; _infoLabel.AutoHeight = true; - var grid = playbackGroup.CustomContainer(); + var grid = playbackGroup.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = Button.DefaultHeight; diff --git a/Source/Editor/CustomEditors/Dedicated/ClothEditor.cs b/Source/Editor/CustomEditors/Dedicated/ClothEditor.cs index e16f1141c..abb27867a 100644 --- a/Source/Editor/CustomEditors/Dedicated/ClothEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ClothEditor.cs @@ -59,7 +59,7 @@ namespace FlaxEditor.CustomEditors.Dedicated var paintValue = new ReadOnlyValueContainer(new ScriptType(typeof(ClothPaintingGizmoMode)), _gizmoMode); paintGroup.Object(paintValue); { - var grid = paintGroup.CustomContainer(); + var grid = paintGroup.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = Button.DefaultHeight; diff --git a/Source/Editor/CustomEditors/Dedicated/LocalizationSettingsEditor.cs b/Source/Editor/CustomEditors/Dedicated/LocalizationSettingsEditor.cs index bfe3d5efe..db7434125 100644 --- a/Source/Editor/CustomEditors/Dedicated/LocalizationSettingsEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/LocalizationSettingsEditor.cs @@ -92,12 +92,14 @@ namespace FlaxEditor.CustomEditors.Dedicated // Update add button var update = group.Button("Update").Button; + group.Space(0); update.TooltipText = "Refreshes the dashboard statistics"; update.Height = 16.0f; update.Clicked += RebuildLayout; // New locale add button var addLocale = group.Button("Add Locale...").Button; + group.Space(0); addLocale.TooltipText = "Shows a locale picker and creates new localization for it with not translated string tables"; addLocale.Height = 16.0f; addLocale.ButtonClicked += delegate(Button button) @@ -167,12 +169,14 @@ namespace FlaxEditor.CustomEditors.Dedicated // Export button var exportLocalization = group.Button("Export...").Button; + group.Space(0); exportLocalization.TooltipText = "Exports the localization strings into .pot file for translation"; exportLocalization.Height = 16.0f; exportLocalization.Clicked += () => Export(tableEntries, allKeys); // Find localized strings in code button var findStringsCode = group.Button("Find localized strings in code").Button; + group.Space(0); findStringsCode.TooltipText = "Searches for localized string usage in inside a project source files"; findStringsCode.Height = 16.0f; findStringsCode.Clicked += delegate diff --git a/Source/Editor/CustomEditors/Dedicated/ModelPrefabEditor.cs b/Source/Editor/CustomEditors/Dedicated/ModelPrefabEditor.cs index f57548258..22c5d7ece 100644 --- a/Source/Editor/CustomEditors/Dedicated/ModelPrefabEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ModelPrefabEditor.cs @@ -55,7 +55,7 @@ public class ModelPrefabEditor : GenericEditor // Creates the import path UI var group = layout.Group("Import Path"); - Utilities.Utils.CreateImportPathUI(group, modelPrefab.ImportPath, false); + Utilities.Utils.CreateImportPathUI(group, modelPrefab.ImportPath); var button = layout.Button("Reimport", "Reimports the source asset as prefab."); _reimportButton = button.Button; diff --git a/Source/Editor/CustomEditors/Dedicated/ParticleEffectEditor.cs b/Source/Editor/CustomEditors/Dedicated/ParticleEffectEditor.cs index 783b787ae..3de013bfb 100644 --- a/Source/Editor/CustomEditors/Dedicated/ParticleEffectEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ParticleEffectEditor.cs @@ -92,7 +92,7 @@ namespace FlaxEditor.CustomEditors.Dedicated _infoLabel = playbackGroup.Label(string.Empty).Label; _infoLabel.AutoHeight = true; - var grid = playbackGroup.CustomContainer(); + var grid = playbackGroup.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = Button.DefaultHeight; diff --git a/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs b/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs index b68ade40b..ce157240a 100644 --- a/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs @@ -39,7 +39,7 @@ namespace FlaxEditor.CustomEditors.Dedicated if (ragdoll.Parent is AnimatedModel animatedModel && animatedModel.SkinnedModel) { // Builder - var grid = editorGroup.CustomContainer(); + var grid = editorGroup.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = Button.DefaultHeight; @@ -53,7 +53,7 @@ namespace FlaxEditor.CustomEditors.Dedicated if (Presenter.Owner != null) { // Selection - var grid = editorGroup.CustomContainer(); + var grid = editorGroup.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = Button.DefaultHeight; diff --git a/Source/Editor/CustomEditors/Dedicated/SceneAnimationPlayerEditor.cs b/Source/Editor/CustomEditors/Dedicated/SceneAnimationPlayerEditor.cs index aa2b42edc..e4496601b 100644 --- a/Source/Editor/CustomEditors/Dedicated/SceneAnimationPlayerEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/SceneAnimationPlayerEditor.cs @@ -28,7 +28,7 @@ namespace FlaxEditor.CustomEditors.Dedicated _infoLabel = playbackGroup.Label(string.Empty).Label; _infoLabel.AutoHeight = true; - var grid = playbackGroup.CustomContainer(); + var grid = playbackGroup.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = Button.DefaultHeight; diff --git a/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs b/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs index 15566a631..614d2c160 100644 --- a/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs @@ -682,7 +682,7 @@ namespace FlaxEditor.CustomEditors.Dedicated private CustomElementsContainer UniformGridTwoByOne(LayoutElementsContainer cont) { - var grid = cont.CustomContainer(); + var grid = cont.UniformGrid(); grid.CustomControl.SlotsHorizontally = 2; grid.CustomControl.SlotsVertically = 1; grid.CustomControl.SlotPadding = Margin.Zero; diff --git a/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs b/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs index 355321329..2daf2f6af 100644 --- a/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs @@ -41,13 +41,9 @@ namespace FlaxEditor.CustomEditors.Editors public override void Initialize(LayoutElementsContainer layout) { base.Initialize(layout); - + if (XElement.ValueBox.Parent is UniformGridPanel ug) - { - ug.Height += 2; - ug.SlotSpacing = new Float2(4); - ug.SlotPadding = new Margin(0, 0, 1, 1); - } + CheckLayout(ug); // Override colors var back = FlaxEngine.GUI.Style.Current.TextBoxBackground; @@ -75,11 +71,7 @@ namespace FlaxEditor.CustomEditors.Editors base.Initialize(layout); if (XElement.ValueBox.Parent is UniformGridPanel ug) - { - ug.Height += 2; - ug.SlotSpacing = new Float2(4); - ug.SlotPadding = new Margin(0, 0, 1, 1); - } + CheckLayout(ug); // Override colors var back = FlaxEngine.GUI.Style.Current.TextBoxBackground; @@ -136,13 +128,9 @@ namespace FlaxEditor.CustomEditors.Editors menu.AddButton("Link", ToggleLink).LinkTooltip("Links scale components for uniform scaling"); }; } - + if (XElement.ValueBox.Parent is UniformGridPanel ug) - { - ug.Height += 2; - ug.SlotSpacing = new Float2(4); - ug.SlotPadding = new Margin(0, 0, 1, 1); - } + CheckLayout(ug); // Override colors var back = FlaxEngine.GUI.Style.Current.TextBoxBackground; @@ -203,5 +191,13 @@ namespace FlaxEditor.CustomEditors.Editors _linkButton.TooltipText = LinkValues ? "Unlinks scale components from uniform scaling" : "Links scale components for uniform scaling"; } } + + private static void CheckLayout(UniformGridPanel ug) + { + // Enlarge to fix border visibility + ug.Height += 2; + ug.SlotSpacing += new Float2(2); + ug.SlotPadding += new Margin(0, 0, 1, 1); + } } } diff --git a/Source/Editor/CustomEditors/Editors/CollectionEditor.cs b/Source/Editor/CustomEditors/Editors/CollectionEditor.cs index 6ebdb9a58..cfc11d5a5 100644 --- a/Source/Editor/CustomEditors/Editors/CollectionEditor.cs +++ b/Source/Editor/CustomEditors/Editors/CollectionEditor.cs @@ -642,10 +642,10 @@ namespace FlaxEditor.CustomEditors.Editors if (_canResize && !_readOnly) { var panel = dragArea.HorizontalPanel(); - panel.Panel.Size = new Float2(0, 20); - panel.Panel.Margin = new Margin(2); + panel.Panel.Size = new Float2(0, 18); + panel.Panel.Margin = new Margin(0, 0, Utilities.Constants.UIMargin, 0); - var removeButton = panel.Button("-", "Remove last item"); + var removeButton = panel.Button("-", "Remove the last item"); removeButton.Button.Size = new Float2(16, 16); removeButton.Button.Enabled = size > _minCount; removeButton.Button.AnchorPreset = AnchorPresets.TopRight; @@ -656,7 +656,7 @@ namespace FlaxEditor.CustomEditors.Editors Resize(Count - 1); }; - var addButton = panel.Button("+", "Add new item"); + var addButton = panel.Button("+", "Add a new item"); addButton.Button.Size = new Float2(16, 16); addButton.Button.Enabled = (!NotNullItems || size > 0) && size < _maxCount; addButton.Button.AnchorPreset = AnchorPresets.TopRight; diff --git a/Source/Editor/CustomEditors/Editors/ColorTrackball.cs b/Source/Editor/CustomEditors/Editors/ColorTrackball.cs index d0259102d..2ca325e45 100644 --- a/Source/Editor/CustomEditors/Editors/ColorTrackball.cs +++ b/Source/Editor/CustomEditors/Editors/ColorTrackball.cs @@ -50,7 +50,7 @@ namespace FlaxEditor.CustomEditors.Editors // Scale editor { - var grid = masterPanel.CustomContainer(); + var grid = masterPanel.UniformGrid(); var gridControl = grid.CustomControl; gridControl.SlotPadding = new Margin(4, 2, 2, 2); gridControl.ClipChildren = false; diff --git a/Source/Editor/CustomEditors/Editors/QuaternionEditor.cs b/Source/Editor/CustomEditors/Editors/QuaternionEditor.cs index feaada5df..3baad685d 100644 --- a/Source/Editor/CustomEditors/Editors/QuaternionEditor.cs +++ b/Source/Editor/CustomEditors/Editors/QuaternionEditor.cs @@ -46,7 +46,7 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - var grid = layout.CustomContainer(); + var grid = layout.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = TextBox.DefaultHeight; diff --git a/Source/Editor/CustomEditors/Editors/Vector2Editor.cs b/Source/Editor/CustomEditors/Editors/Vector2Editor.cs index 6ae8e608f..8c09298c7 100644 --- a/Source/Editor/CustomEditors/Editors/Vector2Editor.cs +++ b/Source/Editor/CustomEditors/Editors/Vector2Editor.cs @@ -42,7 +42,7 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - var grid = layout.CustomContainer(); + var grid = layout.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = TextBox.DefaultHeight; @@ -131,7 +131,7 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - var grid = layout.CustomContainer(); + var grid = layout.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = TextBox.DefaultHeight; @@ -220,7 +220,7 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - var grid = layout.CustomContainer(); + var grid = layout.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = TextBox.DefaultHeight; diff --git a/Source/Editor/CustomEditors/Editors/Vector3Editor.cs b/Source/Editor/CustomEditors/Editors/Vector3Editor.cs index cb44c60c8..d81cae199 100644 --- a/Source/Editor/CustomEditors/Editors/Vector3Editor.cs +++ b/Source/Editor/CustomEditors/Editors/Vector3Editor.cs @@ -82,7 +82,7 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - var grid = layout.CustomContainer(); + var grid = layout.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = TextBox.DefaultHeight; @@ -469,7 +469,7 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - var grid = layout.CustomContainer(); + var grid = layout.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = TextBox.DefaultHeight; @@ -783,7 +783,7 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - var grid = layout.CustomContainer(); + var grid = layout.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = TextBox.DefaultHeight; diff --git a/Source/Editor/CustomEditors/Editors/Vector4Editor.cs b/Source/Editor/CustomEditors/Editors/Vector4Editor.cs index 01328c34b..34d96a80a 100644 --- a/Source/Editor/CustomEditors/Editors/Vector4Editor.cs +++ b/Source/Editor/CustomEditors/Editors/Vector4Editor.cs @@ -52,7 +52,7 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - var grid = layout.CustomContainer(); + var grid = layout.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = TextBox.DefaultHeight; @@ -163,7 +163,7 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - var grid = layout.CustomContainer(); + var grid = layout.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = TextBox.DefaultHeight; @@ -274,7 +274,7 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - var grid = layout.CustomContainer(); + var grid = layout.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = TextBox.DefaultHeight; diff --git a/Source/Editor/CustomEditors/Editors/VersionEditor.cs b/Source/Editor/CustomEditors/Editors/VersionEditor.cs index 5fc047fed..de9781dc4 100644 --- a/Source/Editor/CustomEditors/Editors/VersionEditor.cs +++ b/Source/Editor/CustomEditors/Editors/VersionEditor.cs @@ -39,7 +39,7 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - var grid = layout.CustomContainer(); + var grid = layout.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = TextBox.DefaultHeight; diff --git a/Source/Editor/CustomEditors/Elements/Container/GroupElement.cs b/Source/Editor/CustomEditors/Elements/Container/GroupElement.cs index e3226ef2b..64bc9080b 100644 --- a/Source/Editor/CustomEditors/Elements/Container/GroupElement.cs +++ b/Source/Editor/CustomEditors/Elements/Container/GroupElement.cs @@ -22,7 +22,8 @@ namespace FlaxEditor.CustomEditors.Elements ArrowImageClosed = new SpriteBrush(Style.Current.ArrowRight), ArrowImageOpened = new SpriteBrush(Style.Current.ArrowDown), EnableDropDownIcon = true, - ItemsMargin = new Margin(7, 7, 3, 3), + ItemsMargin = new Margin(Utilities.Constants.UIMargin), + ItemsSpacing = Utilities.Constants.UIMargin, HeaderHeight = 18.0f, EnableContainmentLines = true, }; diff --git a/Source/Editor/CustomEditors/GUI/PropertiesList.cs b/Source/Editor/CustomEditors/GUI/PropertiesList.cs index 02efbb2a3..ef90fc706 100644 --- a/Source/Editor/CustomEditors/GUI/PropertiesList.cs +++ b/Source/Editor/CustomEditors/GUI/PropertiesList.cs @@ -20,13 +20,6 @@ namespace FlaxEditor.CustomEditors.GUI /// public const int SplitterSize = 2; - /// - /// The splitter margin (in pixels). - /// - public const int SplitterMargin = 4; - - private const int SplitterSizeHalf = SplitterSize / 2; - private PropertiesListElement _element; private float _splitterValue; private Rectangle _splitterRect; @@ -65,16 +58,18 @@ namespace FlaxEditor.CustomEditors.GUI /// The element. public PropertiesList(PropertiesListElement element) { + ClipChildren = false; _element = element; _splitterValue = 0.4f; - BottomMargin = TopMargin = RightMargin = SplitterMargin; + Margin = new Margin(); + Spacing = Utilities.Constants.UIMargin; UpdateSplitRect(); } private void UpdateSplitRect() { - _splitterRect = new Rectangle(Mathf.Clamp(_splitterValue * Width - SplitterSizeHalf, 0.0f, Width), 0, SplitterSize, Height); - LeftMargin = _splitterValue * Width + SplitterMargin; + _splitterRect = new Rectangle(Mathf.Clamp(_splitterValue * Width - SplitterSize * 0.5f, 0.0f, Width), 0, SplitterSize, Height); + LeftMargin = _splitterValue * Width + _spacing; } private void StartTracking() @@ -222,23 +217,33 @@ namespace FlaxEditor.CustomEditors.GUI /// protected override void PerformLayoutAfterChildren() { - // Sort controls from up to down into two columns: one for labels and one for the rest of the stuff - + // Place non-label controls from top to down float y = _margin.Top; float w = Width - _margin.Width; + bool firstItem = true; for (int i = 0; i < _children.Count; i++) { Control c = _children[i]; if (!(c is PropertyNameLabel)) { - var h = c.Height; - c.Bounds = new Rectangle(_margin.Left, y + _spacing, w, h); + var rect = new Rectangle(_margin.Left, y, w, c.Height); + if (c.Visible) + { + if (firstItem) + firstItem = false; + else + rect.Y += _spacing; + } + else if (!firstItem) + rect.Y += _spacing; + c.Bounds = rect; if (c.Visible) y = c.Bottom; } } y += _margin.Bottom; + // Place labels accordingly to their respective controls placement float namesWidth = _splitterValue * Width; int count = _element.Labels.Count; float[] yStarts = new float[count + 1]; @@ -271,7 +276,9 @@ namespace FlaxEditor.CustomEditors.GUI { var label = _element.Labels[i]; - var rect = new Rectangle(0, yStarts[i] + 1, namesWidth, yStarts[i + 1] - yStarts[i] - 2); + var rect = new Rectangle(0, yStarts[i], namesWidth, yStarts[i + 1] - yStarts[i]); + if (i != count - 1) + rect.Height -= _spacing; //label.Parent = this; label.Bounds = rect; } diff --git a/Source/Editor/CustomEditors/LayoutElementsContainer.cs b/Source/Editor/CustomEditors/LayoutElementsContainer.cs index 855a730df..68ac9f47a 100644 --- a/Source/Editor/CustomEditors/LayoutElementsContainer.cs +++ b/Source/Editor/CustomEditors/LayoutElementsContainer.cs @@ -202,6 +202,17 @@ namespace FlaxEditor.CustomEditors return element; } + /// + /// Adds new uniform grid control. + /// + /// The created element. + public CustomElementsContainer UniformGrid() + { + var grid = CustomContainer(); + grid.CustomControl.SlotSpacing = new Float2(Utilities.Constants.UIMargin); + return grid; + } + /// /// Adds new custom element. /// diff --git a/Source/Editor/SceneGraph/Actors/VideoPlayerEditor.cs b/Source/Editor/SceneGraph/Actors/VideoPlayerEditor.cs index 7e50de084..e5f120e04 100644 --- a/Source/Editor/SceneGraph/Actors/VideoPlayerEditor.cs +++ b/Source/Editor/SceneGraph/Actors/VideoPlayerEditor.cs @@ -28,7 +28,7 @@ namespace FlaxEditor.CustomEditors.Dedicated _infoLabel = playbackGroup.Label(string.Empty).Label; _infoLabel.AutoHeight = true; - var grid = playbackGroup.CustomContainer(); + var grid = layout.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = Button.DefaultHeight; diff --git a/Source/Editor/Utilities/Constants.cs b/Source/Editor/Utilities/Constants.cs index cbdb22a66..40fbbb5d7 100644 --- a/Source/Editor/Utilities/Constants.cs +++ b/Source/Editor/Utilities/Constants.cs @@ -20,5 +20,7 @@ namespace FlaxEditor.Utilities #else public const string ShowInExplorer = "Show in explorer"; #endif + + public const float UIMargin = 3.0f; } } diff --git a/Source/Editor/Utilities/Utils.cs b/Source/Editor/Utilities/Utils.cs index 7c7d3d2d2..7112f9d90 100644 --- a/Source/Editor/Utilities/Utils.cs +++ b/Source/Editor/Utilities/Utils.cs @@ -415,13 +415,10 @@ namespace FlaxEditor.Utilities /// /// The parent layout element. /// The import path. - /// Whether to use an initial layout space of 5 for separation. - public static void CreateImportPathUI(CustomEditors.LayoutElementsContainer parentLayout, string path, bool useInitialSpacing = true) + public static void CreateImportPathUI(CustomEditors.LayoutElementsContainer parentLayout, string path) { if (!string.IsNullOrEmpty(path)) { - if (useInitialSpacing) - parentLayout.Space(0); var textBox = parentLayout.TextBox().TextBox; textBox.TooltipText = "Source asset path. Can be relative or absolute to the project. Path is not editable here."; textBox.IsReadOnly = true; diff --git a/Source/Editor/Windows/Assets/ModelBaseWindow.cs b/Source/Editor/Windows/Assets/ModelBaseWindow.cs index 216dede67..1214e9427 100644 --- a/Source/Editor/Windows/Assets/ModelBaseWindow.cs +++ b/Source/Editor/Windows/Assets/ModelBaseWindow.cs @@ -759,7 +759,6 @@ namespace FlaxEditor.Windows.Assets var importSettingsField = typeof(ImportPropertiesProxyBase).GetField(nameof(ImportSettings), BindingFlags.NonPublic | BindingFlags.Instance); var importSettingsValues = new ValueContainer(new ScriptMemberInfo(importSettingsField)) { proxy.ImportSettings }; importSettingsGroup.Object(importSettingsValues); - importSettingsGroup.Space(3); // Creates the import path UI var group = layout.Group("Import Path"); diff --git a/Source/Editor/Windows/Assets/ModelWindow.cs b/Source/Editor/Windows/Assets/ModelWindow.cs index d28c0141b..9a0b1ad82 100644 --- a/Source/Editor/Windows/Assets/ModelWindow.cs +++ b/Source/Editor/Windows/Assets/ModelWindow.cs @@ -114,7 +114,7 @@ namespace FlaxEditor.Windows.Assets lodIndex.IntValue.Value = sdf.Texture != null ? sdf.LOD : 6; _sdfModelLodIndex = lodIndex; - var buttons = group.CustomContainer(); + var buttons = layout.UniformGrid(); var gridControl = buttons.CustomControl; gridControl.ClipChildren = false; gridControl.Height = Button.DefaultHeight; diff --git a/Source/Editor/Windows/Assets/VisualScriptWindow.cs b/Source/Editor/Windows/Assets/VisualScriptWindow.cs index b38fa277a..756daf66a 100644 --- a/Source/Editor/Windows/Assets/VisualScriptWindow.cs +++ b/Source/Editor/Windows/Assets/VisualScriptWindow.cs @@ -413,7 +413,7 @@ namespace FlaxEditor.Windows.Assets var group = layout.Group("Functions"); var nodes = window.VisjectSurface.Nodes; - var grid = group.CustomContainer(); + var grid = layout.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; gridControl.Height = Button.DefaultHeight; diff --git a/Source/Engine/UI/GUI/Panels/DropPanel.cs b/Source/Engine/UI/GUI/Panels/DropPanel.cs index ff9d3df2d..0bfa799c2 100644 --- a/Source/Engine/UI/GUI/Panels/DropPanel.cs +++ b/Source/Engine/UI/GUI/Panels/DropPanel.cs @@ -51,6 +51,11 @@ namespace FlaxEngine.GUI /// protected float _cachedHeight = 16.0f; + /// + /// The items spacing. + /// + protected float _itemsSpacing = 2.0f; + /// /// The items margin. /// @@ -168,9 +173,9 @@ namespace FlaxEngine.GUI } /// - /// Gets or sets the item slots margin (the space between items). + /// Gets or sets the item slots margin (the space around items). /// - [EditorOrder(10), Tooltip("The item slots margin (the space between items).")] + [EditorOrder(10)] public Margin ItemsMargin { get => _itemsMargin; @@ -184,6 +189,23 @@ namespace FlaxEngine.GUI } } + /// + /// Gets or sets the item slots spacing (the margin between items). + /// + [EditorOrder(11)] + public float ItemsSpacing + { + get => _itemsSpacing; + set + { + if (!Mathf.NearEqual(_itemsSpacing, value)) + { + _itemsSpacing = value; + PerformLayout(); + } + } + } + /// /// Gets or sets the panel close/open animation duration (in seconds). /// @@ -563,25 +585,27 @@ namespace FlaxEngine.GUI var slotsLeft = clientArea.Left + slotsMargin.Left; var slotsWidth = clientArea.Width - slotsMargin.Width; float minHeight = HeaderHeight; - float y = clientArea.Top; - float height = clientArea.Top + dropOffset; + float y = clientArea.Top + slotsMargin.Top; + bool anyAdded = false; for (int i = 0; i < _children.Count; i++) { Control c = _children[i]; if (c.IsScrollable && c.Visible) { var h = c.Height; - y += slotsMargin.Top; - c.Bounds = new Rectangle(slotsLeft, y, slotsWidth, h); - - h += slotsMargin.Bottom; + h += _itemsSpacing; y += h; - height += h + slotsMargin.Top; + anyAdded = true; } } // Update panel height + if (anyAdded) + y -= _itemsSpacing; + if (anyAdded) + y += slotsMargin.Bottom; + float height = dropOffset + y; _cachedHeight = height; if (_animationProgress >= 1.0f && _isClosed) y = minHeight; diff --git a/Source/Engine/UI/GUI/Panels/UniformGridPanel.cs b/Source/Engine/UI/GUI/Panels/UniformGridPanel.cs index 6292a3e81..b8d59c4d7 100644 --- a/Source/Engine/UI/GUI/Panels/UniformGridPanel.cs +++ b/Source/Engine/UI/GUI/Panels/UniformGridPanel.cs @@ -72,8 +72,11 @@ namespace FlaxEngine.GUI get => _slotSpacing; set { - _slotSpacing = value; - PerformLayout(); + if (!Float2.NearEqual(ref _slotSpacing, ref value)) + { + _slotSpacing = value; + PerformLayout(); + } } } @@ -89,11 +92,11 @@ namespace FlaxEngine.GUI /// Initializes a new instance of the class. /// /// The slot padding. - public UniformGridPanel(float slotPadding = 0) + public UniformGridPanel(float slotPadding) { AutoFocus = false; - SlotPadding = new Margin(slotPadding); - SlotSpacing = new Float2(2); + _slotPadding = new Margin(slotPadding); + _slotSpacing = new Float2(2); _slotsH = _slotsV = 5; } @@ -105,25 +108,32 @@ namespace FlaxEngine.GUI int slotsV = _slotsV; int slotsH = _slotsH; Float2 slotSize; + Float2 size = Size; + bool applySpacing = true; + APPLY_SPACING: if (_slotsV + _slotsH == 0) { slotSize = HasChildren ? Children[0].Size : new Float2(32); - slotsH = Mathf.CeilToInt(Width / slotSize.X); - slotsV = Mathf.CeilToInt(Height / slotSize.Y); + slotsH = Mathf.CeilToInt(size.X / slotSize.X); + slotsV = Mathf.CeilToInt(size.Y / slotSize.Y); } else if (slotsH == 0) { - float size = Height / slotsV; - slotSize = new Float2(size); + slotSize = new Float2(size.Y / slotsV); } else if (slotsV == 0) { - float size = Width / slotsH; - slotSize = new Float2(size); + slotSize = new Float2(size.X / slotsH); } else { - slotSize = new Float2(Width / slotsH, Height / slotsV); + slotSize = new Float2(size.X / slotsH, size.Y / slotsV); + } + if (applySpacing && _slotSpacing != Float2.Zero) + { + applySpacing = false; + size -= _slotSpacing * new Float2(slotsH > 1 ? slotsH - 1 : 0, slotsV > 1 ? slotsV - 1 : 0); + goto APPLY_SPACING; } int i = 0; @@ -135,45 +145,9 @@ namespace FlaxEngine.GUI for (int x = 0; x < end; x++) { - var slotBounds = new Rectangle(slotSize.X * x, slotSize.Y * y, slotSize.X, slotSize.Y); + var slotBounds = new Rectangle((slotSize + _slotSpacing) * new Float2(x, y), slotSize); _slotPadding.ShrinkRectangle(ref slotBounds); - if (slotsV > 1) - { - if (y == 0) - { - slotBounds.Height -= _slotSpacing.Y * 0.5f; - } - else if (y == slotsV - 1) - { - slotBounds.Height -= _slotSpacing.Y * 0.5f; - slotBounds.Y += _slotSpacing.Y * 0.5f; - } - else - { - slotBounds.Height -= _slotSpacing.Y; - slotBounds.Y += _slotSpacing.Y * 0.5f; - } - } - - if (slotsH > 1) - { - if (x == 0) - { - slotBounds.Width -= _slotSpacing.X * 0.5f; - } - else if (x == slotsH - 1) - { - slotBounds.Width -= _slotSpacing.X * 0.5f; - slotBounds.X += _slotSpacing.X * 0.5f; - } - else - { - slotBounds.Width -= _slotSpacing.X; - slotBounds.X += _slotSpacing.X * 0.5f; - } - } - var c = _children[i++]; c.Bounds = slotBounds; } From d6b1f06721bfb0ef3b9bef9c6b7c82ce687fb15f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 30 May 2025 15:31:10 +0200 Subject: [PATCH 61/77] Fix deprecated asset saving to skip temporary or virtual assets --- Source/Engine/Content/Asset.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Content/Asset.cpp b/Source/Engine/Content/Asset.cpp index 0d5391482..4130993eb 100644 --- a/Source/Engine/Content/Asset.cpp +++ b/Source/Engine/Content/Asset.cpp @@ -15,6 +15,8 @@ #if USE_EDITOR +#include "Engine/Engine/Globals.h" + ThreadLocal ContentDeprecatedFlags; void ContentDeprecated::Mark() @@ -592,7 +594,7 @@ bool Asset::onLoad(LoadAssetTask* task) #if USE_EDITOR // Auto-save deprecated assets to get rid of data in an old format - if (isDeprecated && isLoaded) + if (isDeprecated && isLoaded && !IsVirtual() && !GetPath().StartsWith(StringUtils::GetDirectoryName(Globals::TemporaryFolder))) { PROFILE_CPU_NAMED("Asset.Save"); LOG(Info, "Resaving asset '{}' that uses deprecated data format", ToString()); From 11dec8e8683ea79b5a95727c4648ce1d63dcf377 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 30 May 2025 15:51:35 +0200 Subject: [PATCH 62/77] Fix incorrectly rendered transparency in Physics Colliders view mode #3474 --- Source/Engine/Renderer/ForwardPass.cpp | 12 +++++++++++- Source/Engine/Renderer/ForwardPass.h | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Renderer/ForwardPass.cpp b/Source/Engine/Renderer/ForwardPass.cpp index 42796764f..caf624609 100644 --- a/Source/Engine/Renderer/ForwardPass.cpp +++ b/Source/Engine/Renderer/ForwardPass.cpp @@ -72,7 +72,7 @@ void ForwardPass::Dispose() _shader = nullptr; } -void ForwardPass::Render(RenderContext& renderContext, GPUTexture* input, GPUTexture* output) +void ForwardPass::Render(RenderContext& renderContext, GPUTexture*& input, GPUTexture*& output) { PROFILE_GPU_CPU("Forward"); auto context = GPUDevice::Instance->GetMainContext(); @@ -91,6 +91,16 @@ void ForwardPass::Render(RenderContext& renderContext, GPUTexture* input, GPUTex // Check if there is no objects to render or no resources ready auto& forwardList = mainCache->DrawCallsLists[(int32)DrawCallsListType::Forward]; auto& distortionList = mainCache->DrawCallsLists[(int32)DrawCallsListType::Distortion]; + if ((forwardList.IsEmpty() && distortionList.IsEmpty()) +#if USE_EDITOR + || renderContext.View.Mode == ViewMode::PhysicsColliders +#endif + ) + { + // Skip rendering + Swap(input, output); + return; + } if (distortionList.IsEmpty() || checkIfSkipPass()) { // Copy frame diff --git a/Source/Engine/Renderer/ForwardPass.h b/Source/Engine/Renderer/ForwardPass.h index 552052eb1..be3126e0e 100644 --- a/Source/Engine/Renderer/ForwardPass.h +++ b/Source/Engine/Renderer/ForwardPass.h @@ -31,7 +31,7 @@ public: /// The rendering context. /// Target with renderer frame ready for further processing. /// The output frame. - void Render(RenderContext& renderContext, GPUTexture* input, GPUTexture* output); + void Render(RenderContext& renderContext, GPUTexture*& input, GPUTexture*& output); private: From 0f3044ae722db1c157370b79d20af9f76ac16ec8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 31 May 2025 23:27:51 +0200 Subject: [PATCH 63/77] Optimize debug drawing of terrain shape in Physics Colliders view mode #3469 --- Source/Engine/Debug/DebugDraw.cpp | 25 ++++++++++++++++-- Source/Engine/Debug/DebugDraw.h | 25 ++++++++++++------ Source/Engine/Physics/Actors/Cloth.cpp | 1 + Source/Engine/Terrain/Terrain.cpp | 1 + Source/Engine/Terrain/TerrainPatch.cpp | 35 +++++++++++++++++++++++++- Source/Engine/Terrain/TerrainPatch.h | 2 ++ 6 files changed, 78 insertions(+), 11 deletions(-) diff --git a/Source/Engine/Debug/DebugDraw.cpp b/Source/Engine/Debug/DebugDraw.cpp index a026267cc..44f0f2ce1 100644 --- a/Source/Engine/Debug/DebugDraw.cpp +++ b/Source/Engine/Debug/DebugDraw.cpp @@ -99,6 +99,7 @@ struct DebugGeometryBuffer { GPUBuffer* Buffer; float TimeLeft; + bool Lines; Matrix Transform; }; @@ -810,6 +811,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe defaultWireTriangles = WriteLists(vertexCounter, Context->DebugDrawDefault.DefaultWireTriangles, Context->DebugDrawDefault.OneFrameWireTriangles); { PROFILE_CPU_NAMED("Flush"); + ZoneValue(DebugDrawVB->Data.Count() / 1024); // Size in kB DebugDrawVB->Flush(context); } } @@ -869,8 +871,8 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe Matrix mvp; Matrix::Multiply(geometry.Transform, vp, mvp); Matrix::Transpose(mvp, tmp.ViewProjection); + auto state = data.EnableDepthTest ? (geometry.Lines ? &DebugDrawPsLinesDepthTest : &DebugDrawPsTrianglesDepthTest) : (geometry.Lines ? &DebugDrawPsLinesDefault : &DebugDrawPsTrianglesDefault); context->UpdateCB(cb, &tmp); - auto state = data.EnableDepthTest ? &DebugDrawPsLinesDepthTest : &DebugDrawPsLinesDefault; context->SetState(state->Get(enableDepthWrite, true)); context->BindVB(ToSpan(&geometry.Buffer, 1)); context->Draw(0, geometry.Buffer->GetElementsCount()); @@ -918,8 +920,9 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe Matrix mvp; Matrix::Multiply(geometry.Transform, vp, mvp); Matrix::Transpose(mvp, tmp.ViewProjection); + auto state = geometry.Lines ? &DebugDrawPsLinesDefault : &DebugDrawPsTrianglesDefault; context->UpdateCB(cb, &tmp); - context->SetState(DebugDrawPsLinesDefault.Get(false, false)); + context->SetState(state->Get(false, false)); context->BindVB(ToSpan(&geometry.Buffer, 1)); context->Draw(0, geometry.Buffer->GetElementsCount()); } @@ -1164,6 +1167,7 @@ void DebugDraw::DrawLines(GPUBuffer* lines, const Matrix& transform, float durat auto& geometry = debugDrawData.GeometryBuffers.AddOne(); geometry.Buffer = lines; geometry.TimeLeft = duration; + geometry.Lines = true; geometry.Transform = transform * Matrix::Translation(-Context->Origin); } @@ -1520,6 +1524,23 @@ void DebugDraw::DrawTriangles(const Span& vertices, const Matrix& transf } } +void DebugDraw::DrawTriangles(GPUBuffer* triangles, const Matrix& transform, float duration, bool depthTest) +{ + if (triangles == nullptr || triangles->GetSize() == 0) + return; + if (triangles->GetSize() % (sizeof(Vertex) * 3) != 0) + { + DebugLog::ThrowException("Cannot draw debug lines with incorrect amount of items in array"); + return; + } + auto& debugDrawData = depthTest ? Context->DebugDrawDepthTest : Context->DebugDrawDefault; + auto& geometry = debugDrawData.GeometryBuffers.AddOne(); + geometry.Buffer = triangles; + geometry.TimeLeft = duration; + geometry.Lines = false; + geometry.Transform = transform * Matrix::Translation(-Context->Origin); +} + void DebugDraw::DrawTriangles(const Array& vertices, const Color& color, float duration, bool depthTest) { DrawTriangles(Span(vertices.Get(), vertices.Count()), color, duration, depthTest); diff --git a/Source/Engine/Debug/DebugDraw.h b/Source/Engine/Debug/DebugDraw.h index aa3836105..c3ea5f254 100644 --- a/Source/Engine/Debug/DebugDraw.h +++ b/Source/Engine/Debug/DebugDraw.h @@ -296,12 +296,21 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw /// Draws the triangles. /// /// The triangle vertices list (must have multiple of 3 elements). - /// The custom matrix used to transform all line vertices. + /// The custom matrix used to transform all triangle vertices. /// The color. /// The duration (in seconds). Use 0 to draw it only once. /// If set to true depth test will be performed, otherwise depth will be ignored. API_FUNCTION() static void DrawTriangles(const Span& vertices, const Matrix& transform, const Color& color = Color::White, float duration = 0.0f, bool depthTest = true); + /// + /// Draws the triangles using the provided vertex buffer that contains groups of 3 Vertex elements per-triangle. + /// + /// The GPU buffer with vertices for triangles (must have multiple of 3 elements). + /// The custom matrix used to transform all triangle vertices. + /// The duration (in seconds). Use 0 to draw it only once. + /// If set to true depth test will be performed, otherwise depth will be ignored. + API_FUNCTION() static void DrawTriangles(GPUBuffer* triangles, const Matrix& transform, float duration = 0.0f, bool depthTest = true); + /// /// Draws the triangles. /// @@ -315,7 +324,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw /// Draws the triangles. /// /// The triangle vertices list (must have multiple of 3 elements). - /// The custom matrix used to transform all line vertices. + /// The custom matrix used to transform all triangle vertices. /// The color. /// The duration (in seconds). Use 0 to draw it only once. /// If set to true depth test will be performed, otherwise depth will be ignored. @@ -336,7 +345,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw /// /// The triangle vertices list. /// The triangle indices list (must have multiple of 3 elements). - /// The custom matrix used to transform all line vertices. + /// The custom matrix used to transform all triangle vertices. /// The color. /// The duration (in seconds). Use 0 to draw it only once. /// If set to true depth test will be performed, otherwise depth will be ignored. @@ -357,7 +366,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw /// /// The triangle vertices list. /// The triangle indices list (must have multiple of 3 elements). - /// The custom matrix used to transform all line vertices. + /// The custom matrix used to transform all triangle vertices. /// The color. /// The duration (in seconds). Use 0 to draw it only once. /// If set to true depth test will be performed, otherwise depth will be ignored. @@ -376,7 +385,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw /// Draws the triangles. /// /// The triangle vertices list (must have multiple of 3 elements). - /// The custom matrix used to transform all line vertices. + /// The custom matrix used to transform all triangle vertices. /// The color. /// The duration (in seconds). Use 0 to draw it only once. /// If set to true depth test will be performed, otherwise depth will be ignored. @@ -395,7 +404,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw /// Draws the triangles. /// /// The triangle vertices list (must have multiple of 3 elements). - /// The custom matrix used to transform all line vertices. + /// The custom matrix used to transform all triangle vertices. /// The color. /// The duration (in seconds). Use 0 to draw it only once. /// If set to true depth test will be performed, otherwise depth will be ignored. @@ -416,7 +425,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw /// /// The triangle vertices list. /// The triangle indices list (must have multiple of 3 elements). - /// The custom matrix used to transform all line vertices. + /// The custom matrix used to transform all triangle vertices. /// The color. /// The duration (in seconds). Use 0 to draw it only once. /// If set to true depth test will be performed, otherwise depth will be ignored. @@ -437,7 +446,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw /// /// The triangle vertices list. /// The triangle indices list (must have multiple of 3 elements). - /// The custom matrix used to transform all line vertices. + /// The custom matrix used to transform all triangle vertices. /// The color. /// The duration (in seconds). Use 0 to draw it only once. /// If set to true depth test will be performed, otherwise depth will be ignored. diff --git a/Source/Engine/Physics/Actors/Cloth.cpp b/Source/Engine/Physics/Actors/Cloth.cpp index 889a0874e..b184bfbda 100644 --- a/Source/Engine/Physics/Actors/Cloth.cpp +++ b/Source/Engine/Physics/Actors/Cloth.cpp @@ -335,6 +335,7 @@ void Cloth::DrawPhysicsDebug(RenderView& view) #if WITH_CLOTH && COMPILE_WITH_DEBUG_DRAW if (_cloth) { + PROFILE_CPU(); const ModelInstanceActor::MeshReference mesh = GetMesh(); if (mesh.Actor == nullptr) return; diff --git a/Source/Engine/Terrain/Terrain.cpp b/Source/Engine/Terrain/Terrain.cpp index b39b7ef2f..f8c9bc22e 100644 --- a/Source/Engine/Terrain/Terrain.cpp +++ b/Source/Engine/Terrain/Terrain.cpp @@ -240,6 +240,7 @@ void Terrain::DrawChunk(const RenderContext& renderContext, const Int2& patchCoo void Terrain::DrawPhysicsDebug(RenderView& view) { + PROFILE_CPU(); for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++) { _patches[pathIndex]->DrawPhysicsDebug(view); diff --git a/Source/Engine/Terrain/TerrainPatch.cpp b/Source/Engine/Terrain/TerrainPatch.cpp index b2f668a9d..1c754d843 100644 --- a/Source/Engine/Terrain/TerrainPatch.cpp +++ b/Source/Engine/Terrain/TerrainPatch.cpp @@ -104,6 +104,8 @@ void TerrainPatch::Init(Terrain* terrain, int16 x, int16 z) #endif #if USE_EDITOR _collisionTriangles.Resize(0); + SAFE_DELETE_GPU_RESOURCE(_collisionTrianglesBuffer); + _collisionTrianglesBufferDirty = true; #endif _collisionVertices.Resize(0); } @@ -120,6 +122,9 @@ TerrainPatch::~TerrainPatch() #if TERRAIN_USE_PHYSICS_DEBUG SAFE_DELETE_GPU_RESOURCE(_debugLines); #endif +#if USE_EDITOR + SAFE_DELETE_GPU_RESOURCE(_collisionTrianglesBuffer); +#endif } RawDataAsset* TerrainPatch::GetHeightfield() const @@ -2225,6 +2230,8 @@ void TerrainPatch::DestroyCollision() #endif #if USE_EDITOR _collisionTriangles.Resize(0); + SAFE_DELETE(_collisionTrianglesBuffer); + _collisionTrianglesBufferDirty = true; #endif _collisionVertices.Resize(0); } @@ -2317,7 +2324,32 @@ void TerrainPatch::DrawPhysicsDebug(RenderView& view) return; if (view.Mode == ViewMode::PhysicsColliders) { - DEBUG_DRAW_TRIANGLES(GetCollisionTriangles(), Color::DarkOliveGreen, 0, true); + const auto& triangles = GetCollisionTriangles(); + typedef DebugDraw::Vertex Vertex; + if (!_collisionTrianglesBuffer) + _collisionTrianglesBuffer = GPUDevice::Instance->CreateBuffer(TEXT("Terrain.CollisionTriangles")); + const uint32 count = triangles.Count(); + if (_collisionTrianglesBuffer->GetElementsCount() != count) + { + if (_collisionTrianglesBuffer->Init(GPUBufferDescription::Vertex(Vertex::GetLayout(), sizeof(Vertex), count))) + return; + _collisionTrianglesBufferDirty = true; + } + if (_collisionTrianglesBufferDirty) + { + const Color32 color(Color::DarkOliveGreen); + Array vertices; + vertices.Resize((int32)count); + const Vector3* src = triangles.Get(); + Vertex* dst = vertices.Get(); + for (uint32 i = 0; i < count; i++) + { + dst[i] = { (Float3)src[i], color }; + } + _collisionTrianglesBuffer->SetData(vertices.Get(), _collisionTrianglesBuffer->GetSize()); + _collisionTrianglesBufferDirty = false; + } + DebugDraw::DrawTriangles(_collisionTrianglesBuffer, Matrix::Identity, 0, true); } else { @@ -2351,6 +2383,7 @@ const Array& TerrainPatch::GetCollisionTriangles() PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols); _collisionTriangles.Resize((rows - 1) * (cols - 1) * 6); + _collisionTrianglesBufferDirty = true; Vector3* data = _collisionTriangles.Get(); #define GET_VERTEX(x, y) Vector3 v##x##y((float)(row + (x)), PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, row + (x), col + (y)) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y))); Vector3::Transform(v##x##y, world, v##x##y) diff --git a/Source/Engine/Terrain/TerrainPatch.h b/Source/Engine/Terrain/TerrainPatch.h index 8e4277068..7d85c5b1c 100644 --- a/Source/Engine/Terrain/TerrainPatch.h +++ b/Source/Engine/Terrain/TerrainPatch.h @@ -49,6 +49,8 @@ private: #endif #if USE_EDITOR Array _collisionTriangles; // TODO: large-worlds + class GPUBuffer* _collisionTrianglesBuffer = nullptr; + bool _collisionTrianglesBufferDirty = true; #endif Array _collisionVertices; // TODO: large-worlds From 83b3b1af76d2b93b8b7d28c50e402f5cd5f975e3 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 1 Jun 2025 09:19:49 +0200 Subject: [PATCH 64/77] Fix terrain collision debug draw flickering when moving camera in Large Worlds #3260 --- Source/Engine/Debug/DebugDraw.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Source/Engine/Debug/DebugDraw.cpp b/Source/Engine/Debug/DebugDraw.cpp index 44f0f2ce1..2bb921f70 100644 --- a/Source/Engine/Debug/DebugDraw.cpp +++ b/Source/Engine/Debug/DebugDraw.cpp @@ -235,6 +235,14 @@ void TeleportList(const Float3& delta, Array& list) } } +void TeleportList(const Float3& delta, Array& list) +{ + for (auto& v : list) + { + v.Transform.SetTranslation(v.Transform.GetTranslation() + delta); + } +} + struct DebugDrawData { Array GeometryBuffers; @@ -303,6 +311,7 @@ struct DebugDrawData void Teleport(const Float3& delta) { + TeleportList(delta, GeometryBuffers); TeleportList(delta, DefaultLines); TeleportList(delta, OneFrameLines); TeleportList(delta, DefaultTriangles); From 89baa91552421384e4aaa81906440c15ea9bcaae Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 1 Jun 2025 09:20:11 +0200 Subject: [PATCH 65/77] Don't sue --- Source/Editor/Surface/SurfaceNode.cs | 2 +- Source/Engine/Debug/DebugDraw.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Editor/Surface/SurfaceNode.cs b/Source/Editor/Surface/SurfaceNode.cs index 59f379bde..8a42a7a92 100644 --- a/Source/Editor/Surface/SurfaceNode.cs +++ b/Source/Editor/Surface/SurfaceNode.cs @@ -409,7 +409,7 @@ namespace FlaxEditor.Surface /// /// Called after adding the control to the surface after paste. /// - /// The nodes IDs mapping (original node ID to pasted node ID). Can be sued to update internal node's data after paste operation from the original data. + /// The nodes IDs mapping (original node ID to pasted node ID). Can be used to update internal node's data after paste operation from the original data. public virtual void OnPasted(System.Collections.Generic.Dictionary idsMapping) { } diff --git a/Source/Engine/Debug/DebugDraw.h b/Source/Engine/Debug/DebugDraw.h index c3ea5f254..3b51c0e13 100644 --- a/Source/Engine/Debug/DebugDraw.h +++ b/Source/Engine/Debug/DebugDraw.h @@ -74,7 +74,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw API_FUNCTION() static bool CanClear(void* context = nullptr); #endif - // Gets the last view position when rendering the current context. Can be sued for custom culling or LODing when drawing more complex shapes. + // Gets the last view position when rendering the current context. Can be used for custom culling or LODing when drawing more complex shapes. static Vector3 GetViewPos(); /// From 619c5ac3b0dc4a8eaee00784bb4158f3b3ec229a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 1 Jun 2025 15:45:27 +0200 Subject: [PATCH 66/77] Fix unit of gravity in doc comment #3509 --- Source/Engine/Physics/PhysicsSettings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Physics/PhysicsSettings.h b/Source/Engine/Physics/PhysicsSettings.h index 897d2d633..cfb1bc75e 100644 --- a/Source/Engine/Physics/PhysicsSettings.h +++ b/Source/Engine/Physics/PhysicsSettings.h @@ -59,7 +59,7 @@ API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings", NoConstructor) class public: /// - /// The default gravity force value (in cm^2/s). + /// The default gravity value (in cm/(s^2)). /// API_FIELD(Attributes="EditorOrder(0), EditorDisplay(\"Simulation\")") Vector3 DefaultGravity = Vector3(0, -981.0f, 0); From 66add1f3bd412dd8917e1cde90bf271ce181c2ee Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Sun, 1 Jun 2025 16:01:55 +0200 Subject: [PATCH 67/77] fix missing whitespaces --- Source/Engine/Core/Math/Quaternion.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Core/Math/Quaternion.cs b/Source/Engine/Core/Math/Quaternion.cs index 935354354..9029ed365 100644 --- a/Source/Engine/Core/Math/Quaternion.cs +++ b/Source/Engine/Core/Math/Quaternion.cs @@ -1149,7 +1149,7 @@ namespace FlaxEngine } /// - /// Gets the quaternion that will rotate vector from into vector to, around their plan perpendicular axis.The input vectors don't need to be normalized. + /// Gets the quaternion that will rotate vector from into vector to, around their plan perpendicular axis. The input vectors don't need to be normalized. /// /// The source vector. /// The destination vector. @@ -1179,7 +1179,7 @@ namespace FlaxEngine } /// - /// Gets the quaternion that will rotate vector from into vector to, around their plan perpendicular axis.The input vectors don't need to be normalized. + /// Gets the quaternion that will rotate the from into vector to, around their plan perpendicular axis. The input vectors don't need to be normalized. /// /// The source vector. /// The destination vector. From 3083e3f6111200cc87f7201345a713b1b543092e Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Sun, 1 Jun 2025 16:04:30 +0200 Subject: [PATCH 68/77] fix wrong unit in physics settings --- Source/Engine/Physics/PhysicsSettings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Physics/PhysicsSettings.h b/Source/Engine/Physics/PhysicsSettings.h index 897d2d633..00dfa62b3 100644 --- a/Source/Engine/Physics/PhysicsSettings.h +++ b/Source/Engine/Physics/PhysicsSettings.h @@ -59,7 +59,7 @@ API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings", NoConstructor) class public: /// - /// The default gravity force value (in cm^2/s). + /// The default gravity acceleration value (in cm/(s^2)). /// API_FIELD(Attributes="EditorOrder(0), EditorDisplay(\"Simulation\")") Vector3 DefaultGravity = Vector3(0, -981.0f, 0); From ae2088bb9dc8971f3e007c70d0968b49476b8c51 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 2 Jun 2025 00:06:13 +0200 Subject: [PATCH 69/77] Fix Android NDK version parsing when using beta build #3504 --- Source/Tools/Flax.Build/Platforms/Android/AndroidNdk.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Source/Tools/Flax.Build/Platforms/Android/AndroidNdk.cs b/Source/Tools/Flax.Build/Platforms/Android/AndroidNdk.cs index 0f2fc517c..a1018368b 100644 --- a/Source/Tools/Flax.Build/Platforms/Android/AndroidNdk.cs +++ b/Source/Tools/Flax.Build/Platforms/Android/AndroidNdk.cs @@ -87,6 +87,13 @@ namespace Flax.Build.Platforms if (lines.Length > 1) { var ver = lines[1].Substring(lines[1].IndexOf(" = ", StringComparison.Ordinal) + 2); + if (ver.Contains('-')) + { + // Ignore any beta tags (eg. '29.0.13113456-beta1') + var parts = ver.Split('-'); + if (parts.Length > 1) + ver = parts[0]; + } if (Version.TryParse(ver, out var v)) { Version = v; From 28c70f50781d7f5476add0d77952c78e3360b364 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 2 Jun 2025 11:00:33 +0200 Subject: [PATCH 70/77] Fix some editor UI #3460 #3491 --- Source/Editor/CustomEditors/Dedicated/ActorEditor.cs | 11 +++++------ Source/Editor/GUI/Tree/TreeNode.cs | 11 +++++++---- Source/Editor/Windows/ContentWindow.cs | 1 + 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs index f627c5ceb..0c17cf9fa 100644 --- a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs @@ -9,7 +9,6 @@ using FlaxEditor.CustomEditors.Elements; using FlaxEditor.GUI; using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.Tree; -using FlaxEditor.Modules; using FlaxEditor.Scripting; using FlaxEditor.Windows; using FlaxEditor.Windows.Assets; @@ -263,7 +262,7 @@ namespace FlaxEditor.CustomEditors.Dedicated if (editor.Values.GetAttributes().FirstOrDefault(x => x is EditorDisplayAttribute) is EditorDisplayAttribute editorDisplayAttribute && !string.IsNullOrEmpty(editorDisplayAttribute.Name)) node.Text = $"{Utilities.Utils.GetPropertyNameUI(editorDisplayAttribute.Name)} ({Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name)})"; else - node.Text = $"{Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name)}"; + node.Text = Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name); } else if (sceneObject is Actor actor) node.Text = $"{actor.Name} ({Utilities.Utils.GetPropertyNameUI(sceneObject.GetType().Name)})"; @@ -278,8 +277,8 @@ namespace FlaxEditor.CustomEditors.Dedicated // Common type else if (editor.Values.Info != ScriptMemberInfo.Null) { - if (editor.Values.GetAttributes().FirstOrDefault(x => x is EditorDisplayAttribute) is EditorDisplayAttribute editorDisplayAttribute - && !string.IsNullOrEmpty(editorDisplayAttribute.Name) + if (editor.Values.GetAttributes().FirstOrDefault(x => x is EditorDisplayAttribute) is EditorDisplayAttribute editorDisplayAttribute + && !string.IsNullOrEmpty(editorDisplayAttribute.Name) && !editorDisplayAttribute.Name.Contains("_inline")) node.Text = $"{Utilities.Utils.GetPropertyNameUI(editorDisplayAttribute.Name)} ({Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name)})"; else @@ -406,7 +405,7 @@ namespace FlaxEditor.CustomEditors.Dedicated var presenter = new CustomEditorPresenter(null); var layout = new CustomElementsContainer(); var rootNode = CreateDiffTree(rootActor, presenter, layout); - + // Skip if no changes detected if (rootNode == null) { @@ -415,7 +414,7 @@ namespace FlaxEditor.CustomEditors.Dedicated cm1.Show(target, targetLocation); return; } - + // Create context menu var cm = new PrefabDiffContextMenu(); cm.Tree.AddChild(rootNode); diff --git a/Source/Editor/GUI/Tree/TreeNode.cs b/Source/Editor/GUI/Tree/TreeNode.cs index bed32e797..40c276bf4 100644 --- a/Source/Editor/GUI/Tree/TreeNode.cs +++ b/Source/Editor/GUI/Tree/TreeNode.cs @@ -760,20 +760,21 @@ namespace FlaxEditor.GUI.Tree // Show tree guidelines if (Editor.Instance.Options.Options.Interface.ShowTreeLines) { - TreeNode parentNode = Parent as TreeNode; + ContainerControl parent = Parent; + TreeNode parentNode = parent as TreeNode; bool thisNodeIsLast = false; - while (parentNode != null && (parentNode != ParentTree.Children[0] || _tree.DrawRootTreeLine)) + while (parentNode != null && (parentNode != tree.Children[0] || tree.DrawRootTreeLine)) { float bottomOffset = 0; float topOffset = 0; - if (Parent == parentNode && this == Parent.Children[0]) + if (parent == parentNode && this == parent.Children[0]) topOffset = 2; if (thisNodeIsLast && parentNode.Children.Count == 1) bottomOffset = topOffset != 0 ? 4 : 2; - if (Parent == parentNode && this == Parent.Children[^1] && !_opened) + if (parent == parentNode && this == parent.Children[^1] && !_opened) { thisNodeIsLast = true; bottomOffset = topOffset != 0 ? 4 : 2; @@ -784,6 +785,8 @@ namespace FlaxEditor.GUI.Tree if (_iconCollaped.IsValid) leftOffset += 18; var lineRect1 = new Rectangle(parentNode.TextRect.Left - leftOffset, parentNode.HeaderRect.Top + topOffset, 1, parentNode.HeaderRect.Height - bottomOffset); + if (HasAnyVisibleChild && CustomArrowRect.HasValue && CustomArrowRect.Value.Intersects(lineRect1)) + lineRect1 = Rectangle.Empty; // Skip drawing line if it's overlapping the arrow rectangle Render2D.FillRectangle(lineRect1, isSelected ? style.ForegroundGrey : style.LightBackground); parentNode = parentNode.Parent as TreeNode; } diff --git a/Source/Editor/Windows/ContentWindow.cs b/Source/Editor/Windows/ContentWindow.cs index f63db04bd..cf33d0b63 100644 --- a/Source/Editor/Windows/ContentWindow.cs +++ b/Source/Editor/Windows/ContentWindow.cs @@ -204,6 +204,7 @@ namespace FlaxEditor.Windows // Content structure tree _tree = new Tree(false) { + DrawRootTreeLine = false, Parent = _contentTreePanel, }; _tree.SelectedChanged += OnTreeSelectionChanged; From 4d9407e4e9087307e2e6a0bde2caf14705443990 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 2 Jun 2025 11:03:16 +0200 Subject: [PATCH 71/77] Merge code on properties objects locking to use the same path for prefab and scene properties panels --- .../CustomEditors/CustomEditorPresenter.cs | 11 +++++++ .../CustomEditors/Dedicated/ActorEditor.cs | 33 ++++++------------- .../Windows/Assets/BehaviorTreeWindow.cs | 6 ++++ .../Windows/Assets/PrefabWindow.Selection.cs | 2 +- Source/Editor/Windows/Assets/PrefabWindow.cs | 2 +- Source/Editor/Windows/PropertiesWindow.cs | 8 ++--- 6 files changed, 33 insertions(+), 29 deletions(-) diff --git a/Source/Editor/CustomEditors/CustomEditorPresenter.cs b/Source/Editor/CustomEditors/CustomEditorPresenter.cs index a518d92a1..1030abfda 100644 --- a/Source/Editor/CustomEditors/CustomEditorPresenter.cs +++ b/Source/Editor/CustomEditors/CustomEditorPresenter.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using FlaxEditor.SceneGraph; using FlaxEditor.Scripting; using FlaxEngine; using FlaxEngine.GUI; @@ -52,6 +53,16 @@ namespace FlaxEditor.CustomEditors /// /// The nodes to select public void Select(List nodes); + + /// + /// Gets the current selection. + /// + public List Selection { get; } + + /// + /// Indication of if the properties window is locked on specific objects. + /// + public bool LockSelection { get; set; } } /// diff --git a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs index 0c17cf9fa..98eeb881b 100644 --- a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs @@ -132,35 +132,22 @@ namespace FlaxEditor.CustomEditors.Dedicated var actor = (Actor)Values[0]; var scriptType = TypeUtils.GetType(actor.TypeName); var item = scriptType.ContentItem; - if (Presenter.Owner is PropertiesWindow propertiesWindow) + if (Presenter.Owner != null) { - var lockButton = cm.AddButton(propertiesWindow.LockObjects ? "Unlock" : "Lock"); + var lockButton = cm.AddButton(Presenter.Owner.LockSelection ? "Unlock" : "Lock"); lockButton.ButtonClicked += button => { - propertiesWindow.LockObjects = !propertiesWindow.LockObjects; + var owner = Presenter?.Owner; + if (owner == null) + return; + owner.LockSelection = !owner.LockSelection; // Reselect current selection - if (!propertiesWindow.LockObjects && Editor.Instance.SceneEditing.SelectionCount > 0) + if (!owner.LockSelection && owner.Selection.Count > 0) { - var cachedSelection = Editor.Instance.SceneEditing.Selection.ToArray(); - Editor.Instance.SceneEditing.Select(null); - Editor.Instance.SceneEditing.Select(cachedSelection); - } - }; - } - else if (Presenter.Owner is PrefabWindow prefabWindow) - { - var lockButton = cm.AddButton(prefabWindow.LockSelectedObjects ? "Unlock" : "Lock"); - lockButton.ButtonClicked += button => - { - prefabWindow.LockSelectedObjects = !prefabWindow.LockSelectedObjects; - - // Reselect current selection - if (!prefabWindow.LockSelectedObjects && prefabWindow.Selection.Count > 0) - { - var cachedSelection = prefabWindow.Selection.ToList(); - prefabWindow.Select(null); - prefabWindow.Select(cachedSelection); + var cachedSelection = owner.Selection.ToList(); + owner.Select(null); + owner.Select(cachedSelection); } }; } diff --git a/Source/Editor/Windows/Assets/BehaviorTreeWindow.cs b/Source/Editor/Windows/Assets/BehaviorTreeWindow.cs index 2fd71d860..2b86664f2 100644 --- a/Source/Editor/Windows/Assets/BehaviorTreeWindow.cs +++ b/Source/Editor/Windows/Assets/BehaviorTreeWindow.cs @@ -635,5 +635,11 @@ namespace FlaxEditor.Windows.Assets public void Select(List nodes) { } + + /// + public List Selection => new List(); + + /// + public bool LockSelection { get; set; } } } diff --git a/Source/Editor/Windows/Assets/PrefabWindow.Selection.cs b/Source/Editor/Windows/Assets/PrefabWindow.Selection.cs index f6d3f1669..03e2a9652 100644 --- a/Source/Editor/Windows/Assets/PrefabWindow.Selection.cs +++ b/Source/Editor/Windows/Assets/PrefabWindow.Selection.cs @@ -51,7 +51,7 @@ namespace FlaxEditor.Windows.Assets /// The selection before the change. public void OnSelectionChanged(SceneGraphNode[] before) { - if (LockSelectedObjects) + if (LockSelection) return; Undo.AddAction(new SelectionChangeAction(before, Selection.ToArray(), OnSelectionUndo)); diff --git a/Source/Editor/Windows/Assets/PrefabWindow.cs b/Source/Editor/Windows/Assets/PrefabWindow.cs index 1b2ca48bc..44c21d863 100644 --- a/Source/Editor/Windows/Assets/PrefabWindow.cs +++ b/Source/Editor/Windows/Assets/PrefabWindow.cs @@ -78,7 +78,7 @@ namespace FlaxEditor.Windows.Assets /// /// Indication of if the prefab window selection is locked on specific objects. /// - public bool LockSelectedObjects + public bool LockSelection { get => _lockSelection; set diff --git a/Source/Editor/Windows/PropertiesWindow.cs b/Source/Editor/Windows/PropertiesWindow.cs index 5ca2d3f53..e90003038 100644 --- a/Source/Editor/Windows/PropertiesWindow.cs +++ b/Source/Editor/Windows/PropertiesWindow.cs @@ -45,7 +45,7 @@ namespace FlaxEditor.Windows /// /// Indication of if the properties window is locked on specific objects. /// - public bool LockObjects + public bool LockSelection { get => _lockObjects; set @@ -87,9 +87,9 @@ namespace FlaxEditor.Windows if (Level.ScenesCount > 1) return; _actorScrollValues.Clear(); - if (LockObjects) + if (LockSelection) { - LockObjects = false; + LockSelection = false; Presenter.Deselect(); } } @@ -122,7 +122,7 @@ namespace FlaxEditor.Windows private void OnSelectionChanged() { - if (LockObjects) + if (LockSelection) return; // Update selected objects From 6c499e877f41e2debf065cb44844775057b09d61 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 2 Jun 2025 11:50:10 +0200 Subject: [PATCH 72/77] Fix prefab diff in Editor on mesh reference --- Source/Engine/Level/MeshReference.cs | 22 +++++++++++++++++++ Source/Engine/Serialization/JsonSerializer.cs | 9 +++++++- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 Source/Engine/Level/MeshReference.cs diff --git a/Source/Engine/Level/MeshReference.cs b/Source/Engine/Level/MeshReference.cs new file mode 100644 index 000000000..14ef0c72b --- /dev/null +++ b/Source/Engine/Level/MeshReference.cs @@ -0,0 +1,22 @@ +// Copyright (c) Wojciech Figat. All rights reserved. + + +using FlaxEngine.Json; + +namespace FlaxEngine +{ + partial class ModelInstanceActor + { + partial struct MeshReference : ICustomValueEquals + { + /// + public bool ValueEquals(object other) + { + var o = (MeshReference)other; + return JsonSerializer.ValueEquals(Actor, o.Actor) && + LODIndex == o.LODIndex && + MeshIndex == o.MeshIndex; + } + } + } +} diff --git a/Source/Engine/Serialization/JsonSerializer.cs b/Source/Engine/Serialization/JsonSerializer.cs index de1556577..4321ffa36 100644 --- a/Source/Engine/Serialization/JsonSerializer.cs +++ b/Source/Engine/Serialization/JsonSerializer.cs @@ -27,6 +27,11 @@ namespace FlaxEngine.Json } } + internal interface ICustomValueEquals + { + bool ValueEquals(object other); + } + partial class JsonSerializer { internal class SerializerCache @@ -262,7 +267,7 @@ namespace FlaxEngine.Json return true; if (objA == null || objB == null) return false; - + // Special case when saving reference to prefab object and the objects are different but the point to the same prefab object // In that case, skip saving reference as it's defined in prefab (will be populated via IdsMapping during deserialization) if (objA is SceneObject sceneA && objB is SceneObject sceneB && sceneA && sceneB && sceneA.HasPrefabLink && sceneB.HasPrefabLink) @@ -311,6 +316,8 @@ namespace FlaxEngine.Json return !bEnumerator.MoveNext(); } + if (objA is ICustomValueEquals customValueEquals && objA.GetType() == objB.GetType()) + return customValueEquals.ValueEquals(objB); return objA.Equals(objB); #endif } From eb90ab84f20bd4bbc960a3c16dbb6bcebc82d10a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 2 Jun 2025 13:17:51 +0200 Subject: [PATCH 73/77] Fix performing layout after changing selected tab #3467 #3487 --- Source/Editor/GUI/Tabs/Tabs.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Editor/GUI/Tabs/Tabs.cs b/Source/Editor/GUI/Tabs/Tabs.cs index f2bd260d4..7555185e6 100644 --- a/Source/Editor/GUI/Tabs/Tabs.cs +++ b/Source/Editor/GUI/Tabs/Tabs.cs @@ -47,6 +47,7 @@ namespace FlaxEditor.GUI.Tabs if (EnabledInHierarchy && Tab.Enabled) { Tabs.SelectedTab = Tab; + Tab.PerformLayout(true); Tabs.Focus(); } return true; From 1d0a0a409de70502304b6702265c12b17a9d4c07 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 2 Jun 2025 13:40:27 +0200 Subject: [PATCH 74/77] Fix panel scroll bars update to be performed once again if controls are gets changed during layout #3470 #3486 --- Source/Engine/UI/GUI/Panels/Panel.cs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Source/Engine/UI/GUI/Panels/Panel.cs b/Source/Engine/UI/GUI/Panels/Panel.cs index 01c3bb61d..ff5483d0f 100644 --- a/Source/Engine/UI/GUI/Panels/Panel.cs +++ b/Source/Engine/UI/GUI/Panels/Panel.cs @@ -20,6 +20,7 @@ namespace FlaxEngine.GUI private Color _scrollbarTrackColor; private Color _scrollbarThumbColor; private Color _scrollbarThumbSelectedColor; + private Rectangle _controlsBoundsBeforeLayout; /// /// The cached scroll area bounds. Used to scroll contents of the panel control. Cached during performing layout. @@ -530,8 +531,25 @@ namespace FlaxEngine.GUI { // Arrange controls and get scroll bounds ArrangeAndGetBounds(); + UpdateScrollBars(); + _controlsBoundsBeforeLayout = _controlsBounds; + } - // Update scroll bars + /// + protected override void PerformLayoutAfterChildren() + { + // If controls area changed during layout then update scroll bars again + ArrangeAndGetBounds(); + if (_controlsBoundsBeforeLayout != _controlsBounds) + { + UpdateScrollBars(); + } + + base.PerformLayoutAfterChildren(); + } + + private void UpdateScrollBars() + { var controlsBounds = _controlsBounds; var scrollBounds = controlsBounds; _scrollMargin.ExpandRectangle(ref scrollBounds); From 057489e5b9cfe213f5b68a8d4e47ca5a9c9a3599 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 2 Jun 2025 14:42:18 +0200 Subject: [PATCH 75/77] Fix Output Log scroll when using search #3442 #3456 --- Source/Editor/Windows/OutputLogWindow.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Editor/Windows/OutputLogWindow.cs b/Source/Editor/Windows/OutputLogWindow.cs index cba0ba8d9..6fc0659d7 100644 --- a/Source/Editor/Windows/OutputLogWindow.cs +++ b/Source/Editor/Windows/OutputLogWindow.cs @@ -984,6 +984,10 @@ namespace FlaxEditor.Windows var cachedOutputTargetViewOffset = _output.TargetViewOffset; var isBottomScroll = _vScroll.Value >= _vScroll.Maximum - (_scrollSize * 2) || wasEmpty; _output.Text = _textBuffer.ToString(); + if (_hScroll.Maximum <= 0.0) + cachedOutputTargetViewOffset.X = 0; + if (_vScroll.Maximum <= 0.0) + cachedOutputTargetViewOffset.Y = 0; _output.TargetViewOffset = cachedOutputTargetViewOffset; _textBufferCount = _entries.Count; if (!_vScroll.IsThumbClicked) From b51ba58063588217d72cd297820450bb6c7952db Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 2 Jun 2025 14:56:51 +0200 Subject: [PATCH 76/77] Fix crash on invalid particle data to be a soft check instead --- .../Particles/Graph/CPU/ParticleEmitterGraph.CPU.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.cpp b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.cpp index f198a3b8f..39f87d561 100644 --- a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.cpp +++ b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.cpp @@ -223,7 +223,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa #endif } #endif - ASSERT(!isnan(sphere.Radius) && !isinf(sphere.Radius) && !sphere.Center.IsNanOrInfinity()); + CHECK_RETURN(!isnan(sphere.Radius) && !isinf(sphere.Radius) && !sphere.Center.IsNanOrInfinity(), false); // Expand sphere based on the render modules rules (sprite or mesh size) for (int32 moduleIndex = 0; moduleIndex < emitter->Graph.RenderModules.Count(); moduleIndex++) @@ -244,7 +244,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa Vector2::Max(*((Vector2*)spriteSize), maxSpriteSize, maxSpriteSize); spriteSize += stride; } - ASSERT(!maxSpriteSize.IsNanOrInfinity()); + CHECK_RETURN(!maxSpriteSize.IsNanOrInfinity(), false); // Enlarge the emitter bounds sphere sphere.Radius += maxSpriteSize.MaxValue(); @@ -267,7 +267,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa if (radius > maxRadius) maxRadius = radius; } - ASSERT(!isnan(maxRadius) && !isinf(maxRadius)); + CHECK_RETURN(!isnan(maxRadius) && !isinf(maxRadius), false); // Enlarge the emitter bounds sphere sphere.Radius += maxRadius; @@ -315,7 +315,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa maxRibbonWidth = Math::Max(*((float*)ribbonWidth), maxRibbonWidth); ribbonWidth += stride; } - ASSERT(!isnan(maxRibbonWidth) && !isinf(maxRibbonWidth)); + CHECK_RETURN(!isnan(maxRibbonWidth) && !isinf(maxRibbonWidth), false); // Enlarge the emitter bounds sphere sphere.Radius += maxRibbonWidth * 0.5f; @@ -335,7 +335,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa maxRadius = Math::Max(*((float*)radius), maxRadius); radius += stride; } - ASSERT(!isnan(maxRadius) && !isinf(maxRadius)); + CHECK_RETURN(!isnan(maxRadius) && !isinf(maxRadius), false); } else { From fa89e710d85f55b0ae98cf02a5ca4ab1c2045748 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 2 Jun 2025 15:05:20 +0200 Subject: [PATCH 77/77] Fix Terrain shader error when using Position Offset #3479 --- Content/Editor/MaterialTemplates/Terrain.shader | 1 - 1 file changed, 1 deletion(-) diff --git a/Content/Editor/MaterialTemplates/Terrain.shader b/Content/Editor/MaterialTemplates/Terrain.shader index 3b786a7cd..abc444316 100644 --- a/Content/Editor/MaterialTemplates/Terrain.shader +++ b/Content/Editor/MaterialTemplates/Terrain.shader @@ -438,7 +438,6 @@ VertexOutput VS(TerrainVertexInput input) // Apply world position offset per-vertex #if USE_POSITION_OFFSET output.Geometry.WorldPosition += material.PositionOffset; - output.Geometry.PrevWorldPosition += material.PositionOffset; output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix); #endif