From e07ae33040fafadc1a1597fd95b645eb71d9513e Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Fri, 6 Oct 2023 15:23:43 +0200 Subject: [PATCH 01/34] - Added input box to animation sample node to receive animation assets - AssetSelect not gets shown or hidden depending on if the box has a connection - Animation asset reference box now overrides asset picker --- Source/Editor/Surface/Archetypes/Animation.cs | 22 ++++++++++++++++++- .../Animations/Graph/AnimGroup.Animation.cpp | 14 +++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/Animation.cs b/Source/Editor/Surface/Archetypes/Animation.cs index 6364106e4..2e362ae79 100644 --- a/Source/Editor/Surface/Archetypes/Animation.cs +++ b/Source/Editor/Surface/Archetypes/Animation.cs @@ -34,6 +34,9 @@ namespace FlaxEditor.Surface.Archetypes /// public class Sample : SurfaceNode { + private AssetSelect _assetSelect; + private Box _assetBox; + /// public Sample(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch) : base(id, context, nodeArch, groupArch) @@ -54,7 +57,12 @@ namespace FlaxEditor.Surface.Archetypes base.OnSurfaceLoaded(); if (Surface != null) + { + _assetSelect = GetChild(); + _assetBox = GetBox(8); + _assetSelect.Visible = !_assetBox.HasAnyConnection; UpdateTitle(); + } } private void UpdateTitle() @@ -64,6 +72,17 @@ namespace FlaxEditor.Surface.Archetypes var style = Style.Current; Resize(Mathf.Max(230, style.FontLarge.MeasureText(Title).X + 30), 160); } + + /// + public override void ConnectionTick(Box box) + { + base.ConnectionTick(box); + + if(box.ID != _assetBox.ID) + return; + + _assetSelect.Visible = !box.HasAnyConnection; + } } /// @@ -305,7 +324,8 @@ namespace FlaxEditor.Surface.Archetypes NodeElementArchetype.Factory.Input(0, "Speed", true, typeof(float), 5, 1), NodeElementArchetype.Factory.Input(1, "Loop", true, typeof(bool), 6, 2), NodeElementArchetype.Factory.Input(2, "Start Position", true, typeof(float), 7, 3), - NodeElementArchetype.Factory.Asset(0, Surface.Constants.LayoutOffsetY * 3, 0, typeof(FlaxEngine.Animation)), + NodeElementArchetype.Factory.Input(3, "Animation Asset", true, typeof(FlaxEngine.Animation), 8), + NodeElementArchetype.Factory.Asset(0, Surface.Constants.LayoutOffsetY * 4, 0, typeof(FlaxEngine.Animation)), } }, new NodeArchetype diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp index 73ddbc41c..088e11ed3 100644 --- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp +++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp @@ -749,7 +749,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu // Animation case 2: { - const auto anim = node->Assets[0].As(); + auto anim = node->Assets[0].As(); auto& bucket = context.Data->State[node->BucketIndex].Animation; switch (box->ID) @@ -761,6 +761,18 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu const float speed = (float)tryGetValue(node->GetBox(5), node->Values[1]); const bool loop = (bool)tryGetValue(node->GetBox(6), node->Values[2]); const float startTimePos = (float)tryGetValue(node->GetBox(7), node->Values[3]); + + // Override animation when animation reference box is connected + auto animationAssetBox = node->GetBox(8); + if(animationAssetBox->HasConnection()) + { + const Value assetBoxValue = tryGetValue(animationAssetBox, Value::Null); + if(assetBoxValue != Value::Null) + anim = (Animation*)assetBoxValue.AsAsset; + else + anim = nullptr; + } + const float length = anim ? anim->GetLength() : 0.0f; // Calculate new time position From ea355dd560f5757e07d4e009d34ebdde61ce6eed Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Fri, 6 Oct 2023 15:30:52 +0200 Subject: [PATCH 02/34] - Title of Animation sample node gets updated when connection of animation reference box changes --- Source/Editor/Surface/Archetypes/Animation.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Surface/Archetypes/Animation.cs b/Source/Editor/Surface/Archetypes/Animation.cs index 2e362ae79..2155b014e 100644 --- a/Source/Editor/Surface/Archetypes/Animation.cs +++ b/Source/Editor/Surface/Archetypes/Animation.cs @@ -68,7 +68,7 @@ namespace FlaxEditor.Surface.Archetypes private void UpdateTitle() { var asset = Editor.Instance.ContentDatabase.Find((Guid)Values[0]); - Title = asset?.ShortName ?? "Animation"; + Title = _assetBox.HasAnyConnection || asset == null ? "Animation" : asset.ShortName; var style = Style.Current; Resize(Mathf.Max(230, style.FontLarge.MeasureText(Title).X + 30), 160); } @@ -82,6 +82,7 @@ namespace FlaxEditor.Surface.Archetypes return; _assetSelect.Visible = !box.HasAnyConnection; + UpdateTitle(); } } From 63d57151d0a91cdbd116c40de141103a6d54416d Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Fri, 6 Oct 2023 17:50:19 +0200 Subject: [PATCH 03/34] - Minor cleanup --- Source/Editor/Surface/Archetypes/Animation.cs | 4 ++-- Source/Engine/Animations/Graph/AnimGroup.Animation.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/Animation.cs b/Source/Editor/Surface/Archetypes/Animation.cs index 2155b014e..1b9e212b2 100644 --- a/Source/Editor/Surface/Archetypes/Animation.cs +++ b/Source/Editor/Surface/Archetypes/Animation.cs @@ -36,7 +36,7 @@ namespace FlaxEditor.Surface.Archetypes { private AssetSelect _assetSelect; private Box _assetBox; - + /// public Sample(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch) : base(id, context, nodeArch, groupArch) @@ -77,7 +77,7 @@ namespace FlaxEditor.Surface.Archetypes public override void ConnectionTick(Box box) { base.ConnectionTick(box); - + if(box.ID != _assetBox.ID) return; diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp index 088e11ed3..043c57b4d 100644 --- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp +++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp @@ -772,7 +772,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu else anim = nullptr; } - + const float length = anim ? anim->GetLength() : 0.0f; // Calculate new time position From 2ff4a69f53d498ee037d05ba028e3117d0802cba Mon Sep 17 00:00:00 2001 From: nothingTVatYT Date: Mon, 9 Oct 2023 17:25:28 +0200 Subject: [PATCH 04/34] fix reading of pipe buffer from external filechooser --- .../Engine/Platform/Linux/LinuxFileSystem.cpp | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Platform/Linux/LinuxFileSystem.cpp b/Source/Engine/Platform/Linux/LinuxFileSystem.cpp index 279813470..3f33a8f65 100644 --- a/Source/Engine/Platform/Linux/LinuxFileSystem.cpp +++ b/Source/Engine/Platform/Linux/LinuxFileSystem.cpp @@ -69,7 +69,30 @@ bool LinuxFileSystem::ShowOpenFileDialog(Window* parentWindow, const StringView& } FILE* f = popen(cmd, "r"); char buf[2048]; - fgets(buf, ARRAY_COUNT(buf), f); + char* writePointer = buf; + int remainingCapacity = ARRAY_COUNT(buf); + // make sure we read all output from kdialog + while (remainingCapacity > 0 && fgets(writePointer, remainingCapacity, f)) + { + int r = strlen(writePointer); + writePointer += r; + remainingCapacity -= r; + } + if (remainingCapacity <= 0) + { + LOG(Error, "You selected more files than an internal buffer can hold. Try selecting fewer files at a time."); + // in case of an overflow we miss the closing null byte, add it after the rightmost linefeed + while (*writePointer != '\n') + { + writePointer--; + if (writePointer == buf) + { + *buf = 0; + break; + } + } + *(++writePointer) = 0; + } int result = pclose(f); if (result != 0) { From 00a03beb788e4ee4300708a9f76a0c6484cf008c Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 9 Oct 2023 21:45:36 +0200 Subject: [PATCH 05/34] Optimize `Half2` conversion in `Render2D` --- Source/Engine/Core/Math/Color.h | 4 +- Source/Engine/Core/Math/Half.cpp | 52 ++++++++++++++++++------ Source/Engine/Core/Math/Half.h | 68 +++++++++++--------------------- 3 files changed, 65 insertions(+), 59 deletions(-) diff --git a/Source/Engine/Core/Math/Color.h b/Source/Engine/Core/Math/Color.h index af93fc0f2..836ead090 100644 --- a/Source/Engine/Core/Math/Color.h +++ b/Source/Engine/Core/Math/Color.h @@ -71,7 +71,7 @@ public: /// The green channel value. /// The blue channel value. /// The alpha channel value. - Color(float r, float g, float b, float a = 1) + FORCE_INLINE Color(float r, float g, float b, float a = 1) : R(r) , G(g) , B(b) @@ -203,7 +203,7 @@ public: return Color(R - b.R, G - b.G, B - b.B, A - b.A); } - Color operator*(const Color& b) const + FORCE_INLINE Color operator*(const Color& b) const { return Color(R * b.R, G * b.G, B * b.B, A * b.A); } diff --git a/Source/Engine/Core/Math/Half.cpp b/Source/Engine/Core/Math/Half.cpp index 4e4b6eb50..b3c1696a5 100644 --- a/Source/Engine/Core/Math/Half.cpp +++ b/Source/Engine/Core/Math/Half.cpp @@ -1,10 +1,8 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #include "Half.h" -#include "Rectangle.h" -#include "Vector2.h" -#include "Vector3.h" #include "Vector4.h" +#include "Rectangle.h" #include "Color.h" static_assert(sizeof(Half) == 2, "Invalid Half type size."); @@ -16,12 +14,47 @@ Half2 Half2::Zero(0.0f, 0.0f); Half3 Half3::Zero(0.0f, 0.0f, 0.0f); Half4 Half4::Zero(0.0f, 0.0f, 0.0f, 0.0f); -Half2::Half2(const Float2& v) +#if !USE_SSE_HALF_CONVERSION + +Half Float16Compressor::Compress(float value) { - X = Float16Compressor::Compress(v.X); - Y = Float16Compressor::Compress(v.Y); + Bits v, s; + v.f = value; + uint32 sign = v.si & signN; + v.si ^= sign; + sign >>= shiftSign; // logical shift + s.si = mulN; + s.si = static_cast(s.f * v.f); // correct subnormals + v.si ^= (s.si ^ v.si) & -(minN > v.si); + v.si ^= (infN ^ v.si) & -((infN > v.si) & (v.si > maxN)); + v.si ^= (nanN ^ v.si) & -((nanN > v.si) & (v.si > infN)); + v.ui >>= shift; // logical shift + v.si ^= ((v.si - maxD) ^ v.si) & -(v.si > maxC); + v.si ^= ((v.si - minD) ^ v.si) & -(v.si > subC); + return v.ui | sign; } +float Float16Compressor::Decompress(Half value) +{ + Bits v; + v.ui = value; + int32 sign = v.si & signC; + v.si ^= sign; + sign <<= shiftSign; + v.si ^= ((v.si + minD) ^ v.si) & -(v.si > subC); + v.si ^= ((v.si + maxD) ^ v.si) & -(v.si > maxC); + Bits s; + s.si = mulC; + s.f *= v.si; + const int32 mask = -(norC > v.si); + v.si <<= shift; + v.si ^= (s.si ^ v.si) & mask; + v.si |= sign; + return v.f; +} + +#endif + Float2 Half2::ToFloat2() const { return Float2( @@ -30,13 +63,6 @@ Float2 Half2::ToFloat2() const ); } -Half3::Half3(const Float3& v) -{ - X = Float16Compressor::Compress(v.X); - Y = Float16Compressor::Compress(v.Y); - Z = Float16Compressor::Compress(v.Z); -} - Float3 Half3::ToFloat3() const { return Float3( diff --git a/Source/Engine/Core/Math/Half.h b/Source/Engine/Core/Math/Half.h index 346b5d6b3..44b90df66 100644 --- a/Source/Engine/Core/Math/Half.h +++ b/Source/Engine/Core/Math/Half.h @@ -3,6 +3,8 @@ #pragma once #include "Math.h" +#include "Vector2.h" +#include "Vector3.h" /// /// Half-precision 16 bit floating point number consisting of a sign bit, a 5 bit biased exponent, and a 10 bit mantissa @@ -45,54 +47,23 @@ class FLAXENGINE_API Float16Compressor static const int32 minD = minC - subC - 1; public: - static Half Compress(const float value) - { #if USE_SSE_HALF_CONVERSION + FORCE_INLINE static Half Compress(float value) + { __m128 value1 = _mm_set_ss(value); __m128i value2 = _mm_cvtps_ph(value1, 0); return static_cast(_mm_cvtsi128_si32(value2)); -#else - Bits v, s; - v.f = value; - uint32 sign = v.si & signN; - v.si ^= sign; - sign >>= shiftSign; // logical shift - s.si = mulN; - s.si = static_cast(s.f * v.f); // correct subnormals - v.si ^= (s.si ^ v.si) & -(minN > v.si); - v.si ^= (infN ^ v.si) & -((infN > v.si) & (v.si > maxN)); - v.si ^= (nanN ^ v.si) & -((nanN > v.si) & (v.si > infN)); - v.ui >>= shift; // logical shift - v.si ^= ((v.si - maxD) ^ v.si) & -(v.si > maxC); - v.si ^= ((v.si - minD) ^ v.si) & -(v.si > subC); - return v.ui | sign; -#endif } - - static float Decompress(const Half value) + FORCE_INLINE static float Decompress(Half value) { -#if USE_SSE_HALF_CONVERSION __m128i value1 = _mm_cvtsi32_si128(static_cast(value)); __m128 value2 = _mm_cvtph_ps(value1); return _mm_cvtss_f32(value2); -#else - Bits v; - v.ui = value; - int32 sign = v.si & signC; - v.si ^= sign; - sign <<= shiftSign; - v.si ^= ((v.si + minD) ^ v.si) & -(v.si > subC); - v.si ^= ((v.si + maxD) ^ v.si) & -(v.si > maxC); - Bits s; - s.si = mulC; - s.f *= v.si; - const int32 mask = -(norC > v.si); - v.si <<= shift; - v.si ^= (s.si ^ v.si) & mask; - v.si |= sign; - return v.f; -#endif } +#else + static Half Compress(float value); + static float Decompress(Half value); +#endif }; /// @@ -128,7 +99,7 @@ public: /// /// X component /// Y component - Half2(Half x, Half y) + FORCE_INLINE Half2(Half x, Half y) : X(x) , Y(y) { @@ -139,7 +110,7 @@ public: /// /// X component /// Y component - Half2(float x, float y) + FORCE_INLINE Half2(float x, float y) { X = Float16Compressor::Compress(x); Y = Float16Compressor::Compress(y); @@ -149,7 +120,11 @@ public: /// Init /// /// X and Y components - Half2(const Float2& v); + FORCE_INLINE Half2(const Float2& v) + { + X = Float16Compressor::Compress(v.X); + Y = Float16Compressor::Compress(v.Y); + } public: Float2 ToFloat2() const; @@ -185,21 +160,26 @@ public: public: Half3() = default; - Half3(Half x, Half y, Half z) + FORCE_INLINE Half3(Half x, Half y, Half z) : X(x) , Y(y) , Z(z) { } - Half3(const float x, const float y, const float z) + FORCE_INLINE Half3(float x, float y, float z) { X = Float16Compressor::Compress(x); Y = Float16Compressor::Compress(y); Z = Float16Compressor::Compress(z); } - Half3(const Float3& v); + FORCE_INLINE Half3(const Float3& v) + { + X = Float16Compressor::Compress(v.X); + Y = Float16Compressor::Compress(v.Y); + Z = Float16Compressor::Compress(v.Z); + } public: Float3 ToFloat3() const; From 3ac7c4e0ee80c4896120e0beb7300d303b03afe8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 9 Oct 2023 23:21:02 +0200 Subject: [PATCH 06/34] Codestyle fix --- .../CustomEditors/Dedicated/ClothEditor.cs | 4 ++-- Source/Editor/Editor.cs | 2 +- Source/Editor/GUI/AssetPicker.cs | 4 ++-- .../GUI/ContextMenu/ContextMenuChildMenu.cs | 2 +- Source/Editor/GUI/Dialogs/Dialog.cs | 2 +- Source/Editor/GUI/Input/SearchBox.cs | 4 ++-- Source/Editor/GUI/Row.cs | 2 +- Source/Editor/Modules/ContentEditingModule.cs | 2 +- Source/Editor/Modules/PrefabsModule.cs | 2 +- Source/Editor/Modules/SceneEditingModule.cs | 6 +++--- Source/Editor/Modules/SceneModule.cs | 2 +- .../SourceCodeEditing/CodeEditingModule.cs | 8 ++++---- Source/Editor/Modules/UIModule.cs | 6 +++--- Source/Editor/Progress/ProgressHandler.cs | 4 ++-- Source/Editor/Surface/Archetypes/Animation.cs | 2 +- Source/Editor/Surface/Archetypes/Parameters.cs | 16 ++++++++-------- Source/Editor/Surface/VisjectSurface.Draw.cs | 2 +- Source/Editor/ViewportDebugDrawData.cs | 2 +- .../Windows/Assets/PrefabWindow.Actions.cs | 6 +++--- Source/Editor/Windows/Assets/PrefabWindow.cs | 4 ++-- Source/Editor/Windows/Profiler/Network.cs | 4 ++-- .../Animations/Graph/AnimGroup.Animation.cpp | 6 +++--- 22 files changed, 46 insertions(+), 46 deletions(-) diff --git a/Source/Editor/CustomEditors/Dedicated/ClothEditor.cs b/Source/Editor/CustomEditors/Dedicated/ClothEditor.cs index c6043e8b6..4053c6e16 100644 --- a/Source/Editor/CustomEditors/Dedicated/ClothEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ClothEditor.cs @@ -36,7 +36,7 @@ namespace FlaxEditor.CustomEditors.Dedicated return; var gizmos = gizmoOwner.Gizmos; _gizmoMode = new ClothPaintingGizmoMode(); - + var projectCache = Editor.Instance.ProjectCache; if (projectCache.TryGetCustomData("ClothGizmoPaintValue", out var cachedPaintValue)) _gizmoMode.PaintValue = JsonSerializer.Deserialize(cachedPaintValue); @@ -48,7 +48,7 @@ namespace FlaxEditor.CustomEditors.Dedicated _gizmoMode.BrushSize = JsonSerializer.Deserialize(cachedBrushSize); if (projectCache.TryGetCustomData("ClothGizmoBrushStrength", out var cachedBrushStrength)) _gizmoMode.BrushStrength = JsonSerializer.Deserialize(cachedBrushStrength); - + gizmos.AddMode(_gizmoMode); _prevMode = gizmos.ActiveMode; gizmos.ActiveMode = _gizmoMode; diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index 1b46222ea..b384b6515 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -364,7 +364,7 @@ namespace FlaxEditor { foreach (var preview in activePreviews) { - if (preview == loadingPreview || + if (preview == loadingPreview || (preview.Instance != null && (preview.Instance == control || preview.Instance.HasActorInHierarchy(control)))) { // Link it to the prefab preview to see it in the editor diff --git a/Source/Editor/GUI/AssetPicker.cs b/Source/Editor/GUI/AssetPicker.cs index 3e5d22eb0..8d6b0f9e2 100644 --- a/Source/Editor/GUI/AssetPicker.cs +++ b/Source/Editor/GUI/AssetPicker.cs @@ -482,8 +482,8 @@ namespace FlaxEditor.GUI Focus(); }); if (_selected != null) - { - var selectedAssetName = Path.GetFileNameWithoutExtension(_selected.Path); + { + var selectedAssetName = Path.GetFileNameWithoutExtension(_selected.Path); popup.ScrollToAndHighlightItemByName(selectedAssetName); } } diff --git a/Source/Editor/GUI/ContextMenu/ContextMenuChildMenu.cs b/Source/Editor/GUI/ContextMenu/ContextMenuChildMenu.cs index 7af36fae0..49a60a04e 100644 --- a/Source/Editor/GUI/ContextMenu/ContextMenuChildMenu.cs +++ b/Source/Editor/GUI/ContextMenu/ContextMenuChildMenu.cs @@ -72,7 +72,7 @@ namespace FlaxEditor.GUI.ContextMenu // Hide parent CM popups and set itself as child parentContextMenu.ShowChild(ContextMenu, PointToParent(ParentContextMenu, new Float2(Width, 0))); } - + /// public override bool OnMouseUp(Float2 location, MouseButton button) { diff --git a/Source/Editor/GUI/Dialogs/Dialog.cs b/Source/Editor/GUI/Dialogs/Dialog.cs index 07fc3ff0d..5054aee98 100644 --- a/Source/Editor/GUI/Dialogs/Dialog.cs +++ b/Source/Editor/GUI/Dialogs/Dialog.cs @@ -293,7 +293,7 @@ namespace FlaxEditor.GUI.Dialogs if (Root != null) { bool shiftDown = Root.GetKey(KeyboardKeys.Shift); - Root.Navigate(shiftDown ? NavDirection.Previous : NavDirection.Next); + Root.Navigate(shiftDown ? NavDirection.Previous : NavDirection.Next); } return true; } diff --git a/Source/Editor/GUI/Input/SearchBox.cs b/Source/Editor/GUI/Input/SearchBox.cs index 994ef14b1..73cfe55bf 100644 --- a/Source/Editor/GUI/Input/SearchBox.cs +++ b/Source/Editor/GUI/Input/SearchBox.cs @@ -20,7 +20,7 @@ namespace FlaxEditor.GUI.Input : this(false, 0, 0) { } - + /// /// Init search box /// @@ -28,7 +28,7 @@ namespace FlaxEditor.GUI.Input : base(isMultiline, x, y, width) { WatermarkText = "Search..."; - + ClearSearchButton = new Button { Parent = this, diff --git a/Source/Editor/GUI/Row.cs b/Source/Editor/GUI/Row.cs index b07d693e5..cb9cb09b2 100644 --- a/Source/Editor/GUI/Row.cs +++ b/Source/Editor/GUI/Row.cs @@ -241,7 +241,7 @@ namespace FlaxEditor.GUI { DoubleClick?.Invoke(); RowDoubleClick?.Invoke(this); - + return base.OnMouseDoubleClick(location, button); } diff --git a/Source/Editor/Modules/ContentEditingModule.cs b/Source/Editor/Modules/ContentEditingModule.cs index 1a8920916..f262864dd 100644 --- a/Source/Editor/Modules/ContentEditingModule.cs +++ b/Source/Editor/Modules/ContentEditingModule.cs @@ -104,7 +104,7 @@ namespace FlaxEditor.Modules hint = "Too long name."; return false; } - + if (item.IsFolder && shortName.EndsWith(".")) { hint = "Name cannot end with '.'"; diff --git a/Source/Editor/Modules/PrefabsModule.cs b/Source/Editor/Modules/PrefabsModule.cs index bb76e125b..adb5f7685 100644 --- a/Source/Editor/Modules/PrefabsModule.cs +++ b/Source/Editor/Modules/PrefabsModule.cs @@ -133,7 +133,7 @@ namespace FlaxEditor.Modules return; var actorsList = new List(); Utilities.Utils.GetActorsTree(actorsList, actor); - + var actions = new IUndoAction[actorsList.Count]; for (int i = 0; i < actorsList.Count; i++) actions[i] = BreakPrefabLinkAction.Linked(actorsList[i]); diff --git a/Source/Editor/Modules/SceneEditingModule.cs b/Source/Editor/Modules/SceneEditingModule.cs index 2b8bf718e..970ca8e99 100644 --- a/Source/Editor/Modules/SceneEditingModule.cs +++ b/Source/Editor/Modules/SceneEditingModule.cs @@ -453,7 +453,7 @@ namespace FlaxEditor.Modules { Editor.Windows.SceneWin.Focus(); } - + // fix scene window layout Editor.Windows.SceneWin.PerformLayout(); Editor.Windows.SceneWin.PerformLayout(); @@ -520,7 +520,7 @@ namespace FlaxEditor.Modules Undo.AddAction(new MultiUndoAction(pasteAction, selectAction)); OnSelectionChanged(); } - + // Scroll to new selected node while pasting Editor.Windows.SceneWin.ScrollToSelectedNode(); } @@ -620,7 +620,7 @@ namespace FlaxEditor.Modules Undo.AddAction(new MultiUndoAction(undoActions)); OnSelectionChanged(); } - + // Scroll to new selected node while duplicating Editor.Windows.SceneWin.ScrollToSelectedNode(); } diff --git a/Source/Editor/Modules/SceneModule.cs b/Source/Editor/Modules/SceneModule.cs index 257262585..7789eb7c4 100644 --- a/Source/Editor/Modules/SceneModule.cs +++ b/Source/Editor/Modules/SceneModule.cs @@ -332,7 +332,7 @@ namespace FlaxEditor.Modules continue; scenes.Add(s); } - + // In play-mode Editor mocks the level streaming script if (Editor.IsPlayMode) { diff --git a/Source/Editor/Modules/SourceCodeEditing/CodeEditingModule.cs b/Source/Editor/Modules/SourceCodeEditing/CodeEditingModule.cs index 4089f6d79..e9ff4c5b5 100644 --- a/Source/Editor/Modules/SourceCodeEditing/CodeEditingModule.cs +++ b/Source/Editor/Modules/SourceCodeEditing/CodeEditingModule.cs @@ -29,10 +29,10 @@ namespace FlaxEditor.Modules.SourceCodeEditing private static bool CheckFunc(ScriptType scriptType) { - if (scriptType.IsStatic || - scriptType.IsGenericType || - !scriptType.IsPublic || - scriptType.HasAttribute(typeof(HideInEditorAttribute), true) || + if (scriptType.IsStatic || + scriptType.IsGenericType || + !scriptType.IsPublic || + scriptType.HasAttribute(typeof(HideInEditorAttribute), true) || scriptType.HasAttribute(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), false)) return false; var managedType = TypeUtils.GetType(scriptType); diff --git a/Source/Editor/Modules/UIModule.cs b/Source/Editor/Modules/UIModule.cs index c882efb87..492d78918 100644 --- a/Source/Editor/Modules/UIModule.cs +++ b/Source/Editor/Modules/UIModule.cs @@ -299,7 +299,7 @@ namespace FlaxEditor.Modules else text = "Ready"; - if(ProgressVisible) + if (ProgressVisible) { color = Style.Current.Statusbar.Loading; } @@ -402,7 +402,7 @@ namespace FlaxEditor.Modules { UpdateStatusBar(); } - else if(ProgressVisible) + else if (ProgressVisible) { UpdateStatusBar(); } @@ -557,7 +557,7 @@ namespace FlaxEditor.Modules cm.AddButton("Game Settings", () => { var item = Editor.ContentDatabase.Find(GameSettings.GameSettingsAssetPath); - if(item != null) + if (item != null) Editor.ContentEditing.Open(item); }); diff --git a/Source/Editor/Progress/ProgressHandler.cs b/Source/Editor/Progress/ProgressHandler.cs index 2738b7c57..9581a0de6 100644 --- a/Source/Editor/Progress/ProgressHandler.cs +++ b/Source/Editor/Progress/ProgressHandler.cs @@ -16,7 +16,7 @@ namespace FlaxEditor.Progress /// /// The calling handler. public delegate void ProgressDelegate(ProgressHandler handler); - + /// /// Progress failed handler event delegate /// @@ -127,7 +127,7 @@ namespace FlaxEditor.Progress { if (!_isActive) throw new InvalidOperationException("Already ended."); - + _isActive = false; _progress = 0; _infoText = string.Empty; diff --git a/Source/Editor/Surface/Archetypes/Animation.cs b/Source/Editor/Surface/Archetypes/Animation.cs index 9bdb88054..a05ede1e7 100644 --- a/Source/Editor/Surface/Archetypes/Animation.cs +++ b/Source/Editor/Surface/Archetypes/Animation.cs @@ -78,7 +78,7 @@ namespace FlaxEditor.Surface.Archetypes { base.ConnectionTick(box); - if(box.ID != _assetBox.ID) + if (box.ID != _assetBox.ID) return; _assetSelect.Visible = !box.HasAnyConnection; diff --git a/Source/Editor/Surface/Archetypes/Parameters.cs b/Source/Editor/Surface/Archetypes/Parameters.cs index 3fe727840..6ed5a61e6 100644 --- a/Source/Editor/Surface/Archetypes/Parameters.cs +++ b/Source/Editor/Surface/Archetypes/Parameters.cs @@ -510,7 +510,7 @@ namespace FlaxEditor.Surface.Archetypes for (var i = 0; i < elements.Length; i++) { - if(elements[i].Type != NodeElementType.Output) + if (elements[i].Type != NodeElementType.Output) continue; if (VisjectSurface.FullCastCheck(elements[i].ConnectionsType, inputType, hint)) @@ -533,7 +533,7 @@ namespace FlaxEditor.Surface.Archetypes for (var i = 0; i < elements.Length; i++) { - if(elements[i].Type != NodeElementType.Input) + if (elements[i].Type != NodeElementType.Input) continue; if (VisjectSurface.FullCastCheck(elements[i].ConnectionsType, outputType, hint)) return true; @@ -725,7 +725,7 @@ namespace FlaxEditor.Surface.Archetypes /// protected override bool UseNormalMaps => false; - + internal new static bool IsOutputCompatible(NodeArchetype nodeArch, ScriptType inputType, ConnectionsHint hint, VisjectSurfaceContext context) { if (inputType == ScriptType.Object) @@ -743,7 +743,7 @@ namespace FlaxEditor.Surface.Archetypes for (var i = 0; i < elements.Length; i++) { - if(elements[i].Type != NodeElementType.Output) + if (elements[i].Type != NodeElementType.Output) continue; if (VisjectSurface.FullCastCheck(elements[i].ConnectionsType, inputType, hint)) return true; @@ -765,7 +765,7 @@ namespace FlaxEditor.Surface.Archetypes for (var i = 0; i < elements.Length; i++) { - if(elements[i].Type != NodeElementType.Input) + if (elements[i].Type != NodeElementType.Input) continue; if (VisjectSurface.FullCastCheck(elements[i].ConnectionsType, outputType, hint)) return true; @@ -789,7 +789,7 @@ namespace FlaxEditor.Surface.Archetypes /// protected override bool UseNormalMaps => false; - + internal new static bool IsOutputCompatible(NodeArchetype nodeArch, ScriptType inputType, ConnectionsHint hint, VisjectSurfaceContext context) { if (inputType == ScriptType.Object) @@ -987,7 +987,7 @@ namespace FlaxEditor.Surface.Archetypes _combobox.Width = Width - 50; } } - + internal static bool IsOutputCompatible(NodeArchetype nodeArch, ScriptType inputType, ConnectionsHint hint, VisjectSurfaceContext context) { return inputType == ScriptType.Void; @@ -997,7 +997,7 @@ namespace FlaxEditor.Surface.Archetypes { if (outputType == ScriptType.Void) return true; - + SurfaceParameter parameter = context.GetParameter((Guid)nodeArch.DefaultValues[0]); ScriptType type = parameter?.Type ?? ScriptType.Null; diff --git a/Source/Editor/Surface/VisjectSurface.Draw.cs b/Source/Editor/Surface/VisjectSurface.Draw.cs index f60f6ff3a..e7b76a538 100644 --- a/Source/Editor/Surface/VisjectSurface.Draw.cs +++ b/Source/Editor/Surface/VisjectSurface.Draw.cs @@ -141,7 +141,7 @@ namespace FlaxEditor.Surface if (_connectionInstigator is Archetypes.Tools.RerouteNode) { - if (endPos.X < startPos.X && _lastInstigatorUnderMouse is null or Box { IsOutput: true}) + if (endPos.X < startPos.X && _lastInstigatorUnderMouse is null or Box { IsOutput: true }) { actualStartPos = endPos; actualEndPos = startPos; diff --git a/Source/Editor/ViewportDebugDrawData.cs b/Source/Editor/ViewportDebugDrawData.cs index 48b551675..7fccd697f 100644 --- a/Source/Editor/ViewportDebugDrawData.cs +++ b/Source/Editor/ViewportDebugDrawData.cs @@ -97,7 +97,7 @@ namespace FlaxEditor if (_highlightMaterial == null || (_highlights.Count == 0 && _highlightTriangles.Count == 0) || renderContext.View.Pass == DrawPass.Depth - ) + ) return; Profiler.BeginEvent("ViewportDebugDrawData.OnDraw"); diff --git a/Source/Editor/Windows/Assets/PrefabWindow.Actions.cs b/Source/Editor/Windows/Assets/PrefabWindow.Actions.cs index 6de553a30..05b59b800 100644 --- a/Source/Editor/Windows/Assets/PrefabWindow.Actions.cs +++ b/Source/Editor/Windows/Assets/PrefabWindow.Actions.cs @@ -153,7 +153,7 @@ namespace FlaxEditor.Windows.Assets { OnPasteAction(pasteAction); } - + // Scroll to new selected node ScrollToSelectedNode(); } @@ -183,7 +183,7 @@ namespace FlaxEditor.Windows.Assets { OnPasteAction(pasteAction); } - + // Scroll to new selected node ScrollToSelectedNode(); } @@ -334,7 +334,7 @@ namespace FlaxEditor.Windows.Assets }, action2.ActionString); action.Do(); Undo.AddAction(action); - + _treePanel.PerformLayout(); _treePanel.PerformLayout(); } diff --git a/Source/Editor/Windows/Assets/PrefabWindow.cs b/Source/Editor/Windows/Assets/PrefabWindow.cs index 4deaf5d7d..4face0dc0 100644 --- a/Source/Editor/Windows/Assets/PrefabWindow.cs +++ b/Source/Editor/Windows/Assets/PrefabWindow.cs @@ -207,7 +207,7 @@ namespace FlaxEditor.Windows.Assets InputActions.Add(options => options.Rename, Rename); InputActions.Add(options => options.FocusSelection, _viewport.FocusSelection); } - + /// /// Enables or disables vertical and horizontal scrolling on the tree panel. /// @@ -257,7 +257,7 @@ namespace FlaxEditor.Windows.Assets { if (base.OnMouseUp(location, button)) return true; - + if (button == MouseButton.Right && _treePanel.ContainsPoint(ref location)) { _tree.Deselect(); diff --git a/Source/Editor/Windows/Profiler/Network.cs b/Source/Editor/Windows/Profiler/Network.cs index dbee0e8e7..78d84ad9d 100644 --- a/Source/Editor/Windows/Profiler/Network.cs +++ b/Source/Editor/Windows/Profiler/Network.cs @@ -128,7 +128,7 @@ namespace FlaxEditor.Windows.Profiler _tableRep.IsLayoutLocked = true; RecycleTableRows(_tableRpc, _tableRowsCache); RecycleTableRows(_tableRep, _tableRowsCache); - + var events = _events.Get(selectedFrame); var rowCount = Int2.Zero; if (events != null && events.Length != 0) @@ -186,7 +186,7 @@ namespace FlaxEditor.Windows.Profiler _tableRep.Visible = rowCount.Y != 0; _tableRpc.Children.Sort(SortRows); _tableRep.Children.Sort(SortRows); - + _tableRpc.UnlockChildrenRecursive(); _tableRpc.PerformLayout(); _tableRep.UnlockChildrenRecursive(); diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp index 29288f658..a19b84370 100644 --- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp +++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp @@ -530,7 +530,7 @@ void AnimGraphExecutor::UpdateStateTransitions(AnimGraphContext& context, const transitionData.Position = 0; transitionData.Length = ZeroTolerance; } - + const bool useDefaultRule = EnumHasAnyFlags(transition.Flags, AnimGraphStateTransition::FlagTypes::UseDefaultRule); if (transition.RuleGraph && !useDefaultRule) { @@ -765,10 +765,10 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu // Override animation when animation reference box is connected auto animationAssetBox = node->GetBox(8); - if(animationAssetBox->HasConnection()) + if (animationAssetBox->HasConnection()) { const Value assetBoxValue = tryGetValue(animationAssetBox, Value::Null); - if(assetBoxValue != Value::Null) + if (assetBoxValue != Value::Null) anim = (Animation*)assetBoxValue.AsAsset; else anim = nullptr; From ccf346930751d1ab85888f3ad331e34d26a38b11 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 10 Oct 2023 14:17:34 +0200 Subject: [PATCH 07/34] Minor Vulkan tweaks --- .../GraphicsDevice/Vulkan/GPUContextVulkan.cpp | 10 ++++------ .../GraphicsDevice/Vulkan/GPUTimerQueryVulkan.cpp | 12 ++++++------ .../GraphicsDevice/Vulkan/GPUTimerQueryVulkan.h | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp index d758ec999..79e882f6d 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp @@ -1210,16 +1210,16 @@ void GPUContextVulkan::ResolveMultisample(GPUTexture* sourceMultisampleTexture, void GPUContextVulkan::DrawInstanced(uint32 verticesCount, uint32 instanceCount, int32 startInstance, int32 startVertex) { - const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer(); OnDrawCall(); + const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer(); vkCmdDraw(cmdBuffer->GetHandle(), verticesCount, instanceCount, startVertex, startInstance); RENDER_STAT_DRAW_CALL(verticesCount * instanceCount, verticesCount * instanceCount / 3); } void GPUContextVulkan::DrawIndexedInstanced(uint32 indicesCount, uint32 instanceCount, int32 startInstance, int32 startVertex, int32 startIndex) { - const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer(); OnDrawCall(); + const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer(); vkCmdDrawIndexed(cmdBuffer->GetHandle(), indicesCount, instanceCount, startIndex, startVertex, startInstance); RENDER_STAT_DRAW_CALL(0, indicesCount / 3 * instanceCount); } @@ -1227,10 +1227,9 @@ void GPUContextVulkan::DrawIndexedInstanced(uint32 indicesCount, uint32 instance void GPUContextVulkan::DrawInstancedIndirect(GPUBuffer* bufferForArgs, uint32 offsetForArgs) { ASSERT(bufferForArgs && EnumHasAnyFlags(bufferForArgs->GetFlags(), GPUBufferFlags::Argument)); - + OnDrawCall(); auto bufferForArgsVK = (GPUBufferVulkan*)bufferForArgs; const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer(); - OnDrawCall(); vkCmdDrawIndirect(cmdBuffer->GetHandle(), bufferForArgsVK->GetHandle(), (VkDeviceSize)offsetForArgs, 1, sizeof(VkDrawIndirectCommand)); RENDER_STAT_DRAW_CALL(0, 0); } @@ -1238,10 +1237,9 @@ void GPUContextVulkan::DrawInstancedIndirect(GPUBuffer* bufferForArgs, uint32 of void GPUContextVulkan::DrawIndexedInstancedIndirect(GPUBuffer* bufferForArgs, uint32 offsetForArgs) { ASSERT(bufferForArgs && EnumHasAnyFlags(bufferForArgs->GetFlags(), GPUBufferFlags::Argument)); - + OnDrawCall(); auto bufferForArgsVK = (GPUBufferVulkan*)bufferForArgs; const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer(); - OnDrawCall(); vkCmdDrawIndexedIndirect(cmdBuffer->GetHandle(), bufferForArgsVK->GetHandle(), (VkDeviceSize)offsetForArgs, 1, sizeof(VkDrawIndexedIndirectCommand)); RENDER_STAT_DRAW_CALL(0, 0); } diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUTimerQueryVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUTimerQueryVulkan.cpp index 9c58b77b0..cce86799a 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUTimerQueryVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUTimerQueryVulkan.cpp @@ -16,7 +16,7 @@ void GPUTimerQueryVulkan::Interrupt(CmdBufferVulkan* cmdBuffer) if (!_interrupted) { _interrupted = true; - WriteTimestamp(cmdBuffer, _queries[_queryIndex].End); + WriteTimestamp(cmdBuffer, _queries[_queryIndex].End, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); } } @@ -28,7 +28,7 @@ void GPUTimerQueryVulkan::Resume(CmdBufferVulkan* cmdBuffer) e.End.Pool = nullptr; _interrupted = false; - WriteTimestamp(cmdBuffer, e.Begin); + WriteTimestamp(cmdBuffer, e.Begin, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); _queries.Add(e); _queryIndex++; @@ -56,13 +56,13 @@ bool GPUTimerQueryVulkan::GetResult(Query& query) return false; } -void GPUTimerQueryVulkan::WriteTimestamp(CmdBufferVulkan* cmdBuffer, Query& query) const +void GPUTimerQueryVulkan::WriteTimestamp(CmdBufferVulkan* cmdBuffer, Query& query, VkPipelineStageFlagBits stage) const { auto pool = _device->FindAvailableTimestampQueryPool(); uint32 index; pool->AcquireQuery(index); - vkCmdWriteTimestamp(cmdBuffer->GetHandle(), VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, pool->GetHandle(), index); + vkCmdWriteTimestamp(cmdBuffer->GetHandle(), stage, pool->GetHandle(), index); pool->MarkQueryAsStarted(index); query.Pool = pool; @@ -168,7 +168,7 @@ void GPUTimerQueryVulkan::Begin() _queryIndex = 0; _interrupted = false; - WriteTimestamp(cmdBuffer, e.Begin); + WriteTimestamp(cmdBuffer, e.Begin, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); context->GetCmdBufferManager()->OnQueryBegin(this); ASSERT(_queries.IsEmpty()); @@ -193,7 +193,7 @@ void GPUTimerQueryVulkan::End() if (!_interrupted) { - WriteTimestamp(cmdBuffer, _queries[_queryIndex].End); + WriteTimestamp(cmdBuffer, _queries[_queryIndex].End, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); } context->GetCmdBufferManager()->OnQueryEnd(this); } diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUTimerQueryVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUTimerQueryVulkan.h index b081b946d..ddf461b13 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUTimerQueryVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUTimerQueryVulkan.h @@ -59,7 +59,7 @@ public: private: bool GetResult(Query& query); - void WriteTimestamp(CmdBufferVulkan* cmdBuffer, Query& query) const; + void WriteTimestamp(CmdBufferVulkan* cmdBuffer, Query& query, VkPipelineStageFlagBits stage) const; bool TryGetResult(); bool UseQueries(); From 7fcb0a1da7c50e108806ac46e993994c34dc7464 Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Tue, 10 Oct 2023 10:46:47 -0400 Subject: [PATCH 08/34] change terrain brush size with scroll --- Source/Editor/Tools/Terrain/PaintTerrainGizmo.cs | 8 ++++++++ Source/Editor/Tools/Terrain/PaintTerrainGizmoMode.cs | 4 ++-- Source/Editor/Tools/Terrain/SculptTerrainGizmo.cs | 8 ++++++++ Source/Editor/Tools/Terrain/SculptTerrainGizmoMode.cs | 4 ++-- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Source/Editor/Tools/Terrain/PaintTerrainGizmo.cs b/Source/Editor/Tools/Terrain/PaintTerrainGizmo.cs index c16bdd7e6..dd837fe00 100644 --- a/Source/Editor/Tools/Terrain/PaintTerrainGizmo.cs +++ b/Source/Editor/Tools/Terrain/PaintTerrainGizmo.cs @@ -150,6 +150,14 @@ namespace FlaxEditor.Tools.Terrain return; } + // Increase or decrease brush size with scroll + if (Input.GetKey(KeyboardKeys.Shift)) + { + var currentBrush = Mode.CurrentBrush; + currentBrush.Size += dt * currentBrush.Size * Input.Mouse.ScrollDelta * 5f; + Mode.CurrentBrush = currentBrush; + } + // Check if no terrain is selected var terrain = SelectedTerrain; if (!terrain) diff --git a/Source/Editor/Tools/Terrain/PaintTerrainGizmoMode.cs b/Source/Editor/Tools/Terrain/PaintTerrainGizmoMode.cs index 1d1bf87ca..a68b90ce8 100644 --- a/Source/Editor/Tools/Terrain/PaintTerrainGizmoMode.cs +++ b/Source/Editor/Tools/Terrain/PaintTerrainGizmoMode.cs @@ -139,9 +139,9 @@ namespace FlaxEditor.Tools.Terrain } /// - /// Gets the current brush. + /// Gets or set the current brush. /// - public Brush CurrentBrush => _brushes[(int)_brushType]; + public Brush CurrentBrush { get => _brushes[(int)_brushType]; set => _brushes[(int)_brushType] = value; } /// /// Gets the circle brush instance. diff --git a/Source/Editor/Tools/Terrain/SculptTerrainGizmo.cs b/Source/Editor/Tools/Terrain/SculptTerrainGizmo.cs index 96270a740..837c86dcb 100644 --- a/Source/Editor/Tools/Terrain/SculptTerrainGizmo.cs +++ b/Source/Editor/Tools/Terrain/SculptTerrainGizmo.cs @@ -158,6 +158,14 @@ namespace FlaxEditor.Tools.Terrain return; } + // Increase or decrease brush size with scroll + if (Input.GetKey(KeyboardKeys.Shift)) + { + var currentBrush = Mode.CurrentBrush; + currentBrush.Size += dt * currentBrush.Size * Input.Mouse.ScrollDelta * 5f; + Mode.CurrentBrush = currentBrush; + } + // Check if selected terrain was changed during painting if (terrain != _paintTerrain && IsPainting) { diff --git a/Source/Editor/Tools/Terrain/SculptTerrainGizmoMode.cs b/Source/Editor/Tools/Terrain/SculptTerrainGizmoMode.cs index 4b19cfbde..b99ac135f 100644 --- a/Source/Editor/Tools/Terrain/SculptTerrainGizmoMode.cs +++ b/Source/Editor/Tools/Terrain/SculptTerrainGizmoMode.cs @@ -158,9 +158,9 @@ namespace FlaxEditor.Tools.Terrain } /// - /// Gets the current brush. + /// Gets or set the current brush. /// - public Brush CurrentBrush => _brushes[(int)_brushType]; + public Brush CurrentBrush { get => _brushes[(int)_brushType]; set => _brushes[(int)_brushType] = value; } /// /// Gets the circle brush instance. From 902c82ae1e1a574584142c7d70b9794b06fcf649 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 10 Oct 2023 20:22:53 +0200 Subject: [PATCH 09/34] Add pixel format logging when not supported for shadow map --- Source/Engine/Renderer/ShadowsPass.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Renderer/ShadowsPass.cpp b/Source/Engine/Renderer/ShadowsPass.cpp index b22effdc9..7e0cd1053 100644 --- a/Source/Engine/Renderer/ShadowsPass.cpp +++ b/Source/Engine/Renderer/ShadowsPass.cpp @@ -9,6 +9,7 @@ #include "Engine/Graphics/PixelFormatExtensions.h" #include "Engine/Content/Content.h" #include "Engine/Graphics/GPUContext.h" +#include "Engine/Scripting/Enums.h" #if USE_EDITOR #include "Engine/Renderer/Lightmaps.h" #endif @@ -86,11 +87,12 @@ bool ShadowsPass::Init() const auto formatFeaturesTexture = GPUDevice::Instance->GetFormatFeatures(formatTexture); _supportsShadows = EnumHasAllFlags(formatFeaturesDepth.Support, FormatSupport::DepthStencil | FormatSupport::Texture2D) && EnumHasAllFlags(formatFeaturesTexture.Support, FormatSupport::ShaderSample | FormatSupport::ShaderSampleComparison); + // TODO: fallback to 32-bit shadow map format if 16-bit is not supported if (!_supportsShadows) { LOG(Warning, "GPU doesn't support shadows rendering"); - LOG(Warning, "Format: {0}, features support: {1}", (int32)SHADOW_MAPS_FORMAT, (uint32)formatFeaturesDepth.Support); - LOG(Warning, "Format: {0}, features support: {1}", (int32)formatTexture, (uint32)formatFeaturesTexture.Support); + LOG(Warning, "Format: {0}, features support: {1}", ScriptingEnum::ToString(SHADOW_MAPS_FORMAT), (uint32)formatFeaturesDepth.Support); + LOG(Warning, "Format: {0}, features support: {1}", ScriptingEnum::ToString(formatTexture), (uint32)formatFeaturesTexture.Support); } return false; From ac542bf920f8a1716df50aa1b240d1beff6d0a52 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 10 Oct 2023 20:52:12 +0200 Subject: [PATCH 10/34] Fix `FieldHelper.GetFieldOffset` crash for classes with `const` fields (compile-time) Inline call in `CreateScriptingObject` for perf --- Source/Engine/Engine/NativeInterop.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index f3bb57665..094e8836b 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -429,6 +429,9 @@ namespace FlaxEngine.Interop /// internal static int GetFieldOffset(FieldInfo field, Type type) { + if (field.IsLiteral) + return 0; + // Get the address of the field, source: https://stackoverflow.com/a/56512720 int fieldOffset = Unsafe.Read((field.FieldHandle.Value + 4 + IntPtr.Size).ToPointer()) & 0xFFFFFF; if (!type.IsValueType) @@ -1308,7 +1311,7 @@ namespace FlaxEngine.Interop internal object CreateScriptingObject(IntPtr unmanagedPtr, IntPtr idPtr) { - object obj = CreateObject(); + object obj = RuntimeHelpers.GetUninitializedObject(wrappedType); if (obj is Object) { { @@ -1332,7 +1335,7 @@ namespace FlaxEngine.Interop return obj; } - public static implicit operator Type(TypeHolder holder) => holder?.type ?? null; + public static implicit operator Type(TypeHolder holder) => holder?.type; public bool Equals(TypeHolder other) => type == other.type; public bool Equals(Type other) => type == other; public override int GetHashCode() => type.GetHashCode(); From a7937c2b2e81de8d866092fff82b4e05e95f8d4b Mon Sep 17 00:00:00 2001 From: Menotdan <32620310+Menotdan@users.noreply.github.com> Date: Tue, 10 Oct 2023 19:12:21 -0400 Subject: [PATCH 11/34] Fixed script serialization failures from removing scripts. --- Source/Editor/Undo/Actions/AddRemoveScriptAction.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Undo/Actions/AddRemoveScriptAction.cs b/Source/Editor/Undo/Actions/AddRemoveScriptAction.cs index 69a790b39..fb9f33619 100644 --- a/Source/Editor/Undo/Actions/AddRemoveScriptAction.cs +++ b/Source/Editor/Undo/Actions/AddRemoveScriptAction.cs @@ -49,7 +49,14 @@ namespace FlaxEditor.Actions _scriptTypeName = script.TypeName; _prefabId = script.PrefabID; _prefabObjectId = script.PrefabObjectID; - _scriptData = FlaxEngine.Json.JsonSerializer.Serialize(script); + try + { + _scriptData = FlaxEngine.Json.JsonSerializer.Serialize(script); + } + catch + { + _scriptData = null; + } _parentId = script.Actor.ID; _orderInParent = script.OrderInParent; _enabled = script.Enabled; From cbdd6c49641019d425737a1db6e7dc5d61b12845 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 11 Oct 2023 10:15:44 +0200 Subject: [PATCH 12/34] Add `HasDepthClip` to GPU Device limits --- Source/Engine/Graphics/GPULimits.h | 5 +++++ .../DirectX/DX11/GPUDeviceDX11.cpp | 2 ++ .../DirectX/DX12/GPUDeviceDX12.cpp | 1 + .../Engine/GraphicsDevice/Null/GPUDeviceNull.cpp | 16 +--------------- .../GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp | 1 + .../Vulkan/GPUPipelineStateVulkan.cpp | 2 +- 6 files changed, 11 insertions(+), 16 deletions(-) diff --git a/Source/Engine/Graphics/GPULimits.h b/Source/Engine/Graphics/GPULimits.h index 11da5aca3..0cae4fdfd 100644 --- a/Source/Engine/Graphics/GPULimits.h +++ b/Source/Engine/Graphics/GPULimits.h @@ -259,6 +259,11 @@ API_STRUCT() struct GPULimits /// API_FIELD() bool HasDepthAsSRV; + /// + /// True if device supports depth buffer clipping (see GPUPipelineState::Description::DepthClipEnable). + /// + API_FIELD() bool HasDepthClip; + /// /// True if device supports depth buffer texture as a readonly depth buffer (can be sampled in the shader while performing depth-test). /// diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp index c29c6254d..026422799 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp @@ -359,6 +359,7 @@ bool GPUDeviceDX11::Init() limits.HasAppendConsumeBuffers = true; limits.HasSeparateRenderTargetBlendState = true; limits.HasDepthAsSRV = true; + limits.HasDepthClip = true; limits.HasReadOnlyDepth = true; limits.HasMultisampleDepthAsSRV = true; limits.HasTypedUAVLoad = featureDataD3D11Options2.TypedUAVLoadAdditionalFormats != 0; @@ -382,6 +383,7 @@ bool GPUDeviceDX11::Init() limits.HasAppendConsumeBuffers = false; limits.HasSeparateRenderTargetBlendState = false; limits.HasDepthAsSRV = false; + limits.HasDepthClip = true; limits.HasReadOnlyDepth = createdFeatureLevel == D3D_FEATURE_LEVEL_10_1; limits.HasMultisampleDepthAsSRV = false; limits.HasTypedUAVLoad = false; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp index e2266f551..d9dc54f97 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp @@ -381,6 +381,7 @@ bool GPUDeviceDX12::Init() limits.HasAppendConsumeBuffers = true; limits.HasSeparateRenderTargetBlendState = true; limits.HasDepthAsSRV = true; + limits.HasDepthClip = true; limits.HasReadOnlyDepth = true; limits.HasMultisampleDepthAsSRV = true; limits.HasTypedUAVLoad = options.TypedUAVLoadAdditionalFormats != 0; diff --git a/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp b/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp index 7869ef312..fa390ccab 100644 --- a/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp +++ b/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp @@ -50,18 +50,7 @@ bool GPUDeviceNull::Init() // Init device limits { auto& limits = Limits; - limits.HasCompute = false; - limits.HasTessellation = false; - limits.HasGeometryShaders = false; - limits.HasInstancing = false; - limits.HasVolumeTextureRendering = false; - limits.HasDrawIndirect = false; - limits.HasAppendConsumeBuffers = false; - limits.HasSeparateRenderTargetBlendState = false; - limits.HasDepthAsSRV = false; - limits.HasReadOnlyDepth = false; - limits.HasMultisampleDepthAsSRV = false; - limits.HasTypedUAVLoad = false; + Platform::MemoryClear(&limits, sizeof(limits)); limits.MaximumMipLevelsCount = 14; limits.MaximumTexture1DSize = 8192; limits.MaximumTexture1DArraySize = 512; @@ -70,11 +59,8 @@ bool GPUDeviceNull::Init() limits.MaximumTexture3DSize = 2048; limits.MaximumTextureCubeSize = 16384; limits.MaximumSamplerAnisotropy = 1; - for (int32 i = 0; i < static_cast(PixelFormat::MAX); i++) - { FeaturesPerFormat[i] = FormatFeatures(static_cast(i), MSAALevel::None, FormatSupport::None); - } } // Create main context diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index b4a6112a9..9c553060f 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -1704,6 +1704,7 @@ bool GPUDeviceVulkan::Init() limits.HasDrawIndirect = PhysicalDeviceLimits.maxDrawIndirectCount >= 1; limits.HasAppendConsumeBuffers = false; // TODO: add Append Consume buffers support for Vulkan limits.HasSeparateRenderTargetBlendState = true; + limits.HasDepthClip = PhysicalDeviceFeatures.depthClamp; limits.HasDepthAsSRV = true; limits.HasReadOnlyDepth = true; limits.HasMultisampleDepthAsSRV = !!PhysicalDeviceFeatures.sampleRateShading; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp index 136a7c6e5..c5c1970e0 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp @@ -340,7 +340,7 @@ bool GPUPipelineStateVulkan::Init(const Description& desc) break; } _descRasterization.frontFace = VK_FRONT_FACE_CLOCKWISE; - _descRasterization.depthClampEnable = !desc.DepthClipEnable; + _descRasterization.depthClampEnable = !desc.DepthClipEnable && _device->Limits.HasDepthClip; _descRasterization.lineWidth = 1.0f; _desc.pRasterizationState = &_descRasterization; From bc762761ddb2f64218a1d626a71ba97dfe88f245 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 11 Oct 2023 12:35:27 +0200 Subject: [PATCH 13/34] Fix engine when used without C# scripting at all --- Source/Engine/Scripting/Internal/ManagedDictionary.cpp | 4 ++++ Source/Engine/Scripting/ManagedCLR/MAssembly.h | 4 +++- Source/Engine/Scripting/ManagedCLR/MCore.cpp | 10 +++++++--- Source/Engine/Scripting/Runtime/Mono.cpp | 2 +- Source/Engine/Scripting/Runtime/None.cpp | 3 +-- Source/Engine/Scripting/Scripting.cpp | 2 ++ 6 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Source/Engine/Scripting/Internal/ManagedDictionary.cpp b/Source/Engine/Scripting/Internal/ManagedDictionary.cpp index 7cb4d1cfb..6d3508b3d 100644 --- a/Source/Engine/Scripting/Internal/ManagedDictionary.cpp +++ b/Source/Engine/Scripting/Internal/ManagedDictionary.cpp @@ -1,5 +1,8 @@ +// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. + #include "ManagedDictionary.h" +#if USE_CSHARP Dictionary ManagedDictionary::CachedDictionaryTypes; #if !USE_MONO_AOT ManagedDictionary::MakeGenericTypeThunk ManagedDictionary::MakeGenericType; @@ -12,3 +15,4 @@ MMethod* ManagedDictionary::CreateInstance; MMethod* ManagedDictionary::AddDictionaryItem; MMethod* ManagedDictionary::GetDictionaryKeys; #endif +#endif diff --git a/Source/Engine/Scripting/ManagedCLR/MAssembly.h b/Source/Engine/Scripting/ManagedCLR/MAssembly.h index 3862627d0..ff1645e5e 100644 --- a/Source/Engine/Scripting/ManagedCLR/MAssembly.h +++ b/Source/Engine/Scripting/ManagedCLR/MAssembly.h @@ -25,8 +25,8 @@ private: MonoAssembly* _monoAssembly = nullptr; MonoImage* _monoImage = nullptr; #elif USE_NETCORE - StringAnsi _fullname; void* _handle = nullptr; + StringAnsi _fullname; #endif MDomain* _domain; @@ -50,6 +50,7 @@ public: /// The assembly name. MAssembly(MDomain* domain, const StringAnsiView& name); +#if USE_NETCORE /// /// Initializes a new instance of the class. /// @@ -58,6 +59,7 @@ public: /// The assembly full name. /// The managed handle of the assembly. MAssembly(MDomain* domain, const StringAnsiView& name, const StringAnsiView& fullname, void* handle); +#endif /// /// Finalizes an instance of the class. diff --git a/Source/Engine/Scripting/ManagedCLR/MCore.cpp b/Source/Engine/Scripting/ManagedCLR/MCore.cpp index d9cc6f863..02a834a9f 100644 --- a/Source/Engine/Scripting/ManagedCLR/MCore.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MCore.cpp @@ -48,18 +48,22 @@ MAssembly::MAssembly(MDomain* domain, const StringAnsiView& name) { } +#if USE_NETCORE + MAssembly::MAssembly(MDomain* domain, const StringAnsiView& name, const StringAnsiView& fullname, void* handle) - : _domain(domain) + : _handle(handle) + , _fullname(fullname) + , _domain(domain) , _isLoaded(false) , _isLoading(false) , _hasCachedClasses(false) , _reloadCount(0) , _name(name) - , _fullname(fullname) - , _handle(handle) { } +#endif + MAssembly::~MAssembly() { Unload(); diff --git a/Source/Engine/Scripting/Runtime/Mono.cpp b/Source/Engine/Scripting/Runtime/Mono.cpp index ef0c42818..00f16fd44 100644 --- a/Source/Engine/Scripting/Runtime/Mono.cpp +++ b/Source/Engine/Scripting/Runtime/Mono.cpp @@ -2157,7 +2157,7 @@ MObject* MCore::ScriptingObject::CreateScriptingObject(MClass* klass, void* unma if (managedInstance) { // Set unmanaged object handle and id - MCore::ScriptingObject::SetInternalValues(klass, managedInstance, unmanagedPtr, _id); + MCore::ScriptingObject::SetInternalValues(klass, managedInstance, unmanagedPtr, id); // Initialize managed instance (calls constructor) MCore::Object::Init(managedInstance); diff --git a/Source/Engine/Scripting/Runtime/None.cpp b/Source/Engine/Scripting/Runtime/None.cpp index a25d59c59..414a3e666 100644 --- a/Source/Engine/Scripting/Runtime/None.cpp +++ b/Source/Engine/Scripting/Runtime/None.cpp @@ -1,9 +1,8 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #include "Engine/Scripting/Types.h" - #if !USE_CSHARP - +#include "Engine/Core/Types/Span.h" #include "Engine/Scripting/ManagedCLR/MCore.h" #include "Engine/Scripting/ManagedCLR/MDomain.h" #include "Engine/Scripting/ManagedCLR/MAssembly.h" diff --git a/Source/Engine/Scripting/Scripting.cpp b/Source/Engine/Scripting/Scripting.cpp index cce66cd98..e1494cd04 100644 --- a/Source/Engine/Scripting/Scripting.cpp +++ b/Source/Engine/Scripting/Scripting.cpp @@ -493,9 +493,11 @@ bool Scripting::Load() flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector3"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Float3"]; flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector4"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Float4"]; #endif +#if USE_CSHARP 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"]; +#endif #if USE_EDITOR // Skip loading game modules in Editor on startup - Editor loads them later during splash screen (eg. after first compilation) From b92345c3ef86e4ad9233fdd50acea90e825821eb Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 11 Oct 2023 12:36:49 +0200 Subject: [PATCH 14/34] Fix crash when running async C# code with Mono --- Source/Engine/Scripting/Runtime/DotNet.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index 7f82f8dfc..1d2dc1af1 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -41,12 +41,18 @@ #include #include #include +#include #include #include +#include #include #include typedef char char_t; #define DOTNET_HOST_MONO_DEBUG 0 +#ifdef USE_MONO_AOT_MODULE +void* MonoAotModuleHandle = nullptr; +#endif +MonoDomain* MonoDomainHandle = nullptr; #else #error "Unknown .NET runtime host." #endif @@ -516,6 +522,12 @@ void MCore::GC::FreeMemory(void* ptr, bool coTaskMem) void MCore::Thread::Attach() { +#if DOTNET_HOST_MONO + if (!IsInMainThread() && !mono_domain_get()) + { + mono_thread_attach(MonoDomainHandle); + } +#endif } void MCore::Thread::Exit() @@ -1767,11 +1779,6 @@ void* GetStaticMethodPointer(const String& methodName) #elif DOTNET_HOST_MONO -#ifdef USE_MONO_AOT_MODULE -void* MonoAotModuleHandle = nullptr; -#endif -MonoDomain* MonoDomainHandle = nullptr; - void OnLogCallback(const char* logDomain, const char* logLevel, const char* message, mono_bool fatal, void* userData) { String currentDomain(logDomain); From af468ee6aeb476e58645ba539b0a1fb67ac0eb17 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 11 Oct 2023 15:18:28 +0200 Subject: [PATCH 15/34] Fix scripting interop in AOT mode to use reflection-based field access --- .../Engine/Engine/NativeInterop.Unmanaged.cs | 31 ++-- Source/Engine/Engine/NativeInterop.cs | 169 ++++++++++++++---- Source/Engine/Scripting/Runtime/DotNet.cpp | 27 ++- Source/Engine/Scripting/ScriptingObject.cpp | 2 +- Source/Engine/UI/UICanvas.cpp | 1 + 5 files changed, 173 insertions(+), 57 deletions(-) diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index b40fa740a..2094a528f 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -857,36 +857,25 @@ namespace FlaxEngine.Interop } [UnmanagedCallersOnly] - internal static void FieldGetValueReference(ManagedHandle fieldOwnerHandle, ManagedHandle fieldHandle, IntPtr valuePtr) + internal static void FieldGetValueReference(ManagedHandle fieldOwnerHandle, ManagedHandle fieldHandle, int fieldOffset, IntPtr valuePtr) { object fieldOwner = fieldOwnerHandle.Target; + IntPtr fieldRef; +#if USE_AOT FieldHolder field = Unsafe.As(fieldHandle.Target); + fieldRef = IntPtr.Zero; + Debug.LogError("Not supported FieldGetValueReference"); +#else if (fieldOwner.GetType().IsValueType) { - ref IntPtr fieldRef = ref FieldHelper.GetValueTypeFieldReference(field.fieldOffset, ref fieldOwner); - Unsafe.Write(valuePtr.ToPointer(), fieldRef); + fieldRef = FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); } else { - ref IntPtr fieldRef = ref FieldHelper.GetReferenceTypeFieldReference(field.fieldOffset, ref fieldOwner); - Unsafe.Write(valuePtr.ToPointer(), fieldRef); - } - } - - [UnmanagedCallersOnly] - internal static void FieldGetValueReferenceWithOffset(ManagedHandle fieldOwnerHandle, int fieldOffset, IntPtr valuePtr) - { - object fieldOwner = fieldOwnerHandle.Target; - if (fieldOwner.GetType().IsValueType) - { - ref IntPtr fieldRef = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); - Unsafe.Write(valuePtr.ToPointer(), fieldRef); - } - else - { - ref IntPtr fieldRef = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); - Unsafe.Write(valuePtr.ToPointer(), fieldRef); + fieldRef = FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); } +#endif + Unsafe.Write(valuePtr.ToPointer(), fieldRef); } [UnmanagedCallersOnly] diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 094e8836b..2f74e421c 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -119,6 +119,7 @@ namespace FlaxEngine.Interop { } +#if !USE_AOT // Cache offsets to frequently accessed fields of FlaxEngine.Object private static int unmanagedPtrFieldOffset = IntPtr.Size + (Unsafe.Read((typeof(FlaxEngine.Object).GetField("__unmanagedPtr", BindingFlags.Instance | BindingFlags.NonPublic).FieldHandle.Value + 4 + IntPtr.Size).ToPointer()) & 0xFFFFFF); private static int internalIdFieldOffset = IntPtr.Size + (Unsafe.Read((typeof(FlaxEngine.Object).GetField("__internalId", BindingFlags.Instance | BindingFlags.NonPublic).FieldHandle.Value + 4 + IntPtr.Size).ToPointer()) & 0xFFFFFF); @@ -150,6 +151,7 @@ namespace FlaxEngine.Interop object obj = typeHolder.CreateScriptingObject(unmanagedPtr, idPtr); return ManagedHandle.Alloc(obj); } +#endif internal static void* NativeAlloc(int byteCount) { @@ -439,6 +441,23 @@ namespace FlaxEngine.Interop return fieldOffset; } +#if USE_AOT + /// + /// Helper utility to set field of the referenced value via reflection. + /// + internal static void SetReferenceTypeField(FieldInfo field, ref T fieldOwner, object fieldValue) + { + if (typeof(T).IsValueType) + { + // Value types need setting via boxed object to properly propagate value + object fieldOwnerBoxed = fieldOwner; + field.SetValue(fieldOwnerBoxed, fieldValue); + fieldOwner = (T)fieldOwnerBoxed; + } + else + field.SetValue(fieldOwner, fieldValue); + } +#else /// /// Returns a reference to the value of the field. /// @@ -465,6 +484,7 @@ namespace FlaxEngine.Interop byte* fieldPtr = (byte*)Unsafe.As(ref fieldOwner) + fieldOffset; return ref Unsafe.AsRef(fieldPtr); } +#endif } /// @@ -738,29 +758,49 @@ namespace FlaxEngine.Interop private static void ToManagedFieldPointerValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct { +#if USE_AOT + IntPtr fieldValue = Unsafe.Read(nativeFieldPtr.ToPointer()); + FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); +#else ref IntPtr fieldValueRef = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); fieldValueRef = Unsafe.Read(nativeFieldPtr.ToPointer()); +#endif fieldSize = IntPtr.Size; } private static void ToManagedFieldPointerReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class { +#if USE_AOT + IntPtr fieldValue = Unsafe.Read(nativeFieldPtr.ToPointer()); + FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); +#else ref IntPtr fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); fieldValueRef = Unsafe.Read(nativeFieldPtr.ToPointer()); +#endif fieldSize = IntPtr.Size; } private static void ToNativeFieldPointerValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct { - ref IntPtr fieldValueRef = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); - Unsafe.Write(nativeFieldPtr.ToPointer(), fieldValueRef); +#if USE_AOT + object boxed = field.GetValue(fieldOwner); + IntPtr fieldValue = new IntPtr(Pointer.Unbox(boxed)); +#else + IntPtr fieldValue = FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); +#endif + Unsafe.Write(nativeFieldPtr.ToPointer(), fieldValue); fieldSize = IntPtr.Size; } private static void ToNativeFieldPointerReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class { - ref IntPtr fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); - Unsafe.Write(nativeFieldPtr.ToPointer(), fieldValueRef); +#if USE_AOT + object boxed = field.GetValue(fieldOwner); + IntPtr fieldValue = new IntPtr(Pointer.Unbox(boxed)); +#else + IntPtr fieldValue = FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); +#endif + Unsafe.Write(nativeFieldPtr.ToPointer(), fieldValue); fieldSize = IntPtr.Size; } @@ -802,8 +842,15 @@ namespace FlaxEngine.Interop fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); } - ref TField fieldValueRef = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); - MarshalHelper.ToManaged(ref fieldValueRef, nativeFieldPtr, false); +#if USE_AOT + TField fieldValue = default; +#else + ref TField fieldValue = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); +#endif + MarshalHelper.ToManaged(ref fieldValue, nativeFieldPtr, false); +#if USE_AOT + FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); +#endif } internal static void ToManagedFieldReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class @@ -816,8 +863,15 @@ namespace FlaxEngine.Interop fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); } - ref TField fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); - MarshalHelper.ToManaged(ref fieldValueRef, nativeFieldPtr, false); +#if USE_AOT + TField fieldValue = default; +#else + ref TField fieldValue = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); +#endif + MarshalHelper.ToManaged(ref fieldValue, nativeFieldPtr, false); +#if USE_AOT + FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); +#endif } internal static void ToManagedFieldArrayValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct @@ -828,8 +882,15 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); - ref TField[] fieldValueRef = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); - MarshalHelper.ToManaged(ref fieldValueRef, Unsafe.Read(nativeFieldPtr.ToPointer()), false); +#if USE_AOT + TField[] fieldValue = (TField[])field.GetValue(fieldOwner); +#else + ref TField[] fieldValue = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); +#endif + MarshalHelper.ToManaged(ref fieldValue, Unsafe.Read(nativeFieldPtr.ToPointer()), false); +#if USE_AOT + FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); +#endif } internal static void ToManagedFieldArrayReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class @@ -840,8 +901,15 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); - ref TField[] fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); - MarshalHelper.ToManaged(ref fieldValueRef, Unsafe.Read(nativeFieldPtr.ToPointer()), false); +#if USE_AOT + TField[] fieldValue = null; +#else + ref TField[] fieldValue = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); +#endif + MarshalHelper.ToManaged(ref fieldValue, Unsafe.Read(nativeFieldPtr.ToPointer()), false); +#if USE_AOT + FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); +#endif } internal static void ToNativeFieldValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct @@ -855,11 +923,11 @@ namespace FlaxEngine.Interop } #if USE_AOT - TField fieldValueRef = (TField)field.GetValue(fieldOwner); + TField fieldValue = (TField)field.GetValue(fieldOwner); #else - ref TField fieldValueRef = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); + ref TField fieldValue = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); #endif - MarshalHelper.ToNative(ref fieldValueRef, nativeFieldPtr); + MarshalHelper.ToNative(ref fieldValue, nativeFieldPtr); } internal static void ToNativeFieldReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class @@ -873,11 +941,11 @@ namespace FlaxEngine.Interop } #if USE_AOT - TField fieldValueRef = (TField)field.GetValue(fieldOwner); + TField fieldValue = (TField)field.GetValue(fieldOwner); #else - ref TField fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); + ref TField fieldValue = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); #endif - MarshalHelper.ToNative(ref fieldValueRef, nativeFieldPtr); + MarshalHelper.ToNative(ref fieldValue, nativeFieldPtr); } } @@ -907,8 +975,15 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); - ref TField fieldValueRef = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); - MarshalHelper.ToManaged(ref fieldValueRef, Unsafe.Read(nativeFieldPtr.ToPointer()), false); +#if USE_AOT + TField fieldValue = null; +#else + ref TField fieldValue = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); +#endif + MarshalHelper.ToManaged(ref fieldValue, Unsafe.Read(nativeFieldPtr.ToPointer()), false); +#if USE_AOT + FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); +#endif } internal static void ToManagedFieldReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class @@ -918,8 +993,15 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); - ref TField fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); - MarshalHelper.ToManaged(ref fieldValueRef, Unsafe.Read(nativeFieldPtr.ToPointer()), false); +#if USE_AOT + TField fieldValue = default; +#else + ref TField fieldValue = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); +#endif + MarshalHelper.ToManaged(ref fieldValue, Unsafe.Read(nativeFieldPtr.ToPointer()), false); +#if USE_AOT + FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); +#endif } internal static void ToManagedFieldArrayValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct @@ -929,8 +1011,15 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); - ref TField[] fieldValueRef = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); - MarshalHelper.ToManaged(ref fieldValueRef, Unsafe.Read(nativeFieldPtr.ToPointer()), false); +#if USE_AOT + TField[] fieldValue = null; +#else + ref TField[] fieldValue = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); +#endif + MarshalHelper.ToManaged(ref fieldValue, Unsafe.Read(nativeFieldPtr.ToPointer()), false); +#if USE_AOT + FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); +#endif } internal static void ToManagedFieldArrayReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class @@ -940,8 +1029,15 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); - ref TField[] fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); - MarshalHelper.ToManaged(ref fieldValueRef, Unsafe.Read(nativeFieldPtr.ToPointer()), false); +#if USE_AOT + TField[] fieldValue = null; +#else + ref TField[] fieldValue = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); +#endif + MarshalHelper.ToManaged(ref fieldValue, Unsafe.Read(nativeFieldPtr.ToPointer()), false); +#if USE_AOT + FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); +#endif } internal static void ToNativeFieldValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct @@ -951,8 +1047,12 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); - ref TField fieldValueRef = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); - MarshalHelper.ToNative(ref fieldValueRef, nativeFieldPtr); +#if USE_AOT + TField fieldValue = (TField)field.GetValue(fieldOwner); +#else + ref TField fieldValue = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); +#endif + MarshalHelper.ToNative(ref fieldValue, nativeFieldPtr); } internal static void ToNativeFieldReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class @@ -962,8 +1062,12 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); - ref TField fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); - MarshalHelper.ToNative(ref fieldValueRef, nativeFieldPtr); +#if USE_AOT + TField fieldValue = (TField)field.GetValue(fieldOwner); +#else + ref TField fieldValue = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); +#endif + MarshalHelper.ToNative(ref fieldValue, nativeFieldPtr); } } } @@ -1047,7 +1151,7 @@ namespace FlaxEngine.Interop var fields = MarshalHelper.marshallableFields; var offsets = MarshalHelper.marshallableFieldOffsets; var marshallers = MarshalHelper.toNativeFieldMarshallers; - for (int i = 0; i < MarshalHelper.marshallableFields.Length; i++) + for (int i = 0; i < fields.Length; i++) { marshallers[i](fields[i], offsets[i], ref managedValue, nativePtr, out int fieldSize); nativePtr += fieldSize; @@ -1309,11 +1413,13 @@ namespace FlaxEngine.Interop return RuntimeHelpers.GetUninitializedObject(wrappedType); } +#if !USE_AOT internal object CreateScriptingObject(IntPtr unmanagedPtr, IntPtr idPtr) { object obj = RuntimeHelpers.GetUninitializedObject(wrappedType); if (obj is Object) { + // TODO: use UnsafeAccessorAttribute on .NET 8 and use this path on all platforms (including non-Desktop, see MCore::ScriptingObject::CreateScriptingObject) { ref IntPtr fieldRef = ref FieldHelper.GetReferenceTypeFieldReference(unmanagedPtrFieldOffset, ref obj); fieldRef = unmanagedPtr; @@ -1334,6 +1440,7 @@ namespace FlaxEngine.Interop return obj; } +#endif public static implicit operator Type(TypeHolder holder) => holder?.type; public bool Equals(TypeHolder other) => type == other.type; diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index 1d2dc1af1..a111ae337 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -186,7 +186,7 @@ void* GetStaticMethodPointer(const String& methodName); /// Calls the managed static method in NativeInterop class with given parameters. /// template -inline RetType CallStaticMethodByName(const String& methodName, Args... args) +FORCE_INLINE RetType CallStaticMethodByName(const String& methodName, Args... args) { typedef RetType (CORECLR_DELEGATE_CALLTYPE* fun)(Args...); return ((fun)GetStaticMethodPointer(methodName))(args...); @@ -196,7 +196,7 @@ inline RetType CallStaticMethodByName(const String& methodName, Args... args) /// Calls the managed static method with given parameters. /// template -inline RetType CallStaticMethod(void* methodPtr, Args... args) +FORCE_INLINE RetType CallStaticMethod(void* methodPtr, Args... args) { typedef RetType (CORECLR_DELEGATE_CALLTYPE* fun)(Args...); return ((fun)methodPtr)(args...); @@ -629,14 +629,33 @@ bool MCore::Type::IsReference(MType* type) void MCore::ScriptingObject::SetInternalValues(MClass* klass, MObject* object, void* unmanagedPtr, const Guid* id) { +#if PLATFORM_DESKTOP && !USE_MONO_AOT static void* ScriptingObjectSetInternalValuesPtr = GetStaticMethodPointer(TEXT("ScriptingObjectSetInternalValues")); CallStaticMethod(ScriptingObjectSetInternalValuesPtr, object, unmanagedPtr, id); +#else + const MField* monoUnmanagedPtrField = klass->GetField("__unmanagedPtr"); + if (monoUnmanagedPtrField) + monoUnmanagedPtrField->SetValue(object, &unmanagedPtr); + const MField* monoIdField = klass->GetField("__internalId"); + if (id != nullptr && monoIdField) + monoIdField->SetValue(object, (void*)id); +#endif } MObject* MCore::ScriptingObject::CreateScriptingObject(MClass* klass, void* unmanagedPtr, const Guid* id) { +#if PLATFORM_DESKTOP && !USE_MONO_AOT static void* ScriptingObjectSetInternalValuesPtr = GetStaticMethodPointer(TEXT("ScriptingObjectCreate")); return CallStaticMethod(ScriptingObjectSetInternalValuesPtr, klass->_handle, unmanagedPtr, id); +#else + MObject* object = MCore::Object::New(klass); + if (object) + { + MCore::ScriptingObject::SetInternalValues(klass, object, unmanagedPtr, id); + MCore::Object::Init(object); + } + return object; +#endif } const MAssembly::ClassesDictionary& MAssembly::GetClasses() const @@ -1253,8 +1272,8 @@ void MField::GetValue(MObject* instance, void* result) const void MField::GetValueReference(MObject* instance, void* result) const { - static void* FieldGetValueReferencePtr = GetStaticMethodPointer(TEXT("FieldGetValueReferenceWithOffset")); - CallStaticMethod(FieldGetValueReferencePtr, instance, _fieldOffset, result); + static void* FieldGetValueReferencePtr = GetStaticMethodPointer(TEXT("FieldGetValueReference")); + CallStaticMethod(FieldGetValueReferencePtr, instance, _handle, _fieldOffset, result); } MObject* MField::GetValueBoxed(MObject* instance) const diff --git a/Source/Engine/Scripting/ScriptingObject.cpp b/Source/Engine/Scripting/ScriptingObject.cpp index c32f37066..ac88db1bf 100644 --- a/Source/Engine/Scripting/ScriptingObject.cpp +++ b/Source/Engine/Scripting/ScriptingObject.cpp @@ -241,7 +241,7 @@ ScriptingObject* ScriptingObject::ToNative(MObject* obj) #if USE_CSHARP if (obj) { -#if USE_MONO +#if USE_MONO || USE_MONO_AOT const auto ptrField = MCore::Object::GetClass(obj)->GetField(ScriptingObject_unmanagedPtr); CHECK_RETURN(ptrField, nullptr); ptrField->GetValue(obj, &ptr); diff --git a/Source/Engine/UI/UICanvas.cpp b/Source/Engine/UI/UICanvas.cpp index b3318c75c..a83d61f7a 100644 --- a/Source/Engine/UI/UICanvas.cpp +++ b/Source/Engine/UI/UICanvas.cpp @@ -56,6 +56,7 @@ UICanvas::UICanvas(const SpawnParams& params) UICanvas_EndPlay = mclass->GetMethod("EndPlay"); UICanvas_ParentChanged = mclass->GetMethod("ParentChanged"); UICanvas_Serialize = mclass->GetMethod("Serialize"); + Platform::MemoryBarrier(); } #endif } From 1986f2b58b0ddad7b6783742a728b63e5ae91a68 Mon Sep 17 00:00:00 2001 From: MineBill Date: Wed, 11 Oct 2023 17:06:16 +0300 Subject: [PATCH 16/34] Only set WS_CAPTION if the window is a regular window --- Source/Engine/Platform/Windows/WindowsWindow.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Source/Engine/Platform/Windows/WindowsWindow.cpp b/Source/Engine/Platform/Windows/WindowsWindow.cpp index 1bc50f207..8d6cbdf18 100644 --- a/Source/Engine/Platform/Windows/WindowsWindow.cpp +++ b/Source/Engine/Platform/Windows/WindowsWindow.cpp @@ -108,8 +108,7 @@ WindowsWindow::WindowsWindow(const CreateWindowSettings& settings) style |= WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_SYSMENU | WS_THICKFRAME | WS_GROUP; #elif WINDOWS_USE_NEWER_BORDER_LESS if (settings.IsRegularWindow) - style |= WS_THICKFRAME | WS_SYSMENU; - style |= WS_CAPTION; + style |= WS_THICKFRAME | WS_SYSMENU | WS_CAPTION; #endif exStyle |= WS_EX_WINDOWEDGE; } From dad3e1f77da66bfad200cf5897a256ee2fa6b1de Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 11 Oct 2023 17:17:46 +0200 Subject: [PATCH 17/34] Revert f1d57e47cb7e86596cf9cdb376d7002d8d0cfe6c in favor of #1670 --- Source/Engine/Platform/Windows/WindowsWindow.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Source/Engine/Platform/Windows/WindowsWindow.cpp b/Source/Engine/Platform/Windows/WindowsWindow.cpp index 8d6cbdf18..fb9fbe09d 100644 --- a/Source/Engine/Platform/Windows/WindowsWindow.cpp +++ b/Source/Engine/Platform/Windows/WindowsWindow.cpp @@ -219,12 +219,6 @@ void WindowsWindow::Show() if (!_settings.HasBorder) { SetWindowPos(_handle, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - if (!_settings.IsRegularWindow && _settings.ShowAfterFirstPaint && _settings.StartPosition == WindowStartPosition::Manual) - { - int32 x = Math::TruncToInt(_settings.Position.X); - int32 y = Math::TruncToInt(_settings.Position.Y); - SetWindowPos(_handle, nullptr, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER); - } } #endif From 6dd9f0f0368f2d4a309383b7f6f6dee58a4f37d0 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 11 Oct 2023 17:25:32 +0200 Subject: [PATCH 18/34] Improve #1667 to log exception --- Source/Editor/Undo/Actions/AddRemoveScriptAction.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Undo/Actions/AddRemoveScriptAction.cs b/Source/Editor/Undo/Actions/AddRemoveScriptAction.cs index fb9f33619..a5710494c 100644 --- a/Source/Editor/Undo/Actions/AddRemoveScriptAction.cs +++ b/Source/Editor/Undo/Actions/AddRemoveScriptAction.cs @@ -53,9 +53,11 @@ namespace FlaxEditor.Actions { _scriptData = FlaxEngine.Json.JsonSerializer.Serialize(script); } - catch + catch (Exception ex) { _scriptData = null; + Debug.LogError("Failed to serialize script data for Undo due to exception"); + Debug.LogException(ex); } _parentId = script.Actor.ID; _orderInParent = script.OrderInParent; From 8f3a5bd74a9028c1640f8392874444bf08c02245 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 11 Oct 2023 17:41:35 +0200 Subject: [PATCH 19/34] Improve ObjectsRemovalService to handle newly added objects removing --- Source/Engine/Core/ObjectsRemovalService.cpp | 29 +++++++++++++++---- .../Internal/EngineInternalCalls.cpp | 1 - 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Source/Engine/Core/ObjectsRemovalService.cpp b/Source/Engine/Core/ObjectsRemovalService.cpp index bb3fd8bf1..a020f7844 100644 --- a/Source/Engine/Core/ObjectsRemovalService.cpp +++ b/Source/Engine/Core/ObjectsRemovalService.cpp @@ -5,7 +5,6 @@ #include "Collections/Dictionary.h" #include "Engine/Engine/Time.h" #include "Engine/Engine/EngineService.h" -#include "Engine/Threading/Threading.h" #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Scripting/ScriptingObject.h" @@ -14,16 +13,15 @@ const Char* HertzSizesData[] = { TEXT("Hz"), TEXT("KHz"), TEXT("MHz"), TEXT("GHz Span Utilities::Private::BytesSizes(BytesSizesData, ARRAY_COUNT(BytesSizesData)); Span Utilities::Private::HertzSizes(HertzSizesData, ARRAY_COUNT(HertzSizesData)); -namespace ObjectsRemovalServiceImpl +namespace { CriticalSection PoolLocker; DateTime LastUpdate; float LastUpdateGameTime; Dictionary Pool(8192); + uint64 PoolCounter = 0; } -using namespace ObjectsRemovalServiceImpl; - class ObjectsRemoval : public EngineService { public: @@ -64,6 +62,7 @@ void ObjectsRemovalService::Add(Object* obj, float timeToLive, bool useGameTime) PoolLocker.Lock(); Pool[obj] = timeToLive; + PoolCounter++; PoolLocker.Unlock(); } @@ -72,6 +71,7 @@ void ObjectsRemovalService::Flush(float dt, float gameDelta) PROFILE_CPU(); PoolLocker.Lock(); + PoolCounter = 0; // Update timeouts and delete objects that timed out for (auto i = Pool.Begin(); i.IsNotEnd(); ++i) @@ -90,6 +90,24 @@ void ObjectsRemovalService::Flush(float dt, float gameDelta) } } + // If any object was added to the pool while removing objects (by this thread) then retry removing any nested objects (but without delta time) + if (PoolCounter != 0) + { + RETRY: + PoolCounter = 0; + for (auto i = Pool.Begin(); i.IsNotEnd(); ++i) + { + if (i->Value <= 0.0f) + { + Object* obj = i->Key; + Pool.Remove(i); + obj->OnDeleteObject(); + } + } + if (PoolCounter != 0) + goto RETRY; + } + PoolLocker.Unlock(); } @@ -121,7 +139,7 @@ void ObjectsRemoval::Dispose() // Delete all remaining objects { - ScopeLock lock(PoolLocker); + PoolLocker.Lock(); for (auto i = Pool.Begin(); i.IsNotEnd(); ++i) { Object* obj = i->Key; @@ -129,6 +147,7 @@ void ObjectsRemoval::Dispose() obj->OnDeleteObject(); } Pool.Clear(); + PoolLocker.Unlock(); } } diff --git a/Source/Engine/Scripting/Internal/EngineInternalCalls.cpp b/Source/Engine/Scripting/Internal/EngineInternalCalls.cpp index 27bb8aa47..e3e5b4342 100644 --- a/Source/Engine/Scripting/Internal/EngineInternalCalls.cpp +++ b/Source/Engine/Scripting/Internal/EngineInternalCalls.cpp @@ -190,7 +190,6 @@ DEFINE_INTERNAL_CALL(bool) ScriptingInternal_IsTypeFromGameScripts(MTypeObject* DEFINE_INTERNAL_CALL(void) ScriptingInternal_FlushRemovedObjects() { - ASSERT(IsInMainThread()); ObjectsRemovalService::Flush(); } From fa96707c578e681dd90517d98d063e3a32d60388 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 11 Oct 2023 18:39:51 +0200 Subject: [PATCH 20/34] Fix crash when implementing `INetworkSerializable` in C#-only #1664 --- .../Engine/Networking/NetworkReplicator.cpp | 36 ++++++++++++++++--- Source/Engine/Scripting/ScriptingObject.cpp | 13 ++++--- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/Source/Engine/Networking/NetworkReplicator.cpp b/Source/Engine/Networking/NetworkReplicator.cpp index 4d85238e3..1e9ea5b79 100644 --- a/Source/Engine/Networking/NetworkReplicator.cpp +++ b/Source/Engine/Networking/NetworkReplicator.cpp @@ -258,18 +258,32 @@ void NetworkReplicationService::Dispose() NetworkReplicationService NetworkReplicationServiceInstance; -void INetworkSerializable_Serialize(void* instance, NetworkStream* stream, void* tag) +void INetworkSerializable_Native_Serialize(void* instance, NetworkStream* stream, void* tag) { const int16 vtableOffset = (int16)(intptr)tag; ((INetworkSerializable*)((byte*)instance + vtableOffset))->Serialize(stream); } -void INetworkSerializable_Deserialize(void* instance, NetworkStream* stream, void* tag) +void INetworkSerializable_Native_Deserialize(void* instance, NetworkStream* stream, void* tag) { const int16 vtableOffset = (int16)(intptr)tag; ((INetworkSerializable*)((byte*)instance + vtableOffset))->Deserialize(stream); } +void INetworkSerializable_Script_Serialize(void* instance, NetworkStream* stream, void* tag) +{ + auto obj = (ScriptingObject*)instance; + auto interface = ScriptingObject::ToInterface(obj); + interface->Serialize(stream); +} + +void INetworkSerializable_Script_Deserialize(void* instance, NetworkStream* stream, void* tag) +{ + auto obj = (ScriptingObject*)instance; + auto interface = ScriptingObject::ToInterface(obj); + interface->Deserialize(stream); +} + NetworkReplicatedObject* ResolveObject(Guid objectId) { auto it = Objects.Find(objectId); @@ -1064,9 +1078,21 @@ bool NetworkReplicator::InvokeSerializer(const ScriptingTypeHandle& typeHandle, const ScriptingType::InterfaceImplementation* interface = type.GetInterface(INetworkSerializable::TypeInitializer); if (interface) { - serializer.Methods[0] = INetworkSerializable_Serialize; - serializer.Methods[1] = INetworkSerializable_Deserialize; - serializer.Tags[0] = serializer.Tags[1] = (void*)(intptr)interface->VTableOffset; // Pass VTableOffset to the callback + if (interface->IsNative) + { + // Native interface (implemented in C++) + serializer.Methods[0] = INetworkSerializable_Native_Serialize; + serializer.Methods[1] = INetworkSerializable_Native_Deserialize; + serializer.Tags[0] = serializer.Tags[1] = (void*)(intptr)interface->VTableOffset; // Pass VTableOffset to the callback + } + else + { + // Generic interface (implemented in C# or elsewhere) + ASSERT(type.Type == ScriptingTypes::Script); + serializer.Methods[0] = INetworkSerializable_Script_Serialize; + serializer.Methods[1] = INetworkSerializable_Script_Deserialize; + serializer.Tags[0] = serializer.Tags[1] = nullptr; + } SerializersTable.Add(typeHandle, serializer); } else if (const ScriptingTypeHandle baseTypeHandle = typeHandle.GetType().GetBaseType()) diff --git a/Source/Engine/Scripting/ScriptingObject.cpp b/Source/Engine/Scripting/ScriptingObject.cpp index ac88db1bf..59ac26484 100644 --- a/Source/Engine/Scripting/ScriptingObject.cpp +++ b/Source/Engine/Scripting/ScriptingObject.cpp @@ -6,6 +6,7 @@ #include "BinaryModule.h" #include "Engine/Level/Actor.h" #include "Engine/Core/Log.h" +#include "Engine/Core/Types/Pair.h" #include "Engine/Utilities/StringConverter.h" #include "Engine/Content/Asset.h" #include "Engine/Content/Content.h" @@ -25,7 +26,8 @@ #define ScriptingObject_id "__internalId" // TODO: don't leak memory (use some kind of late manual GC for those wrapper objects) -Dictionary ScriptingObjectsInterfaceWrappers; +typedef Pair ScriptingObjectsInterfaceKey; +Dictionary ScriptingObjectsInterfaceWrappers; SerializableScriptingObject::SerializableScriptingObject(const SpawnParams& params) : ScriptingObject(params) @@ -202,10 +204,10 @@ ScriptingObject* ScriptingObject::FromInterface(void* interfaceObj, const Script } // Special case for interface wrapper object - for (auto& e : ScriptingObjectsInterfaceWrappers) + for (const auto& e : ScriptingObjectsInterfaceWrappers) { if (e.Value == interfaceObj) - return e.Key; + return e.Key.First; } return nullptr; @@ -226,10 +228,11 @@ void* ScriptingObject::ToInterface(ScriptingObject* obj, const ScriptingTypeHand else if (interface) { // Interface implemented in scripting (eg. C# class inherits C++ interface) - if (!ScriptingObjectsInterfaceWrappers.TryGet(obj, result)) + const ScriptingObjectsInterfaceKey key(obj, interfaceType); + if (!ScriptingObjectsInterfaceWrappers.TryGet(key, result)) { result = interfaceType.GetType().Interface.GetInterfaceWrapper(obj); - ScriptingObjectsInterfaceWrappers.Add(obj, result); + ScriptingObjectsInterfaceWrappers.Add(key, result); } } return result; From 3ed28998e9840c2f6d8888e1bc0b93ae9df69db6 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Thu, 21 Sep 2023 21:28:55 +0300 Subject: [PATCH 21/34] Add more descriptive deprecation messages --- .../CustomEditors/Elements/DoubleValueElement.cs | 2 +- .../CustomEditors/Elements/FloatValueElement.cs | 2 +- Source/Engine/Graphics/Mesh.cs | 12 ++++++------ Source/Engine/Graphics/SkinnedMesh.cs | 6 +++--- Source/Engine/Physics/CollisionData.cs | 6 +++--- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Source/Editor/CustomEditors/Elements/DoubleValueElement.cs b/Source/Editor/CustomEditors/Elements/DoubleValueElement.cs index e46040a42..07af5e991 100644 --- a/Source/Editor/CustomEditors/Elements/DoubleValueElement.cs +++ b/Source/Editor/CustomEditors/Elements/DoubleValueElement.cs @@ -22,7 +22,7 @@ namespace FlaxEditor.CustomEditors.Elements /// /// [Deprecated on 26.05.2022, expires on 26.05.2024] /// - [System.Obsolete("Deprecated in 1.4")] + [System.Obsolete("Deprecated in 1.4, use ValueBox instead")] public DoubleValueBox DoubleValue => ValueBox; /// diff --git a/Source/Editor/CustomEditors/Elements/FloatValueElement.cs b/Source/Editor/CustomEditors/Elements/FloatValueElement.cs index 552e9d125..789d8966e 100644 --- a/Source/Editor/CustomEditors/Elements/FloatValueElement.cs +++ b/Source/Editor/CustomEditors/Elements/FloatValueElement.cs @@ -22,7 +22,7 @@ namespace FlaxEditor.CustomEditors.Elements /// /// [Deprecated on 26.05.2022, expires on 26.05.2024] /// - [System.Obsolete("Deprecated in 1.4, ValueBox instead")] + [System.Obsolete("Deprecated in 1.4, use ValueBox instead")] public FloatValueBox FloatValue => ValueBox; /// diff --git a/Source/Engine/Graphics/Mesh.cs b/Source/Engine/Graphics/Mesh.cs index 0a986d44d..68ff7e07f 100644 --- a/Source/Engine/Graphics/Mesh.cs +++ b/Source/Engine/Graphics/Mesh.cs @@ -339,7 +339,7 @@ namespace FlaxEngine /// The normal vectors (per vertex). Use null to compute them from normal vectors. /// The texture coordinates (per vertex). /// The vertex colors (per vertex). - [Obsolete("Deprecated in 1.4")] + [Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")] public void UpdateMesh(Vector3[] vertices, int[] triangles, Vector3[] normals = null, Vector3[] tangents = null, Vector2[] uv = null, Color32[] colors = null) { UpdateMesh(Utils.ConvertCollection(vertices), triangles, Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv), colors); @@ -357,7 +357,7 @@ namespace FlaxEngine /// The normal vectors (per vertex). Use null to compute them from normal vectors. /// The texture coordinates (per vertex). /// The vertex colors (per vertex). - [Obsolete("Deprecated in 1.4")] + [Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")] public void UpdateMesh(List vertices, List triangles, List normals = null, List tangents = null, List uv = null, List colors = null) { UpdateMesh(Utils.ConvertCollection(vertices), triangles, Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv), colors); @@ -375,7 +375,7 @@ namespace FlaxEngine /// The normal vectors (per vertex). Use null to compute them from normal vectors. /// The texture coordinates (per vertex). /// The vertex colors (per vertex). - [Obsolete("Deprecated in 1.4")] + [Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")] public void UpdateMesh(Vector3[] vertices, uint[] triangles, Vector3[] normals = null, Vector3[] tangents = null, Vector2[] uv = null, Color32[] colors = null) { UpdateMesh(Utils.ConvertCollection(vertices), triangles, Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv), colors); @@ -393,7 +393,7 @@ namespace FlaxEngine /// The normal vectors (per vertex). Use null to compute them from normal vectors. /// The texture coordinates (per vertex). /// The vertex colors (per vertex). - [Obsolete("Deprecated in 1.4")] + [Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")] public void UpdateMesh(List vertices, List triangles, List normals = null, List tangents = null, List uv = null, List colors = null) { UpdateMesh(Utils.ConvertCollection(vertices), triangles, Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv), colors); @@ -411,7 +411,7 @@ namespace FlaxEngine /// The tangent vectors (per vertex). Use null to compute them from normal vectors. /// The texture coordinates (per vertex). /// The vertex colors (per vertex). - [Obsolete("Deprecated in 1.4")] + [Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")] public void UpdateMesh(Vector3[] vertices, ushort[] triangles, Vector3[] normals = null, Vector3[] tangents = null, Vector2[] uv = null, Color32[] colors = null) { UpdateMesh(Utils.ConvertCollection(vertices), triangles, Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv), colors); @@ -429,7 +429,7 @@ namespace FlaxEngine /// The tangent vectors (per vertex). Use null to compute them from normal vectors. /// The texture coordinates (per vertex). /// The vertex colors (per vertex). - [Obsolete("Deprecated in 1.4")] + [Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")] public void UpdateMesh(List vertices, List triangles, List normals = null, List tangents = null, List uv = null, List colors = null) { UpdateMesh(Utils.ConvertCollection(vertices), triangles, Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv), colors); diff --git a/Source/Engine/Graphics/SkinnedMesh.cs b/Source/Engine/Graphics/SkinnedMesh.cs index 8fb7a83dc..a7b7594bb 100644 --- a/Source/Engine/Graphics/SkinnedMesh.cs +++ b/Source/Engine/Graphics/SkinnedMesh.cs @@ -216,7 +216,7 @@ namespace FlaxEngine /// The normal vectors (per vertex). /// The normal vectors (per vertex). Use null to compute them from normal vectors. /// The texture coordinates (per vertex). - [Obsolete("Deprecated in 1.4")] + [Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")] public void UpdateMesh(Vector3[] vertices, int[] triangles, Int4[] blendIndices, Vector4[] blendWeights, Vector3[] normals = null, Vector3[] tangents = null, Vector2[] uv = null) { UpdateMesh(Utils.ConvertCollection(vertices), triangles, blendIndices, Utils.ConvertCollection(blendWeights), Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv)); @@ -235,7 +235,7 @@ namespace FlaxEngine /// The normal vectors (per vertex). /// The normal vectors (per vertex). Use null to compute them from normal vectors. /// The texture coordinates (per vertex). - [Obsolete("Deprecated in 1.4")] + [Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")] public void UpdateMesh(Vector3[] vertices, uint[] triangles, Int4[] blendIndices, Vector4[] blendWeights, Vector3[] normals = null, Vector3[] tangents = null, Vector2[] uv = null) { UpdateMesh(Utils.ConvertCollection(vertices), triangles, blendIndices, Utils.ConvertCollection(blendWeights), Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv)); @@ -254,7 +254,7 @@ namespace FlaxEngine /// The normal vectors (per vertex). /// The tangent vectors (per vertex). Use null to compute them from normal vectors. /// The texture coordinates (per vertex). - [Obsolete("Deprecated in 1.4")] + [Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")] public void UpdateMesh(Vector3[] vertices, ushort[] triangles, Int4[] blendIndices, Vector4[] blendWeights, Vector3[] normals = null, Vector3[] tangents = null, Vector2[] uv = null) { UpdateMesh(Utils.ConvertCollection(vertices), triangles, blendIndices, Utils.ConvertCollection(blendWeights), Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv)); diff --git a/Source/Engine/Physics/CollisionData.cs b/Source/Engine/Physics/CollisionData.cs index 8b54c6218..e7f76a90f 100644 --- a/Source/Engine/Physics/CollisionData.cs +++ b/Source/Engine/Physics/CollisionData.cs @@ -19,7 +19,7 @@ namespace FlaxEngine /// The convex mesh generation flags. /// The convex mesh vertex limit. Use values in range [8;255] /// True if failed, otherwise false. - [Obsolete("Deprecated in 1.4")] + [Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")] public bool CookCollision(CollisionDataType type, Vector3[] vertices, uint[] triangles, ConvexMeshGenerationFlags convexFlags = ConvexMeshGenerationFlags.None, int convexVertexLimit = 255) { if (vertices == null) @@ -43,7 +43,7 @@ namespace FlaxEngine /// The convex mesh generation flags. /// The convex mesh vertex limit. Use values in range [8;255] /// True if failed, otherwise false. - [Obsolete("Deprecated in 1.4")] + [Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")] public bool CookCollision(CollisionDataType type, Vector3[] vertices, int[] triangles, ConvexMeshGenerationFlags convexFlags = ConvexMeshGenerationFlags.None, int convexVertexLimit = 255) { if (vertices == null) @@ -60,7 +60,7 @@ namespace FlaxEngine /// /// The output vertex buffer. /// The output index buffer. - [Obsolete("Deprecated in 1.4")] + [Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")] public void ExtractGeometry(out Vector3[] vertexBuffer, out int[] indexBuffer) { ExtractGeometry(out Float3[] tmp, out indexBuffer); From 02a219a376d4362885f34a02a3c001f793e678db Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 17 Sep 2023 17:05:20 +0300 Subject: [PATCH 22/34] Fix Editor viewport camera transformation getting corrupted when focused --- Source/Editor/Viewport/EditorViewport.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs index 13c06157a..e20069120 100644 --- a/Source/Editor/Viewport/EditorViewport.cs +++ b/Source/Editor/Viewport/EditorViewport.cs @@ -1119,7 +1119,12 @@ namespace FlaxEditor.Viewport var win = (WindowRootControl)Root; // Get current mouse position in the view - _viewMousePos = PointFromWindow(win.MousePosition); + { + // When the window is not focused, the position in window does not return sane values + Float2 pos = PointFromWindow(win.MousePosition); + if (!float.IsInfinity(pos.LengthSquared)) + _viewMousePos = pos; + } // Update input var window = win.Window; From f2c9ba5a00e56962d711b1768b08a83317a8f80b Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Wed, 11 Oct 2023 15:33:32 -0500 Subject: [PATCH 23/34] Focus parent on value box slide end. --- Source/Editor/GUI/Input/ValueBox.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Editor/GUI/Input/ValueBox.cs b/Source/Editor/GUI/Input/ValueBox.cs index 492887611..321782a8e 100644 --- a/Source/Editor/GUI/Input/ValueBox.cs +++ b/Source/Editor/GUI/Input/ValueBox.cs @@ -182,6 +182,7 @@ namespace FlaxEditor.GUI.Input } SlidingEnd?.Invoke(); Defocus(); + Parent?.Focus(); } /// From 8eb9df9a18b928b197ec1cc77617a90f64a65c5f Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Wed, 11 Oct 2023 15:57:02 -0500 Subject: [PATCH 24/34] Change new anim port to TryGetBox. --- Source/Editor/Surface/Archetypes/Animation.cs | 20 ++++++++++++++----- .../Animations/Graph/AnimGroup.Animation.cpp | 17 +++++++++------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/Animation.cs b/Source/Editor/Surface/Archetypes/Animation.cs index a05ede1e7..5743b2a84 100644 --- a/Source/Editor/Surface/Archetypes/Animation.cs +++ b/Source/Editor/Surface/Archetypes/Animation.cs @@ -59,8 +59,11 @@ namespace FlaxEditor.Surface.Archetypes if (Surface != null) { _assetSelect = GetChild(); - _assetBox = GetBox(8); - _assetSelect.Visible = !_assetBox.HasAnyConnection; + if (TryGetBox(8, out var box)) + { + _assetBox = box; + _assetSelect.Visible = !_assetBox.HasAnyConnection; + } UpdateTitle(); } } @@ -68,7 +71,11 @@ namespace FlaxEditor.Surface.Archetypes private void UpdateTitle() { var asset = Editor.Instance.ContentDatabase.Find((Guid)Values[0]); - Title = _assetBox.HasAnyConnection || asset == null ? "Animation" : asset.ShortName; + if (_assetBox != null) + Title = _assetBox.HasAnyConnection || asset == null ? "Animation" : asset.ShortName; + else + Title = asset?.ShortName ?? "Animation"; + var style = Style.Current; Resize(Mathf.Max(230, style.FontLarge.MeasureText(Title).X + 30), 160); } @@ -78,8 +85,11 @@ namespace FlaxEditor.Surface.Archetypes { base.ConnectionTick(box); - if (box.ID != _assetBox.ID) - return; + if (_assetBox != null) + { + if (box.ID != _assetBox.ID) + return; + } _assetSelect.Visible = !box.HasAnyConnection; UpdateTitle(); diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp index a19b84370..6e4783d2c 100644 --- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp +++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp @@ -764,14 +764,17 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu const float startTimePos = (float)tryGetValue(node->GetBox(7), node->Values[3]); // Override animation when animation reference box is connected - auto animationAssetBox = node->GetBox(8); - if (animationAssetBox->HasConnection()) + auto animationAssetBox = node->TryGetBox(8); + if (animationAssetBox) { - const Value assetBoxValue = tryGetValue(animationAssetBox, Value::Null); - if (assetBoxValue != Value::Null) - anim = (Animation*)assetBoxValue.AsAsset; - else - anim = nullptr; + if (animationAssetBox->HasConnection()) + { + const Value assetBoxValue = tryGetValue(animationAssetBox, Value::Null); + if (assetBoxValue != Value::Null) + anim = (Animation*)assetBoxValue.AsAsset; + else + anim = nullptr; + } } const float length = anim ? anim->GetLength() : 0.0f; From 28d6fe84efde592e384579c27059bca3d5b20f45 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Wed, 11 Oct 2023 16:17:59 -0500 Subject: [PATCH 25/34] Small change --- Source/Editor/Surface/Archetypes/Animation.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/Animation.cs b/Source/Editor/Surface/Archetypes/Animation.cs index 5743b2a84..40a3d2a63 100644 --- a/Source/Editor/Surface/Archetypes/Animation.cs +++ b/Source/Editor/Surface/Archetypes/Animation.cs @@ -85,11 +85,10 @@ namespace FlaxEditor.Surface.Archetypes { base.ConnectionTick(box); - if (_assetBox != null) - { - if (box.ID != _assetBox.ID) - return; - } + if (_assetBox == null) + return; + if (box.ID != _assetBox.ID) + return; _assetSelect.Visible = !box.HasAnyConnection; UpdateTitle(); From e97ec74bf8035da4d09ad505b3e8d44981853643 Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Wed, 11 Oct 2023 18:37:04 -0400 Subject: [PATCH 26/34] clean code --- Source/Editor/Tools/Terrain/PaintTerrainGizmo.cs | 4 +--- Source/Editor/Tools/Terrain/PaintTerrainGizmoMode.cs | 4 ++-- Source/Editor/Tools/Terrain/SculptTerrainGizmo.cs | 4 +--- Source/Editor/Tools/Terrain/SculptTerrainGizmoMode.cs | 4 ++-- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Source/Editor/Tools/Terrain/PaintTerrainGizmo.cs b/Source/Editor/Tools/Terrain/PaintTerrainGizmo.cs index dd837fe00..c9a521734 100644 --- a/Source/Editor/Tools/Terrain/PaintTerrainGizmo.cs +++ b/Source/Editor/Tools/Terrain/PaintTerrainGizmo.cs @@ -153,9 +153,7 @@ namespace FlaxEditor.Tools.Terrain // Increase or decrease brush size with scroll if (Input.GetKey(KeyboardKeys.Shift)) { - var currentBrush = Mode.CurrentBrush; - currentBrush.Size += dt * currentBrush.Size * Input.Mouse.ScrollDelta * 5f; - Mode.CurrentBrush = currentBrush; + Mode.CurrentBrush.Size += dt * Mode.CurrentBrush.Size * Input.Mouse.ScrollDelta * 5f; } // Check if no terrain is selected diff --git a/Source/Editor/Tools/Terrain/PaintTerrainGizmoMode.cs b/Source/Editor/Tools/Terrain/PaintTerrainGizmoMode.cs index a68b90ce8..1d1bf87ca 100644 --- a/Source/Editor/Tools/Terrain/PaintTerrainGizmoMode.cs +++ b/Source/Editor/Tools/Terrain/PaintTerrainGizmoMode.cs @@ -139,9 +139,9 @@ namespace FlaxEditor.Tools.Terrain } /// - /// Gets or set the current brush. + /// Gets the current brush. /// - public Brush CurrentBrush { get => _brushes[(int)_brushType]; set => _brushes[(int)_brushType] = value; } + public Brush CurrentBrush => _brushes[(int)_brushType]; /// /// Gets the circle brush instance. diff --git a/Source/Editor/Tools/Terrain/SculptTerrainGizmo.cs b/Source/Editor/Tools/Terrain/SculptTerrainGizmo.cs index 837c86dcb..fef8bbf09 100644 --- a/Source/Editor/Tools/Terrain/SculptTerrainGizmo.cs +++ b/Source/Editor/Tools/Terrain/SculptTerrainGizmo.cs @@ -161,9 +161,7 @@ namespace FlaxEditor.Tools.Terrain // Increase or decrease brush size with scroll if (Input.GetKey(KeyboardKeys.Shift)) { - var currentBrush = Mode.CurrentBrush; - currentBrush.Size += dt * currentBrush.Size * Input.Mouse.ScrollDelta * 5f; - Mode.CurrentBrush = currentBrush; + Mode.CurrentBrush.Size += dt * Mode.CurrentBrush.Size * Input.Mouse.ScrollDelta * 5f; } // Check if selected terrain was changed during painting diff --git a/Source/Editor/Tools/Terrain/SculptTerrainGizmoMode.cs b/Source/Editor/Tools/Terrain/SculptTerrainGizmoMode.cs index b99ac135f..4b19cfbde 100644 --- a/Source/Editor/Tools/Terrain/SculptTerrainGizmoMode.cs +++ b/Source/Editor/Tools/Terrain/SculptTerrainGizmoMode.cs @@ -158,9 +158,9 @@ namespace FlaxEditor.Tools.Terrain } /// - /// Gets or set the current brush. + /// Gets the current brush. /// - public Brush CurrentBrush { get => _brushes[(int)_brushType]; set => _brushes[(int)_brushType] = value; } + public Brush CurrentBrush => _brushes[(int)_brushType]; /// /// Gets the circle brush instance. From b1ad2c3a02771ddd7d94f73a5c5a0476474c4517 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 12 Oct 2023 12:10:21 +0200 Subject: [PATCH 27/34] Fix sprite shadow to match the sprite facing camera #1504 --- Source/Engine/UI/SpriteRender.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/UI/SpriteRender.cpp b/Source/Engine/UI/SpriteRender.cpp index fb4f54e7f..25446c9c5 100644 --- a/Source/Engine/UI/SpriteRender.cpp +++ b/Source/Engine/UI/SpriteRender.cpp @@ -113,7 +113,7 @@ void SpriteRender::Draw(RenderContext& renderContext) auto model = _quadModel.As(); if (model->GetLoadedLODs() == 0) return; - const auto& view = renderContext.View; + const auto& view = (renderContext.LodProxyView ? *renderContext.LodProxyView : renderContext.View); Matrix m1, m2, m3, world; Matrix::Scaling(_size.X, _size.Y, 1.0f, m2); Matrix::RotationY(PI, m3); From 0175186c2783dd2f28ba9b39d3def897a2b40f62 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 12 Oct 2023 12:17:55 +0200 Subject: [PATCH 28/34] Improve #1627 to return proper anim length --- .../Animations/Graph/AnimGroup.Animation.cpp | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp index 6e4783d2c..0518fe248 100644 --- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp +++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #include "AnimGraph.h" +#include "Engine/Core/Types/VariantValueCast.h" #include "Engine/Content/Assets/Animation.h" #include "Engine/Content/Assets/SkeletonMask.h" #include "Engine/Content/Assets/AnimationGraphFunction.h" @@ -753,6 +754,13 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu auto anim = node->Assets[0].As(); auto& bucket = context.Data->State[node->BucketIndex].Animation; + // Override animation when animation reference box is connected + auto animationAssetBox = node->TryGetBox(8); + if (animationAssetBox && animationAssetBox->HasConnection()) + { + anim = TVariantValueCast::Cast(tryGetValue(animationAssetBox, Value::Null)); + } + switch (box->ID) { // Animation @@ -762,21 +770,6 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu const float speed = (float)tryGetValue(node->GetBox(5), node->Values[1]); const bool loop = (bool)tryGetValue(node->GetBox(6), node->Values[2]); const float startTimePos = (float)tryGetValue(node->GetBox(7), node->Values[3]); - - // Override animation when animation reference box is connected - auto animationAssetBox = node->TryGetBox(8); - if (animationAssetBox) - { - if (animationAssetBox->HasConnection()) - { - const Value assetBoxValue = tryGetValue(animationAssetBox, Value::Null); - if (assetBoxValue != Value::Null) - anim = (Animation*)assetBoxValue.AsAsset; - else - anim = nullptr; - } - } - const float length = anim ? anim->GetLength() : 0.0f; // Calculate new time position From b19bf57dfb0aba4d1306f7b5eab03a5e313d4434 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 12 Oct 2023 13:10:34 +0200 Subject: [PATCH 29/34] Add logging any XAudio2 backed errors --- .../Audio/XAudio2/AudioBackendXAudio2.cpp | 61 ++++++++++++------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp b/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp index f90c58875..988a1797a 100644 --- a/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp +++ b/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp @@ -27,7 +27,15 @@ #define MAX_INPUT_CHANNELS 2 #define MAX_OUTPUT_CHANNELS 8 #define MAX_CHANNELS_MATRIX_SIZE (MAX_INPUT_CHANNELS*MAX_OUTPUT_CHANNELS) - +#if BUILD_RELEASE +#define XAUDIO2_CHECK_ERROR(method) +#else +#define XAUDIO2_CHECK_ERROR(method) \ + if (hr != 0) \ + { \ + LOG(Error, "XAudio2 method {0} failed with error 0x{1:X} (at line {2})", TEXT(#method), hr, __LINE__ - 1); \ + } +#endif #define FLAX_COORD_SCALE 0.01f // units are meters #define FLAX_DST_TO_XAUDIO(x) x * FLAX_COORD_SCALE #define FLAX_POS_TO_XAUDIO(vec) X3DAUDIO_VECTOR(vec.X * FLAX_COORD_SCALE, vec.Y * FLAX_COORD_SCALE, vec.Z * FLAX_COORD_SCALE) @@ -263,10 +271,7 @@ namespace XAudio2 } const HRESULT hr = aSource->Voice->SubmitSourceBuffer(&buffer); - if (FAILED(hr)) - { - LOG(Warning, "XAudio2: Failed to submit source buffer (error: 0x{0:x})", hr); - } + XAUDIO2_CHECK_ERROR(SubmitSourceBuffer); } void VoiceCallback::OnBufferEnd(void* pBufferContext) @@ -391,12 +396,10 @@ void AudioBackendXAudio2::Source_OnAdd(AudioSource* source) 1, &aSource->Destination }; - const HRESULT hr = XAudio2::Instance->CreateSourceVoice(&aSource->Voice, &aSource->Format, 0, 2.0f, &aSource->Callback, &sendList); + HRESULT hr = XAudio2::Instance->CreateSourceVoice(&aSource->Voice, &aSource->Format, 0, 2.0f, &aSource->Callback, &sendList); + XAUDIO2_CHECK_ERROR(CreateSourceVoice); if (FAILED(hr)) - { - LOG(Error, "Failed to create XAudio2 voice. Error: 0x{0:x}", hr); return; - } // Prepare source state aSource->Callback.Source = source; @@ -410,7 +413,8 @@ void AudioBackendXAudio2::Source_OnAdd(AudioSource* source) aSource->DopplerFactor = source->GetDopplerFactor(); aSource->UpdateTransform(source); aSource->UpdateVelocity(source); - aSource->Voice->SetVolume(source->GetVolume()); + hr = aSource->Voice->SetVolume(source->GetVolume()); + XAUDIO2_CHECK_ERROR(SetVolume); // 0 is invalid ID so shift them sourceID++; @@ -451,7 +455,8 @@ void AudioBackendXAudio2::Source_VolumeChanged(AudioSource* source) auto aSource = XAudio2::GetSource(source); if (aSource && aSource->Voice) { - aSource->Voice->SetVolume(source->GetVolume()); + const HRESULT hr = aSource->Voice->SetVolume(source->GetVolume()); + XAUDIO2_CHECK_ERROR(SetVolume); } } @@ -494,11 +499,16 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source) XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1]; XAudio2::Locker.Unlock(); + HRESULT hr; const bool isPlaying = source->IsActuallyPlayingSth(); if (isPlaying) - aSource->Voice->Stop(); + { + hr = aSource->Voice->Stop(); + XAUDIO2_CHECK_ERROR(Stop); + } - aSource->Voice->FlushSourceBuffers(); + hr = aSource->Voice->FlushSourceBuffers(); + XAUDIO2_CHECK_ERROR(FlushSourceBuffers); aSource->LastBufferStartSamplesPlayed = 0; aSource->BuffersProcessed = 0; @@ -517,7 +527,10 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source) XAudio2::QueueBuffer(aSource, source, bufferId, buffer); if (isPlaying) - aSource->Voice->Start(); + { + hr = aSource->Voice->Start(); + XAUDIO2_CHECK_ERROR(Start); + } } void AudioBackendXAudio2::Source_SpatialSetupChanged(AudioSource* source) @@ -572,7 +585,8 @@ void AudioBackendXAudio2::Source_Play(AudioSource* source) if (aSource && aSource->Voice && !aSource->IsPlaying) { // Play - aSource->Voice->Start(); + const HRESULT hr = aSource->Voice->Start(); + XAUDIO2_CHECK_ERROR(Start); aSource->IsPlaying = true; } } @@ -583,7 +597,8 @@ void AudioBackendXAudio2::Source_Pause(AudioSource* source) if (aSource && aSource->Voice && aSource->IsPlaying) { // Pause - aSource->Voice->Stop(); + const HRESULT hr = aSource->Voice->Stop(); + XAUDIO2_CHECK_ERROR(Stop); aSource->IsPlaying = false; } } @@ -596,11 +611,13 @@ void AudioBackendXAudio2::Source_Stop(AudioSource* source) aSource->StartTime = 0.0f; // Pause - aSource->Voice->Stop(); + HRESULT hr = aSource->Voice->Stop(); + XAUDIO2_CHECK_ERROR(Stop); aSource->IsPlaying = false; // Unset streaming buffers to rewind - aSource->Voice->FlushSourceBuffers(); + hr = aSource->Voice->FlushSourceBuffers(); + XAUDIO2_CHECK_ERROR(FlushSourceBuffers); aSource->BuffersProcessed = 0; aSource->Callback.PeekSamples(); } @@ -697,10 +714,7 @@ void AudioBackendXAudio2::Source_DequeueProcessedBuffers(AudioSource* source) if (aSource && aSource->Voice) { const HRESULT hr = aSource->Voice->FlushSourceBuffers(); - if (FAILED(hr)) - { - LOG(Warning, "XAudio2: FlushSourceBuffers failed. Error: 0x{0:x}", hr); - } + XAUDIO2_CHECK_ERROR(FlushSourceBuffers); aSource->BuffersProcessed = 0; } } @@ -779,7 +793,8 @@ void AudioBackendXAudio2::Base_SetVolume(float value) { if (XAudio2::MasteringVoice) { - XAudio2::MasteringVoice->SetVolume(value); + const HRESULT hr = XAudio2::MasteringVoice->SetVolume(value); + XAUDIO2_CHECK_ERROR(SetVolume); } } From 749c0cacb40c0175cbe9533f314bcb4a7f717862 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 12 Oct 2023 13:11:07 +0200 Subject: [PATCH 30/34] Fix audio playback in XAudio2 when clip is 3D but source is 2D --- Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp b/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp index 988a1797a..1998b8e5e 100644 --- a/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp +++ b/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp @@ -380,7 +380,7 @@ void AudioBackendXAudio2::Source_OnAdd(AudioSource* source) const auto& header = clip->AudioHeader; auto& format = aSource->Format; format.wFormatTag = WAVE_FORMAT_PCM; - format.nChannels = source->Is3D() ? 1 : header.Info.NumChannels; // 3d audio is always mono (AudioClip auto-converts before buffer write) + format.nChannels = clip->Is3D() ? 1 : header.Info.NumChannels; // 3d audio is always mono (AudioClip auto-converts before buffer write) format.nSamplesPerSec = header.Info.SampleRate; format.wBitsPerSample = header.Info.BitDepth; format.nBlockAlign = (WORD)(format.nChannels * (format.wBitsPerSample / 8)); From 2671e3881fd1cf95532c877f2c85e03388116560 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 12 Oct 2023 14:03:13 +0200 Subject: [PATCH 31/34] Add `Spacebar` to toggle play/pause in Audio Clip window --- Source/Editor/Windows/Assets/AudioClipWindow.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Source/Editor/Windows/Assets/AudioClipWindow.cs b/Source/Editor/Windows/Assets/AudioClipWindow.cs index 8cf31f416..b1d9796dc 100644 --- a/Source/Editor/Windows/Assets/AudioClipWindow.cs +++ b/Source/Editor/Windows/Assets/AudioClipWindow.cs @@ -335,6 +335,22 @@ namespace FlaxEditor.Windows.Assets } } + /// + public override bool OnKeyDown(KeyboardKeys key) + { + if (base.OnKeyDown(key)) + return true; + + if (key == KeyboardKeys.Spacebar) + { + if (_previewSource?.State == AudioSource.States.Playing) + OnPause(); + else + OnPlay(); + } + return false; + } + /// public override bool UseLayoutData => true; From 69fb2c331f2d8966090ef29f97a98dcde24cd6c5 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 12 Oct 2023 14:03:43 +0200 Subject: [PATCH 32/34] Minor improvements to audio --- Source/Engine/Audio/AudioSource.cpp | 1 - Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Audio/AudioSource.cpp b/Source/Engine/Audio/AudioSource.cpp index afe5c4b49..cb32e0967 100644 --- a/Source/Engine/Audio/AudioSource.cpp +++ b/Source/Engine/Audio/AudioSource.cpp @@ -187,7 +187,6 @@ float AudioSource::GetTime() const return 0.0f; float time = AudioBackend::Source::GetCurrentBufferTime(this); - ASSERT(time >= 0.0f && time <= Clip->GetLength()); if (UseStreaming()) { diff --git a/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp b/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp index 1998b8e5e..c857b4064 100644 --- a/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp +++ b/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp @@ -27,14 +27,14 @@ #define MAX_INPUT_CHANNELS 2 #define MAX_OUTPUT_CHANNELS 8 #define MAX_CHANNELS_MATRIX_SIZE (MAX_INPUT_CHANNELS*MAX_OUTPUT_CHANNELS) -#if BUILD_RELEASE -#define XAUDIO2_CHECK_ERROR(method) -#else +#if ENABLE_ASSERTION #define XAUDIO2_CHECK_ERROR(method) \ if (hr != 0) \ { \ LOG(Error, "XAudio2 method {0} failed with error 0x{1:X} (at line {2})", TEXT(#method), hr, __LINE__ - 1); \ } +#else +#define XAUDIO2_CHECK_ERROR(method) #endif #define FLAX_COORD_SCALE 0.01f // units are meters #define FLAX_DST_TO_XAUDIO(x) x * FLAX_COORD_SCALE @@ -112,7 +112,9 @@ namespace XAudio2 COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE OnVoiceError(THIS_ void* pBufferContext, HRESULT Error) override { +#if ENABLE_ASSERTION LOG(Warning, "IXAudio2VoiceCallback::OnVoiceError! Error: 0x{0:x}", Error); +#endif } public: From 4ac65ee91cea59f03344688f147548d8f047fddb Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 12 Oct 2023 14:31:41 +0200 Subject: [PATCH 33/34] Fix audio preview for multi-channel audio clips --- Source/Editor/Viewport/Previews/AudioClipPreview.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/Viewport/Previews/AudioClipPreview.cs b/Source/Editor/Viewport/Previews/AudioClipPreview.cs index 446cef657..3235cd194 100644 --- a/Source/Editor/Viewport/Previews/AudioClipPreview.cs +++ b/Source/Editor/Viewport/Previews/AudioClipPreview.cs @@ -171,7 +171,7 @@ namespace FlaxEditor.Viewport.Previews case DrawModes.Fill: clipsInView = 1.0f; clipWidth = width; - samplesPerIndex = (uint)(samplesPerChannel / width); + samplesPerIndex = (uint)(samplesPerChannel / width) * info.NumChannels; break; case DrawModes.Single: clipsInView = Mathf.Min(clipsInView, 1.0f); From 455b3f2446b7694bb66dae9da54ae9bf5dae835d Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 12 Oct 2023 15:20:23 +0200 Subject: [PATCH 34/34] Fix XAudio2 playback when seeking audio start play location --- .../Audio/XAudio2/AudioBackendXAudio2.cpp | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp b/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp index c857b4064..3092a2229 100644 --- a/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp +++ b/Source/Engine/Audio/XAudio2/AudioBackendXAudio2.cpp @@ -31,7 +31,7 @@ #define XAUDIO2_CHECK_ERROR(method) \ if (hr != 0) \ { \ - LOG(Error, "XAudio2 method {0} failed with error 0x{1:X} (at line {2})", TEXT(#method), hr, __LINE__ - 1); \ + LOG(Error, "XAudio2 method {0} failed with error 0x{1:X} (at line {2})", TEXT(#method), (uint32)hr, __LINE__ - 1); \ } #else #define XAUDIO2_CHECK_ERROR(method) @@ -131,7 +131,8 @@ namespace XAudio2 XAUDIO2_SEND_DESCRIPTOR Destination; float Pitch; float Pan; - float StartTime; + float StartTimeForQueueBuffer; + float LastBufferStartTime; float DopplerFactor; uint64 LastBufferStartSamplesPlayed; int32 BuffersProcessed; @@ -155,7 +156,8 @@ namespace XAudio2 Destination.pOutputVoice = nullptr; Pitch = 1.0f; Pan = 0.0f; - StartTime = 0.0f; + StartTimeForQueueBuffer = 0.0f; + LastBufferStartTime = 0.0f; IsDirty = false; Is3D = false; IsPlaying = false; @@ -265,11 +267,14 @@ namespace XAudio2 buffer.pAudioData = aBuffer->Data.Get(); buffer.AudioBytes = aBuffer->Data.Count(); - if (aSource->StartTime > ZeroTolerance) + if (aSource->StartTimeForQueueBuffer > ZeroTolerance) { - buffer.PlayBegin = (UINT32)(aSource->StartTime * (aBuffer->Info.SampleRate * aBuffer->Info.NumChannels)); - buffer.PlayLength = aBuffer->Info.NumSamples / aBuffer->Info.NumChannels - buffer.PlayBegin; - aSource->StartTime = 0; + // Offset start position when playing buffer with a custom time offset + const uint32 bytesPerSample = aBuffer->Info.BitDepth / 8 * aBuffer->Info.NumChannels; + buffer.PlayBegin = (UINT32)(aSource->StartTimeForQueueBuffer * aBuffer->Info.SampleRate); + buffer.PlayLength = (buffer.AudioBytes / bytesPerSample) - buffer.PlayBegin; + aSource->LastBufferStartTime = aSource->StartTimeForQueueBuffer; + aSource->StartTimeForQueueBuffer = 0; } const HRESULT hr = aSource->Voice->SubmitSourceBuffer(&buffer); @@ -512,6 +517,7 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source) hr = aSource->Voice->FlushSourceBuffers(); XAUDIO2_CHECK_ERROR(FlushSourceBuffers); aSource->LastBufferStartSamplesPlayed = 0; + aSource->LastBufferStartTime = 0; aSource->BuffersProcessed = 0; XAUDIO2_BUFFER buffer = { 0 }; @@ -524,7 +530,7 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source) const UINT32 totalSamples = aBuffer->Info.NumSamples / aBuffer->Info.NumChannels; buffer.PlayBegin = state.SamplesPlayed % totalSamples; buffer.PlayLength = totalSamples - buffer.PlayBegin; - aSource->StartTime = 0; + aSource->StartTimeForQueueBuffer = 0; XAudio2::QueueBuffer(aSource, source, bufferId, buffer); @@ -610,7 +616,8 @@ void AudioBackendXAudio2::Source_Stop(AudioSource* source) auto aSource = XAudio2::GetSource(source); if (aSource && aSource->Voice) { - aSource->StartTime = 0.0f; + aSource->StartTimeForQueueBuffer = 0.0f; + aSource->LastBufferStartTime = 0.0f; // Pause HRESULT hr = aSource->Voice->Stop(); @@ -620,6 +627,7 @@ void AudioBackendXAudio2::Source_Stop(AudioSource* source) // Unset streaming buffers to rewind hr = aSource->Voice->FlushSourceBuffers(); XAUDIO2_CHECK_ERROR(FlushSourceBuffers); + Platform::Sleep(10); // TODO: find a better way to handle case when VoiceCallback::OnBufferEnd is called after source was stopped thus BuffersProcessed != 0, probably via buffers contexts ptrs aSource->BuffersProcessed = 0; aSource->Callback.PeekSamples(); } @@ -631,7 +639,7 @@ void AudioBackendXAudio2::Source_SetCurrentBufferTime(AudioSource* source, float if (aSource) { // Store start time so next buffer submitted will start from here (assumes audio is stopped) - aSource->StartTime = value; + aSource->StartTimeForQueueBuffer = value; } } @@ -647,8 +655,9 @@ float AudioBackendXAudio2::Source_GetCurrentBufferTime(const AudioSource* source aSource->Voice->GetState(&state); const uint32 numChannels = clipInfo.NumChannels; const uint32 totalSamples = clipInfo.NumSamples / numChannels; + const uint32 sampleRate = clipInfo.SampleRate;// / clipInfo.NumChannels; state.SamplesPlayed -= aSource->LastBufferStartSamplesPlayed % totalSamples; // Offset by the last buffer start to get time relative to its begin - time = aSource->StartTime + (state.SamplesPlayed % totalSamples) / static_cast(Math::Max(1U, clipInfo.SampleRate)); + time = aSource->LastBufferStartTime + (state.SamplesPlayed % totalSamples) / static_cast(Math::Max(1U, sampleRate)); } return time; } @@ -765,8 +774,7 @@ void AudioBackendXAudio2::Buffer_Write(uint32 bufferId, byte* samples, const Aud XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1]; XAudio2::Locker.Unlock(); - const uint32 bytesPerSample = info.BitDepth / 8; - const int32 samplesLength = info.NumSamples * bytesPerSample; + const uint32 samplesLength = info.NumSamples * info.BitDepth / 8; aBuffer->Info = info; aBuffer->Data.Set(samples, samplesLength);