Merge remote-tracking branch 'origin/master' into sdl_platform

This commit is contained in:
2025-06-02 18:15:16 +03:00
124 changed files with 1244 additions and 436 deletions

View File

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

View File

@@ -6,7 +6,7 @@
Flax Engine is a high quality modern 3D game engine written in C++ and C#.
From stunning graphics to powerful scripts, it's designed for fast workflow with many ready-to-use features waiting for you right now. To learn more see the website ([www.flaxengine.com](https://flaxengine.com)).
This repository contains full source code of the Flax Engine (excluding NDA-protected platforms support). Anyone is welcome to contribute or use the modified source in Flax-based games.
This repository contains full source code of the Flax Engine (excluding NDA-protected platforms support). Documentation source is also available in a separate repository. Anyone is welcome to contribute or use the modified source in Flax-based games.
# Development
@@ -46,21 +46,26 @@ Follow the instructions below to compile and run the engine from source.
* 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))
* 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`
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
* 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
* Ubuntu: `sudo apt-get install git git-lfs`
* Arch: `sudo pacman -S git git-lfs`
* `git-lfs install`
* Install the required packages:
* 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`
* Install Clang compiler (version 6 or later):
* Ubuntu: `sudo apt-get install clang lldb lld`
* Fedora: `sudo dnf install clang llvm lldb lld`
* Arch: `sudo pacman -S clang lldb lld`
* Clone the repository (with LFS)
* git-lfs clone https://github.com/FlaxEngine/FlaxEngine.git
* Run `./GenerateProjectFiles.sh`
* Open workspace with Visual Code
* Build and run (configuration and task named `Flax|Editor.Linux.Development|x64`)

View File

@@ -13,6 +13,11 @@ namespace FlaxEditor.Content.Create
/// <inheritdoc />
public string ResultUrl { get; }
/// <summary>
/// Gets a value indicating wether a file can be created based on the current settings.
/// </summary>
public abstract bool CanBeCreated { get; }
/// <summary>
/// Gets a value indicating whether this entry has settings to modify.
/// </summary>

View File

@@ -60,7 +60,8 @@ namespace FlaxEditor.Content.Create
Text = "Create",
AnchorPreset = AnchorPresets.BottomRight,
Offsets = new Margin(-ButtonsWidth - ButtonsMargin, ButtonsWidth, -ButtonsHeight - ButtonsMargin, ButtonsHeight),
Parent = this
Parent = this,
Enabled = entry.CanBeCreated,
};
createButton.Clicked += OnSubmit;
var cancelButton = new Button
@@ -68,7 +69,7 @@ namespace FlaxEditor.Content.Create
Text = "Cancel",
AnchorPreset = AnchorPresets.BottomRight,
Offsets = new Margin(-ButtonsWidth - ButtonsMargin - ButtonsWidth - ButtonsMargin, ButtonsWidth, -ButtonsHeight - ButtonsMargin, ButtonsHeight),
Parent = this
Parent = this,
};
cancelButton.Clicked += OnCancel;
@@ -77,7 +78,7 @@ namespace FlaxEditor.Content.Create
{
AnchorPreset = AnchorPresets.HorizontalStretchTop,
Offsets = new Margin(2, 2, infoLabel.Bottom + 2, EditorHeight),
Parent = this
Parent = this,
};
// Settings editor
@@ -87,6 +88,7 @@ namespace FlaxEditor.Content.Create
_dialogSize = new Float2(TotalWidth, panel.Bottom);
_settingsEditor.Select(_entry.Settings);
_settingsEditor.Modified += () => createButton.Enabled = _entry.CanBeCreated;
}
/// <inheritdoc />

View File

@@ -12,6 +12,9 @@ namespace FlaxEditor.Content.Create
/// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" />
public class ParticleEmitterCreateEntry : CreateFileEntry
{
/// <inheritdoc/>
public override bool CanBeCreated => true;
/// <summary>
/// Types of the emitter templates that can be created.
/// </summary>

View File

@@ -14,6 +14,9 @@ namespace FlaxEditor.Content.Create
/// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" />
public class PrefabCreateEntry : CreateFileEntry
{
/// <inheritdoc />
public override bool CanBeCreated => _options.RootActorType != null;
/// <summary>
/// The create options.
/// </summary>
@@ -73,6 +76,9 @@ namespace FlaxEditor.Content.Create
/// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" />
public class WidgetCreateEntry : CreateFileEntry
{
/// <inheritdoc/>
public override bool CanBeCreated => _options.RootControlType != null;
/// <summary>
/// The create options.
/// </summary>

View File

@@ -17,6 +17,8 @@ namespace FlaxEditor.Content.Create
/// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" />
internal class SettingsCreateEntry : CreateFileEntry
{
public override bool CanBeCreated => _options.Type != null;
internal class Options
{
[Tooltip("The settings type.")]

View File

@@ -11,6 +11,9 @@ namespace FlaxEditor.Content.Create
/// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" />
public class VisualScriptCreateEntry : CreateFileEntry
{
/// <inheritdoc/>
public override bool CanBeCreated => _options.BaseClass != null;
/// <summary>
/// The create options.
/// </summary>

View File

@@ -65,6 +65,9 @@ namespace FlaxEditor.Content
/// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" />
public class GenericJsonCreateEntry : CreateFileEntry
{
/// <inheritdoc/>
public override bool CanBeCreated => _options.Type != null;
/// <summary>
/// The create options.
/// </summary>

View File

@@ -33,8 +33,8 @@ namespace FlaxEditor
private void Set(CustomEditorWindow value)
{
_customEditor = value;
_presenter.Select(value);
_presenter.OverrideEditor = value;
_presenter.Select(value);
}
/// <inheritdoc />

View File

@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FlaxEditor.SceneGraph;
using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -52,6 +53,16 @@ namespace FlaxEditor.CustomEditors
/// </summary>
/// <param name="nodes">The nodes to select</param>
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>
@@ -81,6 +92,8 @@ namespace FlaxEditor.CustomEditors
Offsets = Margin.Zero;
Pivot = Float2.Zero;
IsScrollable = true;
Spacing = Utilities.Constants.UIMargin;
Margin = new Margin(Utilities.Constants.UIMargin);
}
/// <inheritdoc />
@@ -95,7 +108,7 @@ namespace FlaxEditor.CustomEditors
{
FlaxEditor.Editor.LogWarning(ex);
// Refresh layout on errors to reduce lgo spam
// Refresh layout on errors to reduce log spam
_presenter.BuildLayout();
}
@@ -132,6 +145,8 @@ namespace FlaxEditor.CustomEditors
get => _overrideEditor;
set
{
if (_overrideEditor == value)
return;
_overrideEditor = value;
RebuildLayout();
}
@@ -200,7 +215,6 @@ namespace FlaxEditor.CustomEditors
protected override void Deinitialize()
{
Editor = null;
_overrideEditor = null;
base.Deinitialize();
}

View File

@@ -9,7 +9,6 @@ using FlaxEditor.CustomEditors.Elements;
using FlaxEditor.GUI;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Tree;
using FlaxEditor.Modules;
using FlaxEditor.Scripting;
using FlaxEditor.Windows;
using FlaxEditor.Windows.Assets;
@@ -71,14 +70,14 @@ namespace FlaxEditor.CustomEditors.Dedicated
// Display prefab UI (when displaying object inside Prefab Window then display only nested prefabs)
prefab.GetNestedObject(ref prefabObjectId, out var nestedPrefabId, out var nestedPrefabObjectId);
var nestedPrefab = FlaxEngine.Content.Load<Prefab>(nestedPrefabId);
var panel = layout.CustomContainer<UniformGridPanel>();
var panel = layout.UniformGrid();
panel.CustomControl.Height = 20.0f;
panel.CustomControl.SlotsVertically = 1;
if (Presenter == Editor.Instance.Windows.PropertiesWin.Presenter || nestedPrefab)
{
var targetPrefab = nestedPrefab ?? prefab;
panel.CustomControl.SlotsHorizontally = 3;
// Selecting actor prefab asset
var selectPrefab = panel.Button("Select Prefab");
selectPrefab.Button.Clicked += () =>
@@ -133,35 +132,22 @@ namespace FlaxEditor.CustomEditors.Dedicated
var actor = (Actor)Values[0];
var scriptType = TypeUtils.GetType(actor.TypeName);
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 =>
{
propertiesWindow.LockObjects = !propertiesWindow.LockObjects;
var owner = Presenter?.Owner;
if (owner == null)
return;
owner.LockSelection = !owner.LockSelection;
// 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();
Editor.Instance.SceneEditing.Select(null);
Editor.Instance.SceneEditing.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);
var cachedSelection = owner.Selection.ToList();
owner.Select(null);
owner.Select(cachedSelection);
}
};
}
@@ -258,7 +244,17 @@ namespace FlaxEditor.CustomEditors.Dedicated
else if (editor.Values[0] is SceneObject sceneObject)
{
node.TextColor = sceneObject.HasPrefabLink ? FlaxEngine.GUI.Style.Current.ProgressNormal : FlaxEngine.GUI.Style.Current.BackgroundSelected;
node.Text = Utilities.Utils.GetPropertyNameUI(sceneObject.GetType().Name);
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);
}
// Array Item
else if (editor.ParentEditor is CollectionEditor)
@@ -268,7 +264,12 @@ namespace FlaxEditor.CustomEditors.Dedicated
// Common type
else if (editor.Values.Info != ScriptMemberInfo.Null)
{
node.Text = Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name);
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);
}
// Custom type
else if (editor.Values[0] != null)
@@ -316,7 +317,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
var childEditor = editor.ChildrenEditors[i];
// 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;
var child = ProcessDiff(childEditor, !isScriptEditorWithRefValue);
@@ -361,13 +362,39 @@ namespace FlaxEditor.CustomEditors.Dedicated
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)
{
// 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
if (rootNode == null || rootNode.ChildrenCount == 0)
if (rootNode == null)
{
var cm1 = new ContextMenu();
cm1.AddButton("No changes detected");

View File

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

View File

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

View File

@@ -92,12 +92,14 @@ namespace FlaxEditor.CustomEditors.Dedicated
// Update add button
var update = group.Button("Update").Button;
group.Space(0);
update.TooltipText = "Refreshes the dashboard statistics";
update.Height = 16.0f;
update.Clicked += RebuildLayout;
// New locale add 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.Height = 16.0f;
addLocale.ButtonClicked += delegate(Button button)
@@ -167,12 +169,14 @@ namespace FlaxEditor.CustomEditors.Dedicated
// Export button
var exportLocalization = group.Button("Export...").Button;
group.Space(0);
exportLocalization.TooltipText = "Exports the localization strings into .pot file for translation";
exportLocalization.Height = 16.0f;
exportLocalization.Clicked += () => Export(tableEntries, allKeys);
// 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.Height = 16.0f;
findStringsCode.Clicked += delegate

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using System.Collections.Generic;
using System.Reflection.Emit;
using FlaxEditor.CustomEditors.GUI;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -93,8 +94,10 @@ namespace FlaxEditor.CustomEditors.Dedicated
// Add info box
if (IsSingleObject && Values[0] is RigidBody && Editor.IsPlayMode)
{
_infoLabel = layout.Label(string.Empty).Label;
var group = layout.Group("Info");
_infoLabel = group.Label(string.Empty).Label;
_infoLabel.AutoHeight = true;
_infoLabel.Margin = new Margin(3);
}
}
}

