Merge branch 'master' into 1.11

This commit is contained in:
Wojtek Figat
2025-06-05 18:03:17 +02:00
189 changed files with 4627 additions and 1426 deletions

View File

@@ -438,7 +438,6 @@ VertexOutput VS(TerrainVertexInput input)
// Apply world position offset per-vertex // Apply world position offset per-vertex
#if USE_POSITION_OFFSET #if USE_POSITION_OFFSET
output.Geometry.WorldPosition += material.PositionOffset; output.Geometry.WorldPosition += material.PositionOffset;
output.Geometry.PrevWorldPosition += material.PositionOffset;
output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix); output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
#endif #endif

View File

@@ -46,21 +46,26 @@ Follow the instructions below to compile and run the engine from source.
* Install Visual Studio Code * Install Visual Studio Code
* Install .NET 8 or 9 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)) * Install .NET 8 or 9 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
* Ubuntu: `sudo apt install dotnet-sdk-8.0` * Ubuntu: `sudo apt install dotnet-sdk-8.0`
* Fedora: `sudo dnf install dotnet-sdk-8.0`
* Arch: `sudo pacman -S dotnet-sdk-8.0 dotnet-runtime-8.0 dotnet-targeting-pack-8.0 dotnet-host` * Arch: `sudo pacman -S dotnet-sdk-8.0 dotnet-runtime-8.0 dotnet-targeting-pack-8.0 dotnet-host`
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/)) * Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
* Ubuntu: `sudo apt install vulkan-sdk` * Ubuntu: `sudo apt install vulkan-sdk`
* Arch: `sudo pacman -S spirv-tools vulkan-headers vulkan-tools vulkan-validation-layers` * Fedora: `sudo dnf install vulkan-headers vulkan-tools vulkan-validation-layers`
* Arch: `sudo pacman -S vulkan-headers vulkan-tools vulkan-validation-layers`
* Install Git with LFS * Install Git with LFS
* Ubuntu: `sudo apt-get install git git-lfs` * Ubuntu: `sudo apt-get install git git-lfs`
* Arch: `sudo pacman -S git git-lfs` * Arch: `sudo pacman -S git git-lfs`
* `git-lfs install` * `git-lfs install`
* Install the required packages: * Install the required packages:
* Ubuntu: `sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev zlib1g-dev` * Ubuntu: `sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev zlib1g-dev`
* Fedora: `sudo dnf install libX11-devel libXcursor-devel libXinerama-devel ghc-zlib-devel`
* Arch: `sudo pacman -S base-devel libx11 libxcursor libxinerama zlib` * Arch: `sudo pacman -S base-devel libx11 libxcursor libxinerama zlib`
* Install Clang compiler (version 6 or later): * Install Clang compiler (version 6 or later):
* Ubuntu: `sudo apt-get install clang lldb lld` * Ubuntu: `sudo apt-get install clang lldb lld`
* Fedora: `sudo dnf install clang llvm lldb lld`
* Arch: `sudo pacman -S clang lldb lld` * Arch: `sudo pacman -S clang lldb lld`
* Clone the repository (with LFS) * Clone the repository (with LFS)
* git-lfs clone https://github.com/FlaxEngine/FlaxEngine.git
* Run `./GenerateProjectFiles.sh` * Run `./GenerateProjectFiles.sh`
* Open workspace with Visual Code * Open workspace with Visual Code
* Build and run (configuration and task named `Flax|Editor.Linux.Development|x64`) * Build and run (configuration and task named `Flax|Editor.Linux.Development|x64`)

View File

@@ -14,6 +14,7 @@ namespace FlaxEditor.Content.Create
/// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" /> /// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" />
public class PrefabCreateEntry : CreateFileEntry public class PrefabCreateEntry : CreateFileEntry
{ {
/// <inheritdoc />
public override bool CanBeCreated => _options.RootActorType != null; public override bool CanBeCreated => _options.RootActorType != null;
/// <summary> /// <summary>

View File

@@ -145,7 +145,7 @@ namespace FlaxEditor.Content.GUI
set set
{ {
value = Mathf.Clamp(value, 0.3f, 3.0f); value = Mathf.Clamp(value, 0.3f, 3.0f);
if (!Mathf.NearEqual(value, _viewScale)) if (value != _viewScale)
{ {
_viewScale = value; _viewScale = value;
ViewScaleChanged?.Invoke(); ViewScaleChanged?.Invoke();

View File

@@ -10,11 +10,9 @@ using FlaxEngine;
namespace FlaxEditor.Content namespace FlaxEditor.Content
{ {
/// <summary> /// <summary>
/// Context proxy object for shader source files (represented by <see cref="ShaderSourceItem"/>). /// Base class for shader source files.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.ContentProxy" /> public abstract class ShaderBaseProxy : ContentProxy
[ContentContextMenu("New/Shader Source")]
public class ShaderSourceProxy : ContentProxy
{ {
/// <inheritdoc /> /// <inheritdoc />
public override bool CanCreate(ContentFolder targetLocation) public override bool CanCreate(ContentFolder targetLocation)
@@ -29,6 +27,21 @@ namespace FlaxEditor.Content
return targetLocation.ShortName == "Source" && prevTargetLocation.ShortName == "Shaders"; return targetLocation.ShortName == "Source" && prevTargetLocation.ShortName == "Shaders";
} }
/// <inheritdoc />
public override EditorWindow Open(Editor editor, ContentItem item)
{
Editor.Instance.CodeEditing.OpenFile(item.Path);
return null;
}
}
/// <summary>
/// Context proxy object for shader source files (represented by <see cref="ShaderSourceItem"/>).
/// </summary>
/// <seealso cref="FlaxEditor.Content.ContentProxy" />
[ContentContextMenu("New/Shader Source (.shader)")]
public class ShaderSourceProxy : ShaderBaseProxy
{
/// <inheritdoc /> /// <inheritdoc />
public override void Create(string outputPath, object arg) public override void Create(string outputPath, object arg)
{ {
@@ -44,13 +57,6 @@ namespace FlaxEditor.Content
File.WriteAllText(outputPath, shaderTemplate, Encoding.UTF8); File.WriteAllText(outputPath, shaderTemplate, Encoding.UTF8);
} }
/// <inheritdoc />
public override EditorWindow Open(Editor editor, ContentItem item)
{
Editor.Instance.CodeEditing.OpenFile(item.Path);
return null;
}
/// <inheritdoc /> /// <inheritdoc />
public override Color AccentColor => Color.FromRGB(0x7542f5); public override Color AccentColor => Color.FromRGB(0x7542f5);
@@ -66,4 +72,33 @@ namespace FlaxEditor.Content
return item is ShaderSourceItem; return item is ShaderSourceItem;
} }
} }
/// <summary>
/// Context proxy object for shader header files.
/// </summary>
/// <seealso cref="FlaxEditor.Content.ContentProxy" />
[ContentContextMenu("New/Shader Header (.hlsl)")]
public class ShaderHeaderProxy : ShaderBaseProxy
{
/// <inheritdoc />
public override void Create(string outputPath, object arg)
{
File.WriteAllText(outputPath, "\n", Encoding.UTF8);
}
/// <inheritdoc />
public override Color AccentColor => Color.FromRGB(0x2545a5);
/// <inheritdoc />
public override string FileExtension => "hlsl";
/// <inheritdoc />
public override string Name => "Shader Header";
/// <inheritdoc />
public override bool IsProxyFor(ContentItem item)
{
return false;
}
}
} }

View File

@@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using FlaxEditor.SceneGraph;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
@@ -52,6 +53,16 @@ namespace FlaxEditor.CustomEditors
/// </summary> /// </summary>
/// <param name="nodes">The nodes to select</param> /// <param name="nodes">The nodes to select</param>
public void Select(List<SceneGraph.SceneGraphNode> nodes); public void Select(List<SceneGraph.SceneGraphNode> nodes);
/// <summary>
/// Gets the current selection.
/// </summary>
public List<SceneGraphNode> Selection { get; }
/// <summary>
/// Indication of if the properties window is locked on specific objects.
/// </summary>
public bool LockSelection { get; set; }
} }
/// <summary> /// <summary>
@@ -81,6 +92,8 @@ namespace FlaxEditor.CustomEditors
Offsets = Margin.Zero; Offsets = Margin.Zero;
Pivot = Float2.Zero; Pivot = Float2.Zero;
IsScrollable = true; IsScrollable = true;
Spacing = Utilities.Constants.UIMargin;
Margin = new Margin(Utilities.Constants.UIMargin);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -95,7 +108,7 @@ namespace FlaxEditor.CustomEditors
{ {
FlaxEditor.Editor.LogWarning(ex); FlaxEditor.Editor.LogWarning(ex);
// Refresh layout on errors to reduce lgo spam // Refresh layout on errors to reduce log spam
_presenter.BuildLayout(); _presenter.BuildLayout();
} }

View File

@@ -9,7 +9,6 @@ using FlaxEditor.CustomEditors.Elements;
using FlaxEditor.GUI; using FlaxEditor.GUI;
using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Tree; using FlaxEditor.GUI.Tree;
using FlaxEditor.Modules;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Windows; using FlaxEditor.Windows;
using FlaxEditor.Windows.Assets; using FlaxEditor.Windows.Assets;
@@ -71,7 +70,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
// Display prefab UI (when displaying object inside Prefab Window then display only nested prefabs) // Display prefab UI (when displaying object inside Prefab Window then display only nested prefabs)
prefab.GetNestedObject(ref prefabObjectId, out var nestedPrefabId, out var nestedPrefabObjectId); prefab.GetNestedObject(ref prefabObjectId, out var nestedPrefabId, out var nestedPrefabObjectId);
var nestedPrefab = FlaxEngine.Content.Load<Prefab>(nestedPrefabId); var nestedPrefab = FlaxEngine.Content.Load<Prefab>(nestedPrefabId);
var panel = layout.CustomContainer<UniformGridPanel>(); var panel = layout.UniformGrid();
panel.CustomControl.Height = 20.0f; panel.CustomControl.Height = 20.0f;
panel.CustomControl.SlotsVertically = 1; panel.CustomControl.SlotsVertically = 1;
if (Presenter == Editor.Instance.Windows.PropertiesWin.Presenter || nestedPrefab) if (Presenter == Editor.Instance.Windows.PropertiesWin.Presenter || nestedPrefab)
@@ -133,35 +132,22 @@ namespace FlaxEditor.CustomEditors.Dedicated
var actor = (Actor)Values[0]; var actor = (Actor)Values[0];
var scriptType = TypeUtils.GetType(actor.TypeName); var scriptType = TypeUtils.GetType(actor.TypeName);
var item = scriptType.ContentItem; var item = scriptType.ContentItem;
if (Presenter.Owner is PropertiesWindow propertiesWindow) if (Presenter.Owner != null)
{ {
var lockButton = cm.AddButton(propertiesWindow.LockObjects ? "Unlock" : "Lock"); var lockButton = cm.AddButton(Presenter.Owner.LockSelection ? "Unlock" : "Lock");
lockButton.ButtonClicked += button => lockButton.ButtonClicked += button =>
{ {
propertiesWindow.LockObjects = !propertiesWindow.LockObjects; var owner = Presenter?.Owner;
if (owner == null)
return;
owner.LockSelection = !owner.LockSelection;
// Reselect current selection // Reselect current selection
if (!propertiesWindow.LockObjects && Editor.Instance.SceneEditing.SelectionCount > 0) if (!owner.LockSelection && owner.Selection.Count > 0)
{ {
var cachedSelection = Editor.Instance.SceneEditing.Selection.ToArray(); var cachedSelection = owner.Selection.ToList();
Editor.Instance.SceneEditing.Select(null); owner.Select(null);
Editor.Instance.SceneEditing.Select(cachedSelection); owner.Select(cachedSelection);
}
};
}
else if (Presenter.Owner is PrefabWindow prefabWindow)
{
var lockButton = cm.AddButton(prefabWindow.LockSelectedObjects ? "Unlock" : "Lock");
lockButton.ButtonClicked += button =>
{
prefabWindow.LockSelectedObjects = !prefabWindow.LockSelectedObjects;
// Reselect current selection
if (!prefabWindow.LockSelectedObjects && prefabWindow.Selection.Count > 0)
{
var cachedSelection = prefabWindow.Selection.ToList();
prefabWindow.Select(null);
prefabWindow.Select(cachedSelection);
} }
}; };
} }
@@ -258,6 +244,16 @@ namespace FlaxEditor.CustomEditors.Dedicated
else if (editor.Values[0] is SceneObject sceneObject) else if (editor.Values[0] is SceneObject sceneObject)
{ {
node.TextColor = sceneObject.HasPrefabLink ? FlaxEngine.GUI.Style.Current.ProgressNormal : FlaxEngine.GUI.Style.Current.BackgroundSelected; node.TextColor = sceneObject.HasPrefabLink ? FlaxEngine.GUI.Style.Current.ProgressNormal : FlaxEngine.GUI.Style.Current.BackgroundSelected;
if (editor.Values.Info != ScriptMemberInfo.Null)
{
if (editor.Values.GetAttributes().FirstOrDefault(x => x is EditorDisplayAttribute) is EditorDisplayAttribute editorDisplayAttribute && !string.IsNullOrEmpty(editorDisplayAttribute.Name))
node.Text = $"{Utilities.Utils.GetPropertyNameUI(editorDisplayAttribute.Name)} ({Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name)})";
else
node.Text = Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name);
}
else if (sceneObject is Actor actor)
node.Text = $"{actor.Name} ({Utilities.Utils.GetPropertyNameUI(sceneObject.GetType().Name)})";
else
node.Text = Utilities.Utils.GetPropertyNameUI(sceneObject.GetType().Name); node.Text = Utilities.Utils.GetPropertyNameUI(sceneObject.GetType().Name);
} }
// Array Item // Array Item
@@ -268,6 +264,11 @@ namespace FlaxEditor.CustomEditors.Dedicated
// Common type // Common type
else if (editor.Values.Info != ScriptMemberInfo.Null) else if (editor.Values.Info != ScriptMemberInfo.Null)
{ {
if (editor.Values.GetAttributes().FirstOrDefault(x => x is EditorDisplayAttribute) is EditorDisplayAttribute editorDisplayAttribute
&& !string.IsNullOrEmpty(editorDisplayAttribute.Name)
&& !editorDisplayAttribute.Name.Contains("_inline"))
node.Text = $"{Utilities.Utils.GetPropertyNameUI(editorDisplayAttribute.Name)} ({Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name)})";
else
node.Text = Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name); node.Text = Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name);
} }
// Custom type // Custom type
@@ -316,7 +317,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
var childEditor = editor.ChildrenEditors[i]; var childEditor = editor.ChildrenEditors[i];
// Special case for root actor transformation (can be applied only in Prefab editor, not in Level) // Special case for root actor transformation (can be applied only in Prefab editor, not in Level)
if (isActorEditorInLevel && childEditor.Values.Info.Name is "LocalPosition" or "LocalOrientation" or "LocalScale") if (isActorEditorInLevel && childEditor.Values.Info.Name is "LocalPosition" or "LocalOrientation" or "LocalScale" or "Name")
continue; continue;
var child = ProcessDiff(childEditor, !isScriptEditorWithRefValue); var child = ProcessDiff(childEditor, !isScriptEditorWithRefValue);
@@ -361,13 +362,39 @@ namespace FlaxEditor.CustomEditors.Dedicated
return result; return result;
} }
private TreeNode CreateDiffTree(Actor actor, CustomEditorPresenter presenter, LayoutElementsContainer layout)
{
var actorNode = Editor.Instance.Scene.GetActorNode(actor);
ValueContainer vc = new ValueContainer(ScriptMemberInfo.Null);
vc.SetType(new ScriptType(actorNode.EditableObject.GetType()));
vc.Add(actorNode.EditableObject);
var editor = CustomEditorsUtil.CreateEditor(vc, null, false);
editor.Initialize(presenter, layout, vc);
var node = ProcessDiff(editor, false);
layout.ClearLayout();
foreach (var child in actor.Children)
{
var childNode = CreateDiffTree(child, presenter, layout);
if (childNode == null)
continue;
if (node == null)
node = CreateDiffNode(editor);
node.AddChild(childNode);
}
return node;
}
private void ViewChanges(Control target, Float2 targetLocation) private void ViewChanges(Control target, Float2 targetLocation)
{ {
// Build a tree out of modified properties // Build a tree out of modified properties
var rootNode = ProcessDiff(this, false); var thisActor = (Actor)Values[0];
var rootActor = thisActor.IsPrefabRoot ? thisActor : thisActor.GetPrefabRoot();
var presenter = new CustomEditorPresenter(null);
var layout = new CustomElementsContainer<ContainerControl>();
var rootNode = CreateDiffTree(rootActor, presenter, layout);
// Skip if no changes detected // Skip if no changes detected
if (rootNode == null || rootNode.ChildrenCount == 0) if (rootNode == null)
{ {
var cm1 = new ContextMenu(); var cm1 = new ContextMenu();
cm1.AddButton("No changes detected"); cm1.AddButton("No changes detected");

View File

@@ -28,7 +28,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
_infoLabel = playbackGroup.Label(string.Empty).Label; _infoLabel = playbackGroup.Label(string.Empty).Label;
_infoLabel.AutoHeight = true; _infoLabel.AutoHeight = true;
var grid = playbackGroup.CustomContainer<UniformGridPanel>(); var grid = playbackGroup.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = Button.DefaultHeight; gridControl.Height = Button.DefaultHeight;

View File

@@ -59,7 +59,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
var paintValue = new ReadOnlyValueContainer(new ScriptType(typeof(ClothPaintingGizmoMode)), _gizmoMode); var paintValue = new ReadOnlyValueContainer(new ScriptType(typeof(ClothPaintingGizmoMode)), _gizmoMode);
paintGroup.Object(paintValue); paintGroup.Object(paintValue);
{ {
var grid = paintGroup.CustomContainer<UniformGridPanel>(); var grid = paintGroup.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = Button.DefaultHeight; gridControl.Height = Button.DefaultHeight;

View File

@@ -92,12 +92,14 @@ namespace FlaxEditor.CustomEditors.Dedicated
// Update add button // Update add button
var update = group.Button("Update").Button; var update = group.Button("Update").Button;
group.Space(0);
update.TooltipText = "Refreshes the dashboard statistics"; update.TooltipText = "Refreshes the dashboard statistics";
update.Height = 16.0f; update.Height = 16.0f;
update.Clicked += RebuildLayout; update.Clicked += RebuildLayout;
// New locale add button // New locale add button
var addLocale = group.Button("Add Locale...").Button; var addLocale = group.Button("Add Locale...").Button;
group.Space(0);
addLocale.TooltipText = "Shows a locale picker and creates new localization for it with not translated string tables"; addLocale.TooltipText = "Shows a locale picker and creates new localization for it with not translated string tables";
addLocale.Height = 16.0f; addLocale.Height = 16.0f;
addLocale.ButtonClicked += delegate(Button button) addLocale.ButtonClicked += delegate(Button button)
@@ -167,12 +169,14 @@ namespace FlaxEditor.CustomEditors.Dedicated
// Export button // Export button
var exportLocalization = group.Button("Export...").Button; var exportLocalization = group.Button("Export...").Button;
group.Space(0);
exportLocalization.TooltipText = "Exports the localization strings into .pot file for translation"; exportLocalization.TooltipText = "Exports the localization strings into .pot file for translation";
exportLocalization.Height = 16.0f; exportLocalization.Height = 16.0f;
exportLocalization.Clicked += () => Export(tableEntries, allKeys); exportLocalization.Clicked += () => Export(tableEntries, allKeys);
// Find localized strings in code button // Find localized strings in code button
var findStringsCode = group.Button("Find localized strings in code").Button; var findStringsCode = group.Button("Find localized strings in code").Button;
group.Space(0);
findStringsCode.TooltipText = "Searches for localized string usage in inside a project source files"; findStringsCode.TooltipText = "Searches for localized string usage in inside a project source files";
findStringsCode.Height = 16.0f; findStringsCode.Height = 16.0f;
findStringsCode.Clicked += delegate findStringsCode.Clicked += delegate

View File

@@ -55,7 +55,7 @@ public class ModelPrefabEditor : GenericEditor
// Creates the import path UI // Creates the import path UI
var group = layout.Group("Import Path"); var group = layout.Group("Import Path");
Utilities.Utils.CreateImportPathUI(group, modelPrefab.ImportPath, false); Utilities.Utils.CreateImportPathUI(group, modelPrefab.ImportPath);
var button = layout.Button("Reimport", "Reimports the source asset as prefab."); var button = layout.Button("Reimport", "Reimports the source asset as prefab.");
_reimportButton = button.Button; _reimportButton = button.Button;

View File

@@ -92,7 +92,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
_infoLabel = playbackGroup.Label(string.Empty).Label; _infoLabel = playbackGroup.Label(string.Empty).Label;
_infoLabel.AutoHeight = true; _infoLabel.AutoHeight = true;
var grid = playbackGroup.CustomContainer<UniformGridPanel>(); var grid = playbackGroup.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = Button.DefaultHeight; gridControl.Height = Button.DefaultHeight;

View File

@@ -39,7 +39,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
if (ragdoll.Parent is AnimatedModel animatedModel && animatedModel.SkinnedModel) if (ragdoll.Parent is AnimatedModel animatedModel && animatedModel.SkinnedModel)
{ {
// Builder // Builder
var grid = editorGroup.CustomContainer<UniformGridPanel>(); var grid = editorGroup.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = Button.DefaultHeight; gridControl.Height = Button.DefaultHeight;
@@ -53,7 +53,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
if (Presenter.Owner != null) if (Presenter.Owner != null)
{ {
// Selection // Selection
var grid = editorGroup.CustomContainer<UniformGridPanel>(); var grid = editorGroup.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = Button.DefaultHeight; gridControl.Height = Button.DefaultHeight;

View File

@@ -28,7 +28,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
_infoLabel = playbackGroup.Label(string.Empty).Label; _infoLabel = playbackGroup.Label(string.Empty).Label;
_infoLabel.AutoHeight = true; _infoLabel.AutoHeight = true;
var grid = playbackGroup.CustomContainer<UniformGridPanel>(); var grid = playbackGroup.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = Button.DefaultHeight; gridControl.Height = Button.DefaultHeight;

View File

@@ -682,7 +682,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
private CustomElementsContainer<UniformGridPanel> UniformGridTwoByOne(LayoutElementsContainer cont) private CustomElementsContainer<UniformGridPanel> UniformGridTwoByOne(LayoutElementsContainer cont)
{ {
var grid = cont.CustomContainer<UniformGridPanel>(); var grid = cont.UniformGrid();
grid.CustomControl.SlotsHorizontally = 2; grid.CustomControl.SlotsHorizontally = 2;
grid.CustomControl.SlotsVertically = 1; grid.CustomControl.SlotsVertically = 1;
grid.CustomControl.SlotPadding = Margin.Zero; grid.CustomControl.SlotPadding = Margin.Zero;

View File

@@ -43,11 +43,7 @@ namespace FlaxEditor.CustomEditors.Editors
base.Initialize(layout); base.Initialize(layout);
if (XElement.ValueBox.Parent is UniformGridPanel ug) if (XElement.ValueBox.Parent is UniformGridPanel ug)
{ CheckLayout(ug);
ug.Height += 2;
ug.SlotSpacing = new Float2(4);
ug.SlotPadding = new Margin(0, 0, 1, 1);
}
// Override colors // Override colors
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground; var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
@@ -75,11 +71,7 @@ namespace FlaxEditor.CustomEditors.Editors
base.Initialize(layout); base.Initialize(layout);
if (XElement.ValueBox.Parent is UniformGridPanel ug) if (XElement.ValueBox.Parent is UniformGridPanel ug)
{ CheckLayout(ug);
ug.Height += 2;
ug.SlotSpacing = new Float2(4);
ug.SlotPadding = new Margin(0, 0, 1, 1);
}
// Override colors // Override colors
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground; var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
@@ -138,11 +130,7 @@ namespace FlaxEditor.CustomEditors.Editors
} }
if (XElement.ValueBox.Parent is UniformGridPanel ug) if (XElement.ValueBox.Parent is UniformGridPanel ug)
{ CheckLayout(ug);
ug.Height += 2;
ug.SlotSpacing = new Float2(4);
ug.SlotPadding = new Margin(0, 0, 1, 1);
}
// Override colors // Override colors
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground; var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
@@ -203,5 +191,13 @@ namespace FlaxEditor.CustomEditors.Editors
_linkButton.TooltipText = LinkValues ? "Unlinks scale components from uniform scaling" : "Links scale components for uniform scaling"; _linkButton.TooltipText = LinkValues ? "Unlinks scale components from uniform scaling" : "Links scale components for uniform scaling";
} }
} }
private static void CheckLayout(UniformGridPanel ug)
{
// Enlarge to fix border visibility
ug.Height += 2;
ug.SlotSpacing += new Float2(2);
ug.SlotPadding += new Margin(0, 0, 1, 1);
}
} }
} }

View File

@@ -642,10 +642,10 @@ namespace FlaxEditor.CustomEditors.Editors
if (_canResize && !_readOnly) if (_canResize && !_readOnly)
{ {
var panel = dragArea.HorizontalPanel(); var panel = dragArea.HorizontalPanel();
panel.Panel.Size = new Float2(0, 20); panel.Panel.Size = new Float2(0, 18);
panel.Panel.Margin = new Margin(2); panel.Panel.Margin = new Margin(0, 0, Utilities.Constants.UIMargin, 0);
var removeButton = panel.Button("-", "Remove last item"); var removeButton = panel.Button("-", "Remove the last item");
removeButton.Button.Size = new Float2(16, 16); removeButton.Button.Size = new Float2(16, 16);
removeButton.Button.Enabled = size > _minCount; removeButton.Button.Enabled = size > _minCount;
removeButton.Button.AnchorPreset = AnchorPresets.TopRight; removeButton.Button.AnchorPreset = AnchorPresets.TopRight;
@@ -656,7 +656,7 @@ namespace FlaxEditor.CustomEditors.Editors
Resize(Count - 1); Resize(Count - 1);
}; };
var addButton = panel.Button("+", "Add new item"); var addButton = panel.Button("+", "Add a new item");
addButton.Button.Size = new Float2(16, 16); addButton.Button.Size = new Float2(16, 16);
addButton.Button.Enabled = (!NotNullItems || size > 0) && size < _maxCount; addButton.Button.Enabled = (!NotNullItems || size > 0) && size < _maxCount;
addButton.Button.AnchorPreset = AnchorPresets.TopRight; addButton.Button.AnchorPreset = AnchorPresets.TopRight;

View File

@@ -27,7 +27,7 @@ namespace FlaxEditor.CustomEditors.Editors
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
float trackBallSize = 80.0f; float trackBallSize = 100f;
float margin = 4.0f; float margin = 4.0f;
// Panel // Panel
@@ -50,7 +50,7 @@ namespace FlaxEditor.CustomEditors.Editors
// Scale editor // Scale editor
{ {
var grid = masterPanel.CustomContainer<UniformGridPanel>(); var grid = masterPanel.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.SlotPadding = new Margin(4, 2, 2, 2); gridControl.SlotPadding = new Margin(4, 2, 2, 2);
gridControl.ClipChildren = false; gridControl.ClipChildren = false;

View File

@@ -21,6 +21,7 @@ namespace FlaxEditor.CustomEditors.Editors
public sealed class LocalizedStringEditor : GenericEditor public sealed class LocalizedStringEditor : GenericEditor
{ {
private TextBoxElement _idElement, _valueElement; private TextBoxElement _idElement, _valueElement;
private Button _viewStringButton;
/// <inheritdoc /> /// <inheritdoc />
public override DisplayStyle Style => DisplayStyle.Inline; public override DisplayStyle Style => DisplayStyle.Inline;
@@ -70,6 +71,21 @@ namespace FlaxEditor.CustomEditors.Editors
}; };
addString.SetAnchorPreset(AnchorPresets.MiddleRight, false, true); addString.SetAnchorPreset(AnchorPresets.MiddleRight, false, true);
addString.ButtonClicked += OnAddStringClicked; addString.ButtonClicked += OnAddStringClicked;
var viewString = new Button
{
Visible = false,
Width = 16.0f,
BackgroundColor = Color.White,
BackgroundColorHighlighted = Color.Gray,
BackgroundBrush = new SpriteBrush(Editor.Instance.Icons.Search12),
TooltipText = "Find localized text in Localized String Table asset for the current locale...",
Parent = valueElement.TextBox,
};
viewString.SetAnchorPreset(AnchorPresets.MiddleRight, false, true);
viewString.LocalX -= 16.0f;
viewString.ButtonClicked += OnViewStringClicked;
_viewStringButton = viewString;
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -80,6 +96,7 @@ namespace FlaxEditor.CustomEditors.Editors
if (_valueElement != null) if (_valueElement != null)
{ {
_valueElement.TextBox.WatermarkText = Localization.GetString(_idElement.Text); _valueElement.TextBox.WatermarkText = Localization.GetString(_idElement.Text);
_viewStringButton.Visible = !string.IsNullOrEmpty(_valueElement.TextBox.WatermarkText);
} }
} }
@@ -92,14 +109,21 @@ namespace FlaxEditor.CustomEditors.Editors
_valueElement = null; _valueElement = null;
} }
private void OnSelectStringClicked(Button button) private bool GetSettings(out LocalizationSettings settings)
{ {
var settings = GameSettings.Load<LocalizationSettings>(); settings = GameSettings.Load<LocalizationSettings>();
if (settings?.LocalizedStringTables == null || settings.LocalizedStringTables.Length == 0) if (settings?.LocalizedStringTables == null || settings.LocalizedStringTables.Length == 0)
{ {
MessageBox.Show("No valid localization settings setup."); MessageBox.Show("No valid localization settings setup.");
return; return true;
} }
return false;
}
private void OnSelectStringClicked(Button button)
{
if (GetSettings(out var settings))
return;
Profiler.BeginEvent("LocalizedStringEditor.OnSelectStringClicked"); Profiler.BeginEvent("LocalizedStringEditor.OnSelectStringClicked");
var allKeys = new HashSet<string>(); var allKeys = new HashSet<string>();
for (int i = 0; i < settings.LocalizedStringTables.Length; i++) for (int i = 0; i < settings.LocalizedStringTables.Length; i++)
@@ -136,6 +160,7 @@ namespace FlaxEditor.CustomEditors.Editors
{ {
menu.Hide(); menu.Hide();
_idElement.TextBox.SetTextAsUser(after[0].Text); _idElement.TextBox.SetTextAsUser(after[0].Text);
_valueElement.TextBox.SetTextAsUser(string.Empty);
} }
}; };
searchBox.TextChanged += delegate searchBox.TextChanged += delegate
@@ -158,12 +183,8 @@ namespace FlaxEditor.CustomEditors.Editors
private void OnAddStringClicked(Button button) private void OnAddStringClicked(Button button)
{ {
var settings = GameSettings.Load<LocalizationSettings>(); if (GetSettings(out var settings))
if (settings?.LocalizedStringTables == null || settings.LocalizedStringTables.Length == 0)
{
MessageBox.Show("No valid localization settings setup.");
return; return;
}
Profiler.BeginEvent("LocalizedStringEditor.OnAddStringClicked"); Profiler.BeginEvent("LocalizedStringEditor.OnAddStringClicked");
var allKeys = new HashSet<string>(); var allKeys = new HashSet<string>();
for (int i = 0; i < settings.LocalizedStringTables.Length; i++) for (int i = 0; i < settings.LocalizedStringTables.Length; i++)
@@ -231,5 +252,30 @@ namespace FlaxEditor.CustomEditors.Editors
_idElement.TextBox.SetTextAsUser(newKey); _idElement.TextBox.SetTextAsUser(newKey);
Profiler.EndEvent(); Profiler.EndEvent();
} }
private void OnViewStringClicked(Button button)
{
if (GetSettings(out var settings))
return;
var id = _idElement.TextBox.Text;
var value = _valueElement.TextBox.WatermarkText;
for (int i = 0; i < settings.LocalizedStringTables.Length; i++)
{
var table = settings.LocalizedStringTables[i];
if (table && !table.WaitForLoaded())
{
var entries = table.Entries;
if (entries.TryGetValue(id, out var messages))
{
if (messages.Length != 0 && messages[0] == value)
{
Editor.Instance.ContentEditing.Open(table);
return;
}
}
}
}
MessageBox.Show("Unable to find localized string table.");
}
} }
} }

