diff --git a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl index 066815dfe..435675a9f 100644 --- a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl +++ b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl @@ -133,6 +133,8 @@ void PS_Forward( // Add lighting (apply ambient occlusion) output.rgb += light.rgb * gBuffer.AO; +#endif + #if USE_FOG // Calculate exponential height fog float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0); @@ -148,7 +150,5 @@ void PS_Forward( output = float4(lerp(float3(1, 1, 1), output.rgb, fog.aaa * fog.aaa), output.a); #endif -#endif - #endif } diff --git a/Source/Editor/CustomEditorWindow.cs b/Source/Editor/CustomEditorWindow.cs index 242b4d28d..5c3fedd6c 100644 --- a/Source/Editor/CustomEditorWindow.cs +++ b/Source/Editor/CustomEditorWindow.cs @@ -1,9 +1,9 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using FlaxEditor.CustomEditors; +using FlaxEditor.GUI.Docking; using FlaxEditor.Windows; using FlaxEngine.GUI; -using DockState = FlaxEditor.GUI.Docking.DockState; namespace FlaxEditor { @@ -97,9 +97,12 @@ namespace FlaxEditor /// Shows the window. /// /// Initial window state. - public void Show(DockState state = DockState.Float) + /// The panel to dock to, if any. + /// Only used if is set. If true the window will be selected after docking it. + /// The splitter value to use if toDock is not null. If not specified, a default value will be used. + public void Show(DockState state = DockState.Float, DockPanel toDock = null, bool autoSelect = true, float? splitterValue = null) { - _win.Show(state); + _win.Show(state, toDock, autoSelect, splitterValue); } } } diff --git a/Source/Editor/CustomEditors/Editors/ColorTrackball.cs b/Source/Editor/CustomEditors/Editors/ColorTrackball.cs index 8de972f86..836a1e9b8 100644 --- a/Source/Editor/CustomEditors/Editors/ColorTrackball.cs +++ b/Source/Editor/CustomEditors/Editors/ColorTrackball.cs @@ -3,6 +3,7 @@ using System.Linq; using FlaxEditor.CustomEditors.Elements; using FlaxEditor.GUI.Dialogs; +using FlaxEditor.GUI.Input; using FlaxEngine; using FlaxEngine.GUI; @@ -17,6 +18,7 @@ namespace FlaxEditor.CustomEditors.Editors private FloatValueElement _yElement; private FloatValueElement _zElement; private FloatValueElement _wElement; + private ColorValueBox _colorBox; private CustomElement _trackball; /// @@ -53,7 +55,7 @@ namespace FlaxEditor.CustomEditors.Editors gridControl.SlotPadding = new Margin(4, 2, 2, 2); gridControl.ClipChildren = false; gridControl.SlotsHorizontally = 1; - gridControl.SlotsVertically = 4; + gridControl.SlotsVertically = 5; LimitAttribute limit = null; var attributes = Values.GetAttributes(); @@ -61,7 +63,8 @@ namespace FlaxEditor.CustomEditors.Editors { limit = (LimitAttribute)attributes.FirstOrDefault(x => x is LimitAttribute); } - + _colorBox = grid.Custom().CustomControl; + _colorBox.ValueChanged += OnColorBoxChanged; _xElement = CreateFloatEditor(grid, limit, Color.Red); _yElement = CreateFloatEditor(grid, limit, Color.Green); _zElement = CreateFloatEditor(grid, limit, Color.Blue); @@ -93,6 +96,13 @@ namespace FlaxEditor.CustomEditors.Editors SetValue(value, token); } + private void OnColorBoxChanged() + { + var token = _colorBox.IsSliding ? this : null; + var color = _colorBox.Value; + SetValue(new Float4(color.R, color.G, color.B, color.A), token); + } + private void OnValueChanged() { if (IsSetBlocked) @@ -130,6 +140,7 @@ namespace FlaxEditor.CustomEditors.Editors _yElement.Value = color.Y; _zElement.Value = color.Z; _wElement.Value = scale; + _colorBox.Value = new Color(color.X, color.Y, color.Z, scale); _trackball.CustomControl.Color = Float3.Abs(color); } } diff --git a/Source/Editor/GUI/Docking/DockPanel.cs b/Source/Editor/GUI/Docking/DockPanel.cs index b04aad08c..df6a75bef 100644 --- a/Source/Editor/GUI/Docking/DockPanel.cs +++ b/Source/Editor/GUI/Docking/DockPanel.cs @@ -518,9 +518,9 @@ namespace FlaxEditor.GUI.Docking } } - internal virtual void DockWindowInternal(DockState state, DockWindow window) + internal virtual void DockWindowInternal(DockState state, DockWindow window, bool autoSelect = true, float? splitterValue = null) { - DockWindow(state, window); + DockWindow(state, window, autoSelect, splitterValue); } /// @@ -528,7 +528,9 @@ namespace FlaxEditor.GUI.Docking /// /// The state. /// The window. - protected virtual void DockWindow(DockState state, DockWindow window) + /// Whether or not to automatically select the window after docking it. + /// The splitter value to use when docking to window. + protected virtual void DockWindow(DockState state, DockWindow window, bool autoSelect = true, float? splitterValue = null) { CreateTabsProxy(); @@ -536,12 +538,12 @@ namespace FlaxEditor.GUI.Docking if (state == DockState.DockFill) { // Add tab - AddTab(window); + AddTab(window, autoSelect); } else { // Create child panel - var dockPanel = CreateChildPanel(state, DefaultSplitterValue); + var dockPanel = CreateChildPanel(state, splitterValue ?? DefaultSplitterValue); // Dock window as a tab in a child panel dockPanel.DockWindow(DockState.DockFill, window); diff --git a/Source/Editor/GUI/Docking/DockWindow.cs b/Source/Editor/GUI/Docking/DockWindow.cs index dd4e39ce2..15608d3e1 100644 --- a/Source/Editor/GUI/Docking/DockWindow.cs +++ b/Source/Editor/GUI/Docking/DockWindow.cs @@ -63,12 +63,9 @@ namespace FlaxEditor.GUI.Docking public bool IsHidden => !Visible || _dockedTo == null; /// - /// Gets the default window size. + /// Gets the default window size (in UI units, unscaled by DPI which is handled by windowing system). /// - /// - /// Scaled by the DPI, because the window should be large enough for its content on every monitor - /// - public virtual Float2 DefaultSize => new Float2(900, 580) * DpiScale; + public virtual Float2 DefaultSize => new Float2(900, 580); /// /// Gets the serialization typename. @@ -217,7 +214,9 @@ namespace FlaxEditor.GUI.Docking /// /// Initial window state. /// Panel to dock to it. - public void Show(DockState state = DockState.Float, DockPanel toDock = null) + /// Only used if is set. If true the window will be selected after docking it. + /// Only used if is set. The splitter value to use. If not specified, a default value will be used. + public void Show(DockState state = DockState.Float, DockPanel toDock = null, bool autoSelect = true, float? splitterValue = null) { if (state == DockState.Hidden) { @@ -235,7 +234,7 @@ namespace FlaxEditor.GUI.Docking Undock(); // Then dock - (toDock ?? _masterPanel).DockWindowInternal(state, this); + (toDock ?? _masterPanel).DockWindowInternal(state, this, autoSelect, splitterValue); OnShow(); PerformLayout(); } diff --git a/Source/Editor/GUI/Row.cs b/Source/Editor/GUI/Row.cs index f6bd5b02a..ca45ec6f5 100644 --- a/Source/Editor/GUI/Row.cs +++ b/Source/Editor/GUI/Row.cs @@ -24,6 +24,11 @@ namespace FlaxEditor.GUI /// public object[] Values { get; set; } + /// + /// Gets or sets the cell background colors. Null if unused, transparent values are ignored. + /// + public Color[] BackgroundColors { get; set; } + /// /// Gets or sets the row depth level. /// @@ -58,6 +63,7 @@ namespace FlaxEditor.GUI { float x = 0; int end = Mathf.Min(Values.Length, _table.Columns.Length); + var backgroundColors = BackgroundColors; for (int i = 0; i < end; i++) { var column = _table.Columns[i]; @@ -98,6 +104,8 @@ namespace FlaxEditor.GUI rect.Width -= leftDepthMargin; Render2D.PushClip(rect); + if (backgroundColors != null && backgroundColors[i].A > 0) + Render2D.FillRectangle(rect, backgroundColors[i]); Render2D.DrawText(style.FontMedium, text, rect, style.Foreground, column.CellAlignment, TextAlignment.Center); Render2D.PopClip(); diff --git a/Source/Editor/Modules/WindowsModule.cs b/Source/Editor/Modules/WindowsModule.cs index cda83b56e..a935e73f2 100644 --- a/Source/Editor/Modules/WindowsModule.cs +++ b/Source/Editor/Modules/WindowsModule.cs @@ -36,6 +36,22 @@ namespace FlaxEditor.Modules { public string AssemblyName; public string TypeName; + + public DockState DockState; + public DockPanel DockedTo; + public float? SplitterValue = null; + + public bool SelectOnShow = false; + + public bool Maximize; + public bool Minimize; + public Float2 FloatSize; + public Float2 FloatPosition; + + // Constructor, to allow for default values + public WindowRestoreData() + { + } } private readonly List _restoreWindows = new List(); @@ -676,7 +692,9 @@ namespace FlaxEditor.Modules if (newLocation == DockState.Float) { // Check if there is a floating window that has the same size - var defaultSize = window.DefaultSize; + var dpi = (float)Platform.Dpi / 96.0f; + var dpiScale = Platform.CustomDpiScale; + var defaultSize = window.DefaultSize * dpi; for (var i = 0; i < Editor.UI.MasterPanel.FloatingPanels.Count; i++) { var win = Editor.UI.MasterPanel.FloatingPanels[i]; @@ -688,7 +706,7 @@ namespace FlaxEditor.Modules } } - window.ShowFloating(defaultSize); + window.ShowFloating(defaultSize * dpiScale); } else { @@ -800,10 +818,38 @@ namespace FlaxEditor.Modules if (constructor == null || type.IsGenericType) return; - WindowRestoreData winData; + var winData = new WindowRestoreData(); + var panel = win.Window.ParentDockPanel; + + // Ensure that this window is only selected following recompilation + // if it was the active tab in its dock panel. Otherwise, there is a + // risk of interrupting the user's workflow by potentially selecting + // background tabs. + winData.SelectOnShow = panel.SelectedTab == win.Window; + if (panel is FloatWindowDockPanel) + { + winData.DockState = DockState.Float; + var window = win.Window.RootWindow.Window; + winData.FloatPosition = window.Position; + winData.FloatSize = window.ClientSize; + winData.Maximize = window.IsMaximized; + winData.Minimize = window.IsMinimized; + } + else + { + if (panel.TabsCount > 1) + { + winData.DockState = DockState.DockFill; + winData.DockedTo = panel; + }else + { + winData.DockState = panel.TryGetDockState(out var splitterValue); + winData.DockedTo = panel.ParentDockPanel; + winData.SplitterValue = splitterValue; + } + } winData.AssemblyName = type.Assembly.GetName().Name; winData.TypeName = type.FullName; - // TODO: cache and restore docking info _restoreWindows.Add(winData); } @@ -822,7 +868,24 @@ namespace FlaxEditor.Modules if (type != null) { var win = (CustomEditorWindow)Activator.CreateInstance(type); - win.Show(); + win.Show(winData.DockState, winData.DockedTo, winData.SelectOnShow, winData.SplitterValue); + if (winData.DockState == DockState.Float) + { + var window = win.Window.RootWindow.Window; + window.Position = winData.FloatPosition; + if (winData.Maximize) + { + window.Maximize(); + } + else if (winData.Minimize) + { + window.Minimize(); + } + else + { + window.ClientSize = winData.FloatSize; + } + } } } } diff --git a/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs b/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs index 478439e0e..f263d4734 100644 --- a/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs +++ b/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs @@ -386,6 +386,7 @@ namespace FlaxEditor.Windows.Assets // Spawn it Spawn(actor); + Rename(); } /// @@ -415,6 +416,7 @@ namespace FlaxEditor.Windows.Assets // Create undo action var action = new CustomDeleteActorsAction(new List(1) { actorNode }, true); Undo.AddAction(action); + Select(actorNode); } private void OnTreeRightClick(TreeNode node, Float2 location) diff --git a/Source/Editor/Windows/Profiler/CPU.cs b/Source/Editor/Windows/Profiler/CPU.cs index 0cbb3fa9b..ba569f04f 100644 --- a/Source/Editor/Windows/Profiler/CPU.cs +++ b/Source/Editor/Windows/Profiler/CPU.cs @@ -452,7 +452,6 @@ namespace FlaxEditor.Windows.Profiler var data = _events.Get(_mainChart.SelectedSampleIndex); if (data == null || data.Length == 0) return; - float totalTimeMs = _mainChart.SelectedSample; // Add rows @@ -501,17 +500,24 @@ namespace FlaxEditor.Windows.Profiler row = new Row { Values = new object[6], + BackgroundColors = new Color[6], }; + for (int k = 0; k < row.BackgroundColors.Length; k++) + row.BackgroundColors[k] = Color.Transparent; } { // Event row.Values[0] = name; // Total (%) - row.Values[1] = (int)(time / totalTimeMs * 1000.0f) / 10.0f; + float rowTotalTimePerc = (float)(time / totalTimeMs); + row.Values[1] = (int)(rowTotalTimePerc * 1000.0f) / 10.0f; + row.BackgroundColors[1] = Color.Red.AlphaMultiplied(Mathf.Min(1, rowTotalTimePerc) * 0.5f); // Self (%) - row.Values[2] = (int)((time - subEventsTimeTotal) / time * 1000.0f) / 10.0f; + float rowSelfTimePerc = (float)((time - subEventsTimeTotal) / totalTimeMs); + row.Values[2] = (int)(rowSelfTimePerc * 1000.0f) / 10.0f; + row.BackgroundColors[2] = Color.Red.AlphaMultiplied(Mathf.Min(1, rowSelfTimePerc) * 0.5f); // Time ms row.Values[3] = (float)((time * 10000.0f) / 10000.0f); diff --git a/Source/Engine/Content/BinaryAsset.cpp b/Source/Engine/Content/BinaryAsset.cpp index 9519f73df..cf4aa36b6 100644 --- a/Source/Engine/Content/BinaryAsset.cpp +++ b/Source/Engine/Content/BinaryAsset.cpp @@ -150,9 +150,7 @@ void BinaryAsset::ClearDependencies() { auto asset = Cast(Content::GetAsset(e.First)); if (asset) - { asset->_dependantAssets.Remove(this); - } } Dependencies.Clear(); } @@ -387,6 +385,16 @@ bool BinaryAsset::SaveToAsset(const StringView& path, AssetInitData& data, bool if (binaryAsset) binaryAsset->_isSaving = false; + if (binaryAsset) + { + // Inform dependant asset (use cloned version because it might be modified by assets when they got reloaded) + auto dependantAssets = binaryAsset->_dependantAssets; + for (auto& e : dependantAssets) + { + e->OnDependencyModified(binaryAsset); + } + } + return result; } diff --git a/Source/Engine/Content/Storage/FlaxStorage.cpp b/Source/Engine/Content/Storage/FlaxStorage.cpp index 9d4691be1..df99418bb 100644 --- a/Source/Engine/Content/Storage/FlaxStorage.cpp +++ b/Source/Engine/Content/Storage/FlaxStorage.cpp @@ -963,6 +963,7 @@ bool FlaxStorage::Create(WriteStream* stream, const AssetInitData* data, int32 d // Asset Dependencies stream->WriteInt32(header.Dependencies.Count()); stream->WriteBytes(header.Dependencies.Get(), header.Dependencies.Count() * sizeof(Pair)); + static_assert(sizeof(Pair) == sizeof(Guid) + sizeof(DateTime), "Invalid data size."); } #if ASSETS_LOADING_EXTRA_VERIFICATION diff --git a/Source/Engine/Graphics/PostProcessSettings.cpp b/Source/Engine/Graphics/PostProcessSettings.cpp index a564bc85f..6e2b21045 100644 --- a/Source/Engine/Graphics/PostProcessSettings.cpp +++ b/Source/Engine/Graphics/PostProcessSettings.cpp @@ -207,13 +207,12 @@ void PostFxMaterialsSettings::BlendWith(PostFxMaterialsSettings& other, float we if (isHalf) { int32 indexSrc = 0; - const auto materialsSrc = other.Materials.Get(); + const AssetReference* materialsSrc = other.Materials.Get(); while (Materials.Count() != POST_PROCESS_SETTINGS_MAX_MATERIALS && indexSrc < other.Materials.Count()) { - if (materialsSrc[indexSrc]) - { - Materials.Add(materialsSrc[indexSrc]); - } + MaterialBase* mat = materialsSrc[indexSrc].Get(); + if (mat && !Materials.Contains(mat)) + Materials.Add(mat); indexSrc++; } } diff --git a/Source/Engine/Platform/Android/AndroidFileSystem.cpp b/Source/Engine/Platform/Android/AndroidFileSystem.cpp index a04fc0229..6ea5b394b 100644 --- a/Source/Engine/Platform/Android/AndroidFileSystem.cpp +++ b/Source/Engine/Platform/Android/AndroidFileSystem.cpp @@ -244,7 +244,7 @@ bool AndroidFileSystem::FileExists(const StringView& path) bool AndroidFileSystem::DeleteFile(const StringView& path) { const StringAsANSI<> pathANSI(*path, path.Length()); - return unlink(pathANSI.Get()) == 0; + return unlink(pathANSI.Get()) != 0; } uint64 AndroidFileSystem::GetFileSize(const StringView& path) diff --git a/Source/Engine/Platform/Apple/AppleFileSystem.cpp b/Source/Engine/Platform/Apple/AppleFileSystem.cpp index 9e306019a..0d36f1dfb 100644 --- a/Source/Engine/Platform/Apple/AppleFileSystem.cpp +++ b/Source/Engine/Platform/Apple/AppleFileSystem.cpp @@ -218,7 +218,7 @@ bool AppleFileSystem::FileExists(const StringView& path) bool AppleFileSystem::DeleteFile(const StringView& path) { const StringAsANSI<> pathANSI(*path, path.Length()); - return unlink(pathANSI.Get()) == 0; + return unlink(pathANSI.Get()) != 0; } uint64 AppleFileSystem::GetFileSize(const StringView& path) diff --git a/Source/Engine/Platform/Linux/LinuxFileSystem.cpp b/Source/Engine/Platform/Linux/LinuxFileSystem.cpp index 97cde4a1c..23d47a029 100644 --- a/Source/Engine/Platform/Linux/LinuxFileSystem.cpp +++ b/Source/Engine/Platform/Linux/LinuxFileSystem.cpp @@ -364,7 +364,7 @@ bool LinuxFileSystem::FileExists(const StringView& path) bool LinuxFileSystem::DeleteFile(const StringView& path) { const StringAsANSI<> pathANSI(*path, path.Length()); - return unlink(pathANSI.Get()) == 0; + return unlink(pathANSI.Get()) != 0; } uint64 LinuxFileSystem::GetFileSize(const StringView& path)