View File

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

View File

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

View File

@@ -41,13 +41,9 @@ namespace FlaxEditor.CustomEditors.Editors
public override void Initialize(LayoutElementsContainer layout)
{
base.Initialize(layout);
if (XElement.ValueBox.Parent is UniformGridPanel ug)
{
ug.Height += 2;
ug.SlotSpacing = new Float2(4);
ug.SlotPadding = new Margin(0, 0, 1, 1);
}
CheckLayout(ug);
// Override colors
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
@@ -75,11 +71,7 @@ namespace FlaxEditor.CustomEditors.Editors
base.Initialize(layout);
if (XElement.ValueBox.Parent is UniformGridPanel ug)
{
ug.Height += 2;
ug.SlotSpacing = new Float2(4);
ug.SlotPadding = new Margin(0, 0, 1, 1);
}
CheckLayout(ug);
// Override colors
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
@@ -136,13 +128,9 @@ namespace FlaxEditor.CustomEditors.Editors
menu.AddButton("Link", ToggleLink).LinkTooltip("Links scale components for uniform scaling");
};
}
if (XElement.ValueBox.Parent is UniformGridPanel ug)
{
ug.Height += 2;
ug.SlotSpacing = new Float2(4);
ug.SlotPadding = new Margin(0, 0, 1, 1);
}
CheckLayout(ug);
// Override colors
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";
}
}
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)
{
var panel = dragArea.HorizontalPanel();
panel.Panel.Size = new Float2(0, 20);
panel.Panel.Margin = new Margin(2);
panel.Panel.Size = new Float2(0, 18);
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.Enabled = size > _minCount;
removeButton.Button.AnchorPreset = AnchorPresets.TopRight;
@@ -656,7 +656,7 @@ namespace FlaxEditor.CustomEditors.Editors
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.Enabled = (!NotNullItems || size > 0) && size < _maxCount;
addButton.Button.AnchorPreset = AnchorPresets.TopRight;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,13 +20,6 @@ namespace FlaxEditor.CustomEditors.GUI
/// </summary>
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 float _splitterValue;
private Rectangle _splitterRect;
@@ -65,16 +58,18 @@ namespace FlaxEditor.CustomEditors.GUI
/// <param name="element">The element.</param>
public PropertiesList(PropertiesListElement element)
{
ClipChildren = false;
_element = element;
_splitterValue = 0.4f;
BottomMargin = TopMargin = RightMargin = SplitterMargin;
Margin = new Margin();
Spacing = Utilities.Constants.UIMargin;
UpdateSplitRect();
}
private void UpdateSplitRect()
{
_splitterRect = new Rectangle(Mathf.Clamp(_splitterValue * Width - SplitterSizeHalf, 0.0f, Width), 0, SplitterSize, Height);
LeftMargin = _splitterValue * Width + SplitterMargin;
_splitterRect = new Rectangle(Mathf.Clamp(_splitterValue * Width - SplitterSize * 0.5f, 0.0f, Width), 0, SplitterSize, Height);
LeftMargin = _splitterValue * Width + _spacing;
}
private void StartTracking()
@@ -222,23 +217,33 @@ namespace FlaxEditor.CustomEditors.GUI
/// <inheritdoc />
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 w = Width - _margin.Width;
bool firstItem = true;
for (int i = 0; i < _children.Count; i++)
{
Control c = _children[i];
if (!(c is PropertyNameLabel))
{
var h = c.Height;
c.Bounds = new Rectangle(_margin.Left, y + _spacing, w, h);
var rect = new Rectangle(_margin.Left, y, w, c.Height);
if (c.Visible)
{
if (firstItem)
firstItem = false;
else
rect.Y += _spacing;
}
else if (!firstItem)
rect.Y += _spacing;
c.Bounds = rect;
if (c.Visible)
y = c.Bottom;
}
}
y += _margin.Bottom;
// Place labels accordingly to their respective controls placement
float namesWidth = _splitterValue * Width;
int count = _element.Labels.Count;
float[] yStarts = new float[count + 1];
@@ -271,7 +276,9 @@ namespace FlaxEditor.CustomEditors.GUI
{
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.Bounds = rect;
}

View File

@@ -202,6 +202,17 @@ namespace FlaxEditor.CustomEditors
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>
/// Adds new custom element.
/// </summary>

View File

@@ -1031,6 +1031,8 @@ namespace FlaxEditor
{
Internal_GetEditorBoxWithChildren(FlaxEngine.Object.GetUnmanagedPtr(actor), out var box);
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);
}
else

View File

@@ -611,6 +611,16 @@ namespace FlaxEditor.GUI
OnClickItem(focusedItem);
return true;
}
else
{
// Select first item if no item is focused (most likely to be the best result), saves the user from pressing arrow down first
var visibleItems = GetVisibleItems();
if (visibleItems.Count > 0)
{
OnClickItem(visibleItems[0]);
return true;
}
}
break;
}

View File

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

View File

@@ -40,6 +40,7 @@ namespace FlaxEditor.GUI.Tree
private readonly bool _supportMultiSelect;
private Margin _margin;
private bool _autoSize = true;
private bool _deferLayoutUpdate = false;
/// <summary>
/// The TreeNode that is being dragged over. This could have a value when not dragging.
@@ -66,6 +67,11 @@ namespace FlaxEditor.GUI.Tree
/// Gets the first selected node or null.
/// </summary>
public TreeNode SelectedNode => Selection.Count > 0 ? Selection[0] : null;
/// <summary>
/// Allow nodes to Draw the root tree line.
/// </summary>
public bool DrawRootTreeLine = true;
/// <summary>
/// Gets or sets the margin for the child tree nodes.
@@ -353,9 +359,25 @@ namespace FlaxEditor.GUI.Tree
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 />
public override void Update(float deltaTime)
{
if (_deferLayoutUpdate)
{
base.PerformLayout();
_deferLayoutUpdate = false;
}
var node = SelectedNode;
// 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
if (Editor.Instance.Options.Options.Interface.ShowTreeLines)
{
TreeNode parentNode = Parent as TreeNode;
ContainerControl parent = Parent;
TreeNode parentNode = parent as TreeNode;
bool thisNodeIsLast = false;
while (parentNode != null && parentNode != ParentTree.Children[0])
while (parentNode != null && (parentNode != tree.Children[0] || tree.DrawRootTreeLine))
{
float bottomOffset = 0;
float topOffset = 0;
if (Parent == parentNode && this == Parent.Children[0])
if (parent == parentNode && this == parent.Children[0])
topOffset = 2;
if (thisNodeIsLast && parentNode.Children.Count == 1)
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;
bottomOffset = topOffset != 0 ? 4 : 2;
@@ -784,6 +785,8 @@ namespace FlaxEditor.GUI.Tree
if (_iconCollaped.IsValid)
leftOffset += 18;
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);
parentNode = parentNode.Parent as TreeNode;
}

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)
var originalTransform = instance.LocalTransform;
var originalName = instance.Name;
if (instance.IsPrefabRoot && instance.HasScene)
{
instance.LocalTransform = prefab.GetDefaultInstance().Transform;
instance.Name = prefab.GetDefaultInstance().Name;
}
// Call backend
var failed = PrefabManager.Internal_ApplyAll(FlaxEngine.Object.GetUnmanagedPtr(instance));
instance.LocalTransform = originalTransform;
instance.Name = originalName;
if (failed)
throw new Exception("Failed to apply the prefab. See log to learn more.");