View File

@@ -46,7 +46,7 @@ namespace FlaxEditor.CustomEditors.Editors
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
var grid = layout.CustomContainer<UniformGridPanel>(); var grid = layout.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = TextBox.DefaultHeight; gridControl.Height = TextBox.DefaultHeight;

View File

@@ -35,7 +35,7 @@ namespace FlaxEditor.CustomEditors.Editors
} }
_element = layout.TextBox(isMultiLine); _element = layout.TextBox(isMultiLine);
_defaultWatermarkColor = _element.TextBox.WatermarkTextColor; _watermarkColor = _defaultWatermarkColor = _element.TextBox.WatermarkTextColor;
if (watermarkAttribute is WatermarkAttribute watermark) if (watermarkAttribute is WatermarkAttribute watermark)
{ {
_watermarkText = watermark.WatermarkText; _watermarkText = watermark.WatermarkText;

View File

@@ -42,7 +42,7 @@ namespace FlaxEditor.CustomEditors.Editors
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
var grid = layout.CustomContainer<UniformGridPanel>(); var grid = layout.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = TextBox.DefaultHeight; gridControl.Height = TextBox.DefaultHeight;
@@ -131,7 +131,7 @@ namespace FlaxEditor.CustomEditors.Editors
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
var grid = layout.CustomContainer<UniformGridPanel>(); var grid = layout.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = TextBox.DefaultHeight; gridControl.Height = TextBox.DefaultHeight;
@@ -220,7 +220,7 @@ namespace FlaxEditor.CustomEditors.Editors
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
var grid = layout.CustomContainer<UniformGridPanel>(); var grid = layout.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = TextBox.DefaultHeight; gridControl.Height = TextBox.DefaultHeight;

View File

@@ -82,7 +82,7 @@ namespace FlaxEditor.CustomEditors.Editors
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
var grid = layout.CustomContainer<UniformGridPanel>(); var grid = layout.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = TextBox.DefaultHeight; gridControl.Height = TextBox.DefaultHeight;
@@ -469,7 +469,7 @@ namespace FlaxEditor.CustomEditors.Editors
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
var grid = layout.CustomContainer<UniformGridPanel>(); var grid = layout.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = TextBox.DefaultHeight; gridControl.Height = TextBox.DefaultHeight;
@@ -783,7 +783,7 @@ namespace FlaxEditor.CustomEditors.Editors
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
var grid = layout.CustomContainer<UniformGridPanel>(); var grid = layout.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = TextBox.DefaultHeight; gridControl.Height = TextBox.DefaultHeight;

View File

@@ -52,7 +52,7 @@ namespace FlaxEditor.CustomEditors.Editors
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
var grid = layout.CustomContainer<UniformGridPanel>(); var grid = layout.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = TextBox.DefaultHeight; gridControl.Height = TextBox.DefaultHeight;
@@ -163,7 +163,7 @@ namespace FlaxEditor.CustomEditors.Editors
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
var grid = layout.CustomContainer<UniformGridPanel>(); var grid = layout.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = TextBox.DefaultHeight; gridControl.Height = TextBox.DefaultHeight;
@@ -274,7 +274,7 @@ namespace FlaxEditor.CustomEditors.Editors
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
var grid = layout.CustomContainer<UniformGridPanel>(); var grid = layout.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = TextBox.DefaultHeight; gridControl.Height = TextBox.DefaultHeight;

View File

@@ -39,7 +39,7 @@ namespace FlaxEditor.CustomEditors.Editors
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
var grid = layout.CustomContainer<UniformGridPanel>(); var grid = layout.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = TextBox.DefaultHeight; gridControl.Height = TextBox.DefaultHeight;

View File

@@ -22,7 +22,8 @@ namespace FlaxEditor.CustomEditors.Elements
ArrowImageClosed = new SpriteBrush(Style.Current.ArrowRight), ArrowImageClosed = new SpriteBrush(Style.Current.ArrowRight),
ArrowImageOpened = new SpriteBrush(Style.Current.ArrowDown), ArrowImageOpened = new SpriteBrush(Style.Current.ArrowDown),
EnableDropDownIcon = true, EnableDropDownIcon = true,
ItemsMargin = new Margin(7, 7, 3, 3), ItemsMargin = new Margin(Utilities.Constants.UIMargin),
ItemsSpacing = Utilities.Constants.UIMargin,
HeaderHeight = 18.0f, HeaderHeight = 18.0f,
EnableContainmentLines = true, EnableContainmentLines = true,
}; };

View File

@@ -20,13 +20,6 @@ namespace FlaxEditor.CustomEditors.GUI
/// </summary> /// </summary>
public const int SplitterSize = 2; public const int SplitterSize = 2;
/// <summary>
/// The splitter margin (in pixels).
/// </summary>
public const int SplitterMargin = 4;
private const int SplitterSizeHalf = SplitterSize / 2;
private PropertiesListElement _element; private PropertiesListElement _element;
private float _splitterValue; private float _splitterValue;
private Rectangle _splitterRect; private Rectangle _splitterRect;
@@ -65,16 +58,18 @@ namespace FlaxEditor.CustomEditors.GUI
/// <param name="element">The element.</param> /// <param name="element">The element.</param>
public PropertiesList(PropertiesListElement element) public PropertiesList(PropertiesListElement element)
{ {
ClipChildren = false;
_element = element; _element = element;
_splitterValue = 0.4f; _splitterValue = 0.4f;
BottomMargin = TopMargin = RightMargin = SplitterMargin; Margin = new Margin();
Spacing = Utilities.Constants.UIMargin;
UpdateSplitRect(); UpdateSplitRect();
} }
private void UpdateSplitRect() private void UpdateSplitRect()
{ {
_splitterRect = new Rectangle(Mathf.Clamp(_splitterValue * Width - SplitterSizeHalf, 0.0f, Width), 0, SplitterSize, Height); _splitterRect = new Rectangle(Mathf.Clamp(_splitterValue * Width - SplitterSize * 0.5f, 0.0f, Width), 0, SplitterSize, Height);
LeftMargin = _splitterValue * Width + SplitterMargin; LeftMargin = _splitterValue * Width + _spacing;
} }
private void StartTracking() private void StartTracking()
@@ -222,23 +217,33 @@ namespace FlaxEditor.CustomEditors.GUI
/// <inheritdoc /> /// <inheritdoc />
protected override void PerformLayoutAfterChildren() protected override void PerformLayoutAfterChildren()
{ {
// Sort controls from up to down into two columns: one for labels and one for the rest of the stuff // Place non-label controls from top to down
float y = _margin.Top; float y = _margin.Top;
float w = Width - _margin.Width; float w = Width - _margin.Width;
bool firstItem = true;
for (int i = 0; i < _children.Count; i++) for (int i = 0; i < _children.Count; i++)
{ {
Control c = _children[i]; Control c = _children[i];
if (!(c is PropertyNameLabel)) if (!(c is PropertyNameLabel))
{ {
var h = c.Height; var rect = new Rectangle(_margin.Left, y, w, c.Height);
c.Bounds = new Rectangle(_margin.Left, y + _spacing, w, h); if (c.Visible)
{
if (firstItem)
firstItem = false;
else
rect.Y += _spacing;
}
else if (!firstItem)
rect.Y += _spacing;
c.Bounds = rect;
if (c.Visible) if (c.Visible)
y = c.Bottom; y = c.Bottom;
} }
} }
y += _margin.Bottom; y += _margin.Bottom;
// Place labels accordingly to their respective controls placement
float namesWidth = _splitterValue * Width; float namesWidth = _splitterValue * Width;
int count = _element.Labels.Count; int count = _element.Labels.Count;
float[] yStarts = new float[count + 1]; float[] yStarts = new float[count + 1];
@@ -271,7 +276,9 @@ namespace FlaxEditor.CustomEditors.GUI
{ {
var label = _element.Labels[i]; var label = _element.Labels[i];
var rect = new Rectangle(0, yStarts[i] + 1, namesWidth, yStarts[i + 1] - yStarts[i] - 2); var rect = new Rectangle(0, yStarts[i], namesWidth, yStarts[i + 1] - yStarts[i]);
if (i != count - 1)
rect.Height -= _spacing;
//label.Parent = this; //label.Parent = this;
label.Bounds = rect; label.Bounds = rect;
} }

View File

@@ -202,6 +202,17 @@ namespace FlaxEditor.CustomEditors
return element; return element;
} }
/// <summary>
/// Adds new uniform grid control.
/// </summary>
/// <returns>The created element.</returns>
public CustomElementsContainer<UniformGridPanel> UniformGrid()
{
var grid = CustomContainer<UniformGridPanel>();
grid.CustomControl.SlotSpacing = new Float2(Utilities.Constants.UIMargin);
return grid;
}
/// <summary> /// <summary>
/// Adds new custom element. /// Adds new custom element.
/// </summary> /// </summary>

View File

@@ -1031,6 +1031,8 @@ namespace FlaxEditor
{ {
Internal_GetEditorBoxWithChildren(FlaxEngine.Object.GetUnmanagedPtr(actor), out var box); Internal_GetEditorBoxWithChildren(FlaxEngine.Object.GetUnmanagedPtr(actor), out var box);
BoundingSphere.FromBox(ref box, out sphere); BoundingSphere.FromBox(ref box, out sphere);
if (sphere == BoundingSphere.Empty)
sphere = new BoundingSphere(actor.Position, sphere.Radius);
sphere.Radius = Math.Max(sphere.Radius, 15.0f); sphere.Radius = Math.Max(sphere.Radius, 15.0f);
} }
else else

View File

