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)