View File

@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Linq;
using FlaxEditor.Actions;
using FlaxEditor.SceneGraph;
using FlaxEditor.SceneGraph.Actors;
using FlaxEngine;
namespace FlaxEditor.Modules
@@ -561,7 +562,8 @@ namespace FlaxEditor.Modules
public void CreateParentForSelectedActors()
{
List<SceneGraphNode> selection = Editor.SceneEditing.Selection;
var actors = selection.Where(x => x is ActorNode).Select(x => ((ActorNode)x).Actor);
// Get Actors but skip scene node
var actors = selection.Where(x => x is ActorNode and not SceneNode).Select(x => ((ActorNode)x).Actor);
var actorsCount = actors.Count();
if (actorsCount == 0)
return;

View File

@@ -306,19 +306,21 @@ namespace FlaxEditor.Modules
public override void OnPlayEnd()
{
var gameWin = Editor.Windows.GameWin;
switch (gameWin.FocusOnPlayOption)
if (gameWin != null)
{
case Options.InterfaceOptions.PlayModeFocus.None: break;
case Options.InterfaceOptions.PlayModeFocus.GameWindow: break;
case Options.InterfaceOptions.PlayModeFocus.GameWindowThenRestore:
if (_previousWindow != null && !_previousWindow.IsDisposing)
switch (gameWin.FocusOnPlayOption)
{
if (!Editor.Windows.GameWin.ParentDockPanel.ContainsTab(_previousWindow))
break;
_previousWindow.Focus();
case Options.InterfaceOptions.PlayModeFocus.None: break;
case Options.InterfaceOptions.PlayModeFocus.GameWindow: break;
case Options.InterfaceOptions.PlayModeFocus.GameWindowThenRestore:
if (_previousWindow != null && !_previousWindow.IsDisposing)
{
if (!Editor.Windows.GameWin.ParentDockPanel.ContainsTab(_previousWindow))
break;
_previousWindow.Focus();
}
break;
}
break;
}
Editor.UI.UncheckPauseButton();

View File

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

View File

@@ -33,6 +33,25 @@ namespace FlaxEditor.Options
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>
/// Input editor options data container.
/// </summary>
@@ -40,6 +59,16 @@ namespace FlaxEditor.Options
[HideInEditor]
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
[DefaultValue(typeof(InputBinding), "Ctrl+S")]
@@ -230,9 +259,9 @@ namespace FlaxEditor.Options
#region Profiler
[DefaultValue(typeof(InputBinding), "None")]
[DefaultValue(typeof(InputBinding), "Ctrl+Alpha7")]
[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")]
[EditorDisplay("Profiler", "Start/Stop Profiler"), EditorOrder(631)]
@@ -356,24 +385,267 @@ namespace FlaxEditor.Options
#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
[DefaultValue(typeof(InputBinding), "Ctrl+W")]
[EditorDisplay("Interface"), EditorOrder(2000)]
[EditorDisplay("Interface"), EditorOrder(3500)]
public InputBinding CloseTab = new InputBinding(KeyboardKeys.W, KeyboardKeys.Control);
[DefaultValue(typeof(InputBinding), "Ctrl+Tab")]
[EditorDisplay("Interface"), EditorOrder(2010)]
[EditorDisplay("Interface"), EditorOrder(3510)]
public InputBinding NextTab = new InputBinding(KeyboardKeys.Tab, KeyboardKeys.Control);
[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);
[DefaultValue(SceneNodeDoubleClick.Expand)]
[EditorDisplay("Interface"), EditorOrder(2030)]
[EditorDisplay("Interface"), EditorOrder(3530)]
public SceneNodeDoubleClick DoubleClickSceneNode = SceneNodeDoubleClick.Expand;
#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

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

View File

@@ -320,7 +320,7 @@ namespace FlaxEditor.SceneGraph.GUI
if (noFilter && actor != null)
{
// 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);
}

View File

@@ -573,11 +573,11 @@ namespace FlaxEditor.Surface.Archetypes
"Blend animation poses (with additive mode)" +
"\n" +
"\nNote: " +
"\nOrder of nodes matters, because Additive animation is appplayed on top of curent frame." +
"\nThe order of the nodes is important, because additive animation is applied on top of current frame." +
"\n" +
"\nTip for blender users:" +
"\nInside NLA the the order is bottom (first node in flax) to the top (last node in flax)" +
"\nu need to place it in this order to get correct resoults",
"\nInside NLA the the order is bottom (first node in flax) to the top (last node in flax)." +
"\nYou need to place animations in this order to get correct results.",
Flags = NodeFlags.AnimGraph,
Size = new Float2(170, 80),
DefaultValues = new object[]

View File

@@ -607,14 +607,14 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Terrain Layer Weight",
Description = "Terrain layer weight mask used for blending terrain layers",
Flags = NodeFlags.MaterialGraph,
Size = new Float2(220, 30),
Size = new Float2(200, 30),
DefaultValues = new object[]
{
0,
},
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),
}
},

View File

@@ -409,7 +409,7 @@ namespace FlaxEditor.Surface
/// <summary>
/// Called after adding the control to the surface after paste.
/// </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)
{
}

View File

@@ -369,24 +369,14 @@ namespace FlaxEditor.Surface
}
// Change scale (disable scaling during selecting nodes)
if (IsMouseOver && !_leftMouseDown && !IsPrimaryMenuOpened)
if (IsMouseOver && !_leftMouseDown && !_rightMouseDown && !IsPrimaryMenuOpened)
{
var nextViewScale = ViewScale + delta * 0.1f;
if (delta > 0 && !_rightMouseDown)
{
// Scale towards mouse when zooming in
var nextCenterPosition = ViewPosition + location / ViewScale;
ViewScale = nextViewScale;
ViewPosition = nextCenterPosition - (location / ViewScale);
}
else
{
// Scale while keeping center position when zooming out or when dragging view
var viewCenter = ViewCenterPosition;
ViewScale = nextViewScale;
ViewCenterPosition = viewCenter;
}
// Scale towards/ away from mouse when zooming in/ out
var nextCenterPosition = ViewPosition + location / ViewScale;
ViewScale = nextViewScale;
ViewPosition = nextCenterPosition - (location / ViewScale);
return true;
}

View File

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

View File