@@ -285,6 +285,17 @@ namespace FlaxEditor.GUI.ContextMenu
} }
} }
private static void ForceDefocus(ContainerControl c)
{
foreach (var cc in c.Children)
{
if (cc.ContainsFocus)
cc.Defocus();
if (cc is ContainerControl ccc)
ForceDefocus(ccc);
}
}
/// <summary> /// <summary>
/// Hide popup menu and all child menus. /// Hide popup menu and all child menus.
/// </summary> /// </summary>
@@ -299,6 +310,9 @@ namespace FlaxEditor.GUI.ContextMenu
// Close child // Close child
HideChild(); HideChild();
// Force defocus
ForceDefocus(this);
// Unlink from window // Unlink from window
Parent = null; Parent = null;

View File

@@ -41,7 +41,7 @@ namespace FlaxEditor.GUI.Input
get => _min; get => _min;
set set
{ {
if (!Mathd.NearEqual(_min, value)) if (_min != value)
{ {
if (value > _max) if (value > _max)
throw new ArgumentException(); throw new ArgumentException();
@@ -58,7 +58,7 @@ namespace FlaxEditor.GUI.Input
get => _max; get => _max;
set set
{ {
if (!Mathd.NearEqual(_max, value)) if (_max != value)
{ {
if (value < _min) if (value < _min)
throw new ArgumentException(); throw new ArgumentException();

View File

@@ -38,7 +38,7 @@ namespace FlaxEditor.GUI.Input
get => _min; get => _min;
set set
{ {
if (!Mathf.NearEqual(_min, value)) if (_min != value)
{ {
if (value > _max) if (value > _max)
throw new ArgumentException(); throw new ArgumentException();
@@ -54,7 +54,7 @@ namespace FlaxEditor.GUI.Input
get => _max; get => _max;
set set
{ {
if (!Mathf.NearEqual(_max, value)) if (_max != value)
{ {
if (value < _min) if (value < _min)
throw new ArgumentException(); throw new ArgumentException();

View File

@@ -54,7 +54,7 @@ namespace FlaxEditor.GUI.Input
set set
{ {
value = Mathf.Clamp(value, Minimum, Maximum); value = Mathf.Clamp(value, Minimum, Maximum);
if (!Mathf.NearEqual(value, _value)) if (value != _value)
{ {
_value = value; _value = value;
@@ -311,7 +311,7 @@ namespace FlaxEditor.GUI.Input
get => _min; get => _min;
set set
{ {
if (!Mathf.NearEqual(_min, value)) if (_min != value)
{ {
if (value > _max) if (value > _max)
throw new ArgumentException(); throw new ArgumentException();
@@ -330,7 +330,7 @@ namespace FlaxEditor.GUI.Input
get => _max; get => _max;
set set
{ {
if (!Mathf.NearEqual(_max, value)) if (_max != value)
{ {
if (value < _min) if (value < _min)
throw new ArgumentException(); throw new ArgumentException();

View File

@@ -47,6 +47,7 @@ namespace FlaxEditor.GUI.Tabs
if (EnabledInHierarchy && Tab.Enabled) if (EnabledInHierarchy && Tab.Enabled)
{ {
Tabs.SelectedTab = Tab; Tabs.SelectedTab = Tab;
Tab.PerformLayout(true);
Tabs.Focus(); Tabs.Focus();
} }
return true; return true;

View File

@@ -40,6 +40,7 @@ namespace FlaxEditor.GUI.Tree
private readonly bool _supportMultiSelect; private readonly bool _supportMultiSelect;
private Margin _margin; private Margin _margin;
private bool _autoSize = true; private bool _autoSize = true;
private bool _deferLayoutUpdate = false;
/// <summary> /// <summary>
/// The TreeNode that is being dragged over. This could have a value when not dragging. /// The TreeNode that is being dragged over. This could have a value when not dragging.
@@ -67,6 +68,11 @@ namespace FlaxEditor.GUI.Tree
/// </summary> /// </summary>
public TreeNode SelectedNode => Selection.Count > 0 ? Selection[0] : null; public TreeNode SelectedNode => Selection.Count > 0 ? Selection[0] : null;
/// <summary>
/// Allow nodes to Draw the root tree line.
/// </summary>
public bool DrawRootTreeLine = true;
/// <summary> /// <summary>
/// Gets or sets the margin for the child tree nodes. /// Gets or sets the margin for the child tree nodes.
/// </summary> /// </summary>
@@ -353,9 +359,25 @@ namespace FlaxEditor.GUI.Tree
BulkSelectUpdateExpanded(false); BulkSelectUpdateExpanded(false);
} }
/// <inheritdoc />
public override void PerformLayout(bool force = false)
{
if (_isLayoutLocked && !force)
return;
// In case the tree was fully expanded or collapsed along its children, avoid calculating the layout multiple times for each child
_deferLayoutUpdate = true;
}
/// <inheritdoc /> /// <inheritdoc />
public override void Update(float deltaTime) public override void Update(float deltaTime)
{ {
if (_deferLayoutUpdate)
{
base.PerformLayout();
_deferLayoutUpdate = false;
}
var node = SelectedNode; var node = SelectedNode;
// Check if has focus and if any node is focused and it isn't a root // Check if has focus and if any node is focused and it isn't a root

View File

@@ -760,20 +760,21 @@ namespace FlaxEditor.GUI.Tree
// Show tree guidelines // Show tree guidelines
if (Editor.Instance.Options.Options.Interface.ShowTreeLines) if (Editor.Instance.Options.Options.Interface.ShowTreeLines)
{ {
TreeNode parentNode = Parent as TreeNode; ContainerControl parent = Parent;
TreeNode parentNode = parent as TreeNode;
bool thisNodeIsLast = false; bool thisNodeIsLast = false;
while (parentNode != null && parentNode != ParentTree.Children[0]) while (parentNode != null && (parentNode != tree.Children[0] || tree.DrawRootTreeLine))
{ {
float bottomOffset = 0; float bottomOffset = 0;
float topOffset = 0; float topOffset = 0;
if (Parent == parentNode && this == Parent.Children[0]) if (parent == parentNode && this == parent.Children[0])
topOffset = 2; topOffset = 2;
if (thisNodeIsLast && parentNode.Children.Count == 1) if (thisNodeIsLast && parentNode.Children.Count == 1)
bottomOffset = topOffset != 0 ? 4 : 2; bottomOffset = topOffset != 0 ? 4 : 2;
if (Parent == parentNode && this == Parent.Children[Parent.Children.Count - 1] && !_opened) if (parent == parentNode && this == parent.Children[^1] && !_opened)
{ {
thisNodeIsLast = true; thisNodeIsLast = true;
bottomOffset = topOffset != 0 ? 4 : 2; bottomOffset = topOffset != 0 ? 4 : 2;
@@ -784,6 +785,8 @@ namespace FlaxEditor.GUI.Tree
if (_iconCollaped.IsValid) if (_iconCollaped.IsValid)
leftOffset += 18; leftOffset += 18;
var lineRect1 = new Rectangle(parentNode.TextRect.Left - leftOffset, parentNode.HeaderRect.Top + topOffset, 1, parentNode.HeaderRect.Height - bottomOffset); var lineRect1 = new Rectangle(parentNode.TextRect.Left - leftOffset, parentNode.HeaderRect.Top + topOffset, 1, parentNode.HeaderRect.Height - bottomOffset);
if (HasAnyVisibleChild && CustomArrowRect.HasValue && CustomArrowRect.Value.Intersects(lineRect1))
lineRect1 = Rectangle.Empty; // Skip drawing line if it's overlapping the arrow rectangle
Render2D.FillRectangle(lineRect1, isSelected ? style.ForegroundGrey : style.LightBackground); Render2D.FillRectangle(lineRect1, isSelected ? style.ForegroundGrey : style.LightBackground);
parentNode = parentNode.Parent as TreeNode; parentNode = parentNode.Parent as TreeNode;
} }

View File

@@ -1135,6 +1135,7 @@ namespace FlaxEditor.Modules
Proxy.Add(new FontProxy()); Proxy.Add(new FontProxy());
Proxy.Add(new ShaderProxy()); Proxy.Add(new ShaderProxy());
Proxy.Add(new ShaderSourceProxy()); Proxy.Add(new ShaderSourceProxy());
Proxy.Add(new ShaderHeaderProxy());
Proxy.Add(new ParticleEmitterProxy()); Proxy.Add(new ParticleEmitterProxy());
Proxy.Add(new ParticleEmitterFunctionProxy()); Proxy.Add(new ParticleEmitterFunctionProxy());
Proxy.Add(new ParticleSystemProxy()); Proxy.Add(new ParticleSystemProxy());

View File

@@ -255,12 +255,17 @@ namespace FlaxEditor.Modules
// When applying changes to prefab from actor in level ignore it's root transformation (see ActorEditor.ProcessDiff) // When applying changes to prefab from actor in level ignore it's root transformation (see ActorEditor.ProcessDiff)
var originalTransform = instance.LocalTransform; var originalTransform = instance.LocalTransform;
var originalName = instance.Name;
if (instance.IsPrefabRoot && instance.HasScene) if (instance.IsPrefabRoot && instance.HasScene)
{
instance.LocalTransform = prefab.GetDefaultInstance().Transform; instance.LocalTransform = prefab.GetDefaultInstance().Transform;
instance.Name = prefab.GetDefaultInstance().Name;
}
// Call backend // Call backend
var failed = PrefabManager.Internal_ApplyAll(FlaxEngine.Object.GetUnmanagedPtr(instance)); var failed = PrefabManager.Internal_ApplyAll(FlaxEngine.Object.GetUnmanagedPtr(instance));
instance.LocalTransform = originalTransform; instance.LocalTransform = originalTransform;
instance.Name = originalName;
if (failed) if (failed)
throw new Exception("Failed to apply the prefab. See log to learn more."); throw new Exception("Failed to apply the prefab. See log to learn more.");

View File

@@ -306,7 +306,8 @@ namespace FlaxEditor.Modules
public override void OnPlayEnd() public override void OnPlayEnd()
{ {
var gameWin = Editor.Windows.GameWin; var gameWin = Editor.Windows.GameWin;
if (gameWin != null)
{
switch (gameWin.FocusOnPlayOption) switch (gameWin.FocusOnPlayOption)
{ {
case Options.InterfaceOptions.PlayModeFocus.None: break; case Options.InterfaceOptions.PlayModeFocus.None: break;
@@ -320,6 +321,7 @@ namespace FlaxEditor.Modules
} }
break; break;
} }
}
Editor.UI.UncheckPauseButton(); Editor.UI.UncheckPauseButton();

View File

@@ -628,19 +628,19 @@ namespace FlaxEditor.Modules
MenuWindow = MainMenu.AddButton("Window"); MenuWindow = MainMenu.AddButton("Window");
cm = MenuWindow.ContextMenu; cm = MenuWindow.ContextMenu;
cm.VisibleChanged += OnMenuWindowVisibleChanged; cm.VisibleChanged += OnMenuWindowVisibleChanged;
cm.AddButton("Content", Editor.Windows.ContentWin.FocusOrShow); cm.AddButton("Content", inputOptions.ContentWindow,Editor.Windows.ContentWin.FocusOrShow);
cm.AddButton("Scene", Editor.Windows.SceneWin.FocusOrShow); cm.AddButton("Scene", inputOptions.SceneWindow, Editor.Windows.SceneWin.FocusOrShow);
cm.AddButton("Toolbox", Editor.Windows.ToolboxWin.FocusOrShow); cm.AddButton("Toolbox", inputOptions.ToolboxWindow, Editor.Windows.ToolboxWin.FocusOrShow);
cm.AddButton("Properties", Editor.Windows.PropertiesWin.FocusOrShow); cm.AddButton("Properties", inputOptions.PropertiesWindow, Editor.Windows.PropertiesWin.FocusOrShow);
cm.AddButton("Game", Editor.Windows.GameWin.FocusOrShow); cm.AddButton("Game", inputOptions.GameWindow, Editor.Windows.GameWin.FocusOrShow);
cm.AddButton("Editor", Editor.Windows.EditWin.FocusOrShow); cm.AddButton("Editor", inputOptions.EditorWindow, Editor.Windows.EditWin.FocusOrShow);
cm.AddButton("Debug Log", Editor.Windows.DebugLogWin.FocusOrShow); cm.AddButton("Debug Log", inputOptions.DebugLogWindow, Editor.Windows.DebugLogWin.FocusOrShow);
cm.AddButton("Output Log", Editor.Windows.OutputLogWin.FocusOrShow); cm.AddButton("Output Log", inputOptions.OutputLogWindow, Editor.Windows.OutputLogWin.FocusOrShow);
cm.AddButton("Graphics Quality", Editor.Windows.GraphicsQualityWin.FocusOrShow); cm.AddButton("Graphics Quality", inputOptions.GraphicsQualityWindow, Editor.Windows.GraphicsQualityWin.FocusOrShow);
cm.AddButton("Game Cooker", Editor.Windows.GameCookerWin.FocusOrShow); cm.AddButton("Game Cooker", inputOptions.GameCookerWindow, Editor.Windows.GameCookerWin.FocusOrShow);
cm.AddButton("Profiler", inputOptions.ProfilerWindow, Editor.Windows.ProfilerWin.FocusOrShow); cm.AddButton("Profiler", inputOptions.ProfilerWindow, Editor.Windows.ProfilerWin.FocusOrShow);
cm.AddButton("Content Search", Editor.ContentFinding.ShowSearch); cm.AddButton("Content Search", inputOptions.ContentSearchWindow, Editor.ContentFinding.ShowSearch);
cm.AddButton("Visual Script Debugger", Editor.Windows.VisualScriptDebuggerWin.FocusOrShow); cm.AddButton("Visual Script Debugger", inputOptions.VisualScriptDebuggerWindow, Editor.Windows.VisualScriptDebuggerWin.FocusOrShow);
cm.AddSeparator(); cm.AddSeparator();
cm.AddButton("Save window layout", Editor.Windows.SaveLayout); cm.AddButton("Save window layout", Editor.Windows.SaveLayout);
_menuWindowApplyWindowLayout = cm.AddChildMenu("Window layouts"); _menuWindowApplyWindowLayout = cm.AddChildMenu("Window layouts");

View File

@@ -33,6 +33,25 @@ namespace FlaxEditor.Options
OpenPrefab, OpenPrefab,
} }
/// <summary>
/// Shortcut availability in play mode.
/// </summary>
public enum PlayModeShortcutAvailability
{
/// <summary>
/// None of the window shortcuts will be available in play mode.
/// </summary>
None,
/// <summary>
/// Only the profiler window shortcut will be available in play mode.
/// </summary>
ProfilerOnly,
/// <summary>
/// All window shortcuts will be available in play mode.
/// </summary>
All,
}
/// <summary> /// <summary>
/// Input editor options data container. /// Input editor options data container.
/// </summary> /// </summary>
@@ -40,6 +59,16 @@ namespace FlaxEditor.Options
[HideInEditor] [HideInEditor]
public sealed class InputOptions public sealed class InputOptions
{ {
/// <summary>
/// Gets a value based on the current settings that indicates wether window shortcuts will be avaliable during play mode.
/// </summary>
public static bool WindowShortcutsAvaliable => !Editor.IsPlayMode || Editor.Instance.Options.Options.Input.PlayModeWindowShortcutAvaliability == PlayModeShortcutAvailability.All;
/// <summary>
/// Gets a value based on the current settings that indicates wether the profiler window shortcut will be avaliable during play mode.
/// </summary>
public static bool ProfilerShortcutAvaliable => WindowShortcutsAvaliable || Editor.Instance.Options.Options.Input.PlayModeWindowShortcutAvaliability == PlayModeShortcutAvailability.ProfilerOnly;
#region Common #region Common
[DefaultValue(typeof(InputBinding), "Ctrl+S")] [DefaultValue(typeof(InputBinding), "Ctrl+S")]
@@ -230,9 +259,9 @@ namespace FlaxEditor.Options
#region Profiler #region Profiler
[DefaultValue(typeof(InputBinding), "None")] [DefaultValue(typeof(InputBinding), "Ctrl+Alpha7")]
[EditorDisplay("Profiler", "Open Profiler Window"), EditorOrder(630)] [EditorDisplay("Profiler", "Open Profiler Window"), EditorOrder(630)]
public InputBinding ProfilerWindow = new InputBinding(KeyboardKeys.None); public InputBinding ProfilerWindow = new InputBinding(KeyboardKeys.Alpha7, KeyboardKeys.Control);
[DefaultValue(typeof(InputBinding), "None")] [DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Profiler", "Start/Stop Profiler"), EditorOrder(631)] [EditorDisplay("Profiler", "Start/Stop Profiler"), EditorOrder(631)]
@@ -356,24 +385,267 @@ namespace FlaxEditor.Options
#endregion #endregion
#region Debug Views
[DefaultValue(typeof(InputBinding), "Alt+Alpha4")]
[EditorDisplay("Debug Views"), EditorOrder(2000)]
public InputBinding Default = new InputBinding(KeyboardKeys.Alpha4, KeyboardKeys.Alt);
[DefaultValue(typeof(InputBinding), "Alt+Alpha3")]
[EditorDisplay("Debug Views"), EditorOrder(2010)]
public InputBinding Unlit = new InputBinding(KeyboardKeys.Alpha3, KeyboardKeys.Alt);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Debug Views"), EditorOrder(2020)]
public InputBinding NoPostFX = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "Alt+Alpha2")]
[EditorDisplay("Debug Views"), EditorOrder(2030)]
public InputBinding Wireframe = new InputBinding(KeyboardKeys.Alpha2, KeyboardKeys.Alt);
[DefaultValue(typeof(InputBinding), "Alt+Alpha5")]
[EditorDisplay("Debug Views"), EditorOrder(2040)]
public InputBinding LightBuffer = new InputBinding(KeyboardKeys.Alpha5, KeyboardKeys.Alt);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Debug Views"), EditorOrder(2050)]
public InputBinding ReflectionsBuffer = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Debug Views"), EditorOrder(2060)]
public InputBinding DepthBuffer = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Debug Views"), EditorOrder(2070)]
public InputBinding MotionVectors = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Debug Views"), EditorOrder(2080)]
public InputBinding LightmapUVDensity = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Debug Views"), EditorOrder(2090)]
public InputBinding VertexColors = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "Alt+Alpha1")]
[EditorDisplay("Debug Views"), EditorOrder(2100)]
public InputBinding PhysicsColliders = new InputBinding(KeyboardKeys.Alpha1, KeyboardKeys.Alt);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Debug Views"), EditorOrder(2110)]
public InputBinding LODPreview = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Debug Views"), EditorOrder(2120)]
public InputBinding MaterialComplexity = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Debug Views"), EditorOrder(2130)]
public InputBinding QuadOverdraw = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Debug Views"), EditorOrder(2140)]
public InputBinding GloablSDF = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Debug Views"), EditorOrder(2150)]
public InputBinding GlobalSurfaceAtlas = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Debug Views"), EditorOrder(2160)]
public InputBinding GlobalIllumination = new InputBinding(KeyboardKeys.None);
#endregion
#region View Flags
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3000)]
public InputBinding AntiAliasing = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3010)]
public InputBinding Shadows = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha7")]
[EditorDisplay("View Flags"), EditorOrder(3020)]
public InputBinding EditorSprites = new InputBinding(KeyboardKeys.Alpha7, KeyboardKeys.Control, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3030)]
public InputBinding Reflections = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3040)]
public InputBinding ScreenSpaceReflections = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3050)]
public InputBinding AmbientOcclusion = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha6")]
[EditorDisplay("View Flags", "Global Illumination"), EditorOrder(3060)]
public InputBinding GlobalIlluminationViewFlag = new InputBinding(KeyboardKeys.Alpha6, KeyboardKeys.Control, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3070)]
public InputBinding DirectionalLights = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3080)]
public InputBinding PointLights = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3090)]
public InputBinding SpotLights = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3100)]
public InputBinding SkyLights = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3110)]
public InputBinding Sky = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3120)]
public InputBinding Fog = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3130)]
public InputBinding SpecularLight = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3140)]
public InputBinding Decals = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha3")]
[EditorDisplay("View Flags"), EditorOrder(3150)]
public InputBinding CustomPostProcess = new InputBinding(KeyboardKeys.Alpha3, KeyboardKeys.Control, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3160)]
public InputBinding Bloom = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3170)]
public InputBinding ToneMapping = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha2")]
[EditorDisplay("View Flags"), EditorOrder(3180)]
public InputBinding EyeAdaptation = new InputBinding(KeyboardKeys.Alpha2, KeyboardKeys.Control, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3190)]
public InputBinding CameraArtifacts = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3200)]
public InputBinding LensFlares = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3210)]
public InputBinding DepthOfField = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3220)]
public InputBinding MotionBlur = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3230)]
public InputBinding ContactShadows = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha1")]
[EditorDisplay("View Flags"), EditorOrder(3240)]
public InputBinding PhysicsDebug = new InputBinding(KeyboardKeys.Alpha1, KeyboardKeys.Control, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha5")]
[EditorDisplay("View Flags"), EditorOrder(3250)]
public InputBinding LightsDebug = new InputBinding(KeyboardKeys.Alpha5, KeyboardKeys.Control, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha4")]
[EditorDisplay("View Flags"), EditorOrder(3260)]
public InputBinding DebugDraw = new InputBinding(KeyboardKeys.Alpha4, KeyboardKeys.Control, KeyboardKeys.Shift);
#endregion
#region Interface #region Interface
[DefaultValue(typeof(InputBinding), "Ctrl+W")] [DefaultValue(typeof(InputBinding), "Ctrl+W")]
[EditorDisplay("Interface"), EditorOrder(2000)] [EditorDisplay("Interface"), EditorOrder(3500)]
public InputBinding CloseTab = new InputBinding(KeyboardKeys.W, KeyboardKeys.Control); public InputBinding CloseTab = new InputBinding(KeyboardKeys.W, KeyboardKeys.Control);
[DefaultValue(typeof(InputBinding), "Ctrl+Tab")] [DefaultValue(typeof(InputBinding), "Ctrl+Tab")]
[EditorDisplay("Interface"), EditorOrder(2010)] [EditorDisplay("Interface"), EditorOrder(3510)]
public InputBinding NextTab = new InputBinding(KeyboardKeys.Tab, KeyboardKeys.Control); public InputBinding NextTab = new InputBinding(KeyboardKeys.Tab, KeyboardKeys.Control);
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Tab")] [DefaultValue(typeof(InputBinding), "Shift+Ctrl+Tab")]
[EditorDisplay("Interface"), EditorOrder(2020)] [EditorDisplay("Interface"), EditorOrder(3520)]
public InputBinding PreviousTab = new InputBinding(KeyboardKeys.Tab, KeyboardKeys.Control, KeyboardKeys.Shift); public InputBinding PreviousTab = new InputBinding(KeyboardKeys.Tab, KeyboardKeys.Control, KeyboardKeys.Shift);
[DefaultValue(SceneNodeDoubleClick.Expand)] [DefaultValue(SceneNodeDoubleClick.Expand)]
[EditorDisplay("Interface"), EditorOrder(2030)] [EditorDisplay("Interface"), EditorOrder(3530)]
public SceneNodeDoubleClick DoubleClickSceneNode = SceneNodeDoubleClick.Expand; public SceneNodeDoubleClick DoubleClickSceneNode = SceneNodeDoubleClick.Expand;
#endregion #endregion
#region Windows
/// <summary>
/// Gets or sets a value indicating what window shortcuts will be available during play mode.
/// </summary>
[DefaultValue(PlayModeShortcutAvailability.ProfilerOnly)]
[EditorDisplay("Windows", "Avaliability in Play Mode"), EditorOrder(3000)]
public PlayModeShortcutAvailability PlayModeWindowShortcutAvaliability { get; set; } = PlayModeShortcutAvailability.ProfilerOnly;
[DefaultValue(typeof(InputBinding), "Ctrl+Alpha5")]
[EditorDisplay("Windows"), EditorOrder(3010)]
public InputBinding ContentWindow = new InputBinding(KeyboardKeys.Alpha5, KeyboardKeys.Control);
[DefaultValue(typeof(InputBinding), "Ctrl+Alpha4")]
[EditorDisplay("Windows"), EditorOrder(3020)]
public InputBinding SceneWindow = new InputBinding(KeyboardKeys.Alpha4, KeyboardKeys.Control);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Windows"), EditorOrder(3030)]
public InputBinding ToolboxWindow = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "Ctrl+Alpha3")]
[EditorDisplay("Windows"), EditorOrder(3040)]
public InputBinding PropertiesWindow = new InputBinding(KeyboardKeys.Alpha3, KeyboardKeys.Control);
[DefaultValue(typeof(InputBinding), "Ctrl+Alpha2")]
[EditorDisplay("Windows"), EditorOrder(3050)]
public InputBinding GameWindow = new InputBinding(KeyboardKeys.Alpha2, KeyboardKeys.Control);
[DefaultValue(typeof(InputBinding), "Ctrl+Alpha1")]
[EditorDisplay("Windows"), EditorOrder(3060)]
public InputBinding EditorWindow = new InputBinding(KeyboardKeys.Alpha1, KeyboardKeys.Control);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Windows"), EditorOrder(3070)]
public InputBinding DebugLogWindow = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Windows"), EditorOrder(3080)]
public InputBinding OutputLogWindow = new InputBinding(KeyboardKeys.C, KeyboardKeys.Control, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Windows"), EditorOrder(3090)]
public InputBinding GraphicsQualityWindow = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Windows"), EditorOrder(4000)]
public InputBinding GameCookerWindow = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Windows"), EditorOrder(4010)]
public InputBinding ContentSearchWindow = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Windows"), EditorOrder(4020)]
public InputBinding VisualScriptDebuggerWindow = new InputBinding(KeyboardKeys.None);
#endregion
} }
} }

