Merge remote-tracking branch 'origin/master' into 1.11
This commit is contained in:
BIN
Content/Shaders/Editor/Grid.flax
(Stored with Git LFS)
BIN
Content/Shaders/Editor/Grid.flax
(Stored with Git LFS)
Binary file not shown.
@@ -1,6 +1,5 @@
|
|||||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FlaxEditor.Content.Settings;
|
using FlaxEditor.Content.Settings;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
@@ -16,6 +15,11 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
{
|
{
|
||||||
private int _layersCount;
|
private int _layersCount;
|
||||||
private List<CheckBox> _checkBoxes;
|
private List<CheckBox> _checkBoxes;
|
||||||
|
private VerticalPanel _upperRightCell;
|
||||||
|
private VerticalPanel _bottomLeftCell;
|
||||||
|
private UniformGridPanel _grid;
|
||||||
|
private Border _horizontalHighlight;
|
||||||
|
private Border _verticalHighlight;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override DisplayStyle Style => DisplayStyle.InlineIntoParent;
|
public override DisplayStyle Style => DisplayStyle.InlineIntoParent;
|
||||||
@@ -37,12 +41,29 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
Parent = panel,
|
Parent = panel,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var style = FlaxEngine.GUI.Style.Current;
|
||||||
|
_horizontalHighlight = new Border()
|
||||||
|
{
|
||||||
|
Parent = panel,
|
||||||
|
BorderColor = style.Foreground,
|
||||||
|
BorderWidth = 1.0f,
|
||||||
|
Visible = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
_verticalHighlight = new Border()
|
||||||
|
{
|
||||||
|
Parent = panel,
|
||||||
|
BorderColor = style.Foreground,
|
||||||
|
BorderWidth = 1.0f,
|
||||||
|
Visible = false,
|
||||||
|
};
|
||||||
|
|
||||||
var upperLeftCell = new Label
|
var upperLeftCell = new Label
|
||||||
{
|
{
|
||||||
Parent = gridPanel,
|
Parent = gridPanel,
|
||||||
};
|
};
|
||||||
|
|
||||||
var upperRightCell = new VerticalPanel
|
_upperRightCell = new VerticalPanel
|
||||||
{
|
{
|
||||||
ClipChildren = false,
|
ClipChildren = false,
|
||||||
Pivot = new Float2(0.00001f, 0.0f),
|
Pivot = new Float2(0.00001f, 0.0f),
|
||||||
@@ -54,7 +75,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
Parent = gridPanel,
|
Parent = gridPanel,
|
||||||
};
|
};
|
||||||
|
|
||||||
var bottomLeftCell = new VerticalPanel
|
_bottomLeftCell = new VerticalPanel
|
||||||
{
|
{
|
||||||
Pivot = Float2.Zero,
|
Pivot = Float2.Zero,
|
||||||
Spacing = 0,
|
Spacing = 0,
|
||||||
@@ -63,7 +84,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
Parent = gridPanel,
|
Parent = gridPanel,
|
||||||
};
|
};
|
||||||
|
|
||||||
var grid = new UniformGridPanel(0)
|
_grid = new UniformGridPanel(0)
|
||||||
{
|
{
|
||||||
SlotsHorizontally = layersCount,
|
SlotsHorizontally = layersCount,
|
||||||
SlotsVertically = layersCount,
|
SlotsVertically = layersCount,
|
||||||
@@ -74,13 +95,13 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
int layerIndex = 0;
|
int layerIndex = 0;
|
||||||
for (; layerIndex < layerNames.Length; layerIndex++)
|
for (; layerIndex < layerNames.Length; layerIndex++)
|
||||||
{
|
{
|
||||||
upperRightCell.AddChild(new Label
|
_upperRightCell.AddChild(new Label
|
||||||
{
|
{
|
||||||
Height = labelsHeight,
|
Height = labelsHeight,
|
||||||
Text = layerNames[layerNames.Length - layerIndex - 1],
|
Text = layerNames[layerNames.Length - layerIndex - 1],
|
||||||
HorizontalAlignment = TextAlignment.Near,
|
HorizontalAlignment = TextAlignment.Near,
|
||||||
});
|
});
|
||||||
bottomLeftCell.AddChild(new Label
|
_bottomLeftCell.AddChild(new Label
|
||||||
{
|
{
|
||||||
Height = labelsHeight,
|
Height = labelsHeight,
|
||||||
Text = layerNames[layerIndex],
|
Text = layerNames[layerIndex],
|
||||||
@@ -90,13 +111,13 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
for (; layerIndex < layersCount; layerIndex++)
|
for (; layerIndex < layersCount; layerIndex++)
|
||||||
{
|
{
|
||||||
string name = "Layer " + layerIndex;
|
string name = "Layer " + layerIndex;
|
||||||
upperRightCell.AddChild(new Label
|
_upperRightCell.AddChild(new Label
|
||||||
{
|
{
|
||||||
Height = labelsHeight,
|
Height = labelsHeight,
|
||||||
Text = name,
|
Text = name,
|
||||||
HorizontalAlignment = TextAlignment.Near,
|
HorizontalAlignment = TextAlignment.Near,
|
||||||
});
|
});
|
||||||
bottomLeftCell.AddChild(new Label
|
_bottomLeftCell.AddChild(new Label
|
||||||
{
|
{
|
||||||
Height = labelsHeight,
|
Height = labelsHeight,
|
||||||
Text = name,
|
Text = name,
|
||||||
@@ -118,7 +139,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
var box = new CheckBox(0, 0, true)
|
var box = new CheckBox(0, 0, true)
|
||||||
{
|
{
|
||||||
Tag = new Float2(_layersCount - column - 1, row),
|
Tag = new Float2(_layersCount - column - 1, row),
|
||||||
Parent = grid,
|
Parent = _grid,
|
||||||
Checked = GetBit(column, row),
|
Checked = GetBit(column, row),
|
||||||
};
|
};
|
||||||
box.StateChanged += OnCheckBoxChanged;
|
box.StateChanged += OnCheckBoxChanged;
|
||||||
@@ -126,7 +147,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
}
|
}
|
||||||
for (; column < layersCount; column++)
|
for (; column < layersCount; column++)
|
||||||
{
|
{
|
||||||
grid.AddChild(new Label());
|
_grid.AddChild(new Label());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,6 +162,18 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Refresh()
|
public override void Refresh()
|
||||||
{
|
{
|
||||||
|
int selectedColumn = -1;
|
||||||
|
int selectedRow = -1;
|
||||||
|
var style = FlaxEngine.GUI.Style.Current;
|
||||||
|
bool mouseOverGrid = _grid.IsMouseOver;
|
||||||
|
|
||||||
|
// Only hide highlights if mouse is not over the grid to reduce flickering
|
||||||
|
if (!mouseOverGrid)
|
||||||
|
{
|
||||||
|
_horizontalHighlight.Visible = false;
|
||||||
|
_verticalHighlight.Visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Sync check boxes
|
// Sync check boxes
|
||||||
for (int i = 0; i < _checkBoxes.Count; i++)
|
for (int i = 0; i < _checkBoxes.Count; i++)
|
||||||
{
|
{
|
||||||
@@ -148,6 +181,39 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
int column = (int)((Float2)box.Tag).X;
|
int column = (int)((Float2)box.Tag).X;
|
||||||
int row = (int)((Float2)box.Tag).Y;
|
int row = (int)((Float2)box.Tag).Y;
|
||||||
box.Checked = GetBit(column, row);
|
box.Checked = GetBit(column, row);
|
||||||
|
|
||||||
|
if (box.IsMouseOver)
|
||||||
|
{
|
||||||
|
selectedColumn = column;
|
||||||
|
selectedRow = row;
|
||||||
|
|
||||||
|
_horizontalHighlight.X = _grid.X - _bottomLeftCell.Width;
|
||||||
|
_horizontalHighlight.Y = _grid.Y + box.Y;
|
||||||
|
_horizontalHighlight.Width = _bottomLeftCell.Width + box.Width + box.X;
|
||||||
|
_horizontalHighlight.Height = box.Height;
|
||||||
|
_horizontalHighlight.Visible = true;
|
||||||
|
|
||||||
|
_verticalHighlight.X = _grid.X + box.X;
|
||||||
|
_verticalHighlight.Y = _grid.Y - _upperRightCell.Height;
|
||||||
|
_verticalHighlight.Width = box.Width;
|
||||||
|
_verticalHighlight.Height = _upperRightCell.Height + box.Height + box.Y;
|
||||||
|
_verticalHighlight.Visible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < _checkBoxes.Count; i++)
|
||||||
|
{
|
||||||
|
var box = _checkBoxes[i];
|
||||||
|
int column = (int)((Float2)box.Tag).X;
|
||||||
|
int row = (int)((Float2)box.Tag).Y;
|
||||||
|
|
||||||
|
if (!mouseOverGrid)
|
||||||
|
box.ImageColor = style.BorderSelected;
|
||||||
|
else if (selectedColumn > -1 && selectedRow > -1)
|
||||||
|
{
|
||||||
|
bool isRowOrColumn = column == selectedColumn || row == selectedRow;
|
||||||
|
box.ImageColor = style.BorderSelected * (isRowOrColumn ? 1.2f : 0.75f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -670,6 +670,8 @@ namespace FlaxEditor
|
|||||||
{
|
{
|
||||||
FlaxEngine.Networking.NetworkManager.Stop(); // Shutdown any multiplayer from playmode
|
FlaxEngine.Networking.NetworkManager.Stop(); // Shutdown any multiplayer from playmode
|
||||||
PlayModeEnding?.Invoke();
|
PlayModeEnding?.Invoke();
|
||||||
|
for (int i = 0; i < _modules.Count; i++)
|
||||||
|
_modules[i].OnPlayEnding();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnPlayEnd()
|
internal void OnPlayEnd()
|
||||||
|
|||||||
@@ -299,6 +299,7 @@ namespace FlaxEditor.GUI
|
|||||||
{
|
{
|
||||||
// Select asset
|
// Select asset
|
||||||
Editor.Instance.Windows.ContentWin.Select(Validator.SelectedItem);
|
Editor.Instance.Windows.ContentWin.Select(Validator.SelectedItem);
|
||||||
|
Editor.Instance.Windows.ContentWin.ClearItemsSearch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Button1Rect.Contains(location))
|
else if (Button1Rect.Contains(location))
|
||||||
@@ -312,6 +313,7 @@ namespace FlaxEditor.GUI
|
|||||||
{
|
{
|
||||||
// Select asset
|
// Select asset
|
||||||
Editor.Instance.Windows.ContentWin.Select(Validator.SelectedItem);
|
Editor.Instance.Windows.ContentWin.Select(Validator.SelectedItem);
|
||||||
|
Editor.Instance.Windows.ContentWin.ClearItemsSearch();
|
||||||
}
|
}
|
||||||
else if (Button3Rect.Contains(location))
|
else if (Button3Rect.Contains(location))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -563,8 +563,17 @@ namespace FlaxEditor.GUI
|
|||||||
case KeyboardKeys.Escape:
|
case KeyboardKeys.Escape:
|
||||||
Hide();
|
Hide();
|
||||||
return true;
|
return true;
|
||||||
|
case KeyboardKeys.Backspace:
|
||||||
|
// Alow the user to quickly focus the searchbar
|
||||||
|
if (_searchBox != null && !_searchBox.IsFocused)
|
||||||
|
{
|
||||||
|
_searchBox.Focus();
|
||||||
|
_searchBox.SelectAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case KeyboardKeys.ArrowDown:
|
case KeyboardKeys.ArrowDown:
|
||||||
{
|
case KeyboardKeys.ArrowUp:
|
||||||
if (RootWindow.FocusedControl == null)
|
if (RootWindow.FocusedControl == null)
|
||||||
{
|
{
|
||||||
// Focus search box if nothing is focused
|
// Focus search box if nothing is focused
|
||||||
@@ -572,39 +581,17 @@ namespace FlaxEditor.GUI
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Focus the first visible item or then next one
|
// Get the next item
|
||||||
var items = GetVisibleItems();
|
var items = GetVisibleItems();
|
||||||
var focusedIndex = items.IndexOf(focusedItem);
|
var focusedIndex = items.IndexOf(focusedItem);
|
||||||
if (focusedIndex == -1)
|
int delta = key == KeyboardKeys.ArrowDown ? -1 : 1;
|
||||||
focusedIndex = -1;
|
int nextIndex = Mathf.Wrap(focusedIndex - delta, 0, items.Count - 1);
|
||||||
if (focusedIndex + 1 < items.Count)
|
var nextItem = items[nextIndex];
|
||||||
{
|
|
||||||
var item = items[focusedIndex + 1];
|
// Focus the next item
|
||||||
item.Focus();
|
nextItem.Focus();
|
||||||
_scrollPanel.ScrollViewTo(item);
|
_scrollPanel.ScrollViewTo(nextItem);
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KeyboardKeys.ArrowUp:
|
|
||||||
if (focusedItem != null)
|
|
||||||
{
|
|
||||||
// Focus the previous visible item or the search box
|
|
||||||
var items = GetVisibleItems();
|
|
||||||
var focusedIndex = items.IndexOf(focusedItem);
|
|
||||||
if (focusedIndex == 0)
|
|
||||||
{
|
|
||||||
_searchBox?.Focus();
|
|
||||||
}
|
|
||||||
else if (focusedIndex > 0)
|
|
||||||
{
|
|
||||||
var item = items[focusedIndex - 1];
|
|
||||||
item.Focus();
|
|
||||||
_scrollPanel.ScrollViewTo(item);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KeyboardKeys.Return:
|
case KeyboardKeys.Return:
|
||||||
if (focusedItem != null)
|
if (focusedItem != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -266,6 +266,19 @@ namespace FlaxEditor.GUI
|
|||||||
return AddChild(new MainMenuButton(text));
|
return AddChild(new MainMenuButton(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or adds a button.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The button text</param>
|
||||||
|
/// <returns>The existing or created button control.</returns>
|
||||||
|
public MainMenuButton GetOrAddButton(string text)
|
||||||
|
{
|
||||||
|
MainMenuButton result = GetButton(text);
|
||||||
|
if (result == null)
|
||||||
|
result = AddButton(text);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the button.
|
/// Gets the button.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -122,6 +122,14 @@ namespace FlaxEditor.GUI
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnClicked()
|
||||||
|
{
|
||||||
|
if (AutoCheck)
|
||||||
|
Checked = !Checked;
|
||||||
|
Clicked?.Invoke();
|
||||||
|
(Parent as ToolStrip)?.OnButtonClicked(this);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Draw()
|
public override void Draw()
|
||||||
{
|
{
|
||||||
@@ -196,11 +204,7 @@ namespace FlaxEditor.GUI
|
|||||||
if (button == MouseButton.Left && _primaryMouseDown)
|
if (button == MouseButton.Left && _primaryMouseDown)
|
||||||
{
|
{
|
||||||
_primaryMouseDown = false;
|
_primaryMouseDown = false;
|
||||||
if (AutoCheck)
|
OnClicked();
|
||||||
Checked = !Checked;
|
|
||||||
Clicked?.Invoke();
|
|
||||||
(Parent as ToolStrip)?.OnButtonClicked(this);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (button == MouseButton.Right && _secondaryMouseDown)
|
if (button == MouseButton.Right && _secondaryMouseDown)
|
||||||
@@ -215,6 +219,18 @@ namespace FlaxEditor.GUI
|
|||||||
return base.OnMouseUp(location, button);
|
return base.OnMouseUp(location, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
|
||||||
|
{
|
||||||
|
if (button == MouseButton.Left)
|
||||||
|
{
|
||||||
|
OnClicked();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnMouseLeave()
|
public override void OnMouseLeave()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ namespace FlaxEditor.GUI.Tree
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool DrawRootTreeLine = true;
|
public bool DrawRootTreeLine = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when the deferred layout operation was performed.
|
||||||
|
/// </summary>
|
||||||
|
public event Action AfterDeferredLayout;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the margin for the child tree nodes.
|
/// Gets or sets the margin for the child tree nodes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -375,6 +380,7 @@ namespace FlaxEditor.GUI.Tree
|
|||||||
if (_deferLayoutUpdate)
|
if (_deferLayoutUpdate)
|
||||||
{
|
{
|
||||||
base.PerformLayout();
|
base.PerformLayout();
|
||||||
|
AfterDeferredLayout?.Invoke();
|
||||||
_deferLayoutUpdate = false;
|
_deferLayoutUpdate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,13 @@ namespace FlaxEditor.Modules
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when Editor will leave the play mode.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void OnPlayEnding()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when Editor leaves the play mode.
|
/// Called when Editor leaves the play mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1223,6 +1223,13 @@ namespace FlaxEditor.Modules
|
|||||||
Windows[i].OnPlayBegin();
|
Windows[i].OnPlayBegin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnPlayEnding()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Windows.Count; i++)
|
||||||
|
Windows[i].OnPlayEnding();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnPlayEnd()
|
public override void OnPlayEnd()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -139,6 +139,10 @@ namespace FlaxEditor.Options
|
|||||||
[EditorDisplay("Common"), EditorOrder(240)]
|
[EditorDisplay("Common"), EditorOrder(240)]
|
||||||
public InputBinding ToggleFullscreen = new InputBinding(KeyboardKeys.F11);
|
public InputBinding ToggleFullscreen = new InputBinding(KeyboardKeys.F11);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "Ctrl+BackQuote")]
|
||||||
|
[EditorDisplay("Common"), EditorOrder(250)]
|
||||||
|
public InputBinding FocusConsoleCommand = new InputBinding(KeyboardKeys.BackQuote, KeyboardKeys.Control);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region File
|
#region File
|
||||||
@@ -647,5 +651,45 @@ namespace FlaxEditor.Options
|
|||||||
public InputBinding VisualScriptDebuggerWindow = new InputBinding(KeyboardKeys.None);
|
public InputBinding VisualScriptDebuggerWindow = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Node editors
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "Shift+W")]
|
||||||
|
[EditorDisplay("Node editors"), EditorOrder(4500)]
|
||||||
|
public InputBinding NodesAlignTop = new InputBinding(KeyboardKeys.W, KeyboardKeys.Shift);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "Shift+A")]
|
||||||
|
[EditorDisplay("Node editors"), EditorOrder(4510)]
|
||||||
|
public InputBinding NodesAlignLeft = new InputBinding(KeyboardKeys.A, KeyboardKeys.Shift);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "Shift+S")]
|
||||||
|
[EditorDisplay("Node editors"), EditorOrder(4520)]
|
||||||
|
public InputBinding NodesAlignBottom = new InputBinding(KeyboardKeys.S, KeyboardKeys.Shift);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "Shift+D")]
|
||||||
|
[EditorDisplay("Node editors"), EditorOrder(4530)]
|
||||||
|
public InputBinding NodesAlignRight = new InputBinding(KeyboardKeys.D, KeyboardKeys.Shift);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "Alt+Shift+W")]
|
||||||
|
[EditorDisplay("Node editors"), EditorOrder(4540)]
|
||||||
|
public InputBinding NodesAlignMiddle = new InputBinding(KeyboardKeys.W, KeyboardKeys.Shift, KeyboardKeys.Alt);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "Alt+Shift+S")]
|
||||||
|
[EditorDisplay("Node editors"), EditorOrder(4550)]
|
||||||
|
public InputBinding NodesAlignCenter = new InputBinding(KeyboardKeys.S, KeyboardKeys.Shift, KeyboardKeys.Alt);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "Q")]
|
||||||
|
[EditorDisplay("Node editors"), EditorOrder(4560)]
|
||||||
|
public InputBinding NodesAutoFormat = new InputBinding(KeyboardKeys.Q);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Node editors"), EditorOrder(4570)]
|
||||||
|
public InputBinding NodesDistributeHorizontal = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Node editors"), EditorOrder(4580)]
|
||||||
|
public InputBinding NodesDistributeVertical = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
43
Source/Editor/Surface/NodeAlignmentType.cs
Normal file
43
Source/Editor/Surface/NodeAlignmentType.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using FlaxEngine;
|
||||||
|
|
||||||
|
namespace FlaxEditor.Surface
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Node Alignment type
|
||||||
|
/// </summary>
|
||||||
|
[HideInEditor]
|
||||||
|
public enum NodeAlignmentType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Align nodes vertically to top, matching top-most node
|
||||||
|
/// </summary>
|
||||||
|
Top,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Align nodes vertically to middle, using average of all nodes
|
||||||
|
/// </summary>
|
||||||
|
Middle,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Align nodes vertically to bottom, matching bottom-most node
|
||||||
|
/// </summary>
|
||||||
|
Bottom,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Align nodes horizontally to left, matching left-most node
|
||||||
|
/// </summary>
|
||||||
|
Left,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Align nodes horizontally to center, using average of all nodes
|
||||||
|
/// </summary>
|
||||||
|
Center,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Align nodes horizontally to right, matching right-most node
|
||||||
|
/// </summary>
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -912,7 +912,7 @@ namespace FlaxEditor.Surface
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool OnTestTooltipOverControl(ref Float2 location)
|
public override bool OnTestTooltipOverControl(ref Float2 location)
|
||||||
{
|
{
|
||||||
return _headerRect.Contains(ref location) && ShowTooltip;
|
return _headerRect.Contains(ref location) && ShowTooltip && !Surface.IsConnecting && !Surface.IsBoxSelecting;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -1070,7 +1070,7 @@ namespace FlaxEditor.Surface
|
|||||||
|
|
||||||
// Header
|
// Header
|
||||||
var headerColor = style.BackgroundHighlighted;
|
var headerColor = style.BackgroundHighlighted;
|
||||||
if (_headerRect.Contains(ref _mousePosition))
|
if (_headerRect.Contains(ref _mousePosition) && !Surface.IsConnecting && !Surface.IsBoxSelecting)
|
||||||
headerColor *= 1.07f;
|
headerColor *= 1.07f;
|
||||||
Render2D.FillRectangle(_headerRect, headerColor);
|
Render2D.FillRectangle(_headerRect, headerColor);
|
||||||
Render2D.DrawText(style.FontLarge, Title, _headerRect, style.Foreground, TextAlignment.Center, TextAlignment.Center);
|
Render2D.DrawText(style.FontLarge, Title, _headerRect, style.Foreground, TextAlignment.Center, TextAlignment.Center);
|
||||||
@@ -1078,7 +1078,8 @@ namespace FlaxEditor.Surface
|
|||||||
// Close button
|
// Close button
|
||||||
if ((Archetype.Flags & NodeFlags.NoCloseButton) == 0 && Surface.CanEdit)
|
if ((Archetype.Flags & NodeFlags.NoCloseButton) == 0 && Surface.CanEdit)
|
||||||
{
|
{
|
||||||
Render2D.DrawSprite(style.Cross, _closeButtonRect, _closeButtonRect.Contains(_mousePosition) ? style.Foreground : style.ForegroundGrey);
|
bool highlightClose = _closeButtonRect.Contains(_mousePosition) && !Surface.IsConnecting && !Surface.IsBoxSelecting;
|
||||||
|
Render2D.DrawSprite(style.Cross, _closeButtonRect, highlightClose ? style.Foreground : style.ForegroundGrey);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Footer
|
// Footer
|
||||||
@@ -1123,8 +1124,9 @@ namespace FlaxEditor.Surface
|
|||||||
if (base.OnMouseUp(location, button))
|
if (base.OnMouseUp(location, button))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Close
|
// Close/ delete
|
||||||
if (button == MouseButton.Left && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location))
|
bool canDelete = !Surface.IsConnecting && !Surface.WasBoxSelecting && !Surface.WasMovingSelection;
|
||||||
|
if (button == MouseButton.Left && canDelete && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location))
|
||||||
{
|
{
|
||||||
Surface.Delete(this);
|
Surface.Delete(this);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -191,7 +191,16 @@ namespace FlaxEditor.Surface
|
|||||||
|
|
||||||
private ContextMenuButton _cmCopyButton;
|
private ContextMenuButton _cmCopyButton;
|
||||||
private ContextMenuButton _cmDuplicateButton;
|
private ContextMenuButton _cmDuplicateButton;
|
||||||
|
private ContextMenuChildMenu _cmFormatNodesMenu;
|
||||||
private ContextMenuButton _cmFormatNodesConnectionButton;
|
private ContextMenuButton _cmFormatNodesConnectionButton;
|
||||||
|
private ContextMenuButton _cmAlignNodesTopButton;
|
||||||
|
private ContextMenuButton _cmAlignNodesMiddleButton;
|
||||||
|
private ContextMenuButton _cmAlignNodesBottomButton;
|
||||||
|
private ContextMenuButton _cmAlignNodesLeftButton;
|
||||||
|
private ContextMenuButton _cmAlignNodesCenterButton;
|
||||||
|
private ContextMenuButton _cmAlignNodesRightButton;
|
||||||
|
private ContextMenuButton _cmDistributeNodesHorizontallyButton;
|
||||||
|
private ContextMenuButton _cmDistributeNodesVerticallyButton;
|
||||||
private ContextMenuButton _cmRemoveNodeConnectionsButton;
|
private ContextMenuButton _cmRemoveNodeConnectionsButton;
|
||||||
private ContextMenuButton _cmRemoveBoxConnectionsButton;
|
private ContextMenuButton _cmRemoveBoxConnectionsButton;
|
||||||
private readonly Float2 ContextMenuOffset = new Float2(5);
|
private readonly Float2 ContextMenuOffset = new Float2(5);
|
||||||
@@ -399,8 +408,24 @@ namespace FlaxEditor.Surface
|
|||||||
}
|
}
|
||||||
menu.AddSeparator();
|
menu.AddSeparator();
|
||||||
|
|
||||||
_cmFormatNodesConnectionButton = menu.AddButton("Format node(s)", () => { FormatGraph(SelectedNodes); });
|
_cmFormatNodesMenu = menu.AddChildMenu("Format node(s)");
|
||||||
_cmFormatNodesConnectionButton.Enabled = CanEdit && HasNodesSelection;
|
_cmFormatNodesMenu.Enabled = CanEdit && HasNodesSelection;
|
||||||
|
|
||||||
|
_cmFormatNodesConnectionButton = _cmFormatNodesMenu.ContextMenu.AddButton("Auto format", Editor.Instance.Options.Options.Input.NodesAutoFormat, () => { FormatGraph(SelectedNodes); });
|
||||||
|
|
||||||
|
_cmFormatNodesMenu.ContextMenu.AddSeparator();
|
||||||
|
_cmAlignNodesTopButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align top", Editor.Instance.Options.Options.Input.NodesAlignTop, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Top); });
|
||||||
|
_cmAlignNodesMiddleButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align middle", Editor.Instance.Options.Options.Input.NodesAlignMiddle, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Middle); });
|
||||||
|
_cmAlignNodesBottomButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align bottom", Editor.Instance.Options.Options.Input.NodesAlignBottom, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Bottom); });
|
||||||
|
|
||||||
|
_cmFormatNodesMenu.ContextMenu.AddSeparator();
|
||||||
|
_cmAlignNodesLeftButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align left", Editor.Instance.Options.Options.Input.NodesAlignLeft, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Left); });
|
||||||
|
_cmAlignNodesCenterButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align center", Editor.Instance.Options.Options.Input.NodesAlignCenter, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Center); });
|
||||||
|
_cmAlignNodesRightButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align right", Editor.Instance.Options.Options.Input.NodesAlignRight, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Right); });
|
||||||
|
|
||||||
|
_cmFormatNodesMenu.ContextMenu.AddSeparator();
|
||||||
|
_cmDistributeNodesHorizontallyButton = _cmFormatNodesMenu.ContextMenu.AddButton("Distribute horizontally", Editor.Instance.Options.Options.Input.NodesDistributeHorizontal, () => { DistributeNodes(SelectedNodes, false); });
|
||||||
|
_cmDistributeNodesVerticallyButton = _cmFormatNodesMenu.ContextMenu.AddButton("Distribute vertically", Editor.Instance.Options.Options.Input.NodesDistributeVertical, () => { DistributeNodes(SelectedNodes, true); });
|
||||||
|
|
||||||
_cmRemoveNodeConnectionsButton = menu.AddButton("Remove all connections to that node(s)", () =>
|
_cmRemoveNodeConnectionsButton = menu.AddButton("Remove all connections to that node(s)", () =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ namespace FlaxEditor.Surface
|
|||||||
|
|
||||||
_rootControl.DrawComments();
|
_rootControl.DrawComments();
|
||||||
|
|
||||||
if (IsSelecting)
|
if (IsBoxSelecting)
|
||||||
{
|
{
|
||||||
DrawSelection();
|
DrawSelection();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -282,5 +282,122 @@ namespace FlaxEditor.Surface
|
|||||||
|
|
||||||
return maxOffset;
|
return maxOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Align given nodes on a graph using the given alignment type.
|
||||||
|
/// Ignores any potential overlap.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodes">List of nodes</param>
|
||||||
|
/// <param name="alignmentType">Alignemnt type</param>
|
||||||
|
public void AlignNodes(List<SurfaceNode> nodes, NodeAlignmentType alignmentType)
|
||||||
|
{
|
||||||
|
if(nodes.Count <= 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var undoActions = new List<MoveNodesAction>();
|
||||||
|
var boundingBox = GetNodesBounds(nodes);
|
||||||
|
for(int i = 0; i < nodes.Count; i++)
|
||||||
|
{
|
||||||
|
var centerY = boundingBox.Center.Y - (nodes[i].Height / 2);
|
||||||
|
var centerX = boundingBox.Center.X - (nodes[i].Width / 2);
|
||||||
|
|
||||||
|
var newLocation = alignmentType switch
|
||||||
|
{
|
||||||
|
NodeAlignmentType.Top => new Float2(nodes[i].Location.X, boundingBox.Top),
|
||||||
|
NodeAlignmentType.Middle => new Float2(nodes[i].Location.X, centerY),
|
||||||
|
NodeAlignmentType.Bottom => new Float2(nodes[i].Location.X, boundingBox.Bottom - nodes[i].Height),
|
||||||
|
|
||||||
|
NodeAlignmentType.Left => new Float2(boundingBox.Left, nodes[i].Location.Y),
|
||||||
|
NodeAlignmentType.Center => new Float2(centerX, nodes[i].Location.Y),
|
||||||
|
NodeAlignmentType.Right => new Float2(boundingBox.Right - nodes[i].Width, nodes[i].Location.Y),
|
||||||
|
|
||||||
|
_ => throw new NotImplementedException($"Unsupported node alignment type: {alignmentType}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
var locationDelta = newLocation - nodes[i].Location;
|
||||||
|
nodes[i].Location = newLocation;
|
||||||
|
|
||||||
|
if(Undo != null)
|
||||||
|
undoActions.Add(new MoveNodesAction(Context, new[] { nodes[i].ID }, locationDelta));
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkAsEdited(false);
|
||||||
|
Undo?.AddAction(new MultiUndoAction(undoActions, $"Align nodes ({alignmentType})"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Distribute the given nodes as equally as possible inside the bounding box, if no fit can be done it will use a default pad of 10 pixels between nodes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodes">List of nodes</param>
|
||||||
|
/// <param name="vertically">If false will be done horizontally, if true will be done vertically</param>
|
||||||
|
public void DistributeNodes(List<SurfaceNode> nodes, bool vertically)
|
||||||
|
{
|
||||||
|
if(nodes.Count <= 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var undoActions = new List<MoveNodesAction>();
|
||||||
|
var boundingBox = GetNodesBounds(nodes);
|
||||||
|
float padding = 10;
|
||||||
|
float totalSize = 0;
|
||||||
|
for (int i = 0; i < nodes.Count; i++)
|
||||||
|
{
|
||||||
|
if (vertically)
|
||||||
|
{
|
||||||
|
totalSize += nodes[i].Height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
totalSize += nodes[i].Width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(vertically)
|
||||||
|
{
|
||||||
|
nodes.Sort((leftValue, rightValue) => { return leftValue.Y.CompareTo(rightValue.Y); });
|
||||||
|
|
||||||
|
float position = boundingBox.Top;
|
||||||
|
if(totalSize < boundingBox.Height)
|
||||||
|
{
|
||||||
|
padding = (boundingBox.Height - totalSize) / nodes.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < nodes.Count; i++)
|
||||||
|
{
|
||||||
|
var newLocation = new Float2(nodes[i].X, position);
|
||||||
|
var locationDelta = newLocation - nodes[i].Location;
|
||||||
|
nodes[i].Location = newLocation;
|
||||||
|
|
||||||
|
position += nodes[i].Height + padding;
|
||||||
|
|
||||||
|
if (Undo != null)
|
||||||
|
undoActions.Add(new MoveNodesAction(Context, new[] { nodes[i].ID }, locationDelta));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nodes.Sort((leftValue, rightValue) => { return leftValue.X.CompareTo(rightValue.X); });
|
||||||
|
|
||||||
|
float position = boundingBox.Left;
|
||||||
|
if(totalSize < boundingBox.Width)
|
||||||
|
{
|
||||||
|
padding = (boundingBox.Width - totalSize) / nodes.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < nodes.Count; i++)
|
||||||
|
{
|
||||||
|
var newLocation = new Float2(position, nodes[i].Y);
|
||||||
|
var locationDelta = newLocation - nodes[i].Location;
|
||||||
|
nodes[i].Location = newLocation;
|
||||||
|
|
||||||
|
position += nodes[i].Width + padding;
|
||||||
|
|
||||||
|
if (Undo != null)
|
||||||
|
undoActions.Add(new MoveNodesAction(Context, new[] { nodes[i].ID }, locationDelta));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkAsEdited(false);
|
||||||
|
Undo?.AddAction(new MultiUndoAction(undoActions, vertically ? "Distribute nodes vertically" : "Distribute nodes horizontally"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ namespace FlaxEditor.Surface
|
|||||||
private Float2 _movingNodesDelta;
|
private Float2 _movingNodesDelta;
|
||||||
private Float2 _gridRoundingDelta;
|
private Float2 _gridRoundingDelta;
|
||||||
private HashSet<SurfaceNode> _movingNodes;
|
private HashSet<SurfaceNode> _movingNodes;
|
||||||
|
private HashSet<SurfaceNode> _temporarySelectedNodes;
|
||||||
private readonly Stack<InputBracket> _inputBrackets = new Stack<InputBracket>();
|
private readonly Stack<InputBracket> _inputBrackets = new Stack<InputBracket>();
|
||||||
|
|
||||||
private class InputBracket
|
private class InputBracket
|
||||||
@@ -130,13 +131,34 @@ namespace FlaxEditor.Surface
|
|||||||
if (_rootControl.Children[i] is SurfaceControl control)
|
if (_rootControl.Children[i] is SurfaceControl control)
|
||||||
{
|
{
|
||||||
var select = control.IsSelectionIntersecting(ref selectionRect);
|
var select = control.IsSelectionIntersecting(ref selectionRect);
|
||||||
if (select != control.IsSelected)
|
|
||||||
|
if (Root.GetKey(KeyboardKeys.Shift))
|
||||||
{
|
{
|
||||||
control.IsSelected = select;
|
if (select == control.IsSelected && _temporarySelectedNodes.Contains(control))
|
||||||
selectionChanged = true;
|
{
|
||||||
|
control.IsSelected = !select;
|
||||||
|
selectionChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Root.GetKey(KeyboardKeys.Control))
|
||||||
|
{
|
||||||
|
if (select != control.IsSelected && !_temporarySelectedNodes.Contains(control))
|
||||||
|
{
|
||||||
|
control.IsSelected = select;
|
||||||
|
selectionChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (select != control.IsSelected)
|
||||||
|
{
|
||||||
|
control.IsSelected = select;
|
||||||
|
selectionChanged = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectionChanged)
|
if (selectionChanged)
|
||||||
SelectionChanged?.Invoke();
|
SelectionChanged?.Invoke();
|
||||||
}
|
}
|
||||||
@@ -461,6 +483,19 @@ namespace FlaxEditor.Surface
|
|||||||
// Cache data
|
// Cache data
|
||||||
_isMovingSelection = false;
|
_isMovingSelection = false;
|
||||||
_mousePos = location;
|
_mousePos = location;
|
||||||
|
if(_temporarySelectedNodes == null)
|
||||||
|
_temporarySelectedNodes = new HashSet<SurfaceNode>();
|
||||||
|
else
|
||||||
|
_temporarySelectedNodes.Clear();
|
||||||
|
|
||||||
|
for (int i = 0; i < _rootControl.Children.Count; i++)
|
||||||
|
{
|
||||||
|
if (_rootControl.Children[i] is SurfaceNode node && node.IsSelected)
|
||||||
|
{
|
||||||
|
_temporarySelectedNodes.Add(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (button == MouseButton.Left)
|
if (button == MouseButton.Left)
|
||||||
{
|
{
|
||||||
_leftMouseDown = true;
|
_leftMouseDown = true;
|
||||||
@@ -488,9 +523,11 @@ namespace FlaxEditor.Surface
|
|||||||
// Check if user is pressing control
|
// Check if user is pressing control
|
||||||
if (Root.GetKey(KeyboardKeys.Control))
|
if (Root.GetKey(KeyboardKeys.Control))
|
||||||
{
|
{
|
||||||
// Add/remove from selection
|
AddToSelection(controlUnderMouse);
|
||||||
controlUnderMouse.IsSelected = !controlUnderMouse.IsSelected;
|
}
|
||||||
SelectionChanged?.Invoke();
|
else if (Root.GetKey(KeyboardKeys.Shift))
|
||||||
|
{
|
||||||
|
RemoveFromSelection(controlUnderMouse);
|
||||||
}
|
}
|
||||||
// Check if node isn't selected
|
// Check if node isn't selected
|
||||||
else if (!controlUnderMouse.IsSelected)
|
else if (!controlUnderMouse.IsSelected)
|
||||||
@@ -500,10 +537,14 @@ namespace FlaxEditor.Surface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start moving selected nodes
|
// Start moving selected nodes
|
||||||
StartMouseCapture();
|
if (!Root.GetKey(KeyboardKeys.Shift))
|
||||||
_movingSelectionViewPos = _rootControl.Location;
|
{
|
||||||
_movingNodesDelta = Float2.Zero;
|
StartMouseCapture();
|
||||||
OnGetNodesToMove();
|
_movingSelectionViewPos = _rootControl.Location;
|
||||||
|
_movingNodesDelta = Float2.Zero;
|
||||||
|
OnGetNodesToMove();
|
||||||
|
}
|
||||||
|
|
||||||
Focus();
|
Focus();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -515,7 +556,12 @@ namespace FlaxEditor.Surface
|
|||||||
{
|
{
|
||||||
// Start selecting or commenting
|
// Start selecting or commenting
|
||||||
StartMouseCapture();
|
StartMouseCapture();
|
||||||
ClearSelection();
|
|
||||||
|
if (!Root.GetKey(KeyboardKeys.Control) && !Root.GetKey(KeyboardKeys.Shift))
|
||||||
|
{
|
||||||
|
ClearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
Focus();
|
Focus();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -544,6 +590,9 @@ namespace FlaxEditor.Surface
|
|||||||
// Cache flags and state
|
// Cache flags and state
|
||||||
if (_leftMouseDown && button == MouseButton.Left)
|
if (_leftMouseDown && button == MouseButton.Left)
|
||||||
{
|
{
|
||||||
|
WasBoxSelecting = IsBoxSelecting;
|
||||||
|
WasMovingSelection = _isMovingSelection;
|
||||||
|
|
||||||
_leftMouseDown = false;
|
_leftMouseDown = false;
|
||||||
EndMouseCapture();
|
EndMouseCapture();
|
||||||
Cursor = CursorType.Default;
|
Cursor = CursorType.Default;
|
||||||
|
|||||||
@@ -232,15 +232,25 @@ namespace FlaxEditor.Surface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether user is selecting nodes.
|
/// Gets a value indicating whether user is box selecting nodes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsSelecting => _leftMouseDown && !_isMovingSelection && _connectionInstigator == null;
|
public bool IsBoxSelecting => _leftMouseDown && !_isMovingSelection && _connectionInstigator == null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether user was previously box selecting nodes.
|
||||||
|
/// </summary>
|
||||||
|
public bool WasBoxSelecting { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether user is moving selected nodes.
|
/// Gets a value indicating whether user is moving selected nodes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsMovingSelection => _leftMouseDown && _isMovingSelection && _connectionInstigator == null;
|
public bool IsMovingSelection => _leftMouseDown && _isMovingSelection && _connectionInstigator == null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether user was previously moving selected nodes.
|
||||||
|
/// </summary>
|
||||||
|
public bool WasMovingSelection { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether user is connecting nodes.
|
/// Gets a value indicating whether user is connecting nodes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -405,6 +415,15 @@ namespace FlaxEditor.Surface
|
|||||||
new InputActionsContainer.Binding(options => options.Paste, Paste),
|
new InputActionsContainer.Binding(options => options.Paste, Paste),
|
||||||
new InputActionsContainer.Binding(options => options.Cut, Cut),
|
new InputActionsContainer.Binding(options => options.Cut, Cut),
|
||||||
new InputActionsContainer.Binding(options => options.Duplicate, Duplicate),
|
new InputActionsContainer.Binding(options => options.Duplicate, Duplicate),
|
||||||
|
new InputActionsContainer.Binding(options => options.NodesAutoFormat, () => { FormatGraph(SelectedNodes); }),
|
||||||
|
new InputActionsContainer.Binding(options => options.NodesAlignTop, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Top); }),
|
||||||
|
new InputActionsContainer.Binding(options => options.NodesAlignMiddle, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Middle); }),
|
||||||
|
new InputActionsContainer.Binding(options => options.NodesAlignBottom, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Bottom); }),
|
||||||
|
new InputActionsContainer.Binding(options => options.NodesAlignLeft, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Left); }),
|
||||||
|
new InputActionsContainer.Binding(options => options.NodesAlignCenter, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Center); }),
|
||||||
|
new InputActionsContainer.Binding(options => options.NodesAlignRight, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Right); }),
|
||||||
|
new InputActionsContainer.Binding(options => options.NodesDistributeHorizontal, () => { DistributeNodes(SelectedNodes, false); }),
|
||||||
|
new InputActionsContainer.Binding(options => options.NodesDistributeVertical, () => { DistributeNodes(SelectedNodes, true); }),
|
||||||
});
|
});
|
||||||
|
|
||||||
Context.ControlSpawned += OnSurfaceControlSpawned;
|
Context.ControlSpawned += OnSurfaceControlSpawned;
|
||||||
@@ -710,6 +729,18 @@ namespace FlaxEditor.Surface
|
|||||||
SelectionChanged?.Invoke();
|
SelectionChanged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the specified control from the selection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="control">The control.</param>
|
||||||
|
public void RemoveFromSelection(SurfaceControl control)
|
||||||
|
{
|
||||||
|
if (!control.IsSelected)
|
||||||
|
return;
|
||||||
|
control.IsSelected = false;
|
||||||
|
SelectionChanged?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Selects the specified control.
|
/// Selects the specified control.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1518,6 +1518,7 @@ namespace FlaxEditor.Utilities
|
|||||||
inputActions.Add(options => options.OpenScriptsProject, () => Editor.Instance.CodeEditing.OpenSolution());
|
inputActions.Add(options => options.OpenScriptsProject, () => Editor.Instance.CodeEditing.OpenSolution());
|
||||||
inputActions.Add(options => options.GenerateScriptsProject, () => Editor.Instance.ProgressReporting.GenerateScriptsProjectFiles.RunAsync());
|
inputActions.Add(options => options.GenerateScriptsProject, () => Editor.Instance.ProgressReporting.GenerateScriptsProjectFiles.RunAsync());
|
||||||
inputActions.Add(options => options.RecompileScripts, ScriptsBuilder.Compile);
|
inputActions.Add(options => options.RecompileScripts, ScriptsBuilder.Compile);
|
||||||
|
inputActions.Add(options => options.FocusConsoleCommand, () => Editor.Instance.Windows.OutputLogWin.FocusCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string ToPathProject(string path)
|
internal static string ToPathProject(string path)
|
||||||
|
|||||||
@@ -236,6 +236,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
var group = layout.Group("General");
|
var group = layout.Group("General");
|
||||||
|
|
||||||
var minScreenSize = group.FloatValue("Min Screen Size", "The minimum screen size to draw model (the bottom limit). Used to cull small models. Set to 0 to disable this feature.");
|
var minScreenSize = group.FloatValue("Min Screen Size", "The minimum screen size to draw model (the bottom limit). Used to cull small models. Set to 0 to disable this feature.");
|
||||||
|
minScreenSize.ValueBox.SlideSpeed = 0.005f;
|
||||||
minScreenSize.ValueBox.MinValue = 0.0f;
|
minScreenSize.ValueBox.MinValue = 0.0f;
|
||||||
minScreenSize.ValueBox.MaxValue = 1.0f;
|
minScreenSize.ValueBox.MaxValue = 1.0f;
|
||||||
minScreenSize.ValueBox.Value = proxy.Asset.MinScreenSize;
|
minScreenSize.ValueBox.Value = proxy.Asset.MinScreenSize;
|
||||||
@@ -476,12 +477,12 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[EditorOrder(1), EditorDisplay(null, "LOD"), Limit(0, Model.MaxLODs), VisibleIf("ShowUVs")]
|
[EditorOrder(1), EditorDisplay(null, "LOD"), Limit(0, Model.MaxLODs, 0.01f), VisibleIf("ShowUVs")]
|
||||||
[Tooltip("Level Of Detail index to preview UVs layout.")]
|
[Tooltip("Level Of Detail index to preview UVs layout at.")]
|
||||||
public int LOD = 0;
|
public int LOD = 0;
|
||||||
|
|
||||||
[EditorOrder(2), EditorDisplay(null, "Mesh"), Limit(-1, 1000000), VisibleIf("ShowUVs")]
|
[EditorOrder(2), EditorDisplay(null, "Mesh"), Limit(-1, 1000000, 0.01f), VisibleIf("ShowUVs")]
|
||||||
[Tooltip("Mesh index to preview UVs layout. Use -1 for all meshes")]
|
[Tooltip("Mesh index to show UVs layout for. Use -1 to display all UVs of all meshes")]
|
||||||
public int Mesh = -1;
|
public int Mesh = -1;
|
||||||
|
|
||||||
private bool ShowUVs => _uvChannel != UVChannel.None;
|
private bool ShowUVs => _uvChannel != UVChannel.None;
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resolution = group.FloatValue("Resolution Scale", Window.Editor.CodeDocs.GetTooltip(typeof(ModelTool.Options), nameof(ModelImportSettings.Settings.SDFResolution)));
|
var resolution = group.FloatValue("Resolution Scale", Window.Editor.CodeDocs.GetTooltip(typeof(ModelTool.Options), nameof(ModelImportSettings.Settings.SDFResolution)));
|
||||||
|
resolution.ValueBox.SlideSpeed = 0.001f;
|
||||||
resolution.ValueBox.MinValue = 0.0001f;
|
resolution.ValueBox.MinValue = 0.0001f;
|
||||||
resolution.ValueBox.MaxValue = 100.0f;
|
resolution.ValueBox.MaxValue = 100.0f;
|
||||||
resolution.ValueBox.Value = sdf.Texture != null ? sdf.ResolutionScale : 1.0f;
|
resolution.ValueBox.Value = sdf.Texture != null ? sdf.ResolutionScale : 1.0f;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FlaxEditor.Content;
|
using FlaxEditor.Content;
|
||||||
using FlaxEditor.CustomEditors;
|
using FlaxEditor.CustomEditors;
|
||||||
|
using FlaxEditor.GUI;
|
||||||
using FlaxEditor.Scripting;
|
using FlaxEditor.Scripting;
|
||||||
using FlaxEditor.Surface;
|
using FlaxEditor.Surface;
|
||||||
using FlaxEditor.Viewport.Previews;
|
using FlaxEditor.Viewport.Previews;
|
||||||
@@ -114,6 +115,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
|
|
||||||
private readonly PropertiesProxy _properties;
|
private readonly PropertiesProxy _properties;
|
||||||
private Tab _previewTab;
|
private Tab _previewTab;
|
||||||
|
private ToolStripButton _showSourceCodeButton;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ParticleEmitterWindow(Editor editor, AssetItem item)
|
public ParticleEmitterWindow(Editor editor, AssetItem item)
|
||||||
@@ -146,7 +148,8 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
|
|
||||||
// Toolstrip
|
// Toolstrip
|
||||||
SurfaceUtils.PerformCommonSetup(this, _toolstrip, _surface, out _saveButton, out _undoButton, out _redoButton);
|
SurfaceUtils.PerformCommonSetup(this, _toolstrip, _surface, out _saveButton, out _undoButton, out _redoButton);
|
||||||
_toolstrip.AddButton(editor.Icons.Code64, ShowSourceCode).LinkTooltip("Show generated shader source code");
|
_showSourceCodeButton = _toolstrip.AddButton(editor.Icons.Code64, ShowSourceCode);
|
||||||
|
_showSourceCodeButton.LinkTooltip("Show generated shader source code");
|
||||||
_toolstrip.AddSeparator();
|
_toolstrip.AddSeparator();
|
||||||
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/particles/index.html")).LinkTooltip("See documentation to learn more");
|
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/particles/index.html")).LinkTooltip("See documentation to learn more");
|
||||||
}
|
}
|
||||||
@@ -285,5 +288,15 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public SearchAssetTypes AssetType => SearchAssetTypes.ParticleEmitter;
|
public SearchAssetTypes AssetType => SearchAssetTypes.ParticleEmitter;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Update(float deltaTime)
|
||||||
|
{
|
||||||
|
base.Update(deltaTime);
|
||||||
|
|
||||||
|
if (_asset == null)
|
||||||
|
return;
|
||||||
|
_showSourceCodeButton.Enabled = _asset.HasShaderCode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,10 +97,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
|
|
||||||
// For single node selected scroll view so user can see it
|
// For single node selected scroll view so user can see it
|
||||||
if (nodes.Count == 1)
|
if (nodes.Count == 1)
|
||||||
{
|
ScrollToSelectedNode();
|
||||||
nodes[0].ExpandAllParents(true);
|
|
||||||
ScrollViewTo(nodes[0]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update properties editor
|
// Update properties editor
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ namespace FlaxEditor.Windows
|
|||||||
private Color _colorWarning;
|
private Color _colorWarning;
|
||||||
private Color _colorError;
|
private Color _colorError;
|
||||||
private bool _colorDebugLogText;
|
private bool _colorDebugLogText;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="DebugLogWindow"/> class.
|
/// Initializes a new instance of the <see cref="DebugLogWindow"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -352,24 +352,12 @@ namespace FlaxEditor.Windows
|
|||||||
editor.Options.Apply(editor.Options.Options);
|
editor.Options.Apply(editor.Options.Options);
|
||||||
}).SetAutoCheck(true).LinkTooltip("Performs auto pause on error");
|
}).SetAutoCheck(true).LinkTooltip("Performs auto pause on error");
|
||||||
toolstrip.AddSeparator();
|
toolstrip.AddSeparator();
|
||||||
_groupButtons[0] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Error32, () =>
|
_groupButtons[0] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Error32, () => { OnGroupButtonPressed(0); })
|
||||||
{
|
.SetAutoCheck(true).LinkTooltip("Shows/hides error messages");
|
||||||
UpdateLogTypeVisibility(LogGroup.Error, _groupButtons[0].Checked);
|
_groupButtons[1] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Warning32, () => { OnGroupButtonPressed(1); })
|
||||||
editor.Options.Options.Interface.DebugLogShowErrorMessages = _groupButtons[0].Checked;
|
.SetAutoCheck(true).LinkTooltip("Shows/hides warning messages");
|
||||||
editor.Options.Apply(editor.Options.Options);
|
_groupButtons[2] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Info32, () => { OnGroupButtonPressed(2); })
|
||||||
}).SetAutoCheck(true).LinkTooltip("Shows/hides error messages");
|
.SetAutoCheck(true).LinkTooltip("Shows/hides info messages");
|
||||||
_groupButtons[1] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Warning32, () =>
|
|
||||||
{
|
|
||||||
UpdateLogTypeVisibility(LogGroup.Warning, _groupButtons[1].Checked);
|
|
||||||
editor.Options.Options.Interface.DebugLogShowWarningMessages = _groupButtons[1].Checked;
|
|
||||||
editor.Options.Apply(editor.Options.Options);
|
|
||||||
}).SetAutoCheck(true).LinkTooltip("Shows/hides warning messages");
|
|
||||||
_groupButtons[2] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Info32, () =>
|
|
||||||
{
|
|
||||||
UpdateLogTypeVisibility(LogGroup.Info, _groupButtons[2].Checked);
|
|
||||||
editor.Options.Options.Interface.DebugLogShowInfoMessages = _groupButtons[2].Checked;
|
|
||||||
editor.Options.Apply(editor.Options.Options);
|
|
||||||
}).SetAutoCheck(true).LinkTooltip("Shows/hides info messages");
|
|
||||||
UpdateCount();
|
UpdateCount();
|
||||||
|
|
||||||
// Split panel
|
// Split panel
|
||||||
@@ -418,6 +406,27 @@ namespace FlaxEditor.Windows
|
|||||||
OnEditorOptionsChanged(Editor.Options.Options);
|
OnEditorOptionsChanged(Editor.Options.Options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnGroupButtonPressed(int index)
|
||||||
|
{
|
||||||
|
UpdateLogTypeVisibility((LogGroup)index, _groupButtons[index].Checked);
|
||||||
|
if (Input.GetKey(KeyboardKeys.Shift))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (int)LogGroup.Max; i++)
|
||||||
|
{
|
||||||
|
if (i == index)
|
||||||
|
continue;
|
||||||
|
_groupButtons[i].Checked = !_groupButtons[index].Checked;
|
||||||
|
UpdateLogTypeVisibility((LogGroup)i, _groupButtons[i].Checked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = Editor.Options.Options.Interface;
|
||||||
|
options.DebugLogShowErrorMessages = _groupButtons[0].Checked;
|
||||||
|
options.DebugLogShowWarningMessages = _groupButtons[1].Checked;
|
||||||
|
options.DebugLogShowInfoMessages = _groupButtons[2].Checked;
|
||||||
|
Editor.Options.Apply(Editor.Options.Options);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnEditorOptionsChanged(EditorOptions options)
|
private void OnEditorOptionsChanged(EditorOptions options)
|
||||||
{
|
{
|
||||||
_timestampsFormats = options.Interface.DebugLogTimestampsFormat;
|
_timestampsFormats = options.Interface.DebugLogTimestampsFormat;
|
||||||
@@ -455,15 +464,9 @@ namespace FlaxEditor.Windows
|
|||||||
// Create new entry
|
// Create new entry
|
||||||
switch (_timestampsFormats)
|
switch (_timestampsFormats)
|
||||||
{
|
{
|
||||||
case InterfaceOptions.TimestampsFormats.Utc:
|
case InterfaceOptions.TimestampsFormats.Utc: desc.Title = $"[{DateTime.UtcNow}] {desc.Title}"; break;
|
||||||
desc.Title = $"[{DateTime.UtcNow}] {desc.Title}";
|
case InterfaceOptions.TimestampsFormats.LocalTime: desc.Title = $"[{DateTime.Now}] {desc.Title}"; break;
|
||||||
break;
|
case InterfaceOptions.TimestampsFormats.TimeSinceStartup: desc.Title = string.Format("[{0:g}] ", TimeSpan.FromSeconds(Time.TimeSinceStartup)) + desc.Title; break;
|
||||||
case InterfaceOptions.TimestampsFormats.LocalTime:
|
|
||||||
desc.Title = $"[{DateTime.Now}] {desc.Title}";
|
|
||||||
break;
|
|
||||||
case InterfaceOptions.TimestampsFormats.TimeSinceStartup:
|
|
||||||
desc.Title = string.Format("[{0:g}] ", TimeSpan.FromSeconds(Time.TimeSinceStartup)) + desc.Title;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
var newEntry = new LogEntry(this, ref desc);
|
var newEntry = new LogEntry(this, ref desc);
|
||||||
|
|
||||||
|
|||||||
@@ -219,6 +219,13 @@ namespace FlaxEditor.Windows
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when Editor will leave the play mode.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void OnPlayEnding()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when Editor leaves the play mode.
|
/// Called when Editor leaves the play mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -405,6 +405,7 @@ namespace FlaxEditor.Windows
|
|||||||
return;
|
return;
|
||||||
Editor.Instance.SceneEditing.Delete();
|
Editor.Instance.SceneEditing.Delete();
|
||||||
});
|
});
|
||||||
|
InputActions.Add(options => options.FocusConsoleCommand, () => Editor.Instance.Windows.OutputLogWin.FocusCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ChangeViewportRatio(ViewportScaleOptions v)
|
private void ChangeViewportRatio(ViewportScaleOptions v)
|
||||||
|
|||||||
@@ -830,6 +830,15 @@ namespace FlaxEditor.Windows
|
|||||||
OnOutputTextChanged();
|
OnOutputTextChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Focus the debug command line and ensure that the output log window is visible.
|
||||||
|
/// </summary>
|
||||||
|
public void FocusCommand()
|
||||||
|
{
|
||||||
|
FocusOrShow();
|
||||||
|
_commandLineBox.Focus();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Update(float deltaTime)
|
public override void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ namespace FlaxEditor.Windows
|
|||||||
private DragScriptItems _dragScriptItems;
|
private DragScriptItems _dragScriptItems;
|
||||||
private DragHandlers _dragHandlers;
|
private DragHandlers _dragHandlers;
|
||||||
private bool _isDropping = false;
|
private bool _isDropping = false;
|
||||||
|
private bool _forceScrollNodeToView = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Scene tree panel.
|
/// Scene tree panel.
|
||||||
@@ -91,6 +92,15 @@ namespace FlaxEditor.Windows
|
|||||||
_tree.SelectedChanged += Tree_OnSelectedChanged;
|
_tree.SelectedChanged += Tree_OnSelectedChanged;
|
||||||
_tree.RightClick += OnTreeRightClick;
|
_tree.RightClick += OnTreeRightClick;
|
||||||
_tree.Parent = _sceneTreePanel;
|
_tree.Parent = _sceneTreePanel;
|
||||||
|
_tree.AfterDeferredLayout += () =>
|
||||||
|
{
|
||||||
|
if (_forceScrollNodeToView)
|
||||||
|
{
|
||||||
|
_forceScrollNodeToView = false;
|
||||||
|
ScrollToSelectedNode();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
headerPanel.Parent = this;
|
headerPanel.Parent = this;
|
||||||
|
|
||||||
// Setup input actions
|
// Setup input actions
|
||||||
@@ -142,6 +152,16 @@ namespace FlaxEditor.Windows
|
|||||||
root.TreeNode.UpdateFilter(query);
|
root.TreeNode.UpdateFilter(query);
|
||||||
|
|
||||||
_tree.UnlockChildrenRecursive();
|
_tree.UnlockChildrenRecursive();
|
||||||
|
|
||||||
|
// When keep the selected nodes in a view
|
||||||
|
var nodeSelection = _tree.Selection;
|
||||||
|
if (nodeSelection.Count != 0)
|
||||||
|
{
|
||||||
|
var node = nodeSelection[nodeSelection.Count - 1];
|
||||||
|
node.Expand(true);
|
||||||
|
_forceScrollNodeToView = true;
|
||||||
|
}
|
||||||
|
|
||||||
PerformLayout();
|
PerformLayout();
|
||||||
PerformLayout();
|
PerformLayout();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ namespace FlaxEditor.Windows.Search
|
|||||||
if (value == _selectedItem || (value != null && !_matchedItems.Contains(value)))
|
if (value == _selectedItem || (value != null && !_matchedItems.Contains(value)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Restore the previous selected item to the non-selected color
|
||||||
if (_selectedItem != null)
|
if (_selectedItem != null)
|
||||||
{
|
{
|
||||||
_selectedItem.BackgroundColor = Color.Transparent;
|
_selectedItem.BackgroundColor = Color.Transparent;
|
||||||
@@ -54,6 +55,7 @@ namespace FlaxEditor.Windows.Search
|
|||||||
_selectedItem.BackgroundColor = Style.Current.BackgroundSelected;
|
_selectedItem.BackgroundColor = Style.Current.BackgroundSelected;
|
||||||
if (_matchedItems.Count > VisibleItemCount)
|
if (_matchedItems.Count > VisibleItemCount)
|
||||||
{
|
{
|
||||||
|
_selectedItem.Focus();
|
||||||
_resultPanel.ScrollViewTo(_selectedItem, true);
|
_resultPanel.ScrollViewTo(_selectedItem, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,39 +182,17 @@ namespace FlaxEditor.Windows.Search
|
|||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
case KeyboardKeys.ArrowDown:
|
case KeyboardKeys.ArrowDown:
|
||||||
{
|
|
||||||
if (_matchedItems.Count == 0)
|
|
||||||
return true;
|
|
||||||
int currentPos;
|
|
||||||
if (_selectedItem != null)
|
|
||||||
{
|
|
||||||
currentPos = _matchedItems.IndexOf(_selectedItem) + 1;
|
|
||||||
if (currentPos >= _matchedItems.Count)
|
|
||||||
currentPos--;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
currentPos = 0;
|
|
||||||
}
|
|
||||||
SelectedItem = _matchedItems[currentPos];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case KeyboardKeys.ArrowUp:
|
case KeyboardKeys.ArrowUp:
|
||||||
{
|
{
|
||||||
if (_matchedItems.Count == 0)
|
if (_matchedItems.Count == 0)
|
||||||
return true;
|
return true;
|
||||||
int currentPos;
|
|
||||||
if (_selectedItem != null)
|
var focusedIndex = _matchedItems.IndexOf(_selectedItem);
|
||||||
{
|
int delta = key == KeyboardKeys.ArrowDown ? -1 : 1;
|
||||||
currentPos = _matchedItems.IndexOf(_selectedItem) - 1;
|
int nextIndex = Mathf.Wrap(focusedIndex - delta, 0, _matchedItems.Count - 1);
|
||||||
if (currentPos < 0)
|
var nextItem = _matchedItems[nextIndex];
|
||||||
currentPos = 0;
|
|
||||||
}
|
SelectedItem = nextItem;
|
||||||
else
|
|
||||||
{
|
|
||||||
currentPos = 0;
|
|
||||||
}
|
|
||||||
SelectedItem = _matchedItems[currentPos];
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case KeyboardKeys.Return:
|
case KeyboardKeys.Return:
|
||||||
@@ -234,6 +214,17 @@ namespace FlaxEditor.Windows.Search
|
|||||||
Hide();
|
Hide();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case KeyboardKeys.Backspace:
|
||||||
|
{
|
||||||
|
// Alow the user to quickly focus the searchbar
|
||||||
|
if (_searchBox != null && !_searchBox.IsFocused)
|
||||||
|
{
|
||||||
|
_searchBox.Focus();
|
||||||
|
_searchBox.SelectAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.OnKeyDown(key);
|
return base.OnKeyDown(key);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "Engine/Tools/AudioTool/OggVorbisDecoder.h"
|
#include "Engine/Tools/AudioTool/OggVorbisDecoder.h"
|
||||||
#include "Engine/Tools/AudioTool/OggVorbisEncoder.h"
|
#include "Engine/Tools/AudioTool/OggVorbisEncoder.h"
|
||||||
#include "Engine/Serialization/JsonWriters.h"
|
#include "Engine/Serialization/JsonWriters.h"
|
||||||
|
#include "Engine/Platform/MessageBox.h"
|
||||||
|
|
||||||
bool ImportAudio::TryGetImportOptions(const StringView& path, Options& options)
|
bool ImportAudio::TryGetImportOptions(const StringView& path, Options& options)
|
||||||
{
|
{
|
||||||
@@ -118,6 +119,7 @@ CreateAssetResult ImportAudio::Import(CreateAssetContext& context, AudioDecoder&
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define HANDLE_VORBIS(chunkIndex, dataPtr, dataSize) \
|
#define HANDLE_VORBIS(chunkIndex, dataPtr, dataSize) \
|
||||||
|
MessageBox::Show(TEXT("Vorbis format is not supported."), TEXT("Import warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning);
|
||||||
LOG(Warning, "Vorbis format is not supported."); \
|
LOG(Warning, "Vorbis format is not supported."); \
|
||||||
return CreateAssetResult::Error;
|
return CreateAssetResult::Error;
|
||||||
#endif
|
#endif
|
||||||
@@ -140,6 +142,7 @@ CreateAssetResult ImportAudio::Import(CreateAssetContext& context, AudioDecoder&
|
|||||||
break; \
|
break; \
|
||||||
default: \
|
default: \
|
||||||
{ \
|
{ \
|
||||||
|
MessageBox::Show(TEXT("Unknown audio format."), TEXT("Import warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning); \
|
||||||
LOG(Warning, "Unknown audio format."); \
|
LOG(Warning, "Unknown audio format."); \
|
||||||
return CreateAssetResult::Error; \
|
return CreateAssetResult::Error; \
|
||||||
} \
|
} \
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ API_CLASS(InBuild) class BitArray
|
|||||||
public:
|
public:
|
||||||
using ItemType = uint64;
|
using ItemType = uint64;
|
||||||
using AllocationData = typename AllocationType::template Data<ItemType>;
|
using AllocationData = typename AllocationType::template Data<ItemType>;
|
||||||
|
static constexpr int32 ItemBitCount = 64;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int32 _count;
|
int32 _count;
|
||||||
@@ -209,8 +210,8 @@ public:
|
|||||||
bool Get(const int32 index) const
|
bool Get(const int32 index) const
|
||||||
{
|
{
|
||||||
ASSERT(index >= 0 && index < _count);
|
ASSERT(index >= 0 && index < _count);
|
||||||
const ItemType offset = index / sizeof(ItemType);
|
const ItemType offset = index / ItemBitCount;
|
||||||
const ItemType bitMask = (ItemType)(int32)(1 << (index & ((int32)sizeof(ItemType) - 1)));
|
const ItemType bitMask = (ItemType)(1 << (index & (ItemBitCount - 1)));
|
||||||
const ItemType item = ((ItemType*)_allocation.Get())[offset];
|
const ItemType item = ((ItemType*)_allocation.Get())[offset];
|
||||||
return (item & bitMask) != 0;
|
return (item & bitMask) != 0;
|
||||||
}
|
}
|
||||||
@@ -223,13 +224,13 @@ public:
|
|||||||
void Set(const int32 index, const bool value)
|
void Set(const int32 index, const bool value)
|
||||||
{
|
{
|
||||||
ASSERT(index >= 0 && index < _count);
|
ASSERT(index >= 0 && index < _count);
|
||||||
const ItemType offset = index / sizeof(ItemType);
|
const ItemType offset = index / ItemBitCount;
|
||||||
const ItemType bitMask = (ItemType)(int32)(1 << (index & ((int32)sizeof(ItemType) - 1)));
|
const ItemType bitMask = (ItemType)(1 << (index & (ItemBitCount - 1)));
|
||||||
ItemType& item = ((ItemType*)_allocation.Get())[offset];
|
ItemType& item = ((ItemType*)_allocation.Get())[offset];
|
||||||
if (value)
|
if (value)
|
||||||
item |= bitMask;
|
item |= bitMask; // Set the bit
|
||||||
else
|
else
|
||||||
item &= ~bitMask; // Clear the bit
|
item &= ~bitMask; // Unset the bit
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
|
_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
|
||||||
#define PRAGMA_ENABLE_DEPRECATION_WARNINGS \
|
#define PRAGMA_ENABLE_DEPRECATION_WARNINGS \
|
||||||
_Pragma("clang diagnostic pop")
|
_Pragma("clang diagnostic pop")
|
||||||
|
#define PRAGMA_DISABLE_OPTIMIZATION
|
||||||
|
#define PRAGMA_ENABLE_OPTIMIZATION
|
||||||
|
|
||||||
#pragma clang diagnostic ignored "-Wswitch"
|
#pragma clang diagnostic ignored "-Wswitch"
|
||||||
#pragma clang diagnostic ignored "-Wmacro-redefined"
|
#pragma clang diagnostic ignored "-Wmacro-redefined"
|
||||||
@@ -54,6 +56,8 @@
|
|||||||
#define OFFSET_OF(X, Y) __builtin_offsetof(X, Y)
|
#define OFFSET_OF(X, Y) __builtin_offsetof(X, Y)
|
||||||
#define PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
#define PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||||
#define PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
#define PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||||
|
#define PRAGMA_DISABLE_OPTIMIZATION
|
||||||
|
#define PRAGMA_ENABLE_OPTIMIZATION
|
||||||
|
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
|
|
||||||
@@ -86,6 +90,8 @@
|
|||||||
__pragma(warning(disable: 4996))
|
__pragma(warning(disable: 4996))
|
||||||
#define PRAGMA_ENABLE_DEPRECATION_WARNINGS \
|
#define PRAGMA_ENABLE_DEPRECATION_WARNINGS \
|
||||||
__pragma (warning(pop))
|
__pragma (warning(pop))
|
||||||
|
#define PRAGMA_DISABLE_OPTIMIZATION __pragma(optimize("", off))
|
||||||
|
#define PRAGMA_ENABLE_OPTIMIZATION __pragma(optimize("", on))
|
||||||
|
|
||||||
#pragma warning(disable: 4251)
|
#pragma warning(disable: 4251)
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "Engine/Tools/ModelTool/VertexTriangleAdjacency.h"
|
#include "Engine/Tools/ModelTool/VertexTriangleAdjacency.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
#include "Engine/Platform/Platform.h"
|
#include "Engine/Platform/Platform.h"
|
||||||
|
#include "Engine/Platform/MessageBox.h"
|
||||||
#define USE_MIKKTSPACE 1
|
#define USE_MIKKTSPACE 1
|
||||||
#include "ThirdParty/MikkTSpace/mikktspace.h"
|
#include "ThirdParty/MikkTSpace/mikktspace.h"
|
||||||
#if USE_ASSIMP
|
#if USE_ASSIMP
|
||||||
@@ -181,6 +182,7 @@ bool MeshData::GenerateLightmapUVs()
|
|||||||
for (int32 i = 0; i < (int32)vb.size(); i++)
|
for (int32 i = 0; i < (int32)vb.size(); i++)
|
||||||
lightmapChannel.Get()[i] = *(Float2*)&vb[i].uv;
|
lightmapChannel.Get()[i] = *(Float2*)&vb[i].uv;
|
||||||
#else
|
#else
|
||||||
|
MessageBox::Show(TEXT("Model lightmap UVs generation is not supported on this platform."), TEXT("Import error"), MessageBoxButtons::OK, MessageBoxIcon::Error);
|
||||||
LOG(Error, "Model lightmap UVs generation is not supported on this platform.");
|
LOG(Error, "Model lightmap UVs generation is not supported on this platform.");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -656,6 +656,23 @@ GPUTask* GPUTexture::UploadMipMapAsync(const BytesContainer& data, int32 mipInde
|
|||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GPUTexture::UploadData(TextureData& data, bool copyData)
|
||||||
|
{
|
||||||
|
if (!IsAllocated())
|
||||||
|
return true;
|
||||||
|
if (data.Width != Width() || data.Height != Height() || data.Depth != Depth() || data.GetArraySize() != ArraySize() || data.Format != Format())
|
||||||
|
return true;
|
||||||
|
for (int32 arrayIndex = 0; arrayIndex < ArraySize(); arrayIndex++)
|
||||||
|
{
|
||||||
|
for (int32 mipLevel = 0; mipLevel < MipLevels(); mipLevel++)
|
||||||
|
{
|
||||||
|
TextureMipData* mip = data.GetData(arrayIndex, mipLevel);
|
||||||
|
UploadMipMapAsync(mip->Data, mipLevel, mip->RowPitch, mip->DepthPitch, copyData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
class TextureDownloadDataTask : public ThreadPoolTask
|
class TextureDownloadDataTask : public ThreadPoolTask
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -499,7 +499,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Uploads mip map data to the GPU. Creates async GPU task.
|
/// Uploads mip map data to the GPU. Creates async GPU task.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">Data to upload (it must be valid for the next a few frames due to GPU latency and async works executing)</param>
|
/// <param name="data">Data to upload, it must match texture dimensions. It must be valid for the next couple of frames due to GPU async task latency or use data copy.</param>
|
||||||
/// <param name="mipIndex">Mip level index.</param>
|
/// <param name="mipIndex">Mip level index.</param>
|
||||||
/// <param name="copyData">If true, the data will be copied to the async execution task instead of using the input pointer provided.</param>
|
/// <param name="copyData">If true, the data will be copied to the async execution task instead of using the input pointer provided.</param>
|
||||||
/// <returns>Created async task or null if cannot.</returns>
|
/// <returns>Created async task or null if cannot.</returns>
|
||||||
@@ -508,7 +508,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Uploads mip map data to the GPU. Creates async GPU task.
|
/// Uploads mip map data to the GPU. Creates async GPU task.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">Data to upload (it must be valid for the next a few frames due to GPU latency and async works executing)</param>
|
/// <param name="data">Data to upload, it must match texture dimensions. It must be valid for the next couple of frames due to GPU async task latency or use data copy.</param>
|
||||||
/// <param name="mipIndex">Mip level index.</param>
|
/// <param name="mipIndex">Mip level index.</param>
|
||||||
/// <param name="rowPitch">The data row pitch.</param>
|
/// <param name="rowPitch">The data row pitch.</param>
|
||||||
/// <param name="slicePitch">The data slice pitch.</param>
|
/// <param name="slicePitch">The data slice pitch.</param>
|
||||||
@@ -516,6 +516,14 @@ public:
|
|||||||
/// <returns>Created async task or null if cannot.</returns>
|
/// <returns>Created async task or null if cannot.</returns>
|
||||||
GPUTask* UploadMipMapAsync(const BytesContainer& data, int32 mipIndex, int32 rowPitch, int32 slicePitch, bool copyData = false);
|
GPUTask* UploadMipMapAsync(const BytesContainer& data, int32 mipIndex, int32 rowPitch, int32 slicePitch, bool copyData = false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Uploads texture data to the GPU. Actual data copy to the GPU memory is performed via async task.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">Data to upload, it must match texture dimensions. It must be valid for the next couple of frames due to GPU async task latency or use data copy.</param>
|
||||||
|
/// <param name="copyData">If true, the data will be copied to the async execution task instead of using the input pointer provided.</param>
|
||||||
|
/// <returns>True if cannot upload data, otherwise false.</returns>
|
||||||
|
API_FUNCTION() bool UploadData(TextureData& data, bool copyData = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Downloads the texture data to be accessible from CPU. For frequent access, use staging textures, otherwise current thread will be stalled to wait for the GPU frame to copy data into staging buffer.
|
/// Downloads the texture data to be accessible from CPU. For frequent access, use staging textures, otherwise current thread will be stalled to wait for the GPU frame to copy data into staging buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The animation update delta timescale. 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>
|
/// </summary>
|
||||||
API_FIELD(Attributes="EditorOrder(45), EditorDisplay(\"Skinned Model\")")
|
API_FIELD(Attributes="EditorOrder(45), Limit(0, float.MaxValue, 0.025f), EditorDisplay(\"Skinned Model\")")
|
||||||
float UpdateSpeed = 1.0f;
|
float UpdateSpeed = 1.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -122,7 +122,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The master scale parameter for the actor bounding box. Helps to reduce 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>
|
/// </summary>
|
||||||
API_FIELD(Attributes="EditorOrder(60), DefaultValue(1.5f), Limit(0), EditorDisplay(\"Skinned Model\")")
|
API_FIELD(Attributes="EditorOrder(60), DefaultValue(1.5f), Limit(0, float.MaxValue, 0.025f), EditorDisplay(\"Skinned Model\")")
|
||||||
float BoundsScale = 1.5f;
|
float BoundsScale = 1.5f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -443,4 +443,18 @@ bool ParticleEmitter::Save(const StringView& path)
|
|||||||
return SaveSurface(data);
|
return SaveSurface(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ParticleEmitter::HasShaderCode() const
|
||||||
|
{
|
||||||
|
if (SimulationMode != ParticlesSimulationMode::GPU)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#if COMPILE_WITH_PARTICLE_GPU_GRAPH && COMPILE_WITH_SHADER_COMPILER
|
||||||
|
if (_shaderHeader.ParticleEmitter.GraphVersion == PARTICLE_GPU_GRAPH_VERSION
|
||||||
|
&& HasChunk(SHADER_FILE_CHUNK_SOURCE)
|
||||||
|
&& !HasDependenciesModified())
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -173,6 +173,11 @@ public:
|
|||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
void GetReferences(Array<Guid>& assets, Array<String>& files) const override;
|
void GetReferences(Array<Guid>& assets, Array<String>& files) const override;
|
||||||
bool Save(const StringView& path = StringView::Empty) override;
|
bool Save(const StringView& path = StringView::Empty) override;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the particle emitter has valid shader code present.
|
||||||
|
/// </summary>
|
||||||
|
API_PROPERTY() bool HasShaderCode() const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -262,16 +262,16 @@ void CharacterController::OnDebugDrawSelected()
|
|||||||
Quaternion rotation = Quaternion::Euler(90, 0, 0);
|
Quaternion rotation = Quaternion::Euler(90, 0, 0);
|
||||||
const Vector3 position = GetControllerPosition();
|
const Vector3 position = GetControllerPosition();
|
||||||
DEBUG_DRAW_WIRE_CAPSULE(position, rotation, _radius, _height, Color::GreenYellow, 0, false);
|
DEBUG_DRAW_WIRE_CAPSULE(position, rotation, _radius, _height, Color::GreenYellow, 0, false);
|
||||||
if (_contactOffset > 0)
|
|
||||||
DEBUG_DRAW_WIRE_CAPSULE(position, rotation, _radius - _contactOffset, _height, Color::Blue.AlphaMultiplied(0.4f), 0, false);
|
|
||||||
#if 1
|
|
||||||
// More technical visuals debugging
|
|
||||||
if (_controller)
|
if (_controller)
|
||||||
{
|
{
|
||||||
|
// Physics backend capsule shape
|
||||||
float height, radius;
|
float height, radius;
|
||||||
GetControllerSize(height, radius);
|
GetControllerSize(height, radius);
|
||||||
Vector3 base = PhysicsBackend::GetControllerBasePosition(_controller);
|
|
||||||
Vector3 pos = PhysicsBackend::GetControllerPosition(_controller);
|
Vector3 pos = PhysicsBackend::GetControllerPosition(_controller);
|
||||||
|
DEBUG_DRAW_WIRE_CAPSULE(pos, rotation, radius, height, Color::Blue.AlphaMultiplied(0.2f), 0, false);
|
||||||
|
#if 0
|
||||||
|
// More technical visuals debugging
|
||||||
|
Vector3 base = PhysicsBackend::GetControllerBasePosition(_controller);
|
||||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(base, 5.0f), Color::Red, 0, false);
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(base, 5.0f), Color::Red, 0, false);
|
||||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos, 4.0f), Color::Red, 0, false);
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos, 4.0f), Color::Red, 0, false);
|
||||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos + Vector3(0, height * 0.5f, 0), 2.0f), Color::Red, 0, false);
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos + Vector3(0, height * 0.5f, 0), 2.0f), Color::Red, 0, false);
|
||||||
@@ -279,17 +279,8 @@ void CharacterController::OnDebugDrawSelected()
|
|||||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos + Vector3(0, height * 0.5f, 0), radius), Color::Red.AlphaMultiplied(0.5f), 0, false);
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos + Vector3(0, height * 0.5f, 0), radius), Color::Red.AlphaMultiplied(0.5f), 0, false);
|
||||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos - Vector3(0, height * 0.5f, 0), radius), Color::Red.AlphaMultiplied(0.5f), 0, false);
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos - Vector3(0, height * 0.5f, 0), radius), Color::Red.AlphaMultiplied(0.5f), 0, false);
|
||||||
DEBUG_DRAW_WIRE_CYLINDER(pos, Quaternion::Identity, radius, height, Color::Red.AlphaMultiplied(0.2f), 0, false);
|
DEBUG_DRAW_WIRE_CYLINDER(pos, Quaternion::Identity, radius, height, Color::Red.AlphaMultiplied(0.2f), 0, false);
|
||||||
}
|
|
||||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(position, 3.0f), Color::GreenYellow, 0, false);
|
|
||||||
#else
|
|
||||||
if (_controller)
|
|
||||||
{
|
|
||||||
// Physics backend capsule shape
|
|
||||||
float height, radius;
|
|
||||||
GetControllerSize(height, radius);
|
|
||||||
DEBUG_DRAW_WIRE_CAPSULE(PhysicsBackend::GetControllerPosition(_controller), rotation, radius, height, Color::Blue.AlphaMultiplied(0.2f), 0, false);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Base
|
// Base
|
||||||
Collider::OnDebugDrawSelected();
|
Collider::OnDebugDrawSelected();
|
||||||
|
|||||||
@@ -78,6 +78,32 @@ TEST_CASE("Array")
|
|||||||
|
|
||||||
TEST_CASE("BitArray")
|
TEST_CASE("BitArray")
|
||||||
{
|
{
|
||||||
|
SECTION("Test Access")
|
||||||
|
{
|
||||||
|
BitArray<> a1;
|
||||||
|
CHECK(a1.Count() == 0);
|
||||||
|
for (int32 i = 0; i < 310; i++)
|
||||||
|
{
|
||||||
|
a1.Add(false);
|
||||||
|
}
|
||||||
|
CHECK(a1.Count() == 310);
|
||||||
|
a1.Resize(300);
|
||||||
|
CHECK(a1.Count() == 300);
|
||||||
|
CHECK(a1.Capacity() >= 300);
|
||||||
|
a1.SetAll(true);
|
||||||
|
a1.SetAll(false);
|
||||||
|
for (int32 i = 0; i < 300; i++)
|
||||||
|
{
|
||||||
|
a1.Set(i, true);
|
||||||
|
for (int32 j = 0; j < 300; j++)
|
||||||
|
{
|
||||||
|
bool expected = j == i;
|
||||||
|
CHECK(a1.Get(j) == expected);
|
||||||
|
}
|
||||||
|
a1.Set(i, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("Test Allocators")
|
SECTION("Test Allocators")
|
||||||
{
|
{
|
||||||
BitArray<> a1;
|
BitArray<> a1;
|
||||||
@@ -142,7 +168,7 @@ TEST_CASE("BitArray")
|
|||||||
|
|
||||||
// Generate some random data for testing
|
// Generate some random data for testing
|
||||||
BitArray<> testData;
|
BitArray<> testData;
|
||||||
testData.Resize(32);
|
testData.Resize(128);
|
||||||
RandomStream rand(101);
|
RandomStream rand(101);
|
||||||
for (int32 i = 0; i < testData.Count(); i++)
|
for (int32 i = 0; i < testData.Count(); i++)
|
||||||
testData.Set(i, rand.GetBool());
|
testData.Set(i, rand.GetBool());
|
||||||
@@ -151,8 +177,8 @@ TEST_CASE("BitArray")
|
|||||||
{
|
{
|
||||||
const BitArray<> a1(testData);
|
const BitArray<> a1(testData);
|
||||||
const BitArray<InlinedAllocation<8>> a2(testData);
|
const BitArray<InlinedAllocation<8>> a2(testData);
|
||||||
const BitArray<InlinedAllocation<64>> a3(testData);
|
const BitArray<InlinedAllocation<256>> a3(testData);
|
||||||
const BitArray<FixedAllocation<64>> a4(testData);
|
const BitArray<FixedAllocation<256>> a4(testData);
|
||||||
CHECK(a1 == testData);
|
CHECK(a1 == testData);
|
||||||
CHECK(a2 == testData);
|
CHECK(a2 == testData);
|
||||||
CHECK(a3 == testData);
|
CHECK(a3 == testData);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "Engine/Graphics/Textures/TextureData.h"
|
#include "Engine/Graphics/Textures/TextureData.h"
|
||||||
#include "Engine/Graphics/PixelFormatExtensions.h"
|
#include "Engine/Graphics/PixelFormatExtensions.h"
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
|
#include "Engine/Platform/MessageBox.h"
|
||||||
#include "Engine/Graphics/GPUDevice.h"
|
#include "Engine/Graphics/GPUDevice.h"
|
||||||
#endif
|
#endif
|
||||||
#include "Engine/Utilities/AnsiPathTempFile.h"
|
#include "Engine/Utilities/AnsiPathTempFile.h"
|
||||||
@@ -358,6 +359,9 @@ HRESULT LoadFromEXRFile(const StringView& path, DirectX::ScratchImage& image)
|
|||||||
free(pixels);
|
free(pixels);
|
||||||
return result;
|
return result;
|
||||||
#else
|
#else
|
||||||
|
#if USE_EDITOR
|
||||||
|
MessageBox::Show(TEXT("EXR format is not supported."), TEXT("Import warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning);
|
||||||
|
#endif
|
||||||
LOG(Warning, "EXR format is not supported.");
|
LOG(Warning, "EXR format is not supported.");
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "Engine/Graphics/PixelFormatExtensions.h"
|
#include "Engine/Graphics/PixelFormatExtensions.h"
|
||||||
#include "Engine/Utilities/AnsiPathTempFile.h"
|
#include "Engine/Utilities/AnsiPathTempFile.h"
|
||||||
#include "Engine/Platform/File.h"
|
#include "Engine/Platform/File.h"
|
||||||
|
#include "Engine/Platform/MessageBox.h"
|
||||||
|
|
||||||
#define STBI_ASSERT(x) ASSERT(x)
|
#define STBI_ASSERT(x) ASSERT(x)
|
||||||
#define STBI_MALLOC(sz) Allocator::Allocate(sz)
|
#define STBI_MALLOC(sz) Allocator::Allocate(sz)
|
||||||
@@ -286,21 +287,27 @@ bool TextureTool::ExportTextureStb(ImageType type, const StringView& path, const
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ImageType::GIF:
|
case ImageType::GIF:
|
||||||
|
MessageBox::Show(TEXT("GIF format is not supported."), TEXT("Export warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning);
|
||||||
LOG(Warning, "GIF format is not supported.");
|
LOG(Warning, "GIF format is not supported.");
|
||||||
break;
|
break;
|
||||||
case ImageType::TIFF:
|
case ImageType::TIFF:
|
||||||
|
MessageBox::Show(TEXT("TIFF format is not supported."), TEXT("Export warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning);
|
||||||
LOG(Warning, "GIF format is not supported.");
|
LOG(Warning, "GIF format is not supported.");
|
||||||
break;
|
break;
|
||||||
case ImageType::DDS:
|
case ImageType::DDS:
|
||||||
|
MessageBox::Show(TEXT("DDS format is not supported."), TEXT("Export warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning);
|
||||||
LOG(Warning, "DDS format is not supported.");
|
LOG(Warning, "DDS format is not supported.");
|
||||||
break;
|
break;
|
||||||
case ImageType::RAW:
|
case ImageType::RAW:
|
||||||
|
MessageBox::Show(TEXT("RAW format is not supported."), TEXT("Export warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning);
|
||||||
LOG(Warning, "RAW format is not supported.");
|
LOG(Warning, "RAW format is not supported.");
|
||||||
break;
|
break;
|
||||||
case ImageType::EXR:
|
case ImageType::EXR:
|
||||||
|
MessageBox::Show(TEXT("EXR format is not supported."), TEXT("Export warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning);
|
||||||
LOG(Warning, "EXR format is not supported.");
|
LOG(Warning, "EXR format is not supported.");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
MessageBox::Show(TEXT("Unknown format."), TEXT("Export warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning);
|
||||||
LOG(Warning, "Unknown format.");
|
LOG(Warning, "Unknown format.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -434,17 +441,21 @@ bool TextureTool::ImportTextureStb(ImageType type, const StringView& path, Textu
|
|||||||
|
|
||||||
free(pixels);
|
free(pixels);
|
||||||
#else
|
#else
|
||||||
|
MessageBox::Show(TEXT("EXR format is not supported."), TEXT("Import warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning);
|
||||||
LOG(Warning, "EXR format is not supported.");
|
LOG(Warning, "EXR format is not supported.");
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ImageType::DDS:
|
case ImageType::DDS:
|
||||||
|
MessageBox::Show(TEXT("DDS format is not supported."), TEXT("Import warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning);
|
||||||
LOG(Warning, "DDS format is not supported.");
|
LOG(Warning, "DDS format is not supported.");
|
||||||
break;
|
break;
|
||||||
case ImageType::TIFF:
|
case ImageType::TIFF:
|
||||||
|
MessageBox::Show(TEXT("TIFF format is not supported."), TEXT("Import warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning);
|
||||||
LOG(Warning, "TIFF format is not supported.");
|
LOG(Warning, "TIFF format is not supported.");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
MessageBox::Show(TEXT("Unknown format."), TEXT("Import warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning);
|
||||||
LOG(Warning, "Unknown format.");
|
LOG(Warning, "Unknown format.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// Ben Golus
|
// Ben Golus
|
||||||
// https://bgolus.medium.com/the-best-darn-grid-shader-yet-727f9278b9d8#3e73
|
// https://bgolus.medium.com/the-best-darn-grid-shader-yet-727f9278b9d8#3e73
|
||||||
|
|
||||||
#define USE_FORWARD true;
|
#define MIN_DERIV 0.00001f
|
||||||
|
|
||||||
#include "./Flax/Common.hlsl"
|
#include "./Flax/Common.hlsl"
|
||||||
|
|
||||||
@@ -61,11 +61,6 @@ float remap(float origFrom, float origTo, float targetFrom, float targetTo, floa
|
|||||||
return lerp(targetFrom, targetTo, rel);
|
return lerp(targetFrom, targetTo, rel);
|
||||||
}
|
}
|
||||||
|
|
||||||
float ddLength(float a)
|
|
||||||
{
|
|
||||||
return length(float2(ddx(a), ddy(a)));
|
|
||||||
}
|
|
||||||
|
|
||||||
float GetLine(float pos, float scale, float thickness)
|
float GetLine(float pos, float scale, float thickness)
|
||||||
{
|
{
|
||||||
float lineWidth = thickness;
|
float lineWidth = thickness;
|
||||||
@@ -73,7 +68,7 @@ float GetLine(float pos, float scale, float thickness)
|
|||||||
|
|
||||||
float2 uvDDXY = float2(ddx(coord), ddy(coord));
|
float2 uvDDXY = float2(ddx(coord), ddy(coord));
|
||||||
|
|
||||||
float deriv = float(length(uvDDXY.xy));
|
float deriv = max(float(length(uvDDXY.xy)), MIN_DERIV);
|
||||||
float drawWidth = clamp(lineWidth, deriv, 0.5);
|
float drawWidth = clamp(lineWidth, deriv, 0.5);
|
||||||
float lineAA = deriv * 1.5;
|
float lineAA = deriv * 1.5;
|
||||||
float gridUV = abs(coord);
|
float gridUV = abs(coord);
|
||||||
@@ -92,7 +87,7 @@ float GetGrid(float3 pos, float scale, float thickness)
|
|||||||
|
|
||||||
float4 uvDDXY = float4(ddx(coord), ddy(coord));
|
float4 uvDDXY = float4(ddx(coord), ddy(coord));
|
||||||
|
|
||||||
float2 deriv = float2(length(uvDDXY.xz), length(uvDDXY.yw));
|
float2 deriv = max(float2(length(uvDDXY.xz), length(uvDDXY.yw)), float2(MIN_DERIV, MIN_DERIV));
|
||||||
float2 drawWidth = clamp(lineWidth, deriv, 0.5);
|
float2 drawWidth = clamp(lineWidth, deriv, 0.5);
|
||||||
float2 lineAA = deriv * 1.5;
|
float2 lineAA = deriv * 1.5;
|
||||||
float2 gridUV = 1.0 - abs(frac(coord) * 2.0 - 1.0);
|
float2 gridUV = 1.0 - abs(frac(coord) * 2.0 - 1.0);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace Flax.Build
|
|||||||
private static Platform _buildPlatform;
|
private static Platform _buildPlatform;
|
||||||
private static Platform[] _platforms;
|
private static Platform[] _platforms;
|
||||||
private Dictionary<TargetArchitecture, Toolchain> _toolchains;
|
private Dictionary<TargetArchitecture, Toolchain> _toolchains;
|
||||||
|
private uint _failedArchitectures = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current target platform that build tool runs on.
|
/// Gets the current target platform that build tool runs on.
|
||||||
@@ -251,7 +252,8 @@ namespace Flax.Build
|
|||||||
public Toolchain TryGetToolchain(TargetArchitecture targetArchitecture)
|
public Toolchain TryGetToolchain(TargetArchitecture targetArchitecture)
|
||||||
{
|
{
|
||||||
Toolchain result = null;
|
Toolchain result = null;
|
||||||
if (HasRequiredSDKsInstalled)
|
uint failedMask = 1u << (int)targetArchitecture; // Skip retrying if it already failed once on this arch
|
||||||
|
if (HasRequiredSDKsInstalled && (_failedArchitectures & failedMask) != failedMask)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -259,6 +261,7 @@ namespace Flax.Build
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
_failedArchitectures |= failedMask;
|
||||||
Log.Exception(ex);
|
Log.Exception(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user