@@ -402,7 +402,7 @@ namespace FlaxEditor.Utilities
/// <summary>
/// Creates an Import path ui that show the asset import path and adds a button to show the folder in the file system.
/// </summary>
/// <param name="parentLayout">The parent layout container.</param>
/// <param name="parentLayout">The parent layout element.</param>
/// <param name="assetItem">The asset item to get the import path of.</param>
public static void CreateImportPathUI(CustomEditors.LayoutElementsContainer parentLayout, Content.BinaryAssetItem assetItem)
{
@@ -413,21 +413,16 @@ namespace FlaxEditor.Utilities
/// <summary>
/// Creates an Import path ui that show the import path and adds a button to show the folder in the file system.
/// </summary>
/// <param name="parentLayout">The parent layout container.</param>
/// <param name="parentLayout">The parent layout element.</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, bool useInitialSpacing = true)
public static void CreateImportPathUI(CustomEditors.LayoutElementsContainer parentLayout, string path)
{
if (!string.IsNullOrEmpty(path))
{
if (useInitialSpacing)
parentLayout.Space(5);
parentLayout.Label("Import Path:").Label.TooltipText = "Source asset path (can be relative or absolute to the project)";
var textBox = parentLayout.TextBox().TextBox;
textBox.TooltipText = "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.Text = path;
parentLayout.Space(2);
var button = parentLayout.Button(Constants.ShowInExplorer).Button;
button.Clicked += () => FileSystem.ShowFileExplorer(Path.GetDirectoryName(path));
}
@@ -1505,7 +1500,6 @@ namespace FlaxEditor.Utilities
inputActions.Add(options => options.BuildNav, Editor.Instance.BuildNavMesh);
inputActions.Add(options => options.BuildSDF, Editor.Instance.BuildAllMeshesSDF);
inputActions.Add(options => options.TakeScreenshot, Editor.Instance.Windows.TakeScreenshot);
inputActions.Add(options => options.ProfilerWindow, () => Editor.Instance.Windows.ProfilerWin.FocusOrShow());
#if USE_PROFILER
inputActions.Add(options => options.ProfilerStartStop, () =>
{

View File

@@ -916,7 +916,7 @@ namespace FlaxEditor.Viewport
for (int i = 0; i < ViewFlagsValues.Length; i++)
{
var v = ViewFlagsValues[i];
var button = viewFlags.AddButton(v.Name);
var button = viewFlags.AddButton(v.Name, v.InputBinding.ToString());
button.CloseMenuOnClick = false;
button.Tag = v.Mode;
}
@@ -965,7 +965,7 @@ namespace FlaxEditor.Viewport
}
else
{
var button = debugView.AddButton(v.Name);
var button = debugView.AddButton(v.Name, v.InputBinding.ToString());
button.CloseMenuOnClick = false;
button.Tag = v.Mode;
}
@@ -1011,16 +1011,64 @@ namespace FlaxEditor.Viewport
#endregion View mode widget
}
// Viewpoints
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.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.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)));
// Editor camera
InputActions.Add(options => options.CameraToggleRotation, () => _isVirtualMouseRightDown = !_isVirtualMouseRightDown);
InputActions.Add(options => options.CameraIncreaseMoveSpeed, () => AdjustCameraMoveSpeed(1));
InputActions.Add(options => options.CameraDecreaseMoveSpeed, () => AdjustCameraMoveSpeed(-1));
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
task.Begin += OnRenderBegin;
@@ -1965,8 +2013,17 @@ namespace FlaxEditor.Viewport
{
public readonly string Name;
public readonly ViewMode Mode;
public readonly InputBinding InputBinding;
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)
{
Mode = mode;
@@ -1984,13 +2041,13 @@ namespace FlaxEditor.Viewport
private static readonly ViewModeOptions[] ViewModeValues =
{
new ViewModeOptions(ViewMode.Default, "Default"),
new ViewModeOptions(ViewMode.Unlit, "Unlit"),
new ViewModeOptions(ViewMode.NoPostFx, "No PostFx"),
new ViewModeOptions(ViewMode.Wireframe, "Wireframe"),
new ViewModeOptions(ViewMode.LightBuffer, "Light Buffer"),
new ViewModeOptions(ViewMode.Reflections, "Reflections Buffer"),
new ViewModeOptions(ViewMode.Depth, "Depth Buffer"),
new ViewModeOptions(ViewMode.Default, "Default", Editor.Instance.Options.Options.Input.Default),
new ViewModeOptions(ViewMode.Unlit, "Unlit", Editor.Instance.Options.Options.Input.Unlit),
new ViewModeOptions(ViewMode.NoPostFx, "No PostFx", Editor.Instance.Options.Options.Input.NoPostFX),
new ViewModeOptions(ViewMode.Wireframe, "Wireframe", Editor.Instance.Options.Options.Input.Wireframe),
new ViewModeOptions(ViewMode.LightBuffer, "Light Buffer", Editor.Instance.Options.Options.Input.LightBuffer),
new ViewModeOptions(ViewMode.Reflections, "Reflections Buffer", Editor.Instance.Options.Options.Input.ReflectionsBuffer),
new ViewModeOptions(ViewMode.Depth, "Depth Buffer", Editor.Instance.Options.Options.Input.DepthBuffer),
new ViewModeOptions("GBuffer", new[]
{
new ViewModeOptions(ViewMode.Diffuse, "Diffuse"),
@@ -2004,16 +2061,16 @@ namespace FlaxEditor.Viewport
new ViewModeOptions(ViewMode.Normals, "Normals"),
new ViewModeOptions(ViewMode.AmbientOcclusion, "Ambient Occlusion"),
}),
new ViewModeOptions(ViewMode.MotionVectors, "Motion Vectors"),
new ViewModeOptions(ViewMode.LightmapUVsDensity, "Lightmap UVs Density"),
new ViewModeOptions(ViewMode.VertexColors, "Vertex Colors"),
new ViewModeOptions(ViewMode.PhysicsColliders, "Physics Colliders"),
new ViewModeOptions(ViewMode.LODPreview, "LOD Preview"),
new ViewModeOptions(ViewMode.MaterialComplexity, "Material Complexity"),
new ViewModeOptions(ViewMode.QuadOverdraw, "Quad Overdraw"),
new ViewModeOptions(ViewMode.GlobalSDF, "Global SDF"),
new ViewModeOptions(ViewMode.GlobalSurfaceAtlas, "Global Surface Atlas"),
new ViewModeOptions(ViewMode.GlobalIllumination, "Global Illumination"),
new ViewModeOptions(ViewMode.MotionVectors, "Motion Vectors", Editor.Instance.Options.Options.Input.MotionVectors),
new ViewModeOptions(ViewMode.LightmapUVsDensity, "Lightmap UVs Density", Editor.Instance.Options.Options.Input.LightmapUVDensity),
new ViewModeOptions(ViewMode.VertexColors, "Vertex Colors", Editor.Instance.Options.Options.Input.VertexColors),
new ViewModeOptions(ViewMode.PhysicsColliders, "Physics Colliders", Editor.Instance.Options.Options.Input.PhysicsColliders),
new ViewModeOptions(ViewMode.LODPreview, "LOD Preview", Editor.Instance.Options.Options.Input.LODPreview),
new ViewModeOptions(ViewMode.MaterialComplexity, "Material Complexity", Editor.Instance.Options.Options.Input.MaterialComplexity),
new ViewModeOptions(ViewMode.QuadOverdraw, "Quad Overdraw", Editor.Instance.Options.Options.Input.QuadOverdraw),
new ViewModeOptions(ViewMode.GlobalSDF, "Global SDF", Editor.Instance.Options.Options.Input.GloablSDF),
new ViewModeOptions(ViewMode.GlobalSurfaceAtlas, "Global Surface Atlas", Editor.Instance.Options.Options.Input.GlobalSurfaceAtlas),
new ViewModeOptions(ViewMode.GlobalIllumination, "Global Illumination", Editor.Instance.Options.Options.Input.GlobalIllumination),
};
private void WidgetViewModeShowHideClicked(ContextMenuButton button)
@@ -2046,43 +2103,45 @@ namespace FlaxEditor.Viewport
{
public readonly ViewFlags Mode;
public readonly string Name;
public readonly InputBinding InputBinding;
public ViewFlagOptions(ViewFlags mode, string name)
public ViewFlagOptions(ViewFlags mode, string name, InputBinding inputBinding)
{
Mode = mode;
Name = name;
InputBinding = inputBinding;
}
}
private static readonly ViewFlagOptions[] ViewFlagsValues =
{
new ViewFlagOptions(ViewFlags.AntiAliasing, "Anti Aliasing"),
new ViewFlagOptions(ViewFlags.Shadows, "Shadows"),
new ViewFlagOptions(ViewFlags.EditorSprites, "Editor Sprites"),
new ViewFlagOptions(ViewFlags.Reflections, "Reflections"),
new ViewFlagOptions(ViewFlags.SSR, "Screen Space Reflections"),
new ViewFlagOptions(ViewFlags.AO, "Ambient Occlusion"),
new ViewFlagOptions(ViewFlags.GI, "Global Illumination"),
new ViewFlagOptions(ViewFlags.DirectionalLights, "Directional Lights"),
new ViewFlagOptions(ViewFlags.PointLights, "Point Lights"),
new ViewFlagOptions(ViewFlags.SpotLights, "Spot Lights"),
new ViewFlagOptions(ViewFlags.SkyLights, "Sky Lights"),
new ViewFlagOptions(ViewFlags.Sky, "Sky"),
new ViewFlagOptions(ViewFlags.Fog, "Fog"),
new ViewFlagOptions(ViewFlags.SpecularLight, "Specular Light"),
new ViewFlagOptions(ViewFlags.Decals, "Decals"),
new ViewFlagOptions(ViewFlags.CustomPostProcess, "Custom Post Process"),
new ViewFlagOptions(ViewFlags.Bloom, "Bloom"),
new ViewFlagOptions(ViewFlags.ToneMapping, "Tone Mapping"),
new ViewFlagOptions(ViewFlags.EyeAdaptation, "Eye Adaptation"),
new ViewFlagOptions(ViewFlags.CameraArtifacts, "Camera Artifacts"),
new ViewFlagOptions(ViewFlags.LensFlares, "Lens Flares"),
new ViewFlagOptions(ViewFlags.DepthOfField, "Depth of Field"),
new ViewFlagOptions(ViewFlags.MotionBlur, "Motion Blur"),
new ViewFlagOptions(ViewFlags.ContactShadows, "Contact Shadows"),
new ViewFlagOptions(ViewFlags.PhysicsDebug, "Physics Debug"),
new ViewFlagOptions(ViewFlags.LightsDebug, "Lights Debug"),
new ViewFlagOptions(ViewFlags.DebugDraw, "Debug Draw"),
new ViewFlagOptions(ViewFlags.AntiAliasing, "Anti Aliasing", Editor.Instance.Options.Options.Input.AntiAliasing),
new ViewFlagOptions(ViewFlags.Shadows, "Shadows", Editor.Instance.Options.Options.Input.Shadows),
new ViewFlagOptions(ViewFlags.EditorSprites, "Editor Sprites", Editor.Instance.Options.Options.Input.EditorSprites),
new ViewFlagOptions(ViewFlags.Reflections, "Reflections", Editor.Instance.Options.Options.Input.Reflections),
new ViewFlagOptions(ViewFlags.SSR, "Screen Space Reflections", Editor.Instance.Options.Options.Input.ScreenSpaceReflections),
new ViewFlagOptions(ViewFlags.AO, "Ambient Occlusion", Editor.Instance.Options.Options.Input.AmbientOcclusion),
new ViewFlagOptions(ViewFlags.GI, "Global Illumination", Editor.Instance.Options.Options.Input.GlobalIlluminationViewFlag),
new ViewFlagOptions(ViewFlags.DirectionalLights, "Directional Lights", Editor.Instance.Options.Options.Input.DirectionalLights),
new ViewFlagOptions(ViewFlags.PointLights, "Point Lights", Editor.Instance.Options.Options.Input.PointLights),
new ViewFlagOptions(ViewFlags.SpotLights, "Spot Lights", Editor.Instance.Options.Options.Input.SpotLights),
new ViewFlagOptions(ViewFlags.SkyLights, "Sky Lights", Editor.Instance.Options.Options.Input.SkyLights),
new ViewFlagOptions(ViewFlags.Sky, "Sky", Editor.Instance.Options.Options.Input.Sky),
new ViewFlagOptions(ViewFlags.Fog, "Fog", Editor.Instance.Options.Options.Input.Fog),
new ViewFlagOptions(ViewFlags.SpecularLight, "Specular Light", Editor.Instance.Options.Options.Input.SpecularLight),
new ViewFlagOptions(ViewFlags.Decals, "Decals", Editor.Instance.Options.Options.Input.Decals),
new ViewFlagOptions(ViewFlags.CustomPostProcess, "Custom Post Process", Editor.Instance.Options.Options.Input.CustomPostProcess),
new ViewFlagOptions(ViewFlags.Bloom, "Bloom", Editor.Instance.Options.Options.Input.Bloom),
new ViewFlagOptions(ViewFlags.ToneMapping, "Tone Mapping", Editor.Instance.Options.Options.Input.ToneMapping),
new ViewFlagOptions(ViewFlags.EyeAdaptation, "Eye Adaptation", Editor.Instance.Options.Options.Input.EyeAdaptation),
new ViewFlagOptions(ViewFlags.CameraArtifacts, "Camera Artifacts", Editor.Instance.Options.Options.Input.CameraArtifacts),
new ViewFlagOptions(ViewFlags.LensFlares, "Lens Flares", Editor.Instance.Options.Options.Input.LensFlares),
new ViewFlagOptions(ViewFlags.DepthOfField, "Depth of Field", Editor.Instance.Options.Options.Input.DepthOfField),
new ViewFlagOptions(ViewFlags.MotionBlur, "Motion Blur", Editor.Instance.Options.Options.Input.MotionBlur),
new ViewFlagOptions(ViewFlags.ContactShadows, "Contact Shadows", Editor.Instance.Options.Options.Input.ContactShadows),
new ViewFlagOptions(ViewFlags.PhysicsDebug, "Physics Debug", Editor.Instance.Options.Options.Input.PhysicsDebug),
new ViewFlagOptions(ViewFlags.LightsDebug, "Lights Debug", Editor.Instance.Options.Options.Input.LightsDebug),
new ViewFlagOptions(ViewFlags.DebugDraw, "Debug Draw", Editor.Instance.Options.Options.Input.DebugDraw),
};
private void WidgetViewFlagsShowHide(Control cm)

View File

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

View File

@@ -231,7 +231,8 @@ namespace FlaxEditor.Windows.Assets
group.Object(importSettingsValues);
// Creates the import path UI
Utilities.Utils.CreateImportPathUI(layout, proxy.Window.Item as BinaryAssetItem);
group = layout.Group("Import Path");
Utilities.Utils.CreateImportPathUI(group, proxy.Window.Item as BinaryAssetItem);
layout.Space(5);
var reimportButton = layout.Button("Reimport");

View File

@@ -6,6 +6,7 @@ using FlaxEditor.Content.Import;
using FlaxEditor.CustomEditors;
using FlaxEditor.CustomEditors.Editors;
using FlaxEditor.GUI;
using FlaxEditor.Scripting;
using FlaxEditor.Viewport.Previews;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -76,7 +77,8 @@ namespace FlaxEditor.Windows.Assets
{
public override void Initialize(LayoutElementsContainer layout)
{
var window = ((PropertiesProxy)Values[0])._window;
var proxy = ((PropertiesProxy)Values[0]);
var window = proxy._window;
if (window == null)
{
layout.Label("Loading...", TextAlignment.Center);
@@ -101,7 +103,8 @@ namespace FlaxEditor.Windows.Assets
base.Initialize(layout);
// Creates the import path UI
Utilities.Utils.CreateImportPathUI(layout, window.Item as BinaryAssetItem);
var pathGroup = layout.Group("Import Path");
Utilities.Utils.CreateImportPathUI(pathGroup, window.Item as BinaryAssetItem);
layout.Space(5);
var reimportButton = layout.Button("Reimport");

View File

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

View File

@@ -102,6 +102,8 @@ namespace FlaxEditor.Windows.Assets
private class CookData : CreateFileEntry
{
public override bool CanBeCreated => true;
public PropertiesProxy Proxy;
public CollisionDataType Type;
public ModelBase Model;

View File

@@ -55,10 +55,11 @@ namespace FlaxEditor.Windows.Assets
base.Initialize(layout);
// Creates the import path UI
Utilities.Utils.CreateImportPathUI(layout, window.Item as BinaryAssetItem);
var pathGroup = layout.Group("Import Path");
Utilities.Utils.CreateImportPathUI(pathGroup, window.Item as BinaryAssetItem);
layout.Space(5);
var reimportButton = layout.Button("Reimport");
pathGroup.Space(5);
var reimportButton = pathGroup.Button("Reimport");
reimportButton.Button.Clicked += () => ((PropertiesProxy)Values[0]).Reimport();
}
}

View File

@@ -754,17 +754,17 @@ namespace FlaxEditor.Windows.Assets
if (Utilities.Utils.OnAssetProperties(layout, proxy.Asset))
return;
var group = layout.Group("Import Settings");
var importSettingsGroup = layout.Group("Import Settings");
var importSettingsField = typeof(ImportPropertiesProxyBase).GetField(nameof(ImportSettings), BindingFlags.NonPublic | BindingFlags.Instance);
var importSettingsValues = new ValueContainer(new ScriptMemberInfo(importSettingsField)) { proxy.ImportSettings };
group.Object(importSettingsValues);
importSettingsGroup.Object(importSettingsValues);
// Creates the import path UI
Utilities.Utils.CreateImportPathUI(layout, proxy.Window.Item as BinaryAssetItem);
var group = layout.Group("Import Path");
Utilities.Utils.CreateImportPathUI(group, proxy.Window.Item as BinaryAssetItem);
layout.Space(5);
var reimportButton = group.Button("Reimport");
var reimportButton = importSettingsGroup.Button("Reimport");
reimportButton.Button.Clicked += () => ((ImportPropertiesProxyBase)Values[0]).Reimport();
}
}

View File

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

View File

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

View File

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

View File

@@ -78,7 +78,7 @@ namespace FlaxEditor.Windows.Assets
/// <summary>
/// Indication of if the prefab window selection is locked on specific objects.
/// </summary>
public bool LockSelectedObjects
public bool LockSelection
{
get => _lockSelection;
set
@@ -160,6 +160,7 @@ namespace FlaxEditor.Windows.Assets
AnchorPreset = AnchorPresets.HorizontalStretchMiddle,
Parent = headerPanel,
Bounds = new Rectangle(4, 4, headerPanel.Width - 8, 18),
TooltipText = "Search the prefab.\n\nYou can prefix your search with different search operators:\ns: -> Actor with script of type\na: -> Actor type\nc: -> Control type",
};
_searchBox.TextChanged += OnSearchBoxTextChanged;

View File

@@ -119,9 +119,10 @@ namespace FlaxEditor.Windows.Assets
}
base.Initialize(layout);
// Creates the import path UI
Utilities.Utils.CreateImportPathUI(layout, proxy._window.Item as BinaryAssetItem);
var group = layout.Group("Import Path");
Utilities.Utils.CreateImportPathUI(group, proxy._window.Item as BinaryAssetItem);
layout.Space(5);
var reimportButton = layout.Button("Reimport");