View File

@@ -35,7 +35,8 @@ namespace FlaxEditor.SceneGraph
return false; return false;
} }
BoundingSphere sphere = new BoundingSphere(Transform.Translation, 7.0f); var center = _actor.Transform.Translation;
ViewportIconsRenderer.GetBounds(ref center, ref ray.Ray.Position, out var sphere);
return CollisionsHelper.RayIntersectsSphere(ref ray.Ray, ref sphere, out distance); return CollisionsHelper.RayIntersectsSphere(ref ray.Ray, ref sphere, out distance);
} }
} }

View File

@@ -28,7 +28,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
_infoLabel = playbackGroup.Label(string.Empty).Label; _infoLabel = playbackGroup.Label(string.Empty).Label;
_infoLabel.AutoHeight = true; _infoLabel.AutoHeight = true;
var grid = playbackGroup.CustomContainer<UniformGridPanel>(); var grid = layout.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = Button.DefaultHeight; gridControl.Height = Button.DefaultHeight;

View File

@@ -320,7 +320,7 @@ namespace FlaxEditor.SceneGraph.GUI
if (noFilter && actor != null) if (noFilter && actor != null)
{ {
// Pick the correct id when inside a prefab window. // Pick the correct id when inside a prefab window.
var id = actor.HasPrefabLink && actor.Scene.Scene == null ? actor.PrefabObjectID : actor.ID; var id = actor.HasPrefabLink && actor.Scene == null ? actor.PrefabObjectID : actor.ID;
isExpanded = Editor.Instance.ProjectCache.IsExpandedActor(ref id); isExpanded = Editor.Instance.ProjectCache.IsExpandedActor(ref id);
} }

View File

@@ -534,7 +534,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Tangent Vector", Title = "Tangent Vector",
Description = "World space tangent vector", Description = "World space tangent vector",
Flags = NodeFlags.MaterialGraph, Flags = NodeFlags.MaterialGraph,
Size = new Float2(160, 40), Size = new Float2(160, 30),
Elements = new[] Elements = new[]
{ {
NodeElementArchetype.Factory.Output(0, "Tangent", typeof(Float3), 0), NodeElementArchetype.Factory.Output(0, "Tangent", typeof(Float3), 0),
@@ -546,7 +546,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Bitangent Vector", Title = "Bitangent Vector",
Description = "World space bitangent vector", Description = "World space bitangent vector",
Flags = NodeFlags.MaterialGraph, Flags = NodeFlags.MaterialGraph,
Size = new Float2(160, 40), Size = new Float2(160, 30),
Elements = new[] Elements = new[]
{ {
NodeElementArchetype.Factory.Output(0, "Bitangent", typeof(Float3), 0), NodeElementArchetype.Factory.Output(0, "Bitangent", typeof(Float3), 0),
@@ -558,7 +558,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Camera Position", Title = "Camera Position",
Description = "World space camera location", Description = "World space camera location",
Flags = NodeFlags.MaterialGraph, Flags = NodeFlags.MaterialGraph,
Size = new Float2(160, 40), Size = new Float2(160, 30),
Elements = new[] Elements = new[]
{ {
NodeElementArchetype.Factory.Output(0, "XYZ", typeof(Float3), 0), NodeElementArchetype.Factory.Output(0, "XYZ", typeof(Float3), 0),
@@ -570,7 +570,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Per Instance Random", Title = "Per Instance Random",
Description = "Per object instance random value (normalized to range 0-1)", Description = "Per object instance random value (normalized to range 0-1)",
Flags = NodeFlags.MaterialGraph, Flags = NodeFlags.MaterialGraph,
Size = new Float2(200, 40), Size = new Float2(200, 30),
Elements = new[] Elements = new[]
{ {
NodeElementArchetype.Factory.Output(0, "", typeof(float), 0), NodeElementArchetype.Factory.Output(0, "", typeof(float), 0),
@@ -607,14 +607,14 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Terrain Layer Weight", Title = "Terrain Layer Weight",
Description = "Terrain layer weight mask used for blending terrain layers", Description = "Terrain layer weight mask used for blending terrain layers",
Flags = NodeFlags.MaterialGraph, Flags = NodeFlags.MaterialGraph,
Size = new Float2(220, 30), Size = new Float2(200, 30),
DefaultValues = new object[] DefaultValues = new object[]
{ {
0, 0,
}, },
Elements = new[] Elements = new[]
{ {
NodeElementArchetype.Factory.ComboBox(0, 0, 70.0f, 0, LayersAndTagsSettings.GetCurrentTerrainLayers()), NodeElementArchetype.Factory.ComboBox(0, 0, 175.0f, 0, LayersAndTagsSettings.GetCurrentTerrainLayers()),
NodeElementArchetype.Factory.Output(0, "", typeof(float), 0), NodeElementArchetype.Factory.Output(0, "", typeof(float), 0),
} }
}, },

View File

@@ -409,7 +409,7 @@ namespace FlaxEditor.Surface
/// <summary> /// <summary>
/// Called after adding the control to the surface after paste. /// Called after adding the control to the surface after paste.
/// </summary> /// </summary>
/// <param name="idsMapping">The nodes IDs mapping (original node ID to pasted node ID). Can be sued to update internal node's data after paste operation from the original data.</param> /// <param name="idsMapping">The nodes IDs mapping (original node ID to pasted node ID). Can be used to update internal node's data after paste operation from the original data.</param>
public virtual void OnPasted(System.Collections.Generic.Dictionary<uint, uint> idsMapping) public virtual void OnPasted(System.Collections.Generic.Dictionary<uint, uint> idsMapping)
{ {
} }

View File

@@ -369,24 +369,14 @@ namespace FlaxEditor.Surface
} }
// Change scale (disable scaling during selecting nodes) // Change scale (disable scaling during selecting nodes)
if (IsMouseOver && !_leftMouseDown && !IsPrimaryMenuOpened) if (IsMouseOver && !_leftMouseDown && !_rightMouseDown && !IsPrimaryMenuOpened)
{ {
var nextViewScale = ViewScale + delta * 0.1f; var nextViewScale = ViewScale + delta * 0.1f;
if (delta > 0 && !_rightMouseDown) // Scale towards/ away from mouse when zooming in/ out
{
// Scale towards mouse when zooming in
var nextCenterPosition = ViewPosition + location / ViewScale; var nextCenterPosition = ViewPosition + location / ViewScale;
ViewScale = nextViewScale; ViewScale = nextViewScale;
ViewPosition = nextCenterPosition - (location / ViewScale); ViewPosition = nextCenterPosition - (location / ViewScale);
}
else
{
// Scale while keeping center position when zooming out or when dragging view
var viewCenter = ViewCenterPosition;
ViewScale = nextViewScale;
ViewCenterPosition = viewCenter;
}
return true; return true;
} }
@@ -498,11 +488,9 @@ namespace FlaxEditor.Surface
// Check if user is pressing control // Check if user is pressing control
if (Root.GetKey(KeyboardKeys.Control)) if (Root.GetKey(KeyboardKeys.Control))
{ {
// Add to selection // Add/remove from selection
if (!controlUnderMouse.IsSelected) controlUnderMouse.IsSelected = !controlUnderMouse.IsSelected;
{ SelectionChanged?.Invoke();
AddToSelection(controlUnderMouse);
}
} }
// Check if node isn't selected // Check if node isn't selected
else if (!controlUnderMouse.IsSelected) else if (!controlUnderMouse.IsSelected)

View File

@@ -20,5 +20,7 @@ namespace FlaxEditor.Utilities
#else #else
public const string ShowInExplorer = "Show in explorer"; public const string ShowInExplorer = "Show in explorer";
#endif #endif
public const float UIMargin = 3.0f;
} }
} }

View File

