From e1dcd290b167260bdc6e45726ec5d6b0b7720854 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Thu, 11 Jul 2024 15:48:50 -0500 Subject: [PATCH 01/19] Add Editor update event. --- Source/Editor/Editor.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index 8af1bc9f4..f5118e74e 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -247,6 +247,11 @@ namespace FlaxEditor /// public event Action PlayModeEnd; + /// + /// Fired on Editor update + /// + public event Action EditorUpdate; + internal Editor() { Instance = this; @@ -485,6 +490,8 @@ namespace FlaxEditor { StateMachine.CurrentState.UpdateFPS(); } + + EditorUpdate?.Invoke(); // Update modules for (int i = 0; i < _modules.Count; i++) From c168ce3a7eac8eefe848fd4774086582c81a7acf Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Thu, 11 Jul 2024 17:39:11 -0500 Subject: [PATCH 02/19] Deprecate `IsActuallyPlayingSth` and add `IsActuallyPlaying` to `AudioSource` --- Source/Engine/Audio/AudioSource.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Audio/AudioSource.h b/Source/Engine/Audio/AudioSource.h index 7e3c17d80..450edf44a 100644 --- a/Source/Engine/Audio/AudioSource.h +++ b/Source/Engine/Audio/AudioSource.h @@ -277,8 +277,17 @@ public: public: /// /// Determines whether this audio source started playing audio via audio backend. After audio play it may wait for audio clip data to be loaded or streamed. + /// [Deprecated in v1.9] /// - API_PROPERTY() FORCE_INLINE bool IsActuallyPlayingSth() const + API_PROPERTY() DEPRECATED FORCE_INLINE bool IsActuallyPlayingSth() const + { + return _isActuallyPlayingSth; + } + + /// + /// Determines whether this audio source started playing audio via audio backend. After audio play it may wait for audio clip data to be loaded or streamed. + /// + API_PROPERTY() FORCE_INLINE bool IsActuallyPlaying() const { return _isActuallyPlayingSth; } From 7b4e50914057b2c48274cb3f42a8ab99d804c950 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Thu, 11 Jul 2024 18:44:55 -0500 Subject: [PATCH 03/19] Fix mesh collider not rotating correctly due to negative scale. --- Source/Engine/Physics/Colliders/MeshCollider.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Physics/Colliders/MeshCollider.cpp b/Source/Engine/Physics/Colliders/MeshCollider.cpp index 621432d0e..0027a0c28 100644 --- a/Source/Engine/Physics/Colliders/MeshCollider.cpp +++ b/Source/Engine/Physics/Colliders/MeshCollider.cpp @@ -133,7 +133,13 @@ void MeshCollider::GetGeometry(CollisionShape& collision) // Prepare scale Float3 scale = _cachedScale; const float minSize = 0.001f; - scale = Float3::Max(scale.GetAbsolute(), minSize); + Float3 scaleAbs = scale.GetAbsolute(); + if (scaleAbs.X < minSize) + scale.X = Math::Sign(scale.X) * minSize; + if (scaleAbs.Y < minSize) + scale.Y = Math::Sign(scale.Y) * minSize; + if (scaleAbs.Z < minSize) + scale.Z = Math::Sign(scale.Z) * minSize; // Setup shape (based on type) CollisionDataType type = CollisionDataType::None; From f1fc0866122aad52886ec535b0e14777d0063084 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sat, 13 Jul 2024 14:19:47 +0300 Subject: [PATCH 04/19] Fix CharacterController to not process hits against removed actors --- Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp index 80d264857..1047618b2 100644 --- a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp +++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp @@ -321,7 +321,12 @@ class CharacterControllerHitReportPhysX : public PxUserControllerHitReport { void onHit(const PxControllerHit& hit, Collision& c) { - ASSERT_LOW_LAYER(c.ThisActor && c.OtherActor); + if (c.ThisActor == nullptr || c.OtherActor == nullptr) + { + // One of the actors was deleted (eg. via RigidBody destroyed by gameplay) then skip processing this collision + return; + } + c.Impulse = Vector3::Zero; c.ThisVelocity = P2C(hit.dir) * hit.length; c.OtherVelocity = Vector3::Zero; From 35d46e23a82b221d0427b33e47c8fb610a947d82 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sat, 13 Jul 2024 15:52:57 +0300 Subject: [PATCH 05/19] Fix `CharacterController::SimpleMove` gravity displacement handling --- .../Physics/Colliders/CharacterController.cpp | 15 +++++++++++---- .../Physics/Colliders/CharacterController.h | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Physics/Colliders/CharacterController.cpp b/Source/Engine/Physics/Colliders/CharacterController.cpp index 3561da8f2..4a4452fc2 100644 --- a/Source/Engine/Physics/Colliders/CharacterController.cpp +++ b/Source/Engine/Physics/Colliders/CharacterController.cpp @@ -19,6 +19,7 @@ CharacterController::CharacterController(const SpawnParams& params) , _minMoveDistance(0.0f) , _isUpdatingTransform(false) , _upDirection(Vector3::Up) + , _gravityDisplacement(Vector3::Zero) , _nonWalkableMode(NonWalkableModes::PreventClimbing) , _lastFlags(CollisionFlags::None) { @@ -148,10 +149,16 @@ CharacterController::CollisionFlags CharacterController::GetFlags() const CharacterController::CollisionFlags CharacterController::SimpleMove(const Vector3& speed) { const float deltaTime = Time::GetCurrentSafe()->DeltaTime.GetTotalSeconds(); - Vector3 displacement = speed; - displacement += GetPhysicsScene()->GetGravity() * deltaTime; - displacement *= deltaTime; - return Move(displacement); + Vector3 displacement = speed + _gravityDisplacement; + CollisionFlags result = Move(displacement * deltaTime); + if ((static_cast(result) & static_cast(CollisionFlags::Below)) != 0) + { + // Reset accumulated gravity acceleration when we touch the ground + _gravityDisplacement = Vector3::Zero; + } + else + _gravityDisplacement += GetPhysicsScene()->GetGravity() * deltaTime; + return result; } CharacterController::CollisionFlags CharacterController::Move(const Vector3& displacement) diff --git a/Source/Engine/Physics/Colliders/CharacterController.h b/Source/Engine/Physics/Colliders/CharacterController.h index 545f4e9d9..540adc5c9 100644 --- a/Source/Engine/Physics/Colliders/CharacterController.h +++ b/Source/Engine/Physics/Colliders/CharacterController.h @@ -66,6 +66,7 @@ private: float _minMoveDistance; bool _isUpdatingTransform; Vector3 _upDirection; + Vector3 _gravityDisplacement; NonWalkableModes _nonWalkableMode; CollisionFlags _lastFlags; From d700df6afb157ffb57ac6f972dba6d07b226b2ee Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Mon, 15 Jul 2024 16:23:49 -0500 Subject: [PATCH 06/19] Add PhysX option for enabling enhanced determinism --- Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp | 2 ++ Source/Engine/Physics/PhysicsSettings.h | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp index 80d264857..60da71ad3 100644 --- a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp +++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp @@ -1256,6 +1256,8 @@ void* PhysicsBackend::CreateScene(const PhysicsSettings& settings) sceneDesc.simulationEventCallback = &scenePhysX->EventsCallback; sceneDesc.filterShader = FilterShader; sceneDesc.bounceThresholdVelocity = settings.BounceThresholdVelocity; + if (settings.EnableEnhancedDeterminism) + sceneDesc.flags |= PxSceneFlag::eENABLE_ENHANCED_DETERMINISM; switch (settings.SolverType) { case PhysicsSolverType::ProjectedGaussSeidelIterativeSolver: diff --git a/Source/Engine/Physics/PhysicsSettings.h b/Source/Engine/Physics/PhysicsSettings.h index fca1ea2d4..728a18367 100644 --- a/Source/Engine/Physics/PhysicsSettings.h +++ b/Source/Engine/Physics/PhysicsSettings.h @@ -94,10 +94,16 @@ public: API_FIELD(Attributes="EditorOrder(71), EditorDisplay(\"Simulation\")") PhysicsBroadPhaseType BroadPhaseType = PhysicsBroadPhaseType::ParallelAutomaticBoxPruning; + /// + /// Enables enhanced determinism in the simulation. This has a performance impact. + /// + API_FIELD(Attributes="EditorOrder(71), EditorDisplay(\"Simulation\")") + bool EnableEnhancedDeterminism = false; + /// /// The solver type to use in the simulation. /// - API_FIELD(Attributes="EditorOrder(72), EditorDisplay(\"Simulation\")") + API_FIELD(Attributes="EditorOrder(73), EditorDisplay(\"Simulation\")") PhysicsSolverType SolverType = PhysicsSolverType::ProjectedGaussSeidelIterativeSolver; /// From 6588a718792993922020097d209e43af391632c5 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Mon, 15 Jul 2024 18:19:14 -0500 Subject: [PATCH 07/19] Dont allow resize of layers array. --- Source/Engine/Core/Config/LayersAndTagsSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Core/Config/LayersAndTagsSettings.cs b/Source/Engine/Core/Config/LayersAndTagsSettings.cs index 005906872..9346efee7 100644 --- a/Source/Engine/Core/Config/LayersAndTagsSettings.cs +++ b/Source/Engine/Core/Config/LayersAndTagsSettings.cs @@ -18,7 +18,7 @@ namespace FlaxEditor.Content.Settings /// /// The layers names. /// - [EditorOrder(10), EditorDisplay("Layers", EditorDisplayAttribute.InlineStyle), Collection(CanResize = true, Display = CollectionAttribute.DisplayType.Inline)] + [EditorOrder(10), EditorDisplay("Layers", EditorDisplayAttribute.InlineStyle), Collection(CanResize = false, Display = CollectionAttribute.DisplayType.Inline)] public string[] Layers = new string[32]; /// From d4bf8368b1dd427d21dc5bedb8068d3007e62957 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Tue, 16 Jul 2024 11:43:04 -0500 Subject: [PATCH 08/19] Separate import settings as new tab in texture window. --- Source/Editor/Windows/Assets/TextureWindow.cs | 228 ++++++++++++------ 1 file changed, 160 insertions(+), 68 deletions(-) diff --git a/Source/Editor/Windows/Assets/TextureWindow.cs b/Source/Editor/Windows/Assets/TextureWindow.cs index cf913df2b..9d4b94024 100644 --- a/Source/Editor/Windows/Assets/TextureWindow.cs +++ b/Source/Editor/Windows/Assets/TextureWindow.cs @@ -21,54 +21,75 @@ namespace FlaxEditor.Windows.Assets /// public sealed class TextureWindow : AssetEditorWindowBase { - private sealed class ProxyEditor : GenericEditor + /// + /// Properties base class. + /// + public class PropertiesProxyBase { - public override void Initialize(LayoutElementsContainer layout) + internal TextureWindow _window; + + /// + /// Gathers parameters from the specified texture. + /// + /// The asset window. + public virtual void OnLoad(TextureWindow window) { - var window = ((PropertiesProxy)Values[0])._window; - var texture = window?.Asset; - if (texture == null || !texture.IsLoaded) - { - layout.Label("Loading...", TextAlignment.Center); - return; - } - - // Texture info - var general = layout.Group("General"); - general.Label("Format: " + texture.Format); - general.Label(string.Format("Size: {0}x{1}", texture.Width, texture.Height)).AddCopyContextMenu(); - general.Label("Mip levels: " + texture.MipLevels); - general.Label("Memory usage: " + Utilities.Utils.FormatBytesCount(texture.TotalMemoryUsage)).AddCopyContextMenu(); - - // Texture properties - var properties = layout.Group("Properties"); - var textureGroup = new CustomValueContainer(new ScriptType(typeof(int)), texture.TextureGroup, - (instance, index) => texture.TextureGroup, - (instance, index, value) => - { - texture.TextureGroup = (int)value; - window.MarkAsEdited(); - }); - properties.Property("Texture Group", textureGroup, new TextureGroupEditor(), "The texture group used by this texture."); - - // Import settings - base.Initialize(layout); - - // Reimport - layout.Space(10); - var reimportButton = layout.Button("Reimport"); - reimportButton.Button.Clicked += () => ((PropertiesProxy)Values[0]).Reimport(); + // Link + _window = window; + } + + /// + /// Clears temporary data. + /// + public void OnClean() + { + // Unlink + _window = null; } } + [CustomEditor(typeof(ProxyEditor))] + private sealed class TexturePropertiesProxy : PropertiesProxyBase + { + private sealed class ProxyEditor : GenericEditor + { + public override void Initialize(LayoutElementsContainer layout) + { + var window = ((TexturePropertiesProxy)Values[0])._window; + var texture = window?.Asset; + if (texture == null || !texture.IsLoaded) + { + layout.Label("Loading...", TextAlignment.Center); + return; + } + + // Texture info + var general = layout.Group("General"); + general.Label("Format: " + texture.Format); + general.Label(string.Format("Size: {0}x{1}", texture.Width, texture.Height)).AddCopyContextMenu(); + general.Label("Mip levels: " + texture.MipLevels); + general.Label("Memory usage: " + Utilities.Utils.FormatBytesCount(texture.TotalMemoryUsage)).AddCopyContextMenu(); + + // Texture properties + var properties = layout.Group("Properties"); + var textureGroup = new CustomValueContainer(new ScriptType(typeof(int)), texture.TextureGroup, + (instance, index) => texture.TextureGroup, + (instance, index, value) => + { + texture.TextureGroup = (int)value; + window.MarkAsEdited(); + }); + properties.Property("Texture Group", textureGroup, new TextureGroupEditor(), "The texture group used by this texture."); + } + } + } + /// - /// The texture properties proxy object. + /// The texture import properties proxy object. /// [CustomEditor(typeof(ProxyEditor))] - private sealed class PropertiesProxy + private sealed class ImportPropertiesProxy : PropertiesProxyBase { - internal TextureWindow _window; - [EditorOrder(1000), EditorDisplay("Import Settings", EditorDisplayAttribute.InlineStyle)] public FlaxEngine.Tools.TextureTool.Options ImportSettings = new(); @@ -76,10 +97,9 @@ namespace FlaxEditor.Windows.Assets /// Gathers parameters from the specified texture. /// /// The asset window. - public void OnLoad(TextureWindow window) + public override void OnLoad(TextureWindow window) { - // Link - _window = window; + base.OnLoad(window); // Try to restore target asset texture import options (useful for fast reimport) Editor.TryRestoreImportOptions(ref ImportSettings, window.Item.Path); @@ -109,22 +129,85 @@ namespace FlaxEditor.Windows.Assets public void DiscardChanges() { } - - /// - /// Clears temporary data. - /// - public void OnClean() + + private sealed class ProxyEditor : GenericEditor { - // Unlink - _window = null; + public override void Initialize(LayoutElementsContainer layout) + { + // Import settings + base.Initialize(layout); + + // Reimport + layout.Space(10); + var reimportButton = layout.Button("Reimport"); + reimportButton.Button.Clicked += () => ((ImportPropertiesProxy)Values[0]).Reimport(); + } } } + private class Tab : GUI.Tabs.Tab + { + /// + /// The presenter to use in the tab. + /// + public CustomEditorPresenter Presenter; + + /// + /// The proxy to use in the tab. + /// + public PropertiesProxyBase Proxy; + + public Tab(string text, TextureWindow window, bool modifiesAsset = true) + : base(text) + { + var scrollPanel = new Panel(ScrollBars.Vertical) + { + AnchorPreset = AnchorPresets.StretchAll, + Offsets = Margin.Zero, + Parent = this + }; + + Presenter = new CustomEditorPresenter(null); + Presenter.Panel.Parent = scrollPanel; + if (modifiesAsset) + Presenter.Modified += window.MarkAsEdited; + } + + /// + public override void OnDestroy() + { + Presenter.Deselect(); + Presenter = null; + Proxy = null; + + base.OnDestroy(); + } + } + + private class TextureTab : Tab + { + public TextureTab(TextureWindow window) + : base("Texture", window) + { + Proxy = new TexturePropertiesProxy(); + Presenter.Select(Proxy); + } + } + + private class ImportTab : Tab + { + public ImportTab(TextureWindow window) + : base("Import", window) + { + Proxy = new ImportPropertiesProxy(); + Presenter.Select(Proxy); + } + } + + private readonly GUI.Tabs.Tabs _tabs; private readonly SplitPanel _split; private readonly TexturePreview _preview; - private readonly CustomEditorPresenter _propertiesEditor; private readonly ToolStripButton _saveButton; - private readonly PropertiesProxy _properties; private bool _isWaitingForLoad; /// @@ -145,12 +228,20 @@ namespace FlaxEditor.Windows.Assets { Parent = _split.Panel1 }; + + // Properties tabs + _tabs = new() + { + AnchorPreset = AnchorPresets.StretchAll, + Offsets = Margin.Zero, + TabsSize = new Float2(60, 20), + TabsTextHorizontalAlignment = TextAlignment.Center, + UseScroll = true, + Parent = _split.Panel2 + }; - // Texture properties editor - _propertiesEditor = new CustomEditorPresenter(null); - _propertiesEditor.Panel.Parent = _split.Panel2; - _properties = new PropertiesProxy(); - _propertiesEditor.Select(_properties); + _tabs.AddTab(new TextureTab(this)); + _tabs.AddTab(new ImportTab(this)); // Toolstrip _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save"); @@ -164,7 +255,11 @@ namespace FlaxEditor.Windows.Assets /// protected override void UnlinkItem() { - _properties.OnClean(); + foreach (var child in _tabs.Children) + { + if (child is Tab tab && tab.Proxy != null) + tab.Proxy.OnClean(); + } _preview.Asset = null; _isWaitingForLoad = false; @@ -195,15 +290,6 @@ namespace FlaxEditor.Windows.Assets base.UpdateToolstrip(); } - /// - protected override void OnClose() - { - // Discard unsaved changes - _properties.DiscardChanges(); - - base.OnClose(); - } - /// public override void Save() { @@ -231,8 +317,14 @@ namespace FlaxEditor.Windows.Assets _isWaitingForLoad = false; // Init properties and parameters proxy - _properties.OnLoad(this); - _propertiesEditor.BuildLayout(); + foreach (var child in _tabs.Children) + { + if (child is Tab tab && tab.Proxy != null) + { + tab.Proxy.OnLoad(this); + tab.Presenter.BuildLayout(); + } + } // Setup ClearEditedFlag(); From e1cf41b94bcd30af56348befa7c06852d8474a6f Mon Sep 17 00:00:00 2001 From: Zode Date: Wed, 17 Jul 2024 01:12:17 +0300 Subject: [PATCH 09/19] Fix Quaternion.FromDirection giving bogus output when fed a perfect down vector --- Source/Engine/Core/Math/Quaternion.cpp | 4 ++++ Source/Engine/Core/Math/Quaternion.cs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Source/Engine/Core/Math/Quaternion.cpp b/Source/Engine/Core/Math/Quaternion.cpp index 03989dab5..5927e0665 100644 --- a/Source/Engine/Core/Math/Quaternion.cpp +++ b/Source/Engine/Core/Math/Quaternion.cpp @@ -294,6 +294,10 @@ Quaternion Quaternion::FromDirection(const Float3& direction) { RotationAxis(Float3::Left, PI_OVER_2, orientation); } + else if (Float3::Dot(direction, Float3::Down) >= 0.999f) + { + RotationAxis(Float3::Right, PI_OVER_2, orientation); + } else { Float3 right, up; diff --git a/Source/Engine/Core/Math/Quaternion.cs b/Source/Engine/Core/Math/Quaternion.cs index 86a6e4e2d..d4d0fe96c 100644 --- a/Source/Engine/Core/Math/Quaternion.cs +++ b/Source/Engine/Core/Math/Quaternion.cs @@ -654,6 +654,10 @@ namespace FlaxEngine { orientation = RotationAxis(Float3.Left, Mathf.PiOverTwo); } + else if (Float3.Dot(direction, Float3.Down) >= 0.999f) + { + orientation = RotationAxis(Float3.Right, Mathf.PiOverTwo); + } else { var right = Float3.Cross(direction, Float3.Up); From e5e1f945ea03ffa0b493abedc42538f22715cca4 Mon Sep 17 00:00:00 2001 From: Olly Rybak Date: Wed, 17 Jul 2024 10:04:14 +1000 Subject: [PATCH 10/19] Added eDETECT_CCD_CONTACT to PairFlags, hopefully properly enabling CCD --- Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp index 80d264857..ea05851a6 100644 --- a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp +++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp @@ -666,6 +666,8 @@ PxFilterFlags FilterShader( { const bool maskTest = (filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1); + auto& settings = *PhysicsSettings::Get(); + // Let triggers through if (PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1)) { @@ -697,6 +699,8 @@ PxFilterFlags FilterShader( pairFlags |= PxPairFlag::eNOTIFY_TOUCH_LOST; pairFlags |= PxPairFlag::ePOST_SOLVER_VELOCITY; pairFlags |= PxPairFlag::eNOTIFY_CONTACT_POINTS; + if (!settings.DisableCCD) + pairFlags |= PxPairFlag::eDETECT_CCD_CONTACT; return PxFilterFlag::eDEFAULT; } From 7090e85224f6a0f29f651ce511fa218379167dd9 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Tue, 16 Jul 2024 19:25:05 -0500 Subject: [PATCH 11/19] Fix not being able to drag a window tab all of the way to the right. --- Source/Editor/GUI/Docking/DockPanel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/GUI/Docking/DockPanel.cs b/Source/Editor/GUI/Docking/DockPanel.cs index 3e00f3a65..5f229f25b 100644 --- a/Source/Editor/GUI/Docking/DockPanel.cs +++ b/Source/Editor/GUI/Docking/DockPanel.cs @@ -629,7 +629,7 @@ namespace FlaxEditor.GUI.Docking internal void MoveTabRight(int index) { - if (index < _tabs.Count - 2) + if (index < _tabs.Count - 1) { var tab = _tabs[index]; _tabs.RemoveAt(index); From 12f70572b0f30b5eeb3cc1eac2aca3ee3c7c95d2 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Tue, 16 Jul 2024 20:05:27 -0500 Subject: [PATCH 12/19] Remove redundant first tab on floating window. --- Source/Editor/GUI/Docking/DockPanelProxy.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/Editor/GUI/Docking/DockPanelProxy.cs b/Source/Editor/GUI/Docking/DockPanelProxy.cs index 1234c7777..5ca4a024a 100644 --- a/Source/Editor/GUI/Docking/DockPanelProxy.cs +++ b/Source/Editor/GUI/Docking/DockPanelProxy.cs @@ -187,6 +187,10 @@ namespace FlaxEditor.GUI.Docking var headerRect = HeaderRectangle; var tabsCount = _panel.TabsCount; + // Return and don't draw tab if only 1 window and it is floating + if (_panel.IsFloating && tabsCount == 1 && _panel.ChildPanelsCount == 0) + return; + // Check if has only one window docked if (tabsCount == 1) { @@ -501,7 +505,10 @@ namespace FlaxEditor.GUI.Docking /// public override void GetDesireClientArea(out Rectangle rect) { - rect = new Rectangle(0, DockPanel.DefaultHeaderHeight, Width, Height - DockPanel.DefaultHeaderHeight); + if (_panel.TabsCount == 1 && _panel.IsFloating && _panel.ChildPanelsCount == 0) + rect = new Rectangle(0, 0, Width, Height); + else + rect = new Rectangle(0, DockPanel.DefaultHeaderHeight, Width, Height - DockPanel.DefaultHeaderHeight); } private DragDropEffect TrySelectTabUnderLocation(ref Float2 location) From 531c75bff95dfb67ba51c59239e3ac5213c3259f Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Tue, 16 Jul 2024 20:32:47 -0500 Subject: [PATCH 13/19] Display asset picker type. --- Source/Editor/GUI/AssetPicker.cs | 36 ++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/Source/Editor/GUI/AssetPicker.cs b/Source/Editor/GUI/AssetPicker.cs index 5c8f02a06..da40af241 100644 --- a/Source/Editor/GUI/AssetPicker.cs +++ b/Source/Editor/GUI/AssetPicker.cs @@ -105,9 +105,9 @@ namespace FlaxEditor.GUI private Rectangle Button1Rect => new Rectangle(Height + ButtonsOffset, 0, ButtonsSize, ButtonsSize); - private Rectangle Button2Rect => new Rectangle(Height + ButtonsOffset, ButtonsSize, ButtonsSize, ButtonsSize); + private Rectangle Button2Rect => new Rectangle(Height + ButtonsOffset, ButtonsSize + 2, ButtonsSize, ButtonsSize); - private Rectangle Button3Rect => new Rectangle(Height + ButtonsOffset, ButtonsSize * 2, ButtonsSize, ButtonsSize); + private Rectangle Button3Rect => new Rectangle(Height + ButtonsOffset, (ButtonsSize + 2) * 2, ButtonsSize, ButtonsSize); /// public override void Draw() @@ -149,6 +149,13 @@ namespace FlaxEditor.GUI style.Foreground, TextAlignment.Near, TextAlignment.Center); + Render2D.DrawText( + style.FontSmall, + $"{TypeUtils.GetTypeDisplayName(Validator.AssetType.Type)}", + new Rectangle(button1Rect.Right + 2, ButtonsSize + 2, sizeForTextLeft, ButtonsSize), + style.ForegroundGrey, + TextAlignment.Near, + TextAlignment.Center); } } // Check if has no item but has an asset (eg. virtual asset) @@ -171,6 +178,13 @@ namespace FlaxEditor.GUI style.Foreground, TextAlignment.Near, TextAlignment.Center); + Render2D.DrawText( + style.FontSmall, + $"{TypeUtils.GetTypeDisplayName(Validator.AssetType.Type)}", + new Rectangle(button1Rect.Right + 2, ButtonsSize + 2, sizeForTextLeft, ButtonsSize), + style.ForegroundGrey, + TextAlignment.Near, + TextAlignment.Center); } } else @@ -178,6 +192,24 @@ namespace FlaxEditor.GUI // No element selected Render2D.FillRectangle(iconRect, style.BackgroundNormal); Render2D.DrawText(style.FontMedium, "No asset\nselected", iconRect, Color.Orange, TextAlignment.Center, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, Height / DefaultIconSize); + float sizeForTextLeft = Width - button1Rect.Right; + if (sizeForTextLeft > 30) + { + Render2D.DrawText( + style.FontSmall, + $"None", + new Rectangle(button1Rect.Right + 2, 0, sizeForTextLeft, ButtonsSize), + style.Foreground, + TextAlignment.Near, + TextAlignment.Center); + Render2D.DrawText( + style.FontSmall, + $"{TypeUtils.GetTypeDisplayName(Validator.AssetType.Type)}", + new Rectangle(button1Rect.Right + 2, ButtonsSize + 2, sizeForTextLeft, ButtonsSize), + style.ForegroundGrey, + TextAlignment.Near, + TextAlignment.Center); + } } // Check if drag is over From 85a04f8e81b32442e080e9e8b6bf5dd8b362711b Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Tue, 16 Jul 2024 20:36:27 -0500 Subject: [PATCH 14/19] Perform layout of splitter panel once splitter is done being dragged. --- Source/Engine/UI/GUI/Panels/SplitPanel.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Engine/UI/GUI/Panels/SplitPanel.cs b/Source/Engine/UI/GUI/Panels/SplitPanel.cs index e721ee8a3..9203bcda0 100644 --- a/Source/Engine/UI/GUI/Panels/SplitPanel.cs +++ b/Source/Engine/UI/GUI/Panels/SplitPanel.cs @@ -130,6 +130,7 @@ namespace FlaxEngine.GUI { // Clear flag _splitterClicked = false; + PerformLayout(); // End capturing mouse EndMouseCapture(); From fe41ef619b103e61f2c6abb402fe3a5fa3334534 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Jul 2024 10:47:46 +0200 Subject: [PATCH 15/19] Improve floating dock window hidden header to handle inputs properly #2770 --- Source/Editor/GUI/Docking/DockPanelProxy.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Source/Editor/GUI/Docking/DockPanelProxy.cs b/Source/Editor/GUI/Docking/DockPanelProxy.cs index 5ca4a024a..f489b0c39 100644 --- a/Source/Editor/GUI/Docking/DockPanelProxy.cs +++ b/Source/Editor/GUI/Docking/DockPanelProxy.cs @@ -51,6 +51,7 @@ namespace FlaxEditor.GUI.Docking public DockWindow StartDragAsyncWindow; private Rectangle HeaderRectangle => new Rectangle(0, 0, Width, DockPanel.DefaultHeaderHeight); + private bool IsSingleFloatingWindow => _panel.TabsCount == 1 && _panel.IsFloating && _panel.ChildPanelsCount == 0; /// /// Initializes a new instance of the class. @@ -188,9 +189,9 @@ namespace FlaxEditor.GUI.Docking var tabsCount = _panel.TabsCount; // Return and don't draw tab if only 1 window and it is floating - if (_panel.IsFloating && tabsCount == 1 && _panel.ChildPanelsCount == 0) + if (IsSingleFloatingWindow) return; - + // Check if has only one window docked if (tabsCount == 1) { @@ -325,6 +326,9 @@ namespace FlaxEditor.GUI.Docking /// public override bool OnMouseDoubleClick(Float2 location, MouseButton button) { + if (IsSingleFloatingWindow) + return base.OnMouseDoubleClick(location, button); + // Maximize/restore on double click var tab = GetTabAtPos(location, out _); var rootWindow = tab?.RootWindow; @@ -343,6 +347,8 @@ namespace FlaxEditor.GUI.Docking /// public override bool OnMouseDown(Float2 location, MouseButton button) { + if (IsSingleFloatingWindow) + return base.OnMouseDown(location, button); MouseDownWindow = GetTabAtPos(location, out IsMouseDownOverCross); // Check buttons @@ -372,6 +378,9 @@ namespace FlaxEditor.GUI.Docking /// public override bool OnMouseUp(Float2 location, MouseButton button) { + if (IsSingleFloatingWindow) + return base.OnMouseUp(location, button); + // Check tabs under mouse position at the beginning and at the end var tab = GetTabAtPos(location, out var overCross); @@ -414,7 +423,7 @@ namespace FlaxEditor.GUI.Docking public override void OnMouseMove(Float2 location) { MousePosition = location; - if (IsMouseLeftButtonDown) + if (IsMouseLeftButtonDown && !IsSingleFloatingWindow) { // Check if mouse is outside the header if (!HeaderRectangle.Contains(location)) @@ -505,7 +514,7 @@ namespace FlaxEditor.GUI.Docking /// public override void GetDesireClientArea(out Rectangle rect) { - if (_panel.TabsCount == 1 && _panel.IsFloating && _panel.ChildPanelsCount == 0) + if (IsSingleFloatingWindow) rect = new Rectangle(0, 0, Width, Height); else rect = new Rectangle(0, DockPanel.DefaultHeaderHeight, Width, Height - DockPanel.DefaultHeaderHeight); From 529de24da474f28e04de7fae0804d2ada0e2d765 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Jul 2024 12:39:15 +0200 Subject: [PATCH 16/19] Cache `DisableCCD` locally in physics backend #2768 --- Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp index 58b416cac..3439fa27e 100644 --- a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp +++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp @@ -569,6 +569,7 @@ namespace Array DeleteObjects; bool _queriesHitTriggers = true; + bool _enableCCD = true; PhysicsCombineMode _frictionCombineMode = PhysicsCombineMode::Average; PhysicsCombineMode _restitutionCombineMode = PhysicsCombineMode::Average; @@ -671,8 +672,6 @@ PxFilterFlags FilterShader( { const bool maskTest = (filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1); - auto& settings = *PhysicsSettings::Get(); - // Let triggers through if (PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1)) { @@ -704,7 +703,7 @@ PxFilterFlags FilterShader( pairFlags |= PxPairFlag::eNOTIFY_TOUCH_LOST; pairFlags |= PxPairFlag::ePOST_SOLVER_VELOCITY; pairFlags |= PxPairFlag::eNOTIFY_CONTACT_POINTS; - if (!settings.DisableCCD) + if (_enableCCD) pairFlags |= PxPairFlag::eDETECT_CCD_CONTACT; return PxFilterFlag::eDEFAULT; } @@ -1229,6 +1228,7 @@ void PhysicsBackend::Shutdown() void PhysicsBackend::ApplySettings(const PhysicsSettings& settings) { _queriesHitTriggers = settings.QueriesHitTriggers; + _enableCCD = !settings.DisableCCD; _frictionCombineMode = settings.FrictionCombineMode; _restitutionCombineMode = settings.RestitutionCombineMode; From 5e0d90af2ebfe4117ff7d4936d0c92e7a1ed431d Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Jul 2024 14:18:52 +0200 Subject: [PATCH 17/19] Add displaying file extension for scripts in content finder to distinguish C++ files --- Source/Editor/GUI/Popups/AssetSearchPopup.cs | 6 ++++-- Source/Editor/Modules/ContentFindingModule.cs | 12 +++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Source/Editor/GUI/Popups/AssetSearchPopup.cs b/Source/Editor/GUI/Popups/AssetSearchPopup.cs index 7a7d90aec..e28c19b65 100644 --- a/Source/Editor/GUI/Popups/AssetSearchPopup.cs +++ b/Source/Editor/GUI/Popups/AssetSearchPopup.cs @@ -38,7 +38,7 @@ namespace FlaxEditor.GUI ContentItem = item; ContentItem.AddReference(this); - Name = item.ShortName; + OnItemRenamed(item); TooltipText = item.Path; Height = IconSize + 4; @@ -82,7 +82,9 @@ namespace FlaxEditor.GUI /// public void OnItemRenamed(ContentItem item) { - Name = ContentItem.ShortName; + Name = item.ShortName; + if (item is ScriptItem) + Name = item.FileName; // Show extension for scripts (esp. for .h and .cpp files of the same name) } /// diff --git a/Source/Editor/Modules/ContentFindingModule.cs b/Source/Editor/Modules/ContentFindingModule.cs index 73e22d769..e3aa22b0e 100644 --- a/Source/Editor/Modules/ContentFindingModule.cs +++ b/Source/Editor/Modules/ContentFindingModule.cs @@ -342,9 +342,10 @@ namespace FlaxEditor.Modules { foreach (var contentItem in items) { + var name = contentItem.ShortName; if (contentItem.IsAsset) { - if (nameRegex.Match(contentItem.ShortName).Success) + if (nameRegex.Match(name).Success) { var asset = contentItem as AssetItem; if (asset == null || !typeRegex.Match(asset.TypeName).Success) @@ -358,7 +359,7 @@ namespace FlaxEditor.Modules var splits = asset.TypeName.Split('.'); finalName = splits[splits.Length - 1]; } - matches.Add(new SearchResult { Name = asset.ShortName, Type = finalName, Item = asset }); + matches.Add(new SearchResult { Name = name, Type = finalName, Item = asset }); } } else if (contentItem.IsFolder) @@ -370,11 +371,12 @@ namespace FlaxEditor.Modules } else { - if (nameRegex.Match(contentItem.ShortName).Success && typeRegex.Match(contentItem.GetType().Name).Success) + if (nameRegex.Match(name).Success && typeRegex.Match(contentItem.GetType().Name).Success) { string finalName = contentItem.GetType().Name.Replace("Item", ""); - - matches.Add(new SearchResult { Name = contentItem.ShortName, Type = finalName, Item = contentItem }); + if (contentItem is ScriptItem) + name = contentItem.FileName; // Show extension for scripts (esp. for .h and .cpp files of the same name) + matches.Add(new SearchResult { Name = name, Type = finalName, Item = contentItem }); } } } From f132198eade128d867d3e945280a63498e824677 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Jul 2024 14:19:27 +0200 Subject: [PATCH 18/19] Add more functionality and thumbnail to content items in finder for scripts --- Source/Editor/Windows/Search/ContentFinder.cs | 4 +- Source/Editor/Windows/Search/SearchItem.cs | 59 +++++++++++-------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/Source/Editor/Windows/Search/ContentFinder.cs b/Source/Editor/Windows/Search/ContentFinder.cs index 5b7ec18df..06b5852dd 100644 --- a/Source/Editor/Windows/Search/ContentFinder.cs +++ b/Source/Editor/Windows/Search/ContentFinder.cs @@ -139,8 +139,8 @@ namespace FlaxEditor.Windows.Search { var item = items[i]; SearchItem searchItem; - if (item.Item is AssetItem assetItem) - searchItem = new AssetSearchItem(item.Name, item.Type, assetItem, this, itemsWidth, itemHeight); + if (item.Item is ContentItem contentItem) + searchItem = new ContentSearchItem(item.Name, item.Type, contentItem, this, itemsWidth, itemHeight); else searchItem = new SearchItem(item.Name, item.Type, item.Item, this, itemsWidth, itemHeight); searchItem.Y = i * itemHeight; diff --git a/Source/Editor/Windows/Search/SearchItem.cs b/Source/Editor/Windows/Search/SearchItem.cs index 780b43346..577f75dc0 100644 --- a/Source/Editor/Windows/Search/SearchItem.cs +++ b/Source/Editor/Windows/Search/SearchItem.cs @@ -113,17 +113,17 @@ namespace FlaxEditor.Windows.Search } /// - /// The for assets. Supports using asset thumbnail. + /// The for assets. Supports using content item thumbnail. /// /// /// - internal class AssetSearchItem : SearchItem, IContentItemOwner + internal class ContentSearchItem : SearchItem, IContentItemOwner { - private AssetItem _asset; - private FlaxEditor.GUI.ContextMenu.ContextMenu _cm; + private ContentItem _asset; + private ContextMenu _cm; /// - public AssetSearchItem(string name, string type, AssetItem item, ContentFinder finder, float width, float height) + public ContentSearchItem(string name, string type, ContentItem item, ContentFinder finder, float width, float height) : base(name, type, item, finder, width, height) { _asset = item; @@ -136,31 +136,41 @@ namespace FlaxEditor.Windows.Search /// public override bool OnShowTooltip(out string text, out Float2 location, out Rectangle area) { - if (string.IsNullOrEmpty(TooltipText) && Item is AssetItem assetItem) + if (string.IsNullOrEmpty(TooltipText) && Item is ContentItem contentItem) { - assetItem.UpdateTooltipText(); - TooltipText = assetItem.TooltipText; + contentItem.UpdateTooltipText(); + TooltipText = contentItem.TooltipText; } return base.OnShowTooltip(out text, out location, out area); } + /// + public override bool OnMouseDown(Float2 location, MouseButton button) + { + if (base.OnMouseDown(location, button)) + return true; + if (button == MouseButton.Right && Item is ContentItem) + return true; + return false; + } + /// public override bool OnMouseUp(Float2 location, MouseButton button) { if (base.OnMouseUp(location, button)) return true; - if (button == MouseButton.Right && Item is AssetItem assetItem) + if (button == MouseButton.Right && Item is ContentItem contentItem) { // Show context menu - var proxy = Editor.Instance.ContentDatabase.GetProxy(assetItem); + var proxy = Editor.Instance.ContentDatabase.GetProxy(contentItem); ContextMenuButton b; - var cm = new FlaxEditor.GUI.ContextMenu.ContextMenu { Tag = assetItem }; + var cm = new ContextMenu { Tag = contentItem }; b = cm.AddButton("Open", () => Editor.Instance.ContentFinding.Open(Item)); cm.AddSeparator(); - cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(assetItem.Path))); - cm.AddButton("Show in Content window", () => Editor.Instance.Windows.ContentWin.Select(assetItem, true)); - b.Enabled = proxy != null && proxy.CanReimport(assetItem); - if (assetItem is BinaryAssetItem binaryAsset) + cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(contentItem.Path))); + cm.AddButton("Show in Content window", () => Editor.Instance.Windows.ContentWin.Select(contentItem, true)); + b.Enabled = proxy != null && proxy.CanReimport(contentItem); + if (contentItem is BinaryAssetItem binaryAsset) { if (!binaryAsset.GetImportPath(out string importPath)) { @@ -172,14 +182,17 @@ namespace FlaxEditor.Windows.Search } } cm.AddSeparator(); - cm.AddButton("Copy asset ID", () => Clipboard.Text = FlaxEngine.Json.JsonSerializer.GetStringID(assetItem.ID)); - cm.AddButton("Select actors using this asset", () => Editor.Instance.SceneEditing.SelectActorsUsingAsset(assetItem.ID)); - cm.AddButton("Show asset references graph", () => Editor.Instance.Windows.Open(new AssetReferencesGraphWindow(Editor.Instance, assetItem))); - cm.AddSeparator(); - proxy?.OnContentWindowContextMenu(cm, assetItem); - assetItem.OnContextMenu(cm); - cm.AddButton("Copy name to Clipboard", () => Clipboard.Text = assetItem.NamePath); - cm.AddButton("Copy path to Clipboard", () => Clipboard.Text = assetItem.Path); + if (contentItem is AssetItem assetItem) + { + cm.AddButton("Copy asset ID", () => Clipboard.Text = FlaxEngine.Json.JsonSerializer.GetStringID(assetItem.ID)); + cm.AddButton("Select actors using this asset", () => Editor.Instance.SceneEditing.SelectActorsUsingAsset(assetItem.ID)); + cm.AddButton("Show asset references graph", () => Editor.Instance.Windows.Open(new AssetReferencesGraphWindow(Editor.Instance, assetItem))); + cm.AddButton("Copy name to Clipboard", () => Clipboard.Text = assetItem.NamePath); + cm.AddButton("Copy path to Clipboard", () => Clipboard.Text = assetItem.Path); + cm.AddSeparator(); + } + proxy?.OnContentWindowContextMenu(cm, contentItem); + contentItem.OnContextMenu(cm); cm.Show(this, location); _cm = cm; return true; From d879b8e064dc05a535419e54ba7bb40d42b92e43 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Jul 2024 15:14:26 +0200 Subject: [PATCH 19/19] Add utility `GetInstance` method to Json Asset refs in csharp #2774 --- Source/Engine/Content/JsonAsset.cs | 11 +++++++++++ Source/Engine/Content/JsonAssetReference.cs | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/Source/Engine/Content/JsonAsset.cs b/Source/Engine/Content/JsonAsset.cs index 15ff3cd4d..a3f10b646 100644 --- a/Source/Engine/Content/JsonAsset.cs +++ b/Source/Engine/Content/JsonAsset.cs @@ -14,6 +14,17 @@ namespace FlaxEngine /// public object Instance => _instance ?? (_instance = CreateInstance()); + /// + /// Gets the instance of the serialized object from the json data. Cached internally. + /// + /// The asset instance object or null. + public T GetInstance() + { + if (Instance is T instance) + return instance; + return default; + } + /// /// Creates a new instance of the serialized object from the json asset data. /// diff --git a/Source/Engine/Content/JsonAssetReference.cs b/Source/Engine/Content/JsonAssetReference.cs index bec0cedf7..a3a17fe2b 100644 --- a/Source/Engine/Content/JsonAssetReference.cs +++ b/Source/Engine/Content/JsonAssetReference.cs @@ -33,6 +33,15 @@ namespace FlaxEngine Asset = asset; } + /// + /// Gets the deserialized native object instance of the given type. Returns null if asset is not loaded or loaded object has different type. + /// + /// The asset instance object or null. + public U GetInstance() + { + return Asset ? Asset.GetInstance() : default(U); + } + /// /// Implicit cast operator. ///