View File

@@ -143,7 +143,8 @@ namespace FlaxEditor.Windows.Assets
base.Initialize(layout);
// Creates the import path UI
Utilities.Utils.CreateImportPathUI(layout, proxy._window.Item as BinaryAssetItem);
var group = layout.Group("Import Path");
Utilities.Utils.CreateImportPathUI(group, proxy._window.Item as BinaryAssetItem);
// Reimport
layout.Space(5);

View File

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

View File

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

View File

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

View File

@@ -2,6 +2,7 @@
using System;
using FlaxEditor.Content;
using FlaxEditor.Options;
using FlaxEngine;
using FlaxEngine.GUI;
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
Editor.Windows.OnWindowAdd(this);
}

View File

@@ -292,7 +292,7 @@ namespace FlaxEditor.Windows
private class GameRoot : UIEditorRoot
{
internal bool Editable = true;
public override bool EnableInputs => !Time.GamePaused && Editor.IsPlayMode && Editable;
public override bool EnableInputs => !Time.GamePaused && Editor.IsPlayMode;
public override bool EnableSelecting => (!Editor.IsPlayMode || Time.GamePaused) && Editable;
public override TransformGizmo TransformGizmo => Editor.Instance.MainTransformGizmo;
}
@@ -305,6 +305,7 @@ namespace FlaxEditor.Windows
: base(editor, true, ScrollBars.None)
{
Title = "Game";
Icon = editor.Icons.Play64;
AutoFocus = true;
var task = MainRenderTask.Instance;

View File

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

View File

@@ -492,7 +492,7 @@ namespace FlaxEditor.Windows.Profiler
{
break;
}
subEventsMemoryTotal += sub.ManagedMemoryAllocation + e.NativeMemoryAllocation;
subEventsMemoryTotal += sub.ManagedMemoryAllocation + sub.NativeMemoryAllocation;
}
string name = e.Name.Replace("::", ".");