@@ -415,13 +415,10 @@ namespace FlaxEditor.Utilities
/// </summary> /// </summary>
/// <param name="parentLayout">The parent layout element.</param> /// <param name="parentLayout">The parent layout element.</param>
/// <param name="path">The import path.</param> /// <param name="path">The import path.</param>
/// <param name="useInitialSpacing">Whether to use an initial layout space of 5 for separation.</param> public static void CreateImportPathUI(CustomEditors.LayoutElementsContainer parentLayout, string path)
public static void CreateImportPathUI(CustomEditors.LayoutElementsContainer parentLayout, string path, bool useInitialSpacing = true)
{ {
if (!string.IsNullOrEmpty(path)) if (!string.IsNullOrEmpty(path))
{ {
if (useInitialSpacing)
parentLayout.Space(0);
var textBox = parentLayout.TextBox().TextBox; var textBox = parentLayout.TextBox().TextBox;
textBox.TooltipText = "Source asset path. Can be relative or absolute to the project. Path is not editable here."; textBox.TooltipText = "Source asset path. Can be relative or absolute to the project. Path is not editable here.";
textBox.IsReadOnly = true; textBox.IsReadOnly = true;
@@ -1503,7 +1500,6 @@ namespace FlaxEditor.Utilities
inputActions.Add(options => options.BuildNav, Editor.Instance.BuildNavMesh); inputActions.Add(options => options.BuildNav, Editor.Instance.BuildNavMesh);
inputActions.Add(options => options.BuildSDF, Editor.Instance.BuildAllMeshesSDF); inputActions.Add(options => options.BuildSDF, Editor.Instance.BuildAllMeshesSDF);
inputActions.Add(options => options.TakeScreenshot, Editor.Instance.Windows.TakeScreenshot); inputActions.Add(options => options.TakeScreenshot, Editor.Instance.Windows.TakeScreenshot);
inputActions.Add(options => options.ProfilerWindow, () => Editor.Instance.Windows.ProfilerWin.FocusOrShow());
#if USE_PROFILER #if USE_PROFILER
inputActions.Add(options => options.ProfilerStartStop, () => inputActions.Add(options => options.ProfilerStartStop, () =>
{ {

View File

@@ -24,8 +24,6 @@
#include "Engine/Level/Actors/SpotLight.h" #include "Engine/Level/Actors/SpotLight.h"
#include "Engine/Video/VideoPlayer.h" #include "Engine/Video/VideoPlayer.h"
#define ICON_RADIUS 7.0f
enum class IconTypes enum class IconTypes
{ {
PointLight, PointLight,
@@ -67,6 +65,16 @@ public:
}; };
ViewportIconsRendererService ViewportIconsRendererServiceInstance; ViewportIconsRendererService ViewportIconsRendererServiceInstance;
float ViewportIconsRenderer::Scale = 1.0f;
void ViewportIconsRenderer::GetBounds(const Vector3& position, const Vector3& viewPosition, BoundingSphere& bounds)
{
constexpr Real minSize = 7.0;
constexpr Real maxSize = 30.0;
Real scale = Math::Square(Vector3::Distance(position, viewPosition) / 1000.0f);
Real radius = minSize + Math::Min<Real>(scale, 1.0f) * (maxSize - minSize);
bounds = BoundingSphere(position, radius * Scale);
}
void ViewportIconsRenderer::DrawIcons(RenderContext& renderContext, Actor* actor) void ViewportIconsRenderer::DrawIcons(RenderContext& renderContext, Actor* actor)
{ {
@@ -134,7 +142,8 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Scene
AssetReference<Texture> texture; AssetReference<Texture> texture;
for (Actor* icon : icons) for (Actor* icon : icons)
{ {
BoundingSphere sphere(icon->GetPosition() - renderContext.View.Origin, ICON_RADIUS); BoundingSphere sphere;
ViewportIconsRenderer::GetBounds(icon->GetPosition() - renderContext.View.Origin, renderContext.View.Position, sphere);
if (!frustum.Intersects(sphere)) if (!frustum.Intersects(sphere))
continue; continue;
IconTypes iconType; IconTypes iconType;
@@ -174,7 +183,7 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Scene
if (draw.Buffer) if (draw.Buffer)
{ {
// Create world matrix // Create world matrix
Matrix::Scaling(ICON_RADIUS * 2.0f, m2); Matrix::Scaling((float)sphere.Radius * 2.0f, m2);
Matrix::RotationY(PI, world); Matrix::RotationY(PI, world);
Matrix::Multiply(m2, world, m1); Matrix::Multiply(m2, world, m1);
Matrix::Billboard(sphere.Center, view.Position, Vector3::Up, view.Direction, m2); Matrix::Billboard(sphere.Center, view.Position, Vector3::Up, view.Direction, m2);
@@ -194,14 +203,15 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor
auto& view = renderContext.View; auto& view = renderContext.View;
const BoundingFrustum frustum = view.Frustum; const BoundingFrustum frustum = view.Frustum;
Matrix m1, m2, world; Matrix m1, m2, world;
BoundingSphere sphere(actor->GetPosition() - renderContext.View.Origin, ICON_RADIUS); BoundingSphere sphere;
ViewportIconsRenderer::GetBounds(actor->GetPosition() - renderContext.View.Origin, renderContext.View.Position, sphere);
IconTypes iconType; IconTypes iconType;
AssetReference<Texture> texture; AssetReference<Texture> texture;
if (frustum.Intersects(sphere) && ActorTypeToIconType.TryGet(actor->GetTypeHandle(), iconType)) if (frustum.Intersects(sphere) && ActorTypeToIconType.TryGet(actor->GetTypeHandle(), iconType))
{ {
// Create world matrix // Create world matrix
Matrix::Scaling(ICON_RADIUS * 2.0f, m2); Matrix::Scaling((float)sphere.Radius * 2.0f, m2);
Matrix::RotationY(PI, world); Matrix::RotationY(PI, world);
Matrix::Multiply(m2, world, m1); Matrix::Multiply(m2, world, m1);
Matrix::Billboard(sphere.Center, view.Position, Vector3::Up, view.Direction, m2); Matrix::Billboard(sphere.Center, view.Position, Vector3::Up, view.Direction, m2);

View File

@@ -17,6 +17,19 @@ API_CLASS(Static, Namespace="FlaxEditor") class FLAXENGINE_API ViewportIconsRend
DECLARE_SCRIPTING_TYPE_NO_SPAWN(ViewportIconsRenderer); DECLARE_SCRIPTING_TYPE_NO_SPAWN(ViewportIconsRenderer);
public: public:
/// <summary>
/// Global scale of the icons.
/// </summary>
API_FIELD() static float Scale;
/// <summary>
/// Draws the icons for the actors in the given scene (or actor tree).
/// </summary>
/// <param name="position">The icon position.</param>
/// <param name="viewPosition">The viewer position.</param>
/// <param name="bounds">The computed bounds for the icon.</param>
API_FUNCTION() static void GetBounds(API_PARAM(Ref) const Vector3& position, API_PARAM(Ref) const Vector3& viewPosition, API_PARAM(Out) BoundingSphere& bounds);
/// <summary> /// <summary>
/// Draws the icons for the actors in the given scene (or actor tree). /// Draws the icons for the actors in the given scene (or actor tree).
/// </summary> /// </summary>

View File

@@ -910,7 +910,7 @@ namespace FlaxEditor.Viewport
for (int i = 0; i < ViewFlagsValues.Length; i++) for (int i = 0; i < ViewFlagsValues.Length; i++)
{ {
var v = ViewFlagsValues[i]; var v = ViewFlagsValues[i];
var button = viewFlags.AddButton(v.Name); var button = viewFlags.AddButton(v.Name, v.InputBinding.ToString());
button.CloseMenuOnClick = false; button.CloseMenuOnClick = false;
button.Tag = v.Mode; button.Tag = v.Mode;
} }
@@ -959,7 +959,7 @@ namespace FlaxEditor.Viewport
} }
else else
{ {
var button = debugView.AddButton(v.Name); var button = debugView.AddButton(v.Name, v.InputBinding.ToString());
button.CloseMenuOnClick = false; button.CloseMenuOnClick = false;
button.Tag = v.Mode; button.Tag = v.Mode;
} }
@@ -1002,19 +1002,79 @@ namespace FlaxEditor.Viewport
ViewWidgetButtonMenu.VisibleChanged += control => resolutionValue.Value = ResolutionScale; ViewWidgetButtonMenu.VisibleChanged += control => resolutionValue.Value = ResolutionScale;
} }
// Icons Scale
{
var icons = ViewWidgetButtonMenu.AddButton("Icons");
icons.CloseMenuOnClick = false;
var iconsValue = new FloatValueBox(ViewportIconsRenderer.Scale, xLocationForExtras, 2, 70.0f, 0.01f, 100.0f, 0.001f)
{
Parent = icons
};
iconsValue.ValueChanged += () => ViewportIconsRenderer.Scale = iconsValue.Value;
ViewWidgetButtonMenu.VisibleChanged += control => iconsValue.Value = ViewportIconsRenderer.Scale;
}
#endregion View mode widget #endregion View mode widget
} }
// Viewpoints
InputActions.Add(options => options.ViewpointTop, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Top").Orientation))); InputActions.Add(options => options.ViewpointTop, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Top").Orientation)));
InputActions.Add(options => options.ViewpointBottom, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Bottom").Orientation))); InputActions.Add(options => options.ViewpointBottom, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Bottom").Orientation)));
InputActions.Add(options => options.ViewpointFront, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Front").Orientation))); InputActions.Add(options => options.ViewpointFront, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Front").Orientation)));
InputActions.Add(options => options.ViewpointBack, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Back").Orientation))); InputActions.Add(options => options.ViewpointBack, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Back").Orientation)));
InputActions.Add(options => options.ViewpointRight, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Right").Orientation))); InputActions.Add(options => options.ViewpointRight, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Right").Orientation)));
InputActions.Add(options => options.ViewpointLeft, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Left").Orientation))); InputActions.Add(options => options.ViewpointLeft, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Left").Orientation)));
// Editor camera
InputActions.Add(options => options.CameraToggleRotation, () => _isVirtualMouseRightDown = !_isVirtualMouseRightDown); InputActions.Add(options => options.CameraToggleRotation, () => _isVirtualMouseRightDown = !_isVirtualMouseRightDown);
InputActions.Add(options => options.CameraIncreaseMoveSpeed, () => AdjustCameraMoveSpeed(1)); InputActions.Add(options => options.CameraIncreaseMoveSpeed, () => AdjustCameraMoveSpeed(1));
InputActions.Add(options => options.CameraDecreaseMoveSpeed, () => AdjustCameraMoveSpeed(-1)); InputActions.Add(options => options.CameraDecreaseMoveSpeed, () => AdjustCameraMoveSpeed(-1));
InputActions.Add(options => options.ToggleOrthographic, () => OnOrthographicModeToggled(null)); InputActions.Add(options => options.ToggleOrthographic, () => OnOrthographicModeToggled(null));
// Debug views
InputActions.Add(options => options.Default, () => Task.ViewMode = ViewMode.Default);
InputActions.Add(options => options.Unlit, () => Task.ViewMode = ViewMode.Unlit);
InputActions.Add(options => options.NoPostFX, () => Task.ViewMode = ViewMode.NoPostFx);
InputActions.Add(options => options.Wireframe, () => Task.ViewMode = ViewMode.Wireframe);
InputActions.Add(options => options.LightBuffer, () => Task.ViewMode = ViewMode.LightBuffer);
InputActions.Add(options => options.ReflectionsBuffer, () => Task.ViewMode = ViewMode.Reflections);
InputActions.Add(options => options.DepthBuffer, () => Task.ViewMode = ViewMode.Depth);
InputActions.Add(options => options.MotionVectors, () => Task.ViewMode = ViewMode.MotionVectors);
InputActions.Add(options => options.LightmapUVDensity, () => Task.ViewMode = ViewMode.LightmapUVsDensity);
InputActions.Add(options => options.VertexColors, () => Task.ViewMode = ViewMode.VertexColors);
InputActions.Add(options => options.PhysicsColliders, () => Task.ViewMode = ViewMode.PhysicsColliders);
InputActions.Add(options => options.LODPreview, () => Task.ViewMode = ViewMode.LODPreview);
InputActions.Add(options => options.MaterialComplexity, () => Task.ViewMode = ViewMode.MaterialComplexity);
InputActions.Add(options => options.QuadOverdraw, () => Task.ViewMode = ViewMode.QuadOverdraw);
InputActions.Add(options => options.GloablSDF, () => Task.ViewMode = ViewMode.GlobalSDF);
InputActions.Add(options => options.GlobalSurfaceAtlas, () => Task.ViewMode = ViewMode.GlobalSurfaceAtlas);
InputActions.Add(options => options.GlobalIllumination, () => Task.ViewMode = ViewMode.GlobalIllumination);
// View flags
InputActions.Add(options => options.AntiAliasing, () => Task.ViewFlags ^= ViewFlags.AntiAliasing);
InputActions.Add(options => options.Shadows, () => Task.ViewFlags ^= ViewFlags.Shadows);
InputActions.Add(options => options.EditorSprites, () => Task.ViewFlags ^= ViewFlags.EditorSprites);
InputActions.Add(options => options.Reflections, () => Task.ViewFlags ^= ViewFlags.Reflections);
InputActions.Add(options => options.ScreenSpaceReflections, () => Task.ViewFlags ^= ViewFlags.SSR);
InputActions.Add(options => options.AmbientOcclusion, () => Task.ViewFlags ^= ViewFlags.AO);
InputActions.Add(options => options.GlobalIllumination, () => Task.ViewFlags ^= ViewFlags.GI);
InputActions.Add(options => options.DirectionalLights, () => Task.ViewFlags ^= ViewFlags.DirectionalLights);
InputActions.Add(options => options.PointLights, () => Task.ViewFlags ^= ViewFlags.PointLights);
InputActions.Add(options => options.SpotLights, () => Task.ViewFlags ^= ViewFlags.SpotLights);
InputActions.Add(options => options.SkyLights, () => Task.ViewFlags ^= ViewFlags.SkyLights);
InputActions.Add(options => options.Sky, () => Task.ViewFlags ^= ViewFlags.Sky);
InputActions.Add(options => options.Fog, () => Task.ViewFlags ^= ViewFlags.Fog);
InputActions.Add(options => options.SpecularLight, () => Task.ViewFlags ^= ViewFlags.SpecularLight);
InputActions.Add(options => options.Decals, () => Task.ViewFlags ^= ViewFlags.Decals);
InputActions.Add(options => options.CustomPostProcess, () => Task.ViewFlags ^= ViewFlags.CustomPostProcess);
InputActions.Add(options => options.Bloom, () => Task.ViewFlags ^= ViewFlags.Bloom);
InputActions.Add(options => options.ToneMapping, () => Task.ViewFlags ^= ViewFlags.ToneMapping);
InputActions.Add(options => options.EyeAdaptation, () => Task.ViewFlags ^= ViewFlags.EyeAdaptation);
InputActions.Add(options => options.CameraArtifacts, () => Task.ViewFlags ^= ViewFlags.CameraArtifacts);
InputActions.Add(options => options.LensFlares, () => Task.ViewFlags ^= ViewFlags.LensFlares);
InputActions.Add(options => options.DepthOfField, () => Task.ViewFlags ^= ViewFlags.DepthOfField);
InputActions.Add(options => options.MotionBlur, () => Task.ViewFlags ^= ViewFlags.MotionBlur);
InputActions.Add(options => options.ContactShadows, () => Task.ViewFlags ^= ViewFlags.ContactShadows);
InputActions.Add(options => options.PhysicsDebug, () => Task.ViewFlags ^= ViewFlags.PhysicsDebug);
InputActions.Add(options => options.LightsDebug, () => Task.ViewFlags ^= ViewFlags.LightsDebug);
InputActions.Add(options => options.DebugDraw, () => Task.ViewFlags ^= ViewFlags.DebugDraw);
// Link for task event // Link for task event
task.Begin += OnRenderBegin; task.Begin += OnRenderBegin;
@@ -1933,8 +1993,17 @@ namespace FlaxEditor.Viewport
{ {
public readonly string Name; public readonly string Name;
public readonly ViewMode Mode; public readonly ViewMode Mode;
public readonly InputBinding InputBinding;
public readonly ViewModeOptions[] Options; public readonly ViewModeOptions[] Options;
public ViewModeOptions(ViewMode mode, string name, InputBinding inputBinding)
{
Mode = mode;
Name = name;
InputBinding = inputBinding;
Options = null;
}
public ViewModeOptions(ViewMode mode, string name) public ViewModeOptions(ViewMode mode, string name)
{ {
Mode = mode; Mode = mode;
@@ -1952,13 +2021,13 @@ namespace FlaxEditor.Viewport
private static readonly ViewModeOptions[] ViewModeValues = private static readonly ViewModeOptions[] ViewModeValues =
{ {
new ViewModeOptions(ViewMode.Default, "Default"), new ViewModeOptions(ViewMode.Default, "Default", Editor.Instance.Options.Options.Input.Default),
new ViewModeOptions(ViewMode.Unlit, "Unlit"), new ViewModeOptions(ViewMode.Unlit, "Unlit", Editor.Instance.Options.Options.Input.Unlit),
new ViewModeOptions(ViewMode.NoPostFx, "No PostFx"), new ViewModeOptions(ViewMode.NoPostFx, "No PostFx", Editor.Instance.Options.Options.Input.NoPostFX),
new ViewModeOptions(ViewMode.Wireframe, "Wireframe"), new ViewModeOptions(ViewMode.Wireframe, "Wireframe", Editor.Instance.Options.Options.Input.Wireframe),
new ViewModeOptions(ViewMode.LightBuffer, "Light Buffer"), new ViewModeOptions(ViewMode.LightBuffer, "Light Buffer", Editor.Instance.Options.Options.Input.LightBuffer),
new ViewModeOptions(ViewMode.Reflections, "Reflections Buffer"), new ViewModeOptions(ViewMode.Reflections, "Reflections Buffer", Editor.Instance.Options.Options.Input.ReflectionsBuffer),
new ViewModeOptions(ViewMode.Depth, "Depth Buffer"), new ViewModeOptions(ViewMode.Depth, "Depth Buffer", Editor.Instance.Options.Options.Input.DepthBuffer),
new ViewModeOptions("GBuffer", new[] new ViewModeOptions("GBuffer", new[]
{ {
new ViewModeOptions(ViewMode.Diffuse, "Diffuse"), new ViewModeOptions(ViewMode.Diffuse, "Diffuse"),
@@ -1972,16 +2041,16 @@ namespace FlaxEditor.Viewport
new ViewModeOptions(ViewMode.Normals, "Normals"), new ViewModeOptions(ViewMode.Normals, "Normals"),
new ViewModeOptions(ViewMode.AmbientOcclusion, "Ambient Occlusion"), new ViewModeOptions(ViewMode.AmbientOcclusion, "Ambient Occlusion"),
}), }),
new ViewModeOptions(ViewMode.MotionVectors, "Motion Vectors"), new ViewModeOptions(ViewMode.MotionVectors, "Motion Vectors", Editor.Instance.Options.Options.Input.MotionVectors),
new ViewModeOptions(ViewMode.LightmapUVsDensity, "Lightmap UVs Density"), new ViewModeOptions(ViewMode.LightmapUVsDensity, "Lightmap UVs Density", Editor.Instance.Options.Options.Input.LightmapUVDensity),
new ViewModeOptions(ViewMode.VertexColors, "Vertex Colors"), new ViewModeOptions(ViewMode.VertexColors, "Vertex Colors", Editor.Instance.Options.Options.Input.VertexColors),
new ViewModeOptions(ViewMode.PhysicsColliders, "Physics Colliders"), new ViewModeOptions(ViewMode.PhysicsColliders, "Physics Colliders", Editor.Instance.Options.Options.Input.PhysicsColliders),
new ViewModeOptions(ViewMode.LODPreview, "LOD Preview"), new ViewModeOptions(ViewMode.LODPreview, "LOD Preview", Editor.Instance.Options.Options.Input.LODPreview),
new ViewModeOptions(ViewMode.MaterialComplexity, "Material Complexity"), new ViewModeOptions(ViewMode.MaterialComplexity, "Material Complexity", Editor.Instance.Options.Options.Input.MaterialComplexity),
new ViewModeOptions(ViewMode.QuadOverdraw, "Quad Overdraw"), new ViewModeOptions(ViewMode.QuadOverdraw, "Quad Overdraw", Editor.Instance.Options.Options.Input.QuadOverdraw),
new ViewModeOptions(ViewMode.GlobalSDF, "Global SDF"), new ViewModeOptions(ViewMode.GlobalSDF, "Global SDF", Editor.Instance.Options.Options.Input.GloablSDF),
new ViewModeOptions(ViewMode.GlobalSurfaceAtlas, "Global Surface Atlas"), new ViewModeOptions(ViewMode.GlobalSurfaceAtlas, "Global Surface Atlas", Editor.Instance.Options.Options.Input.GlobalSurfaceAtlas),
new ViewModeOptions(ViewMode.GlobalIllumination, "Global Illumination"), new ViewModeOptions(ViewMode.GlobalIllumination, "Global Illumination", Editor.Instance.Options.Options.Input.GlobalIllumination),
}; };
private void WidgetViewModeShowHideClicked(ContextMenuButton button) private void WidgetViewModeShowHideClicked(ContextMenuButton button)
@@ -2014,43 +2083,45 @@ namespace FlaxEditor.Viewport
{ {
public readonly ViewFlags Mode; public readonly ViewFlags Mode;
public readonly string Name; public readonly string Name;
public readonly InputBinding InputBinding;
public ViewFlagOptions(ViewFlags mode, string name) public ViewFlagOptions(ViewFlags mode, string name, InputBinding inputBinding)
{ {
Mode = mode; Mode = mode;
Name = name; Name = name;
InputBinding = inputBinding;
} }
} }
private static readonly ViewFlagOptions[] ViewFlagsValues = private static readonly ViewFlagOptions[] ViewFlagsValues =
{ {
new ViewFlagOptions(ViewFlags.AntiAliasing, "Anti Aliasing"), new ViewFlagOptions(ViewFlags.AntiAliasing, "Anti Aliasing", Editor.Instance.Options.Options.Input.AntiAliasing),
new ViewFlagOptions(ViewFlags.Shadows, "Shadows"), new ViewFlagOptions(ViewFlags.Shadows, "Shadows", Editor.Instance.Options.Options.Input.Shadows),
new ViewFlagOptions(ViewFlags.EditorSprites, "Editor Sprites"), new ViewFlagOptions(ViewFlags.EditorSprites, "Editor Sprites", Editor.Instance.Options.Options.Input.EditorSprites),
new ViewFlagOptions(ViewFlags.Reflections, "Reflections"), new ViewFlagOptions(ViewFlags.Reflections, "Reflections", Editor.Instance.Options.Options.Input.Reflections),
new ViewFlagOptions(ViewFlags.SSR, "Screen Space Reflections"), new ViewFlagOptions(ViewFlags.SSR, "Screen Space Reflections", Editor.Instance.Options.Options.Input.ScreenSpaceReflections),
new ViewFlagOptions(ViewFlags.AO, "Ambient Occlusion"), new ViewFlagOptions(ViewFlags.AO, "Ambient Occlusion", Editor.Instance.Options.Options.Input.AmbientOcclusion),
new ViewFlagOptions(ViewFlags.GI, "Global Illumination"), new ViewFlagOptions(ViewFlags.GI, "Global Illumination", Editor.Instance.Options.Options.Input.GlobalIlluminationViewFlag),
new ViewFlagOptions(ViewFlags.DirectionalLights, "Directional Lights"), new ViewFlagOptions(ViewFlags.DirectionalLights, "Directional Lights", Editor.Instance.Options.Options.Input.DirectionalLights),
new ViewFlagOptions(ViewFlags.PointLights, "Point Lights"), new ViewFlagOptions(ViewFlags.PointLights, "Point Lights", Editor.Instance.Options.Options.Input.PointLights),
new ViewFlagOptions(ViewFlags.SpotLights, "Spot Lights"), new ViewFlagOptions(ViewFlags.SpotLights, "Spot Lights", Editor.Instance.Options.Options.Input.SpotLights),
new ViewFlagOptions(ViewFlags.SkyLights, "Sky Lights"), new ViewFlagOptions(ViewFlags.SkyLights, "Sky Lights", Editor.Instance.Options.Options.Input.SkyLights),
new ViewFlagOptions(ViewFlags.Sky, "Sky"), new ViewFlagOptions(ViewFlags.Sky, "Sky", Editor.Instance.Options.Options.Input.Sky),
new ViewFlagOptions(ViewFlags.Fog, "Fog"), new ViewFlagOptions(ViewFlags.Fog, "Fog", Editor.Instance.Options.Options.Input.Fog),
new ViewFlagOptions(ViewFlags.SpecularLight, "Specular Light"), new ViewFlagOptions(ViewFlags.SpecularLight, "Specular Light", Editor.Instance.Options.Options.Input.SpecularLight),
new ViewFlagOptions(ViewFlags.Decals, "Decals"), new ViewFlagOptions(ViewFlags.Decals, "Decals", Editor.Instance.Options.Options.Input.Decals),
new ViewFlagOptions(ViewFlags.CustomPostProcess, "Custom Post Process"), new ViewFlagOptions(ViewFlags.CustomPostProcess, "Custom Post Process", Editor.Instance.Options.Options.Input.CustomPostProcess),
new ViewFlagOptions(ViewFlags.Bloom, "Bloom"), new ViewFlagOptions(ViewFlags.Bloom, "Bloom", Editor.Instance.Options.Options.Input.Bloom),
new ViewFlagOptions(ViewFlags.ToneMapping, "Tone Mapping"), new ViewFlagOptions(ViewFlags.ToneMapping, "Tone Mapping", Editor.Instance.Options.Options.Input.ToneMapping),
new ViewFlagOptions(ViewFlags.EyeAdaptation, "Eye Adaptation"), new ViewFlagOptions(ViewFlags.EyeAdaptation, "Eye Adaptation", Editor.Instance.Options.Options.Input.EyeAdaptation),
new ViewFlagOptions(ViewFlags.CameraArtifacts, "Camera Artifacts"), new ViewFlagOptions(ViewFlags.CameraArtifacts, "Camera Artifacts", Editor.Instance.Options.Options.Input.CameraArtifacts),
new ViewFlagOptions(ViewFlags.LensFlares, "Lens Flares"), new ViewFlagOptions(ViewFlags.LensFlares, "Lens Flares", Editor.Instance.Options.Options.Input.LensFlares),
new ViewFlagOptions(ViewFlags.DepthOfField, "Depth of Field"), new ViewFlagOptions(ViewFlags.DepthOfField, "Depth of Field", Editor.Instance.Options.Options.Input.DepthOfField),
new ViewFlagOptions(ViewFlags.MotionBlur, "Motion Blur"), new ViewFlagOptions(ViewFlags.MotionBlur, "Motion Blur", Editor.Instance.Options.Options.Input.MotionBlur),
new ViewFlagOptions(ViewFlags.ContactShadows, "Contact Shadows"), new ViewFlagOptions(ViewFlags.ContactShadows, "Contact Shadows", Editor.Instance.Options.Options.Input.ContactShadows),
new ViewFlagOptions(ViewFlags.PhysicsDebug, "Physics Debug"), new ViewFlagOptions(ViewFlags.PhysicsDebug, "Physics Debug", Editor.Instance.Options.Options.Input.PhysicsDebug),
new ViewFlagOptions(ViewFlags.LightsDebug, "Lights Debug"), new ViewFlagOptions(ViewFlags.LightsDebug, "Lights Debug", Editor.Instance.Options.Options.Input.LightsDebug),
new ViewFlagOptions(ViewFlags.DebugDraw, "Debug Draw"), new ViewFlagOptions(ViewFlags.DebugDraw, "Debug Draw", Editor.Instance.Options.Options.Input.DebugDraw),
}; };
private void WidgetViewFlagsShowHide(Control cm) private void WidgetViewFlagsShowHide(Control cm)

View File

@@ -185,7 +185,7 @@ namespace FlaxEditor.Viewport.Previews
{ {
UseTimeScale = false, UseTimeScale = false,
UpdateWhenOffscreen = true, UpdateWhenOffscreen = true,
BoundsScale = 100.0f, BoundsScale = 1.0f,
UpdateMode = AnimatedModel.AnimationUpdateMode.Manual, UpdateMode = AnimatedModel.AnimationUpdateMode.Manual,
}; };
Task.AddCustomActor(_previewModel); Task.AddCustomActor(_previewModel);

View File

@@ -635,5 +635,11 @@ namespace FlaxEditor.Windows.Assets
public void Select(List<SceneGraphNode> nodes) public void Select(List<SceneGraphNode> nodes)
{ {
} }
/// <inheritdoc />
public List<SceneGraphNode> Selection => new List<SceneGraphNode>();
/// <inheritdoc />
public bool LockSelection { get; set; }
} }
} }

View File

