Merge remote-tracking branch 'origin/master' into 1.9
This commit is contained in:
@@ -248,6 +248,11 @@ namespace FlaxEditor
|
||||
/// </summary>
|
||||
public event Action PlayModeEnd;
|
||||
|
||||
/// <summary>
|
||||
/// Fired on Editor update
|
||||
/// </summary>
|
||||
public event Action EditorUpdate;
|
||||
|
||||
internal Editor()
|
||||
{
|
||||
Instance = this;
|
||||
@@ -486,6 +491,8 @@ namespace FlaxEditor
|
||||
{
|
||||
StateMachine.CurrentState.UpdateFPS();
|
||||
}
|
||||
|
||||
EditorUpdate?.Invoke();
|
||||
|
||||
// Update modules
|
||||
for (int i = 0; i < _modules.Count; i++)
|
||||
|
||||
@@ -103,9 +103,9 @@ namespace FlaxEditor.GUI
|
||||
|
||||
private Rectangle Button1Rect => new Rectangle(Height + ButtonsOffset, 0, ButtonsSize, ButtonsSize);
|
||||
|
||||
private Rectangle Button2Rect => new Rectangle(Height + ButtonsOffset, ButtonsSize, ButtonsSize, ButtonsSize);
|
||||
private Rectangle Button2Rect => new Rectangle(Height + ButtonsOffset, ButtonsSize + 2, ButtonsSize, ButtonsSize);
|
||||
|
||||
private Rectangle Button3Rect => new Rectangle(Height + ButtonsOffset, ButtonsSize * 2, ButtonsSize, ButtonsSize);
|
||||
private Rectangle Button3Rect => new Rectangle(Height + ButtonsOffset, (ButtonsSize + 2) * 2, ButtonsSize, ButtonsSize);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
@@ -147,6 +147,13 @@ namespace FlaxEditor.GUI
|
||||
style.Foreground,
|
||||
TextAlignment.Near,
|
||||
TextAlignment.Center);
|
||||
Render2D.DrawText(
|
||||
style.FontSmall,
|
||||
$"{TypeUtils.GetTypeDisplayName(Validator.AssetType.Type)}",
|
||||
new Rectangle(button1Rect.Right + 2, ButtonsSize + 2, sizeForTextLeft, ButtonsSize),
|
||||
style.ForegroundGrey,
|
||||
TextAlignment.Near,
|
||||
TextAlignment.Center);
|
||||
}
|
||||
}
|
||||
// Check if has no item but has an asset (eg. virtual asset)
|
||||
@@ -169,6 +176,13 @@ namespace FlaxEditor.GUI
|
||||
style.Foreground,
|
||||
TextAlignment.Near,
|
||||
TextAlignment.Center);
|
||||
Render2D.DrawText(
|
||||
style.FontSmall,
|
||||
$"{TypeUtils.GetTypeDisplayName(Validator.AssetType.Type)}",
|
||||
new Rectangle(button1Rect.Right + 2, ButtonsSize + 2, sizeForTextLeft, ButtonsSize),
|
||||
style.ForegroundGrey,
|
||||
TextAlignment.Near,
|
||||
TextAlignment.Center);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -176,6 +190,24 @@ namespace FlaxEditor.GUI
|
||||
// No element selected
|
||||
Render2D.FillRectangle(iconRect, style.BackgroundNormal);
|
||||
Render2D.DrawText(style.FontMedium, "No asset\nselected", iconRect, Color.Orange, TextAlignment.Center, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, Height / DefaultIconSize);
|
||||
float sizeForTextLeft = Width - button1Rect.Right;
|
||||
if (sizeForTextLeft > 30)
|
||||
{
|
||||
Render2D.DrawText(
|
||||
style.FontSmall,
|
||||
$"None",
|
||||
new Rectangle(button1Rect.Right + 2, 0, sizeForTextLeft, ButtonsSize),
|
||||
style.Foreground,
|
||||
TextAlignment.Near,
|
||||
TextAlignment.Center);
|
||||
Render2D.DrawText(
|
||||
style.FontSmall,
|
||||
$"{TypeUtils.GetTypeDisplayName(Validator.AssetType.Type)}",
|
||||
new Rectangle(button1Rect.Right + 2, ButtonsSize + 2, sizeForTextLeft, ButtonsSize),
|
||||
style.ForegroundGrey,
|
||||
TextAlignment.Near,
|
||||
TextAlignment.Center);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if drag is over
|
||||
|
||||
@@ -629,7 +629,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
|
||||
internal void MoveTabRight(int index)
|
||||
{
|
||||
if (index < _tabs.Count - 2)
|
||||
if (index < _tabs.Count - 1)
|
||||
{
|
||||
var tab = _tabs[index];
|
||||
_tabs.RemoveAt(index);
|
||||
|
||||
@@ -51,6 +51,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
public DockWindow StartDragAsyncWindow;
|
||||
|
||||
private Rectangle HeaderRectangle => new Rectangle(0, 0, Width, DockPanel.DefaultHeaderHeight);
|
||||
private bool IsSingleFloatingWindow => _panel.TabsCount == 1 && _panel.IsFloating && _panel.ChildPanelsCount == 0;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DockPanelProxy"/> class.
|
||||
@@ -187,6 +188,10 @@ namespace FlaxEditor.GUI.Docking
|
||||
var headerRect = HeaderRectangle;
|
||||
var tabsCount = _panel.TabsCount;
|
||||
|
||||
// Return and don't draw tab if only 1 window and it is floating
|
||||
if (IsSingleFloatingWindow)
|
||||
return;
|
||||
|
||||
// Check if has only one window docked
|
||||
if (tabsCount == 1)
|
||||
{
|
||||
@@ -321,6 +326,9 @@ namespace FlaxEditor.GUI.Docking
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
|
||||
{
|
||||
if (IsSingleFloatingWindow)
|
||||
return base.OnMouseDoubleClick(location, button);
|
||||
|
||||
// Maximize/restore on double click
|
||||
var tab = GetTabAtPos(location, out _);
|
||||
var rootWindow = tab?.RootWindow;
|
||||
@@ -339,6 +347,8 @@ namespace FlaxEditor.GUI.Docking
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (IsSingleFloatingWindow)
|
||||
return base.OnMouseDown(location, button);
|
||||
MouseDownWindow = GetTabAtPos(location, out IsMouseDownOverCross);
|
||||
|
||||
// Check buttons
|
||||
@@ -368,6 +378,9 @@ namespace FlaxEditor.GUI.Docking
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (IsSingleFloatingWindow)
|
||||
return base.OnMouseUp(location, button);
|
||||
|
||||
// Check tabs under mouse position at the beginning and at the end
|
||||
var tab = GetTabAtPos(location, out var overCross);
|
||||
|
||||
@@ -410,7 +423,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
public override void OnMouseMove(Float2 location)
|
||||
{
|
||||
MousePosition = location;
|
||||
if (IsMouseLeftButtonDown)
|
||||
if (IsMouseLeftButtonDown && !IsSingleFloatingWindow)
|
||||
{
|
||||
// Check if mouse is outside the header
|
||||
if (!HeaderRectangle.Contains(location))
|
||||
@@ -501,7 +514,10 @@ namespace FlaxEditor.GUI.Docking
|
||||
/// <inheritdoc />
|
||||
public override void GetDesireClientArea(out Rectangle rect)
|
||||
{
|
||||
rect = new Rectangle(0, DockPanel.DefaultHeaderHeight, Width, Height - DockPanel.DefaultHeaderHeight);
|
||||
if (IsSingleFloatingWindow)
|
||||
rect = new Rectangle(0, 0, Width, Height);
|
||||
else
|
||||
rect = new Rectangle(0, DockPanel.DefaultHeaderHeight, Width, Height - DockPanel.DefaultHeaderHeight);
|
||||
}
|
||||
|
||||
private DragDropEffect TrySelectTabUnderLocation(ref Float2 location)
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace FlaxEditor.GUI
|
||||
ContentItem = item;
|
||||
ContentItem.AddReference(this);
|
||||
|
||||
Name = item.ShortName;
|
||||
OnItemRenamed(item);
|
||||
TooltipText = item.Path;
|
||||
|
||||
Height = IconSize + 4;
|
||||
@@ -82,7 +82,9 @@ namespace FlaxEditor.GUI
|
||||
/// <inheritdoc />
|
||||
public void OnItemRenamed(ContentItem item)
|
||||
{
|
||||
Name = ContentItem.ShortName;
|
||||
Name = item.ShortName;
|
||||
if (item is ScriptItem)
|
||||
Name = item.FileName; // Show extension for scripts (esp. for .h and .cpp files of the same name)
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -342,9 +342,10 @@ namespace FlaxEditor.Modules
|
||||
{
|
||||
foreach (var contentItem in items)
|
||||
{
|
||||
var name = contentItem.ShortName;
|
||||
if (contentItem.IsAsset)
|
||||
{
|
||||
if (nameRegex.Match(contentItem.ShortName).Success)
|
||||
if (nameRegex.Match(name).Success)
|
||||
{
|
||||
var asset = contentItem as AssetItem;
|
||||
if (asset == null || !typeRegex.Match(asset.TypeName).Success)
|
||||
@@ -358,7 +359,7 @@ namespace FlaxEditor.Modules
|
||||
var splits = asset.TypeName.Split('.');
|
||||
finalName = splits[splits.Length - 1];
|
||||
}
|
||||
matches.Add(new SearchResult { Name = asset.ShortName, Type = finalName, Item = asset });
|
||||
matches.Add(new SearchResult { Name = name, Type = finalName, Item = asset });
|
||||
}
|
||||
}
|
||||
else if (contentItem.IsFolder)
|
||||
@@ -370,11 +371,12 @@ namespace FlaxEditor.Modules
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nameRegex.Match(contentItem.ShortName).Success && typeRegex.Match(contentItem.GetType().Name).Success)
|
||||
if (nameRegex.Match(name).Success && typeRegex.Match(contentItem.GetType().Name).Success)
|
||||
{
|
||||
string finalName = contentItem.GetType().Name.Replace("Item", "");
|
||||
|
||||
matches.Add(new SearchResult { Name = contentItem.ShortName, Type = finalName, Item = contentItem });
|
||||
if (contentItem is ScriptItem)
|
||||
name = contentItem.FileName; // Show extension for scripts (esp. for .h and .cpp files of the same name)
|
||||
matches.Add(new SearchResult { Name = name, Type = finalName, Item = contentItem });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,54 +21,75 @@ namespace FlaxEditor.Windows.Assets
|
||||
/// <seealso cref="FlaxEditor.Windows.Assets.AssetEditorWindow" />
|
||||
public sealed class TextureWindow : AssetEditorWindowBase<Texture>
|
||||
{
|
||||
private sealed class ProxyEditor : GenericEditor
|
||||
/// <summary>
|
||||
/// Properties base class.
|
||||
/// </summary>
|
||||
public class PropertiesProxyBase
|
||||
{
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
internal TextureWindow _window;
|
||||
|
||||
/// <summary>
|
||||
/// Gathers parameters from the specified texture.
|
||||
/// </summary>
|
||||
/// <param name="window">The asset window.</param>
|
||||
public virtual void OnLoad(TextureWindow window)
|
||||
{
|
||||
var window = ((PropertiesProxy)Values[0])._window;
|
||||
var texture = window?.Asset;
|
||||
if (texture == null || !texture.IsLoaded)
|
||||
{
|
||||
layout.Label("Loading...", TextAlignment.Center);
|
||||
return;
|
||||
}
|
||||
|
||||
// Texture info
|
||||
var general = layout.Group("General");
|
||||
general.Label("Format: " + texture.Format);
|
||||
general.Label(string.Format("Size: {0}x{1}", texture.Width, texture.Height)).AddCopyContextMenu();
|
||||
general.Label("Mip levels: " + texture.MipLevels);
|
||||
general.Label("Memory usage: " + Utilities.Utils.FormatBytesCount(texture.TotalMemoryUsage)).AddCopyContextMenu();
|
||||
|
||||
// Texture properties
|
||||
var properties = layout.Group("Properties");
|
||||
var textureGroup = new CustomValueContainer(new ScriptType(typeof(int)), texture.TextureGroup,
|
||||
(instance, index) => texture.TextureGroup,
|
||||
(instance, index, value) =>
|
||||
{
|
||||
texture.TextureGroup = (int)value;
|
||||
window.MarkAsEdited();
|
||||
});
|
||||
properties.Property("Texture Group", textureGroup, new TextureGroupEditor(), "The texture group used by this texture.");
|
||||
|
||||
// Import settings
|
||||
base.Initialize(layout);
|
||||
|
||||
// Reimport
|
||||
layout.Space(10);
|
||||
var reimportButton = layout.Button("Reimport");
|
||||
reimportButton.Button.Clicked += () => ((PropertiesProxy)Values[0]).Reimport();
|
||||
// Link
|
||||
_window = window;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears temporary data.
|
||||
/// </summary>
|
||||
public void OnClean()
|
||||
{
|
||||
// Unlink
|
||||
_window = null;
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(ProxyEditor))]
|
||||
private sealed class TexturePropertiesProxy : PropertiesProxyBase
|
||||
{
|
||||
private sealed class ProxyEditor : GenericEditor
|
||||
{
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var window = ((TexturePropertiesProxy)Values[0])._window;
|
||||
var texture = window?.Asset;
|
||||
if (texture == null || !texture.IsLoaded)
|
||||
{
|
||||
layout.Label("Loading...", TextAlignment.Center);
|
||||
return;
|
||||
}
|
||||
|
||||
// Texture info
|
||||
var general = layout.Group("General");
|
||||
general.Label("Format: " + texture.Format);
|
||||
general.Label(string.Format("Size: {0}x{1}", texture.Width, texture.Height)).AddCopyContextMenu();
|
||||
general.Label("Mip levels: " + texture.MipLevels);
|
||||
general.Label("Memory usage: " + Utilities.Utils.FormatBytesCount(texture.TotalMemoryUsage)).AddCopyContextMenu();
|
||||
|
||||
// Texture properties
|
||||
var properties = layout.Group("Properties");
|
||||
var textureGroup = new CustomValueContainer(new ScriptType(typeof(int)), texture.TextureGroup,
|
||||
(instance, index) => texture.TextureGroup,
|
||||
(instance, index, value) =>
|
||||
{
|
||||
texture.TextureGroup = (int)value;
|
||||
window.MarkAsEdited();
|
||||
});
|
||||
properties.Property("Texture Group", textureGroup, new TextureGroupEditor(), "The texture group used by this texture.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The texture properties proxy object.
|
||||
/// The texture import properties proxy object.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(ProxyEditor))]
|
||||
private sealed class PropertiesProxy
|
||||
private sealed class ImportPropertiesProxy : PropertiesProxyBase
|
||||
{
|
||||
internal TextureWindow _window;
|
||||
|
||||
[EditorOrder(1000), EditorDisplay("Import Settings", EditorDisplayAttribute.InlineStyle)]
|
||||
public FlaxEngine.Tools.TextureTool.Options ImportSettings = new();
|
||||
|
||||
@@ -76,10 +97,9 @@ namespace FlaxEditor.Windows.Assets
|
||||
/// Gathers parameters from the specified texture.
|
||||
/// </summary>
|
||||
/// <param name="window">The asset window.</param>
|
||||
public void OnLoad(TextureWindow window)
|
||||
public override void OnLoad(TextureWindow window)
|
||||
{
|
||||
// Link
|
||||
_window = window;
|
||||
base.OnLoad(window);
|
||||
|
||||
// Try to restore target asset texture import options (useful for fast reimport)
|
||||
Editor.TryRestoreImportOptions(ref ImportSettings, window.Item.Path);
|
||||
@@ -109,22 +129,85 @@ namespace FlaxEditor.Windows.Assets
|
||||
public void DiscardChanges()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears temporary data.
|
||||
/// </summary>
|
||||
public void OnClean()
|
||||
|
||||
private sealed class ProxyEditor : GenericEditor
|
||||
{
|
||||
// Unlink
|
||||
_window = null;
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
// Import settings
|
||||
base.Initialize(layout);
|
||||
|
||||
// Reimport
|
||||
layout.Space(10);
|
||||
var reimportButton = layout.Button("Reimport");
|
||||
reimportButton.Button.Clicked += () => ((ImportPropertiesProxy)Values[0]).Reimport();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class Tab : GUI.Tabs.Tab
|
||||
{
|
||||
/// <summary>
|
||||
/// The presenter to use in the tab.
|
||||
/// </summary>
|
||||
public CustomEditorPresenter Presenter;
|
||||
|
||||
/// <summary>
|
||||
/// The proxy to use in the tab.
|
||||
/// </summary>
|
||||
public PropertiesProxyBase Proxy;
|
||||
|
||||
public Tab(string text, TextureWindow window, bool modifiesAsset = true)
|
||||
: base(text)
|
||||
{
|
||||
var scrollPanel = new Panel(ScrollBars.Vertical)
|
||||
{
|
||||
AnchorPreset = AnchorPresets.StretchAll,
|
||||
Offsets = Margin.Zero,
|
||||
Parent = this
|
||||
};
|
||||
|
||||
Presenter = new CustomEditorPresenter(null);
|
||||
Presenter.Panel.Parent = scrollPanel;
|
||||
if (modifiesAsset)
|
||||
Presenter.Modified += window.MarkAsEdited;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
Presenter.Deselect();
|
||||
Presenter = null;
|
||||
Proxy = null;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
private class TextureTab : Tab
|
||||
{
|
||||
public TextureTab(TextureWindow window)
|
||||
: base("Texture", window)
|
||||
{
|
||||
Proxy = new TexturePropertiesProxy();
|
||||
Presenter.Select(Proxy);
|
||||
}
|
||||
}
|
||||
|
||||
private class ImportTab : Tab
|
||||
{
|
||||
public ImportTab(TextureWindow window)
|
||||
: base("Import", window)
|
||||
{
|
||||
Proxy = new ImportPropertiesProxy();
|
||||
Presenter.Select(Proxy);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly GUI.Tabs.Tabs _tabs;
|
||||
private readonly SplitPanel _split;
|
||||
private readonly TexturePreview _preview;
|
||||
private readonly CustomEditorPresenter _propertiesEditor;
|
||||
private readonly ToolStripButton _saveButton;
|
||||
private readonly PropertiesProxy _properties;
|
||||
private bool _isWaitingForLoad;
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -145,12 +228,20 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
Parent = _split.Panel1
|
||||
};
|
||||
|
||||
// Properties tabs
|
||||
_tabs = new()
|
||||
{
|
||||
AnchorPreset = AnchorPresets.StretchAll,
|
||||
Offsets = Margin.Zero,
|
||||
TabsSize = new Float2(60, 20),
|
||||
TabsTextHorizontalAlignment = TextAlignment.Center,
|
||||
UseScroll = true,
|
||||
Parent = _split.Panel2
|
||||
};
|
||||
|
||||
// Texture properties editor
|
||||
_propertiesEditor = new CustomEditorPresenter(null);
|
||||
_propertiesEditor.Panel.Parent = _split.Panel2;
|
||||
_properties = new PropertiesProxy();
|
||||
_propertiesEditor.Select(_properties);
|
||||
_tabs.AddTab(new TextureTab(this));
|
||||
_tabs.AddTab(new ImportTab(this));
|
||||
|
||||
// Toolstrip
|
||||
_saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
|
||||
@@ -164,7 +255,11 @@ namespace FlaxEditor.Windows.Assets
|
||||
/// <inheritdoc />
|
||||
protected override void UnlinkItem()
|
||||
{
|
||||
_properties.OnClean();
|
||||
foreach (var child in _tabs.Children)
|
||||
{
|
||||
if (child is Tab tab && tab.Proxy != null)
|
||||
tab.Proxy.OnClean();
|
||||
}
|
||||
_preview.Asset = null;
|
||||
_isWaitingForLoad = false;
|
||||
|
||||
@@ -195,15 +290,6 @@ namespace FlaxEditor.Windows.Assets
|
||||
base.UpdateToolstrip();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnClose()
|
||||
{
|
||||
// Discard unsaved changes
|
||||
_properties.DiscardChanges();
|
||||
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Save()
|
||||
{
|
||||
@@ -231,8 +317,14 @@ namespace FlaxEditor.Windows.Assets
|
||||
_isWaitingForLoad = false;
|
||||
|
||||
// Init properties and parameters proxy
|
||||
_properties.OnLoad(this);
|
||||
_propertiesEditor.BuildLayout();
|
||||
foreach (var child in _tabs.Children)
|
||||
{
|
||||
if (child is Tab tab && tab.Proxy != null)
|
||||
{
|
||||
tab.Proxy.OnLoad(this);
|
||||
tab.Presenter.BuildLayout();
|
||||
}
|
||||
}
|
||||
|
||||
// Setup
|
||||
ClearEditedFlag();
|
||||
|
||||
@@ -139,8 +139,8 @@ namespace FlaxEditor.Windows.Search
|
||||
{
|
||||
var item = items[i];
|
||||
SearchItem searchItem;
|
||||
if (item.Item is AssetItem assetItem)
|
||||
searchItem = new AssetSearchItem(item.Name, item.Type, assetItem, this, itemsWidth, itemHeight);
|
||||
if (item.Item is ContentItem contentItem)
|
||||
searchItem = new ContentSearchItem(item.Name, item.Type, contentItem, this, itemsWidth, itemHeight);
|
||||
else
|
||||
searchItem = new SearchItem(item.Name, item.Type, item.Item, this, itemsWidth, itemHeight);
|
||||
searchItem.Y = i * itemHeight;
|
||||
|
||||
@@ -113,17 +113,17 @@ namespace FlaxEditor.Windows.Search
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="SearchItem"/> for assets. Supports using asset thumbnail.
|
||||
/// The <see cref="SearchItem"/> for assets. Supports using content item thumbnail.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Windows.Search.SearchItem" />
|
||||
/// <seealso cref="FlaxEditor.Content.IContentItemOwner" />
|
||||
internal class AssetSearchItem : SearchItem, IContentItemOwner
|
||||
internal class ContentSearchItem : SearchItem, IContentItemOwner
|
||||
{
|
||||
private AssetItem _asset;
|
||||
private FlaxEditor.GUI.ContextMenu.ContextMenu _cm;
|
||||
private ContentItem _asset;
|
||||
private ContextMenu _cm;
|
||||
|
||||
/// <inheritdoc />
|
||||
public AssetSearchItem(string name, string type, AssetItem item, ContentFinder finder, float width, float height)
|
||||
public ContentSearchItem(string name, string type, ContentItem item, ContentFinder finder, float width, float height)
|
||||
: base(name, type, item, finder, width, height)
|
||||
{
|
||||
_asset = item;
|
||||
@@ -136,31 +136,41 @@ namespace FlaxEditor.Windows.Search
|
||||
/// <inheritdoc />
|
||||
public override bool OnShowTooltip(out string text, out Float2 location, out Rectangle area)
|
||||
{
|
||||
if (string.IsNullOrEmpty(TooltipText) && Item is AssetItem assetItem)
|
||||
if (string.IsNullOrEmpty(TooltipText) && Item is ContentItem contentItem)
|
||||
{
|
||||
assetItem.UpdateTooltipText();
|
||||
TooltipText = assetItem.TooltipText;
|
||||
contentItem.UpdateTooltipText();
|
||||
TooltipText = contentItem.TooltipText;
|
||||
}
|
||||
return base.OnShowTooltip(out text, out location, out area);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (base.OnMouseDown(location, button))
|
||||
return true;
|
||||
if (button == MouseButton.Right && Item is ContentItem)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (base.OnMouseUp(location, button))
|
||||
return true;
|
||||
if (button == MouseButton.Right && Item is AssetItem assetItem)
|
||||
if (button == MouseButton.Right && Item is ContentItem contentItem)
|
||||
{
|
||||
// Show context menu
|
||||
var proxy = Editor.Instance.ContentDatabase.GetProxy(assetItem);
|
||||
var proxy = Editor.Instance.ContentDatabase.GetProxy(contentItem);
|
||||
ContextMenuButton b;
|
||||
var cm = new FlaxEditor.GUI.ContextMenu.ContextMenu { Tag = assetItem };
|
||||
var cm = new ContextMenu { Tag = contentItem };
|
||||
b = cm.AddButton("Open", () => Editor.Instance.ContentFinding.Open(Item));
|
||||
cm.AddSeparator();
|
||||
cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(assetItem.Path)));
|
||||
cm.AddButton("Show in Content window", () => Editor.Instance.Windows.ContentWin.Select(assetItem, true));
|
||||
b.Enabled = proxy != null && proxy.CanReimport(assetItem);
|
||||
if (assetItem is BinaryAssetItem binaryAsset)
|
||||
cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(contentItem.Path)));
|
||||
cm.AddButton("Show in Content window", () => Editor.Instance.Windows.ContentWin.Select(contentItem, true));
|
||||
b.Enabled = proxy != null && proxy.CanReimport(contentItem);
|
||||
if (contentItem is BinaryAssetItem binaryAsset)
|
||||
{
|
||||
if (!binaryAsset.GetImportPath(out string importPath))
|
||||
{
|
||||
@@ -172,14 +182,17 @@ namespace FlaxEditor.Windows.Search
|
||||
}
|
||||
}
|
||||
cm.AddSeparator();
|
||||
cm.AddButton("Copy asset ID", () => Clipboard.Text = FlaxEngine.Json.JsonSerializer.GetStringID(assetItem.ID));
|
||||
cm.AddButton("Select actors using this asset", () => Editor.Instance.SceneEditing.SelectActorsUsingAsset(assetItem.ID));
|
||||
cm.AddButton("Show asset references graph", () => Editor.Instance.Windows.Open(new AssetReferencesGraphWindow(Editor.Instance, assetItem)));
|
||||
cm.AddSeparator();
|
||||
proxy?.OnContentWindowContextMenu(cm, assetItem);
|
||||
assetItem.OnContextMenu(cm);
|
||||
cm.AddButton("Copy name to Clipboard", () => Clipboard.Text = assetItem.NamePath);
|
||||
cm.AddButton("Copy path to Clipboard", () => Clipboard.Text = assetItem.Path);
|
||||
if (contentItem is AssetItem assetItem)
|
||||
{
|
||||
cm.AddButton("Copy asset ID", () => Clipboard.Text = FlaxEngine.Json.JsonSerializer.GetStringID(assetItem.ID));
|
||||
cm.AddButton("Select actors using this asset", () => Editor.Instance.SceneEditing.SelectActorsUsingAsset(assetItem.ID));
|
||||
cm.AddButton("Show asset references graph", () => Editor.Instance.Windows.Open(new AssetReferencesGraphWindow(Editor.Instance, assetItem)));
|
||||
cm.AddButton("Copy name to Clipboard", () => Clipboard.Text = assetItem.NamePath);
|
||||
cm.AddButton("Copy path to Clipboard", () => Clipboard.Text = assetItem.Path);
|
||||
cm.AddSeparator();
|
||||
}
|
||||
proxy?.OnContentWindowContextMenu(cm, contentItem);
|
||||
contentItem.OnContextMenu(cm);
|
||||
cm.Show(this, location);
|
||||
_cm = cm;
|
||||
return true;
|
||||
|
||||
@@ -271,8 +271,17 @@ public:
|
||||
public:
|
||||
/// <summary>
|
||||
/// Determines whether this audio source started playing audio via audio backend. After audio play it may wait for audio clip data to be loaded or streamed.
|
||||
/// [Deprecated in v1.9]
|
||||
/// </summary>
|
||||
API_PROPERTY() FORCE_INLINE bool IsActuallyPlayingSth() const
|
||||
API_PROPERTY() DEPRECATED FORCE_INLINE bool IsActuallyPlayingSth() const
|
||||
{
|
||||
return _isActuallyPlayingSth;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this audio source started playing audio via audio backend. After audio play it may wait for audio clip data to be loaded or streamed.
|
||||
/// </summary>
|
||||
API_PROPERTY() FORCE_INLINE bool IsActuallyPlaying() const
|
||||
{
|
||||
return _isActuallyPlayingSth;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,17 @@ namespace FlaxEngine
|
||||
/// </summary>
|
||||
public object Instance => _instance ?? (_instance = CreateInstance());
|
||||
|
||||
/// <summary>
|
||||
/// Gets the instance of the serialized object from the json data. Cached internally.
|
||||
/// </summary>
|
||||
/// <returns>The asset instance object or null.</returns>
|
||||
public T GetInstance<T>()
|
||||
{
|
||||
if (Instance is T instance)
|
||||
return instance;
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the serialized object from the json asset data.
|
||||
/// </summary>
|
||||
|
||||
@@ -33,6 +33,15 @@ namespace FlaxEngine
|
||||
Asset = asset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the deserialized native object instance of the given type. Returns null if asset is not loaded or loaded object has different type.
|
||||
/// </summary>
|
||||
/// <returns>The asset instance object or null.</returns>
|
||||
public U GetInstance<U>()
|
||||
{
|
||||
return Asset ? Asset.GetInstance<U>() : default(U);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicit cast operator.
|
||||
/// </summary>
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace FlaxEditor.Content.Settings
|
||||
/// <summary>
|
||||
/// The layers names.
|
||||
/// </summary>
|
||||
[EditorOrder(10), EditorDisplay("Layers", EditorDisplayAttribute.InlineStyle), Collection(CanResize = true, Display = CollectionAttribute.DisplayType.Inline)]
|
||||
[EditorOrder(10), EditorDisplay("Layers", EditorDisplayAttribute.InlineStyle), Collection(CanResize = false, Display = CollectionAttribute.DisplayType.Inline)]
|
||||
public string[] Layers = new string[32];
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -294,6 +294,10 @@ Quaternion Quaternion::FromDirection(const Float3& direction)
|
||||
{
|
||||
RotationAxis(Float3::Left, PI_OVER_2, orientation);
|
||||
}
|
||||
else if (Float3::Dot(direction, Float3::Down) >= 0.999f)
|
||||
{
|
||||
RotationAxis(Float3::Right, PI_OVER_2, orientation);
|
||||
}
|
||||
else
|
||||
{
|
||||
Float3 right, up;
|
||||
|
||||
@@ -654,6 +654,10 @@ namespace FlaxEngine
|
||||
{
|
||||
orientation = RotationAxis(Float3.Left, Mathf.PiOverTwo);
|
||||
}
|
||||
else if (Float3.Dot(direction, Float3.Down) >= 0.999f)
|
||||
{
|
||||
orientation = RotationAxis(Float3.Right, Mathf.PiOverTwo);
|
||||
}
|
||||
else
|
||||
{
|
||||
var right = Float3.Cross(direction, Float3.Up);
|
||||
|
||||
@@ -19,6 +19,7 @@ CharacterController::CharacterController(const SpawnParams& params)
|
||||
, _minMoveDistance(0.0f)
|
||||
, _isUpdatingTransform(false)
|
||||
, _upDirection(Vector3::Up)
|
||||
, _gravityDisplacement(Vector3::Zero)
|
||||
, _nonWalkableMode(NonWalkableModes::PreventClimbing)
|
||||
, _lastFlags(CollisionFlags::None)
|
||||
{
|
||||
@@ -148,10 +149,16 @@ CharacterController::CollisionFlags CharacterController::GetFlags() const
|
||||
CharacterController::CollisionFlags CharacterController::SimpleMove(const Vector3& speed)
|
||||
{
|
||||
const float deltaTime = Time::GetCurrentSafe()->DeltaTime.GetTotalSeconds();
|
||||
Vector3 displacement = speed;
|
||||
displacement += GetPhysicsScene()->GetGravity() * deltaTime;
|
||||
displacement *= deltaTime;
|
||||
return Move(displacement);
|
||||
Vector3 displacement = speed + _gravityDisplacement;
|
||||
CollisionFlags result = Move(displacement * deltaTime);
|
||||
if ((static_cast<int>(result) & static_cast<int>(CollisionFlags::Below)) != 0)
|
||||
{
|
||||
// Reset accumulated gravity acceleration when we touch the ground
|
||||
_gravityDisplacement = Vector3::Zero;
|
||||
}
|
||||
else
|
||||
_gravityDisplacement += GetPhysicsScene()->GetGravity() * deltaTime;
|
||||
return result;
|
||||
}
|
||||
|
||||
CharacterController::CollisionFlags CharacterController::Move(const Vector3& displacement)
|
||||
|
||||
@@ -66,6 +66,7 @@ private:
|
||||
float _minMoveDistance;
|
||||
bool _isUpdatingTransform;
|
||||
Vector3 _upDirection;
|
||||
Vector3 _gravityDisplacement;
|
||||
NonWalkableModes _nonWalkableMode;
|
||||
CollisionFlags _lastFlags;
|
||||
|
||||
|
||||
@@ -133,7 +133,13 @@ void MeshCollider::GetGeometry(CollisionShape& collision)
|
||||
// Prepare scale
|
||||
Float3 scale = _cachedScale;
|
||||
const float minSize = 0.001f;
|
||||
scale = Float3::Max(scale.GetAbsolute(), minSize);
|
||||
Float3 scaleAbs = scale.GetAbsolute();
|
||||
if (scaleAbs.X < minSize)
|
||||
scale.X = Math::Sign(scale.X) * minSize;
|
||||
if (scaleAbs.Y < minSize)
|
||||
scale.Y = Math::Sign(scale.Y) * minSize;
|
||||
if (scaleAbs.Z < minSize)
|
||||
scale.Z = Math::Sign(scale.Z) * minSize;
|
||||
|
||||
// Setup shape (based on type)
|
||||
CollisionDataType type = CollisionDataType::None;
|
||||
|
||||
@@ -321,7 +321,12 @@ class CharacterControllerHitReportPhysX : public PxUserControllerHitReport
|
||||
{
|
||||
void onHit(const PxControllerHit& hit, Collision& c)
|
||||
{
|
||||
ASSERT_LOW_LAYER(c.ThisActor && c.OtherActor);
|
||||
if (c.ThisActor == nullptr || c.OtherActor == nullptr)
|
||||
{
|
||||
// One of the actors was deleted (eg. via RigidBody destroyed by gameplay) then skip processing this collision
|
||||
return;
|
||||
}
|
||||
|
||||
c.Impulse = Vector3::Zero;
|
||||
c.ThisVelocity = P2C(hit.dir) * hit.length;
|
||||
c.OtherVelocity = Vector3::Zero;
|
||||
@@ -564,6 +569,7 @@ namespace
|
||||
Array<PxBase*> DeleteObjects;
|
||||
|
||||
bool _queriesHitTriggers = true;
|
||||
bool _enableCCD = true;
|
||||
PhysicsCombineMode _frictionCombineMode = PhysicsCombineMode::Average;
|
||||
PhysicsCombineMode _restitutionCombineMode = PhysicsCombineMode::Average;
|
||||
|
||||
@@ -697,6 +703,8 @@ PxFilterFlags FilterShader(
|
||||
pairFlags |= PxPairFlag::eNOTIFY_TOUCH_LOST;
|
||||
pairFlags |= PxPairFlag::ePOST_SOLVER_VELOCITY;
|
||||
pairFlags |= PxPairFlag::eNOTIFY_CONTACT_POINTS;
|
||||
if (_enableCCD)
|
||||
pairFlags |= PxPairFlag::eDETECT_CCD_CONTACT;
|
||||
return PxFilterFlag::eDEFAULT;
|
||||
}
|
||||
|
||||
@@ -1220,6 +1228,7 @@ void PhysicsBackend::Shutdown()
|
||||
void PhysicsBackend::ApplySettings(const PhysicsSettings& settings)
|
||||
{
|
||||
_queriesHitTriggers = settings.QueriesHitTriggers;
|
||||
_enableCCD = !settings.DisableCCD;
|
||||
_frictionCombineMode = settings.FrictionCombineMode;
|
||||
_restitutionCombineMode = settings.RestitutionCombineMode;
|
||||
|
||||
@@ -1256,6 +1265,8 @@ void* PhysicsBackend::CreateScene(const PhysicsSettings& settings)
|
||||
sceneDesc.simulationEventCallback = &scenePhysX->EventsCallback;
|
||||
sceneDesc.filterShader = FilterShader;
|
||||
sceneDesc.bounceThresholdVelocity = settings.BounceThresholdVelocity;
|
||||
if (settings.EnableEnhancedDeterminism)
|
||||
sceneDesc.flags |= PxSceneFlag::eENABLE_ENHANCED_DETERMINISM;
|
||||
switch (settings.SolverType)
|
||||
{
|
||||
case PhysicsSolverType::ProjectedGaussSeidelIterativeSolver:
|
||||
|
||||
@@ -94,10 +94,16 @@ public:
|
||||
API_FIELD(Attributes="EditorOrder(71), EditorDisplay(\"Simulation\")")
|
||||
PhysicsBroadPhaseType BroadPhaseType = PhysicsBroadPhaseType::ParallelAutomaticBoxPruning;
|
||||
|
||||
/// <summary>
|
||||
/// Enables enhanced determinism in the simulation. This has a performance impact.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(71), EditorDisplay(\"Simulation\")")
|
||||
bool EnableEnhancedDeterminism = false;
|
||||
|
||||
/// <summary>
|
||||
/// The solver type to use in the simulation.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(72), EditorDisplay(\"Simulation\")")
|
||||
API_FIELD(Attributes="EditorOrder(73), EditorDisplay(\"Simulation\")")
|
||||
PhysicsSolverType SolverType = PhysicsSolverType::ProjectedGaussSeidelIterativeSolver;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -130,6 +130,7 @@ namespace FlaxEngine.GUI
|
||||
{
|
||||
// Clear flag
|
||||
_splitterClicked = false;
|
||||
PerformLayout();
|
||||
|
||||
// End capturing mouse
|
||||
EndMouseCapture();
|
||||
|
||||
Reference in New Issue
Block a user