View File

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

View File

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

View File

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

View File

@@ -15,6 +15,8 @@
#if USE_EDITOR
#include "Engine/Engine/Globals.h"
ThreadLocal<bool> ContentDeprecatedFlags;
void ContentDeprecated::Mark()
@@ -467,11 +469,13 @@ void Asset::CancelStreaming()
{
// Cancel loading task but go over asset locker to prevent case if other load threads still loads asset while it's reimported on other thread
Locker.Lock();
auto loadTask = (ContentLoadTask*)Platform::AtomicRead(&_loadingTask);
auto loadingTask = (ContentLoadTask*)Platform::AtomicRead(&_loadingTask);
Locker.Unlock();
if (loadTask)
if (loadingTask)
{
loadTask->Cancel();
Platform::AtomicStore(&_loadingTask, 0);
LOG(Warning, "Cancel loading task for \'{0}\'", ToString());
loadingTask->Cancel();
}
}
@@ -590,7 +594,7 @@ bool Asset::onLoad(LoadAssetTask* task)
#if USE_EDITOR
// 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");
LOG(Info, "Resaving asset '{}' that uses deprecated data format", ToString());
@@ -632,18 +636,11 @@ void Asset::onUnload_MainThread()
ASSERT(IsInMainThread());
// Cancel any streaming before calling OnUnloaded event
CancelStreaming();
// Send event
OnUnloaded(this);
// Check if is during loading
auto loadingTask = (ContentLoadTask*)Platform::AtomicRead(&_loadingTask);
if (loadingTask != nullptr)
{
// Cancel loading
Platform::AtomicStore(&_loadingTask, 0);
LOG(Warning, "Cancel loading task for \'{0}\'", ToString());
loadingTask->Cancel();
}
}
#if USE_EDITOR

View File

@@ -34,6 +34,10 @@ public:
public:
// [ContentLoadTask]
String ToString() const override
{
return String::Format(TEXT("Load Asset Data Task ({}, {}, {})"), (int32)GetState(), _chunks, _asset ? _asset->GetPath() : String::Empty);
}
bool HasReference(Object* obj) const override
{
return obj == _asset;

View File

@@ -22,7 +22,7 @@ public:
static CreateAssetResult Create(CreateAssetContext& context)
{
// Base
IMPORT_SETUP(SkeletonMask, 1);
IMPORT_SETUP(SkeletonMask, 2);
// Chunk 0
if (context.AllocateChunk(0))

View File

@@ -93,6 +93,9 @@ public:
// Calculates the inverse of the specified matrix.
static void Invert(const Double4x4& value, Double4x4& result);
// Creates a left-handed, look-at matrix.
static void LookAt(const Double3& eye, const Double3& target, const Double3& up, Double4x4& result);
// Calculates the product of two matrices.
static void Multiply(const Double4x4& left, const Double4x4& right, Double4x4& result);

View File

@@ -1001,6 +1001,37 @@ void Double4x4::Invert(const Double4x4& value, Double4x4& result)
result.M44 = +d44 * det;
}
void Double4x4::LookAt(const Double3& eye, const Double3& target, const Double3& up, Double4x4& result)
{
Double3 xaxis, yaxis, zaxis;
Double3::Subtract(target, eye, zaxis);
zaxis.Normalize();
Double3::Cross(up, zaxis, xaxis);
xaxis.Normalize();
Double3::Cross(zaxis, xaxis, yaxis);
result.M11 = xaxis.X;
result.M21 = xaxis.Y;
result.M31 = xaxis.Z;
result.M12 = yaxis.X;
result.M22 = yaxis.Y;
result.M32 = yaxis.Z;
result.M13 = zaxis.X;
result.M23 = zaxis.Y;
result.M33 = zaxis.Z;
result.M14 = 0.0f;
result.M24 = 0.0f;
result.M34 = 0.0f;
result.M41 = -Double3::Dot(xaxis, eye);
result.M42 = -Double3::Dot(yaxis, eye);
result.M43 = -Double3::Dot(zaxis, eye);
result.M44 = 1.0f;
}
void Double4x4::Multiply(const Double4x4& left, const Double4x4& right, Double4x4& result)
{
result.M11 = left.M11 * right.M11 + left.M12 * right.M21 + left.M13 * right.M31 + left.M14 * right.M41;

View File

@@ -1149,7 +1149,7 @@ namespace FlaxEngine
}
/// <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 vector from into vector to, around their plan perpendicular axis. The input vectors don't need to be normalized.
/// </summary>
/// <param name="from">The source vector.</param>
/// <param name="to">The destination vector.</param>
@@ -1179,7 +1179,7 @@ namespace FlaxEngine
}
/// <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>
/// <param name="from">The source vector.</param>
/// <param name="to">The destination vector.</param>

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