@@ -76,29 +76,29 @@ namespace FlaxEditor.Windows.Assets
// Transparency // Transparency
[EditorOrder(200), DefaultValue(MaterialTransparentLightingMode.Surface), VisibleIf(nameof(IsStandard)), EditorDisplay("Transparency"), Tooltip("Transparent material lighting mode.")] [EditorOrder(200), DefaultValue(MaterialTransparentLightingMode.Surface), VisibleIf(nameof(IsForward)), EditorDisplay("Transparency"), Tooltip("Transparent material lighting mode.")]
public MaterialTransparentLightingMode TransparentLightingMode; public MaterialTransparentLightingMode TransparentLightingMode;
[EditorOrder(205), DefaultValue(true), VisibleIf(nameof(IsStandard)), EditorDisplay("Transparency"), Tooltip("Enables reflections when rendering material.")] [EditorOrder(205), DefaultValue(true), VisibleIf(nameof(IsForward)), EditorDisplay("Transparency"), Tooltip("Enables reflections when rendering material.")]
public bool EnableReflections; public bool EnableReflections;
[VisibleIf(nameof(EnableReflections))] [VisibleIf(nameof(EnableReflections))]
[EditorOrder(210), DefaultValue(false), VisibleIf(nameof(IsStandard)), EditorDisplay("Transparency"), Tooltip("Enables Screen Space Reflections when rendering material.")] [EditorOrder(210), DefaultValue(false), VisibleIf(nameof(IsForward)), EditorDisplay("Transparency"), Tooltip("Enables Screen Space Reflections when rendering material.")]
public bool EnableScreenSpaceReflections; public bool EnableScreenSpaceReflections;
[EditorOrder(210), DefaultValue(true), VisibleIf(nameof(IsStandard)), EditorDisplay("Transparency"), Tooltip("Enables fog effects when rendering material.")] [EditorOrder(210), DefaultValue(true), VisibleIf(nameof(IsForward)), EditorDisplay("Transparency"), Tooltip("Enables fog effects when rendering material.")]
public bool EnableFog; public bool EnableFog;
[EditorOrder(220), DefaultValue(true), VisibleIf(nameof(IsStandard)), EditorDisplay("Transparency"), Tooltip("Enables distortion effect when rendering.")] [EditorOrder(220), DefaultValue(true), VisibleIf(nameof(IsForward)), EditorDisplay("Transparency"), Tooltip("Enables distortion effect when rendering.")]
public bool EnableDistortion; public bool EnableDistortion;
[EditorOrder(224), DefaultValue(false), VisibleIf(nameof(IsStandard)), EditorDisplay("Transparency"), Tooltip("Enables sampling Global Illumination in material (eg. light probes or volumetric lightmap).")] [EditorOrder(224), DefaultValue(false), VisibleIf(nameof(IsForward)), EditorDisplay("Transparency"), Tooltip("Enables sampling Global Illumination in material (eg. light probes or volumetric lightmap).")]
public bool EnableGlobalIllumination; public bool EnableGlobalIllumination;
[EditorOrder(225), DefaultValue(false), VisibleIf(nameof(IsStandard)), EditorDisplay("Transparency"), Tooltip("Enables refraction offset based on the difference between the per-pixel normal and the per-vertex normal. Useful for large water-like surfaces.")] [EditorOrder(225), DefaultValue(false), VisibleIf(nameof(IsForward)), EditorDisplay("Transparency"), Tooltip("Enables refraction offset based on the difference between the per-pixel normal and the per-vertex normal. Useful for large water-like surfaces.")]
public bool PixelNormalOffsetRefraction; public bool PixelNormalOffsetRefraction;
[EditorOrder(230), DefaultValue(0.12f), VisibleIf(nameof(IsStandard)), EditorDisplay("Transparency"), Tooltip("Controls opacity values clipping point."), Limit(0.0f, 1.0f, 0.01f)] [EditorOrder(230), DefaultValue(0.12f), VisibleIf(nameof(IsForward)), EditorDisplay("Transparency"), Tooltip("Controls opacity values clipping point."), Limit(0.0f, 1.0f, 0.01f)]
public float OpacityThreshold; public float OpacityThreshold;
// Tessellation // Tessellation
@@ -146,6 +146,7 @@ namespace FlaxEditor.Windows.Assets
private bool IsDecal => Domain == MaterialDomain.Decal; private bool IsDecal => Domain == MaterialDomain.Decal;
private bool IsGUI => Domain == MaterialDomain.GUI; private bool IsGUI => Domain == MaterialDomain.GUI;
private bool IsStandard => Domain == MaterialDomain.Surface || Domain == MaterialDomain.Terrain || Domain == MaterialDomain.Particle || Domain == MaterialDomain.Deformable; private bool IsStandard => Domain == MaterialDomain.Surface || Domain == MaterialDomain.Terrain || Domain == MaterialDomain.Particle || Domain == MaterialDomain.Deformable;
private bool IsForward => Domain == MaterialDomain.Particle || ((Domain == MaterialDomain.Deformable || Domain == MaterialDomain.Surface) && BlendMode != MaterialBlendMode.Opaque);
private bool IsStandardOrGUI => IsStandard || IsGUI; private bool IsStandardOrGUI => IsStandard || IsGUI;
/// <summary> /// <summary>

View File

@@ -254,6 +254,7 @@ namespace FlaxEditor.Windows.Assets
if (lodIndex >= countLODs - loadedLODs) if (lodIndex >= countLODs - loadedLODs)
{ {
var mesh = lod.GetMesh(0); var mesh = lod.GetMesh(0);
if (mesh != null)
vertexLayout = mesh.VertexLayout; vertexLayout = mesh.VertexLayout;
if (vertexLayout != null && vertexLayout.Elements.Length != 0) if (vertexLayout != null && vertexLayout.Elements.Length != 0)
break; break;
@@ -759,7 +760,6 @@ namespace FlaxEditor.Windows.Assets
var importSettingsField = typeof(ImportPropertiesProxyBase).GetField(nameof(ImportSettings), BindingFlags.NonPublic | BindingFlags.Instance); var importSettingsField = typeof(ImportPropertiesProxyBase).GetField(nameof(ImportSettings), BindingFlags.NonPublic | BindingFlags.Instance);
var importSettingsValues = new ValueContainer(new ScriptMemberInfo(importSettingsField)) { proxy.ImportSettings }; var importSettingsValues = new ValueContainer(new ScriptMemberInfo(importSettingsField)) { proxy.ImportSettings };
importSettingsGroup.Object(importSettingsValues); importSettingsGroup.Object(importSettingsValues);
importSettingsGroup.Space(3);
// Creates the import path UI // Creates the import path UI
var group = layout.Group("Import Path"); var group = layout.Group("Import Path");

View File

@@ -114,7 +114,7 @@ namespace FlaxEditor.Windows.Assets
lodIndex.IntValue.Value = sdf.Texture != null ? sdf.LOD : 6; lodIndex.IntValue.Value = sdf.Texture != null ? sdf.LOD : 6;
_sdfModelLodIndex = lodIndex; _sdfModelLodIndex = lodIndex;
var buttons = group.CustomContainer<UniformGridPanel>(); var buttons = layout.UniformGrid();
var gridControl = buttons.CustomControl; var gridControl = buttons.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = Button.DefaultHeight; gridControl.Height = Button.DefaultHeight;

View File

@@ -56,6 +56,7 @@ namespace FlaxEditor.Windows.Assets
public PrefabTree() public PrefabTree()
: base(true) : base(true)
{ {
DrawRootTreeLine = false;
} }
} }

View File

@@ -51,7 +51,7 @@ namespace FlaxEditor.Windows.Assets
/// <param name="before">The selection before the change.</param> /// <param name="before">The selection before the change.</param>
public void OnSelectionChanged(SceneGraphNode[] before) public void OnSelectionChanged(SceneGraphNode[] before)
{ {
if (LockSelectedObjects) if (LockSelection)
return; return;
Undo.AddAction(new SelectionChangeAction(before, Selection.ToArray(), OnSelectionUndo)); Undo.AddAction(new SelectionChangeAction(before, Selection.ToArray(), OnSelectionUndo));

View File

@@ -78,7 +78,7 @@ namespace FlaxEditor.Windows.Assets
/// <summary> /// <summary>
/// Indication of if the prefab window selection is locked on specific objects. /// Indication of if the prefab window selection is locked on specific objects.
/// </summary> /// </summary>
public bool LockSelectedObjects public bool LockSelection
{ {
get => _lockSelection; get => _lockSelection;
set set

View File

@@ -413,7 +413,7 @@ namespace FlaxEditor.Windows.Assets
var group = layout.Group("Functions"); var group = layout.Group("Functions");
var nodes = window.VisjectSurface.Nodes; var nodes = window.VisjectSurface.Nodes;
var grid = group.CustomContainer<UniformGridPanel>(); var grid = layout.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
gridControl.Height = Button.DefaultHeight; gridControl.Height = Button.DefaultHeight;

View File

@@ -204,6 +204,7 @@ namespace FlaxEditor.Windows
// Content structure tree // Content structure tree
_tree = new Tree(false) _tree = new Tree(false)
{ {
DrawRootTreeLine = false,
Parent = _contentTreePanel, Parent = _contentTreePanel,
}; };
_tree.SelectedChanged += OnTreeSelectionChanged; _tree.SelectedChanged += OnTreeSelectionChanged;

View File

@@ -140,6 +140,7 @@ namespace FlaxEditor.Windows
: base(editor, true, ScrollBars.None) : base(editor, true, ScrollBars.None)
{ {
Title = "Editor"; Title = "Editor";
Icon = editor.Icons.Grid32;
// Create viewport // Create viewport
Viewport = new MainEditorGizmoViewport(editor) Viewport = new MainEditorGizmoViewport(editor)

View File

@@ -2,6 +2,7 @@
using System; using System;
using FlaxEditor.Content; using FlaxEditor.Content;
using FlaxEditor.Options;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using DockWindow = FlaxEditor.GUI.Docking.DockWindow; using DockWindow = FlaxEditor.GUI.Docking.DockWindow;
@@ -49,6 +50,73 @@ namespace FlaxEditor.Windows
} }
}); });
// Set up editor window shortcuts
InputActions.Add(options => options.ContentWindow, () =>
{
if (InputOptions.WindowShortcutsAvaliable)
Editor.Windows.ContentWin.FocusOrShow();
});
InputActions.Add(options => options.SceneWindow, () =>
{
if (InputOptions.WindowShortcutsAvaliable)
Editor.Windows.SceneWin.FocusOrShow();
});
InputActions.Add(options => options.ToolboxWindow, () =>
{
if (InputOptions.WindowShortcutsAvaliable)
Editor.Windows.ToolboxWin.FocusOrShow();
});
InputActions.Add(options => options.PropertiesWindow, () =>
{
if (InputOptions.WindowShortcutsAvaliable)
Editor.Windows.PropertiesWin.FocusOrShow();
});
InputActions.Add(options => options.GameWindow, () =>
{
if (InputOptions.WindowShortcutsAvaliable)
Editor.Windows.GameWin.FocusOrShow();
});
InputActions.Add(options => options.EditorWindow, () =>
{
if (InputOptions.WindowShortcutsAvaliable)
Editor.Windows.EditWin.FocusOrShow();
});
InputActions.Add(options => options.DebugLogWindow, () =>
{
if (InputOptions.WindowShortcutsAvaliable)
Editor.Windows.DebugLogWin.FocusOrShow();
});
InputActions.Add(options => options.OutputLogWindow, () =>
{
if (InputOptions.WindowShortcutsAvaliable)
Editor.Windows.OutputLogWin.FocusOrShow();
});
InputActions.Add(options => options.GraphicsQualityWindow, () =>
{
if (InputOptions.WindowShortcutsAvaliable)
Editor.Windows.GraphicsQualityWin.FocusOrShow();
});
InputActions.Add(options => options.GameCookerWindow, () =>
{
if (InputOptions.WindowShortcutsAvaliable)
Editor.Windows.GameCookerWin.FocusOrShow();
});
InputActions.Add(options => options.ProfilerWindow, () =>
{
if (InputOptions.ProfilerShortcutAvaliable)
Editor.Windows.ProfilerWin.FocusOrShow();
});
InputActions.Add(options => options.ContentFinder, () =>
{
if (InputOptions.WindowShortcutsAvaliable)
Editor.ContentFinding.ShowSearch();
});
InputActions.Add(options => options.VisualScriptDebuggerWindow, () =>
{
if (InputOptions.WindowShortcutsAvaliable)
Editor.Windows.VisualScriptDebuggerWin.FocusOrShow();
});
// Register // Register
Editor.Windows.OnWindowAdd(this); Editor.Windows.OnWindowAdd(this);
} }

View File

