From 1d8ae580b71eb3db23d55135f2f634014cd78c12 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sat, 24 Jun 2023 12:05:51 -0500 Subject: [PATCH 01/85] Add Realloc with alignment. --- Source/Engine/Core/Memory/Memory.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Source/Engine/Core/Memory/Memory.h b/Source/Engine/Core/Memory/Memory.h index 770fd2c22..a35929ed2 100644 --- a/Source/Engine/Core/Memory/Memory.h +++ b/Source/Engine/Core/Memory/Memory.h @@ -36,6 +36,32 @@ namespace AllocatorExt return result; } + /// + /// Reallocates block of the memory. + /// + /// + /// A pointer to the memory block to reallocate. + /// The size of the new allocation (in bytes). + /// The memory alignment (in bytes). Must be an integer power of 2. + /// The pointer to the allocated chunk of the memory. The pointer is a multiple of alignment. + inline void* ReallocWithAlignment(void* ptr, uint64 newSize, uint64 alignment) + { + if (newSize == 0) + { + Allocator::Free(ptr); + return nullptr; + } + if (!ptr) + return Allocator::Allocate(newSize, alignment); + void* result = Allocator::Allocate(newSize, alignment); + if (result) + { + Platform::MemoryCopy(result, ptr, newSize); + Allocator::Free(ptr); + } + return result; + } + /// /// Reallocates block of the memory. /// From cbd1e5c837c0c28a81ddf2e7dc2e2a82bf9a30cc Mon Sep 17 00:00:00 2001 From: Wiktor Kocielski Date: Sun, 25 Jun 2023 23:39:59 +0300 Subject: [PATCH 02/85] Add NetworkReplicationNode::GetObject --- .../Engine/Networking/NetworkReplicationHierarchy.cpp | 11 +++++++++++ .../Engine/Networking/NetworkReplicationHierarchy.h | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp index 32b7978d0..364e4f7dd 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp @@ -63,6 +63,17 @@ bool NetworkReplicationNode::RemoveObject(ScriptingObject* obj) return !Objects.Remove(obj); } +bool NetworkReplicationNode::GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result) +{ + const int32 index = Objects.Find(obj); + if (index != -1) + { + result = Objects[index]; + return true; + } + return false; +} + bool NetworkReplicationNode::DirtyObject(ScriptingObject* obj) { const int32 index = Objects.Find(obj); diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.h b/Source/Engine/Networking/NetworkReplicationHierarchy.h index 36701c15d..1260859a5 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.h +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.h @@ -200,6 +200,14 @@ API_CLASS(Abstract, Namespace = "FlaxEngine.Networking") class FLAXENGINE_API Ne /// True on successful removal, otherwise false. API_FUNCTION() virtual bool RemoveObject(ScriptingObject* obj); + /// + /// Gets object from the hierarchy. + /// + /// The object to get. + /// The hierarchy object to retrieve. + /// True on successful retrieval, otherwise false. + API_FUNCTION() bool GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result); + /// /// Force replicates the object during the next update. Resets any internal tracking state to force the synchronization. /// From 65397621e90138ce9e2b6992cbb1fcd409954321 Mon Sep 17 00:00:00 2001 From: Wiktor Kocielski Date: Mon, 26 Jun 2023 17:12:48 +0300 Subject: [PATCH 03/85] Make GetObject virtual and implement for Grid --- .../Networking/NetworkReplicationHierarchy.cpp | 12 ++++++++++++ .../Engine/Networking/NetworkReplicationHierarchy.h | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp index 364e4f7dd..e95a06423 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp @@ -186,6 +186,18 @@ bool NetworkReplicationGridNode::RemoveObject(ScriptingObject* obj) return false; } +bool NetworkReplicationGridNode::GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result) +{ + for (const auto& e : _children) + { + if (e.Value.Node->GetObject(obj, result)) + { + return true; + } + } + return false; +} + void NetworkReplicationGridNode::Update(NetworkReplicationHierarchyUpdateResult* result) { CHECK(result); diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.h b/Source/Engine/Networking/NetworkReplicationHierarchy.h index 1260859a5..ae482dfa6 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.h +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.h @@ -206,7 +206,7 @@ API_CLASS(Abstract, Namespace = "FlaxEngine.Networking") class FLAXENGINE_API Ne /// The object to get. /// The hierarchy object to retrieve. /// True on successful retrieval, otherwise false. - API_FUNCTION() bool GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result); + API_FUNCTION() virtual bool GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result); /// /// Force replicates the object during the next update. Resets any internal tracking state to force the synchronization. @@ -255,6 +255,7 @@ public: void AddObject(NetworkReplicationHierarchyObject obj) override; bool RemoveObject(ScriptingObject* obj) override; + bool GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result) override; void Update(NetworkReplicationHierarchyUpdateResult* result) override; }; From 60137059889fa164c3897288ee3a3fffe5824e8d Mon Sep 17 00:00:00 2001 From: Wiktor Kocielski Date: Mon, 26 Jun 2023 17:32:19 +0300 Subject: [PATCH 04/85] Implement object to cell caching for the grid --- .../NetworkReplicationHierarchy.cpp | 34 ++++++++++++------- .../Networking/NetworkReplicationHierarchy.h | 1 + 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp index e95a06423..5097b6a26 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp @@ -167,6 +167,7 @@ void NetworkReplicationGridNode::AddObject(NetworkReplicationHierarchyObject obj cell->MinCullDistance = obj.CullDistance; } cell->Node->AddObject(obj); + _objectToCell[obj.Object] = coord; // Cache minimum culling distance for a whole cell to skip it at once cell->MinCullDistance = Math::Min(cell->MinCullDistance, obj.CullDistance); @@ -174,26 +175,35 @@ void NetworkReplicationGridNode::AddObject(NetworkReplicationHierarchyObject obj bool NetworkReplicationGridNode::RemoveObject(ScriptingObject* obj) { - for (const auto& e : _children) + Int3 coord; + + if (!_objectToCell.TryGet(obj, coord)) { - if (e.Value.Node->RemoveObject(obj)) - { - // TODO: remove empty cells? - // TODO: update MinCullDistance for cell? - return true; - } + return false; + } + + if (_children[coord].Node->RemoveObject(obj)) + { + _objectToCell.Remove(obj); + // TODO: remove empty cells? + // TODO: update MinCullDistance for cell? + return true; } return false; } bool NetworkReplicationGridNode::GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result) { - for (const auto& e : _children) + Int3 coord; + + if (!_objectToCell.TryGet(obj, coord)) { - if (e.Value.Node->GetObject(obj, result)) - { - return true; - } + return false; + } + + if (_children[coord].Node->GetObject(obj, result)) + { + return true; } return false; } diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.h b/Source/Engine/Networking/NetworkReplicationHierarchy.h index ae482dfa6..b054de453 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.h +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.h @@ -246,6 +246,7 @@ private: }; Dictionary _children; + Dictionary _objectToCell; public: /// From 90f9754781105f2d29e898aa820bb0c57f54de59 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Wed, 28 Jun 2023 00:35:06 +0300 Subject: [PATCH 05/85] Release custom assets before binary modules on scripting release --- Source/Engine/Scripting/Scripting.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Source/Engine/Scripting/Scripting.cpp b/Source/Engine/Scripting/Scripting.cpp index bbd109cd1..e2d709653 100644 --- a/Source/Engine/Scripting/Scripting.cpp +++ b/Source/Engine/Scripting/Scripting.cpp @@ -559,6 +559,16 @@ void Scripting::Release() } _objectsLocker.Unlock(); + // Release assets sourced from game assemblies + const auto flaxModule = GetBinaryModuleFlaxEngine(); + for (auto asset : Content::GetAssets()) + { + if (asset->GetTypeHandle().Module == flaxModule) + continue; + + asset->DeleteObjectNow(); + } + // Unload assemblies (from back to front) { LOG(Info, "Unloading binary modules"); From fe8260fe140a2b0c7285611726852f87b05c6fd3 Mon Sep 17 00:00:00 2001 From: PhyresiCompany Date: Tue, 27 Jun 2023 19:58:37 -0300 Subject: [PATCH 06/85] Window improvements with a new approach --- .../Viewport/Previews/AnimatedModelPreview.cs | 116 ++--------- .../Viewport/Previews/MaterialPreview.cs | 50 +++-- .../Viewport/Previews/ModelBasePreview.cs | 27 +-- .../Editor/Viewport/Previews/ModelPreview.cs | 84 ++++++-- .../Viewport/Previews/SkinnedModelPreview.cs | 188 ++++++++++++++++++ .../Windows/Assets/CollisionDataWindow.cs | 3 + Source/Editor/Windows/Assets/ModelWindow.cs | 9 + .../Windows/Assets/SkinnedModelWindow.cs | 11 +- 8 files changed, 342 insertions(+), 146 deletions(-) create mode 100644 Source/Editor/Viewport/Previews/SkinnedModelPreview.cs diff --git a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs index 2310668b6..aae48fe11 100644 --- a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs +++ b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs @@ -15,11 +15,13 @@ namespace FlaxEditor.Viewport.Previews /// public class AnimatedModelPreview : AssetPreview { + /// + public AnimatedModel _previewModel; + private ContextMenuButton _showNodesButton, _showBoundsButton, _showFloorButton, _showNodesNamesButton; - private bool _showNodes, _showBounds, _showFloor, _showCurrentLOD, _showNodesNames; - private AnimatedModel _previewModel; + private bool _showNodes, _showBounds, _showFloor, _showNodesNames; private StaticModel _floorModel; - private ContextMenuButton _showCurrentLODButton; + private bool _playAnimation, _playAnimationOnce; private float _playSpeed = 1.0f; @@ -207,26 +209,6 @@ namespace FlaxEditor.Viewport.Previews // Show Floor _showFloorButton = ViewWidgetShowMenu.AddButton("Floor", button => ShowFloor = !ShowFloor); _showFloorButton.IndexInParent = 1; - - // Show Current LOD - _showCurrentLODButton = ViewWidgetShowMenu.AddButton("Current LOD", button => - { - _showCurrentLOD = !_showCurrentLOD; - _showCurrentLODButton.Icon = _showCurrentLOD ? Style.Current.CheckBoxTick : SpriteHandle.Invalid; - }); - _showCurrentLODButton.IndexInParent = 2; - - // Preview LOD - { - var previewLOD = ViewWidgetButtonMenu.AddButton("Preview LOD"); - previewLOD.CloseMenuOnClick = false; - var previewLODValue = new IntValueBox(-1, 90, 2, 70.0f, -1, 10, 0.02f) - { - Parent = previewLOD - }; - previewLODValue.ValueChanged += () => _previewModel.ForcedLOD = previewLODValue.Value; - ViewWidgetButtonMenu.VisibleChanged += control => previewLODValue.Value = _previewModel.ForcedLOD; - } } // Enable shadows @@ -339,44 +321,6 @@ namespace FlaxEditor.Viewport.Previews _previewModel.ResetAnimation(); } - private int ComputeLODIndex(SkinnedModel model) - { - if (PreviewActor.ForcedLOD != -1) - return PreviewActor.ForcedLOD; - - // Based on RenderTools::ComputeModelLOD - CreateProjectionMatrix(out var projectionMatrix); - float screenMultiple = 0.5f * Mathf.Max(projectionMatrix.M11, projectionMatrix.M22); - var sphere = PreviewActor.Sphere; - var viewOrigin = ViewPosition; - var distSqr = Vector3.DistanceSquared(ref sphere.Center, ref viewOrigin); - var screenRadiusSquared = Mathf.Square(screenMultiple * sphere.Radius) / Mathf.Max(1.0f, distSqr); - - // Check if model is being culled - if (Mathf.Square(model.MinScreenSize * 0.5f) > screenRadiusSquared) - return -1; - - // Skip if no need to calculate LOD - if (model.LoadedLODs == 0) - return -1; - var lods = model.LODs; - if (lods.Length == 0) - return -1; - if (lods.Length == 1) - return 0; - - // Iterate backwards and return the first matching LOD - for (int lodIndex = lods.Length - 1; lodIndex >= 0; lodIndex--) - { - if (Mathf.Square(lods[lodIndex].ScreenSize * 0.5f) >= screenRadiusSquared) - { - return lodIndex + PreviewActor.LODBias; - } - } - - return 0; - } - /// protected override void OnDebugDraw(GPUContext context, ref RenderContext renderContext) { @@ -440,45 +384,6 @@ namespace FlaxEditor.Viewport.Previews } } - /// - public override void Draw() - { - base.Draw(); - - var skinnedModel = _previewModel.SkinnedModel; - if (skinnedModel == null || !skinnedModel.IsLoaded) - return; - var lods = skinnedModel.LODs; - if (lods.Length == 0) - { - // Force show skeleton for models without geometry - ShowNodes = true; - return; - } - if (_showCurrentLOD) - { - var lodIndex = ComputeLODIndex(skinnedModel); - string text = string.Format("Current LOD: {0}", lodIndex); - if (lodIndex != -1) - { - lodIndex = Mathf.Clamp(lodIndex + PreviewActor.LODBias, 0, lods.Length - 1); - var lod = lods[lodIndex]; - int triangleCount = 0, vertexCount = 0; - for (int meshIndex = 0; meshIndex < lod.Meshes.Length; meshIndex++) - { - var mesh = lod.Meshes[meshIndex]; - triangleCount += mesh.TriangleCount; - vertexCount += mesh.VertexCount; - } - text += string.Format("\nTriangles: {0:N0}\nVertices: {1:N0}", triangleCount, vertexCount); - } - var font = Style.Current.FontMedium; - var pos = new Float2(10, 50); - Render2D.DrawText(font, text, new Rectangle(pos + Float2.One, Size), Color.Black); - Render2D.DrawText(font, text, new Rectangle(pos, Size), Color.White); - } - } - /// public override void Update(float deltaTime) { @@ -498,6 +403,14 @@ namespace FlaxEditor.Viewport.Previews } } + /// + /// Calls SetArcBallView from ViewportCamera + /// + public void CallSetArcBallView() + { + ViewportCamera.SetArcBallView(_previewModel.Box); + } + /// public override bool OnKeyDown(KeyboardKeys key) { @@ -505,7 +418,7 @@ namespace FlaxEditor.Viewport.Previews { case KeyboardKeys.F: // Pay respect.. - ViewportCamera.SetArcBallView(_previewModel.Box); + CallSetArcBallView(); return true; case KeyboardKeys.Spacebar: PlayAnimation = !PlayAnimation; @@ -525,7 +438,6 @@ namespace FlaxEditor.Viewport.Previews _showNodesButton = null; _showBoundsButton = null; _showFloorButton = null; - _showCurrentLODButton = null; _showNodesNamesButton = null; base.OnDestroy(); diff --git a/Source/Editor/Viewport/Previews/MaterialPreview.cs b/Source/Editor/Viewport/Previews/MaterialPreview.cs index 632ec199e..3dfab1cff 100644 --- a/Source/Editor/Viewport/Previews/MaterialPreview.cs +++ b/Source/Editor/Viewport/Previews/MaterialPreview.cs @@ -4,6 +4,8 @@ using System; using FlaxEditor.Surface; using FlaxEngine; using FlaxEngine.GUI; +using FlaxEditor.Viewport.Widgets; +using FlaxEditor.GUI.ContextMenu; using Object = FlaxEngine.Object; namespace FlaxEditor.Viewport.Previews @@ -63,6 +65,11 @@ namespace FlaxEditor.Viewport.Previews } } + /// + /// The "Model" widget button context menu. + /// + private ContextMenu modelWidgetButtonMenu; + /// /// Gets or sets the selected preview model index. /// @@ -80,6 +87,27 @@ namespace FlaxEditor.Viewport.Previews } } + /// + /// Fill out all models + /// + /// + private void ModelWidgetMenuOnVisibleChanged(Control control) + { + if (!control.Visible) return; + + modelWidgetButtonMenu.ItemsContainer.DisposeChildren(); + + // Fill out all models + for (int i = 0; i < Models.Length; i++) + { + var index = i; + var button = modelWidgetButtonMenu.AddButton(Models[index]); + button.ButtonClicked += (button) => SelectedModelIndex = index; + button.Checked = SelectedModelIndex == index; + button.Tag = index; + } + } + /// /// Initializes a new instance of the class. /// @@ -95,20 +123,18 @@ namespace FlaxEditor.Viewport.Previews Task.AddCustomActor(_previewModel); // Create context menu for primitive switching - if (useWidgets && ViewWidgetButtonMenu != null) + if (useWidgets) { - ViewWidgetButtonMenu.AddSeparator(); - var modelSelect = ViewWidgetButtonMenu.AddChildMenu("Model").ContextMenu; - - // Fill out all models - for (int i = 0; i < Models.Length; i++) + // Model mode widget + var modelMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); + modelWidgetButtonMenu = new ContextMenu(); + modelWidgetButtonMenu.VisibleChanged += ModelWidgetMenuOnVisibleChanged; + var previewLODSModeButton = new ViewportWidgetButton("Model", SpriteHandle.Invalid, modelWidgetButtonMenu) { - var button = modelSelect.AddButton(Models[i]); - button.Tag = i; - } - - // Link the action - modelSelect.ButtonClicked += (button) => SelectedModelIndex = (int)button.Tag; + TooltipText = "Change material model", + Parent = modelMode, + }; + modelMode.Parent = this; } } diff --git a/Source/Editor/Viewport/Previews/ModelBasePreview.cs b/Source/Editor/Viewport/Previews/ModelBasePreview.cs index ffba23094..e5834edc9 100644 --- a/Source/Editor/Viewport/Previews/ModelBasePreview.cs +++ b/Source/Editor/Viewport/Previews/ModelBasePreview.cs @@ -56,25 +56,14 @@ namespace FlaxEditor.Viewport.Previews // Link actors for rendering Task.AddCustomActor(StaticModel); Task.AddCustomActor(AnimatedModel); + } - if (useWidgets) - { - // Preview LOD - { - var previewLOD = ViewWidgetButtonMenu.AddButton("Preview LOD"); - previewLOD.CloseMenuOnClick = false; - var previewLODValue = new IntValueBox(-1, 90, 2, 70.0f, -1, 10, 0.02f) - { - Parent = previewLOD - }; - previewLODValue.ValueChanged += () => - { - StaticModel.ForcedLOD = previewLODValue.Value; - AnimatedModel.ForcedLOD = previewLODValue.Value; - }; - ViewWidgetButtonMenu.VisibleChanged += control => previewLODValue.Value = StaticModel.ForcedLOD; - } - } + /// + /// Calls SetArcBallView from ViewportCamera + /// + public void CallSetArcBallView() + { + ViewportCamera.SetArcBallView(StaticModel.Model != null ? StaticModel.Box : AnimatedModel.Box); } private void OnBegin(RenderTask task, GPUContext context) @@ -104,7 +93,7 @@ namespace FlaxEditor.Viewport.Previews { case KeyboardKeys.F: // Pay respect.. - ViewportCamera.SetArcBallView(StaticModel.Model != null ? StaticModel.Box : AnimatedModel.Box); + CallSetArcBallView(); break; } return base.OnKeyDown(key); diff --git a/Source/Editor/Viewport/Previews/ModelPreview.cs b/Source/Editor/Viewport/Previews/ModelPreview.cs index 9193b6d40..dc0de37da 100644 --- a/Source/Editor/Viewport/Previews/ModelPreview.cs +++ b/Source/Editor/Viewport/Previews/ModelPreview.cs @@ -5,6 +5,7 @@ using FlaxEditor.GUI.Input; using FlaxEngine; using FlaxEngine.GUI; using FlaxEngine.Utilities; +using FlaxEditor.Viewport.Widgets; using Object = FlaxEngine.Object; namespace FlaxEditor.Viewport.Previews @@ -20,6 +21,29 @@ namespace FlaxEditor.Viewport.Previews private bool _showBounds, _showCurrentLOD, _showNormals, _showTangents, _showBitangents, _showFloor; private MeshDataCache _meshDatas; + /// + /// The "PreviewLODS" widget button context menu. + /// + private ContextMenu previewLODSWidgetButtonMenu; + + /// + /// Gets or sets a value that shows LOD statistics + /// + public bool ShowCurrentLOD + { + get => _showCurrentLOD; + set + { + if (_showCurrentLOD == value) + return; + _showCurrentLOD = value; + if (value) + ShowDebugDraw = true; + if (_showCurrentLODButton != null) + _showCurrentLODButton.Checked = value; + } + } + /// /// Gets or sets the model asset to preview. /// @@ -198,16 +222,41 @@ namespace FlaxEditor.Viewport.Previews }); _showCurrentLODButton.IndexInParent = 2; - // Preview LOD + // PreviewLODS mode widget + var PreviewLODSMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); + previewLODSWidgetButtonMenu = new ContextMenu(); + previewLODSWidgetButtonMenu.VisibleChanged += PreviewLODSWidgetMenuOnVisibleChanged; + var previewLODSModeButton = new ViewportWidgetButton("Preview LOD", SpriteHandle.Invalid, previewLODSWidgetButtonMenu) { - var previewLOD = ViewWidgetButtonMenu.AddButton("Preview LOD"); - previewLOD.CloseMenuOnClick = false; - var previewLODValue = new IntValueBox(-1, 90, 2, 70.0f, -1, 10, 0.02f) - { - Parent = previewLOD - }; - previewLODValue.ValueChanged += () => _previewModel.ForcedLOD = previewLODValue.Value; - ViewWidgetButtonMenu.VisibleChanged += control => previewLODValue.Value = _previewModel.ForcedLOD; + TooltipText = "Preview LOD properties", + Parent = PreviewLODSMode, + }; + PreviewLODSMode.Parent = this; + } + } + + /// + /// Fill out all Model LODS + /// + /// + private void PreviewLODSWidgetMenuOnVisibleChanged(Control control) + { + if (!control.Visible) + return; + + var model = _previewModel.Model; + if (model && !model.WaitForLoaded() && model.IsLoaded) + { + previewLODSWidgetButtonMenu.ItemsContainer.DisposeChildren(); + var lods = model.LODs.Length; + for (int i = -1; i < lods; i++) + { + var index = i; + var button = previewLODSWidgetButtonMenu.AddButton("LOD " + (index == -1 ? "Auto" : index)); + button.ButtonClicked += (button) => _previewModel.ForcedLOD = index; + button.Checked = _previewModel.ForcedLOD == index; + button.Tag = index; + if (lods <= 1) return; } } } @@ -346,8 +395,11 @@ namespace FlaxEditor.Viewport.Previews if (_showCurrentLOD) { var asset = Model; - var lodIndex = ComputeLODIndex(asset, out var screenSize); - string text = string.Format("Current LOD: {0}\nScreen Size: {1:F2}", lodIndex, screenSize); + var lodIndex = ComputeLODIndex(asset, out var screenSize); + var auto = _previewModel.ForcedLOD == -1; + string text = auto ? "LOD Automatic" : ""; + text += auto ? string.Format("\nScreen Size: {0:F2}", screenSize) : ""; + text += string.Format("\nCurrent LOD: {0}", lodIndex); if (lodIndex != -1) { var lods = asset.LODs; @@ -369,6 +421,14 @@ namespace FlaxEditor.Viewport.Previews } } + /// + /// Calls SetArcBallView from ViewportCamera + /// + public void CallSetArcBallView() + { + ViewportCamera.SetArcBallView(_previewModel.Box); + } + /// public override bool OnKeyDown(KeyboardKeys key) { @@ -376,7 +436,7 @@ namespace FlaxEditor.Viewport.Previews { case KeyboardKeys.F: // Pay respect.. - ViewportCamera.SetArcBallView(_previewModel.Box); + CallSetArcBallView(); break; } return base.OnKeyDown(key); diff --git a/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs b/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs new file mode 100644 index 000000000..a8b98b423 --- /dev/null +++ b/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs @@ -0,0 +1,188 @@ +using System; +using FlaxEditor.GUI.ContextMenu; +using FlaxEngine; +using FlaxEngine.GUI; +using FlaxEditor.Viewport.Widgets; + +namespace FlaxEditor.Viewport.Previews +{ + /// + /// Animation asset preview editor viewport. + /// + /// + public class SkinnedModelPreview : AnimatedModelPreview + { + private bool _showCurrentLOD; + private ContextMenuButton _showCurrentLODButton; + + /// + /// The "PreviewLODS" widget button context menu. + /// + private ContextMenu previewLODSWidgetButtonMenu; + + /// + /// Gets or sets a value that shows LOD statistics + /// + public bool ShowCurrentLOD + { + get => _showCurrentLOD; + set + { + if (_showCurrentLOD == value) + return; + _showCurrentLOD = value; + if (value) + ShowDebugDraw = true; + if (_showCurrentLODButton != null) + _showCurrentLODButton.Checked = value; + } + } + + /// + /// Initializes a new instance of the class. + /// + /// if set to true use widgets. + public SkinnedModelPreview(bool useWidgets) + : base(useWidgets) + { + if (useWidgets) + { + // Show Current LOD + _showCurrentLODButton = ViewWidgetShowMenu.AddButton("Current LOD", button => + { + _showCurrentLOD = !_showCurrentLOD; + _showCurrentLODButton.Icon = _showCurrentLOD ? Style.Current.CheckBoxTick : SpriteHandle.Invalid; + }); + _showCurrentLODButton.IndexInParent = 2; + + // PreviewLODS mode widget + var PreviewLODSMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); + previewLODSWidgetButtonMenu = new ContextMenu(); + previewLODSWidgetButtonMenu.VisibleChanged += PreviewLODSWidgetMenuOnVisibleChanged; + var previewLODSModeButton = new ViewportWidgetButton("Preview LOD", SpriteHandle.Invalid, previewLODSWidgetButtonMenu) + { + TooltipText = "Preview LOD properties", + Parent = PreviewLODSMode, + }; + PreviewLODSMode.Parent = this; + } + } + + /// + /// Fill out all SkinnedModel LODS + /// + /// + private void PreviewLODSWidgetMenuOnVisibleChanged(Control control) + { + if (!control.Visible) + return; + + var skinned = _previewModel.SkinnedModel; + if (skinned && !skinned.WaitForLoaded() && skinned.IsLoaded) + { + previewLODSWidgetButtonMenu.ItemsContainer.DisposeChildren(); + var lods = skinned.LODs.Length; + for (int i = -1; i < lods; i++) + { + var index = i; + var button = previewLODSWidgetButtonMenu.AddButton("LOD " + (index == -1 ? "Auto" : index)); + button.ButtonClicked += (button) => _previewModel.ForcedLOD = index; + button.Checked = _previewModel.ForcedLOD == index; + button.Tag = index; + if (lods <= 1) return; + } + } + } + + /// + private int ComputeLODIndex(SkinnedModel model, out float screenSize) + { + screenSize = 1.0f; + if (PreviewActor.ForcedLOD != -1) + return PreviewActor.ForcedLOD; + + // Based on RenderTools::ComputeModelLOD + CreateProjectionMatrix(out var projectionMatrix); + float screenMultiple = 0.5f * Mathf.Max(projectionMatrix.M11, projectionMatrix.M22); + var sphere = PreviewActor.Sphere; + var viewOrigin = ViewPosition; + var distSqr = Vector3.DistanceSquared(ref sphere.Center, ref viewOrigin); + var screenRadiusSquared = Mathf.Square(screenMultiple * sphere.Radius) / Mathf.Max(1.0f, distSqr); + screenSize = Mathf.Sqrt((float)screenRadiusSquared) * 2.0f; + + // Check if model is being culled + if (Mathf.Square(model.MinScreenSize * 0.5f) > screenRadiusSquared) + return -1; + + // Skip if no need to calculate LOD + if (model.LoadedLODs == 0) + return -1; + var lods = model.LODs; + if (lods.Length == 0) + return -1; + if (lods.Length == 1) + return 0; + + // Iterate backwards and return the first matching LOD + for (int lodIndex = lods.Length - 1; lodIndex >= 0; lodIndex--) + { + if (Mathf.Square(lods[lodIndex].ScreenSize * 0.5f) >= screenRadiusSquared) + { + return lodIndex + PreviewActor.LODBias; + } + } + + return 0; + } + + /// + public override void Draw() + { + base.Draw(); + + var skinnedModel = _previewModel.SkinnedModel; + if (skinnedModel == null || !skinnedModel.IsLoaded) + return; + var lods = skinnedModel.LODs; + if (lods.Length == 0) + { + // Force show skeleton for models without geometry + ShowNodes = true; + return; + } + if (_showCurrentLOD) + { + var lodIndex = ComputeLODIndex(skinnedModel, out var screenSize); + var auto = _previewModel.ForcedLOD == -1; + string text = auto ? "LOD Automatic" : ""; + text += auto ? string.Format("\nScreen Size: {0:F2}", screenSize) : ""; + text += string.Format("\nCurrent LOD: {0}", lodIndex); + if (lodIndex != -1) + { + lodIndex = Mathf.Clamp(lodIndex + PreviewActor.LODBias, 0, lods.Length - 1); + var lod = lods[lodIndex]; + int triangleCount = 0, vertexCount = 0; + for (int meshIndex = 0; meshIndex < lod.Meshes.Length; meshIndex++) + { + var mesh = lod.Meshes[meshIndex]; + triangleCount += mesh.TriangleCount; + vertexCount += mesh.VertexCount; + } + text += string.Format("\nTriangles: {0:N0}\nVertices: {1:N0}", triangleCount, vertexCount); + } + var font = Style.Current.FontMedium; + var pos = new Float2(10, 50); + Render2D.DrawText(font, text, new Rectangle(pos + Float2.One, Size), Color.Black); + Render2D.DrawText(font, text, new Rectangle(pos, Size), Color.White); + } + } + + /// + public override void OnDestroy() + { + _showCurrentLODButton = null; + + base.OnDestroy(); + } + } +} diff --git a/Source/Editor/Windows/Assets/CollisionDataWindow.cs b/Source/Editor/Windows/Assets/CollisionDataWindow.cs index 9ce4c8765..82e0681fa 100644 --- a/Source/Editor/Windows/Assets/CollisionDataWindow.cs +++ b/Source/Editor/Windows/Assets/CollisionDataWindow.cs @@ -182,6 +182,9 @@ namespace FlaxEditor.Windows.Assets { // Toolstrip _toolstrip.AddSeparator(); + + _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.CallSetArcBallView()).LinkTooltip("Show whole collision"); + _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/physics/colliders/collision-data.html")).LinkTooltip("See documentation to learn more"); // Split Panel diff --git a/Source/Editor/Windows/Assets/ModelWindow.cs b/Source/Editor/Windows/Assets/ModelWindow.cs index e44882b73..cc7657fc7 100644 --- a/Source/Editor/Windows/Assets/ModelWindow.cs +++ b/Source/Editor/Windows/Assets/ModelWindow.cs @@ -779,12 +779,18 @@ namespace FlaxEditor.Windows.Assets private MeshDataCache _meshData; private ModelImportSettings _importSettings = new ModelImportSettings(); private float _backfacesThreshold = 0.6f; + private ToolStripButton _showCurrentLODButton; /// public ModelWindow(Editor editor, AssetItem item) : base(editor, item) { // Toolstrip + _toolstrip.AddSeparator(); + _showCurrentLODButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Info64, () => _preview.ShowCurrentLOD = !_preview.ShowCurrentLOD).LinkTooltip("Show LOD statistics"); + + _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.CallSetArcBallView()).LinkTooltip("Show whole model"); + _toolstrip.AddSeparator(); _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/models/index.html")).LinkTooltip("See documentation to learn more"); @@ -869,6 +875,8 @@ namespace FlaxEditor.Windows.Assets } } + _showCurrentLODButton.Checked = _preview.ShowCurrentLOD; + base.Update(deltaTime); } @@ -946,6 +954,7 @@ namespace FlaxEditor.Windows.Assets base.OnDestroy(); Object.Destroy(ref _highlightActor); + _showCurrentLODButton = null; } } } diff --git a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs index d18593549..367fc3a1a 100644 --- a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs +++ b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs @@ -31,7 +31,7 @@ namespace FlaxEditor.Windows.Assets /// public sealed class SkinnedModelWindow : ModelBaseWindow { - private sealed class Preview : AnimatedModelPreview + private sealed class Preview : SkinnedModelPreview { private readonly SkinnedModelWindow _window; @@ -1105,6 +1105,7 @@ namespace FlaxEditor.Windows.Assets private Preview _preview; private AnimatedModel _highlightActor; private ToolStripButton _showNodesButton; + private ToolStripButton _showCurrentLODButton; private MeshData[][] _meshDatas; private bool _meshDatasInProgress; @@ -1116,7 +1117,13 @@ namespace FlaxEditor.Windows.Assets { // Toolstrip _toolstrip.AddSeparator(); + + _showCurrentLODButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Info64, () => _preview.ShowCurrentLOD = !_preview.ShowCurrentLOD).LinkTooltip("Show LOD statistics"); + _showNodesButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Bone64, () => _preview.ShowNodes = !_preview.ShowNodes).LinkTooltip("Show animated model nodes debug view"); + + _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.CallSetArcBallView()).LinkTooltip("Show whole model"); + _toolstrip.AddSeparator(); _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/skinned-model/index.html")).LinkTooltip("See documentation to learn more"); @@ -1265,6 +1272,7 @@ namespace FlaxEditor.Windows.Assets } } + _showCurrentLODButton.Checked = _preview.ShowCurrentLOD; _showNodesButton.Checked = _preview.ShowNodes; base.Update(deltaTime); @@ -1349,6 +1357,7 @@ namespace FlaxEditor.Windows.Assets Object.Destroy(ref _highlightActor); _preview = null; _showNodesButton = null; + _showCurrentLODButton = null; } } } From 76e4e1b8d49e6a71ae9f6c3c5df7555507a568bc Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Tue, 27 Jun 2023 21:08:12 -0400 Subject: [PATCH 07/85] fix debug vehicle wheel orientation --- Source/Engine/Physics/Actors/WheeledVehicle.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.cpp b/Source/Engine/Physics/Actors/WheeledVehicle.cpp index 2ed59c8f6..995150bdc 100644 --- a/Source/Engine/Physics/Actors/WheeledVehicle.cpp +++ b/Source/Engine/Physics/Actors/WheeledVehicle.cpp @@ -230,10 +230,11 @@ void WheeledVehicle::DrawPhysicsDebug(RenderView& view) { const Vector3 currentPos = wheel.Collider->GetPosition(); const Vector3 basePos = currentPos - Vector3(0, data.State.SuspensionOffset, 0); + const Quaternion wheelDebugOrientation = wheel.Collider->GetOrientation() * Quaternion::Euler(90, 0, 90); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(basePos, wheel.Radius * 0.07f), Color::Blue * 0.3f, 0, true); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(currentPos, wheel.Radius * 0.08f), Color::Blue * 0.8f, 0, true); DEBUG_DRAW_LINE(basePos, currentPos, Color::Blue, 0, true); - DEBUG_DRAW_WIRE_CYLINDER(currentPos, wheel.Collider->GetOrientation(), wheel.Radius, wheel.Width, Color::Red * 0.8f, 0, true); + DEBUG_DRAW_WIRE_CYLINDER(currentPos, wheelDebugOrientation, wheel.Radius, wheel.Width, Color::Red * 0.8f, 0, true); if (!data.State.IsInAir) { DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(data.State.TireContactPoint, 5.0f), Color::Green, 0, true); @@ -260,6 +261,7 @@ void WheeledVehicle::OnDebugDrawSelected() { const Vector3 currentPos = wheel.Collider->GetPosition(); const Vector3 basePos = currentPos - Vector3(0, data.State.SuspensionOffset, 0); + const Quaternion wheelDebugOrientation = wheel.Collider->GetOrientation() * Quaternion::Euler(90, 0, 90); Transform actorPose = Transform::Identity, shapePose = Transform::Identity; PhysicsBackend::GetRigidActorPose(_actor, actorPose.Translation, actorPose.Orientation); PhysicsBackend::GetShapeLocalPose(wheel.Collider->GetPhysicsShape(), shapePose.Translation, shapePose.Orientation); @@ -267,7 +269,7 @@ void WheeledVehicle::OnDebugDrawSelected() DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(currentPos, wheel.Radius * 0.08f), Color::Blue * 0.8f, 0, false); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(actorPose.LocalToWorld(shapePose.Translation), wheel.Radius * 0.11f), Color::OrangeRed * 0.8f, 0, false); DEBUG_DRAW_LINE(basePos, currentPos, Color::Blue, 0, false); - DEBUG_DRAW_WIRE_CYLINDER(currentPos, wheel.Collider->GetOrientation(), wheel.Radius, wheel.Width, Color::Red * 0.4f, 0, false); + DEBUG_DRAW_WIRE_CYLINDER(currentPos, wheelDebugOrientation, wheel.Radius, wheel.Width, Color::Red * 0.4f, 0, false); if (!data.State.SuspensionTraceStart.IsZero()) { DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(data.State.SuspensionTraceStart, 5.0f), Color::AliceBlue, 0, false); From 17aa4ea60dc4b48243c225612995ad515211e932 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 12:21:58 +0200 Subject: [PATCH 08/85] Optimize `CollisionsHelper::FrustumContainsBox` --- Source/Engine/Core/Math/BoundingFrustum.h | 1 + Source/Engine/Core/Math/CollisionsHelper.cpp | 19 +++++-------------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/Source/Engine/Core/Math/BoundingFrustum.h b/Source/Engine/Core/Math/BoundingFrustum.h index 61c5d122f..287d33c2f 100644 --- a/Source/Engine/Core/Math/BoundingFrustum.h +++ b/Source/Engine/Core/Math/BoundingFrustum.h @@ -12,6 +12,7 @@ /// API_STRUCT(InBuild) struct FLAXENGINE_API BoundingFrustum { + friend CollisionsHelper; private: Matrix _matrix; diff --git a/Source/Engine/Core/Math/CollisionsHelper.cpp b/Source/Engine/Core/Math/CollisionsHelper.cpp index 60ba61f28..8ad5b7673 100644 --- a/Source/Engine/Core/Math/CollisionsHelper.cpp +++ b/Source/Engine/Core/Math/CollisionsHelper.cpp @@ -939,7 +939,6 @@ bool CollisionsHelper::RayIntersectsSphere(const Ray& ray, const BoundingSphere& normal = Vector3::Up; return false; } - const Vector3 point = ray.Position + ray.Direction * distance; normal = Vector3::Normalize(point - sphere.Center); return true; @@ -953,22 +952,17 @@ bool CollisionsHelper::RayIntersectsSphere(const Ray& ray, const BoundingSphere& point = Vector3::Zero; return false; } - point = ray.Position + ray.Direction * distance; return true; } PlaneIntersectionType CollisionsHelper::PlaneIntersectsPoint(const Plane& plane, const Vector3& point) { - Real distance = Vector3::Dot(plane.Normal, point); - distance += plane.D; - + const Real distance = Vector3::Dot(plane.Normal, point) + plane.D; if (distance > Plane::DistanceEpsilon) return PlaneIntersectionType::Front; - if (distance < Plane::DistanceEpsilon) return PlaneIntersectionType::Back; - return PlaneIntersectionType::Intersecting; } @@ -1169,7 +1163,6 @@ ContainmentType CollisionsHelper::SphereContainsPoint(const BoundingSphere& sphe { if (Vector3::DistanceSquared(point, sphere.Center) <= sphere.Radius * sphere.Radius) return ContainmentType::Contains; - return ContainmentType::Disjoint; } @@ -1254,13 +1247,10 @@ ContainmentType CollisionsHelper::SphereContainsBox(const BoundingSphere& sphere ContainmentType CollisionsHelper::SphereContainsSphere(const BoundingSphere& sphere1, const BoundingSphere& sphere2) { const Real distance = Vector3::Distance(sphere1.Center, sphere2.Center); - if (sphere1.Radius + sphere2.Radius < distance) return ContainmentType::Disjoint; - if (sphere1.Radius - sphere2.Radius < distance) return ContainmentType::Intersects; - return ContainmentType::Contains; } @@ -1274,7 +1264,8 @@ ContainmentType CollisionsHelper::FrustumContainsBox(const BoundingFrustum& frus auto result = ContainmentType::Contains; for (int32 i = 0; i < 6; i++) { - Plane plane = frustum.GetPlane(i); + Plane plane = frustum._planes[i]; + Vector3 p = box.Minimum; if (plane.Normal.X >= 0) p.X = box.Maximum.X; @@ -1282,7 +1273,7 @@ ContainmentType CollisionsHelper::FrustumContainsBox(const BoundingFrustum& frus p.Y = box.Maximum.Y; if (plane.Normal.Z >= 0) p.Z = box.Maximum.Z; - if (PlaneIntersectsPoint(plane, p) == PlaneIntersectionType::Back) + if (Vector3::Dot(plane.Normal, p) + plane.D < Plane::DistanceEpsilon) return ContainmentType::Disjoint; p = box.Maximum; @@ -1292,7 +1283,7 @@ ContainmentType CollisionsHelper::FrustumContainsBox(const BoundingFrustum& frus p.Y = box.Minimum.Y; if (plane.Normal.Z >= 0) p.Z = box.Minimum.Z; - if (PlaneIntersectsPoint(plane, p) == PlaneIntersectionType::Back) + if (Vector3::Dot(plane.Normal, p) + plane.D < Plane::DistanceEpsilon) result = ContainmentType::Intersects; } return result; From fb6bc75e3a4cc2fae13ee7416b4c8ada25076e54 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 13:42:18 +0200 Subject: [PATCH 09/85] Fix `launchSettings.json` generation bug --- .../Projects/VisualStudio/VisualStudioProjectGenerator.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs index fb5c90872..1955a57ba 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs @@ -547,6 +547,7 @@ namespace Flax.Build.Projects.VisualStudio if (project.Type == TargetType.DotNetCore) { var path = Path.Combine(Path.GetDirectoryName(project.Path), "Properties/launchSettings.json"); + path = Utilities.NormalizePath(path); if (profiles.ContainsKey(path)) profile.AppendLine(","); profile.AppendLine($" \"{project.BaseName}\": {{"); @@ -568,6 +569,7 @@ namespace Flax.Build.Projects.VisualStudio var folder = Path.GetDirectoryName(e.Key); if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); + profile.Clear(); profile.AppendLine("{"); profile.AppendLine(" \"profiles\": {"); profile.AppendLine(e.Value); From d3b96742e73b6a1bfa2a1356bb90ebb42a2fb379 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Wed, 28 Jun 2023 14:42:06 +0300 Subject: [PATCH 10/85] Fix compile-time error in HashSet::ClearDelete --- Source/Engine/Core/Collections/HashSet.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Core/Collections/HashSet.h b/Source/Engine/Core/Collections/HashSet.h index 698788869..ad6f8ffc6 100644 --- a/Source/Engine/Core/Collections/HashSet.h +++ b/Source/Engine/Core/Collections/HashSet.h @@ -357,8 +357,8 @@ public: { for (Iterator i = Begin(); i.IsNotEnd(); ++i) { - if (i->Value) - ::Delete(i->Value); + if (i->Item) + ::Delete(i->Item); } Clear(); } From 093928f2f96059489f4c47463463a6a2671b0ece Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Wed, 28 Jun 2023 06:42:54 -0500 Subject: [PATCH 11/85] Change name to `ReallocAligned` --- Source/Engine/Core/Memory/Memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Core/Memory/Memory.h b/Source/Engine/Core/Memory/Memory.h index a35929ed2..96acc0746 100644 --- a/Source/Engine/Core/Memory/Memory.h +++ b/Source/Engine/Core/Memory/Memory.h @@ -44,7 +44,7 @@ namespace AllocatorExt /// The size of the new allocation (in bytes). /// The memory alignment (in bytes). Must be an integer power of 2. /// The pointer to the allocated chunk of the memory. The pointer is a multiple of alignment. - inline void* ReallocWithAlignment(void* ptr, uint64 newSize, uint64 alignment) + inline void* ReallocAligned(void* ptr, uint64 newSize, uint64 alignment) { if (newSize == 0) { From b16a6199d0b26c9aa1e0437bd8e2fa581704d53a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 14:52:58 +0200 Subject: [PATCH 12/85] Fix invoking Client RPC on Host client when it's not included in `targetIds` list --- Source/Engine/Core/Types/Span.h | 11 ++++++ .../Engine/Networking/NetworkReplicator.cpp | 18 +++++++-- Source/Engine/Networking/NetworkReplicator.cs | 5 ++- Source/Engine/Networking/NetworkReplicator.h | 5 ++- Source/Engine/Networking/NetworkRpc.h | 7 +--- .../Build/Plugins/NetworkingPlugin.cs | 39 ++++--------------- 6 files changed, 41 insertions(+), 44 deletions(-) diff --git a/Source/Engine/Core/Types/Span.h b/Source/Engine/Core/Types/Span.h index 678550e85..e7bea5fbd 100644 --- a/Source/Engine/Core/Types/Span.h +++ b/Source/Engine/Core/Types/Span.h @@ -114,3 +114,14 @@ inline Span ToSpan(const T* ptr, int32 length) { return Span(ptr, length); } + +template +inline bool SpanContains(const Span span, const T& value) +{ + for (int32 i = 0; i < span.Length(); i++) + { + if (span.Get()[i] == value) + return true; + } + return false; +} diff --git a/Source/Engine/Networking/NetworkReplicator.cpp b/Source/Engine/Networking/NetworkReplicator.cpp index c41e104ef..ae7549a50 100644 --- a/Source/Engine/Networking/NetworkReplicator.cpp +++ b/Source/Engine/Networking/NetworkReplicator.cpp @@ -700,9 +700,9 @@ void NetworkReplicator::AddRPC(const ScriptingTypeHandle& typeHandle, const Stri NetworkRpcInfo::RPCsTable[rpcName] = rpcInfo; } -void NetworkReplicator::CSharpEndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, MArray* targetIds) +bool NetworkReplicator::CSharpEndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, MArray* targetIds) { - EndInvokeRPC(obj, type, GetCSharpCachedName(name), argsStream, MUtils::ToSpan(targetIds)); + return EndInvokeRPC(obj, type, GetCSharpCachedName(name), argsStream, MUtils::ToSpan(targetIds)); } StringAnsiView NetworkReplicator::GetCSharpCachedName(const StringAnsiView& name) @@ -1113,12 +1113,12 @@ NetworkStream* NetworkReplicator::BeginInvokeRPC() return CachedWriteStream; } -void NetworkReplicator::EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, Span targetIds) +bool NetworkReplicator::EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, Span targetIds) { Scripting::ObjectsLookupIdMapping.Set(nullptr); const NetworkRpcInfo* info = NetworkRpcInfo::RPCsTable.TryGet(NetworkRpcName(type, name)); if (!info || !obj || NetworkManager::IsOffline()) - return; + return false; ObjectsLock.Lock(); auto& rpc = RpcQueue.AddOne(); rpc.Object = obj; @@ -1135,6 +1135,16 @@ void NetworkReplicator::EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHa } #endif ObjectsLock.Unlock(); + + // Check if skip local execution (eg. server rpc called from client or client rpc with specific targets) + const NetworkManagerMode networkMode = NetworkManager::Mode; + if (info->Server && networkMode == NetworkManagerMode::Client) + return true; + if (info->Client && networkMode == NetworkManagerMode::Server) + return true; + if (info->Client && networkMode == NetworkManagerMode::Host && targetIds.IsValid() && !SpanContains(targetIds, NetworkManager::LocalClientId)) + return true; + return false; } void NetworkInternal::NetworkReplicatorClientConnected(NetworkClient* client) diff --git a/Source/Engine/Networking/NetworkReplicator.cs b/Source/Engine/Networking/NetworkReplicator.cs index 1ca251f75..bc437b82e 100644 --- a/Source/Engine/Networking/NetworkReplicator.cs +++ b/Source/Engine/Networking/NetworkReplicator.cs @@ -120,10 +120,11 @@ namespace FlaxEngine.Networking /// The RPC name. /// The RPC serialized arguments stream returned from BeginInvokeRPC. /// Optional list with network client IDs that should receive RPC. Empty to send on all clients. Ignored by Server RPCs. + /// True if RPC cannot be executed locally, false if execute it locally too (checks RPC mode and target client ids). [Unmanaged] - public static void EndInvokeRPC(Object obj, Type type, string name, NetworkStream argsStream, uint[] targetIds = null) + public static bool EndInvokeRPC(Object obj, Type type, string name, NetworkStream argsStream, uint[] targetIds = null) { - Internal_CSharpEndInvokeRPC(FlaxEngine.Object.GetUnmanagedPtr(obj), type, name, FlaxEngine.Object.GetUnmanagedPtr(argsStream), targetIds); + return Internal_CSharpEndInvokeRPC(FlaxEngine.Object.GetUnmanagedPtr(obj), type, name, FlaxEngine.Object.GetUnmanagedPtr(argsStream), targetIds); } /// diff --git a/Source/Engine/Networking/NetworkReplicator.h b/Source/Engine/Networking/NetworkReplicator.h index 156e7eeea..ecccc52cd 100644 --- a/Source/Engine/Networking/NetworkReplicator.h +++ b/Source/Engine/Networking/NetworkReplicator.h @@ -195,13 +195,14 @@ public: /// The RPC name. /// The RPC serialized arguments stream returned from BeginInvokeRPC. /// Optional list with network client IDs that should receive RPC. Empty to send on all clients. Ignored by Server RPCs. - static void EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, Span targetIds = Span()); + /// True if RPC cannot be executed locally, false if execute it locally too (checks RPC mode and target client ids). + static bool EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, Span targetIds = Span()); private: #if !COMPILE_WITHOUT_CSHARP API_FUNCTION(NoProxy) static void AddSerializer(const ScriptingTypeHandle& typeHandle, const Function& serialize, const Function& deserialize); API_FUNCTION(NoProxy) static void AddRPC(const ScriptingTypeHandle& typeHandle, const StringAnsiView& name, const Function& execute, bool isServer, bool isClient, NetworkChannelType channel); - API_FUNCTION(NoProxy) static void CSharpEndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, MArray* targetIds); + API_FUNCTION(NoProxy) static bool CSharpEndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, MArray* targetIds); static StringAnsiView GetCSharpCachedName(const StringAnsiView& name); #endif }; diff --git a/Source/Engine/Networking/NetworkRpc.h b/Source/Engine/Networking/NetworkRpc.h index c0c8a558e..6e8d26752 100644 --- a/Source/Engine/Networking/NetworkRpc.h +++ b/Source/Engine/Networking/NetworkRpc.h @@ -41,7 +41,7 @@ struct FLAXENGINE_API NetworkRpcInfo uint8 Client : 1; uint8 Channel : 4; void (*Execute)(ScriptingObject* obj, NetworkStream* stream, void* tag); - void (*Invoke)(ScriptingObject* obj, void** args); + bool (*Invoke)(ScriptingObject* obj, void** args); void* Tag; /// @@ -83,10 +83,7 @@ FORCE_INLINE void NetworkRpcInitArg(Array>& args, con { \ Array> args; \ NetworkRpcInitArg(args, __VA_ARGS__); \ - rpcInfo.Invoke(this, args.Get()); \ - if (rpcInfo.Server && networkMode == NetworkManagerMode::Client) \ - return; \ - if (rpcInfo.Client && networkMode == NetworkManagerMode::Server) \ + if (rpcInfo.Invoke(this, args.Get())) \ return; \ } \ } diff --git a/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs b/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs index 21464ab55..b24b887b3 100644 --- a/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs +++ b/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs @@ -254,7 +254,7 @@ namespace Flax.Build.Plugins // Generated method thunk to invoke RPC to network { - contents.Append(" static void ").Append(functionInfo.Name).AppendLine("_Invoke(ScriptingObject* obj, void** args)"); + contents.Append(" static bool ").Append(functionInfo.Name).AppendLine("_Invoke(ScriptingObject* obj, void** args)"); contents.AppendLine(" {"); contents.AppendLine(" NetworkStream* stream = NetworkReplicator::BeginInvokeRPC();"); contents.AppendLine(" Span targetIds;"); @@ -274,7 +274,7 @@ namespace Flax.Build.Plugins } // Invoke RPC - contents.AppendLine($" NetworkReplicator::EndInvokeRPC(obj, {typeInfo.NativeName}::TypeInitializer, StringAnsiView(\"{functionInfo.Name}\", {functionInfo.Name.Length}), stream, targetIds);"); + contents.AppendLine($" return NetworkReplicator::EndInvokeRPC(obj, {typeInfo.NativeName}::TypeInitializer, StringAnsiView(\"{functionInfo.Name}\", {functionInfo.Name.Length}), stream, targetIds);"); contents.AppendLine(" }"); } contents.AppendLine(); @@ -1753,10 +1753,10 @@ namespace Flax.Build.Plugins if (jumpBodyEnd == null) throw new Exception("Missing IL Return op code in method " + method.Name); il.Emit(OpCodes.Ldloc, varsStart + 0); - il.Emit(OpCodes.Brfalse_S, jumpIf2Start); + il.Emit(OpCodes.Brfalse, jumpIf2Start); il.Emit(OpCodes.Ldloc, varsStart + 2); il.Emit(OpCodes.Ldc_I4_2); - il.Emit(OpCodes.Beq_S, jumpIfBodyStart); + il.Emit(OpCodes.Beq, jumpIfBodyStart); // || il.Emit(jumpIf2Start); il.Emit(OpCodes.Ldloc, varsStart + 1); @@ -1812,35 +1812,12 @@ namespace Flax.Build.Plugins else il.Emit(OpCodes.Ldnull); var endInvokeRPC = networkReplicatorType.Resolve().GetMethod("EndInvokeRPC", 5); + if (endInvokeRPC.ReturnType.FullName != boolType.FullName) + throw new Exception("Invalid EndInvokeRPC return type. Remove any 'Binaries' folders to force project recompile."); il.Emit(OpCodes.Call, module.ImportReference(endInvokeRPC)); - // if (server && networkMode == NetworkManagerMode.Client) return; - if (methodRPC.IsServer) - { - il.Emit(OpCodes.Nop); - il.Emit(OpCodes.Ldloc, varsStart + 2); - il.Emit(OpCodes.Ldc_I4_2); - var tmp = ilp.Create(OpCodes.Nop); - il.Emit(OpCodes.Beq_S, tmp); - il.Emit(OpCodes.Br, jumpBodyStart); - il.Emit(tmp); - //il.Emit(OpCodes.Ret); - il.Emit(OpCodes.Br, jumpBodyEnd); - } - - // if (client && networkMode == NetworkManagerMode.Server) return; - if (methodRPC.IsClient) - { - il.Emit(OpCodes.Nop); - il.Emit(OpCodes.Ldloc, varsStart + 2); - il.Emit(OpCodes.Ldc_I4_1); - var tmp = ilp.Create(OpCodes.Nop); - il.Emit(OpCodes.Beq_S, tmp); - il.Emit(OpCodes.Br, jumpBodyStart); - il.Emit(tmp); - //il.Emit(OpCodes.Ret); - il.Emit(OpCodes.Br, jumpBodyEnd); - } + // if (EndInvokeRPC) return + il.Emit(OpCodes.Brtrue, jumpBodyEnd); // Continue to original method body il.Emit(jumpBodyStart); From 864f5f77f5024ab6e038fd1dfd82b7027cf2d520 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 14:53:23 +0200 Subject: [PATCH 13/85] Add output binaries folder cleanp to build clear command --- Source/Tools/Flax.Build/Build/Builder.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Source/Tools/Flax.Build/Build/Builder.cs b/Source/Tools/Flax.Build/Build/Builder.cs index 0765a94ab..aa0f7c879 100644 --- a/Source/Tools/Flax.Build/Build/Builder.cs +++ b/Source/Tools/Flax.Build/Build/Builder.cs @@ -143,6 +143,16 @@ namespace Flax.Build { Log.Info("Removing: " + targetBuildOptions.IntermediateFolder); CleanDirectory(intermediateFolder); + intermediateFolder.Create(); + } + + // Delete all output files + var outputFolder = new DirectoryInfo(targetBuildOptions.OutputFolder); + if (outputFolder.Exists) + { + Log.Info("Removing: " + targetBuildOptions.OutputFolder); + CleanDirectory(outputFolder); + outputFolder.Create(); } } } From bf6daed6d20957f2831ea8cc63399b5dd00fd325 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Wed, 28 Jun 2023 15:56:42 +0300 Subject: [PATCH 14/85] Fix Intellisense errors with referenced binary module structures --- Source/Tools/Flax.Build/Build/Builder.Projects.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Tools/Flax.Build/Build/Builder.Projects.cs b/Source/Tools/Flax.Build/Build/Builder.Projects.cs index 2860148de..4fbabe986 100644 --- a/Source/Tools/Flax.Build/Build/Builder.Projects.cs +++ b/Source/Tools/Flax.Build/Build/Builder.Projects.cs @@ -330,7 +330,7 @@ namespace Flax.Build var referenceBuildOptions = GetBuildOptions(referenceTarget, configurationData.TargetBuildOptions.Platform, configurationData.TargetBuildOptions.Toolchain, configurationData.Architecture, configurationData.Configuration, reference.Project.ProjectFolderPath); referenceBuildOptions.Flags |= BuildFlags.GenerateProject; var referenceModules = CollectModules(rules, referenceBuildOptions.Platform, referenceTarget, referenceBuildOptions, referenceBuildOptions.Toolchain, referenceBuildOptions.Architecture, referenceBuildOptions.Configuration); - var referenceBinaryModules = GetBinaryModules(projectInfo, referenceTarget, referenceModules); + var referenceBinaryModules = referenceModules.Keys.GroupBy(x => x.BinaryModuleName).ToArray(); foreach (var binaryModule in referenceBinaryModules) { project.Defines.Add(binaryModule.Key.ToUpperInvariant() + "_API="); From 9536c376234f8097a8d8154f9049ac97a5face34 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 15:12:58 +0200 Subject: [PATCH 15/85] Add ability to unset type reference with `null` item --- Source/Editor/GUI/Popups/TypeSearchPopup.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Source/Editor/GUI/Popups/TypeSearchPopup.cs b/Source/Editor/GUI/Popups/TypeSearchPopup.cs index 9d9ee2040..73c5baab7 100644 --- a/Source/Editor/GUI/Popups/TypeSearchPopup.cs +++ b/Source/Editor/GUI/Popups/TypeSearchPopup.cs @@ -27,6 +27,17 @@ namespace FlaxEditor.GUI /// public ScriptType Type => _type; + /// + /// Initializes a new instance of the class. + /// + public TypeItemView() + { + _type = ScriptType.Null; + Name = ""; + TooltipText = "Unset value."; + Tag = _type; + } + /// /// Initializes a new instance of the class. /// @@ -83,6 +94,7 @@ namespace FlaxEditor.GUI // TODO: use async thread to search types without UI stall var allTypes = Editor.Instance.CodeEditing.All.Get(); + AddItem(new TypeItemView()); for (int i = 0; i < allTypes.Count; i++) { var type = allTypes[i]; From 890248edf218e81466f07c2dbf69a41f53f22230 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 15:13:33 +0200 Subject: [PATCH 16/85] Fix `MClass::HasInterface` in .NET 7 --- Source/Engine/Scripting/Runtime/DotNet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index 1736cc106..246c1620f 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -846,7 +846,7 @@ bool MClass::IsSubClassOf(const MClass* klass, bool checkInterfaces) const bool MClass::HasInterface(const MClass* klass) const { static void* TypeIsAssignableFrom = GetStaticMethodPointer(TEXT("TypeIsAssignableFrom")); - return klass && CallStaticMethod(TypeIsAssignableFrom, _handle, klass->_handle); + return klass && CallStaticMethod(TypeIsAssignableFrom, klass->_handle, _handle); } bool MClass::IsInstanceOfType(MObject* object) const From c44e97c8bc8ea413056412e5a0e747a295e94835 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 15:22:48 +0200 Subject: [PATCH 17/85] Bump build number --- Flax.flaxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flax.flaxproj b/Flax.flaxproj index d8e86b1ed..7cebe1714 100644 --- a/Flax.flaxproj +++ b/Flax.flaxproj @@ -3,7 +3,7 @@ "Version": { "Major": 1, "Minor": 6, - "Build": 6342 + "Build": 6343 }, "Company": "Flax", "Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.", From bb3cefbe54d14182c971bced908d1ff4f1bec4ee Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 15:48:32 +0200 Subject: [PATCH 18/85] Add check for `NetworkClientsMask` to ensure it has capacity --- Source/Engine/Networking/NetworkReplicator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Engine/Networking/NetworkReplicator.cpp b/Source/Engine/Networking/NetworkReplicator.cpp index ae7549a50..daf2537f4 100644 --- a/Source/Engine/Networking/NetworkReplicator.cpp +++ b/Source/Engine/Networking/NetworkReplicator.cpp @@ -1151,6 +1151,7 @@ void NetworkInternal::NetworkReplicatorClientConnected(NetworkClient* client) { ScopeLock lock(ObjectsLock); NewClients.Add(client); + ASSERT(sizeof(NetworkClientsMask) * 8 >= (uint32)NetworkManager::Clients.Count()); // Ensure that clients mask can hold all of clients } void NetworkInternal::NetworkReplicatorClientDisconnected(NetworkClient* client) From 45a1d336899fb689d3ec8856719c881ec7a91069 Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Wed, 28 Jun 2023 09:56:15 -0400 Subject: [PATCH 19/85] fix orientation --- Source/Engine/Physics/Actors/WheeledVehicle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.cpp b/Source/Engine/Physics/Actors/WheeledVehicle.cpp index 995150bdc..f5f729d39 100644 --- a/Source/Engine/Physics/Actors/WheeledVehicle.cpp +++ b/Source/Engine/Physics/Actors/WheeledVehicle.cpp @@ -230,7 +230,7 @@ void WheeledVehicle::DrawPhysicsDebug(RenderView& view) { const Vector3 currentPos = wheel.Collider->GetPosition(); const Vector3 basePos = currentPos - Vector3(0, data.State.SuspensionOffset, 0); - const Quaternion wheelDebugOrientation = wheel.Collider->GetOrientation() * Quaternion::Euler(90, 0, 90); + const Quaternion wheelDebugOrientation = GetOrientation() * Quaternion::Euler(-data.State.RotationAngle, data.State.SteerAngle, 0) * Quaternion::Euler(90, 0, 90); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(basePos, wheel.Radius * 0.07f), Color::Blue * 0.3f, 0, true); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(currentPos, wheel.Radius * 0.08f), Color::Blue * 0.8f, 0, true); DEBUG_DRAW_LINE(basePos, currentPos, Color::Blue, 0, true); @@ -261,7 +261,7 @@ void WheeledVehicle::OnDebugDrawSelected() { const Vector3 currentPos = wheel.Collider->GetPosition(); const Vector3 basePos = currentPos - Vector3(0, data.State.SuspensionOffset, 0); - const Quaternion wheelDebugOrientation = wheel.Collider->GetOrientation() * Quaternion::Euler(90, 0, 90); + const Quaternion wheelDebugOrientation = GetOrientation() * Quaternion::Euler(-data.State.RotationAngle, data.State.SteerAngle, 0) * Quaternion::Euler(90, 0, 90); Transform actorPose = Transform::Identity, shapePose = Transform::Identity; PhysicsBackend::GetRigidActorPose(_actor, actorPose.Translation, actorPose.Orientation); PhysicsBackend::GetShapeLocalPose(wheel.Collider->GetPhysicsShape(), shapePose.Translation, shapePose.Orientation); From bb9711277ae8094323f255c514bd66e222542c67 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 16:27:42 +0200 Subject: [PATCH 20/85] Cleanup code from #1213 --- .../Viewport/Previews/AnimatedModelPreview.cs | 12 +-- .../Viewport/Previews/MaterialPreview.cs | 48 +++++------ .../Viewport/Previews/ModelBasePreview.cs | 8 +- .../Editor/Viewport/Previews/ModelPreview.cs | 79 ++++++++----------- .../Viewport/Previews/SkinnedModelPreview.cs | 65 +++++++-------- .../Windows/Assets/CollisionDataWindow.cs | 4 +- Source/Editor/Windows/Assets/ModelWindow.cs | 4 +- .../Windows/Assets/SkinnedModelWindow.cs | 6 +- 8 files changed, 88 insertions(+), 138 deletions(-) diff --git a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs index aae48fe11..4a1c57757 100644 --- a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs +++ b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs @@ -3,8 +3,6 @@ using System; using FlaxEditor.GUI.ContextMenu; using FlaxEngine; -using FlaxEditor.GUI.Input; -using FlaxEngine.GUI; using Object = FlaxEngine.Object; namespace FlaxEditor.Viewport.Previews @@ -15,13 +13,10 @@ namespace FlaxEditor.Viewport.Previews /// public class AnimatedModelPreview : AssetPreview { - /// public AnimatedModel _previewModel; - private ContextMenuButton _showNodesButton, _showBoundsButton, _showFloorButton, _showNodesNamesButton; private bool _showNodes, _showBounds, _showFloor, _showNodesNames; private StaticModel _floorModel; - private bool _playAnimation, _playAnimationOnce; private float _playSpeed = 1.0f; @@ -404,9 +399,9 @@ namespace FlaxEditor.Viewport.Previews } /// - /// Calls SetArcBallView from ViewportCamera + /// Resets the camera to focus on a object. /// - public void CallSetArcBallView() + public void ResetCamera() { ViewportCamera.SetArcBallView(_previewModel.Box); } @@ -417,8 +412,7 @@ namespace FlaxEditor.Viewport.Previews switch (key) { case KeyboardKeys.F: - // Pay respect.. - CallSetArcBallView(); + ResetCamera(); return true; case KeyboardKeys.Spacebar: PlayAnimation = !PlayAnimation; diff --git a/Source/Editor/Viewport/Previews/MaterialPreview.cs b/Source/Editor/Viewport/Previews/MaterialPreview.cs index 3dfab1cff..5520d6c4c 100644 --- a/Source/Editor/Viewport/Previews/MaterialPreview.cs +++ b/Source/Editor/Viewport/Previews/MaterialPreview.cs @@ -48,6 +48,7 @@ namespace FlaxEditor.Viewport.Previews private int _selectedModelIndex; private Image _guiMaterialControl; private readonly MaterialBase[] _postFxMaterialsCache = new MaterialBase[1]; + private ContextMenu _modelWidgetButtonMenu; /// /// Gets or sets the material asset to preview. It can be or . @@ -65,11 +66,6 @@ namespace FlaxEditor.Viewport.Previews } } - /// - /// The "Model" widget button context menu. - /// - private ContextMenu modelWidgetButtonMenu; - /// /// Gets or sets the selected preview model index. /// @@ -87,27 +83,6 @@ namespace FlaxEditor.Viewport.Previews } } - /// - /// Fill out all models - /// - /// - private void ModelWidgetMenuOnVisibleChanged(Control control) - { - if (!control.Visible) return; - - modelWidgetButtonMenu.ItemsContainer.DisposeChildren(); - - // Fill out all models - for (int i = 0; i < Models.Length; i++) - { - var index = i; - var button = modelWidgetButtonMenu.AddButton(Models[index]); - button.ButtonClicked += (button) => SelectedModelIndex = index; - button.Checked = SelectedModelIndex == index; - button.Tag = index; - } - } - /// /// Initializes a new instance of the class. /// @@ -127,9 +102,24 @@ namespace FlaxEditor.Viewport.Previews { // Model mode widget var modelMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); - modelWidgetButtonMenu = new ContextMenu(); - modelWidgetButtonMenu.VisibleChanged += ModelWidgetMenuOnVisibleChanged; - var previewLODSModeButton = new ViewportWidgetButton("Model", SpriteHandle.Invalid, modelWidgetButtonMenu) + _modelWidgetButtonMenu = new ContextMenu(); + _modelWidgetButtonMenu.VisibleChanged += control => + { + if (!control.Visible) + return; + _modelWidgetButtonMenu.ItemsContainer.DisposeChildren(); + + // Fill out all models + for (int i = 0; i < Models.Length; i++) + { + var index = i; + var button = _modelWidgetButtonMenu.AddButton(Models[index]); + button.ButtonClicked += _ => SelectedModelIndex = index; + button.Checked = SelectedModelIndex == index; + button.Tag = index; + } + }; + new ViewportWidgetButton("Model", SpriteHandle.Invalid, _modelWidgetButtonMenu) { TooltipText = "Change material model", Parent = modelMode, diff --git a/Source/Editor/Viewport/Previews/ModelBasePreview.cs b/Source/Editor/Viewport/Previews/ModelBasePreview.cs index e5834edc9..e4f1109d4 100644 --- a/Source/Editor/Viewport/Previews/ModelBasePreview.cs +++ b/Source/Editor/Viewport/Previews/ModelBasePreview.cs @@ -1,6 +1,5 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. -using FlaxEditor.GUI.Input; using FlaxEngine; using Object = FlaxEngine.Object; @@ -59,9 +58,9 @@ namespace FlaxEditor.Viewport.Previews } /// - /// Calls SetArcBallView from ViewportCamera + /// Resets the camera to focus on a object. /// - public void CallSetArcBallView() + public void ResetCamera() { ViewportCamera.SetArcBallView(StaticModel.Model != null ? StaticModel.Box : AnimatedModel.Box); } @@ -92,8 +91,7 @@ namespace FlaxEditor.Viewport.Previews switch (key) { case KeyboardKeys.F: - // Pay respect.. - CallSetArcBallView(); + ResetCamera(); break; } return base.OnKeyDown(key); diff --git a/Source/Editor/Viewport/Previews/ModelPreview.cs b/Source/Editor/Viewport/Previews/ModelPreview.cs index dc0de37da..a0b6d0ca0 100644 --- a/Source/Editor/Viewport/Previews/ModelPreview.cs +++ b/Source/Editor/Viewport/Previews/ModelPreview.cs @@ -1,7 +1,6 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using FlaxEditor.GUI.ContextMenu; -using FlaxEditor.GUI.Input; using FlaxEngine; using FlaxEngine.GUI; using FlaxEngine.Utilities; @@ -17,15 +16,11 @@ namespace FlaxEditor.Viewport.Previews public class ModelPreview : AssetPreview { private ContextMenuButton _showBoundsButton, _showCurrentLODButton, _showNormalsButton, _showTangentsButton, _showBitangentsButton, _showFloorButton; + private ContextMenu _previewLODsWidgetButtonMenu; private StaticModel _previewModel, _floorModel; private bool _showBounds, _showCurrentLOD, _showNormals, _showTangents, _showBitangents, _showFloor; private MeshDataCache _meshDatas; - /// - /// The "PreviewLODS" widget button context menu. - /// - private ContextMenu previewLODSWidgetButtonMenu; - /// /// Gets or sets a value that shows LOD statistics /// @@ -37,8 +32,6 @@ namespace FlaxEditor.Viewport.Previews if (_showCurrentLOD == value) return; _showCurrentLOD = value; - if (value) - ShowDebugDraw = true; if (_showCurrentLODButton != null) _showCurrentLODButton.Checked = value; } @@ -222,42 +215,36 @@ namespace FlaxEditor.Viewport.Previews }); _showCurrentLODButton.IndexInParent = 2; - // PreviewLODS mode widget - var PreviewLODSMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); - previewLODSWidgetButtonMenu = new ContextMenu(); - previewLODSWidgetButtonMenu.VisibleChanged += PreviewLODSWidgetMenuOnVisibleChanged; - var previewLODSModeButton = new ViewportWidgetButton("Preview LOD", SpriteHandle.Invalid, previewLODSWidgetButtonMenu) + // Preview LODs mode widget + var PreviewLODsMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); + _previewLODsWidgetButtonMenu = new ContextMenu(); + _previewLODsWidgetButtonMenu.VisibleChanged += control => + { + if (!control.Visible) + return; + var model = _previewModel.Model; + if (model && !model.WaitForLoaded()) + { + _previewLODsWidgetButtonMenu.ItemsContainer.DisposeChildren(); + var lods = model.LODs.Length; + for (int i = -1; i < lods; i++) + { + var index = i; + var button = _previewLODsWidgetButtonMenu.AddButton("LOD " + (index == -1 ? "Auto" : index)); + button.ButtonClicked += _ => _previewModel.ForcedLOD = index; + button.Checked = _previewModel.ForcedLOD == index; + button.Tag = index; + if (lods <= 1) + break; + } + } + }; + new ViewportWidgetButton("Preview LOD", SpriteHandle.Invalid, _previewLODsWidgetButtonMenu) { TooltipText = "Preview LOD properties", - Parent = PreviewLODSMode, + Parent = PreviewLODsMode, }; - PreviewLODSMode.Parent = this; - } - } - - /// - /// Fill out all Model LODS - /// - /// - private void PreviewLODSWidgetMenuOnVisibleChanged(Control control) - { - if (!control.Visible) - return; - - var model = _previewModel.Model; - if (model && !model.WaitForLoaded() && model.IsLoaded) - { - previewLODSWidgetButtonMenu.ItemsContainer.DisposeChildren(); - var lods = model.LODs.Length; - for (int i = -1; i < lods; i++) - { - var index = i; - var button = previewLODSWidgetButtonMenu.AddButton("LOD " + (index == -1 ? "Auto" : index)); - button.ButtonClicked += (button) => _previewModel.ForcedLOD = index; - button.Checked = _previewModel.ForcedLOD == index; - button.Tag = index; - if (lods <= 1) return; - } + PreviewLODsMode.Parent = this; } } @@ -361,7 +348,7 @@ namespace FlaxEditor.Viewport.Previews var distSqr = Vector3.DistanceSquared(ref sphere.Center, ref viewOrigin); var screenRadiusSquared = Mathf.Square(screenMultiple * sphere.Radius) / Mathf.Max(1.0f, distSqr); screenSize = Mathf.Sqrt((float)screenRadiusSquared) * 2.0f; - + // Check if model is being culled if (Mathf.Square(model.MinScreenSize * 0.5f) > screenRadiusSquared) return -1; @@ -422,9 +409,9 @@ namespace FlaxEditor.Viewport.Previews } /// - /// Calls SetArcBallView from ViewportCamera + /// Resets the camera to focus on a object. /// - public void CallSetArcBallView() + public void ResetCamera() { ViewportCamera.SetArcBallView(_previewModel.Box); } @@ -435,8 +422,7 @@ namespace FlaxEditor.Viewport.Previews switch (key) { case KeyboardKeys.F: - // Pay respect.. - CallSetArcBallView(); + ResetCamera(); break; } return base.OnKeyDown(key); @@ -449,6 +435,7 @@ namespace FlaxEditor.Viewport.Previews Object.Destroy(ref _previewModel); _showBoundsButton = null; _showCurrentLODButton = null; + _previewLODsWidgetButtonMenu = null; _showNormalsButton = null; _showTangentsButton = null; _showBitangentsButton = null; diff --git a/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs b/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs index a8b98b423..c11ea9ea4 100644 --- a/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs +++ b/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs @@ -1,4 +1,5 @@ -using System; +// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. + using FlaxEditor.GUI.ContextMenu; using FlaxEngine; using FlaxEngine.GUI; @@ -14,11 +15,7 @@ namespace FlaxEditor.Viewport.Previews { private bool _showCurrentLOD; private ContextMenuButton _showCurrentLODButton; - - /// - /// The "PreviewLODS" widget button context menu. - /// - private ContextMenu previewLODSWidgetButtonMenu; + private ContextMenu _previewLODsWidgetButtonMenu; /// /// Gets or sets a value that shows LOD statistics @@ -31,8 +28,6 @@ namespace FlaxEditor.Viewport.Previews if (_showCurrentLOD == value) return; _showCurrentLOD = value; - if (value) - ShowDebugDraw = true; if (_showCurrentLODButton != null) _showCurrentLODButton.Checked = value; } @@ -57,9 +52,29 @@ namespace FlaxEditor.Viewport.Previews // PreviewLODS mode widget var PreviewLODSMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); - previewLODSWidgetButtonMenu = new ContextMenu(); - previewLODSWidgetButtonMenu.VisibleChanged += PreviewLODSWidgetMenuOnVisibleChanged; - var previewLODSModeButton = new ViewportWidgetButton("Preview LOD", SpriteHandle.Invalid, previewLODSWidgetButtonMenu) + _previewLODsWidgetButtonMenu = new ContextMenu(); + _previewLODsWidgetButtonMenu.VisibleChanged += control => + { + if (!control.Visible) + return; + var skinned = _previewModel.SkinnedModel; + if (skinned && !skinned.WaitForLoaded()) + { + _previewLODsWidgetButtonMenu.ItemsContainer.DisposeChildren(); + var lods = skinned.LODs.Length; + for (int i = -1; i < lods; i++) + { + var index = i; + var button = _previewLODsWidgetButtonMenu.AddButton("LOD " + (index == -1 ? "Auto" : index)); + button.ButtonClicked += (button) => _previewModel.ForcedLOD = index; + button.Checked = _previewModel.ForcedLOD == index; + button.Tag = index; + if (lods <= 1) + break; + } + } + }; + new ViewportWidgetButton("Preview LOD", SpriteHandle.Invalid, _previewLODsWidgetButtonMenu) { TooltipText = "Preview LOD properties", Parent = PreviewLODSMode, @@ -68,33 +83,6 @@ namespace FlaxEditor.Viewport.Previews } } - /// - /// Fill out all SkinnedModel LODS - /// - /// - private void PreviewLODSWidgetMenuOnVisibleChanged(Control control) - { - if (!control.Visible) - return; - - var skinned = _previewModel.SkinnedModel; - if (skinned && !skinned.WaitForLoaded() && skinned.IsLoaded) - { - previewLODSWidgetButtonMenu.ItemsContainer.DisposeChildren(); - var lods = skinned.LODs.Length; - for (int i = -1; i < lods; i++) - { - var index = i; - var button = previewLODSWidgetButtonMenu.AddButton("LOD " + (index == -1 ? "Auto" : index)); - button.ButtonClicked += (button) => _previewModel.ForcedLOD = index; - button.Checked = _previewModel.ForcedLOD == index; - button.Tag = index; - if (lods <= 1) return; - } - } - } - - /// private int ComputeLODIndex(SkinnedModel model, out float screenSize) { screenSize = 1.0f; @@ -181,6 +169,7 @@ namespace FlaxEditor.Viewport.Previews public override void OnDestroy() { _showCurrentLODButton = null; + _previewLODsWidgetButtonMenu = null; base.OnDestroy(); } diff --git a/Source/Editor/Windows/Assets/CollisionDataWindow.cs b/Source/Editor/Windows/Assets/CollisionDataWindow.cs index 82e0681fa..cc1daa45b 100644 --- a/Source/Editor/Windows/Assets/CollisionDataWindow.cs +++ b/Source/Editor/Windows/Assets/CollisionDataWindow.cs @@ -182,9 +182,7 @@ namespace FlaxEditor.Windows.Assets { // Toolstrip _toolstrip.AddSeparator(); - - _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.CallSetArcBallView()).LinkTooltip("Show whole collision"); - + _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.ResetCamera()).LinkTooltip("Show whole collision"); _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/physics/colliders/collision-data.html")).LinkTooltip("See documentation to learn more"); // Split Panel diff --git a/Source/Editor/Windows/Assets/ModelWindow.cs b/Source/Editor/Windows/Assets/ModelWindow.cs index cc7657fc7..f70f6a3b5 100644 --- a/Source/Editor/Windows/Assets/ModelWindow.cs +++ b/Source/Editor/Windows/Assets/ModelWindow.cs @@ -788,9 +788,7 @@ namespace FlaxEditor.Windows.Assets // Toolstrip _toolstrip.AddSeparator(); _showCurrentLODButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Info64, () => _preview.ShowCurrentLOD = !_preview.ShowCurrentLOD).LinkTooltip("Show LOD statistics"); - - _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.CallSetArcBallView()).LinkTooltip("Show whole model"); - + _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.ResetCamera()).LinkTooltip("Show whole model"); _toolstrip.AddSeparator(); _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/models/index.html")).LinkTooltip("See documentation to learn more"); diff --git a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs index 367fc3a1a..a7ee6e767 100644 --- a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs +++ b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs @@ -1117,13 +1117,9 @@ namespace FlaxEditor.Windows.Assets { // Toolstrip _toolstrip.AddSeparator(); - _showCurrentLODButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Info64, () => _preview.ShowCurrentLOD = !_preview.ShowCurrentLOD).LinkTooltip("Show LOD statistics"); - _showNodesButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Bone64, () => _preview.ShowNodes = !_preview.ShowNodes).LinkTooltip("Show animated model nodes debug view"); - - _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.CallSetArcBallView()).LinkTooltip("Show whole model"); - + _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.ResetCamera()).LinkTooltip("Show whole model"); _toolstrip.AddSeparator(); _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/skinned-model/index.html")).LinkTooltip("See documentation to learn more"); From ac54838eea13d6caafb2c3dda75317d0f9becf69 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 18:46:46 +0200 Subject: [PATCH 21/85] Fix custom editor window restore after hot-reload #1208 --- Source/Editor/CustomEditorWindow.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Source/Editor/CustomEditorWindow.cs b/Source/Editor/CustomEditorWindow.cs index 2d5293f30..242b4d28d 100644 --- a/Source/Editor/CustomEditorWindow.cs +++ b/Source/Editor/CustomEditorWindow.cs @@ -3,7 +3,6 @@ using FlaxEditor.CustomEditors; using FlaxEditor.Windows; using FlaxEngine.GUI; -using FlaxEngine; using DockState = FlaxEditor.GUI.Docking.DockState; namespace FlaxEditor @@ -86,8 +85,12 @@ namespace FlaxEditor if (!FlaxEngine.Scripting.IsTypeFromGameScripts(type)) return; - Editor.Instance.Windows.AddToRestore(this); + if (!Window.IsHidden) + { + Editor.Instance.Windows.AddToRestore(this); + } Window.Close(); + Window.Dispose(); } /// From 70ab159dd4bc518d41ff5811bdb30840a537ec8f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 19:55:10 +0200 Subject: [PATCH 22/85] Fix empty clients mask for `NetworkReplicationHierarchy` on client to properly replicate client-owned objects #1205 --- Source/Engine/Networking/NetworkReplicationHierarchy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp index 5097b6a26..6ec5e52c2 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp @@ -23,7 +23,7 @@ void NetworkReplicationHierarchyUpdateResult::Init() { _clientsHaveLocation = false; _clients.Resize(NetworkManager::Clients.Count()); - _clientsMask = NetworkClientsMask(); + _clientsMask = NetworkManager::Mode == NetworkManagerMode::Client ? NetworkClientsMask::All : NetworkClientsMask(); for (int32 i = 0; i < _clients.Count(); i++) _clientsMask.SetBit(i); _entries.Clear(); From 04c1cf469d12d86a6f69ce7d70f667adf07cde98 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 20:08:35 +0200 Subject: [PATCH 23/85] Fix codegen for C++ RPS with Array ParameterDefinition #1209 --- Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs | 2 +- Source/Tools/Flax.Build/Bindings/TypeInfo.cs | 6 +++--- Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index 0cb8982a2..d69b8dcbf 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -1204,7 +1204,7 @@ namespace Flax.Build.Bindings if (apiType != null) { if (parameterInfo.IsOut) - contents.Append(indent).AppendFormat("{1} {0}Temp;", parameterInfo.Name, new TypeInfo(parameterInfo.Type) { IsRef = false }.GetFullNameNative(buildData, caller)).AppendLine(); + contents.Append(indent).AppendFormat("{1} {0}Temp;", parameterInfo.Name, parameterInfo.Type.GetFullNameNative(buildData, caller, false)).AppendLine(); else contents.Append(indent).AppendFormat("auto {0}Temp = {1};", parameterInfo.Name, param).AppendLine(); if (parameterInfo.Type.IsPtr && !parameterInfo.Type.IsRef) diff --git a/Source/Tools/Flax.Build/Bindings/TypeInfo.cs b/Source/Tools/Flax.Build/Bindings/TypeInfo.cs index 7b2326527..df47c85e4 100644 --- a/Source/Tools/Flax.Build/Bindings/TypeInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/TypeInfo.cs @@ -144,7 +144,7 @@ namespace Flax.Build.Bindings GenericArgs = BindingsGenerator.Read(reader, GenericArgs); } - public string GetFullNameNative(Builder.BuildData buildData, ApiTypeInfo caller) + public string GetFullNameNative(Builder.BuildData buildData, ApiTypeInfo caller, bool canRef = true, bool canConst = true) { var type = BindingsGenerator.FindApiTypeInfo(buildData, this, caller); if (type == null) @@ -155,7 +155,7 @@ namespace Flax.Build.Bindings return type.FullNameNative; var sb = new StringBuilder(64); - if (IsConst) + if (IsConst && canConst) sb.Append("const "); sb.Append(type.FullNameNative); if (GenericArgs != null) @@ -171,7 +171,7 @@ namespace Flax.Build.Bindings } if (IsPtr) sb.Append('*'); - if (IsRef) + if (IsRef && canRef) sb.Append('&'); return sb.ToString(); } diff --git a/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs b/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs index b24b887b3..d76fc43cc 100644 --- a/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs +++ b/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs @@ -241,7 +241,7 @@ namespace Flax.Build.Plugins // Deserialize arguments argNames += arg.Name; - contents.AppendLine($" {arg.Type.Type} {arg.Name};"); + contents.AppendLine($" {arg.Type.GetFullNameNative(buildData, typeInfo, false, false)} {arg.Name};"); contents.AppendLine($" stream->Read({arg.Name});"); } @@ -270,7 +270,7 @@ namespace Flax.Build.Plugins } // Serialize arguments - contents.AppendLine($" stream->Write(*({arg.Type.Type}*)args[{i}]);"); + contents.AppendLine($" stream->Write(*(const {arg.Type.GetFullNameNative(buildData, typeInfo, false, false)}*)args[{i}]);"); } // Invoke RPC From 3119c507899961b7ad141479f7d20b6d07e7d677 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 20:09:01 +0200 Subject: [PATCH 24/85] Fix nullable warnings --- Source/Editor/ProjectInfo.cs | 4 ++-- .../Engine/Engine/NativeInterop.Marshallers.cs | 18 +++++++++--------- Source/Engine/Engine/NativeInterop.cs | 2 +- Source/Engine/Utilities/Utils.cs | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Source/Editor/ProjectInfo.cs b/Source/Editor/ProjectInfo.cs index ed9470c35..b00c4e042 100644 --- a/Source/Editor/ProjectInfo.cs +++ b/Source/Editor/ProjectInfo.cs @@ -20,7 +20,7 @@ namespace FlaxEditor /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (value == null) { @@ -44,7 +44,7 @@ namespace FlaxEditor /// The existing property value of the JSON that is being converted. /// The calling serializer. /// The object value. - public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { diff --git a/Source/Engine/Engine/NativeInterop.Marshallers.cs b/Source/Engine/Engine/NativeInterop.Marshallers.cs index a3531d11d..0a23bfcbd 100644 --- a/Source/Engine/Engine/NativeInterop.Marshallers.cs +++ b/Source/Engine/Engine/NativeInterop.Marshallers.cs @@ -350,14 +350,14 @@ namespace FlaxEngine.Interop #endif public static class NativeToManaged { - public static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) + public static T[] AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) { if (unmanaged is null) return null; return new T[numElements]; } - public static Span GetManagedValuesDestination(T[]? managed) => managed; + public static Span GetManagedValuesDestination(T[] managed) => managed; public static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements) { @@ -390,7 +390,7 @@ namespace FlaxEngine.Interop #endif public static class ManagedToNative { - public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[] managed, out int numElements) { if (managed is null) { @@ -402,7 +402,7 @@ namespace FlaxEngine.Interop return (TUnmanagedElement*)ManagedHandle.ToIntPtr(managedArray, GCHandleType.Weak); } - public static ReadOnlySpan GetManagedValuesSource(T[]? managed) => managed; + public static ReadOnlySpan GetManagedValuesSource(T[] managed) => managed; public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) { @@ -431,7 +431,7 @@ namespace FlaxEngine.Interop ManagedArray unmanagedArray; ManagedHandle handle; - public void FromManaged(T[]? managed) + public void FromManaged(T[] managed) { if (managed == null) return; @@ -476,7 +476,7 @@ namespace FlaxEngine.Interop } } - public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[] managed, out int numElements) { if (managed is null) { @@ -489,7 +489,7 @@ namespace FlaxEngine.Interop return (TUnmanagedElement*)handle; } - public static ReadOnlySpan GetManagedValuesSource(T[]? managed) => managed; + public static ReadOnlySpan GetManagedValuesSource(T[] managed) => managed; public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) { @@ -499,9 +499,9 @@ namespace FlaxEngine.Interop return unmanagedArray.ToSpan(); } - public static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) => unmanaged is null ? null : new T[numElements]; + public static T[] AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) => unmanaged is null ? null : new T[numElements]; - public static Span GetManagedValuesDestination(T[]? managed) => managed; + public static Span GetManagedValuesDestination(T[] managed) => managed; public static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements) { diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index faa19d060..4aedbe171 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -96,7 +96,7 @@ namespace FlaxEngine.Interop } #if FLAX_EDITOR - private static Assembly? OnScriptingAssemblyLoadContextResolving(AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName) + private static Assembly OnScriptingAssemblyLoadContextResolving(AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName) { // FIXME: There should be a better way to resolve the path to EditorTargetPath where the dependencies are stored string editorTargetPath = Path.GetDirectoryName(nativeLibraryPaths.Keys.First(x => x != "FlaxEngine")); diff --git a/Source/Engine/Utilities/Utils.cs b/Source/Engine/Utilities/Utils.cs index 5ac43ecd9..cb385efcf 100644 --- a/Source/Engine/Utilities/Utils.cs +++ b/Source/Engine/Utilities/Utils.cs @@ -255,7 +255,7 @@ namespace FlaxEngine #else private class ExtractArrayFromListContext { - public static FieldInfo? itemsField; + public static FieldInfo itemsField; } internal static T[] ExtractArrayFromList(List list) { From 96589557b32f417423a1ea6729dd0aa6586f9e05 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 20:09:18 +0200 Subject: [PATCH 25/85] Fix access level 96a1f20bee63c2096c435e75d3a7dd48622aa05e --- .../Editor/Viewport/Previews/AnimatedModelPreview.cs | 2 +- Source/Editor/Viewport/Previews/SkinnedModelPreview.cs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs index 4a1c57757..9a7ec6800 100644 --- a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs +++ b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs @@ -13,7 +13,7 @@ namespace FlaxEditor.Viewport.Previews /// public class AnimatedModelPreview : AssetPreview { - public AnimatedModel _previewModel; + private AnimatedModel _previewModel; private ContextMenuButton _showNodesButton, _showBoundsButton, _showFloorButton, _showNodesNamesButton; private bool _showNodes, _showBounds, _showFloor, _showNodesNames; private StaticModel _floorModel; diff --git a/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs b/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs index c11ea9ea4..08f8d8509 100644 --- a/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs +++ b/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs @@ -57,7 +57,7 @@ namespace FlaxEditor.Viewport.Previews { if (!control.Visible) return; - var skinned = _previewModel.SkinnedModel; + var skinned = PreviewActor.SkinnedModel; if (skinned && !skinned.WaitForLoaded()) { _previewLODsWidgetButtonMenu.ItemsContainer.DisposeChildren(); @@ -66,8 +66,8 @@ namespace FlaxEditor.Viewport.Previews { var index = i; var button = _previewLODsWidgetButtonMenu.AddButton("LOD " + (index == -1 ? "Auto" : index)); - button.ButtonClicked += (button) => _previewModel.ForcedLOD = index; - button.Checked = _previewModel.ForcedLOD == index; + button.ButtonClicked += (button) => PreviewActor.ForcedLOD = index; + button.Checked = PreviewActor.ForcedLOD == index; button.Tag = index; if (lods <= 1) break; @@ -128,7 +128,7 @@ namespace FlaxEditor.Viewport.Previews { base.Draw(); - var skinnedModel = _previewModel.SkinnedModel; + var skinnedModel = PreviewActor.SkinnedModel; if (skinnedModel == null || !skinnedModel.IsLoaded) return; var lods = skinnedModel.LODs; @@ -141,7 +141,7 @@ namespace FlaxEditor.Viewport.Previews if (_showCurrentLOD) { var lodIndex = ComputeLODIndex(skinnedModel, out var screenSize); - var auto = _previewModel.ForcedLOD == -1; + var auto = PreviewActor.ForcedLOD == -1; string text = auto ? "LOD Automatic" : ""; text += auto ? string.Format("\nScreen Size: {0:F2}", screenSize) : ""; text += string.Format("\nCurrent LOD: {0}", lodIndex); From 0498f1488ebd052110dc3a28b6d094c82ec98e71 Mon Sep 17 00:00:00 2001 From: ExMatics HydrogenC <33123710+HydrogenC@users.noreply.github.com> Date: Fri, 30 Jun 2023 12:25:58 +0800 Subject: [PATCH 26/85] Fix space conversion issue --- Source/Engine/Level/Actors/AnimatedModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index 882026db7..2db3b6fae 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -127,7 +127,7 @@ void AnimatedModel::GetCurrentPose(Array& nodesTransformation, bool worl Matrix world; _transform.GetWorld(world); for (auto& m : nodesTransformation) - m = m * world; + m = world * m; } } From 804826fbc793dbc6bafa931e9789c26150937cfa Mon Sep 17 00:00:00 2001 From: ExMatics HydrogenC <33123710+HydrogenC@users.noreply.github.com> Date: Fri, 30 Jun 2023 14:06:52 +0800 Subject: [PATCH 27/85] Fix multiplication mistake --- Source/Engine/Level/Actors/AnimatedModel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index 2db3b6fae..b33878a50 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -127,7 +127,7 @@ void AnimatedModel::GetCurrentPose(Array& nodesTransformation, bool worl Matrix world; _transform.GetWorld(world); for (auto& m : nodesTransformation) - m = world * m; + m = m * world; } } @@ -144,7 +144,7 @@ void AnimatedModel::SetCurrentPose(const Array& nodesTransformation, boo Matrix invWorld; Matrix::Invert(world, invWorld); for (auto& m : GraphInstance.NodesPose) - m = invWorld * m; + m = m * invWorld; } OnAnimationUpdated(); } From 8c006f6e113401ce0aeabb90c5c9e22c87b22064 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 30 Jun 2023 10:00:12 +0200 Subject: [PATCH 28/85] Fix crash due to replicated objects leak upon system destruction --- Source/Engine/Networking/NetworkReplicator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Engine/Networking/NetworkReplicator.cpp b/Source/Engine/Networking/NetworkReplicator.cpp index daf2537f4..279391e31 100644 --- a/Source/Engine/Networking/NetworkReplicator.cpp +++ b/Source/Engine/Networking/NetworkReplicator.cpp @@ -1204,6 +1204,7 @@ void NetworkInternal::NetworkReplicatorClear() Objects.Remove(it); } } + Objects.Clear(); RpcQueue.Clear(); SpawnQueue.Clear(); DespawnQueue.Clear(); From d5100373be5ad999626b4f26130b067f9773ec4b Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 30 Jun 2023 10:38:08 +0200 Subject: [PATCH 29/85] Fix bugs in C# codegen for network data serialization --- Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs b/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs index d76fc43cc..d646a81cd 100644 --- a/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs +++ b/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs @@ -780,7 +780,7 @@ namespace Flax.Build.Plugins private static void GenerateCallINetworkSerializable(ref DotnetContext context, TypeDefinition type, string name, MethodDefinition method) { var m = new MethodDefinition(name, MethodAttributes.Public | MethodAttributes.HideBySig, context.VoidType); - m.Parameters.Add(new ParameterDefinition("stream", ParameterAttributes.None, context.NetworkStreamType)); + m.Parameters.Add(new ParameterDefinition("stream", ParameterAttributes.None, type.Module.ImportReference(context.NetworkStreamType))); ILProcessor il = m.Body.GetILProcessor(); il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ldarg_0); @@ -1304,7 +1304,10 @@ namespace Flax.Build.Plugins il.Emit(jmp4); valueContext.Load(ref il); il.Emit(OpCodes.Ldloc, varStart + 1); // idx - il.Emit(OpCodes.Ldelem_Ref); + if (elementType.IsValueType) + il.Emit(OpCodes.Ldelem_Any, elementType); + else + il.Emit(OpCodes.Ldelem_Ref); il.Emit(OpCodes.Stloc, varStart + 2); // // Serialize item value From 2bd2bd508122a9a8ef76606abc700b5cdbafead8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 30 Jun 2023 11:02:58 +0200 Subject: [PATCH 30/85] Fix crash when modifying animated model skeleton pose from gameplay code during update event --- Source/Engine/Level/Actors/AnimatedModel.cpp | 8 +++++++- Source/Engine/Level/Actors/AnimatedModel.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index 882026db7..148b57682 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -603,7 +603,13 @@ void AnimatedModel::OnAnimationUpdated_Sync() // Update synchronous stuff UpdateSockets(); ApplyRootMotion(GraphInstance.RootMotion); - AnimationUpdated(); + if (!_isDuringUpdateEvent) + { + // Prevent stack-overflow when gameplay modifies the pose within the event + _isDuringUpdateEvent = true; + AnimationUpdated(); + _isDuringUpdateEvent = false; + } } void AnimatedModel::OnAnimationUpdated() diff --git a/Source/Engine/Level/Actors/AnimatedModel.h b/Source/Engine/Level/Actors/AnimatedModel.h index ccd0ee3b5..33f206580 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.h +++ b/Source/Engine/Level/Actors/AnimatedModel.h @@ -60,6 +60,7 @@ private: AnimationUpdateMode _actualMode; uint32 _counter; Real _lastMinDstSqr; + bool _isDuringUpdateEvent = false; uint64 _lastUpdateFrame; BlendShapesInstance _blendShapes; ScriptingObjectReference _masterPose; From 0ee6aad3ec353b0efe8f50207bb66db6c1758707 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Fri, 30 Jun 2023 13:00:29 +0300 Subject: [PATCH 31/85] Remove old hot-reload files in project references --- Source/Editor/Scripting/ScriptsBuilder.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Source/Editor/Scripting/ScriptsBuilder.cpp b/Source/Editor/Scripting/ScriptsBuilder.cpp index eaffe5691..3082a531e 100644 --- a/Source/Editor/Scripting/ScriptsBuilder.cpp +++ b/Source/Editor/Scripting/ScriptsBuilder.cpp @@ -613,6 +613,28 @@ bool ScriptsBuilderService::Init() const String targetOutput = Globals::ProjectFolder / TEXT("Binaries") / target / platform / architecture / configuration; Array files; FileSystem::DirectoryGetFiles(files, targetOutput, TEXT("*.HotReload.*"), DirectorySearchOption::TopDirectoryOnly); + + for (const auto& reference : Editor::Project->References) + { + if (reference.Project->Name == TEXT("Flax")) + continue; + + String referenceTarget; + if (reference.Project->EditorTarget.HasChars()) + { + referenceTarget = reference.Project->EditorTarget.Get(); + } + else if (reference.Project->GameTarget.HasChars()) + { + referenceTarget = reference.Project->GameTarget.Get(); + } + if (referenceTarget.IsEmpty()) + continue; + + const String referenceTargetOutput = reference.Project->ProjectFolderPath / TEXT("Binaries") / referenceTarget / platform / architecture / configuration; + FileSystem::DirectoryGetFiles(files, referenceTargetOutput, TEXT("*.HotReload.*"), DirectorySearchOption::TopDirectoryOnly); + } + if (files.HasItems()) LOG(Info, "Removing {0} files from previous Editor run hot-reloads", files.Count()); for (auto& file : files) From 58618bd40260a1329847c90839af9f3f34b775f8 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Fri, 30 Jun 2023 14:40:49 +0300 Subject: [PATCH 32/85] Fix garbage DefaultScene value in new projects --- Source/Editor/ProjectInfo.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Editor/ProjectInfo.h b/Source/Editor/ProjectInfo.h index 256269cc9..9f52e414f 100644 --- a/Source/Editor/ProjectInfo.h +++ b/Source/Editor/ProjectInfo.h @@ -112,6 +112,7 @@ public: { Version = ::Version(1, 0); DefaultSceneSpawn = Ray(Vector3::Zero, Vector3::Forward); + DefaultScene = Guid::Empty; } /// From 28335478bd9275078fde606f742b1ed1a57403fc Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 2 Jul 2023 21:55:58 +0300 Subject: [PATCH 33/85] Fix managed library location resolver --- Source/Engine/Engine/NativeInterop.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 4aedbe171..a6eb5368c 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -99,11 +99,14 @@ namespace FlaxEngine.Interop private static Assembly OnScriptingAssemblyLoadContextResolving(AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName) { // FIXME: There should be a better way to resolve the path to EditorTargetPath where the dependencies are stored - string editorTargetPath = Path.GetDirectoryName(nativeLibraryPaths.Keys.First(x => x != "FlaxEngine")); + foreach (string nativeLibraryPath in nativeLibraryPaths.Values) + { + string editorTargetPath = Path.GetDirectoryName(nativeLibraryPath); - var assemblyPath = Path.Combine(editorTargetPath, assemblyName.Name + ".dll"); - if (File.Exists(assemblyPath)) - return assemblyLoadContext.LoadFromAssemblyPath(assemblyPath); + var assemblyPath = Path.Combine(editorTargetPath, assemblyName.Name + ".dll"); + if (File.Exists(assemblyPath)) + return assemblyLoadContext.LoadFromAssemblyPath(assemblyPath); + } return null; } #endif From 4f78f7920177e068e6606d36427233664563b61f Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 2 Jul 2023 22:12:18 +0300 Subject: [PATCH 34/85] Support line-breaks in API_INJECT_CODE macro --- Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs index b09b0c137..c05ab4e73 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs @@ -1417,6 +1417,9 @@ namespace Flax.Build.Bindings context.Tokenizer.SkipUntil(TokenType.Comma, out desc.Lang); desc.Code = context.Tokenizer.ExpectToken(TokenType.String).Value.Replace("\\\"", "\""); desc.Code = desc.Code.Substring(1, desc.Code.Length - 2); + desc.Code = desc.Code.Replace("\\\n", "\n"); + desc.Code = desc.Code.Replace("\\\r\n", "\n"); + desc.Code = desc.Code.Replace("\t", " "); context.Tokenizer.ExpectToken(TokenType.RightParent); return desc; } From 9a1fd12a8582afc5529a6667c3046f4da36f3584 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 3 Jul 2023 11:42:15 +0200 Subject: [PATCH 35/85] Fix sizeof struct within generic type instance #1219 --- .../CustomEditors/Dedicated/RagdollEditor.cs | 4 ++-- Source/Engine/Engine/NativeInterop.Managed.cs | 8 +++---- .../Engine/Engine/NativeInterop.Unmanaged.cs | 1 + Source/Engine/Engine/NativeInterop.cs | 23 ++++++++++++++++++- Source/Engine/Level/Spline.cs | 4 ++-- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs b/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs index 28c039dc8..5a10b9a52 100644 --- a/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs @@ -167,7 +167,7 @@ namespace FlaxEditor.CustomEditors.Dedicated Presenter.Undo?.AddAction(new MultiUndoAction(actions)); // Build ragdoll - SceneGraph.Actors.AnimatedModelNode.BuildRagdoll(animatedModel, options, ragdoll); + AnimatedModelNode.BuildRagdoll(animatedModel, options, ragdoll); } private void OnRebuildBone(Button button) @@ -191,7 +191,7 @@ namespace FlaxEditor.CustomEditors.Dedicated } // Build ragdoll - SceneGraph.Actors.AnimatedModelNode.BuildRagdoll(animatedModel, new AnimatedModelNode.RebuildOptions(), ragdoll, name); + AnimatedModelNode.BuildRagdoll(animatedModel, new AnimatedModelNode.RebuildOptions(), ragdoll, name); } private void OnRemoveBone(Button button) diff --git a/Source/Engine/Engine/NativeInterop.Managed.cs b/Source/Engine/Engine/NativeInterop.Managed.cs index 7eda1cdec..797b02d5b 100644 --- a/Source/Engine/Engine/NativeInterop.Managed.cs +++ b/Source/Engine/Engine/NativeInterop.Managed.cs @@ -50,13 +50,13 @@ namespace FlaxEngine.Interop /// The resources must be released by calling FreePooled() instead of Free()-method. public static ManagedArray WrapPooledArray(Array arr, Type arrayType) { - ManagedArray managedArray = ManagedArrayPool.Get(arr.Length * Marshal.SizeOf(arr.GetType().GetElementType())); + ManagedArray managedArray = ManagedArrayPool.Get(arr.Length * NativeInterop.GetTypeSize(arr.GetType().GetElementType())); managedArray.WrapArray(arr, arrayType); return managedArray; } internal static ManagedArray AllocateNewArray(int length, Type arrayType, Type elementType) - => new ManagedArray((IntPtr)NativeInterop.NativeAlloc(length, Marshal.SizeOf(elementType)), length, arrayType, elementType); + => new ManagedArray((IntPtr)NativeInterop.NativeAlloc(length, NativeInterop.GetTypeSize(elementType)), length, arrayType, elementType); internal static ManagedArray AllocateNewArray(IntPtr ptr, int length, Type arrayType, Type elementType) => new ManagedArray(ptr, length, arrayType, elementType); @@ -86,7 +86,7 @@ namespace FlaxEngine.Interop _length = arr.Length; _arrayType = arrayType; _elementType = arr.GetType().GetElementType(); - _elementSize = Marshal.SizeOf(_elementType); + _elementSize = NativeInterop.GetTypeSize(_elementType); } internal void Allocate(int length) where T : unmanaged @@ -117,7 +117,7 @@ namespace FlaxEngine.Interop _length = length; _arrayType = arrayType; _elementType = elementType; - _elementSize = Marshal.SizeOf(elementType); + _elementSize = NativeInterop.GetTypeSize(_elementType); } ~ManagedArray() diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index c079a14e1..d4a8d44f8 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -885,6 +885,7 @@ namespace FlaxEngine.Interop handle.Free(); fieldHandleCacheCollectible.Clear(); #endif + _typeSizeCache.Clear(); foreach (var pair in classAttributesCacheCollectible) pair.Value.Free(); diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index a6eb5368c..e82cb3858 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -46,6 +46,7 @@ namespace FlaxEngine.Interop #endif private static Dictionary classAttributesCacheCollectible = new(); private static Dictionary assemblyHandles = new(); + private static Dictionary _typeSizeCache = new(); private static Dictionary loadedNativeLibraries = new(); internal static Dictionary nativeLibraryPaths = new(); @@ -584,7 +585,7 @@ namespace FlaxEngine.Interop else if (fieldType.IsClass || fieldType.IsPointer) fieldAlignment = IntPtr.Size; else - fieldAlignment = Marshal.SizeOf(fieldType); + fieldAlignment = GetTypeSize(fieldType); } internal static void ToManagedField(FieldInfo field, ref T fieldOwner, IntPtr fieldPtr, out int fieldOffset) @@ -1088,6 +1089,26 @@ namespace FlaxEngine.Interop return handle; } + internal static int GetTypeSize(Type type) + { + if (!_typeSizeCache.TryGetValue(type, out var size)) + { + try + { + size = Marshal.SizeOf(type); + } + catch + { + // Workaround the issue where structure defined within generic type instance (eg. MyType.MyStruct) fails to get size + // https://github.com/dotnet/runtime/issues/46426 + var obj = Activator.CreateInstance(type); + size = Marshal.SizeOf(obj); + } + _typeSizeCache.Add(type, size); + } + return size; + } + private static class DelegateHelpers { #if USE_AOT diff --git a/Source/Engine/Level/Spline.cs b/Source/Engine/Level/Spline.cs index 28a6aff8c..a2c9aecde 100644 --- a/Source/Engine/Level/Spline.cs +++ b/Source/Engine/Level/Spline.cs @@ -23,8 +23,8 @@ namespace FlaxEngine if (_keyframes == null || _keyframes.Length != count) _keyframes = new BezierCurve.Keyframe[count]; #if !BUILD_RELEASE - if (Marshal.SizeOf(typeof(BezierCurve.Keyframe)) != Transform.SizeInBytes * 3 + sizeof(float)) - throw new Exception("Invalid size of BezierCurve keyframe " + Marshal.SizeOf(typeof(BezierCurve.Keyframe)) + " bytes."); + if (System.Runtime.CompilerServices.Unsafe.SizeOf.Keyframe>() != Transform.SizeInBytes * 3 + sizeof(float)) + throw new Exception("Invalid size of BezierCurve keyframe " + System.Runtime.CompilerServices.Unsafe.SizeOf.Keyframe>() + " bytes."); #endif Internal_GetKeyframes(__unmanagedPtr, _keyframes); return _keyframes; From 9d640656e6a2438c5203e1abb96fdb574f4d0be8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 3 Jul 2023 12:10:06 +0200 Subject: [PATCH 36/85] Fix `StringUtils::ConvertANSI2UTF16` to properly handle multi-byte characters Length #1225 --- Source/Engine/Core/Types/String.cpp | 4 ++-- Source/Engine/Core/Types/StringBuilder.h | 3 ++- Source/Engine/Core/Types/Variant.cpp | 6 ++++-- Source/Engine/Graphics/Shaders/GPUShader.cpp | 2 +- Source/Engine/Platform/StringUtils.h | 2 +- Source/Engine/Platform/Unix/UnixStringUtils.cpp | 7 ++++--- Source/Engine/Platform/Win32/Win32StringUtils.cpp | 8 +++++--- Source/Engine/Platform/Windows/WindowsPlatform.cpp | 3 ++- Source/Engine/Utilities/StringConverter.h | 10 +++++----- 9 files changed, 26 insertions(+), 19 deletions(-) diff --git a/Source/Engine/Core/Types/String.cpp b/Source/Engine/Core/Types/String.cpp index cee60c07c..3de255039 100644 --- a/Source/Engine/Core/Types/String.cpp +++ b/Source/Engine/Core/Types/String.cpp @@ -73,7 +73,7 @@ void String::Set(const char* chars, int32 length) _length = length; } if (chars) - StringUtils::ConvertANSI2UTF16(chars, _data, length); + StringUtils::ConvertANSI2UTF16(chars, _data, length, _length); } void String::SetUTF8(const char* chars, int32 length) @@ -112,7 +112,7 @@ void String::Append(const char* chars, int32 count) _data = (Char*)Platform::Allocate((_length + 1) * sizeof(Char), 16); Platform::MemoryCopy(_data, oldData, oldLength * sizeof(Char)); - StringUtils::ConvertANSI2UTF16(chars, _data + oldLength, count * sizeof(Char)); + StringUtils::ConvertANSI2UTF16(chars, _data + oldLength, count, _length); _data[_length] = 0; Platform::Free(oldData); diff --git a/Source/Engine/Core/Types/StringBuilder.h b/Source/Engine/Core/Types/StringBuilder.h index 39c1b3a84..051554a23 100644 --- a/Source/Engine/Core/Types/StringBuilder.h +++ b/Source/Engine/Core/Types/StringBuilder.h @@ -125,7 +125,8 @@ public: const int32 length = str && *str ? StringUtils::Length(str) : 0; const int32 prevCnt = _data.Count(); _data.AddDefault(length); - StringUtils::ConvertANSI2UTF16(str, _data.Get() + prevCnt, length); + int32 tmp; + StringUtils::ConvertANSI2UTF16(str, _data.Get() + prevCnt, length, tmp); return *this; } diff --git a/Source/Engine/Core/Types/Variant.cpp b/Source/Engine/Core/Types/Variant.cpp index 33ffde349..8232d415f 100644 --- a/Source/Engine/Core/Types/Variant.cpp +++ b/Source/Engine/Core/Types/Variant.cpp @@ -660,7 +660,8 @@ Variant::Variant(const StringAnsiView& v) const int32 length = v.Length() * sizeof(Char) + 2; AsBlob.Data = Allocator::Allocate(length); AsBlob.Length = length; - StringUtils::ConvertANSI2UTF16(v.Get(), (Char*)AsBlob.Data, v.Length()); + int32 tmp; + StringUtils::ConvertANSI2UTF16(v.Get(), (Char*)AsBlob.Data, v.Length(), tmp); ((Char*)AsBlob.Data)[v.Length()] = 0; } else @@ -2578,7 +2579,8 @@ void Variant::SetString(const StringAnsiView& str) AsBlob.Data = Allocator::Allocate(length); AsBlob.Length = length; } - StringUtils::ConvertANSI2UTF16(str.Get(), (Char*)AsBlob.Data, str.Length()); + int32 tmp; + StringUtils::ConvertANSI2UTF16(str.Get(), (Char*)AsBlob.Data, str.Length(), tmp); ((Char*)AsBlob.Data)[str.Length()] = 0; } diff --git a/Source/Engine/Graphics/Shaders/GPUShader.cpp b/Source/Engine/Graphics/Shaders/GPUShader.cpp index 2666bf36b..3639e01b1 100644 --- a/Source/Engine/Graphics/Shaders/GPUShader.cpp +++ b/Source/Engine/Graphics/Shaders/GPUShader.cpp @@ -145,7 +145,7 @@ bool GPUShader::Create(MemoryReadStream& stream) // Create CB #if GPU_ENABLE_RESOURCE_NAMING - String name = ToString() + TEXT(".CB") + i; + String name = String::Format(TEXT("{}.CB{}"), ToString(), i); #else String name; #endif diff --git a/Source/Engine/Platform/StringUtils.h b/Source/Engine/Platform/StringUtils.h index 04e644d2e..72b3b5f4b 100644 --- a/Source/Engine/Platform/StringUtils.h +++ b/Source/Engine/Platform/StringUtils.h @@ -179,7 +179,7 @@ public: public: // Converts characters from ANSI to UTF-16 - static void ConvertANSI2UTF16(const char* from, Char* to, int32 len); + static void ConvertANSI2UTF16(const char* from, Char* to, int32 fromLength, int32& toLength); // Converts characters from UTF-16 to ANSI static void ConvertUTF162ANSI(const Char* from, char* to, int32 len); diff --git a/Source/Engine/Platform/Unix/UnixStringUtils.cpp b/Source/Engine/Platform/Unix/UnixStringUtils.cpp index 7e5c34b24..daa705769 100644 --- a/Source/Engine/Platform/Unix/UnixStringUtils.cpp +++ b/Source/Engine/Platform/Unix/UnixStringUtils.cpp @@ -311,14 +311,14 @@ static inline uint32 Utf8ToUtf32Codepoint(const char* src, int32 length) } } -void StringUtils::ConvertANSI2UTF16(const char* from, Char* to, int32 len) +void StringUtils::ConvertANSI2UTF16(const char* from, Char* to, int32 fromLength, int32& toLength) { - const char* const u8end = from + len; + const char* const u8end = from + fromLength; const char* u8cur = from; char16_t* u16cur = to; while (u8cur < u8end) { - len = Utf8CodepointLength(*u8cur); + int32 len = Utf8CodepointLength(*u8cur); uint32 codepoint = Utf8ToUtf32Codepoint(u8cur, len); // Convert the UTF32 codepoint to one or more UTF16 codepoints @@ -336,6 +336,7 @@ void StringUtils::ConvertANSI2UTF16(const char* from, Char* to, int32 len) } u8cur += len; } + toLength = (int32)(u16cur - to); } static const char32_t kByteMask = 0x000000BF; diff --git a/Source/Engine/Platform/Win32/Win32StringUtils.cpp b/Source/Engine/Platform/Win32/Win32StringUtils.cpp index d1634d90d..2a9bcf174 100644 --- a/Source/Engine/Platform/Win32/Win32StringUtils.cpp +++ b/Source/Engine/Platform/Win32/Win32StringUtils.cpp @@ -179,10 +179,12 @@ const char* StringUtils::Find(const char* str, const char* toFind) return strstr(str, toFind); } -void StringUtils::ConvertANSI2UTF16(const char* from, Char* to, int32 len) +void StringUtils::ConvertANSI2UTF16(const char* from, Char* to, int32 fromLength, int32& toLength) { - if (len) - mbstowcs(to, from, len); + if (fromLength) + toLength = mbstowcs(to, from, fromLength); + else + toLength = 0; } void StringUtils::ConvertUTF162ANSI(const Char* from, char* to, int32 len) diff --git a/Source/Engine/Platform/Windows/WindowsPlatform.cpp b/Source/Engine/Platform/Windows/WindowsPlatform.cpp index 8d02312af..4d43272d1 100644 --- a/Source/Engine/Platform/Windows/WindowsPlatform.cpp +++ b/Source/Engine/Platform/Windows/WindowsPlatform.cpp @@ -992,7 +992,8 @@ void ReadPipe(HANDLE pipe, Array& rawData, Array& logData, LogType l // Log contents logData.Clear(); logData.Resize(rawData.Count() + 1); - StringUtils::ConvertANSI2UTF16(rawData.Get(), logData.Get(), rawData.Count()); + int32 tmp; + StringUtils::ConvertANSI2UTF16(rawData.Get(), logData.Get(), rawData.Count(), tmp); logData.Last() = '\0'; if (settings.LogOutput) Log::Logger::Write(logType, StringView(logData.Get(), rawData.Count())); diff --git a/Source/Engine/Utilities/StringConverter.h b/Source/Engine/Utilities/StringConverter.h index 340278c00..e494a8b94 100644 --- a/Source/Engine/Utilities/StringConverter.h +++ b/Source/Engine/Utilities/StringConverter.h @@ -49,7 +49,7 @@ public: { } - StringAsANSI(const Char* text, const int32 length) + StringAsANSI(const Char* text, int32 length) { if (length + 1 < InlinedSize) { @@ -83,7 +83,7 @@ public: { } - StringAsUTF8(const Char* text, const int32 length) + StringAsUTF8(const Char* text, int32 length) { int32 lengthUtf8; if (length + 1 < InlinedSize) @@ -112,17 +112,17 @@ public: { } - StringAsUTF16(const char* text, const int32 length) + StringAsUTF16(const char* text, int32 length) { if (length + 1 < InlinedSize) { - StringUtils::ConvertANSI2UTF16(text, this->_inlined, length); + StringUtils::ConvertANSI2UTF16(text, this->_inlined, length, length); this->_inlined[length] = 0; } else { this->_dynamic = (CharType*)Allocator::Allocate((length + 1) * sizeof(CharType)); - StringUtils::ConvertANSI2UTF16(text, this->_dynamic, length); + StringUtils::ConvertANSI2UTF16(text, this->_dynamic, length, length); this->_dynamic[length] = 0; } } From 544eb03f7e102e99f61b7708230f5967f65b28d0 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 3 Jul 2023 13:06:08 +0200 Subject: [PATCH 37/85] Add network replication support for in-built object/asset reference holders --- Source/Engine/Serialization/ReadStream.h | 28 +++++++++++++++++++++++ Source/Engine/Serialization/Stream.h | 8 +++++++ Source/Engine/Serialization/WriteStream.h | 20 ++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/Source/Engine/Serialization/ReadStream.h b/Source/Engine/Serialization/ReadStream.h index 9d3215442..26b536c6d 100644 --- a/Source/Engine/Serialization/ReadStream.h +++ b/Source/Engine/Serialization/ReadStream.h @@ -159,6 +159,34 @@ public: Read(ptr); v = ptr; } + template + FORCE_INLINE void Read(SoftObjectReference& v) + { + uint32 id[4]; + ReadBytes(id, sizeof(id)); + v.Set(*(Guid*)id); + } + template + FORCE_INLINE void Read(AssetReference& v) + { + uint32 id[4]; + ReadBytes(id, sizeof(id)); + v = (T*)::LoadAsset(*(Guid*)id, T::TypeInitializer); + } + template + FORCE_INLINE void Read(WeakAssetReference& v) + { + uint32 id[4]; + ReadBytes(id, sizeof(id)); + v = (T*)::LoadAsset(*(Guid*)id, T::TypeInitializer); + } + template + FORCE_INLINE void Read(SoftAssetReference& v) + { + uint32 id[4]; + ReadBytes(id, sizeof(id)); + v.Set(*(Guid*)id); + } /// /// Read data array diff --git a/Source/Engine/Serialization/Stream.h b/Source/Engine/Serialization/Stream.h index 83f0eaf21..e477eee95 100644 --- a/Source/Engine/Serialization/Stream.h +++ b/Source/Engine/Serialization/Stream.h @@ -17,6 +17,14 @@ class ISerializable; class ScriptingObject; template class ScriptingObjectReference; +template +class SoftObjectReference; +template +class AssetReference; +template +class WeakAssetReference; +template +class SoftAssetReference; /// /// Base class for all data streams (memory streams, file streams etc.) diff --git a/Source/Engine/Serialization/WriteStream.h b/Source/Engine/Serialization/WriteStream.h index 92ac211ca..95bd87df9 100644 --- a/Source/Engine/Serialization/WriteStream.h +++ b/Source/Engine/Serialization/WriteStream.h @@ -176,6 +176,26 @@ public: { Write(v.Get()); } + template + FORCE_INLINE void Write(const SoftObjectReference& v) + { + Write(v.Get()); + } + template + FORCE_INLINE void Write(const AssetReference& v) + { + Write(v.Get()); + } + template + FORCE_INLINE void Write(const WeakAssetReference& v) + { + Write(v.Get()); + } + template + FORCE_INLINE void Write(const SoftAssetReference& v) + { + Write(v.Get()); + } template void Write(const Array& data) From 9db3439d0d9be39ef76731013a2dd6531ba08e11 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 3 Jul 2023 16:17:46 +0200 Subject: [PATCH 38/85] Fix compilation error --- Source/Engine/Serialization/ReadStream.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Engine/Serialization/ReadStream.h b/Source/Engine/Serialization/ReadStream.h index 26b536c6d..be80e3249 100644 --- a/Source/Engine/Serialization/ReadStream.h +++ b/Source/Engine/Serialization/ReadStream.h @@ -6,6 +6,7 @@ #include "Engine/Core/Templates.h" extern FLAXENGINE_API class ScriptingObject* FindObject(const Guid& id, class MClass* type); +extern FLAXENGINE_API class Asset* LoadAsset(const Guid& id, const struct ScriptingTypeHandle& type); /// /// Base class for all data read streams From 5d9e6b7364846f8229647bbeeea18d490e801a05 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 3 Jul 2023 22:00:23 +0200 Subject: [PATCH 39/85] Fix C# building to properly use reference assemblies for .NET 7 --- Source/Editor/Editor.Build.cs | 3 ++- .../Flax.Build/Build/DotNet/Builder.DotNet.cs | 10 ++++---- .../Build/NativeCpp/BuildOptions.cs | 24 ++++++++++++++----- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/Source/Editor/Editor.Build.cs b/Source/Editor/Editor.Build.cs index 64578570c..2e769f431 100644 --- a/Source/Editor/Editor.Build.cs +++ b/Source/Editor/Editor.Build.cs @@ -37,7 +37,8 @@ public class Editor : EditorModule { base.Setup(options); - options.ScriptingAPI.SystemReferences.Add("System.Private.Xml"); + options.ScriptingAPI.SystemReferences.Add("System.Xml"); + options.ScriptingAPI.SystemReferences.Add("System.Xml.ReaderWriter"); options.ScriptingAPI.SystemReferences.Add("System.Text.RegularExpressions"); options.ScriptingAPI.SystemReferences.Add("System.ComponentModel.TypeConverter"); diff --git a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs index e6a250eb5..454376c61 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs @@ -164,6 +164,8 @@ namespace Flax.Build if (!dotnetSdk.IsValid) throw new Exception("Cannot compile C# without .NET SDK"); string dotnetPath = "dotnet", referenceAnalyzers; + string[] runtimeVersionNameParts = dotnetSdk.RuntimeVersionName.Split('.'); + string runtimeVersionShort = runtimeVersionNameParts[0] + '.' + runtimeVersionNameParts[1]; #else string monoRoot, monoPath; #endif @@ -174,7 +176,7 @@ namespace Flax.Build #if USE_NETCORE dotnetPath = Path.Combine(dotnetSdk.RootPath, "dotnet.exe"); cscPath = Path.Combine(dotnetSdk.RootPath, @$"sdk\{dotnetSdk.VersionName}\Roslyn\bincore\csc.dll"); - referenceAssemblies = Path.Combine(dotnetSdk.RootPath, @$"shared\Microsoft.NETCore.App\{dotnetSdk.RuntimeVersionName}\"); + referenceAssemblies = Path.Combine(dotnetSdk.RootPath, @$"packs\Microsoft.NETCore.App.Ref\{dotnetSdk.RuntimeVersionName}\ref\net{runtimeVersionShort}\"); referenceAnalyzers = Path.Combine(dotnetSdk.RootPath, @$"packs\Microsoft.NETCore.App.Ref\{dotnetSdk.RuntimeVersionName}\analyzers\dotnet\cs\"); #else monoRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Windows", "Mono"); @@ -190,7 +192,7 @@ namespace Flax.Build { #if USE_NETCORE cscPath = Path.Combine(dotnetSdk.RootPath, $"sdk/{dotnetSdk.VersionName}/Roslyn/bincore/csc.dll"); - referenceAssemblies = Path.Combine(dotnetSdk.RootPath, $"shared/Microsoft.NETCore.App/{dotnetSdk.RuntimeVersionName}/"); + referenceAssemblies = Path.Combine(dotnetSdk.RootPath, $"packs/Microsoft.NETCore.App.Ref/{dotnetSdk.RuntimeVersionName}/ref/net{runtimeVersionShort}/"); referenceAnalyzers = Path.Combine(dotnetSdk.RootPath, $"packs/Microsoft.NETCore.App.Ref/{dotnetSdk.RuntimeVersionName}/analyzers/dotnet/cs/"); #else monoRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Linux", "Mono"); @@ -204,7 +206,7 @@ namespace Flax.Build { #if USE_NETCORE cscPath = Path.Combine(dotnetSdk.RootPath, $"sdk/{dotnetSdk.VersionName}/Roslyn/bincore/csc.dll"); - referenceAssemblies = Path.Combine(dotnetSdk.RootPath, $"shared/Microsoft.NETCore.App/{dotnetSdk.RuntimeVersionName}/"); + referenceAssemblies = Path.Combine(dotnetSdk.RootPath, $"packs/Microsoft.NETCore.App.Ref/{dotnetSdk.RuntimeVersionName}/ref/net{runtimeVersionShort}/"); referenceAnalyzers = Path.Combine(dotnetSdk.RootPath, $"packs/Microsoft.NETCore.App.Ref/{dotnetSdk.RuntimeVersionName}/analyzers/dotnet/cs/"); #else monoRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Mac", "Mono"); @@ -256,6 +258,7 @@ namespace Flax.Build args.Add(buildData.Configuration == TargetConfiguration.Release ? "/optimize+" : "/optimize-"); #else args.Add(buildData.Configuration == TargetConfiguration.Debug ? "/optimize-" : "/optimize+"); + args.Add(string.Format("/reference:\"{0}mscorlib.dll\"", referenceAssemblies)); #endif args.Add(string.Format("/out:\"{0}\"", outputFile)); args.Add(string.Format("/doc:\"{0}\"", outputDocFile)); @@ -263,7 +266,6 @@ namespace Flax.Build args.Add("/define:" + string.Join(";", buildOptions.ScriptingAPI.Defines)); if (buildData.Configuration == TargetConfiguration.Debug) args.Add("/define:DEBUG"); - args.Add(string.Format("/reference:\"{0}mscorlib.dll\"", referenceAssemblies)); foreach (var reference in buildOptions.ScriptingAPI.SystemReferences) args.Add(string.Format("/reference:\"{0}{1}.dll\"", referenceAssemblies, reference)); foreach (var reference in fileReferences) diff --git a/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs b/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs index c2ea81372..ef365d3b7 100644 --- a/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs +++ b/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs @@ -244,6 +244,8 @@ namespace Flax.Build.NativeCpp Defines = new HashSet(), SystemReferences = new HashSet { + "mscorlib", + "netstandard", "Microsoft.CSharp", "System", @@ -258,25 +260,32 @@ namespace Flax.Build.NativeCpp //"System.ComponentModel.TypeConverter", "System.Console", "System.Core", + "System.Diagnostics.StackTrace", "System.Globalization", "System.IO", "System.IO.Compression", "System.IO.FileSystem.Watcher", "System.Linq", "System.Linq.Expressions", + "System.Memory", + "System.Net", "System.Net.Http", "System.Net.Primitives", "System.ObjectModel", - "System.Private.CoreLib", - "System.Private.Uri", - //"System.Private.Xml", + "System.ValueTuple", - "System.Reflection", "System.Runtime", + "System.Runtime.Extensions", + "System.Runtime.Handles", + "System.Runtime.Intrinsics", + "System.Runtime.Numerics", + "System.Runtime.Loader", "System.Runtime.CompilerServices.Unsafe", "System.Runtime.InteropServices", "System.Runtime.InteropServices.RuntimeInformation", - "System.Runtime.Serialization.Formatters", // BinaryFormatter + "System.Runtime.Serialization", + "System.Runtime.Serialization.Formatters", + "System.Security.Cryptography", "System.Security.Cryptography.Algorithms", "System.Security.Cryptography.Primitives", @@ -284,8 +293,11 @@ namespace Flax.Build.NativeCpp "System.Threading.Tasks.Parallel", //"System.Xml", + "System.Threading", + "System.Threading.Thread", + + "System.Reflection", //"System.Reflection.Metadata", - "netstandard", }, SystemAnalyzers = new HashSet { From 5f756a6ceb390a4fd71b7e0d6b1493881a4796c8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 3 Jul 2023 22:00:38 +0200 Subject: [PATCH 40/85] Add `TargetFrameworkAttribute` to compiled C# assembly --- .../Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs index 454376c61..13433f92c 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using Flax.Build.Graph; using Flax.Build.NativeCpp; using Flax.Deploy; @@ -12,7 +13,7 @@ namespace Flax.Build { static partial class Builder { - public static event Action> BuildDotNetAssembly; + public static event Action> BuildDotNetAssembly; private static void BuildTargetDotNet(RulesAssembly rules, TaskGraph graph, Target target, Platform platform, TargetConfiguration configuration) { @@ -151,7 +152,7 @@ namespace Flax.Build } } - private static void BuildDotNet(TaskGraph graph, BuildData buildData, NativeCpp.BuildOptions buildOptions, string name, List sourceFiles, HashSet fileReferences = null, IGrouping binaryModule = null) + private static void BuildDotNet(TaskGraph graph, BuildData buildData, BuildOptions buildOptions, string name, List sourceFiles, HashSet fileReferences = null, IGrouping binaryModule = null) { // Setup build options var buildPlatform = Platform.BuildTargetPlatform; @@ -277,6 +278,13 @@ namespace Flax.Build foreach (var sourceFile in sourceFiles) args.Add("\"" + sourceFile + "\""); +#if USE_NETCORE + // Inject some assembly metadata (similar to msbuild in Visual Studio) + var assemblyAttributesPath = Path.Combine(buildOptions.IntermediateFolder, name + ".AssemblyAttributes.cs"); + File.WriteAllText(assemblyAttributesPath, $"[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(\".NETCoreApp,Version=v{runtimeVersionShort}\", FrameworkDisplayName = \".NET {runtimeVersionShort}\")]\n", Encoding.UTF8); + args.Add("\"" + assemblyAttributesPath + "\""); +#endif + // Generate response file with source files paths and compilation arguments string responseFile = Path.Combine(buildOptions.IntermediateFolder, name + ".response"); Utilities.WriteFileIfChanged(responseFile, string.Join(Environment.NewLine, args)); From 9f7ae5bb58032e0339928dc589c4b2b18e44b1aa Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 3 Jul 2023 22:13:13 +0200 Subject: [PATCH 41/85] Fix warning --- Source/Engine/Platform/Win32/Win32StringUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Platform/Win32/Win32StringUtils.cpp b/Source/Engine/Platform/Win32/Win32StringUtils.cpp index 2a9bcf174..ea1eb8fe9 100644 --- a/Source/Engine/Platform/Win32/Win32StringUtils.cpp +++ b/Source/Engine/Platform/Win32/Win32StringUtils.cpp @@ -182,7 +182,7 @@ const char* StringUtils::Find(const char* str, const char* toFind) void StringUtils::ConvertANSI2UTF16(const char* from, Char* to, int32 fromLength, int32& toLength) { if (fromLength) - toLength = mbstowcs(to, from, fromLength); + toLength = (int32)mbstowcs(to, from, fromLength); else toLength = 0; } From 5ee7b0d939141691ff7d6e3f067985b6547196fa Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 4 Jul 2023 10:18:27 +0200 Subject: [PATCH 42/85] Bump up build number --- Flax.flaxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flax.flaxproj b/Flax.flaxproj index 7cebe1714..50fcaeda3 100644 --- a/Flax.flaxproj +++ b/Flax.flaxproj @@ -3,7 +3,7 @@ "Version": { "Major": 1, "Minor": 6, - "Build": 6343 + "Build": 6344 }, "Company": "Flax", "Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.", From 615ec636d4c3b9bcd0e7b7a1c7a75bdb21464211 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 4 Jul 2023 10:42:49 +0200 Subject: [PATCH 43/85] Fix crash when window gets deleted before show/close sequence --- Source/Engine/Platform/Base/WindowBase.cpp | 1 + Source/Engine/Platform/Base/WindowsManager.cpp | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Platform/Base/WindowBase.cpp b/Source/Engine/Platform/Base/WindowBase.cpp index e2460e373..5cff76361 100644 --- a/Source/Engine/Platform/Base/WindowBase.cpp +++ b/Source/Engine/Platform/Base/WindowBase.cpp @@ -125,6 +125,7 @@ WindowBase::~WindowBase() { ASSERT(!RenderTask); ASSERT(!_swapChain); + WindowsManager::Unregister((Window*)this); } bool WindowBase::IsMain() const diff --git a/Source/Engine/Platform/Base/WindowsManager.cpp b/Source/Engine/Platform/Base/WindowsManager.cpp index ed2106cf5..0d58008d8 100644 --- a/Source/Engine/Platform/Base/WindowsManager.cpp +++ b/Source/Engine/Platform/Base/WindowsManager.cpp @@ -25,7 +25,6 @@ WindowsManagerService WindowsManagerServiceInstance; Window* WindowsManager::GetByNativePtr(void* handle) { Window* result = nullptr; - WindowsLocker.Lock(); for (int32 i = 0; i < Windows.Count(); i++) { @@ -36,7 +35,6 @@ Window* WindowsManager::GetByNativePtr(void* handle) } } WindowsLocker.Unlock(); - return result; } @@ -61,7 +59,7 @@ void WindowsManagerService::Update() // Update windows const float deltaTime = Time::Update.UnscaledDeltaTime.GetTotalSeconds(); WindowsManager::WindowsLocker.Lock(); - for (auto& win : WindowsManager::Windows) + for (Window* win : WindowsManager::Windows) { if (win && win->IsVisible()) win->OnUpdate(deltaTime); @@ -74,7 +72,7 @@ void WindowsManagerService::Dispose() // Close remaining windows WindowsManager::WindowsLocker.Lock(); auto windows = WindowsManager::Windows; - for (auto& win : windows) + for (Window* win : windows) { win->Close(ClosingReason::EngineExit); } From d31fc32399c774acc108bd7075e9b6a84eadce9b Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 4 Jul 2023 11:05:32 +0200 Subject: [PATCH 44/85] Fix and update engine assets --- Content/Editor/CubeTexturePreviewMaterial.flax | 4 ++-- Content/Editor/Gizmo/Material.flax | 4 ++-- Content/Editor/TexturePreviewMaterial.flax | 4 ++-- Source/Editor/CustomEditors/Editors/ColorEditor.cs | 6 +++++- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Content/Editor/CubeTexturePreviewMaterial.flax b/Content/Editor/CubeTexturePreviewMaterial.flax index 28860d3cc..828d620d2 100644 --- a/Content/Editor/CubeTexturePreviewMaterial.flax +++ b/Content/Editor/CubeTexturePreviewMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c04e226f6f8aa0de1049694ed813b0bd75864da76be2df43fb9db08162daadaa -size 31647 +oid sha256:28e5aaeb274e7590bc9ec13212e041d4d14baef562487507ea3621ec040c393b +size 31807 diff --git a/Content/Editor/Gizmo/Material.flax b/Content/Editor/Gizmo/Material.flax index d44e7590a..80d319a03 100644 --- a/Content/Editor/Gizmo/Material.flax +++ b/Content/Editor/Gizmo/Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8b8d0157ba0eb18a8ab9613b4429343b4f52fdeb14d1adc73c0682a75b6a7466 -size 32411 +oid sha256:fc18e2ff1f55cfc41a5b083843b11e1573ac7066bc58153262b2b61ea6105fce +size 32486 diff --git a/Content/Editor/TexturePreviewMaterial.flax b/Content/Editor/TexturePreviewMaterial.flax index d4ff0c0cd..b21daaa5a 100644 --- a/Content/Editor/TexturePreviewMaterial.flax +++ b/Content/Editor/TexturePreviewMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2970eb5c0000661663a3cadffb1b8e67215f4425da24d5313e1d07fc44f0594d -size 10413 +oid sha256:52921ebe6efaf3a74950e817a4e2224ef2ef54e0698efc042ba9cd2c17693e54 +size 10568 diff --git a/Source/Editor/CustomEditors/Editors/ColorEditor.cs b/Source/Editor/CustomEditors/Editors/ColorEditor.cs index 2877fe29e..54b8ba5fb 100644 --- a/Source/Editor/CustomEditors/Editors/ColorEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ColorEditor.cs @@ -41,7 +41,11 @@ namespace FlaxEditor.CustomEditors.Editors } else { - element.CustomControl.Value = (Color)Values[0]; + var value = Values[0]; + if (value is Color asColor) + element.CustomControl.Value = asColor; + else if (value is Float4 asFloat4) + element.CustomControl.Value = asFloat4; } } } From 72d1d8f0857a95883fc924e2ce7e2b2b6c79bfa0 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 4 Jul 2023 11:06:48 +0200 Subject: [PATCH 45/85] More stuff from d31fc32399c774acc108bd7075e9b6a84eadce9b --- Source/Editor/CustomEditors/Editors/ColorEditor.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Editor/CustomEditors/Editors/ColorEditor.cs b/Source/Editor/CustomEditors/Editors/ColorEditor.cs index 54b8ba5fb..865485d02 100644 --- a/Source/Editor/CustomEditors/Editors/ColorEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ColorEditor.cs @@ -46,6 +46,10 @@ namespace FlaxEditor.CustomEditors.Editors element.CustomControl.Value = asColor; else if (value is Float4 asFloat4) element.CustomControl.Value = asFloat4; + else if (value is Double4 asDouble4) + element.CustomControl.Value = (Float4)asDouble4; + else if (value is Vector4 asVector4) + element.CustomControl.Value = asVector4; } } } From d49def6f7ef8ce727a6d122d75e880ed65ebb83d Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 4 Jul 2023 11:46:42 +0200 Subject: [PATCH 46/85] More stuff from d31fc32399c774acc108bd7075e9b6a84eadce9b --- Source/Editor/CustomEditors/Editors/ColorEditor.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Editor/CustomEditors/Editors/ColorEditor.cs b/Source/Editor/CustomEditors/Editors/ColorEditor.cs index 865485d02..4edbde432 100644 --- a/Source/Editor/CustomEditors/Editors/ColorEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ColorEditor.cs @@ -44,6 +44,8 @@ namespace FlaxEditor.CustomEditors.Editors var value = Values[0]; if (value is Color asColor) element.CustomControl.Value = asColor; + else if (value is Color32 asColor32) + element.CustomControl.Value = asColor32; else if (value is Float4 asFloat4) element.CustomControl.Value = asFloat4; else if (value is Double4 asDouble4) From 74ca6b2c513ceaa7f1ea60553592772ce055be5f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 4 Jul 2023 13:12:48 +0200 Subject: [PATCH 47/85] Add missing Shader Model 6 define --- Source/Shaders/Common.hlsl | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Shaders/Common.hlsl b/Source/Shaders/Common.hlsl index 13d2ad28f..19ba3f861 100644 --- a/Source/Shaders/Common.hlsl +++ b/Source/Shaders/Common.hlsl @@ -26,6 +26,7 @@ #define FEATURE_LEVEL_ES3_1 2 #define FEATURE_LEVEL_SM4 3 #define FEATURE_LEVEL_SM5 4 +#define FEATURE_LEVEL_SM6 5 #if !defined(FEATURE_LEVEL) #error "Invalid platform defines" #endif From 27b3538b2fefda9db1c6b3377563d74dce586580 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 4 Jul 2023 13:15:09 +0200 Subject: [PATCH 48/85] Fix regression from 9d640656e6a2438c5203e1abb96fdb574f4d0be8 --- Source/Engine/Core/Types/String.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Engine/Core/Types/String.cpp b/Source/Engine/Core/Types/String.cpp index 3de255039..e53f04af7 100644 --- a/Source/Engine/Core/Types/String.cpp +++ b/Source/Engine/Core/Types/String.cpp @@ -113,6 +113,7 @@ void String::Append(const char* chars, int32 count) Platform::MemoryCopy(_data, oldData, oldLength * sizeof(Char)); StringUtils::ConvertANSI2UTF16(chars, _data + oldLength, count, _length); + _length += oldLength; _data[_length] = 0; Platform::Free(oldData); From d7dc0b76e533d0e3d05b13a88635ebe61c25c09b Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 4 Jul 2023 13:32:51 +0200 Subject: [PATCH 49/85] Softly handle invalid scene rendering key to prevent crashes on scene unload --- Source/Engine/Level/Scene/SceneRendering.cpp | 30 +++++++++++--------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/Source/Engine/Level/Scene/SceneRendering.cpp b/Source/Engine/Level/Scene/SceneRendering.cpp index b75cd6851..01592a335 100644 --- a/Source/Engine/Level/Scene/SceneRendering.cpp +++ b/Source/Engine/Level/Scene/SceneRendering.cpp @@ -157,14 +157,16 @@ void SceneRendering::UpdateActor(Actor* a, int32& key) const int32 category = a->_drawCategory; ScopeLock lock(Locker); auto& list = Actors[category]; - if (list.IsEmpty()) + if (list.Count() > key) // Ignore invalid key softly return; auto& e = list[key]; - ASSERT_LOW_LAYER(a == e.Actor); - for (auto* listener : _listeners) - listener->OnSceneRenderingUpdateActor(a, e.Bounds); - e.LayerMask = a->GetLayerMask(); - e.Bounds = a->GetSphere(); + if (e.Actor == a) + { + for (auto* listener : _listeners) + listener->OnSceneRenderingUpdateActor(a, e.Bounds); + e.LayerMask = a->GetLayerMask(); + e.Bounds = a->GetSphere(); + } } void SceneRendering::RemoveActor(Actor* a, int32& key) @@ -172,14 +174,16 @@ void SceneRendering::RemoveActor(Actor* a, int32& key) const int32 category = a->_drawCategory; ScopeLock lock(Locker); auto& list = Actors[category]; - if (list.HasItems()) + if (list.Count() > key) // Ignore invalid key softly (eg. list after batch clear during scene unload) { - auto& e = list[key]; - ASSERT_LOW_LAYER(a == e.Actor); - for (auto* listener : _listeners) - listener->OnSceneRenderingRemoveActor(a); - e.Actor = nullptr; - e.LayerMask = 0; + auto& e = list.Get()[key]; + if (e.Actor == a) + { + for (auto* listener : _listeners) + listener->OnSceneRenderingRemoveActor(a); + e.Actor = nullptr; + e.LayerMask = 0; + } } key = -1; } From c79952a4d64c07f2a958499a7908d768d56857f0 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 4 Jul 2023 17:57:59 +0200 Subject: [PATCH 50/85] Implement missing dotnet7 interop for field and stabilize interop --- .../Engine/Engine/NativeInterop.Marshallers.cs | 2 +- .../Engine/Engine/NativeInterop.Unmanaged.cs | 18 +++++++++++++++++- Source/Engine/Engine/NativeInterop.cs | 5 ++++- Source/Engine/Scripting/Runtime/DotNet.cpp | 8 ++++---- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/Source/Engine/Engine/NativeInterop.Marshallers.cs b/Source/Engine/Engine/NativeInterop.Marshallers.cs index 0a23bfcbd..2e3bc9183 100644 --- a/Source/Engine/Engine/NativeInterop.Marshallers.cs +++ b/Source/Engine/Engine/NativeInterop.Marshallers.cs @@ -399,7 +399,7 @@ namespace FlaxEngine.Interop } numElements = managed.Length; ManagedArray managedArray = ManagedArray.AllocatePooledArray(managed.Length); - return (TUnmanagedElement*)ManagedHandle.ToIntPtr(managedArray, GCHandleType.Weak); + return (TUnmanagedElement*)ManagedHandle.ToIntPtr(managedArray, GCHandleType.Normal); } public static ReadOnlySpan GetManagedValuesSource(T[] managed) => managed; diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index d4a8d44f8..bba9e3db8 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -770,6 +770,13 @@ namespace FlaxEngine.Interop field.field.SetValue(fieldOwner, value); } + [UnmanagedCallersOnly] + internal static int FieldGetOffset(ManagedHandle fieldHandle) + { + FieldHolder field = Unsafe.As(fieldHandle.Target); + return (int)Marshal.OffsetOf(field.field.DeclaringType, field.field.Name); + } + [UnmanagedCallersOnly] internal static void FieldGetValue(ManagedHandle fieldOwnerHandle, ManagedHandle fieldHandle, IntPtr valuePtr) { @@ -778,6 +785,15 @@ namespace FlaxEngine.Interop field.toNativeMarshaller(field.field, fieldOwner, valuePtr, out int fieldOffset); } + [UnmanagedCallersOnly] + internal static IntPtr FieldGetValueBoxed(ManagedHandle fieldOwnerHandle, ManagedHandle fieldHandle) + { + object fieldOwner = fieldOwnerHandle.Target; + FieldHolder field = Unsafe.As(fieldHandle.Target); + object fieldValue = field.field.GetValue(fieldOwner); + return Invoker.MarshalReturnValueGeneric(field.field.FieldType, fieldValue); + } + [UnmanagedCallersOnly] internal static void WriteArrayReference(ManagedHandle arrayHandle, IntPtr valueHandle, int index) { @@ -924,7 +940,7 @@ namespace FlaxEngine.Interop if (nativeType.IsClass) size = sizeof(IntPtr); else - size = Marshal.SizeOf(nativeType); + size = GetTypeSize(type); return size; } diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index e82cb3858..acfd7181b 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -1095,7 +1095,10 @@ namespace FlaxEngine.Interop { try { - size = Marshal.SizeOf(type); + var marshalType = type; + if (type.IsEnum) + marshalType = type.GetEnumUnderlyingType(); + size = Marshal.SizeOf(marshalType); } catch { diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index 246c1620f..8d75d7a95 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -1163,8 +1163,8 @@ MType* MField::GetType() const int32 MField::GetOffset() const { - MISSING_CODE("TODO: MField::GetOffset"); // TODO: MField::GetOffset - return 0; + static void* FieldGetOffsetPtr = GetStaticMethodPointer(TEXT("FieldGetOffset")); + return CallStaticMethod(FieldGetOffsetPtr, _handle); } void MField::GetValue(MObject* instance, void* result) const @@ -1175,8 +1175,8 @@ void MField::GetValue(MObject* instance, void* result) const MObject* MField::GetValueBoxed(MObject* instance) const { - MISSING_CODE("TODO: MField::GetValueBoxed"); // TODO: MField::GetValueBoxed - return nullptr; + static void* FieldGetValueBoxedPtr = GetStaticMethodPointer(TEXT("FieldGetValueBoxed")); + return CallStaticMethod(FieldGetValueBoxedPtr, instance, _handle); } void MField::SetValue(MObject* instance, void* value) const From 90f377fa83efccbf4598152fe9e5ae0f0a026623 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 4 Jul 2023 17:58:06 +0200 Subject: [PATCH 51/85] Remove leftover log --- Source/Editor/Surface/ContextMenu/VisjectCM.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 3f74e4c07..bae62556e 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -363,7 +363,6 @@ namespace FlaxEditor.Surface.ContextMenu Profiler.BeginEvent("VisjectCM.RemoveGroup"); if (group.Archetypes.Count == 0) { - Debug.Log("Remove"); _groups.RemoveAt(i); group.Dispose(); } From a14de5e255c7c29330bf3aca83307806a022a89d Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 4 Jul 2023 17:58:32 +0200 Subject: [PATCH 52/85] Fix `Array For Each` visual script node local vars setup --- Source/Engine/Content/Assets/VisualScript.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Engine/Content/Assets/VisualScript.cpp b/Source/Engine/Content/Assets/VisualScript.cpp index b11a2af96..e292a0133 100644 --- a/Source/Engine/Content/Assets/VisualScript.cpp +++ b/Source/Engine/Content/Assets/VisualScript.cpp @@ -618,7 +618,7 @@ void VisualScriptExecutor::ProcessGroupFunction(Box* boxBase, Node* node, Value& // Return case 5: { - auto& scope = ThreadStacks.Get().Stack->Scope; + auto scope = ThreadStacks.Get().Stack->Scope; scope->FunctionReturn = tryGetValue(node->GetBox(1), Value::Zero); break; } @@ -634,7 +634,7 @@ void VisualScriptExecutor::ProcessGroupFunction(Box* boxBase, Node* node, Value& else { // Evaluate method parameter value from the current scope - auto& scope = ThreadStacks.Get().Stack->Scope; + auto scope = ThreadStacks.Get().Stack->Scope; int32 index = boxBase->ID - 1; if (index < scope->Parameters.Length()) value = scope->Parameters.Get()[index]; @@ -1138,7 +1138,7 @@ void VisualScriptExecutor::ProcessGroupFlow(Box* boxBase, Node* node, Value& val break; } int32 arrayIndex = 0; - for (; iteratorIndex < scope->ReturnedValues.Count(); arrayIndex++) + for (; arrayIndex < scope->ReturnedValues.Count(); arrayIndex++) { const auto& e = scope->ReturnedValues[arrayIndex]; if (e.NodeId == node->ID && e.BoxId == 1) From 04ef3c60d5adde6827ed2c54905ebeaa92809351 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 5 Jul 2023 09:27:21 +0200 Subject: [PATCH 53/85] Fix regression from c79952a4d64c07f2a958499a7908d768d56857f0 --- Source/Engine/Engine/NativeInterop.Unmanaged.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index bba9e3db8..17b8b73af 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -940,7 +940,7 @@ namespace FlaxEngine.Interop if (nativeType.IsClass) size = sizeof(IntPtr); else - size = GetTypeSize(type); + size = GetTypeSize(nativeType); return size; } From bd0bc42adc0a9a5b0f1ac77f8a7814250697a82e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 5 Jul 2023 12:18:03 +0200 Subject: [PATCH 54/85] Fix regressionn from d7dc0b76e533d0e3d05b13a88635ebe61c25c09b --- Source/Engine/Level/Scene/SceneRendering.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Level/Scene/SceneRendering.cpp b/Source/Engine/Level/Scene/SceneRendering.cpp index 01592a335..48420ed49 100644 --- a/Source/Engine/Level/Scene/SceneRendering.cpp +++ b/Source/Engine/Level/Scene/SceneRendering.cpp @@ -157,7 +157,7 @@ void SceneRendering::UpdateActor(Actor* a, int32& key) const int32 category = a->_drawCategory; ScopeLock lock(Locker); auto& list = Actors[category]; - if (list.Count() > key) // Ignore invalid key softly + if (list.Count() <= key) // Ignore invalid key softly return; auto& e = list[key]; if (e.Actor == a) From d88b93d56bbfb89dcb8b2caa7e981f8fafe85eea Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Wed, 5 Jul 2023 14:00:07 -0500 Subject: [PATCH 55/85] Add find actor by type and tag to level and actor classes. Move find actor by tag code to be by other find actor methods. --- Source/Engine/Level/Actor.cpp | 14 ++ Source/Engine/Level/Actor.cs | 11 ++ Source/Engine/Level/Actor.h | 19 +++ Source/Engine/Level/Level.cpp | 247 +++++++++++++++++++--------------- Source/Engine/Level/Level.cs | 12 ++ Source/Engine/Level/Level.h | 74 ++++++---- 6 files changed, 240 insertions(+), 137 deletions(-) diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp index 67d84b81d..08fb77223 100644 --- a/Source/Engine/Level/Actor.cpp +++ b/Source/Engine/Level/Actor.cpp @@ -1337,6 +1337,20 @@ Actor* Actor::FindActor(const MClass* type, const StringView& name) const return nullptr; } +Actor* Actor::FindActor(const MClass* type, const Tag& tag) const +{ + CHECK_RETURN(type, nullptr); + if (GetClass()->IsSubClassOf(type) && HasTag(tag)) + return const_cast(this); + for (auto child : Children) + { + const auto actor = child->FindActor(type, tag); + if (actor) + return actor; + } + return nullptr; +} + Script* Actor::FindScript(const MClass* type) const { CHECK_RETURN(type, nullptr); diff --git a/Source/Engine/Level/Actor.cs b/Source/Engine/Level/Actor.cs index 957d09c7a..661b350cb 100644 --- a/Source/Engine/Level/Actor.cs +++ b/Source/Engine/Level/Actor.cs @@ -269,6 +269,17 @@ namespace FlaxEngine { return FindActor(typeof(T), name) as T; } + + /// + /// Tries to find actor of the given type and tag in this actor hierarchy (checks this actor and all children hierarchy). + /// + /// A tag on the object. + /// Type of the object. + /// Actor instance if found, null otherwise. + public T FindActor(Tag tag) where T : Actor + { + return FindActor(typeof(T), tag) as T; + } /// /// Searches for all actors of a specific type in this actor children list. diff --git a/Source/Engine/Level/Actor.h b/Source/Engine/Level/Actor.h index fb9fb0848..510bc9eb8 100644 --- a/Source/Engine/Level/Actor.h +++ b/Source/Engine/Level/Actor.h @@ -739,6 +739,14 @@ public: /// Actor instance if found, null otherwise. API_FUNCTION() Actor* FindActor(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type, const StringView& name) const; + /// + /// Tries to find the actor of the given type and tag in this actor hierarchy. + /// + /// Type of the actor to search for. Includes any actors derived from the type. + /// The tag of the actor to search for. + /// Actor instance if found, null otherwise. + API_FUNCTION() Actor* FindActor(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type, const Tag& tag) const; + /// /// Tries to find the actor of the given type in this actor hierarchy (checks this actor and all children hierarchy). /// @@ -759,6 +767,17 @@ public: { return (T*)FindActor(T::GetStaticClass(), name); } + + /// + /// Tries to find the actor of the given type and tag in this actor hierarchy (checks this actor and all children hierarchy). + /// + /// The tag of the actor to search for. + /// Actor instance if found, null otherwise. + template + FORCE_INLINE T* FindActor(const Tag& tag) const + { + return (T*)FindActor(T::GetStaticClass(), tag); + } /// /// Tries to find the script of the given type in this actor hierarchy (checks this actor and all children hierarchy). diff --git a/Source/Engine/Level/Level.cpp b/Source/Engine/Level/Level.cpp index ab8a9bbfe..587d20331 100644 --- a/Source/Engine/Level/Level.cpp +++ b/Source/Engine/Level/Level.cpp @@ -726,116 +726,6 @@ int32 Level::GetLayerIndex(const StringView& layer) return result; } -Actor* FindActorRecursive(Actor* node, const Tag& tag) -{ - if (node->HasTag(tag)) - return node; - Actor* result = nullptr; - for (Actor* child : node->Children) - { - result = FindActorRecursive(child, tag); - if (result) - break; - } - return result; -} - -void FindActorsRecursive(Actor* node, const Tag& tag, const bool activeOnly, Array& result) -{ - if (activeOnly && !node->GetIsActive()) - return; - if (node->HasTag(tag)) - result.Add(node); - for (Actor* child : node->Children) - FindActorsRecursive(child, tag, activeOnly, result); -} - -void FindActorsRecursiveByParentTags(Actor* node, const Array& tags, const bool activeOnly, Array& result) -{ - if (activeOnly && !node->GetIsActive()) - return; - for (Tag tag : tags) - { - if (node->HasTag(tag)) - { - result.Add(node); - break; - } - } - for (Actor* child : node->Children) - FindActorsRecursiveByParentTags(child, tags, activeOnly, result); -} - -Actor* Level::FindActor(const Tag& tag, Actor* root) -{ - PROFILE_CPU(); - if (root) - return FindActorRecursive(root, tag); - Actor* result = nullptr; - for (Scene* scene : Scenes) - { - result = FindActorRecursive(scene, tag); - if (result) - break; - } - return result; -} - -void FindActorRecursive(Actor* node, const Tag& tag, Array& result) -{ - if (node->HasTag(tag)) - result.Add(node); - for (Actor* child : node->Children) - FindActorRecursive(child, tag, result); -} - -Array Level::FindActors(const Tag& tag, const bool activeOnly, Actor* root) -{ - PROFILE_CPU(); - Array result; - if (root) - { - FindActorsRecursive(root, tag, activeOnly, result); - } - else - { - ScopeLock lock(ScenesLock); - for (Scene* scene : Scenes) - FindActorsRecursive(scene, tag, activeOnly, result); - } - return result; -} - -Array Level::FindActorsByParentTag(const Tag& parentTag, const bool activeOnly, Actor* root) -{ - PROFILE_CPU(); - Array result; - const Array subTags = Tags::GetSubTags(parentTag); - - if (subTags.Count() == 0) - { - return result; - } - if (subTags.Count() == 1) - { - result = FindActors(subTags[0], activeOnly, root); - return result; - } - - if (root) - { - FindActorsRecursiveByParentTags(root, subTags, activeOnly, result); - } - else - { - ScopeLock lock(ScenesLock); - for (Scene* scene : Scenes) - FindActorsRecursiveByParentTags(scene, subTags, activeOnly, result); - } - - return result; -} - void Level::callActorEvent(ActorEventType eventType, Actor* a, Actor* b) { PROFILE_CPU(); @@ -1505,6 +1395,143 @@ Actor* Level::FindActor(const MClass* type, const StringView& name) return result; } +Actor* FindActorRecursive(Actor* node, const Tag& tag) +{ + if (node->HasTag(tag)) + return node; + Actor* result = nullptr; + for (Actor* child : node->Children) + { + result = FindActorRecursive(child, tag); + if (result) + break; + } + return result; +} + +Actor* FindActorRecursiveByType(Actor* node, const MClass* type, const Tag& tag) +{ + CHECK_RETURN(type, nullptr); + if (node->HasTag(tag) && node->GetClass()->IsSubClassOf(type)) + return node; + Actor* result = nullptr; + for (Actor* child : node->Children) + { + result = FindActorRecursiveByType(child, type, tag); + if (result) + break; + } + return result; +} + +void FindActorsRecursive(Actor* node, const Tag& tag, const bool activeOnly, Array& result) +{ + if (activeOnly && !node->GetIsActive()) + return; + if (node->HasTag(tag)) + result.Add(node); + for (Actor* child : node->Children) + FindActorsRecursive(child, tag, activeOnly, result); +} + +void FindActorsRecursiveByParentTags(Actor* node, const Array& tags, const bool activeOnly, Array& result) +{ + if (activeOnly && !node->GetIsActive()) + return; + for (Tag tag : tags) + { + if (node->HasTag(tag)) + { + result.Add(node); + break; + } + } + for (Actor* child : node->Children) + FindActorsRecursiveByParentTags(child, tags, activeOnly, result); +} + +Actor* Level::FindActor(const Tag& tag, Actor* root) +{ + PROFILE_CPU(); + if (root) + return FindActorRecursive(root, tag); + Actor* result = nullptr; + for (Scene* scene : Scenes) + { + result = FindActorRecursive(scene, tag); + if (result) + break; + } + return result; +} + +Actor* Level::FindActor(const MClass* type, const Tag& tag, Actor* root) +{ + CHECK_RETURN(type, nullptr); + if (root) + return FindActorRecursiveByType(root, type, tag); + Actor* result = nullptr; + ScopeLock lock(ScenesLock); + for (int32 i = 0; result == nullptr && i < Scenes.Count(); i++) + result = Scenes[i]->FindActor(type, tag); + return result; +} + +void FindActorRecursive(Actor* node, const Tag& tag, Array& result) +{ + if (node->HasTag(tag)) + result.Add(node); + for (Actor* child : node->Children) + FindActorRecursive(child, tag, result); +} + +Array Level::FindActors(const Tag& tag, const bool activeOnly, Actor* root) +{ + PROFILE_CPU(); + Array result; + if (root) + { + FindActorsRecursive(root, tag, activeOnly, result); + } + else + { + ScopeLock lock(ScenesLock); + for (Scene* scene : Scenes) + FindActorsRecursive(scene, tag, activeOnly, result); + } + return result; +} + +Array Level::FindActorsByParentTag(const Tag& parentTag, const bool activeOnly, Actor* root) +{ + PROFILE_CPU(); + Array result; + const Array subTags = Tags::GetSubTags(parentTag); + + if (subTags.Count() == 0) + { + return result; + } + if (subTags.Count() == 1) + { + result = FindActors(subTags[0], activeOnly, root); + return result; + } + + if (root) + { + FindActorsRecursiveByParentTags(root, subTags, activeOnly, result); + } + else + { + ScopeLock lock(ScenesLock); + for (Scene* scene : Scenes) + FindActorsRecursiveByParentTags(scene, subTags, activeOnly, result); + } + + return result; +} + Script* Level::FindScript(const MClass* type) { CHECK_RETURN(type, nullptr); diff --git a/Source/Engine/Level/Level.cs b/Source/Engine/Level/Level.cs index c38b287ca..1e8524f2c 100644 --- a/Source/Engine/Level/Level.cs +++ b/Source/Engine/Level/Level.cs @@ -77,6 +77,18 @@ namespace FlaxEngine { return FindActor(typeof(T), name) as T; } + + /// + /// Tries to find actor of the given type and tag in a root actor or all loaded scenes. + /// + /// A tag on the object. + /// The custom root actor to start searching from (hierarchical), otherwise null to search all loaded scenes. + /// Type of the object. + /// Found actor or null. + public static T FindActor(Tag tag, Actor root = null) where T : Actor + { + return FindActor(typeof(T), tag, root) as T; + } /// /// Tries to find actor with the given ID in all loaded scenes. It's very fast O(1) lookup. diff --git a/Source/Engine/Level/Level.h b/Source/Engine/Level/Level.h index 9a041bda9..1f0acda2d 100644 --- a/Source/Engine/Level/Level.h +++ b/Source/Engine/Level/Level.h @@ -371,6 +371,41 @@ public: /// Actor instance if found, null otherwise. API_FUNCTION() static Actor* FindActor(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type, const StringView& name); + /// + /// Tries to find the actor with the given tag (returns the first one found). + /// + /// The tag of the actor to search for. + /// The custom root actor to start searching from (hierarchical), otherwise null to search all loaded scenes. + /// Found actor or null. + API_FUNCTION() static Actor* FindActor(const Tag& tag, Actor* root = nullptr); + + /// + /// Tries to find the actor of the given type and tag in all the loaded scenes. + /// + /// Type of the actor to search for. Includes any actors derived from the type. + /// The tag of the actor to search for. + /// The custom root actor to start searching from (hierarchical), otherwise null to search all loaded scenes. + /// Actor instance if found, null otherwise. + API_FUNCTION() static Actor* FindActor(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type, const Tag& tag, Actor* root = nullptr); + + /// + /// Tries to find the actors with the given tag (returns all found). + /// + /// The tag of the actor to search for. + /// Find only active actors. + /// The custom root actor to start searching from (hierarchical), otherwise null to search all loaded scenes. + /// Found actors or empty if none. + API_FUNCTION() static Array FindActors(const Tag& tag, const bool activeOnly = false, Actor* root = nullptr); + + /// + /// Search actors using a parent parentTag. + /// + /// The tag to search actors with subtags belonging to this tag + /// Find only active actors. + /// The custom root actor to start searching from (hierarchical), otherwise null to search all loaded scenes. + /// Returns all actors that have subtags belonging to the given parent parentTag + API_FUNCTION() static Array FindActorsByParentTag(const Tag& parentTag, const bool activeOnly = false, Actor* root = nullptr); + /// /// Tries to find the actor of the given type in all the loaded scenes. /// @@ -392,6 +427,18 @@ public: return (T*)FindActor(T::GetStaticClass(), name); } + /// + /// Tries to find the actor of the given type and tag in a root actor or all the loaded scenes. + /// The tag of the actor to search for. + /// The custom root actor to start searching from (hierarchical), otherwise null to search all loaded scenes. + /// + /// Actor instance if found, null otherwise. + template + FORCE_INLINE static T* FindActor(const Tag& tag, Actor* root = nullptr) + { + return (T*)FindActor(T::GetStaticClass(), tag, root); + } + /// /// Tries to find the script of the given type in all the loaded scenes. /// @@ -481,33 +528,6 @@ public: /// API_FUNCTION() static int32 GetLayerIndex(const StringView& layer); -public: - /// - /// Tries to find the actor with the given tag (returns the first one found). - /// - /// The tag of the actor to search for. - /// The custom root actor to start searching from (hierarchical), otherwise null to search all loaded scenes. - /// Found actor or null. - API_FUNCTION() static Actor* FindActor(const Tag& tag, Actor* root = nullptr); - - /// - /// Tries to find the actors with the given tag (returns all found). - /// - /// The tag of the actor to search for. - /// Find only active actors. - /// The custom root actor to start searching from (hierarchical), otherwise null to search all loaded scenes. - /// Found actors or empty if none. - API_FUNCTION() static Array FindActors(const Tag& tag, const bool activeOnly = false, Actor* root = nullptr); - - /// - /// Search actors using a parent parentTag. - /// - /// The tag to search actors with subtags belonging to this tag - /// Find only active actors. - /// The custom root actor to start searching from (hierarchical), otherwise null to search all loaded scenes. - /// Returns all actors that have subtags belonging to the given parent parentTag - API_FUNCTION() static Array FindActorsByParentTag(const Tag& parentTag, const bool activeOnly = false, Actor* root = nullptr); - private: // Actor API enum class ActorEventType From a3dddbfa244564d3e095479392b6673841e6198d Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Wed, 5 Jul 2023 16:19:25 -0500 Subject: [PATCH 56/85] Remove stray debug.log --- Source/Editor/CustomEditors/Editors/TagEditor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/Editor/CustomEditors/Editors/TagEditor.cs b/Source/Editor/CustomEditors/Editors/TagEditor.cs index 948663892..ab5fd5d1a 100644 --- a/Source/Editor/CustomEditors/Editors/TagEditor.cs +++ b/Source/Editor/CustomEditors/Editors/TagEditor.cs @@ -390,7 +390,6 @@ namespace FlaxEditor.CustomEditors.Editors if (addTagDropPanel.IsClosed) { - Debug.Log("Hit"); nameTextBox.BorderColor = Color.Transparent; nameTextBox.BorderSelectedColor = FlaxEngine.GUI.Style.Current.BackgroundSelected; return; From 48474065d78573099b122e83c42ddd2c7944d0c1 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 7 Jul 2023 16:46:35 -0500 Subject: [PATCH 57/85] Add spot light inner circle debug lines. --- Source/Engine/Level/Actors/SpotLight.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/Engine/Level/Actors/SpotLight.cpp b/Source/Engine/Level/Actors/SpotLight.cpp index 26f1700d5..95e47126a 100644 --- a/Source/Engine/Level/Actors/SpotLight.cpp +++ b/Source/Engine/Level/Actors/SpotLight.cpp @@ -203,6 +203,11 @@ void SpotLight::OnDebugDrawSelected() DEBUG_DRAW_LINE(position, position + forward * radius + right * discRadius, color, 0, true); DEBUG_DRAW_LINE(position, position + forward * radius - right * discRadius, color, 0, true); + DEBUG_DRAW_LINE(position, position + forward * radius + up * falloffDiscRadius, color * 0.6f, 0, true); + DEBUG_DRAW_LINE(position, position + forward * radius - up * falloffDiscRadius, color * 0.6f, 0, true); + DEBUG_DRAW_LINE(position, position + forward * radius + right * falloffDiscRadius, color * 0.6f, 0, true); + DEBUG_DRAW_LINE(position, position + forward * radius - right * falloffDiscRadius, color * 0.6f, 0, true); + DEBUG_DRAW_CIRCLE(position + forward * radius, forward, discRadius, color, 0, true); DEBUG_DRAW_CIRCLE(position + forward * radius, forward, falloffDiscRadius, color * 0.6f, 0, true); From a0bb3f29957374f7367d4e8deb76c699eaecb33e Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 7 Jul 2023 17:32:46 -0500 Subject: [PATCH 58/85] Add light debug view flag to draw light shapes --- Source/Editor/Viewport/EditorViewport.cs | 1 + Source/Engine/Graphics/Enums.h | 5 +++ Source/Engine/Level/Actors/Light.cpp | 8 +++++ Source/Engine/Level/Actors/Light.h | 2 ++ Source/Engine/Level/Actors/PointLight.cpp | 10 ++++++ Source/Engine/Level/Actors/PointLight.h | 1 + Source/Engine/Level/Actors/SpotLight.cpp | 33 ++++++++++++++++++++ Source/Engine/Level/Actors/SpotLight.h | 1 + Source/Engine/Level/Scene/SceneRendering.cpp | 10 ++++++ Source/Engine/Level/Scene/SceneRendering.h | 18 +++++++++++ 10 files changed, 89 insertions(+) diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs index b4fb8f8f1..3281d130a 100644 --- a/Source/Editor/Viewport/EditorViewport.cs +++ b/Source/Editor/Viewport/EditorViewport.cs @@ -1538,6 +1538,7 @@ namespace FlaxEditor.Viewport 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"), }; diff --git a/Source/Engine/Graphics/Enums.h b/Source/Engine/Graphics/Enums.h index 3ef462925..4d1422f96 100644 --- a/Source/Engine/Graphics/Enums.h +++ b/Source/Engine/Graphics/Enums.h @@ -1031,6 +1031,11 @@ API_ENUM(Attributes="Flags") enum class ViewFlags : uint64 /// Sky = 1 << 26, + /// + /// Shows/hides light debug shapes. + /// + LightsDebug = 1 << 27, + /// /// Default flags for Game. /// diff --git a/Source/Engine/Level/Actors/Light.cpp b/Source/Engine/Level/Actors/Light.cpp index 594ebdc2b..5e86f6e7e 100644 --- a/Source/Engine/Level/Actors/Light.cpp +++ b/Source/Engine/Level/Actors/Light.cpp @@ -26,6 +26,7 @@ void Light::OnEnable() GetSceneRendering()->AddActor(this, _sceneRenderingKey); #if USE_EDITOR GetSceneRendering()->AddViewportIcon(this); + GetSceneRendering()->AddLightsDebug(this); #endif // Base @@ -36,6 +37,7 @@ void Light::OnDisable() { #if USE_EDITOR GetSceneRendering()->RemoveViewportIcon(this); + GetSceneRendering()->RemoveLightsDebug(this); #endif GetSceneRendering()->RemoveActor(this, _sceneRenderingKey); @@ -43,6 +45,12 @@ void Light::OnDisable() Actor::OnDisable(); } +#if USE_EDITOR +void Light::DrawLightsDebug(RenderView& view) +{ +} +#endif + void Light::Serialize(SerializeStream& stream, const void* otherObj) { // Base diff --git a/Source/Engine/Level/Actors/Light.h b/Source/Engine/Level/Actors/Light.h index dab613c71..86ca59ef5 100644 --- a/Source/Engine/Level/Actors/Light.h +++ b/Source/Engine/Level/Actors/Light.h @@ -66,6 +66,8 @@ public: const Vector3 size(50); return BoundingBox(_transform.Translation - size, _transform.Translation + size); } + + virtual void DrawLightsDebug(RenderView& view); #endif void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; diff --git a/Source/Engine/Level/Actors/PointLight.cpp b/Source/Engine/Level/Actors/PointLight.cpp index 49c0f4c88..0e7ea79ec 100644 --- a/Source/Engine/Level/Actors/PointLight.cpp +++ b/Source/Engine/Level/Actors/PointLight.cpp @@ -143,6 +143,16 @@ void PointLight::OnDebugDrawSelected() LightWithShadow::OnDebugDrawSelected(); } +void PointLight::DrawLightsDebug(RenderView& view) +{ + const BoundingSphere sphere(_sphere.Center - view.Origin, _sphere.Radius); + if (!view.CullingFrustum.Intersects(sphere)) + return; + + // Draw influence range + DEBUG_DRAW_WIRE_SPHERE(_sphere, Color::Yellow, 0, true); +} + #endif void PointLight::OnLayerChanged() diff --git a/Source/Engine/Level/Actors/PointLight.h b/Source/Engine/Level/Actors/PointLight.h index d3e170a03..50df19232 100644 --- a/Source/Engine/Level/Actors/PointLight.h +++ b/Source/Engine/Level/Actors/PointLight.h @@ -95,6 +95,7 @@ public: #if USE_EDITOR void OnDebugDraw() override; void OnDebugDrawSelected() override; + void DrawLightsDebug(RenderView& view) override; #endif void OnLayerChanged() override; void Serialize(SerializeStream& stream, const void* otherObj) override; diff --git a/Source/Engine/Level/Actors/SpotLight.cpp b/Source/Engine/Level/Actors/SpotLight.cpp index 26f1700d5..557d69cd9 100644 --- a/Source/Engine/Level/Actors/SpotLight.cpp +++ b/Source/Engine/Level/Actors/SpotLight.cpp @@ -203,6 +203,11 @@ void SpotLight::OnDebugDrawSelected() DEBUG_DRAW_LINE(position, position + forward * radius + right * discRadius, color, 0, true); DEBUG_DRAW_LINE(position, position + forward * radius - right * discRadius, color, 0, true); + DEBUG_DRAW_LINE(position, position + forward * radius + up * falloffDiscRadius, color * 0.6f, 0, true); + DEBUG_DRAW_LINE(position, position + forward * radius - up * falloffDiscRadius, color * 0.6f, 0, true); + DEBUG_DRAW_LINE(position, position + forward * radius + right * falloffDiscRadius, color * 0.6f, 0, true); + DEBUG_DRAW_LINE(position, position + forward * radius - right * falloffDiscRadius, color * 0.6f, 0, true); + DEBUG_DRAW_CIRCLE(position + forward * radius, forward, discRadius, color, 0, true); DEBUG_DRAW_CIRCLE(position + forward * radius, forward, falloffDiscRadius, color * 0.6f, 0, true); @@ -210,6 +215,34 @@ void SpotLight::OnDebugDrawSelected() LightWithShadow::OnDebugDrawSelected(); } +void SpotLight::DrawLightsDebug(RenderView& view) +{ + const BoundingSphere sphere(_sphere.Center - view.Origin, _sphere.Radius); + if (!view.CullingFrustum.Intersects(sphere)) + return; + + const auto color = Color::Yellow; + Vector3 right = _transform.GetRight(); + Vector3 up = _transform.GetUp(); + Vector3 forward = GetDirection(); + float radius = GetScaledRadius(); + float discRadius = radius * Math::Tan(_outerConeAngle * DegreesToRadians); + float falloffDiscRadius = radius * Math::Tan(_innerConeAngle * DegreesToRadians); + Vector3 position = GetPosition(); + + DEBUG_DRAW_LINE(position, position + forward * radius + up * discRadius, color, 0, true); + DEBUG_DRAW_LINE(position, position + forward * radius - up * discRadius, color, 0, true); + DEBUG_DRAW_LINE(position, position + forward * radius + right * discRadius, color, 0, true); + DEBUG_DRAW_LINE(position, position + forward * radius - right * discRadius, color, 0, true); + + DEBUG_DRAW_LINE(position, position + forward * radius + up * falloffDiscRadius, color * 0.6f, 0, true); + DEBUG_DRAW_LINE(position, position + forward * radius - up * falloffDiscRadius, color * 0.6f, 0, true); + DEBUG_DRAW_LINE(position, position + forward * radius + right * falloffDiscRadius, color * 0.6f, 0, true); + DEBUG_DRAW_LINE(position, position + forward * radius - right * falloffDiscRadius, color * 0.6f, 0, true); + + DEBUG_DRAW_CIRCLE(position + forward * radius, forward, discRadius, color, 0, true); + DEBUG_DRAW_CIRCLE(position + forward * radius, forward, falloffDiscRadius, color * 0.6f, 0, true); +} #endif void SpotLight::Serialize(SerializeStream& stream, const void* otherObj) diff --git a/Source/Engine/Level/Actors/SpotLight.h b/Source/Engine/Level/Actors/SpotLight.h index 6bb0daf8d..e6179a522 100644 --- a/Source/Engine/Level/Actors/SpotLight.h +++ b/Source/Engine/Level/Actors/SpotLight.h @@ -127,6 +127,7 @@ public: #if USE_EDITOR void OnDebugDraw() override; void OnDebugDrawSelected() override; + void DrawLightsDebug(RenderView& view) override; #endif void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; diff --git a/Source/Engine/Level/Scene/SceneRendering.cpp b/Source/Engine/Level/Scene/SceneRendering.cpp index 48420ed49..65773b6c0 100644 --- a/Source/Engine/Level/Scene/SceneRendering.cpp +++ b/Source/Engine/Level/Scene/SceneRendering.cpp @@ -96,6 +96,16 @@ void SceneRendering::Draw(RenderContextBatch& renderContextBatch, DrawCategory c physicsDebugData[i](view); } } + + // Draw light shapes + if (EnumHasAnyFlags(view.Flags, ViewFlags::LightsDebug)) + { + const LightsDebugCallback* lightsDebugData = LightsDebug.Get(); + for (int32 i = 0; i < LightsDebug.Count(); i++) + { + lightsDebugData[i](view); + } + } } #endif } diff --git a/Source/Engine/Level/Scene/SceneRendering.h b/Source/Engine/Level/Scene/SceneRendering.h index ef9fc6c3c..0afe4ea3c 100644 --- a/Source/Engine/Level/Scene/SceneRendering.h +++ b/Source/Engine/Level/Scene/SceneRendering.h @@ -65,6 +65,7 @@ class FLAXENGINE_API SceneRendering { #if USE_EDITOR typedef Function PhysicsDebugCallback; + typedef Function LightsDebugCallback; friend class ViewportIconsRendererService; #endif public: @@ -95,6 +96,7 @@ public: private: #if USE_EDITOR Array PhysicsDebug; + Array LightsDebug; Array ViewportIcons; #endif @@ -153,6 +155,22 @@ public: PhysicsDebug.Remove(f); } + template + FORCE_INLINE void AddLightsDebug(T* obj) + { + LightsDebugCallback f; + f.Bind(obj); + LightsDebug.Add(f); + } + + template + void RemoveLightsDebug(T* obj) + { + LightsDebugCallback f; + f.Bind(obj); + LightsDebug.Remove(f); + } + FORCE_INLINE void AddViewportIcon(Actor* obj) { ViewportIcons.Add(obj); From 0a57cbbecfdea7555ffeb61b4f1f347cbee2917a Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 7 Jul 2023 17:48:16 -0500 Subject: [PATCH 59/85] Add not showing lights debug based on other light flags as well. --- Source/Engine/Level/Actors/PointLight.cpp | 2 +- Source/Engine/Level/Actors/SpotLight.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Level/Actors/PointLight.cpp b/Source/Engine/Level/Actors/PointLight.cpp index 0e7ea79ec..912d21a6a 100644 --- a/Source/Engine/Level/Actors/PointLight.cpp +++ b/Source/Engine/Level/Actors/PointLight.cpp @@ -146,7 +146,7 @@ void PointLight::OnDebugDrawSelected() void PointLight::DrawLightsDebug(RenderView& view) { const BoundingSphere sphere(_sphere.Center - view.Origin, _sphere.Radius); - if (!view.CullingFrustum.Intersects(sphere)) + if (!view.CullingFrustum.Intersects(sphere) || !EnumHasAnyFlags(view.Flags, ViewFlags::PointLights)) return; // Draw influence range diff --git a/Source/Engine/Level/Actors/SpotLight.cpp b/Source/Engine/Level/Actors/SpotLight.cpp index 557d69cd9..90878fc00 100644 --- a/Source/Engine/Level/Actors/SpotLight.cpp +++ b/Source/Engine/Level/Actors/SpotLight.cpp @@ -218,7 +218,7 @@ void SpotLight::OnDebugDrawSelected() void SpotLight::DrawLightsDebug(RenderView& view) { const BoundingSphere sphere(_sphere.Center - view.Origin, _sphere.Radius); - if (!view.CullingFrustum.Intersects(sphere)) + if (!view.CullingFrustum.Intersects(sphere) || !EnumHasAnyFlags(view.Flags, ViewFlags::SpotLights)) return; const auto color = Color::Yellow; From c2da48c49f34f570499557319ddb0dcdd62599a7 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 8 Jul 2023 21:05:20 +0200 Subject: [PATCH 60/85] Fix dotnet installation selection on Linux to favor `lib` over `share` --- Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs index e8739a9fc..d3a706a43 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs @@ -199,7 +199,11 @@ namespace Flax.Build if (rid == ridFallback) ridFallback = ""; if (string.IsNullOrEmpty(dotnetPath)) - dotnetPath = "/usr/share/dotnet/"; + { + dotnetPath = "/usr/lib/dotnet/"; + if (!Directory.Exists(dotnetPath)) + dotnetPath = "/usr/share/dotnet/"; + } break; } case TargetPlatform.Mac: From 843abca8cac5df44f91dd09028fb1ce1125b8ac6 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 14 Jul 2023 10:59:04 +0200 Subject: [PATCH 61/85] Fix error when opening shader asset if it's not visible in Content window --- Source/Editor/Content/Proxy/ShaderProxy.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/Content/Proxy/ShaderProxy.cs b/Source/Editor/Content/Proxy/ShaderProxy.cs index 2f5c6fe42..98d4eaa2d 100644 --- a/Source/Editor/Content/Proxy/ShaderProxy.cs +++ b/Source/Editor/Content/Proxy/ShaderProxy.cs @@ -29,7 +29,7 @@ namespace FlaxEditor.Content if (asset) { var source = Editor.GetShaderSourceCode(asset); - Utilities.Utils.ShowSourceCodeWindow(source, "Shader Source", item.RootWindow.Window); + Utilities.Utils.ShowSourceCodeWindow(source, "Shader Source", item.RootWindow?.Window); } return null; } From 40fc2f82950a967d09c59524346bab1ce5eb1a4e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 14 Jul 2023 11:25:54 +0200 Subject: [PATCH 62/85] Fix missing header files in deployed engine package #1242 --- Source/Editor/Editor.Build.cs | 2 ++ Source/Engine/Content/Content.Build.cs | 3 +++ Source/Engine/ContentExporters/ContentExporters.Build.cs | 3 +++ Source/Engine/ContentImporters/ContentImporters.Build.cs | 3 +++ 4 files changed, 11 insertions(+) diff --git a/Source/Editor/Editor.Build.cs b/Source/Editor/Editor.Build.cs index 2e769f431..cc7c48d23 100644 --- a/Source/Editor/Editor.Build.cs +++ b/Source/Editor/Editor.Build.cs @@ -102,5 +102,7 @@ public class Editor : EditorModule files.Add(Path.Combine(FolderPath, "Cooker/GameCooker.h")); files.Add(Path.Combine(FolderPath, "Cooker/PlatformTools.h")); files.Add(Path.Combine(FolderPath, "Cooker/Steps/CookAssetsStep.h")); + files.Add(Path.Combine(FolderPath, "Utilities/ScreenUtilities.h")); + files.Add(Path.Combine(FolderPath, "Utilities/ViewportIconsRenderer.h")); } } diff --git a/Source/Engine/Content/Content.Build.cs b/Source/Engine/Content/Content.Build.cs index f89ad6277..6bfc3ee22 100644 --- a/Source/Engine/Content/Content.Build.cs +++ b/Source/Engine/Content/Content.Build.cs @@ -37,6 +37,9 @@ public class Content : EngineModule files.AddRange(Directory.GetFiles(FolderPath, "*.h", SearchOption.TopDirectoryOnly)); files.AddRange(Directory.GetFiles(Path.Combine(FolderPath, "Assets"), "*.h", SearchOption.TopDirectoryOnly)); files.AddRange(Directory.GetFiles(Path.Combine(FolderPath, "Cache"), "*.h", SearchOption.TopDirectoryOnly)); + files.AddRange(Directory.GetFiles(Path.Combine(FolderPath, "Factories"), "*.h", SearchOption.TopDirectoryOnly)); files.AddRange(Directory.GetFiles(Path.Combine(FolderPath, "Storage"), "*.h", SearchOption.TopDirectoryOnly)); + files.Add(Path.Combine(FolderPath, "Upgraders/BinaryAssetUpgrader.h")); + files.Add(Path.Combine(FolderPath, "Upgraders/IAssetUpgrader.h")); } } diff --git a/Source/Engine/ContentExporters/ContentExporters.Build.cs b/Source/Engine/ContentExporters/ContentExporters.Build.cs index 6721d43a9..a118022b2 100644 --- a/Source/Engine/ContentExporters/ContentExporters.Build.cs +++ b/Source/Engine/ContentExporters/ContentExporters.Build.cs @@ -1,6 +1,7 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System.Collections.Generic; +using System.IO; using Flax.Build; using Flax.Build.NativeCpp; @@ -23,5 +24,7 @@ public class ContentExporters : EngineModule /// public override void GetFilesToDeploy(List files) { + files.Add(Path.Combine(FolderPath, "AssetsExportingManager.h")); + files.Add(Path.Combine(FolderPath, "Types.h")); } } diff --git a/Source/Engine/ContentImporters/ContentImporters.Build.cs b/Source/Engine/ContentImporters/ContentImporters.Build.cs index 8c4614cd5..f404037a6 100644 --- a/Source/Engine/ContentImporters/ContentImporters.Build.cs +++ b/Source/Engine/ContentImporters/ContentImporters.Build.cs @@ -1,6 +1,7 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System.Collections.Generic; +using System.IO; using Flax.Build; using Flax.Build.NativeCpp; @@ -31,5 +32,7 @@ public class ContentImporters : EngineModule /// public override void GetFilesToDeploy(List files) { + files.Add(Path.Combine(FolderPath, "AssetsImportingManager.h")); + files.Add(Path.Combine(FolderPath, "Types.h")); } } From 7b88569e73cdc6c15488a0bc32cafea08a103fbb Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 14 Jul 2023 11:57:38 +0200 Subject: [PATCH 63/85] Add `sealed` tag to virtual functions in API bindings to block inheritance in C#/VS --- Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs index c05ab4e73..1eeefaf27 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs @@ -847,6 +847,9 @@ namespace Flax.Build.Bindings case "hidden": desc.IsHidden = true; break; + case "sealed": + desc.IsVirtual = false; + break; case "tag": ParseTag(ref desc.Tags, tag); break; From a6924d37c1cd2b4f6cf660ed14531aea347650e7 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 14 Jul 2023 11:58:51 +0200 Subject: [PATCH 64/85] Add `ModelInstanceActor::GetMaterial` to get actual material used to render certain entries --- Source/Engine/Level/Actors/AnimatedModel.cpp | 17 +++++++++++++++++ Source/Engine/Level/Actors/AnimatedModel.h | 1 + .../Engine/Level/Actors/ModelInstanceActor.cpp | 5 ++--- Source/Engine/Level/Actors/ModelInstanceActor.h | 6 ++++++ Source/Engine/Level/Actors/SplineModel.cpp | 17 +++++++++++++++++ Source/Engine/Level/Actors/SplineModel.h | 1 + Source/Engine/Level/Actors/StaticModel.cpp | 17 +++++++++++++++++ Source/Engine/Level/Actors/StaticModel.h | 3 ++- 8 files changed, 63 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index dae5f281f..373278885 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -898,6 +898,23 @@ void AnimatedModel::Deserialize(DeserializeStream& stream, ISerializeModifier* m DrawModes |= DrawPass::GlobalSurfaceAtlas; } +MaterialBase* AnimatedModel::GetMaterial(int32 entryIndex) +{ + if (SkinnedModel) + SkinnedModel->WaitForLoaded(); + else + return nullptr; + CHECK_RETURN(entryIndex >= 0 && entryIndex < Entries.Count(), nullptr); + MaterialBase* material = Entries[entryIndex].Material.Get(); + if (!material) + { + material = SkinnedModel->MaterialSlots[entryIndex].Material.Get(); + if (!material) + material = GPUDevice::Instance->GetDefaultMaterial(); + } + return material; +} + bool AnimatedModel::IntersectsEntry(int32 entryIndex, const Ray& ray, Real& distance, Vector3& normal) { auto model = SkinnedModel.Get(); diff --git a/Source/Engine/Level/Actors/AnimatedModel.h b/Source/Engine/Level/Actors/AnimatedModel.h index 33f206580..2693f573d 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.h +++ b/Source/Engine/Level/Actors/AnimatedModel.h @@ -373,6 +373,7 @@ public: bool IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) override; void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; + MaterialBase* GetMaterial(int32 entryIndex) override; bool IntersectsEntry(int32 entryIndex, const Ray& ray, Real& distance, Vector3& normal) override; bool IntersectsEntry(const Ray& ray, Real& distance, Vector3& normal, int32& entryIndex) override; void OnDeleteObject() override; diff --git a/Source/Engine/Level/Actors/ModelInstanceActor.cpp b/Source/Engine/Level/Actors/ModelInstanceActor.cpp index 0c1879d83..03b873864 100644 --- a/Source/Engine/Level/Actors/ModelInstanceActor.cpp +++ b/Source/Engine/Level/Actors/ModelInstanceActor.cpp @@ -39,10 +39,9 @@ void ModelInstanceActor::SetMaterial(int32 entryIndex, MaterialBase* material) MaterialInstance* ModelInstanceActor::CreateAndSetVirtualMaterialInstance(int32 entryIndex) { WaitForModelLoad(); - CHECK_RETURN(entryIndex >= 0 && entryIndex < Entries.Count(), nullptr); - auto material = Entries[entryIndex].Material.Get(); + MaterialBase* material = GetMaterial(entryIndex); CHECK_RETURN(material && !material->WaitForLoaded(), nullptr); - const auto result = material->CreateVirtualInstance(); + MaterialInstance* result = material->CreateVirtualInstance(); Entries[entryIndex].Material = result; if (_sceneRenderingKey != -1) GetSceneRendering()->UpdateActor(this, _sceneRenderingKey); diff --git a/Source/Engine/Level/Actors/ModelInstanceActor.h b/Source/Engine/Level/Actors/ModelInstanceActor.h index 825b64c23..1dfd5c0e0 100644 --- a/Source/Engine/Level/Actors/ModelInstanceActor.h +++ b/Source/Engine/Level/Actors/ModelInstanceActor.h @@ -35,6 +35,12 @@ public: /// API_PROPERTY() void SetEntries(const Array& value); + /// + /// Gets the material used to draw the meshes which are assigned to that slot (set in Entries or model's default). + /// + /// The material slot entry index. + API_FUNCTION(Sealed) virtual MaterialBase* GetMaterial(int32 entryIndex) = 0; + /// /// Sets the material to the entry slot. Can be used to override the material of the meshes using this slot. /// diff --git a/Source/Engine/Level/Actors/SplineModel.cpp b/Source/Engine/Level/Actors/SplineModel.cpp index 08dc5ddea..843bf6076 100644 --- a/Source/Engine/Level/Actors/SplineModel.cpp +++ b/Source/Engine/Level/Actors/SplineModel.cpp @@ -341,6 +341,23 @@ void SplineModel::OnParentChanged() OnSplineUpdated(); } +MaterialBase* SplineModel::GetMaterial(int32 entryIndex) +{ + if (Model) + Model->WaitForLoaded(); + else + return nullptr; + CHECK_RETURN(entryIndex >= 0 && entryIndex < Entries.Count(), nullptr); + MaterialBase* material = Entries[entryIndex].Material.Get(); + if (!material) + { + material = Model->MaterialSlots[entryIndex].Material.Get(); + if (!material) + material = GPUDevice::Instance->GetDefaultDeformableMaterial(); + } + return material; +} + bool SplineModel::HasContentLoaded() const { return (Model == nullptr || Model->IsLoaded()) && Entries.HasContentLoaded(); diff --git a/Source/Engine/Level/Actors/SplineModel.h b/Source/Engine/Level/Actors/SplineModel.h index 50864d7b7..87f39699c 100644 --- a/Source/Engine/Level/Actors/SplineModel.h +++ b/Source/Engine/Level/Actors/SplineModel.h @@ -115,6 +115,7 @@ public: void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; void OnParentChanged() override; + MaterialBase* GetMaterial(int32 entryIndex) override; protected: // [ModelInstanceActor] diff --git a/Source/Engine/Level/Actors/StaticModel.cpp b/Source/Engine/Level/Actors/StaticModel.cpp index 3eb3b6012..778f24d65 100644 --- a/Source/Engine/Level/Actors/StaticModel.cpp +++ b/Source/Engine/Level/Actors/StaticModel.cpp @@ -535,6 +535,23 @@ void StaticModel::Deserialize(DeserializeStream& stream, ISerializeModifier* mod } } +MaterialBase* StaticModel::GetMaterial(int32 entryIndex) +{ + if (Model) + Model->WaitForLoaded(); + else + return nullptr; + CHECK_RETURN(entryIndex >= 0 && entryIndex < Entries.Count(), nullptr); + MaterialBase* material = Entries[entryIndex].Material.Get(); + if (!material) + { + material = Model->MaterialSlots[entryIndex].Material.Get(); + if (!material) + material = GPUDevice::Instance->GetDefaultMaterial(); + } + return material; +} + bool StaticModel::IntersectsEntry(int32 entryIndex, const Ray& ray, Real& distance, Vector3& normal) { auto model = Model.Get(); diff --git a/Source/Engine/Level/Actors/StaticModel.h b/Source/Engine/Level/Actors/StaticModel.h index af3aa53c0..06fbdd874 100644 --- a/Source/Engine/Level/Actors/StaticModel.h +++ b/Source/Engine/Level/Actors/StaticModel.h @@ -121,7 +121,7 @@ public: /// The zero-based mesh index. /// The LOD index. /// Material or null if not assigned. - API_FUNCTION() MaterialBase* GetMaterial(int32 meshIndex, int32 lodIndex = 0) const; + API_FUNCTION() MaterialBase* GetMaterial(int32 meshIndex, int32 lodIndex) const; /// /// Gets the color of the painter vertex (this model instance). @@ -166,6 +166,7 @@ public: bool IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) override; void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; + MaterialBase* GetMaterial(int32 entryIndex) override; bool IntersectsEntry(int32 entryIndex, const Ray& ray, Real& distance, Vector3& normal) override; bool IntersectsEntry(const Ray& ray, Real& distance, Vector3& normal, int32& entryIndex) override; From f5f948ea4c20650cfdd22554029af6974dbfcd88 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 14 Jul 2023 12:17:21 +0200 Subject: [PATCH 65/85] Fix culling artifacts in animated model preview in Editor --- Source/Editor/Viewport/Previews/AnimatedModelPreview.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs index 9a7ec6800..12371f947 100644 --- a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs +++ b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs @@ -185,8 +185,8 @@ namespace FlaxEditor.Viewport.Previews { UseTimeScale = false, UpdateWhenOffscreen = true, - //_previewModel.BoundsScale = 1000.0f; - UpdateMode = AnimatedModel.AnimationUpdateMode.Manual + BoundsScale = 100.0f, + UpdateMode = AnimatedModel.AnimationUpdateMode.Manual, }; Task.AddCustomActor(_previewModel); From 84c99ea1c3efe713ab9c363c305e5cd6a6042c17 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 14 Jul 2023 13:10:20 +0200 Subject: [PATCH 66/85] Fix nested animation sampling bug #1244 --- Source/Engine/Animations/Graph/AnimGroup.Animation.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp index c508ab3c8..31b97fb52 100644 --- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp +++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp @@ -217,6 +217,7 @@ void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode* const float animPrevPos = GetAnimSamplePos(length, anim, prevPos, speed); // Evaluate nested animations + bool hasNested = false; if (anim->NestedAnims.Count() != 0) { for (auto& e : anim->NestedAnims) @@ -239,6 +240,7 @@ void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode* GetAnimSamplePos(nestedAnim.Loop, nestedAnimLength, nestedAnim.StartTime, nestedAnimPrevPos, nestedAnimPos, nestedAnimPos, nestedAnimPrevPos); ProcessAnimation(nodes, node, true, nestedAnimLength, nestedAnimPos, nestedAnimPrevPos, nestedAnim.Anim, 1.0f, weight, mode); + hasNested = true; } } } @@ -291,7 +293,7 @@ void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode* dstNode.Scale = srcNode.Scale * weight; dstNode.Orientation = srcNode.Orientation * weight; } - else + else if (!hasNested) { dstNode = srcNode; } From ff56152ef2b9166345405e93ba1fa4de6a1c2b11 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sat, 15 Jul 2023 13:19:22 +0300 Subject: [PATCH 67/85] Fix releasing non-collectible types with collectible generic types --- .../Engine/Engine/NativeInterop.Unmanaged.cs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index 17b8b73af..57454ad1e 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -244,7 +244,25 @@ namespace FlaxEngine.Interop @namespace = NativeAllocStringAnsi(type.Namespace ?? ""), typeAttributes = (uint)type.Attributes, }; - *assemblyHandle = GetAssemblyHandle(type.Assembly); + + Assembly assembly = null; + if (type.IsGenericType && !type.Assembly.IsCollectible) + { + // The owning assembly of a generic type with type arguments referencing + // collectible assemblies must be one of the collectible assemblies. + foreach (var genericType in type.GetGenericArguments()) + { + if (genericType.Assembly.IsCollectible) + { + assembly = genericType.Assembly; + break; + } + } + } + if (assembly == null) + assembly = type.Assembly; + + *assemblyHandle = GetAssemblyHandle(assembly); } [UnmanagedCallersOnly] From ba93e1e1d0bcd711a46e6a573abc2085717a2e5d Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sat, 15 Jul 2023 10:00:34 -0500 Subject: [PATCH 68/85] Add showing default materials to model entries. --- .../CustomEditors/Editors/AssetRefEditor.cs | 35 ++++---- .../Editors/ModelInstanceEntryEditor.cs | 85 +++++++++++++++++++ Source/Engine/Graphics/GPUDevice.h | 2 +- 3 files changed, 105 insertions(+), 17 deletions(-) diff --git a/Source/Editor/CustomEditors/Editors/AssetRefEditor.cs b/Source/Editor/CustomEditors/Editors/AssetRefEditor.cs index 17999d772..b83b44d59 100644 --- a/Source/Editor/CustomEditors/Editors/AssetRefEditor.cs +++ b/Source/Editor/CustomEditors/Editors/AssetRefEditor.cs @@ -33,7 +33,10 @@ namespace FlaxEditor.CustomEditors.Editors [CustomEditor(typeof(Asset)), DefaultEditor] public class AssetRefEditor : CustomEditor { - private AssetPicker _picker; + /// + /// The asset picker used to get a reference to an asset. + /// + public AssetPicker Picker; private ScriptType _valueType; /// @@ -44,7 +47,7 @@ namespace FlaxEditor.CustomEditors.Editors { if (HasDifferentTypes) return; - _picker = layout.Custom().CustomControl; + Picker = layout.Custom().CustomControl; _valueType = Values.Type.Type != typeof(object) || Values[0] == null ? Values.Type : TypeUtils.GetObjectType(Values[0]); var assetType = _valueType; @@ -66,7 +69,7 @@ namespace FlaxEditor.CustomEditors.Editors { // Generic file picker assetType = ScriptType.Null; - _picker.FileExtension = assetReference.TypeName; + Picker.FileExtension = assetReference.TypeName; } else { @@ -78,23 +81,23 @@ namespace FlaxEditor.CustomEditors.Editors } } - _picker.AssetType = assetType; - _picker.Height = height; - _picker.SelectedItemChanged += OnSelectedItemChanged; + Picker.AssetType = assetType; + Picker.Height = height; + Picker.SelectedItemChanged += OnSelectedItemChanged; } private void OnSelectedItemChanged() { if (typeof(AssetItem).IsAssignableFrom(_valueType.Type)) - SetValue(_picker.SelectedItem); + SetValue(Picker.SelectedItem); else if (_valueType.Type == typeof(Guid)) - SetValue(_picker.SelectedID); + SetValue(Picker.SelectedID); else if (_valueType.Type == typeof(SceneReference)) - SetValue(new SceneReference(_picker.SelectedID)); + SetValue(new SceneReference(Picker.SelectedID)); else if (_valueType.Type == typeof(string)) - SetValue(_picker.SelectedPath); + SetValue(Picker.SelectedPath); else - SetValue(_picker.SelectedAsset); + SetValue(Picker.SelectedAsset); } /// @@ -105,15 +108,15 @@ namespace FlaxEditor.CustomEditors.Editors if (!HasDifferentValues) { if (Values[0] is AssetItem assetItem) - _picker.SelectedItem = assetItem; + Picker.SelectedItem = assetItem; else if (Values[0] is Guid guid) - _picker.SelectedID = guid; + Picker.SelectedID = guid; else if (Values[0] is SceneReference sceneAsset) - _picker.SelectedItem = Editor.Instance.ContentDatabase.FindAsset(sceneAsset.ID); + Picker.SelectedItem = Editor.Instance.ContentDatabase.FindAsset(sceneAsset.ID); else if (Values[0] is string path) - _picker.SelectedPath = path; + Picker.SelectedPath = path; else - _picker.SelectedAsset = Values[0] as Asset; + Picker.SelectedAsset = Values[0] as Asset; } } } diff --git a/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs b/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs index a08a254d4..6ac96fcea 100644 --- a/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs @@ -1,6 +1,8 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using FlaxEditor.CustomEditors.Elements; +using FlaxEditor.CustomEditors.GUI; +using FlaxEditor.Scripting; using FlaxEngine; namespace FlaxEditor.CustomEditors.Editors @@ -13,6 +15,8 @@ namespace FlaxEditor.CustomEditors.Editors { private GroupElement _group; private bool _updateName; + private MaterialBase _material; + private ModelInstanceEntry _entry; /// public override void Initialize(LayoutElementsContainer layout) @@ -20,10 +24,91 @@ namespace FlaxEditor.CustomEditors.Editors _updateName = true; var group = layout.Group("Entry"); _group = group; + + _entry = (ModelInstanceEntry)Values[0]; + var entryIndex = ParentEditor.ChildrenEditors.IndexOf(this); + var materiaLabel = new PropertyNameLabel("Material"); + materiaLabel.TooltipText = "The mesh surface material used for the rendering."; + if (ParentEditor.ParentEditor.Values[0] is StaticModel staticModel) + { + // Ensure that entry with default material set is set back to null + if (_entry.Material == staticModel.Model.MaterialSlots[entryIndex].Material) + { + staticModel.SetMaterial(entryIndex, null); + } + _material = staticModel.GetMaterial(entryIndex); + var matContainer = new CustomValueContainer(new ScriptType(typeof(MaterialBase)), _material, (instance, index) => _material, (instance, index, value) => _material = value as MaterialBase); + var materialEditor = (_group.Property(materiaLabel, matContainer)) as AssetRefEditor; + materialEditor.Values.SetDefaultValue(staticModel.Model.MaterialSlots[entryIndex].Material); + materialEditor.RefreshDefaultValue(); + materialEditor.Picker.SelectedItemChanged += () => + { + var material = materialEditor.Picker.SelectedAsset as MaterialBase; + if (!material) + { + staticModel.SetMaterial(entryIndex, GPUDevice.Instance.DefaultMaterial); + materialEditor.Picker.SelectedAsset = GPUDevice.Instance.DefaultMaterial; + } + else if (material == staticModel.Model.MaterialSlots[entryIndex]) + { + staticModel.SetMaterial(entryIndex, null); + } + else + { + staticModel.SetMaterial(entryIndex, material); + } + }; + } + else if (ParentEditor.ParentEditor.Values[0] is AnimatedModel animatedModel) + { + // Ensure that entry with default material set is set back to null + if (_entry.Material == animatedModel.SkinnedModel.MaterialSlots[entryIndex].Material) + { + animatedModel.SetMaterial(entryIndex, null); + } + _material = animatedModel.GetMaterial(entryIndex); + + var matContainer = new CustomValueContainer(new ScriptType(typeof(MaterialBase)), _material, (instance, index) => _material, (instance, index, value) => + { + _material = value as MaterialBase; + }); + var materialEditor = (_group.Property(materiaLabel, matContainer)) as AssetRefEditor; + materialEditor.Values.SetDefaultValue(animatedModel.SkinnedModel.MaterialSlots[entryIndex].Material); + materialEditor.RefreshDefaultValue(); + materialEditor.Picker.SelectedItemChanged += () => + { + var material = materialEditor.Picker.SelectedAsset as MaterialBase; + if (!material) + { + animatedModel.SetMaterial(entryIndex, GPUDevice.Instance.DefaultMaterial); + materialEditor.Picker.SelectedAsset = GPUDevice.Instance.DefaultMaterial; + } + else if (material == animatedModel.SkinnedModel.MaterialSlots[entryIndex]) + { + animatedModel.SetMaterial(entryIndex, null); + } + else + { + animatedModel.SetMaterial(entryIndex, material); + } + }; + } + base.Initialize(group); } + /// + protected override void SpawnProperty(LayoutElementsContainer itemLayout, ValueContainer itemValues, ItemInfo item) + { + // Skip material member as it is overridden + if (item.Info.Name == "Material") + { + return; + } + base.SpawnProperty(itemLayout, itemValues, item); + } + /// public override void Refresh() { diff --git a/Source/Engine/Graphics/GPUDevice.h b/Source/Engine/Graphics/GPUDevice.h index 4dbcf6d06..422e554a0 100644 --- a/Source/Engine/Graphics/GPUDevice.h +++ b/Source/Engine/Graphics/GPUDevice.h @@ -238,7 +238,7 @@ public: /// /// Gets the default material. /// - MaterialBase* GetDefaultMaterial() const; + API_PROPERTY() MaterialBase* GetDefaultMaterial() const; /// /// Gets the default material (Deformable domain). From c8edaf5d6eabd0a99a35273652e0b810ef6bd42f Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sat, 15 Jul 2023 10:10:37 -0500 Subject: [PATCH 69/85] Fix bug with not using slot material --- .../Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs b/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs index 6ac96fcea..a605b5464 100644 --- a/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs @@ -50,7 +50,7 @@ namespace FlaxEditor.CustomEditors.Editors staticModel.SetMaterial(entryIndex, GPUDevice.Instance.DefaultMaterial); materialEditor.Picker.SelectedAsset = GPUDevice.Instance.DefaultMaterial; } - else if (material == staticModel.Model.MaterialSlots[entryIndex]) + else if (material == staticModel.Model.MaterialSlots[entryIndex].Material) { staticModel.SetMaterial(entryIndex, null); } @@ -84,7 +84,7 @@ namespace FlaxEditor.CustomEditors.Editors animatedModel.SetMaterial(entryIndex, GPUDevice.Instance.DefaultMaterial); materialEditor.Picker.SelectedAsset = GPUDevice.Instance.DefaultMaterial; } - else if (material == animatedModel.SkinnedModel.MaterialSlots[entryIndex]) + else if (material == animatedModel.SkinnedModel.MaterialSlots[entryIndex].Material) { animatedModel.SetMaterial(entryIndex, null); } @@ -112,6 +112,7 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Refresh() { + Debug.Log("Hit"); if (_updateName && _group != null && ParentEditor?.ParentEditor != null && From 02219beac97507d1d7e578d0715aa7b48e98b908 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sat, 15 Jul 2023 10:27:59 -0500 Subject: [PATCH 70/85] Handle edge case --- .../Editors/ModelInstanceEntryEditor.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs b/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs index a605b5464..d33efe551 100644 --- a/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs @@ -40,7 +40,7 @@ namespace FlaxEditor.CustomEditors.Editors var matContainer = new CustomValueContainer(new ScriptType(typeof(MaterialBase)), _material, (instance, index) => _material, (instance, index, value) => _material = value as MaterialBase); var materialEditor = (_group.Property(materiaLabel, matContainer)) as AssetRefEditor; - materialEditor.Values.SetDefaultValue(staticModel.Model.MaterialSlots[entryIndex].Material); + materialEditor.Values.SetDefaultValue((staticModel.Model.MaterialSlots[entryIndex].Material) ? staticModel.Model.MaterialSlots[entryIndex].Material : GPUDevice.Instance.DefaultMaterial); materialEditor.RefreshDefaultValue(); materialEditor.Picker.SelectedItemChanged += () => { @@ -54,6 +54,10 @@ namespace FlaxEditor.CustomEditors.Editors { staticModel.SetMaterial(entryIndex, null); } + else if (material == GPUDevice.Instance.DefaultMaterial && !staticModel.Model.MaterialSlots[entryIndex].Material) + { + staticModel.SetMaterial(entryIndex, null); + } else { staticModel.SetMaterial(entryIndex, material); @@ -69,12 +73,9 @@ namespace FlaxEditor.CustomEditors.Editors } _material = animatedModel.GetMaterial(entryIndex); - var matContainer = new CustomValueContainer(new ScriptType(typeof(MaterialBase)), _material, (instance, index) => _material, (instance, index, value) => - { - _material = value as MaterialBase; - }); + var matContainer = new CustomValueContainer(new ScriptType(typeof(MaterialBase)), _material, (instance, index) => _material, (instance, index, value) => _material = value as MaterialBase); var materialEditor = (_group.Property(materiaLabel, matContainer)) as AssetRefEditor; - materialEditor.Values.SetDefaultValue(animatedModel.SkinnedModel.MaterialSlots[entryIndex].Material); + materialEditor.Values.SetDefaultValue((animatedModel.SkinnedModel.MaterialSlots[entryIndex].Material) ? animatedModel.SkinnedModel.MaterialSlots[entryIndex].Material : GPUDevice.Instance.DefaultMaterial); materialEditor.RefreshDefaultValue(); materialEditor.Picker.SelectedItemChanged += () => { @@ -88,6 +89,10 @@ namespace FlaxEditor.CustomEditors.Editors { animatedModel.SetMaterial(entryIndex, null); } + else if (material == GPUDevice.Instance.DefaultMaterial && !animatedModel.SkinnedModel.MaterialSlots[entryIndex].Material) + { + animatedModel.SetMaterial(entryIndex, null); + } else { animatedModel.SetMaterial(entryIndex, material); From c89421438b56ae193cebfca8fec44b90c8dd9d33 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sat, 15 Jul 2023 10:42:41 -0500 Subject: [PATCH 71/85] Code cleanup --- .../Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs b/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs index d33efe551..b7989cae3 100644 --- a/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs @@ -108,16 +108,13 @@ namespace FlaxEditor.CustomEditors.Editors { // Skip material member as it is overridden if (item.Info.Name == "Material") - { return; - } base.SpawnProperty(itemLayout, itemValues, item); } /// public override void Refresh() { - Debug.Log("Hit"); if (_updateName && _group != null && ParentEditor?.ParentEditor != null && From 868db7c84890c15e8be07663432c913ebb301ca8 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sat, 15 Jul 2023 13:52:10 -0500 Subject: [PATCH 72/85] Add functionality to combine similar logs into a log with a count. --- Source/Editor/Windows/DebugLogWindow.cs | 34 ++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Windows/DebugLogWindow.cs b/Source/Editor/Windows/DebugLogWindow.cs index b02f63f87..81dcaae92 100644 --- a/Source/Editor/Windows/DebugLogWindow.cs +++ b/Source/Editor/Windows/DebugLogWindow.cs @@ -80,6 +80,7 @@ namespace FlaxEditor.Windows public LogGroup Group; public LogEntryDescription Desc; public SpriteHandle Icon; + public int LogCount = 1; public LogEntry(DebugLogWindow window, ref LogEntryDescription desc) : base(0, 0, 120, DefaultHeight) @@ -137,7 +138,12 @@ namespace FlaxEditor.Windows // Title var textRect = new Rectangle(38, 2, clientRect.Width - 40, clientRect.Height - 10); Render2D.PushClip(ref clientRect); - Render2D.DrawText(style.FontMedium, Desc.Title, textRect, style.Foreground); + string countText = string.Empty; + if (LogCount > 1) + { + countText = $" ({LogCount})"; + } + Render2D.DrawText(style.FontMedium, Desc.Title + countText, textRect, style.Foreground); Render2D.PopClip(); } @@ -289,6 +295,7 @@ namespace FlaxEditor.Windows private readonly List _pendingEntries = new List(32); private readonly ToolStripButton _clearOnPlayButton; + private readonly ToolStripButton _collapseLogsButton; private readonly ToolStripButton _pauseOnErrorButton; private readonly ToolStripButton[] _groupButtons = new ToolStripButton[3]; @@ -316,6 +323,7 @@ namespace FlaxEditor.Windows }; toolstrip.AddButton("Clear", Clear).LinkTooltip("Clears all log entries"); _clearOnPlayButton = (ToolStripButton)toolstrip.AddButton("Clear on Play").SetAutoCheck(true).SetChecked(true).LinkTooltip("Clears all log entries on enter playmode"); + _collapseLogsButton = (ToolStripButton)toolstrip.AddButton("Collapse").SetAutoCheck(true).SetChecked(true).LinkTooltip("Collapses similar logs."); _pauseOnErrorButton = (ToolStripButton)toolstrip.AddButton("Pause on Error").SetAutoCheck(true).LinkTooltip("Performs auto pause on error"); toolstrip.AddSeparator(); _groupButtons[0] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Error32, () => UpdateLogTypeVisibility(LogGroup.Error, _groupButtons[0].Checked)).SetAutoCheck(true).SetChecked(true).LinkTooltip("Shows/hides error messages"); @@ -612,6 +620,30 @@ namespace FlaxEditor.Windows var top = _entriesPanel.Children.Count != 0 ? _entriesPanel.Children[_entriesPanel.Children.Count - 1].Bottom + spacing : margin.Top; for (int i = 0; i < _pendingEntries.Count; i++) { + if (_collapseLogsButton.Checked) + { + bool logExists = false; + foreach (var child in _entriesPanel.Children) + { + if (child is LogEntry entry) + { + var pendingEntry = _pendingEntries[i]; + if (string.Equals(entry.Desc.Title, pendingEntry.Desc.Title) && + string.Equals(entry.Desc.LocationFile, pendingEntry.Desc.LocationFile) && + entry.Desc.Level == pendingEntry.Desc.Level && + string.Equals(entry.Desc.Description, pendingEntry.Desc.Description) && + entry.Desc.LocationLine == pendingEntry.Desc.LocationLine) + { + entry.LogCount += 1; + newEntry = entry; + logExists = true; + break; + } + } + } + if (logExists) + continue; + } newEntry = _pendingEntries[i]; newEntry.Visible = _groupButtons[(int)newEntry.Group].Checked; anyVisible |= newEntry.Visible; From 6d48fce76320a46ecdc5239493ba6dc0ff649244 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 15 Jul 2023 14:01:56 +0200 Subject: [PATCH 73/85] Fix mouse cursor setting on macOS to properly handle screen scale --- Source/Engine/Platform/Mac/MacPlatform.cpp | 7 ++++--- Source/Engine/Platform/Mac/MacWindow.cpp | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Platform/Mac/MacPlatform.cpp b/Source/Engine/Platform/Mac/MacPlatform.cpp index 04f928bba..15b526f02 100644 --- a/Source/Engine/Platform/Mac/MacPlatform.cpp +++ b/Source/Engine/Platform/Mac/MacPlatform.cpp @@ -301,15 +301,16 @@ Float2 MacPlatform::GetMousePosition() CGEventRef event = CGEventCreate(nullptr); CGPoint cursor = CGEventGetLocation(event); CFRelease(event); - return Float2((float)cursor.x, (float)cursor.y); + return Float2((float)cursor.x, (float)cursor.y) * MacPlatform::ScreenScale; } void MacPlatform::SetMousePosition(const Float2& pos) { CGPoint cursor; - cursor.x = (CGFloat)pos.X; - cursor.y = (CGFloat)pos.Y; + cursor.x = (CGFloat)(pos.X / MacPlatform::ScreenScale); + cursor.y = (CGFloat)(pos.Y / MacPlatform::ScreenScale); CGWarpMouseCursorPosition(cursor); + CGAssociateMouseAndMouseCursorPosition(true); } Float2 MacPlatform::GetDesktopSize() diff --git a/Source/Engine/Platform/Mac/MacWindow.cpp b/Source/Engine/Platform/Mac/MacWindow.cpp index 90bb07279..c55f36c7c 100644 --- a/Source/Engine/Platform/Mac/MacWindow.cpp +++ b/Source/Engine/Platform/Mac/MacWindow.cpp @@ -643,7 +643,6 @@ MacWindow::MacWindow(const CreateWindowSettings& settings) // TODO: impl StartPosition for MacWindow // TODO: impl Fullscreen for MacWindow // TODO: impl ShowInTaskbar for MacWindow - // TODO: impl AllowInput for MacWindow // TODO: impl IsTopmost for MacWindow } From 6fc168bdf13b9c86c407635618e279de12964619 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 15 Jul 2023 14:42:54 +0200 Subject: [PATCH 74/85] Add macOS message box with buttons --- Source/Engine/Platform/Mac/MacPlatform.cpp | 80 +++++++++++++++++++--- 1 file changed, 69 insertions(+), 11 deletions(-) diff --git a/Source/Engine/Platform/Mac/MacPlatform.cpp b/Source/Engine/Platform/Mac/MacPlatform.cpp index 15b526f02..46b978e1d 100644 --- a/Source/Engine/Platform/Mac/MacPlatform.cpp +++ b/Source/Engine/Platform/Mac/MacPlatform.cpp @@ -56,36 +56,94 @@ DialogResult MessageBox::Show(Window* parent, const StringView& text, const Stri { if (CommandLine::Options.Headless) return DialogResult::None; - CFStringRef textRef = AppleUtils::ToString(text); - CFStringRef captionRef = AppleUtils::ToString(caption); - CFOptionFlags flags = 0; + NSAlert* alert = [[NSAlert alloc] init]; + ASSERT(alert); switch (buttons) { case MessageBoxButtons::AbortRetryIgnore: + [alert addButtonWithTitle:@"Abort"]; + [alert addButtonWithTitle:@"Retry"]; + [alert addButtonWithTitle:@"Ignore"]; + break; + case MessageBoxButtons::OK: + [alert addButtonWithTitle:@"OK"]; + break; case MessageBoxButtons::OKCancel: + [alert addButtonWithTitle:@"OK"]; + [alert addButtonWithTitle:@"Cancel"]; + break; case MessageBoxButtons::RetryCancel: + [alert addButtonWithTitle:@"Retry"]; + [alert addButtonWithTitle:@"Cancel"]; + break; case MessageBoxButtons::YesNo: + [alert addButtonWithTitle:@"Yes"]; + [alert addButtonWithTitle:@"No"]; + break; case MessageBoxButtons::YesNoCancel: - flags |= kCFUserNotificationCancelResponse; + [alert addButtonWithTitle:@"Yes"]; + [alert addButtonWithTitle:@"No"]; + [alert addButtonWithTitle:@"Cancel"]; break; } switch (icon) { case MessageBoxIcon::Information: - flags |= kCFUserNotificationNoteAlertLevel; + [alert setAlertStyle:NSAlertStyleCritical]; break; case MessageBoxIcon::Error: case MessageBoxIcon::Stop: - flags |= kCFUserNotificationStopAlertLevel; + [alert setAlertStyle:NSAlertStyleInformational]; break; case MessageBoxIcon::Warning: - flags |= kCFUserNotificationCautionAlertLevel; + [alert setAlertStyle:NSAlertStyleWarning]; break; } - SInt32 result = CFUserNotificationDisplayNotice(0, flags, nullptr, nullptr, nullptr, captionRef, textRef, nullptr); - CFRelease(captionRef); - CFRelease(textRef); - return DialogResult::OK; + [alert setMessageText:(NSString*)AppleUtils::ToString(caption)]; + [alert setInformativeText:(NSString*)AppleUtils::ToString(text)]; + NSInteger button = [alert runModal]; + DialogResult result = DialogResult::OK; + switch (buttons) + { + case MessageBoxButtons::AbortRetryIgnore: + if (button == NSAlertFirstButtonReturn) + result = DialogResult::Abort; + else if (button == NSAlertSecondButtonReturn) + result = DialogResult::Retry; + else + result = DialogResult::Ignore; + break; + case MessageBoxButtons::OK: + result = DialogResult::OK; + break; + case MessageBoxButtons::OKCancel: + if (button == NSAlertFirstButtonReturn) + result = DialogResult::OK; + else + result = DialogResult::Cancel; + break; + case MessageBoxButtons::RetryCancel: + if (button == NSAlertFirstButtonReturn) + result = DialogResult::Retry; + else + result = DialogResult::Cancel; + break; + case MessageBoxButtons::YesNo: + if (button == NSAlertFirstButtonReturn) + result = DialogResult::Yes; + else + result = DialogResult::No; + break; + case MessageBoxButtons::YesNoCancel: + if (button == NSAlertFirstButtonReturn) + result = DialogResult::Yes; + else if (button == NSAlertSecondButtonReturn) + result = DialogResult::No; + else + result = DialogResult::Cancel; + break; + } + return result; } Float2 AppleUtils::PosToCoca(const Float2& pos) From 6853aa6e812d607a2312c6aa67fa5995888397b9 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 15 Jul 2023 15:00:55 +0200 Subject: [PATCH 75/85] Add control/command/option keys handling on macOS --- Source/Engine/Platform/Mac/MacWindow.cpp | 29 ++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Platform/Mac/MacWindow.cpp b/Source/Engine/Platform/Mac/MacWindow.cpp index c55f36c7c..a52c11324 100644 --- a/Source/Engine/Platform/Mac/MacWindow.cpp +++ b/Source/Engine/Platform/Mac/MacWindow.cpp @@ -75,8 +75,8 @@ KeyboardKeys GetKey(NSEvent* event) case 0x33: return KeyboardKeys::Delete; //case 0x34: case 0x35: return KeyboardKeys::Escape; - //case 0x36: - //case 0x37: Command + case 0x36: return KeyboardKeys::Control; // Command (right) + case 0x37: return KeyboardKeys::Control; // Command (left) case 0x38: return KeyboardKeys::Shift; case 0x39: return KeyboardKeys::Capital; case 0x3A: return KeyboardKeys::Alt; @@ -411,6 +411,31 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r) Input::Keyboard->OnKeyUp(key); } +- (void)flagsChanged:(NSEvent*)event +{ + int32 modMask; + int32 keyCode = [event keyCode]; + if (keyCode == 0x36 || keyCode == 0x37) + modMask = NSEventModifierFlagCommand; + else if (keyCode == 0x38 || keyCode == 0x3c) + modMask = NSEventModifierFlagShift; + else if (keyCode == 0x3a || keyCode == 0x3d) + modMask = NSEventModifierFlagOption; + else if (keyCode == 0x3b || keyCode == 0x3e) + modMask = NSEventModifierFlagControl; + else + return; + KeyboardKeys key = GetKey(event); + if (key != KeyboardKeys::None) + { + int32 modifierFlags = [event modifierFlags]; + if ((modifierFlags & modMask) == modMask) + Input::Keyboard->OnKeyDown(key); + else + Input::Keyboard->OnKeyUp(key); + } +} + - (void)scrollWheel:(NSEvent*)event { Float2 mousePos = GetMousePosition(Window, event); From 011162744c7f4769f03ccebc77e143b0ca5c8070 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 15 Jul 2023 15:07:52 +0200 Subject: [PATCH 76/85] Fix various keyboard handling on macOS --- Source/Engine/Platform/Mac/MacWindow.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Engine/Platform/Mac/MacWindow.cpp b/Source/Engine/Platform/Mac/MacWindow.cpp index a52c11324..aeee93e37 100644 --- a/Source/Engine/Platform/Mac/MacWindow.cpp +++ b/Source/Engine/Platform/Mac/MacWindow.cpp @@ -72,7 +72,7 @@ KeyboardKeys GetKey(NSEvent* event) case 0x30: return KeyboardKeys::Tab; case 0x31: return KeyboardKeys::Spacebar; case 0x32: return KeyboardKeys::BackQuote; - case 0x33: return KeyboardKeys::Delete; + case 0x33: return KeyboardKeys::Backspace; //case 0x34: case 0x35: return KeyboardKeys::Escape; case 0x36: return KeyboardKeys::Control; // Command (right) @@ -378,7 +378,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r) { KeyboardKeys key = GetKey(event); if (key != KeyboardKeys::None) - Input::Keyboard->OnKeyDown(key); + Input::Keyboard->OnKeyDown(key, Window); // Send a text input event switch (key) @@ -400,7 +400,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r) if (length >= 16) length = 15; [text getCharacters:buffer range:NSMakeRange(0, length)]; - Input::Keyboard->OnCharInput((Char)buffer[0]); + Input::Keyboard->OnCharInput((Char)buffer[0], Window); } } @@ -408,7 +408,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r) { KeyboardKeys key = GetKey(event); if (key != KeyboardKeys::None) - Input::Keyboard->OnKeyUp(key); + Input::Keyboard->OnKeyUp(key, Window); } - (void)flagsChanged:(NSEvent*)event @@ -430,9 +430,9 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r) { int32 modifierFlags = [event modifierFlags]; if ((modifierFlags & modMask) == modMask) - Input::Keyboard->OnKeyDown(key); + Input::Keyboard->OnKeyDown(key, Window); else - Input::Keyboard->OnKeyUp(key); + Input::Keyboard->OnKeyUp(key, Window); } } From 44518e88d567f3e3ea590d029c5ca6392fc6cb65 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 18 Jul 2023 09:48:43 +0200 Subject: [PATCH 77/85] Fix crash when using Vector3 soft casting in Visual Scripts --- Source/Engine/Core/Types/Variant.cpp | 117 +++++++++++++++++++++++++ Source/Engine/Core/Types/Variant.h | 3 + Source/Engine/Scripting/Scripting.cpp | 18 +++- Source/Engine/Visject/VisjectGraph.cpp | 4 + Source/Engine/Visject/VisjectGraph.h | 1 + 5 files changed, 142 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Core/Types/Variant.cpp b/Source/Engine/Core/Types/Variant.cpp index 8232d415f..973e494f1 100644 --- a/Source/Engine/Core/Types/Variant.cpp +++ b/Source/Engine/Core/Types/Variant.cpp @@ -2796,6 +2796,122 @@ String Variant::ToString() const } } +void Variant::Inline() +{ + VariantType::Types type = VariantType::Null; + byte data[sizeof(Matrix)]; + if (Type.Type == VariantType::Structure && AsBlob.Data && AsBlob.Length <= sizeof(Matrix)) + { + for (int32 i = 2; i < VariantType::MAX; i++) + { + if (StringUtils::Compare(Type.TypeName, InBuiltTypesTypeNames[i]) == 0) + { + type = (VariantType::Types)i; + break; + } + } + if (type == VariantType::Null) + { + // Aliases + if (StringUtils::Compare(Type.TypeName, "FlaxEngine.Vector2") == 0) + type = VariantType::Types::Vector2; + else if (StringUtils::Compare(Type.TypeName, "FlaxEngine.Vector3") == 0) + type = VariantType::Types::Vector3; + else if (StringUtils::Compare(Type.TypeName, "FlaxEngine.Vector4") == 0) + type = VariantType::Types::Vector4; + } + if (type != VariantType::Null) + Platform::MemoryCopy(data, AsBlob.Data, AsBlob.Length); + } + if (type != VariantType::Null) + { + switch (type) + { + case VariantType::Bool: + *this = *(bool*)data; + break; + case VariantType::Int: + *this = *(int32*)data; + break; + case VariantType::Uint: + *this = *(uint32*)data; + break; + case VariantType::Int64: + *this = *(int64*)data; + break; + case VariantType::Uint64: + *this = *(uint64*)data; + break; + case VariantType::Float: + *this = *(float*)data; + break; + case VariantType::Double: + *this = *(double*)data; + break; + case VariantType::Float2: + *this = *(Float2*)data; + break; + case VariantType::Float3: + *this = *(Float3*)data; + break; + case VariantType::Float4: + *this = *(Float4*)data; + break; + case VariantType::Color: + *this = *(Color*)data; + break; + case VariantType::Guid: + *this = *(Guid*)data; + break; + case VariantType::BoundingBox: + *this = Variant(*(BoundingBox*)data); + break; + case VariantType::BoundingSphere: + *this = *(BoundingSphere*)data; + break; + case VariantType::Quaternion: + *this = *(Quaternion*)data; + break; + case VariantType::Transform: + *this = Variant(*(Transform*)data); + break; + case VariantType::Rectangle: + *this = *(Rectangle*)data; + break; + case VariantType::Ray: + *this = Variant(*(Ray*)data); + break; + case VariantType::Matrix: + *this = Variant(*(Matrix*)data); + break; + case VariantType::Int2: + *this = *(Int2*)data; + break; + case VariantType::Int3: + *this = *(Int3*)data; + break; + case VariantType::Int4: + *this = *(Int4*)data; + break; + case VariantType::Int16: + *this = *(int16*)data; + break; + case VariantType::Uint16: + *this = *(uint16*)data; + break; + case VariantType::Double2: + *this = *(Double2*)data; + break; + case VariantType::Double3: + *this = *(Double3*)data; + break; + case VariantType::Double4: + *this = *(Double4*)data; + break; + } + } +} + bool Variant::CanCast(const Variant& v, const VariantType& to) { if (v.Type == to) @@ -3682,6 +3798,7 @@ void Variant::AllocStructure() const ScriptingType& type = typeHandle.GetType(); AsBlob.Length = type.Size; AsBlob.Data = Allocator::Allocate(AsBlob.Length); + Platform::MemoryClear(AsBlob.Data, AsBlob.Length); type.Struct.Ctor(AsBlob.Data); } else if (typeName == "System.Int16" || typeName == "System.UInt16") diff --git a/Source/Engine/Core/Types/Variant.h b/Source/Engine/Core/Types/Variant.h index 7745307c3..9776c8e0b 100644 --- a/Source/Engine/Core/Types/Variant.h +++ b/Source/Engine/Core/Types/Variant.h @@ -359,6 +359,9 @@ public: void SetAsset(Asset* asset); String ToString() const; + // Inlines potential value type into in-built format (eg. Vector3 stored as Structure, or String stored as ManagedObject). + void Inline(); + FORCE_INLINE Variant Cast(const VariantType& to) const { return Cast(*this, to); diff --git a/Source/Engine/Scripting/Scripting.cpp b/Source/Engine/Scripting/Scripting.cpp index e2d709653..bbfa802f1 100644 --- a/Source/Engine/Scripting/Scripting.cpp +++ b/Source/Engine/Scripting/Scripting.cpp @@ -476,12 +476,28 @@ bool Scripting::Load() // Load FlaxEngine const String flaxEnginePath = Globals::BinariesFolder / TEXT("FlaxEngine.CSharp.dll"); - if (((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->Load(flaxEnginePath)) + auto* flaxEngineModule = (NativeBinaryModule*)GetBinaryModuleFlaxEngine(); + if (flaxEngineModule->Assembly->Load(flaxEnginePath)) { LOG(Error, "Failed to load FlaxEngine C# assembly."); return true; } + // Insert type aliases for vector types that don't exist in C++ but are just typedef (properly redirect them to actual types) + // TODO: add support for automatic typedef aliases setup for scripting module to properly lookup type from the alias typename +#if USE_LARGE_WORLDS + flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector2"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Double2"]; + flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector3"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Double3"]; + flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector4"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Double4"]; +#else + flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector2"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Float2"]; + flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector3"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Float3"]; + flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector4"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Float4"]; +#endif + flaxEngineModule->ClassToTypeIndex[flaxEngineModule->Assembly->GetClass("FlaxEngine.Vector2")] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector2"]; + flaxEngineModule->ClassToTypeIndex[flaxEngineModule->Assembly->GetClass("FlaxEngine.Vector3")] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector3"]; + flaxEngineModule->ClassToTypeIndex[flaxEngineModule->Assembly->GetClass("FlaxEngine.Vector4")] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector4"]; + #if USE_EDITOR // Skip loading game modules in Editor on startup - Editor loads them later during splash screen (eg. after first compilation) static bool SkipFirstLoad = true; diff --git a/Source/Engine/Visject/VisjectGraph.cpp b/Source/Engine/Visject/VisjectGraph.cpp index 37154e09f..ca4495f67 100644 --- a/Source/Engine/Visject/VisjectGraph.cpp +++ b/Source/Engine/Visject/VisjectGraph.cpp @@ -675,6 +675,10 @@ void VisjectExecutor::ProcessGroupPacking(Box* box, Node* node, Value& value) } } } + + // For in-built structures try to convert it into internal format for better comparability with the scripting + value.Inline(); + break; } // Unpack Structure diff --git a/Source/Engine/Visject/VisjectGraph.h b/Source/Engine/Visject/VisjectGraph.h index 238823afd..0d841f3d4 100644 --- a/Source/Engine/Visject/VisjectGraph.h +++ b/Source/Engine/Visject/VisjectGraph.h @@ -246,6 +246,7 @@ public: void ProcessGroupCollections(Box* box, Node* node, Value& value); protected: + void InlineVariantStruct(Variant& v); virtual Value eatBox(Node* caller, Box* box) = 0; virtual Graph* GetCurrentGraph() const = 0; From 488958ce44b2d7cff21b7edaa9ddbb0e3dd7d3da Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 18 Jul 2023 10:16:11 +0200 Subject: [PATCH 78/85] Fix `DrawSceneDepth` to properly draw scene objects when custom actors list is empty #1253 --- Source/Editor/Gizmo/SelectionOutline.cs | 2 ++ Source/Engine/Renderer/Renderer.cs | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Source/Editor/Gizmo/SelectionOutline.cs b/Source/Editor/Gizmo/SelectionOutline.cs index ccc4bdd27..1374c7247 100644 --- a/Source/Editor/Gizmo/SelectionOutline.cs +++ b/Source/Editor/Gizmo/SelectionOutline.cs @@ -178,6 +178,8 @@ namespace FlaxEditor.Gizmo if (selection[i] is ActorNode actorNode && actorNode.Actor != null) CollectActors(actorNode.Actor); } + if (_actors.Count == 0) + return; // Render selected objects depth Renderer.DrawSceneDepth(context, task, customDepth, _actors); diff --git a/Source/Engine/Renderer/Renderer.cs b/Source/Engine/Renderer/Renderer.cs index bfb81a84c..71dca424b 100644 --- a/Source/Engine/Renderer/Renderer.cs +++ b/Source/Engine/Renderer/Renderer.cs @@ -17,10 +17,13 @@ namespace FlaxEngine [Unmanaged] public static void DrawSceneDepth(GPUContext context, SceneRenderTask task, GPUTexture output, List customActors) { - if (customActors.Count == 0) - return; - var temp = CollectionsMarshal.AsSpan(customActors).ToArray(); // FIXME - var tempCount = temp.Length; + Actor[] temp = null; + int tempCount = 0; + if (customActors != null && customActors.Count != 0) + { + temp = CollectionsMarshal.AsSpan(customActors).ToArray(); // FIXME + tempCount = temp.Length; + } Internal_DrawSceneDepth(FlaxEngine.Object.GetUnmanagedPtr(context), FlaxEngine.Object.GetUnmanagedPtr(task), FlaxEngine.Object.GetUnmanagedPtr(output), temp, ref tempCount); } @@ -32,7 +35,14 @@ namespace FlaxEngine [Unmanaged] public static void DrawActors(ref RenderContext renderContext, List customActors) { - DrawActors(ref renderContext, Utils.ExtractArrayFromList(customActors)); + Actor[] temp = null; + int tempCount = 0; + if (customActors != null && customActors.Count != 0) + { + temp = CollectionsMarshal.AsSpan(customActors).ToArray(); // FIXME + tempCount = temp.Length; + } + Internal_DrawActors(ref renderContext, temp, ref tempCount); } } } From 0f613abfb96a7dcc3e29422eb06ed0dd94dd7031 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 18 Jul 2023 10:54:21 +0200 Subject: [PATCH 79/85] Add `ToSpan` from 24c03c0e4b8bbbf4fb640d7b53b84bc2eaebcd57 --- Source/Engine/Core/Types/Span.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Engine/Core/Types/Span.h b/Source/Engine/Core/Types/Span.h index e7bea5fbd..e0518ec77 100644 --- a/Source/Engine/Core/Types/Span.h +++ b/Source/Engine/Core/Types/Span.h @@ -115,6 +115,12 @@ inline Span ToSpan(const T* ptr, int32 length) return Span(ptr, length); } +template +inline Span ToSpan(const Array& data) +{ + return Span((U*)data.Get(), data.Count()); +} + template inline bool SpanContains(const Span span, const T& value) { From 338499536fe4e3836568969e5493e88d92f4f732 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 18 Jul 2023 10:55:00 +0200 Subject: [PATCH 80/85] Add `ModelInstanceActor::GetMaterialSlots` --- Source/Engine/Content/Assets/MaterialBase.h | 1 - Source/Engine/Level/Actors/AnimatedModel.cpp | 8 ++++++++ Source/Engine/Level/Actors/AnimatedModel.h | 1 + Source/Engine/Level/Actors/ModelInstanceActor.h | 5 +++++ Source/Engine/Level/Actors/SplineModel.cpp | 8 ++++++++ Source/Engine/Level/Actors/SplineModel.h | 1 + Source/Engine/Level/Actors/StaticModel.cpp | 8 ++++++++ Source/Engine/Level/Actors/StaticModel.h | 1 + 8 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Content/Assets/MaterialBase.h b/Source/Engine/Content/Assets/MaterialBase.h index bca70b6da..070347348 100644 --- a/Source/Engine/Content/Assets/MaterialBase.h +++ b/Source/Engine/Content/Assets/MaterialBase.h @@ -27,7 +27,6 @@ public: /// /// Returns true if material is an material instance. /// - /// True if it's a material instance, otherwise false. virtual bool IsMaterialInstance() const = 0; public: diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index 373278885..dff527924 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -898,6 +898,14 @@ void AnimatedModel::Deserialize(DeserializeStream& stream, ISerializeModifier* m DrawModes |= DrawPass::GlobalSurfaceAtlas; } +const Span AnimatedModel::GetMaterialSlots() const +{ + const auto model = SkinnedModel.Get(); + if (model && !model->WaitForLoaded()) + return ToSpan(model->MaterialSlots); + return Span(); +} + MaterialBase* AnimatedModel::GetMaterial(int32 entryIndex) { if (SkinnedModel) diff --git a/Source/Engine/Level/Actors/AnimatedModel.h b/Source/Engine/Level/Actors/AnimatedModel.h index 2693f573d..763629e93 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.h +++ b/Source/Engine/Level/Actors/AnimatedModel.h @@ -373,6 +373,7 @@ public: bool IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) override; void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; + const Span GetMaterialSlots() const override; MaterialBase* GetMaterial(int32 entryIndex) override; bool IntersectsEntry(int32 entryIndex, const Ray& ray, Real& distance, Vector3& normal) override; bool IntersectsEntry(const Ray& ray, Real& distance, Vector3& normal, int32& entryIndex) override; diff --git a/Source/Engine/Level/Actors/ModelInstanceActor.h b/Source/Engine/Level/Actors/ModelInstanceActor.h index 1dfd5c0e0..3faad35b3 100644 --- a/Source/Engine/Level/Actors/ModelInstanceActor.h +++ b/Source/Engine/Level/Actors/ModelInstanceActor.h @@ -35,6 +35,11 @@ public: /// API_PROPERTY() void SetEntries(const Array& value); + /// + /// Gets the material slots array set on the asset (eg. model or skinned model asset). + /// + API_PROPERTY(Sealed) virtual const Span GetMaterialSlots() const = 0; + /// /// Gets the material used to draw the meshes which are assigned to that slot (set in Entries or model's default). /// diff --git a/Source/Engine/Level/Actors/SplineModel.cpp b/Source/Engine/Level/Actors/SplineModel.cpp index 843bf6076..6ca841b41 100644 --- a/Source/Engine/Level/Actors/SplineModel.cpp +++ b/Source/Engine/Level/Actors/SplineModel.cpp @@ -341,6 +341,14 @@ void SplineModel::OnParentChanged() OnSplineUpdated(); } +const Span SplineModel::GetMaterialSlots() const +{ + const auto model = Model.Get(); + if (model && !model->WaitForLoaded()) + return ToSpan(model->MaterialSlots); + return Span(); +} + MaterialBase* SplineModel::GetMaterial(int32 entryIndex) { if (Model) diff --git a/Source/Engine/Level/Actors/SplineModel.h b/Source/Engine/Level/Actors/SplineModel.h index 87f39699c..2a3d45a27 100644 --- a/Source/Engine/Level/Actors/SplineModel.h +++ b/Source/Engine/Level/Actors/SplineModel.h @@ -115,6 +115,7 @@ public: void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; void OnParentChanged() override; + const Span GetMaterialSlots() const override; MaterialBase* GetMaterial(int32 entryIndex) override; protected: diff --git a/Source/Engine/Level/Actors/StaticModel.cpp b/Source/Engine/Level/Actors/StaticModel.cpp index 778f24d65..93eef3056 100644 --- a/Source/Engine/Level/Actors/StaticModel.cpp +++ b/Source/Engine/Level/Actors/StaticModel.cpp @@ -535,6 +535,14 @@ void StaticModel::Deserialize(DeserializeStream& stream, ISerializeModifier* mod } } +const Span StaticModel::GetMaterialSlots() const +{ + const auto model = Model.Get(); + if (model && !model->WaitForLoaded()) + return ToSpan(model->MaterialSlots); + return Span(); +} + MaterialBase* StaticModel::GetMaterial(int32 entryIndex) { if (Model) diff --git a/Source/Engine/Level/Actors/StaticModel.h b/Source/Engine/Level/Actors/StaticModel.h index 06fbdd874..600f174c9 100644 --- a/Source/Engine/Level/Actors/StaticModel.h +++ b/Source/Engine/Level/Actors/StaticModel.h @@ -166,6 +166,7 @@ public: bool IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) override; void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; + const Span GetMaterialSlots() const override; MaterialBase* GetMaterial(int32 entryIndex) override; bool IntersectsEntry(int32 entryIndex, const Ray& ray, Real& distance, Vector3& normal) override; bool IntersectsEntry(const Ray& ray, Real& distance, Vector3& normal, int32& entryIndex) override; From 8f8c0e4b819cc70de89ad20a6f04977995a2d765 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 18 Jul 2023 10:55:15 +0200 Subject: [PATCH 81/85] Minor fixes for #1247 --- .../CustomEditors/Editors/AssetRefEditor.cs | 1 + .../Editors/ModelInstanceEntryEditor.cs | 111 ++++++------------ 2 files changed, 36 insertions(+), 76 deletions(-) diff --git a/Source/Editor/CustomEditors/Editors/AssetRefEditor.cs b/Source/Editor/CustomEditors/Editors/AssetRefEditor.cs index b83b44d59..88f916ae4 100644 --- a/Source/Editor/CustomEditors/Editors/AssetRefEditor.cs +++ b/Source/Editor/CustomEditors/Editors/AssetRefEditor.cs @@ -37,6 +37,7 @@ namespace FlaxEditor.CustomEditors.Editors /// The asset picker used to get a reference to an asset. /// public AssetPicker Picker; + private ScriptType _valueType; /// diff --git a/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs b/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs index b7989cae3..1f04115de 100644 --- a/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs @@ -16,7 +16,6 @@ namespace FlaxEditor.CustomEditors.Editors private GroupElement _group; private bool _updateName; private MaterialBase _material; - private ModelInstanceEntry _entry; /// public override void Initialize(LayoutElementsContainer layout) @@ -24,82 +23,59 @@ namespace FlaxEditor.CustomEditors.Editors _updateName = true; var group = layout.Group("Entry"); _group = group; - - _entry = (ModelInstanceEntry)Values[0]; + + if (ParentEditor == null) + return; + var entry = (ModelInstanceEntry)Values[0]; var entryIndex = ParentEditor.ChildrenEditors.IndexOf(this); - var materiaLabel = new PropertyNameLabel("Material"); - materiaLabel.TooltipText = "The mesh surface material used for the rendering."; - if (ParentEditor.ParentEditor.Values[0] is StaticModel staticModel) + var materialLabel = new PropertyNameLabel("Material"); + materialLabel.TooltipText = "The mesh surface material used for the rendering."; + if (ParentEditor.ParentEditor?.Values[0] is ModelInstanceActor modelInstance) { // Ensure that entry with default material set is set back to null - if (_entry.Material == staticModel.Model.MaterialSlots[entryIndex].Material) + var defaultValue = GPUDevice.Instance.DefaultMaterial; { - staticModel.SetMaterial(entryIndex, null); + var slots = modelInstance.MaterialSlots; + if (entry.Material == slots[entryIndex].Material) + { + modelInstance.SetMaterial(entryIndex, null); + } + _material = modelInstance.GetMaterial(entryIndex); + if (slots[entryIndex].Material) + { + defaultValue = slots[entryIndex].Material; + } } - _material = staticModel.GetMaterial(entryIndex); var matContainer = new CustomValueContainer(new ScriptType(typeof(MaterialBase)), _material, (instance, index) => _material, (instance, index, value) => _material = value as MaterialBase); - var materialEditor = (_group.Property(materiaLabel, matContainer)) as AssetRefEditor; - materialEditor.Values.SetDefaultValue((staticModel.Model.MaterialSlots[entryIndex].Material) ? staticModel.Model.MaterialSlots[entryIndex].Material : GPUDevice.Instance.DefaultMaterial); + var materialEditor = (AssetRefEditor)_group.Property(materialLabel, matContainer); + materialEditor.Values.SetDefaultValue(defaultValue); materialEditor.RefreshDefaultValue(); materialEditor.Picker.SelectedItemChanged += () => { + var slots = modelInstance.MaterialSlots; var material = materialEditor.Picker.SelectedAsset as MaterialBase; + var defaultMaterial = GPUDevice.Instance.DefaultMaterial; if (!material) { - staticModel.SetMaterial(entryIndex, GPUDevice.Instance.DefaultMaterial); - materialEditor.Picker.SelectedAsset = GPUDevice.Instance.DefaultMaterial; + modelInstance.SetMaterial(entryIndex, defaultMaterial); + materialEditor.Picker.SelectedAsset = defaultMaterial; } - else if (material == staticModel.Model.MaterialSlots[entryIndex].Material) + else if (material == slots[entryIndex].Material) { - staticModel.SetMaterial(entryIndex, null); + modelInstance.SetMaterial(entryIndex, null); } - else if (material == GPUDevice.Instance.DefaultMaterial && !staticModel.Model.MaterialSlots[entryIndex].Material) + else if (material == defaultMaterial && !slots[entryIndex].Material) { - staticModel.SetMaterial(entryIndex, null); + modelInstance.SetMaterial(entryIndex, null); } else { - staticModel.SetMaterial(entryIndex, material); + modelInstance.SetMaterial(entryIndex, material); } }; } - else if (ParentEditor.ParentEditor.Values[0] is AnimatedModel animatedModel) - { - // Ensure that entry with default material set is set back to null - if (_entry.Material == animatedModel.SkinnedModel.MaterialSlots[entryIndex].Material) - { - animatedModel.SetMaterial(entryIndex, null); - } - _material = animatedModel.GetMaterial(entryIndex); - - var matContainer = new CustomValueContainer(new ScriptType(typeof(MaterialBase)), _material, (instance, index) => _material, (instance, index, value) => _material = value as MaterialBase); - var materialEditor = (_group.Property(materiaLabel, matContainer)) as AssetRefEditor; - materialEditor.Values.SetDefaultValue((animatedModel.SkinnedModel.MaterialSlots[entryIndex].Material) ? animatedModel.SkinnedModel.MaterialSlots[entryIndex].Material : GPUDevice.Instance.DefaultMaterial); - materialEditor.RefreshDefaultValue(); - materialEditor.Picker.SelectedItemChanged += () => - { - var material = materialEditor.Picker.SelectedAsset as MaterialBase; - if (!material) - { - animatedModel.SetMaterial(entryIndex, GPUDevice.Instance.DefaultMaterial); - materialEditor.Picker.SelectedAsset = GPUDevice.Instance.DefaultMaterial; - } - else if (material == animatedModel.SkinnedModel.MaterialSlots[entryIndex].Material) - { - animatedModel.SetMaterial(entryIndex, null); - } - else if (material == GPUDevice.Instance.DefaultMaterial && !animatedModel.SkinnedModel.MaterialSlots[entryIndex].Material) - { - animatedModel.SetMaterial(entryIndex, null); - } - else - { - animatedModel.SetMaterial(entryIndex, material); - } - }; - } - + base.Initialize(group); } @@ -121,30 +97,13 @@ namespace FlaxEditor.CustomEditors.Editors ParentEditor.ParentEditor.Values.Count > 0) { var entryIndex = ParentEditor.ChildrenEditors.IndexOf(this); - if (ParentEditor.ParentEditor.Values[0] is StaticModel staticModel) + if (ParentEditor.ParentEditor.Values[0] is ModelInstanceActor modelInstance) { - var model = staticModel.Model; - if (model && model.IsLoaded) + var slots = modelInstance.MaterialSlots; + if (slots != null && slots.Length > entryIndex) { - var slots = model.MaterialSlots; - if (slots != null && slots.Length > entryIndex) - { - _group.Panel.HeaderText = "Entry " + slots[entryIndex].Name; - _updateName = false; - } - } - } - else if (ParentEditor.ParentEditor.Values[0] is AnimatedModel animatedModel) - { - var model = animatedModel.SkinnedModel; - if (model && model.IsLoaded) - { - var slots = model.MaterialSlots; - if (slots != null && slots.Length > entryIndex) - { - _group.Panel.HeaderText = "Entry " + slots[entryIndex].Name; - _updateName = false; - } + _group.Panel.HeaderText = "Entry " + slots[entryIndex].Name; + _updateName = false; } } } From 60c0995bc36a14f7d30f79ebc118f1a93e555122 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 18 Jul 2023 11:46:15 +0200 Subject: [PATCH 82/85] Add undo for #1247 --- .../CustomEditors/Editors/AssetRefEditor.cs | 5 + .../Editors/ModelInstanceEntryEditor.cs | 113 ++++++++++++------ 2 files changed, 79 insertions(+), 39 deletions(-) diff --git a/Source/Editor/CustomEditors/Editors/AssetRefEditor.cs b/Source/Editor/CustomEditors/Editors/AssetRefEditor.cs index 88f916ae4..e89c80372 100644 --- a/Source/Editor/CustomEditors/Editors/AssetRefEditor.cs +++ b/Source/Editor/CustomEditors/Editors/AssetRefEditor.cs @@ -38,6 +38,7 @@ namespace FlaxEditor.CustomEditors.Editors /// public AssetPicker Picker; + private bool _isRefreshing; private ScriptType _valueType; /// @@ -89,6 +90,8 @@ namespace FlaxEditor.CustomEditors.Editors private void OnSelectedItemChanged() { + if (_isRefreshing) + return; if (typeof(AssetItem).IsAssignableFrom(_valueType.Type)) SetValue(Picker.SelectedItem); else if (_valueType.Type == typeof(Guid)) @@ -108,6 +111,7 @@ namespace FlaxEditor.CustomEditors.Editors if (!HasDifferentValues) { + _isRefreshing = true; if (Values[0] is AssetItem assetItem) Picker.SelectedItem = assetItem; else if (Values[0] is Guid guid) @@ -118,6 +122,7 @@ namespace FlaxEditor.CustomEditors.Editors Picker.SelectedPath = path; else Picker.SelectedAsset = Values[0] as Asset; + _isRefreshing = false; } } } diff --git a/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs b/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs index 1f04115de..277f9ecb0 100644 --- a/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ModelInstanceEntryEditor.cs @@ -15,7 +15,11 @@ namespace FlaxEditor.CustomEditors.Editors { private GroupElement _group; private bool _updateName; + private int _entryIndex; + private bool _isRefreshing; private MaterialBase _material; + private ModelInstanceActor _modelInstance; + private AssetRefEditor _materialEditor; /// public override void Initialize(LayoutElementsContainer layout) @@ -32,58 +36,75 @@ namespace FlaxEditor.CustomEditors.Editors materialLabel.TooltipText = "The mesh surface material used for the rendering."; if (ParentEditor.ParentEditor?.Values[0] is ModelInstanceActor modelInstance) { - // Ensure that entry with default material set is set back to null - var defaultValue = GPUDevice.Instance.DefaultMaterial; + _entryIndex = entryIndex; + _modelInstance = modelInstance; + var slots = modelInstance.MaterialSlots; + if (entry.Material == slots[entryIndex].Material) { - var slots = modelInstance.MaterialSlots; - if (entry.Material == slots[entryIndex].Material) - { - modelInstance.SetMaterial(entryIndex, null); - } - _material = modelInstance.GetMaterial(entryIndex); - if (slots[entryIndex].Material) - { - defaultValue = slots[entryIndex].Material; - } + // Ensure that entry with default material set is set back to null + modelInstance.SetMaterial(entryIndex, null); + } + _material = modelInstance.GetMaterial(entryIndex); + var defaultValue = GPUDevice.Instance.DefaultMaterial; + if (slots[entryIndex].Material) + { + // Use default value set on asset (eg. Model Asset) + defaultValue = slots[entryIndex].Material; } - var matContainer = new CustomValueContainer(new ScriptType(typeof(MaterialBase)), _material, (instance, index) => _material, (instance, index, value) => _material = value as MaterialBase); - var materialEditor = (AssetRefEditor)_group.Property(materialLabel, matContainer); + // Create material picker + var materialValue = new CustomValueContainer(new ScriptType(typeof(MaterialBase)), _material, (instance, index) => _material, (instance, index, value) => _material = value as MaterialBase); + var materialEditor = (AssetRefEditor)_group.Property(materialLabel, materialValue); materialEditor.Values.SetDefaultValue(defaultValue); materialEditor.RefreshDefaultValue(); - materialEditor.Picker.SelectedItemChanged += () => - { - var slots = modelInstance.MaterialSlots; - var material = materialEditor.Picker.SelectedAsset as MaterialBase; - var defaultMaterial = GPUDevice.Instance.DefaultMaterial; - if (!material) - { - modelInstance.SetMaterial(entryIndex, defaultMaterial); - materialEditor.Picker.SelectedAsset = defaultMaterial; - } - else if (material == slots[entryIndex].Material) - { - modelInstance.SetMaterial(entryIndex, null); - } - else if (material == defaultMaterial && !slots[entryIndex].Material) - { - modelInstance.SetMaterial(entryIndex, null); - } - else - { - modelInstance.SetMaterial(entryIndex, material); - } - }; + materialEditor.Picker.SelectedItemChanged += OnSelectedMaterialChanged; + _materialEditor = materialEditor; } base.Initialize(group); } + private void OnSelectedMaterialChanged() + { + if (_isRefreshing) + return; + _isRefreshing = true; + var slots = _modelInstance.MaterialSlots; + var material = _materialEditor.Picker.SelectedAsset as MaterialBase; + var defaultMaterial = GPUDevice.Instance.DefaultMaterial; + var value = (ModelInstanceEntry)Values[0]; + var prevMaterial = value.Material; + if (!material) + { + // Fallback to default material + _materialEditor.Picker.SelectedAsset = defaultMaterial; + value.Material = defaultMaterial; + } + else if (material == slots[_entryIndex].Material) + { + // Asset default material + value.Material = null; + } + else if (material == defaultMaterial && !slots[_entryIndex].Material) + { + // Default material while asset has no set as well + value.Material = null; + } + else + { + // Custom material + value.Material = material; + } + if (prevMaterial != value.Material) + SetValue(value); + _isRefreshing = false; + } + /// protected override void SpawnProperty(LayoutElementsContainer itemLayout, ValueContainer itemValues, ItemInfo item) { // Skip material member as it is overridden - if (item.Info.Name == "Material") + if (item.Info.Name == "Material" && _materialEditor != null) return; base.SpawnProperty(itemLayout, itemValues, item); } @@ -91,6 +112,7 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Refresh() { + // Update panel title to match material slot name if (_updateName && _group != null && ParentEditor?.ParentEditor != null && @@ -102,13 +124,26 @@ namespace FlaxEditor.CustomEditors.Editors var slots = modelInstance.MaterialSlots; if (slots != null && slots.Length > entryIndex) { - _group.Panel.HeaderText = "Entry " + slots[entryIndex].Name; _updateName = false; + _group.Panel.HeaderText = "Entry " + slots[entryIndex].Name; } } } + // Refresh currently selected material + _material = _modelInstance.GetMaterial(_entryIndex); + base.Refresh(); } + + /// + protected override void Deinitialize() + { + _material = null; + _modelInstance = null; + _materialEditor = null; + + base.Deinitialize(); + } } } From be079b9b67f7c5c9b63ba8189ca4ccc8ce2e2ca4 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Tue, 18 Jul 2023 09:51:21 -0500 Subject: [PATCH 83/85] Improvements to debug log count. --- Source/Editor/Windows/DebugLogWindow.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Source/Editor/Windows/DebugLogWindow.cs b/Source/Editor/Windows/DebugLogWindow.cs index 81dcaae92..49b03ede1 100644 --- a/Source/Editor/Windows/DebugLogWindow.cs +++ b/Source/Editor/Windows/DebugLogWindow.cs @@ -138,12 +138,14 @@ namespace FlaxEditor.Windows // Title var textRect = new Rectangle(38, 2, clientRect.Width - 40, clientRect.Height - 10); Render2D.PushClip(ref clientRect); - string countText = string.Empty; - if (LogCount > 1) + if (LogCount == 1) { - countText = $" ({LogCount})"; + Render2D.DrawText(style.FontMedium, Desc.Title, textRect, style.Foreground); + } + else if (LogCount > 1) + { + Render2D.DrawText(style.FontMedium, $"{Desc.Title} ({LogCount})", textRect, style.Foreground); } - Render2D.DrawText(style.FontMedium, Desc.Title + countText, textRect, style.Foreground); Render2D.PopClip(); } @@ -628,10 +630,10 @@ namespace FlaxEditor.Windows if (child is LogEntry entry) { var pendingEntry = _pendingEntries[i]; - if (string.Equals(entry.Desc.Title, pendingEntry.Desc.Title) && - string.Equals(entry.Desc.LocationFile, pendingEntry.Desc.LocationFile) && + if (string.Equals(entry.Desc.Title, pendingEntry.Desc.Title, StringComparison.Ordinal) && + string.Equals(entry.Desc.LocationFile, pendingEntry.Desc.LocationFile, StringComparison.Ordinal) && entry.Desc.Level == pendingEntry.Desc.Level && - string.Equals(entry.Desc.Description, pendingEntry.Desc.Description) && + string.Equals(entry.Desc.Description, pendingEntry.Desc.Description, StringComparison.Ordinal) && entry.Desc.LocationLine == pendingEntry.Desc.LocationLine) { entry.LogCount += 1; From 872509df2a099b0cea4c1cd7c6d3f5827adbf6b2 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 18 Jul 2023 18:13:19 +0200 Subject: [PATCH 84/85] Fix incorrect `Transform Position To Screen UV` in particles graph in CPU code path --- .../Particles/Graph/CPU/ParticleEmitterGraph.CPU.Particles.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.Particles.cpp b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.Particles.cpp index 649d01d85..9ef996869 100644 --- a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.Particles.cpp +++ b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.Particles.cpp @@ -189,7 +189,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupTools(Box* box, Node* node, Va const Matrix viewProjection = context.ViewTask ? context.ViewTask->View.PrevViewProjection : Matrix::Identity; const Float3 position = (Float3)TryGetValue(node->GetBox(0), Value::Zero); Float4 projPos; - Float3::Transform(position, viewProjection); + Float3::Transform(position, viewProjection, projPos); projPos /= projPos.W; value = Float2(projPos.X * 0.5f + 0.5f, projPos.Y * 0.5f + 0.5f); break; From b2b10ce7da7f3ac47e8f5688bb2693e1a3d7a8c4 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 18 Jul 2023 18:20:11 +0200 Subject: [PATCH 85/85] Fix various core types to be trivially constructible as properly POD-type --- Source/Editor/Tools/Foliage/FoliageTools.cpp | 1 - Source/Engine/Core/Math/BoundingBox.h | 4 +--- Source/Engine/Core/Math/BoundingFrustum.h | 4 +--- Source/Engine/Core/Math/BoundingSphere.h | 4 +--- Source/Engine/Core/Math/Color.h | 4 +--- Source/Engine/Core/Math/Color32.h | 4 +--- Source/Engine/Core/Math/Half.h | 12 +++--------- Source/Engine/Core/Math/Matrix.h | 4 +--- Source/Engine/Core/Math/Matrix3x3.h | 4 +--- Source/Engine/Core/Math/Plane.h | 4 +--- Source/Engine/Core/Math/Quaternion.h | 4 +--- Source/Engine/Core/Math/Ray.h | 4 +--- Source/Engine/Core/Math/Rectangle.h | 4 +--- Source/Engine/Core/Math/Transform.h | 4 +--- Source/Engine/Core/Math/Triangle.h | 4 +--- Source/Engine/Core/Math/Vector2.h | 4 +--- Source/Engine/Core/Math/Vector3.h | 4 +--- Source/Engine/Core/Math/Vector4.h | 4 +--- Source/Engine/Core/Math/Viewport.h | 4 +--- 19 files changed, 20 insertions(+), 61 deletions(-) diff --git a/Source/Editor/Tools/Foliage/FoliageTools.cpp b/Source/Editor/Tools/Foliage/FoliageTools.cpp index b24bcdf00..7d0de7d41 100644 --- a/Source/Editor/Tools/Foliage/FoliageTools.cpp +++ b/Source/Editor/Tools/Foliage/FoliageTools.cpp @@ -292,7 +292,6 @@ void FoliageTools::Paint(Foliage* foliage, Span foliageTypesIndices, cons { PROFILE_CPU_NAMED("Place Instances"); - Matrix matrix; FoliageInstance instance; Quaternion tmp; Matrix world; diff --git a/Source/Engine/Core/Math/BoundingBox.h b/Source/Engine/Core/Math/BoundingBox.h index 0ee4fc1a9..d06ef0b3f 100644 --- a/Source/Engine/Core/Math/BoundingBox.h +++ b/Source/Engine/Core/Math/BoundingBox.h @@ -38,9 +38,7 @@ public: /// /// Empty constructor. /// - BoundingBox() - { - } + BoundingBox() = default; /// /// Initializes a new instance of the struct. diff --git a/Source/Engine/Core/Math/BoundingFrustum.h b/Source/Engine/Core/Math/BoundingFrustum.h index 287d33c2f..1502b6302 100644 --- a/Source/Engine/Core/Math/BoundingFrustum.h +++ b/Source/Engine/Core/Math/BoundingFrustum.h @@ -34,9 +34,7 @@ public: /// /// Empty constructor. /// - BoundingFrustum() - { - } + BoundingFrustum() = default; /// /// Initializes a new instance of the struct. diff --git a/Source/Engine/Core/Math/BoundingSphere.h b/Source/Engine/Core/Math/BoundingSphere.h index 08f5df7f1..da303e8d5 100644 --- a/Source/Engine/Core/Math/BoundingSphere.h +++ b/Source/Engine/Core/Math/BoundingSphere.h @@ -34,9 +34,7 @@ public: /// /// Empty constructor. /// - BoundingSphere() - { - } + BoundingSphere() = default; /// /// Initializes a new instance of the struct. diff --git a/Source/Engine/Core/Math/Color.h b/Source/Engine/Core/Math/Color.h index 997ed9c17..af93fc0f2 100644 --- a/Source/Engine/Core/Math/Color.h +++ b/Source/Engine/Core/Math/Color.h @@ -50,9 +50,7 @@ public: /// /// Empty constructor. /// - Color() - { - } + Color() = default; /// /// Initializes a new instance of the struct. diff --git a/Source/Engine/Core/Math/Color32.h b/Source/Engine/Core/Math/Color32.h index 36da3d41d..6c2b9648d 100644 --- a/Source/Engine/Core/Math/Color32.h +++ b/Source/Engine/Core/Math/Color32.h @@ -53,9 +53,7 @@ public: /// /// Empty constructor. /// - Color32() - { - } + Color32() = default; /// /// Constructs a new Color32 with given r, g, b, a components. diff --git a/Source/Engine/Core/Math/Half.h b/Source/Engine/Core/Math/Half.h index 06b03895d..346b5d6b3 100644 --- a/Source/Engine/Core/Math/Half.h +++ b/Source/Engine/Core/Math/Half.h @@ -121,9 +121,7 @@ public: /// /// Default constructor /// - Half2() - { - } + Half2() = default; /// /// Init @@ -185,9 +183,7 @@ public: Half Z; public: - Half3() - { - } + Half3() = default; Half3(Half x, Half y, Half z) : X(x) @@ -242,9 +238,7 @@ public: Half W; public: - Half4() - { - } + Half4() = default; Half4(Half x, Half y, Half z, Half w) : X(x) diff --git a/Source/Engine/Core/Math/Matrix.h b/Source/Engine/Core/Math/Matrix.h index 7d6d57bac..aed2ead8d 100644 --- a/Source/Engine/Core/Math/Matrix.h +++ b/Source/Engine/Core/Math/Matrix.h @@ -83,9 +83,7 @@ public: /// /// Empty constructor. /// - Matrix() - { - } + Matrix() = default; /// /// Initializes a new instance of the struct. diff --git a/Source/Engine/Core/Math/Matrix3x3.h b/Source/Engine/Core/Math/Matrix3x3.h index 1e29be85a..344f68455 100644 --- a/Source/Engine/Core/Math/Matrix3x3.h +++ b/Source/Engine/Core/Math/Matrix3x3.h @@ -63,9 +63,7 @@ public: /// /// Empty constructor. /// - Matrix3x3() - { - } + Matrix3x3() = default; /// /// Initializes a new instance of the struct. diff --git a/Source/Engine/Core/Math/Plane.h b/Source/Engine/Core/Math/Plane.h index 57a2be344..8c3d4129b 100644 --- a/Source/Engine/Core/Math/Plane.h +++ b/Source/Engine/Core/Math/Plane.h @@ -30,9 +30,7 @@ public: /// /// Empty constructor. /// - Plane() - { - } + Plane() = default; /// /// Init diff --git a/Source/Engine/Core/Math/Quaternion.h b/Source/Engine/Core/Math/Quaternion.h index 5b164f979..e6425f7ab 100644 --- a/Source/Engine/Core/Math/Quaternion.h +++ b/Source/Engine/Core/Math/Quaternion.h @@ -67,9 +67,7 @@ public: /// /// Empty constructor. /// - Quaternion() - { - } + Quaternion() = default; /// /// Init diff --git a/Source/Engine/Core/Math/Ray.h b/Source/Engine/Core/Math/Ray.h index c8486f39e..f2f9081e5 100644 --- a/Source/Engine/Core/Math/Ray.h +++ b/Source/Engine/Core/Math/Ray.h @@ -35,9 +35,7 @@ public: /// /// Empty constructor. /// - Ray() - { - } + Ray() = default; /// /// Initializes a new instance of the struct. diff --git a/Source/Engine/Core/Math/Rectangle.h b/Source/Engine/Core/Math/Rectangle.h index c59905fd6..bf282b6e3 100644 --- a/Source/Engine/Core/Math/Rectangle.h +++ b/Source/Engine/Core/Math/Rectangle.h @@ -31,9 +31,7 @@ public: /// /// Empty constructor. /// - Rectangle() - { - } + Rectangle() = default; // Init // @param x Rectangle location X coordinate diff --git a/Source/Engine/Core/Math/Transform.h b/Source/Engine/Core/Math/Transform.h index ef644f08a..1079b4c23 100644 --- a/Source/Engine/Core/Math/Transform.h +++ b/Source/Engine/Core/Math/Transform.h @@ -40,9 +40,7 @@ public: /// /// Empty constructor. /// - Transform() - { - } + Transform() = default; /// /// Initializes a new instance of the struct. diff --git a/Source/Engine/Core/Math/Triangle.h b/Source/Engine/Core/Math/Triangle.h index a92919cfc..63f0e34ec 100644 --- a/Source/Engine/Core/Math/Triangle.h +++ b/Source/Engine/Core/Math/Triangle.h @@ -30,9 +30,7 @@ public: /// /// Empty constructor. /// - Triangle() - { - } + Triangle() = default; /// /// Initializes a new instance of the struct. diff --git a/Source/Engine/Core/Math/Vector2.h b/Source/Engine/Core/Math/Vector2.h index 87ced1de6..83deb009a 100644 --- a/Source/Engine/Core/Math/Vector2.h +++ b/Source/Engine/Core/Math/Vector2.h @@ -60,9 +60,7 @@ public: /// /// Empty constructor. /// - Vector2Base() - { - } + Vector2Base() = default; FORCE_INLINE Vector2Base(T xy) : X(xy) diff --git a/Source/Engine/Core/Math/Vector3.h b/Source/Engine/Core/Math/Vector3.h index 33be7f2d6..cad5250b7 100644 --- a/Source/Engine/Core/Math/Vector3.h +++ b/Source/Engine/Core/Math/Vector3.h @@ -89,9 +89,7 @@ public: /// /// Empty constructor. /// - Vector3Base() - { - } + Vector3Base() = default; FORCE_INLINE Vector3Base(T xyz) : X(xyz) diff --git a/Source/Engine/Core/Math/Vector4.h b/Source/Engine/Core/Math/Vector4.h index 213f05815..5c7b24c4a 100644 --- a/Source/Engine/Core/Math/Vector4.h +++ b/Source/Engine/Core/Math/Vector4.h @@ -76,9 +76,7 @@ public: /// /// Empty constructor. /// - Vector4Base() - { - } + Vector4Base() = default; FORCE_INLINE Vector4Base(T xyzw) : X(xyzw) diff --git a/Source/Engine/Core/Math/Viewport.h b/Source/Engine/Core/Math/Viewport.h index bb4ec8f8b..d478eb7cc 100644 --- a/Source/Engine/Core/Math/Viewport.h +++ b/Source/Engine/Core/Math/Viewport.h @@ -52,9 +52,7 @@ public: /// /// Empty constructor. /// - Viewport() - { - } + Viewport() = default; // Init // @param x The x coordinate of the upper-left corner of the viewport in pixels