@@ -99,6 +99,7 @@ struct DebugGeometryBuffer
{
GPUBuffer* Buffer;
float TimeLeft;
bool Lines;
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
{
Array<DebugGeometryBuffer> GeometryBuffers;
@@ -302,6 +311,7 @@ struct DebugDrawData
void Teleport(const Float3& delta)
{
TeleportList(delta, GeometryBuffers);
TeleportList(delta, DefaultLines);
TeleportList(delta, OneFrameLines);
TeleportList(delta, DefaultTriangles);
@@ -810,6 +820,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
defaultWireTriangles = WriteLists(vertexCounter, Context->DebugDrawDefault.DefaultWireTriangles, Context->DebugDrawDefault.OneFrameWireTriangles);
{
PROFILE_CPU_NAMED("Flush");
ZoneValue(DebugDrawVB->Data.Count() / 1024); // Size in kB
DebugDrawVB->Flush(context);
}
}
@@ -869,8 +880,8 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
Matrix mvp;
Matrix::Multiply(geometry.Transform, vp, mvp);
Matrix::Transpose(mvp, tmp.ViewProjection);
auto state = data.EnableDepthTest ? (geometry.Lines ? &DebugDrawPsLinesDepthTest : &DebugDrawPsTrianglesDepthTest) : (geometry.Lines ? &DebugDrawPsLinesDefault : &DebugDrawPsTrianglesDefault);
context->UpdateCB(cb, &tmp);
auto state = data.EnableDepthTest ? &DebugDrawPsLinesDepthTest : &DebugDrawPsLinesDefault;
context->SetState(state->Get(enableDepthWrite, true));
context->BindVB(ToSpan(&geometry.Buffer, 1));
context->Draw(0, geometry.Buffer->GetElementsCount());
@@ -918,8 +929,9 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
Matrix mvp;
Matrix::Multiply(geometry.Transform, vp, mvp);
Matrix::Transpose(mvp, tmp.ViewProjection);
auto state = geometry.Lines ? &DebugDrawPsLinesDefault : &DebugDrawPsTrianglesDefault;
context->UpdateCB(cb, &tmp);
context->SetState(DebugDrawPsLinesDefault.Get(false, false));
context->SetState(state->Get(false, false));
context->BindVB(ToSpan(&geometry.Buffer, 1));
context->Draw(0, geometry.Buffer->GetElementsCount());
}
@@ -1164,6 +1176,7 @@ void DebugDraw::DrawLines(GPUBuffer* lines, const Matrix& transform, float durat
auto& geometry = debugDrawData.GeometryBuffers.AddOne();
geometry.Buffer = lines;
geometry.TimeLeft = duration;
geometry.Lines = true;
geometry.Transform = transform * Matrix::Translation(-Context->Origin);
}
@@ -1520,6 +1533,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)
{
DrawTriangles(Span<Float3>(vertices.Get(), vertices.Count()), color, duration, depthTest);

View File

@@ -74,7 +74,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
API_FUNCTION() static bool CanClear(void* context = nullptr);
#endif
// Gets the last view position when rendering the current context. Can be sued for custom culling or LODing when drawing more complex shapes.
// Gets the last view position when rendering the current context. Can be used for custom culling or LODing when drawing more complex shapes.
static Vector3 GetViewPos();
/// <summary>
@@ -296,12 +296,21 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
/// Draws the triangles.
/// </summary>
/// <param name="vertices">The triangle vertices list (must have multiple of 3 elements).</param>
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
/// <param name="color">The color.</param>
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
API_FUNCTION() static void DrawTriangles(const Span<Float3>& vertices, const Matrix& transform, const Color& color = Color::White, float duration = 0.0f, bool depthTest = true);
/// <summary>
/// Draws the triangles using the provided vertex buffer that contains groups of 3 Vertex elements per-triangle.
/// </summary>
/// <param name="triangles">The GPU buffer with vertices for triangles (must have multiple of 3 elements).</param>
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
API_FUNCTION() static void DrawTriangles(GPUBuffer* triangles, const Matrix& transform, float duration = 0.0f, bool depthTest = true);
/// <summary>
/// Draws the triangles.
/// </summary>
@@ -315,7 +324,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
/// Draws the triangles.
/// </summary>
/// <param name="vertices">The triangle vertices list (must have multiple of 3 elements).</param>
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
/// <param name="color">The color.</param>
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
@@ -336,7 +345,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
/// </summary>
/// <param name="vertices">The triangle vertices list.</param>
/// <param name="indices">The triangle indices list (must have multiple of 3 elements).</param>
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
/// <param name="color">The color.</param>
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
@@ -357,7 +366,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
/// </summary>
/// <param name="vertices">The triangle vertices list.</param>
/// <param name="indices">The triangle indices list (must have multiple of 3 elements).</param>
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
/// <param name="color">The color.</param>
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
@@ -376,7 +385,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
/// Draws the triangles.
/// </summary>
/// <param name="vertices">The triangle vertices list (must have multiple of 3 elements).</param>
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
/// <param name="color">The color.</param>
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
@@ -395,7 +404,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
/// Draws the triangles.
/// </summary>
/// <param name="vertices">The triangle vertices list (must have multiple of 3 elements).</param>
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
/// <param name="color">The color.</param>
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
@@ -416,7 +425,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
/// </summary>
/// <param name="vertices">The triangle vertices list.</param>
/// <param name="indices">The triangle indices list (must have multiple of 3 elements).</param>
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
/// <param name="color">The color.</param>
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
@@ -437,7 +446,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
/// </summary>
/// <param name="vertices">The triangle vertices list.</param>
/// <param name="indices">The triangle indices list (must have multiple of 3 elements).</param>
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
/// <param name="color">The color.</param>
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>

View File

@@ -443,6 +443,15 @@ bool Engine::IsEditor()
#endif
}
bool Engine::IsPlayMode()
{
#if USE_EDITOR
return Editor::IsPlayMode;
#else
return true;
#endif
}
int32 Engine::GetFramesPerSecond()
{
return EngineImpl::Fps;

View File

@@ -178,6 +178,11 @@ public:
/// </summary>
API_PROPERTY() static bool IsEditor();
/// <summary>
/// Returns whether the editor is in play mode or will always return true in a shipped applications.
/// </summary>
API_PROPERTY() static bool IsPlayMode();
/// <summary>
/// Gets the amount of frames rendered during last second known as Frames Per Second. User scripts updates or fixed updates for physics may run at a different frequency than scene rendering. Use this property to get an accurate amount of frames rendered during the last second.
/// </summary>

View File

@@ -37,6 +37,21 @@ DEFINE_ENGINE_SERVICE_EVENT(LateFixedUpdate);
DEFINE_ENGINE_SERVICE_EVENT(Draw);
DEFINE_ENGINE_SERVICE_EVENT_INVERTED(BeforeExit);
#if TRACY_ENABLE
StringView FillEventNameBuffer(Char* buffer, StringView name, StringView postfix)
{
int32 size = 0;
for (int32 j = 0; j < name.Length(); j++)
if (name[j] != ' ')
buffer[size++] = name[j];
Platform::MemoryCopy(buffer + size, postfix.Get(), (postfix.Length() + 1) * sizeof(Char));
size += postfix.Length();
return StringView(buffer, size);
}
#endif
EngineService::EngineServicesArray& EngineService::GetServices()
{
static EngineServicesArray Services;
@@ -78,14 +93,9 @@ void EngineService::OnInit()
const StringView name(service->Name);
#if TRACY_ENABLE
ZoneScoped;
int32 nameBufferLength = 0;
Char nameBuffer[100];
for (int32 j = 0; j < name.Length(); j++)
if (name[j] != ' ')
nameBuffer[nameBufferLength++] = name[j];
Platform::MemoryCopy(nameBuffer + nameBufferLength, TEXT("::Init"), 7 * sizeof(Char));
nameBufferLength += 7;
ZoneName(nameBuffer, nameBufferLength);
StringView zoneName = FillEventNameBuffer(nameBuffer, name, StringView(TEXT("::Init"), 6));
ZoneName(zoneName.Get(), zoneName.Length());
#endif
LOG(Info, "Initialize {0}...", name);
service->IsInitialized = true;
@@ -114,15 +124,10 @@ void EngineService::OnDispose()
{
#if TRACY_ENABLE
ZoneScoped;
const StringView name(service->Name);
int32 nameBufferLength = 0;
Char nameBuffer[100];
for (int32 j = 0; j < name.Length(); j++)
if (name[j] != ' ')
nameBuffer[nameBufferLength++] = name[j];
Platform::MemoryCopy(nameBuffer + nameBufferLength, TEXT("::Dispose"), 10 * sizeof(Char));
nameBufferLength += 10;
ZoneName(nameBuffer, nameBufferLength);
const StringView name(service->Name);
StringView zoneName = FillEventNameBuffer(nameBuffer, name, StringView(TEXT("::Dispose"), 9));
ZoneName(zoneName.Get(), zoneName.Length());
#endif
service->IsInitialized = false;
service->Dispose();

View File

@@ -67,6 +67,14 @@ public:
return _type;
}
/// <summary>
/// Gets work synchronization start point
/// </summary>
FORCE_INLINE GPUSyncPoint GetSyncStart() const
{
return _syncPoint;
}
/// <summary>
/// Gets work finish synchronization point
/// </summary>

View File

@@ -36,7 +36,7 @@ GPUTasksContext::~GPUTasksContext()
if (task->GetSyncPoint() <= _currentSyncPoint && task->GetState() != TaskState::Finished)
{
if (!Engine::IsRequestingExit)
LOG(Warning, "{0} has been canceled before a sync", task->ToString());
LOG(Warning, "'{0}' has been canceled before a sync", task->ToString());
task->CancelSync();
}
}
@@ -51,18 +51,15 @@ void GPUTasksContext::Run(GPUTask* task)
ASSERT(task != nullptr);
task->Execute(this);
if (task->IsSyncing())
//if (task->GetSyncStart() != 0)
_tasksSyncing.Add(task);
}
void GPUTasksContext::OnCancelSync(GPUTask* task)
{
ASSERT(task != nullptr);
_tasksSyncing.Remove(task);
if (!Engine::IsRequestingExit)
LOG(Warning, "{0} has been canceled before a sync", task->ToString());
LOG(Warning, "'{0}' has been canceled before a sync", task->ToString());
}
void GPUTasksContext::OnFrameBegin()

View File

@@ -18,7 +18,7 @@ protected:
CriticalSection _locker;
GPUSyncPoint _currentSyncPoint;
int32 _totalTasksDoneCount = 0;
Array<GPUTask*, InlinedAllocation<64>> _tasksSyncing;
Array<GPUTask*> _tasksSyncing;
public:
/// <summary>

View File

@@ -54,9 +54,9 @@ void GPUTask::OnCancel()
if (IsSyncing())
{
// Task has been performed but is waiting for a CPU/GPU sync so we have to cancel that
ASSERT(_context != nullptr);
_context->OnCancelSync(this);
_context = nullptr;
SetState(TaskState::Canceled);
}
// Base

View File