@@ -305,6 +305,7 @@ namespace FlaxEditor.Windows
: base(editor, true, ScrollBars.None) : base(editor, true, ScrollBars.None)
{ {
Title = "Game"; Title = "Game";
Icon = editor.Icons.Play64;
AutoFocus = true; AutoFocus = true;
var task = MainRenderTask.Instance; var task = MainRenderTask.Instance;

View File

@@ -482,6 +482,7 @@ namespace FlaxEditor.Windows
: base(editor, true, ScrollBars.None) : base(editor, true, ScrollBars.None)
{ {
Title = "Output Log"; Title = "Output Log";
Icon = editor.Icons.Info64;
ClipChildren = false; ClipChildren = false;
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this); FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
@@ -983,6 +984,10 @@ namespace FlaxEditor.Windows
var cachedOutputTargetViewOffset = _output.TargetViewOffset; var cachedOutputTargetViewOffset = _output.TargetViewOffset;
var isBottomScroll = _vScroll.Value >= _vScroll.Maximum - (_scrollSize * 2) || wasEmpty; var isBottomScroll = _vScroll.Value >= _vScroll.Maximum - (_scrollSize * 2) || wasEmpty;
_output.Text = _textBuffer.ToString(); _output.Text = _textBuffer.ToString();
if (_hScroll.Maximum <= 0.0)
cachedOutputTargetViewOffset.X = 0;
if (_vScroll.Maximum <= 0.0)
cachedOutputTargetViewOffset.Y = 0;
_output.TargetViewOffset = cachedOutputTargetViewOffset; _output.TargetViewOffset = cachedOutputTargetViewOffset;
_textBufferCount = _entries.Count; _textBufferCount = _entries.Count;
if (!_vScroll.IsThumbClicked) if (!_vScroll.IsThumbClicked)

View File

@@ -45,7 +45,7 @@ namespace FlaxEditor.Windows
/// <summary> /// <summary>
/// Indication of if the properties window is locked on specific objects. /// Indication of if the properties window is locked on specific objects.
/// </summary> /// </summary>
public bool LockObjects public bool LockSelection
{ {
get => _lockObjects; get => _lockObjects;
set set
@@ -66,6 +66,7 @@ namespace FlaxEditor.Windows
: base(editor, true, ScrollBars.Vertical) : base(editor, true, ScrollBars.Vertical)
{ {
Title = "Properties"; Title = "Properties";
Icon = editor.Icons.Build64;
AutoFocus = true; AutoFocus = true;
Presenter = new CustomEditorPresenter(editor.Undo, null, this); Presenter = new CustomEditorPresenter(editor.Undo, null, this);
@@ -86,9 +87,9 @@ namespace FlaxEditor.Windows
if (Level.ScenesCount > 1) if (Level.ScenesCount > 1)
return; return;
_actorScrollValues.Clear(); _actorScrollValues.Clear();
if (LockObjects) if (LockSelection)
{ {
LockObjects = false; LockSelection = false;
Presenter.Deselect(); Presenter.Deselect();
} }
} }
@@ -121,7 +122,7 @@ namespace FlaxEditor.Windows
private void OnSelectionChanged() private void OnSelectionChanged()
{ {
if (LockObjects) if (LockSelection)
return; return;
// Update selected objects // Update selected objects

View File

@@ -48,6 +48,7 @@ namespace FlaxEditor.Windows
: base(editor, true, ScrollBars.None) : base(editor, true, ScrollBars.None)
{ {
Title = "Scene"; Title = "Scene";
Icon = editor.Icons.Globe32;
// Scene searching query input box // Scene searching query input box
var headerPanel = new ContainerControl var headerPanel = new ContainerControl
@@ -84,6 +85,7 @@ namespace FlaxEditor.Windows
{ {
Margin = new Margin(0.0f, 0.0f, -16.0f, _sceneTreePanel.ScrollBarsSize), // Hide root node Margin = new Margin(0.0f, 0.0f, -16.0f, _sceneTreePanel.ScrollBarsSize), // Hide root node
IsScrollable = true, IsScrollable = true,
DrawRootTreeLine = false,
}; };
_tree.AddChild(root.TreeNode); _tree.AddChild(root.TreeNode);
_tree.SelectedChanged += Tree_OnSelectedChanged; _tree.SelectedChanged += Tree_OnSelectedChanged;

View File

@@ -455,6 +455,7 @@ namespace FlaxEditor.Windows
: base(editor, true, ScrollBars.None) : base(editor, true, ScrollBars.None)
{ {
Title = "Toolbox"; Title = "Toolbox";
Icon = editor.Icons.Toolbox96;
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this); FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
} }

View File

@@ -15,6 +15,8 @@
#if USE_EDITOR #if USE_EDITOR
#include "Engine/Engine/Globals.h"
ThreadLocal<bool> ContentDeprecatedFlags; ThreadLocal<bool> ContentDeprecatedFlags;
void ContentDeprecated::Mark() void ContentDeprecated::Mark()
@@ -593,7 +595,7 @@ bool Asset::onLoad(LoadAssetTask* task)
#if USE_EDITOR #if USE_EDITOR
// Auto-save deprecated assets to get rid of data in an old format // Auto-save deprecated assets to get rid of data in an old format
if (isDeprecated && isLoaded) if (isDeprecated && isLoaded && !IsVirtual() && !GetPath().StartsWith(StringUtils::GetDirectoryName(Globals::TemporaryFolder)))
{ {
PROFILE_CPU_NAMED("Asset.Save"); PROFILE_CPU_NAMED("Asset.Save");
LOG(Info, "Resaving asset '{}' that uses deprecated data format", ToString()); LOG(Info, "Resaving asset '{}' that uses deprecated data format", ToString());

View File

@@ -326,7 +326,7 @@ bool Model::Init(const Span<int32>& meshesCountPerLod)
lod.Link(this, lodIndex); lod.Link(this, lodIndex);
lod.ScreenSize = 1.0f; lod.ScreenSize = 1.0f;
const int32 meshesCount = meshesCountPerLod[lodIndex]; const int32 meshesCount = meshesCountPerLod[lodIndex];
if (meshesCount <= 0 || meshesCount > MODEL_MAX_MESHES) if (meshesCount < 0 || meshesCount > MODEL_MAX_MESHES)
return true; return true;
lod.Meshes.Resize(meshesCount); lod.Meshes.Resize(meshesCount);
@@ -365,7 +365,7 @@ bool Model::LoadHeader(ReadStream& stream, byte& headerVersion)
// Meshes // Meshes
uint16 meshesCount; uint16 meshesCount;
stream.ReadUint16(&meshesCount); stream.ReadUint16(&meshesCount);
if (meshesCount == 0 || meshesCount > MODEL_MAX_MESHES) if (meshesCount > MODEL_MAX_MESHES)
return true; return true;
ASSERT(lodIndex == 0 || LODs[0].Meshes.Count() >= meshesCount); ASSERT(lodIndex == 0 || LODs[0].Meshes.Count() >= meshesCount);
lod.Meshes.Resize(meshesCount, false); lod.Meshes.Resize(meshesCount, false);

View File

@@ -669,6 +669,8 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
Array<GPUVertexLayout::Elements, FixedAllocation<MODEL_MAX_VB>> vbElements; Array<GPUVertexLayout::Elements, FixedAllocation<MODEL_MAX_VB>> vbElements;
const bool useSeparatePositions = !isSkinned; const bool useSeparatePositions = !isSkinned;
const bool useSeparateColors = !isSkinned; const bool useSeparateColors = !isSkinned;
PixelFormat positionsFormat = modelData.PositionFormat == ModelData::PositionFormats::Float32 ? PixelFormat::R32G32B32_Float : PixelFormat::R16G16B16A16_Float;
PixelFormat texCoordsFormat = modelData.TexCoordFormat == ModelData::TexCoordFormats::Float16 ? PixelFormat::R16G16_Float : PixelFormat::R8G8_UNorm;
PixelFormat blendIndicesFormat = PixelFormat::R8G8B8A8_UInt; PixelFormat blendIndicesFormat = PixelFormat::R8G8B8A8_UInt;
PixelFormat blendWeightsFormat = PixelFormat::R8G8B8A8_UNorm; PixelFormat blendWeightsFormat = PixelFormat::R8G8B8A8_UNorm;
for (const Int4& indices : mesh.BlendIndices) for (const Int4& indices : mesh.BlendIndices)
@@ -681,14 +683,13 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
} }
{ {
byte vbIndex = 0; byte vbIndex = 0;
// TODO: add option to quantize vertex positions (eg. 16-bit)
// TODO: add option to quantize vertex attributes (eg. 8-bit blend weights, 8-bit texcoords) // TODO: add option to quantize vertex attributes (eg. 8-bit blend weights, 8-bit texcoords)
// Position // Position
if (useSeparatePositions) if (useSeparatePositions)
{ {
auto& vb0 = vbElements.AddOne(); auto& vb0 = vbElements.AddOne();
vb0.Add({ VertexElement::Types::Position, vbIndex, 0, 0, PixelFormat::R32G32B32_Float }); vb0.Add({ VertexElement::Types::Position, vbIndex, 0, 0, positionsFormat });
vbIndex++; vbIndex++;
} }
@@ -696,13 +697,13 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
{ {
auto& vb = vbElements.AddOne(); auto& vb = vbElements.AddOne();
if (!useSeparatePositions) if (!useSeparatePositions)
vb.Add({ VertexElement::Types::Position, vbIndex, 0, 0, PixelFormat::R32G32B32_Float }); vb.Add({ VertexElement::Types::Position, vbIndex, 0, 0, positionsFormat });
for (int32 channelIdx = 0; channelIdx < mesh.UVs.Count(); channelIdx++) for (int32 channelIdx = 0; channelIdx < mesh.UVs.Count(); channelIdx++)
{ {
auto& channel = mesh.UVs.Get()[channelIdx]; auto& channel = mesh.UVs.Get()[channelIdx];
if (channel.HasItems()) if (channel.HasItems())
{ {
vb.Add({ (VertexElement::Types)((int32)VertexElement::Types::TexCoord0 + channelIdx), vbIndex, 0, 0, PixelFormat::R16G16_Float }); vb.Add({ (VertexElement::Types)((int32)VertexElement::Types::TexCoord0 + channelIdx), vbIndex, 0, 0, texCoordsFormat });
} }
} }
vb.Add({ VertexElement::Types::Normal, vbIndex, 0, 0, PixelFormat::R10G10B10A2_UNorm }); vb.Add({ VertexElement::Types::Normal, vbIndex, 0, 0, PixelFormat::R10G10B10A2_UNorm });
@@ -737,7 +738,7 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
// Write vertex buffers // Write vertex buffers
for (int32 vbIndex = 0; vbIndex < vbCount; vbIndex++) for (int32 vbIndex = 0; vbIndex < vbCount; vbIndex++)
{ {
if (useSeparatePositions && vbIndex == 0) if (useSeparatePositions && vbIndex == 0 && positionsFormat == PixelFormat::R32G32B32_Float)
{ {
// Fast path for vertex positions of static models using the first buffer // Fast path for vertex positions of static models using the first buffer
stream.WriteBytes(mesh.Positions.Get(), sizeof(Float3) * vertices); stream.WriteBytes(mesh.Positions.Get(), sizeof(Float3) * vertices);
@@ -755,7 +756,15 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
case VertexElement::Types::Position: case VertexElement::Types::Position:
{ {
const Float3 position = mesh.Positions.Get()[vertex]; const Float3 position = mesh.Positions.Get()[vertex];
if (positionsFormat == PixelFormat::R16G16B16A16_Float)
{
const Half4 positionEnc(Float4(position, 0.0f));
stream.Write(positionEnc);
}
else //if (positionsFormat == PixelFormat::R32G32B32_Float)
{
stream.Write(position); stream.Write(position);
}
break; break;
} }
case VertexElement::Types::Color: case VertexElement::Types::Color:
@@ -821,8 +830,16 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
{ {
const int32 channelIdx = (int32)element.Type - (int32)VertexElement::Types::TexCoord0; const int32 channelIdx = (int32)element.Type - (int32)VertexElement::Types::TexCoord0;
const Float2 uv = mesh.UVs.Get()[channelIdx].Get()[vertex]; const Float2 uv = mesh.UVs.Get()[channelIdx].Get()[vertex];
if (texCoordsFormat == PixelFormat::R8G8_UNorm)
{
stream.Write((uint8)Math::Clamp<int32>((int32)(uv.X * 255), 0, 255));
stream.Write((uint8)Math::Clamp<int32>((int32)(uv.Y * 255), 0, 255));
}
else //if (texCoordsFormat == PixelFormat::R16G16_Float)
{
const Half2 uvEnc(uv); const Half2 uvEnc(uv);
stream.Write(uvEnc); stream.Write(uvEnc);
}
break; break;
} }
default: default:

View File

@@ -478,7 +478,7 @@ bool SkinnedModel::Init(const Span<int32>& meshesCountPerLod)
lod._lodIndex = lodIndex; lod._lodIndex = lodIndex;
lod.ScreenSize = 1.0f; lod.ScreenSize = 1.0f;
const int32 meshesCount = meshesCountPerLod[lodIndex]; const int32 meshesCount = meshesCountPerLod[lodIndex];
if (meshesCount <= 0 || meshesCount > MODEL_MAX_MESHES) if (meshesCount < 0 || meshesCount > MODEL_MAX_MESHES)
return true; return true;
lod.Meshes.Resize(meshesCount); lod.Meshes.Resize(meshesCount);

View File

@@ -9,6 +9,10 @@
#include "Engine/Level/Types.h" #include "Engine/Level/Types.h"
#include "Engine/Debug/Exceptions/JsonParseException.h" #include "Engine/Debug/Exceptions/JsonParseException.h"
#include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Profiler/ProfilerCPU.h"
#if USE_EDITOR
#include "Engine/Core/Collections/HashSet.h"
#include "Engine/Core/Collections/Dictionary.h"
#endif
#include <ThirdParty/rapidjson/document.h> #include <ThirdParty/rapidjson/document.h>
bool JsonStorageProxy::IsValidExtension(const StringView& extension) bool JsonStorageProxy::IsValidExtension(const StringView& extension)
@@ -56,27 +60,31 @@ bool JsonStorageProxy::GetAssetInfo(const StringView& path, Guid& resultId, Stri
#if USE_EDITOR #if USE_EDITOR
void ChangeIds(rapidjson_flax::Value& obj, rapidjson_flax::Document& document, const StringAnsi& srcId, const StringAnsi& dstId) void FindObjectIds(const rapidjson_flax::Value& obj, const rapidjson_flax::Document& document, HashSet<Guid>& ids, const char* parentName = nullptr)
{ {
if (obj.IsObject()) if (obj.IsObject())
{ {
for (rapidjson_flax::Value::MemberIterator i = obj.MemberBegin(); i != obj.MemberEnd(); ++i) for (rapidjson_flax::Value::ConstMemberIterator i = obj.MemberBegin(); i != obj.MemberEnd(); ++i)
{ {
ChangeIds(i->value, document, srcId, dstId); FindObjectIds(i->value, document, ids, i->name.GetString());
} }
} }
else if (obj.IsArray()) else if (obj.IsArray())
{ {
for (rapidjson::SizeType i = 0; i < obj.Size(); i++) for (rapidjson::SizeType i = 0; i < obj.Size(); i++)
{ {
ChangeIds(obj[i], document, srcId, dstId); FindObjectIds(obj[i], document, ids, parentName);
} }
} }
else if (obj.IsString()) else if (obj.IsString() && obj.GetStringLength() == 32)
{ {
if (StringUtils::Compare(srcId.Get(), obj.GetString()) == 0) if (parentName && StringUtils::Compare(parentName, "ID") == 0)
{ {
obj.SetString(dstId.Get(), document.GetAllocator()); auto value = JsonTools::GetGuid(obj);
if (value.IsValid())
{
ids.Add(value);
}
} }
} }
} }
@@ -91,9 +99,7 @@ bool JsonStorageProxy::ChangeId(const StringView& path, const Guid& newId)
// Load file // Load file
Array<byte> fileData; Array<byte> fileData;
if (File::ReadAllBytes(path, fileData)) if (File::ReadAllBytes(path, fileData))
{
return false; return false;
}
// Parse data // Parse data
rapidjson_flax::Document document; rapidjson_flax::Document document;
@@ -107,33 +113,35 @@ bool JsonStorageProxy::ChangeId(const StringView& path, const Guid& newId)
return false; return false;
} }
// Try get asset metadata // Get all IDs inside the file
HashSet<Guid> ids;
FindObjectIds(document, document, ids);
// Remap into a unique IDs
Dictionary<Guid, Guid> remap;
remap.EnsureCapacity(ids.Count());
for (const auto& id : ids)
remap.Add(id.Item, Guid::New());
// Remap asset ID using the provided value
auto idNode = document.FindMember("ID"); auto idNode = document.FindMember("ID");
if (idNode == document.MemberEnd()) if (idNode == document.MemberEnd())
{
return true; return true;
} remap[JsonTools::GetGuid(idNode->value)] = newId;
// Change IDs // Change IDs of asset and objects inside asset
auto oldIdStr = idNode->value.GetString(); JsonTools::ChangeIds(document, remap);
auto newIdStr = newId.ToString(Guid::FormatType::N).ToStringAnsi();
ChangeIds(document, document, oldIdStr, newIdStr);
// Save to file // Save to file
rapidjson_flax::StringBuffer buffer; rapidjson_flax::StringBuffer buffer;
PrettyJsonWriter writer(buffer); PrettyJsonWriter writer(buffer);
document.Accept(writer.GetWriter()); document.Accept(writer.GetWriter());
if (File::WriteAllBytes(path, (byte*)buffer.GetString(), (int32)buffer.GetSize())) if (File::WriteAllBytes(path, (byte*)buffer.GetString(), (int32)buffer.GetSize()))
{
return true; return true;
}
return false; return false;
#else #else
LOG(Warning, "Editing cooked content is invalid."); LOG(Warning, "Editing cooked content is invalid.");
return true; return true;
#endif #endif
} }

View File

@@ -673,23 +673,23 @@ namespace FlaxEngine
/// <summary> /// <summary>
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance. /// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
/// </summary> /// </summary>
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param> /// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ref BoundingBox value) public bool Equals(ref BoundingBox other)
{ {
return Minimum == value.Minimum && Maximum == value.Maximum; return Minimum == other.Minimum && Maximum == other.Maximum;
} }
/// <summary> /// <summary>
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance. /// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
/// </summary> /// </summary>
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param> /// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(BoundingBox value) public bool Equals(BoundingBox other)
{ {
return Equals(ref value); return Equals(ref other);
} }
/// <summary> /// <summary>

View File

@@ -487,23 +487,23 @@ namespace FlaxEngine
/// <summary> /// <summary>
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance. /// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
/// </summary> /// </summary>
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param> /// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ref BoundingSphere value) public bool Equals(ref BoundingSphere other)
{ {
return (Center == value.Center) && (Radius == value.Radius); return Center == other.Center && Radius == other.Radius;
} }
/// <summary> /// <summary>
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance. /// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
/// </summary> /// </summary>
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param> /// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(BoundingSphere value) public bool Equals(BoundingSphere other)
{ {
return Equals(ref value); return Equals(ref other);
} }
/// <summary> /// <summary>

View File

@@ -197,12 +197,9 @@ namespace FlaxEngine
} }
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object other) public override bool Equals(object value)
{ {
if (!(other is Color)) return value is Color other && Equals(ref other);
return false;
var color = (Color)other;
return Equals(ref color);
} }
/// <summary> /// <summary>
@@ -213,7 +210,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ref Color other) public bool Equals(ref Color other)
{ {
return Mathf.NearEqual(other.R, R) && Mathf.NearEqual(other.G, G) && Mathf.NearEqual(other.B, B) && Mathf.NearEqual(other.A, A); return R == other.R && G == other.G && B == other.B && A == other.A;
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -661,23 +658,23 @@ namespace FlaxEngine
/// <summary> /// <summary>
/// Compares two colors. /// Compares two colors.
/// </summary> /// </summary>
/// <param name="lhs">The left.</param> /// <param name="left">The left.</param>
/// <param name="rhs">The right.</param> /// <param name="right">The right.</param>
/// <returns>True if colors are equal, otherwise false.</returns> /// <returns>True if colors are equal, otherwise false.</returns>
public static bool operator ==(Color lhs, Color rhs) public static bool operator ==(Color left, Color right)
{ {
return lhs.Equals(ref rhs); return left.Equals(ref right);
} }
/// <summary> /// <summary>
/// Compares two colors. /// Compares two colors.
/// </summary> /// </summary>
/// <param name="lhs">The left.</param> /// <param name="left">The left.</param>
/// <param name="rhs">The right.</param> /// <param name="right">The right.</param>
/// <returns>True if colors are not equal, otherwise false.</returns> /// <returns>True if colors are not equal, otherwise false.</returns>
public static bool operator !=(Color lhs, Color rhs) public static bool operator !=(Color left, Color right)
{ {
return !lhs.Equals(ref rhs); return !left.Equals(ref right);
} }
/// <summary> /// <summary>

View File

@@ -1464,7 +1464,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Double2 left, Double2 right) public static bool operator ==(Double2 left, Double2 right)
{ {
return Mathd.NearEqual(left.X, right.X) && Mathd.NearEqual(left.Y, right.Y); return left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -1476,7 +1476,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Double2 left, Double2 right) public static bool operator !=(Double2 left, Double2 right)
{ {
return !Mathd.NearEqual(left.X, right.X) || !Mathd.NearEqual(left.Y, right.Y); return !left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -1582,7 +1582,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ref Double2 other) public bool Equals(ref Double2 other)
{ {
return Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y); return X == other.X && Y == other.Y;
} }
/// <summary> /// <summary>
@@ -1590,7 +1590,7 @@ namespace FlaxEngine
/// </summary> /// </summary>
public static bool Equals(ref Double2 a, ref Double2 b) public static bool Equals(ref Double2 a, ref Double2 b)
{ {
return Mathd.NearEqual(a.X, b.X) && Mathd.NearEqual(a.Y, b.Y); return a.Equals(ref b);
} }
/// <summary> /// <summary>
@@ -1601,7 +1601,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Double2 other) public bool Equals(Double2 other)
{ {
return Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y); return Equals(ref other);
} }
/// <summary> /// <summary>
@@ -1611,7 +1611,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public override bool Equals(object value) public override bool Equals(object value)
{ {
return value is Double2 other && Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y); return value is Double2 other && Equals(ref other);
} }
} }
} }

View File

@@ -1759,7 +1759,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Double3 left, Double3 right) public static bool operator ==(Double3 left, Double3 right)
{ {
return Mathd.NearEqual(left.X, right.X) && Mathd.NearEqual(left.Y, right.Y) && Mathd.NearEqual(left.Z, right.Z); return left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -1771,7 +1771,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Double3 left, Double3 right) public static bool operator !=(Double3 left, Double3 right)
{ {
return !Mathd.NearEqual(left.X, right.X) || !Mathd.NearEqual(left.Y, right.Y) || !Mathd.NearEqual(left.Z, right.Z); return !left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -1880,7 +1880,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ref Double3 other) public bool Equals(ref Double3 other)
{ {
return Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y) && Mathd.NearEqual(other.Z, Z); return X == other.X && Y == other.Y && Z == other.Z;
} }
/// <summary> /// <summary>
@@ -1891,7 +1891,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Double3 other) public bool Equals(Double3 other)
{ {
return Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y) && Mathd.NearEqual(other.Z, Z); return Equals(ref other);
} }
/// <summary> /// <summary>
@@ -1901,7 +1901,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public override bool Equals(object value) public override bool Equals(object value)
{ {
return value is Double3 other && Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y) && Mathd.NearEqual(other.Z, Z); return value is Double3 other && Equals(ref other);
} }
} }
} }

View File

@@ -1258,7 +1258,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Double4 left, Double4 right) public static bool operator ==(Double4 left, Double4 right)
{ {
return Mathd.NearEqual(left.X, right.X) && Mathd.NearEqual(left.Y, right.Y) && Mathd.NearEqual(left.Z, right.Z) && Mathd.NearEqual(left.W, right.W); return left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -1379,7 +1379,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="Double4" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Double4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public bool Equals(ref Double4 other) public bool Equals(ref Double4 other)
{ {
return Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y) && Mathd.NearEqual(other.Z, Z) && Mathd.NearEqual(other.W, W); return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
} }
/// <summary> /// <summary>
@@ -1390,7 +1390,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Double4 other) public bool Equals(Double4 other)
{ {
return Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y) && Mathd.NearEqual(other.Z, Z) && Mathd.NearEqual(other.W, W); return Equals(ref other);
} }
/// <summary> /// <summary>
@@ -1400,7 +1400,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public override bool Equals(object value) public override bool Equals(object value)
{ {
return value is Double4 other && Mathd.NearEqual(other.X, X) && Mathd.NearEqual(other.Y, Y) && Mathd.NearEqual(other.Z, Z) && Mathd.NearEqual(other.W, W); return value is Double4 other && Equals(ref other);
} }
} }
} }

View File

@@ -1540,7 +1540,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Float2 left, Float2 right) public static bool operator ==(Float2 left, Float2 right)
{ {
return Mathf.NearEqual(left.X, right.X) && Mathf.NearEqual(left.Y, right.Y); return left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -1552,7 +1552,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Float2 left, Float2 right) public static bool operator !=(Float2 left, Float2 right)
{ {
return !Mathf.NearEqual(left.X, right.X) || !Mathf.NearEqual(left.Y, right.Y); return !left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -1658,7 +1658,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ref Float2 other) public bool Equals(ref Float2 other)
{ {
return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y); return X == other.X && Y == other.Y;
} }
/// <summary> /// <summary>
@@ -1666,7 +1666,7 @@ namespace FlaxEngine
/// </summary> /// </summary>
public static bool Equals(ref Float2 a, ref Float2 b) public static bool Equals(ref Float2 a, ref Float2 b)
{ {
return Mathf.NearEqual(a.X, b.X) && Mathf.NearEqual(a.Y, b.Y); return a.Equals(ref b);
} }
/// <summary> /// <summary>
@@ -1677,7 +1677,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Float2 other) public bool Equals(Float2 other)
{ {
return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y); return Equals(ref other);
} }
/// <summary> /// <summary>
@@ -1687,7 +1687,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public override bool Equals(object value) public override bool Equals(object value)
{ {
return value is Float2 other && Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y); return value is Float2 other && Equals(ref other);
} }
} }
} }

View File

@@ -1791,7 +1791,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Float3 left, Float3 right) public static bool operator ==(Float3 left, Float3 right)
{ {
return Mathf.NearEqual(left.X, right.X) && Mathf.NearEqual(left.Y, right.Y) && Mathf.NearEqual(left.Z, right.Z); return left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -1803,7 +1803,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Float3 left, Float3 right) public static bool operator !=(Float3 left, Float3 right)
{ {
return !Mathf.NearEqual(left.X, right.X) || !Mathf.NearEqual(left.Y, right.Y) || !Mathf.NearEqual(left.Z, right.Z); return !left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -1912,7 +1912,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ref Float3 other) public bool Equals(ref Float3 other)
{ {
return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y) && Mathf.NearEqual(other.Z, Z); return X == other.X && Y == other.Y && Z == other.Z;
} }
/// <summary> /// <summary>
@@ -1923,7 +1923,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Float3 other) public bool Equals(Float3 other)
{ {
return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y) && Mathf.NearEqual(other.Z, Z); return Equals(ref other);
} }
/// <summary> /// <summary>
@@ -1933,7 +1933,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public override bool Equals(object value) public override bool Equals(object value)
{ {
return value is Float3 other && Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y) && Mathf.NearEqual(other.Z, Z); return value is Float3 other && Equals(ref other);
} }
} }
} }

View File

@@ -1288,7 +1288,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Float4 left, Float4 right) public static bool operator ==(Float4 left, Float4 right)
{ {
return Mathf.NearEqual(left.X, right.X) && Mathf.NearEqual(left.Y, right.Y) && Mathf.NearEqual(left.Z, right.Z) && Mathf.NearEqual(left.W, right.W); return left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -1419,7 +1419,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="Float4" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Float4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public bool Equals(ref Float4 other) public bool Equals(ref Float4 other)
{ {
return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y) && Mathf.NearEqual(other.Z, Z) && Mathf.NearEqual(other.W, W); return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
} }
/// <summary> /// <summary>
@@ -1430,7 +1430,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Float4 other) public bool Equals(Float4 other)
{ {
return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y) && Mathf.NearEqual(other.Z, Z) && Mathf.NearEqual(other.W, W); return Equals(ref other);
} }
/// <summary> /// <summary>
@@ -1440,7 +1440,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public override bool Equals(object value) public override bool Equals(object value)
{ {
return value is Float4 other && Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y) && Mathf.NearEqual(other.Z, Z) && Mathf.NearEqual(other.W, W); return value is Float4 other && Equals(ref other);
} }
} }
} }

View File

@@ -163,7 +163,7 @@ bool Matrix::operator==(const Matrix& other) const
{ {
for (int32 i = 0; i < 16; i++) for (int32 i = 0; i < 16; i++)
{ {
if (Math::NotNearEqual(other.Raw[i], Raw[i])) if (other.Raw[i] != Raw[i])
return false; return false;
} }
return true; return true;

View File

@@ -3236,22 +3236,22 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="Matrix" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Matrix" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public bool Equals(ref Matrix other) public bool Equals(ref Matrix other)
{ {
return Mathf.NearEqual(other.M11, M11) && return other.M11 == M11 &&
Mathf.NearEqual(other.M12, M12) && other.M12 == M12 &&
Mathf.NearEqual(other.M13, M13) && other.M13 == M13 &&
Mathf.NearEqual(other.M14, M14) && other.M14 == M14 &&
Mathf.NearEqual(other.M21, M21) && other.M21 == M21 &&
Mathf.NearEqual(other.M22, M22) && other.M22 == M22 &&
Mathf.NearEqual(other.M23, M23) && other.M23 == M23 &&
Mathf.NearEqual(other.M24, M24) && other.M24 == M24 &&
Mathf.NearEqual(other.M31, M31) && other.M31 == M31 &&
Mathf.NearEqual(other.M32, M32) && other.M32 == M32 &&
Mathf.NearEqual(other.M33, M33) && other.M33 == M33 &&
Mathf.NearEqual(other.M34, M34) && other.M34 == M34 &&
Mathf.NearEqual(other.M41, M41) && other.M41 == M41 &&
Mathf.NearEqual(other.M42, M42) && other.M42 == M42 &&
Mathf.NearEqual(other.M43, M43) && other.M43 == M43 &&
Mathf.NearEqual(other.M44, M44); other.M44 == M44;
} }
/// <summary> /// <summary>
@@ -3272,10 +3272,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public override bool Equals(object value) public override bool Equals(object value)
{ {
if (!(value is Matrix)) return value is Matrix other && Equals(ref other);
return false;
var v = (Matrix)value;
return Equals(ref v);
} }
} }
} }

View File

@@ -483,7 +483,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="Matrix2x2"/> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Matrix2x2"/> is equal to this instance; otherwise, <c>false</c>.</returns>
public bool Equals(ref Matrix2x2 other) public bool Equals(ref Matrix2x2 other)
{ {
return Mathf.NearEqual(other.M11, M11) && Mathf.NearEqual(other.M12, M12) && Mathf.NearEqual(other.M21, M21) && Mathf.NearEqual(other.M22, M22); return M11 == other.M11 && M12 == other.M12 && M21 == other.M21 && M22 == other.M22;
} }
/// <summary> /// <summary>
@@ -502,7 +502,7 @@ namespace FlaxEngine
/// </summary> /// </summary>
public static bool Equals(ref Matrix2x2 a, ref Matrix2x2 b) public static bool Equals(ref Matrix2x2 a, ref Matrix2x2 b)
{ {
return Mathf.NearEqual(a.M11, b.M11) && Mathf.NearEqual(a.M12, b.M12) && Mathf.NearEqual(a.M21, b.M21) && Mathf.NearEqual(a.M22, b.M22); return a.Equals(ref b);
} }
/// <summary> /// <summary>

View File

@@ -242,14 +242,13 @@ void Matrix3x3::Decompose(Float3& scale, Quaternion& rotation) const
bool Matrix3x3::operator==(const Matrix3x3& other) const bool Matrix3x3::operator==(const Matrix3x3& other) const
{ {
return return M11 == other.M11 &&
Math::NearEqual(M11, other.M11) && M12 == other.M12 &&
Math::NearEqual(M12, other.M12) && M13 == other.M13 &&
Math::NearEqual(M13, other.M13) && M21 == other.M21 &&
Math::NearEqual(M21, other.M21) && M22 == other.M22 &&
Math::NearEqual(M22, other.M22) && M23 == other.M23 &&
Math::NearEqual(M23, other.M23) && M31 == other.M31 &&
Math::NearEqual(M31, other.M31) && M32 == other.M32 &&
Math::NearEqual(M32, other.M32) && M33 == other.M33;
Math::NearEqual(M33, other.M33);
} }

View File

@@ -2125,15 +2125,15 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="Matrix3x3"/> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Matrix3x3"/> is equal to this instance; otherwise, <c>false</c>.</returns>
public bool Equals(ref Matrix3x3 other) public bool Equals(ref Matrix3x3 other)
{ {
return (Mathf.NearEqual(other.M11, M11) && return M11 == other.M11 &&
Mathf.NearEqual(other.M12, M12) && M12 == other.M12 &&
Mathf.NearEqual(other.M13, M13) && M13 == other.M13 &&
Mathf.NearEqual(other.M21, M21) && M21 == other.M21 &&
Mathf.NearEqual(other.M22, M22) && M22 == other.M22 &&
Mathf.NearEqual(other.M23, M23) && M23 == other.M23 &&
Mathf.NearEqual(other.M31, M31) && M31 == other.M31 &&
Mathf.NearEqual(other.M32, M32) && M32 == other.M32 &&
Mathf.NearEqual(other.M33, M33)); M33 == other.M33;
} }
/// <summary> /// <summary>
@@ -2152,17 +2152,7 @@ namespace FlaxEngine
/// </summary> /// </summary>
public static bool Equals(ref Matrix3x3 a, ref Matrix3x3 b) public static bool Equals(ref Matrix3x3 a, ref Matrix3x3 b)
{ {
return return a.Equals(ref b);
Mathf.NearEqual(a.M11, b.M11) &&
Mathf.NearEqual(a.M12, b.M12) &&
Mathf.NearEqual(a.M13, b.M13) &&
Mathf.NearEqual(a.M21, b.M21) &&
Mathf.NearEqual(a.M22, b.M22) &&
Mathf.NearEqual(a.M23, b.M23) &&
Mathf.NearEqual(a.M31, b.M31) &&
Mathf.NearEqual(a.M32, b.M32) &&
Mathf.NearEqual(a.M33, b.M33)
;
} }
/// <summary> /// <summary>

View File

@@ -397,7 +397,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ref OrientedBoundingBox value) public bool Equals(ref OrientedBoundingBox value)
{ {
return (Extents == value.Extents) && (Transformation == value.Transformation); return Extents == value.Extents && Transformation == value.Transformation;
} }
/// <summary> /// <summary>

View File

@@ -582,23 +582,23 @@ namespace FlaxEngine
/// <summary> /// <summary>
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance. /// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
/// </summary> /// </summary>
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param> /// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ref Plane value) public bool Equals(ref Plane other)
{ {
return Normal == value.Normal && D == value.D; return Normal == other.Normal && D == other.D;
} }
/// <summary> /// <summary>
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance. /// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
/// </summary> /// </summary>
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param> /// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Plane value) public bool Equals(Plane other)
{ {
return Equals(ref value); return Equals(ref other);
} }
/// <summary> /// <summary>
@@ -608,10 +608,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public override bool Equals(object value) public override bool Equals(object value)
{ {
if (!(value is Plane)) return value is Plane other && Equals(ref other);
return false;
var strongValue = (Plane)value;
return Equals(ref strongValue);
} }
} }
} }

View File

@@ -1179,7 +1179,7 @@ namespace FlaxEngine
} }
/// <summary> /// <summary>
/// Gets the quaternion that will rotate vector from into vector to, around their plan perpendicular axis.The input vectors don't need to be normalized. /// Gets the quaternion that will rotate the from into vector to, around their plan perpendicular axis. The input vectors don't need to be normalized.
/// </summary> /// </summary>
/// <param name="from">The source vector.</param> /// <param name="from">The source vector.</param>
/// <param name="to">The destination vector.</param> /// <param name="to">The destination vector.</param>
@@ -1602,7 +1602,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Quaternion left, Quaternion right) public static bool operator ==(Quaternion left, Quaternion right)
{ {
return Dot(ref left, ref right) > Tolerance; return left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -1614,7 +1614,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Quaternion left, Quaternion right) public static bool operator !=(Quaternion left, Quaternion right)
{ {
return Dot(ref left, ref right) <= Tolerance; return !left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -1714,8 +1714,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ref Quaternion other) public bool Equals(ref Quaternion other)
{ {
//return Dot(ref this, ref other) > Tolerance; return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y) && Mathf.NearEqual(other.Z, Z) && Mathf.NearEqual(other.W, W);
} }
/// <summary> /// <summary>
@@ -1736,10 +1735,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public override bool Equals(object value) public override bool Equals(object value)
{ {
if (!(value is Quaternion)) return value is Quaternion other && Equals(ref other);
return false;
var strongValue = (Quaternion)value;
return Equals(ref strongValue);
} }
} }
} }

View File

@@ -348,7 +348,7 @@ public:
/// <returns><c>true</c> if the specified <see cref="Quaternion" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Quaternion" /> is equal to this instance; otherwise, <c>false</c>.</returns>
FORCE_INLINE bool operator==(const Quaternion& other) const FORCE_INLINE bool operator==(const Quaternion& other) const
{ {
return Dot(*this, other) > Tolerance; return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
} }
/// <summary> /// <summary>
@@ -358,7 +358,7 @@ public:
/// <returns><c>true</c> if the specified <see cref="Quaternion" /> isn't equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Quaternion" /> isn't equal to this instance; otherwise, <c>false</c>.</returns>
FORCE_INLINE bool operator!=(const Quaternion& other) const FORCE_INLINE bool operator!=(const Quaternion& other) const
{ {
return Dot(*this, other) < Tolerance; return X != other.X || Y != other.Y || Z != other.Z || W != other.W;
} }
public: public:

View File

@@ -428,23 +428,23 @@ namespace FlaxEngine
/// <summary> /// <summary>
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance. /// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
/// </summary> /// </summary>
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param> /// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ref Ray value) public bool Equals(ref Ray other)
{ {
return (Position == value.Position) && (Direction == value.Direction); return Position == other.Position && Direction == other.Direction;
} }
/// <summary> /// <summary>
/// Determines whether the specified <see cref="Vector4" /> is equal to this instance. /// Determines whether the specified <see cref="Vector4" /> is equal to this instance.
/// </summary> /// </summary>
/// <param name="value">The <see cref="Vector4" /> to compare with this instance.</param> /// <param name="other">The <see cref="Vector4" /> to compare with this instance.</param>
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Ray value) public bool Equals(Ray other)
{ {
return Equals(ref value); return Equals(ref other);
} }
/// <summary> /// <summary>

View File

@@ -499,21 +499,19 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ref Rectangle other) public bool Equals(ref Rectangle other)
{ {
return Location.Equals(ref other.Location) && Size.Equals(ref other.Size); return Location == other.Location && Size == other.Size;
} }
/// <inheritdoc /> /// <inheritdoc />
public bool Equals(Rectangle other) public bool Equals(Rectangle other)
{ {
return Location.Equals(ref other.Location) && Size.Equals(ref other.Size); return Equals(ref other);
} }
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
if (ReferenceEquals(null, obj)) return obj is Rectangle other && Equals(ref other);
return false;
return obj is Rectangle && Equals((Rectangle)obj);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -1654,7 +1654,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vector2 left, Vector2 right) public static bool operator ==(Vector2 left, Vector2 right)
{ {
return Mathr.NearEqual(left.X, right.X) && Mathr.NearEqual(left.Y, right.Y); return left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -1666,7 +1666,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Vector2 left, Vector2 right) public static bool operator !=(Vector2 left, Vector2 right)
{ {
return !Mathr.NearEqual(left.X, right.X) || !Mathr.NearEqual(left.Y, right.Y); return !left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -1782,7 +1782,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ref Vector2 other) public bool Equals(ref Vector2 other)
{ {
return Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y); return X == other.X && Y == other.Y;
} }
/// <summary> /// <summary>
@@ -1790,7 +1790,7 @@ namespace FlaxEngine
/// </summary> /// </summary>
public static bool Equals(ref Vector2 a, ref Vector2 b) public static bool Equals(ref Vector2 a, ref Vector2 b)
{ {
return Mathr.NearEqual(a.X, b.X) && Mathr.NearEqual(a.Y, b.Y); return a.Equals(ref b);
} }
/// <summary> /// <summary>
@@ -1801,7 +1801,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Vector2 other) public bool Equals(Vector2 other)
{ {
return Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y); return Equals(ref other);
} }
/// <summary> /// <summary>
@@ -1811,7 +1811,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public override bool Equals(object value) public override bool Equals(object value)
{ {
return value is Vector2 other && Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y); return value is Vector2 other && Equals(ref other);
} }
} }
} }

View File

@@ -2010,7 +2010,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vector3 left, Vector3 right) public static bool operator ==(Vector3 left, Vector3 right)
{ {
return Mathr.NearEqual(left.X, right.X) && Mathr.NearEqual(left.Y, right.Y) && Mathr.NearEqual(left.Z, right.Z); return left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -2022,7 +2022,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Vector3 left, Vector3 right) public static bool operator !=(Vector3 left, Vector3 right)
{ {
return !Mathr.NearEqual(left.X, right.X) || !Mathr.NearEqual(left.Y, right.Y) || !Mathr.NearEqual(left.Z, right.Z); return !left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -2141,7 +2141,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ref Vector3 other) public bool Equals(ref Vector3 other)
{ {
return Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y) && Mathr.NearEqual(other.Z, Z); return X == other.X && Y == other.Y && Z == other.Z;
} }
/// <summary> /// <summary>
@@ -2152,7 +2152,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Vector3 other) public bool Equals(Vector3 other)
{ {
return Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y) && Mathr.NearEqual(other.Z, Z); return Equals(ref other);
} }
/// <summary> /// <summary>
@@ -2162,7 +2162,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public override bool Equals(object value) public override bool Equals(object value)
{ {
return value is Vector3 other && Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y) && Mathr.NearEqual(other.Z, Z); return value is Vector3 other && Equals(ref other);
} }
} }
} }

View File

@@ -1362,7 +1362,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vector4 left, Vector4 right) public static bool operator ==(Vector4 left, Vector4 right)
{ {
return Mathr.NearEqual(left.X, right.X) && Mathr.NearEqual(left.Y, right.Y) && Mathr.NearEqual(left.Z, right.Z) && Mathr.NearEqual(left.W, right.W); return left.Equals(ref right);
} }
/// <summary> /// <summary>
@@ -1493,7 +1493,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public bool Equals(ref Vector4 other) public bool Equals(ref Vector4 other)
{ {
return Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y) && Mathr.NearEqual(other.Z, Z) && Mathr.NearEqual(other.W, W); return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
} }
/// <summary> /// <summary>
@@ -1504,7 +1504,7 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Vector4 other) public bool Equals(Vector4 other)
{ {
return Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y) && Mathr.NearEqual(other.Z, Z) && Mathr.NearEqual(other.W, W); return Equals(ref other);
} }
/// <summary> /// <summary>
@@ -1514,7 +1514,7 @@ namespace FlaxEngine
/// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
public override bool Equals(object value) public override bool Equals(object value)
{ {
return value is Vector4 other && Mathr.NearEqual(other.X, X) && Mathr.NearEqual(other.Y, Y) && Mathr.NearEqual(other.Z, Z) && Mathr.NearEqual(other.W, W); return value is Vector4 other && Equals(ref other);
} }
} }
} }

View File

@@ -0,0 +1,36 @@
// Copyright (c) Wojciech Figat. All rights reserved.
#pragma once
#include "Core.h"
template<typename FuncType>
struct ScopeExit
{
explicit ScopeExit(FuncType&& func)
: _func((FuncType&&)func)
{
}
~ScopeExit()
{
_func();
}
private:
FuncType _func;
};
namespace THelpers
{
struct ScopeExitInternal
{
template<typename FuncType>
ScopeExit<FuncType> operator*(FuncType&& func)
{
return ScopeExit<FuncType>((FuncType&&)func);
}
};
}
#define SCOPE_EXIT const auto CONCAT_MACROS(__scopeExit, __LINE__) = THelpers::ScopeExitInternal() * [&]()

View File

@@ -1162,9 +1162,9 @@ bool Variant::operator==(const Variant& other) const
case VariantType::Enum: case VariantType::Enum:
return AsEnum == other.AsEnum; return AsEnum == other.AsEnum;
case VariantType::Float: case VariantType::Float:
return Math::NearEqual(AsFloat, other.AsFloat); return AsFloat == other.AsFloat;
case VariantType::Double: case VariantType::Double:
return Math::Abs(AsDouble - other.AsDouble) < ZeroTolerance; return AsDouble == other.AsDouble;
case VariantType::Pointer: case VariantType::Pointer:
return AsPointer == other.AsPointer; return AsPointer == other.AsPointer;
case VariantType::String: case VariantType::String:

View File

@@ -99,6 +99,7 @@ struct DebugGeometryBuffer
{ {
GPUBuffer* Buffer; GPUBuffer* Buffer;
float TimeLeft; float TimeLeft;
bool Lines;
Matrix Transform; Matrix Transform;
}; };
@@ -234,6 +235,14 @@ void TeleportList(const Float3& delta, Array<DebugText3D>& list)
} }
} }
void TeleportList(const Float3& delta, Array<DebugGeometryBuffer>& list)
{
for (auto& v : list)
{
v.Transform.SetTranslation(v.Transform.GetTranslation() + delta);
}
}
struct DebugDrawData struct DebugDrawData
{ {
Array<DebugGeometryBuffer> GeometryBuffers; Array<DebugGeometryBuffer> GeometryBuffers;
@@ -302,6 +311,7 @@ struct DebugDrawData
void Teleport(const Float3& delta) void Teleport(const Float3& delta)
{ {
TeleportList(delta, GeometryBuffers);
TeleportList(delta, DefaultLines); TeleportList(delta, DefaultLines);
TeleportList(delta, OneFrameLines); TeleportList(delta, OneFrameLines);
TeleportList(delta, DefaultTriangles); TeleportList(delta, DefaultTriangles);
@@ -812,6 +822,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
defaultWireTriangles = WriteLists(vertexCounter, Context->DebugDrawDefault.DefaultWireTriangles, Context->DebugDrawDefault.OneFrameWireTriangles); defaultWireTriangles = WriteLists(vertexCounter, Context->DebugDrawDefault.DefaultWireTriangles, Context->DebugDrawDefault.OneFrameWireTriangles);
{ {
PROFILE_CPU_NAMED("Flush"); PROFILE_CPU_NAMED("Flush");
ZoneValue(DebugDrawVB->Data.Count() / 1024); // Size in kB
DebugDrawVB->Flush(context); DebugDrawVB->Flush(context);
} }
} }
@@ -871,8 +882,8 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
Matrix mvp; Matrix mvp;
Matrix::Multiply(geometry.Transform, vp, mvp); Matrix::Multiply(geometry.Transform, vp, mvp);
Matrix::Transpose(mvp, tmp.ViewProjection); Matrix::Transpose(mvp, tmp.ViewProjection);
auto state = data.EnableDepthTest ? (geometry.Lines ? &DebugDrawPsLinesDepthTest : &DebugDrawPsTrianglesDepthTest) : (geometry.Lines ? &DebugDrawPsLinesDefault : &DebugDrawPsTrianglesDefault);
context->UpdateCB(cb, &tmp); context->UpdateCB(cb, &tmp);
auto state = data.EnableDepthTest ? &DebugDrawPsLinesDepthTest : &DebugDrawPsLinesDefault;
context->SetState(state->Get(enableDepthWrite, true)); context->SetState(state->Get(enableDepthWrite, true));
context->BindVB(ToSpan(&geometry.Buffer, 1)); context->BindVB(ToSpan(&geometry.Buffer, 1));
context->Draw(0, geometry.Buffer->GetElementsCount()); context->Draw(0, geometry.Buffer->GetElementsCount());
@@ -920,8 +931,9 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
Matrix mvp; Matrix mvp;
Matrix::Multiply(geometry.Transform, vp, mvp); Matrix::Multiply(geometry.Transform, vp, mvp);
Matrix::Transpose(mvp, tmp.ViewProjection); Matrix::Transpose(mvp, tmp.ViewProjection);
auto state = geometry.Lines ? &DebugDrawPsLinesDefault : &DebugDrawPsTrianglesDefault;
context->UpdateCB(cb, &tmp); context->UpdateCB(cb, &tmp);
context->SetState(DebugDrawPsLinesDefault.Get(false, false)); context->SetState(state->Get(false, false));
context->BindVB(ToSpan(&geometry.Buffer, 1)); context->BindVB(ToSpan(&geometry.Buffer, 1));
context->Draw(0, geometry.Buffer->GetElementsCount()); context->Draw(0, geometry.Buffer->GetElementsCount());
} }
@@ -1166,6 +1178,7 @@ void DebugDraw::DrawLines(GPUBuffer* lines, const Matrix& transform, float durat
auto& geometry = debugDrawData.GeometryBuffers.AddOne(); auto& geometry = debugDrawData.GeometryBuffers.AddOne();
geometry.Buffer = lines; geometry.Buffer = lines;
geometry.TimeLeft = duration; geometry.TimeLeft = duration;
geometry.Lines = true;
geometry.Transform = transform * Matrix::Translation(-Context->Origin); geometry.Transform = transform * Matrix::Translation(-Context->Origin);
} }
@@ -1522,6 +1535,23 @@ void DebugDraw::DrawTriangles(const Span<Float3>& vertices, const Matrix& transf
} }
} }
void DebugDraw::DrawTriangles(GPUBuffer* triangles, const Matrix& transform, float duration, bool depthTest)
{
if (triangles == nullptr || triangles->GetSize() == 0)
return;
if (triangles->GetSize() % (sizeof(Vertex) * 3) != 0)
{
DebugLog::ThrowException("Cannot draw debug lines with incorrect amount of items in array");
return;
}
auto& debugDrawData = depthTest ? Context->DebugDrawDepthTest : Context->DebugDrawDefault;
auto& geometry = debugDrawData.GeometryBuffers.AddOne();
geometry.Buffer = triangles;
geometry.TimeLeft = duration;
geometry.Lines = false;
geometry.Transform = transform * Matrix::Translation(-Context->Origin);
}
void DebugDraw::DrawTriangles(const Array<Float3>& vertices, const Color& color, float duration, bool depthTest) void DebugDraw::DrawTriangles(const Array<Float3>& vertices, const Color& color, float duration, bool depthTest)
{ {
DrawTriangles(Span<Float3>(vertices.Get(), vertices.Count()), color, duration, depthTest); DrawTriangles(Span<Float3>(vertices.Get(), vertices.Count()), color, duration, depthTest);

Some files were not shown because too many files have changed in this diff Show More