@@ -475,6 +475,12 @@ bool MeshBase::Init(uint32 vertices, uint32 triangles, const Array<const void*,
_collisionProxy.Init<uint32>(vertices, triangles, (const Float3*)vbData[0], (const uint32*)ibData);
#endif
// Free old buffers
SAFE_DELETE_GPU_RESOURCE(_vertexBuffers[0]);
SAFE_DELETE_GPU_RESOURCE(_vertexBuffers[1]);
SAFE_DELETE_GPU_RESOURCE(_vertexBuffers[2]);
SAFE_DELETE_GPU_RESOURCE(_indexBuffer);
// Initialize
_vertexBuffers[0] = vertexBuffer0;
_vertexBuffers[1] = vertexBuffer1;

View File

@@ -322,15 +322,17 @@ class StreamTextureMipTask : public GPUUploadTextureMipTask
{
private:
StreamingTexture* _streamingTexture;
Task* _rootTask;
FlaxStorage::LockData _dataLock;
public:
StreamTextureMipTask(StreamingTexture* texture, int32 mipIndex)
StreamTextureMipTask(StreamingTexture* texture, int32 mipIndex, Task* rootTask)
: GPUUploadTextureMipTask(texture->GetTexture(), mipIndex, Span<byte>(nullptr, 0), 0, 0, false)
, _streamingTexture(texture)
, _rootTask(rootTask ? rootTask : this)
, _dataLock(_streamingTexture->GetOwner()->LockData())
{
_streamingTexture->_streamingTasks.Add(this);
_streamingTexture->_streamingTasks.Add(_rootTask);
_texture.Released.Bind<StreamTextureMipTask, &StreamTextureMipTask::OnResourceReleased2>(this);
}
@@ -341,7 +343,7 @@ private:
if (_streamingTexture)
{
ScopeLock lock(_streamingTexture->GetOwner()->GetOwnerLocker());
_streamingTexture->_streamingTasks.Remove(this);
_streamingTexture->_streamingTasks.Remove(_rootTask);
_streamingTexture = nullptr;
}
}
@@ -393,7 +395,7 @@ protected:
if (_streamingTexture)
{
ScopeLock lock(_streamingTexture->GetOwner()->GetOwnerLocker());
_streamingTexture->_streamingTasks.Remove(this);
_streamingTexture->_streamingTasks.Remove(_rootTask);
_streamingTexture = nullptr;
}
@@ -443,7 +445,7 @@ Task* StreamingTexture::CreateStreamingTask(int32 residency)
// Add upload data task
const int32 allocatedMipIndex = TotalIndexToTextureMipIndex(mipIndex);
task = New<StreamTextureMipTask>(this, allocatedMipIndex);
task = New<StreamTextureMipTask>(this, allocatedMipIndex, result);
if (result)
result->ContinueWith(task);
else

View File

@@ -766,7 +766,7 @@ void AnimatedModel::UpdateBounds()
// Apply margin based on model dimensions
const Vector3 modelBoxSize = modelBox.GetSize();
const Vector3 center = box.GetCenter();
const Vector3 sizeHalf = Vector3::Max(box.GetSize() + modelBoxSize * 0.2f, modelBoxSize) * 0.5f;
const Vector3 sizeHalf = Vector3::Max(box.GetSize() + modelBoxSize * 0.2f, modelBoxSize) * (0.5f * BoundsScale);
_box = BoundingBox(center - sizeHalf, center + sizeHalf);
}
else

View File

@@ -96,7 +96,7 @@ public:
bool PerBoneMotionBlur = true;
/// <summary>
/// If true, animation speed will be affected by the global time scale parameter.
/// If true, animation speed will be affected by the global timescale parameter.
/// </summary>
API_FIELD(Attributes="EditorOrder(30), DefaultValue(true), EditorDisplay(\"Skinned Model\")")
bool UseTimeScale = true;
@@ -108,7 +108,7 @@ public:
bool UpdateWhenOffscreen = false;
/// <summary>
/// The animation update delta time scale. Can be used to speed up animation playback or create slow motion effect.
/// The animation update delta timescale. Can be used to speed up animation playback or create slow motion effect.
/// </summary>
API_FIELD(Attributes="EditorOrder(45), EditorDisplay(\"Skinned Model\")")
float UpdateSpeed = 1.0f;
@@ -120,7 +120,7 @@ public:
AnimationUpdateMode UpdateMode = AnimationUpdateMode::Auto;
/// <summary>
/// The master scale parameter for the actor bounding box. Helps reducing mesh flickering effect on screen edges.
/// The master scale parameter for the actor bounding box. Helps to reduce mesh flickering effect on screen edges.
/// </summary>
API_FIELD(Attributes="EditorOrder(60), DefaultValue(1.5f), Limit(0), EditorDisplay(\"Skinned Model\")")
float BoundsScale = 1.5f;
@@ -388,7 +388,7 @@ public:
API_FUNCTION() void PauseSlotAnimation(const StringView& slotName, Animation* anim);
/// <summary>
/// Checks if the any animation playback is active on the any slot in Anim Graph (not paused).
/// Checks if any animation playback is active on any slot in Anim Graph (not paused).
/// </summary>
API_FUNCTION() bool IsPlayingSlotAnimation();

View File

@@ -3,6 +3,7 @@
#include "Camera.h"
#include "Engine/Level/SceneObjectsFactory.h"
#include "Engine/Core/Math/Matrix.h"
#include "Engine/Core/Math/Double4x4.h"
#include "Engine/Core/Math/Viewport.h"
#include "Engine/Content/Assets/Model.h"
#include "Engine/Content/Content.h"
@@ -238,7 +239,7 @@ Ray Camera::ConvertMouseToRay(const Float2& mousePosition, const Viewport& viewp
viewport.Unproject(farPoint, ivp, farPoint);
Vector3 dir = Vector3::Normalize(farPoint - nearPoint);
if (dir.IsZero())
if (dir.IsZero() || dir.IsNanOrInfinity())
return Ray::Identity;
return Ray(nearPoint, dir);
}
@@ -302,12 +303,15 @@ void Camera::GetMatrices(Matrix& view, Matrix& projection, const Viewport& viewp
}
// Create view matrix
const Float3 direction = GetDirection();
const Float3 position = _transform.Translation - origin;
const Float3 target = position + direction;
Float3 up;
Float3::Transform(Float3::Up, GetOrientation(), up);
Matrix::LookAt(position, target, up, view);
const Vector3 direction = Vector3::Transform(Vector3::Forward, GetOrientation());
const Vector3 position = _transform.Translation - origin;
const Vector3 target = position + direction;
Vector3 up;
Vector3::Transform(Vector3::Up, GetOrientation(), up);
Real4x4 viewResult;
Real4x4::LookAt(position, target, up, viewResult);
view = Matrix(viewResult);
}
#if USE_EDITOR

View File

@@ -0,0 +1,22 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEngine.Json;
namespace FlaxEngine
{
partial class ModelInstanceActor
{
partial struct MeshReference : ICustomValueEquals
{
/// <inheritdoc />
public bool ValueEquals(object other)
{
var o = (MeshReference)other;
return JsonSerializer.ValueEquals(Actor, o.Actor) &&
LODIndex == o.LODIndex &&
MeshIndex == o.MeshIndex;
}
}
}
}

View File

@@ -1090,7 +1090,7 @@ bool Prefab::ApplyAllInternal(Actor* targetActor, bool linkTargetActorObjectToPr
root = dynamic_cast<Actor*>(sceneObjects.Value->At(targetActorIdx));
}
// Try using the first actor without a parent as a new ro0t
// Try using the first actor without a parent as a new root
for (int32 i = 1; i < sceneObjects->Count(); i++)
{
SceneObject* obj = sceneObjects.Value->At(i);

View File

@@ -223,7 +223,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
#endif
}
#endif
ASSERT(!isnan(sphere.Radius) && !isinf(sphere.Radius) && !sphere.Center.IsNanOrInfinity());
CHECK_RETURN(!isnan(sphere.Radius) && !isinf(sphere.Radius) && !sphere.Center.IsNanOrInfinity(), false);
// Expand sphere based on the render modules rules (sprite or mesh size)
for (int32 moduleIndex = 0; moduleIndex < emitter->Graph.RenderModules.Count(); moduleIndex++)
@@ -244,7 +244,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
Vector2::Max(*((Vector2*)spriteSize), maxSpriteSize, maxSpriteSize);
spriteSize += stride;
}
ASSERT(!maxSpriteSize.IsNanOrInfinity());
CHECK_RETURN(!maxSpriteSize.IsNanOrInfinity(), false);
// Enlarge the emitter bounds sphere
sphere.Radius += maxSpriteSize.MaxValue();
@@ -267,7 +267,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
if (radius > maxRadius)
maxRadius = radius;
}
ASSERT(!isnan(maxRadius) && !isinf(maxRadius));
CHECK_RETURN(!isnan(maxRadius) && !isinf(maxRadius), false);
// Enlarge the emitter bounds sphere
sphere.Radius += maxRadius;
@@ -315,7 +315,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
maxRibbonWidth = Math::Max(*((float*)ribbonWidth), maxRibbonWidth);
ribbonWidth += stride;
}
ASSERT(!isnan(maxRibbonWidth) && !isinf(maxRibbonWidth));
CHECK_RETURN(!isnan(maxRibbonWidth) && !isinf(maxRibbonWidth), false);
// Enlarge the emitter bounds sphere
sphere.Radius += maxRibbonWidth * 0.5f;
@@ -335,7 +335,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
maxRadius = Math::Max(*((float*)radius), maxRadius);
radius += stride;
}
ASSERT(!isnan(maxRadius) && !isinf(maxRadius));
CHECK_RETURN(!isnan(maxRadius) && !isinf(maxRadius), false);
}
else
{

View File

@@ -335,6 +335,7 @@ void Cloth::DrawPhysicsDebug(RenderView& view)
#if WITH_CLOTH && COMPILE_WITH_DEBUG_DRAW
if (_cloth)
{
PROFILE_CPU();
const ModelInstanceActor::MeshReference mesh = GetMesh();
if (mesh.Actor == nullptr)
return;

View File

@@ -59,7 +59,7 @@ API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings", NoConstructor) class
public:
/// <summary>
/// The default gravity force value (in cm^2/s).
/// The default gravity value (in cm/(s^2)).
/// </summary>
API_FIELD(Attributes="EditorOrder(0), EditorDisplay(\"Simulation\")")
Vector3 DefaultGravity = Vector3(0, -981.0f, 0);

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