Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
"Major": 1,
|
"Major": 1,
|
||||||
"Minor": 11,
|
"Minor": 11,
|
||||||
"Revision": 0,
|
"Revision": 0,
|
||||||
"Build": 6803
|
"Build": 6804
|
||||||
},
|
},
|
||||||
"Company": "Flax",
|
"Company": "Flax",
|
||||||
"Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.",
|
"Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
|
using FlaxEngine.GUI;
|
||||||
|
|
||||||
namespace FlaxEditor.CustomEditors.Dedicated
|
namespace FlaxEditor.CustomEditors.Dedicated
|
||||||
{
|
{
|
||||||
@@ -11,7 +12,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
[CustomEditor(typeof(EnvironmentProbe)), DefaultEditor]
|
[CustomEditor(typeof(EnvironmentProbe)), DefaultEditor]
|
||||||
public class EnvironmentProbeEditor : ActorEditor
|
public class EnvironmentProbeEditor : ActorEditor
|
||||||
{
|
{
|
||||||
private FlaxEngine.GUI.Button _bake;
|
private Button _bake;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Initialize(LayoutElementsContainer layout)
|
public override void Initialize(LayoutElementsContainer layout)
|
||||||
@@ -20,8 +21,9 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
|
|
||||||
if (Values.HasDifferentTypes == false)
|
if (Values.HasDifferentTypes == false)
|
||||||
{
|
{
|
||||||
layout.Space(10);
|
var group = layout.Group("Bake");
|
||||||
_bake = layout.Button("Bake").Button;
|
group.Panel.ItemsMargin = new Margin(Utilities.Constants.UIMargin * 2);
|
||||||
|
_bake = group.Button("Bake").Button;
|
||||||
_bake.Clicked += BakeButtonClicked;
|
_bake.Clicked += BakeButtonClicked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
|
using FlaxEngine.GUI;
|
||||||
|
|
||||||
namespace FlaxEditor.CustomEditors.Dedicated
|
namespace FlaxEditor.CustomEditors.Dedicated
|
||||||
{
|
{
|
||||||
@@ -19,8 +20,9 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
if (Values.HasDifferentTypes == false)
|
if (Values.HasDifferentTypes == false)
|
||||||
{
|
{
|
||||||
// Add 'Bake' button
|
// Add 'Bake' button
|
||||||
layout.Space(10);
|
var group = layout.Group("Bake");
|
||||||
var button = layout.Button("Bake");
|
group.Panel.ItemsMargin = new Margin(Utilities.Constants.UIMargin * 2);
|
||||||
|
var button = group.Button("Bake");
|
||||||
button.Button.Clicked += BakeButtonClicked;
|
button.Button.Clicked += BakeButtonClicked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -650,7 +650,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
panel.Panel.Size = new Float2(0, 18);
|
panel.Panel.Size = new Float2(0, 18);
|
||||||
panel.Panel.Margin = new Margin(0, 0, Utilities.Constants.UIMargin, 0);
|
panel.Panel.Margin = new Margin(0, 0, Utilities.Constants.UIMargin, 0);
|
||||||
|
|
||||||
var removeButton = panel.Button("-", "Remove the last item");
|
var removeButton = panel.Button("-", "Remove the last item.");
|
||||||
removeButton.Button.Size = new Float2(16, 16);
|
removeButton.Button.Size = new Float2(16, 16);
|
||||||
removeButton.Button.Enabled = size > _minCount;
|
removeButton.Button.Enabled = size > _minCount;
|
||||||
removeButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
removeButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
||||||
@@ -661,7 +661,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
Resize(Count - 1);
|
Resize(Count - 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
var addButton = panel.Button("+", "Add a new item");
|
var addButton = panel.Button("+", "Add a new item.");
|
||||||
addButton.Button.Size = new Float2(16, 16);
|
addButton.Button.Size = new Float2(16, 16);
|
||||||
addButton.Button.Enabled = (!NotNullItems || size > 0) && size < _maxCount;
|
addButton.Button.Enabled = (!NotNullItems || size > 0) && size < _maxCount;
|
||||||
addButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
addButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
public event Action<TypePickerControl> TypePickerValueChanged;
|
public event Action<TypePickerControl> TypePickerValueChanged;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The custom callback for types validation. Cane be used to implement a rule for types to pick.
|
/// The custom callback for types validation. Can be used to implement a rule for types to pick.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<ScriptType, bool> CheckValid;
|
public Func<ScriptType, bool> CheckValid;
|
||||||
|
|
||||||
@@ -353,7 +353,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(typeReference.CheckMethod))
|
if (!string.IsNullOrEmpty(typeReference.CheckMethod))
|
||||||
{
|
{
|
||||||
var parentType = ParentEditor.Values[0].GetType();
|
var parentEditor = ParentEditor;
|
||||||
|
// Find actual parent editor if parent editor is collection editor
|
||||||
|
while (parentEditor.GetType().IsAssignableTo(typeof(CollectionEditor)))
|
||||||
|
parentEditor = parentEditor.ParentEditor;
|
||||||
|
|
||||||
|
var parentType = parentEditor.Values[0].GetType();
|
||||||
|
|
||||||
var method = parentType.GetMethod(typeReference.CheckMethod, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
var method = parentType.GetMethod(typeReference.CheckMethod, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
if (method != null)
|
if (method != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -726,7 +726,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
|
|
||||||
private void OnSurfaceMouseUp(ref Float2 mouse, MouseButton buttons, ref bool handled)
|
private void OnSurfaceMouseUp(ref Float2 mouse, MouseButton buttons, ref bool handled)
|
||||||
{
|
{
|
||||||
if (handled)
|
if (handled || Surface.Context != Context)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Check click over the connection
|
// Check click over the connection
|
||||||
@@ -751,7 +751,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
|
|
||||||
private void OnSurfaceMouseDoubleClick(ref Float2 mouse, MouseButton buttons, ref bool handled)
|
private void OnSurfaceMouseDoubleClick(ref Float2 mouse, MouseButton buttons, ref bool handled)
|
||||||
{
|
{
|
||||||
if (handled)
|
if (handled || Surface.Context != Context)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Check double click over the connection
|
// Check double click over the connection
|
||||||
|
|||||||
@@ -2,11 +2,8 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.Loader;
|
|
||||||
using System.Runtime.Serialization.Formatters.Binary;
|
|
||||||
using FlaxEditor.CustomEditors;
|
using FlaxEditor.CustomEditors;
|
||||||
using FlaxEditor.CustomEditors.Editors;
|
using FlaxEditor.CustomEditors.Editors;
|
||||||
using FlaxEditor.GUI.ContextMenu;
|
using FlaxEditor.GUI.ContextMenu;
|
||||||
@@ -18,6 +15,7 @@ namespace FlaxEditor.Surface
|
|||||||
class AttributesEditor : ContextMenuBase
|
class AttributesEditor : ContextMenuBase
|
||||||
{
|
{
|
||||||
private CustomEditorPresenter _presenter;
|
private CustomEditorPresenter _presenter;
|
||||||
|
private Proxy _proxy;
|
||||||
private byte[] _oldData;
|
private byte[] _oldData;
|
||||||
|
|
||||||
private class Proxy
|
private class Proxy
|
||||||
@@ -72,11 +70,11 @@ namespace FlaxEditor.Surface
|
|||||||
/// Initializes a new instance of the <see cref="AttributesEditor"/> class.
|
/// Initializes a new instance of the <see cref="AttributesEditor"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="attributes">The attributes list to edit.</param>
|
/// <param name="attributes">The attributes list to edit.</param>
|
||||||
/// <param name="attributeType">The allowed attribute types to use.</param>
|
/// <param name="attributeTypes">The allowed attribute types to use.</param>
|
||||||
public AttributesEditor(Attribute[] attributes, IList<Type> attributeType)
|
public AttributesEditor(Attribute[] attributes, IList<Type> attributeTypes)
|
||||||
{
|
{
|
||||||
// Context menu dimensions
|
// Context menu dimensions
|
||||||
const float width = 340.0f;
|
const float width = 375.0f;
|
||||||
const float height = 370.0f;
|
const float height = 370.0f;
|
||||||
Size = new Float2(width, height);
|
Size = new Float2(width, height);
|
||||||
|
|
||||||
@@ -88,61 +86,68 @@ namespace FlaxEditor.Surface
|
|||||||
Parent = this
|
Parent = this
|
||||||
};
|
};
|
||||||
|
|
||||||
// Buttons
|
// Ok and Cancel Buttons
|
||||||
float buttonsWidth = (width - 16.0f) * 0.5f;
|
float buttonsWidth = (width - 12.0f) * 0.5f;
|
||||||
float buttonsHeight = 20.0f;
|
float buttonsHeight = 20.0f;
|
||||||
var cancelButton = new Button(4.0f, title.Bottom + 4.0f, buttonsWidth, buttonsHeight)
|
var okButton = new Button(4.0f, Bottom - 4.0f - buttonsHeight, buttonsWidth, buttonsHeight)
|
||||||
|
{
|
||||||
|
Text = "Ok",
|
||||||
|
Parent = this
|
||||||
|
};
|
||||||
|
okButton.Clicked += OnOkButtonClicked;
|
||||||
|
var cancelButton = new Button(okButton.Right + 4.0f, okButton.Y, buttonsWidth, buttonsHeight)
|
||||||
{
|
{
|
||||||
Text = "Cancel",
|
Text = "Cancel",
|
||||||
Parent = this
|
Parent = this
|
||||||
};
|
};
|
||||||
cancelButton.Clicked += Hide;
|
cancelButton.Clicked += Hide;
|
||||||
var okButton = new Button(cancelButton.Right + 4.0f, cancelButton.Y, buttonsWidth, buttonsHeight)
|
|
||||||
{
|
|
||||||
Text = "OK",
|
|
||||||
Parent = this
|
|
||||||
};
|
|
||||||
okButton.Clicked += OnOkButtonClicked;
|
|
||||||
|
|
||||||
// Actual panel
|
// Actual panel used to display attributes
|
||||||
var panel1 = new Panel(ScrollBars.Vertical)
|
var panel1 = new Panel(ScrollBars.Vertical)
|
||||||
{
|
{
|
||||||
Bounds = new Rectangle(0, okButton.Bottom + 4.0f, width, height - okButton.Bottom - 2.0f),
|
Bounds = new Rectangle(0, title.Bottom + 4.0f, width, height - buttonsHeight - title.Height - 14.0f),
|
||||||
Parent = this
|
Parent = this
|
||||||
};
|
};
|
||||||
var editor = new CustomEditorPresenter(null);
|
var editor = new CustomEditorPresenter(null);
|
||||||
editor.Panel.AnchorPreset = AnchorPresets.HorizontalStretchTop;
|
editor.Panel.AnchorPreset = AnchorPresets.HorizontalStretchTop;
|
||||||
editor.Panel.IsScrollable = true;
|
editor.Panel.IsScrollable = true;
|
||||||
editor.Panel.Parent = panel1;
|
editor.Panel.Parent = panel1;
|
||||||
editor.Panel.Tag = attributeType;
|
editor.Panel.Tag = attributeTypes;
|
||||||
_presenter = editor;
|
_presenter = editor;
|
||||||
|
|
||||||
// Cache 'previous' state to check if attributes were edited after operation
|
// Cache 'previous' state to check if attributes were edited after operation
|
||||||
_oldData = SurfaceMeta.GetAttributesData(attributes);
|
_oldData = SurfaceMeta.GetAttributesData(attributes);
|
||||||
|
|
||||||
editor.Select(new Proxy
|
_proxy = new Proxy
|
||||||
{
|
{
|
||||||
Value = attributes,
|
Value = attributes,
|
||||||
});
|
};
|
||||||
|
editor.Select(_proxy);
|
||||||
|
|
||||||
|
_presenter.Modified += OnPresenterModified;
|
||||||
|
OnPresenterModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPresenterModified()
|
||||||
|
{
|
||||||
|
if (_proxy.Value.Length == 0)
|
||||||
|
{
|
||||||
|
var label = _presenter.Label("No attributes.\nPress the \"+\" button to add a new one and then select an attribute type using the \"Type\" dropdown.", TextAlignment.Center);
|
||||||
|
label.Label.Wrapping = TextWrapping.WrapWords;
|
||||||
|
label.Control.Height = 35f;
|
||||||
|
label.Label.Margin = new Margin(10f);
|
||||||
|
label.Label.TextColor = label.Label.TextColorHighlighted = Style.Current.ForegroundGrey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnOkButtonClicked()
|
private void OnOkButtonClicked()
|
||||||
{
|
{
|
||||||
var newValue = ((Proxy)_presenter.Selection[0]).Value;
|
var newValue = ((Proxy)_presenter.Selection[0]).Value;
|
||||||
for (int i = 0; i < newValue.Length; i++)
|
newValue = newValue.Where(v => v != null).ToArray();
|
||||||
{
|
|
||||||
if (newValue[i] == null)
|
|
||||||
{
|
|
||||||
MessageBox.Show("One of the attributes is null. Please set it to the valid object.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var newData = SurfaceMeta.GetAttributesData(newValue);
|
var newData = SurfaceMeta.GetAttributesData(newValue);
|
||||||
if (!_oldData.SequenceEqual(newData))
|
if (!_oldData.SequenceEqual(newData))
|
||||||
{
|
|
||||||
Edited?.Invoke(newValue);
|
Edited?.Invoke(newValue);
|
||||||
}
|
|
||||||
|
|
||||||
Hide();
|
Hide();
|
||||||
}
|
}
|
||||||
@@ -183,7 +188,9 @@ namespace FlaxEditor.Surface
|
|||||||
{
|
{
|
||||||
_presenter = null;
|
_presenter = null;
|
||||||
_oldData = null;
|
_oldData = null;
|
||||||
|
_proxy = null;
|
||||||
Edited = null;
|
Edited = null;
|
||||||
|
_presenter.Modified -= OnPresenterModified;
|
||||||
|
|
||||||
base.OnDestroy();
|
base.OnDestroy();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,22 +214,25 @@ namespace FlaxEditor.Surface
|
|||||||
if (!_isRenaming)
|
if (!_isRenaming)
|
||||||
Render2D.DrawText(style.FontLarge, Title, _headerRect, style.Foreground, TextAlignment.Center, TextAlignment.Center);
|
Render2D.DrawText(style.FontLarge, Title, _headerRect, style.Foreground, TextAlignment.Center, TextAlignment.Center);
|
||||||
|
|
||||||
// Close button
|
if (Surface.CanEdit)
|
||||||
Render2D.DrawSprite(style.Cross, _closeButtonRect, _closeButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
|
|
||||||
|
|
||||||
// Color button
|
|
||||||
Render2D.DrawSprite(style.Settings, _colorButtonRect, _colorButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
|
|
||||||
|
|
||||||
// Check if is resizing
|
|
||||||
if (_isResizing)
|
|
||||||
{
|
{
|
||||||
// Draw overlay
|
// Close button
|
||||||
Render2D.FillRectangle(_resizeButtonRect, style.Selection);
|
Render2D.DrawSprite(style.Cross, _closeButtonRect, _closeButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
|
||||||
Render2D.DrawRectangle(_resizeButtonRect, style.SelectionBorder);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resize button
|
// Color button
|
||||||
Render2D.DrawSprite(style.Scale, _resizeButtonRect, _resizeButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
|
Render2D.DrawSprite(style.Settings, _colorButtonRect, _colorButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
|
||||||
|
|
||||||
|
// Check if is resizing
|
||||||
|
if (_isResizing)
|
||||||
|
{
|
||||||
|
// Draw overlay
|
||||||
|
Render2D.FillRectangle(_resizeButtonRect, style.Selection);
|
||||||
|
Render2D.DrawRectangle(_resizeButtonRect, style.SelectionBorder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize button
|
||||||
|
Render2D.DrawSprite(style.Scale, _resizeButtonRect, _resizeButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
|
||||||
|
}
|
||||||
|
|
||||||
// Selection outline
|
// Selection outline
|
||||||
if (_isSelected)
|
if (_isSelected)
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ namespace FlaxEditor.Windows
|
|||||||
}
|
}
|
||||||
|
|
||||||
private string _cacheFolder;
|
private string _cacheFolder;
|
||||||
private Guid _assetId;
|
private AssetItem _item;
|
||||||
private Surface _surface;
|
private Surface _surface;
|
||||||
private Label _loadingLabel;
|
private Label _loadingLabel;
|
||||||
private CancellationTokenSource _token;
|
private CancellationTokenSource _token;
|
||||||
@@ -163,13 +163,13 @@ namespace FlaxEditor.Windows
|
|||||||
public AssetReferencesGraphWindow(Editor editor, AssetItem assetItem)
|
public AssetReferencesGraphWindow(Editor editor, AssetItem assetItem)
|
||||||
: base(editor, false, ScrollBars.None)
|
: base(editor, false, ScrollBars.None)
|
||||||
{
|
{
|
||||||
Title = assetItem.ShortName + " References";
|
_item = assetItem;
|
||||||
|
Title = _item.ShortName + " References";
|
||||||
|
|
||||||
_tempFolder = StringUtils.NormalizePath(Path.GetDirectoryName(Globals.TemporaryFolder));
|
_tempFolder = StringUtils.NormalizePath(Path.GetDirectoryName(Globals.TemporaryFolder));
|
||||||
_cacheFolder = Path.Combine(Globals.ProjectCacheFolder, "References");
|
_cacheFolder = Path.Combine(Globals.ProjectCacheFolder, "References");
|
||||||
if (!Directory.Exists(_cacheFolder))
|
if (!Directory.Exists(_cacheFolder))
|
||||||
Directory.CreateDirectory(_cacheFolder);
|
Directory.CreateDirectory(_cacheFolder);
|
||||||
_assetId = assetItem.ID;
|
|
||||||
_surface = new Surface(this)
|
_surface = new Surface(this)
|
||||||
{
|
{
|
||||||
AnchorPreset = AnchorPresets.StretchAll,
|
AnchorPreset = AnchorPresets.StretchAll,
|
||||||
@@ -194,6 +194,7 @@ namespace FlaxEditor.Windows
|
|||||||
_nodesAssets.Add(assetId);
|
_nodesAssets.Add(assetId);
|
||||||
var node = new AssetNode((uint)_nodes.Count + 1, _surface.Context, GraphNodes[0], GraphGroups[0], assetId);
|
var node = new AssetNode((uint)_nodes.Count + 1, _surface.Context, GraphNodes[0], GraphGroups[0], assetId);
|
||||||
_nodes.Add(node);
|
_nodes.Add(node);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,8 +393,7 @@ namespace FlaxEditor.Windows
|
|||||||
_nodesAssets = new HashSet<Guid>();
|
_nodesAssets = new HashSet<Guid>();
|
||||||
var searchLevel = 4; // TODO: make it as an option (somewhere in window UI)
|
var searchLevel = 4; // TODO: make it as an option (somewhere in window UI)
|
||||||
// TODO: add option to filter assets by type (eg. show only textures as leaf nodes)
|
// TODO: add option to filter assets by type (eg. show only textures as leaf nodes)
|
||||||
var assetNode = SpawnNode(_assetId);
|
var assetNode = SpawnNode(_item.ID);
|
||||||
// TODO: add some outline or tint color to the main node
|
|
||||||
BuildGraph(assetNode, searchLevel, false);
|
BuildGraph(assetNode, searchLevel, false);
|
||||||
ArrangeGraph(assetNode, false);
|
ArrangeGraph(assetNode, false);
|
||||||
BuildGraph(assetNode, searchLevel, true);
|
BuildGraph(assetNode, searchLevel, true);
|
||||||
@@ -402,6 +402,10 @@ namespace FlaxEditor.Windows
|
|||||||
return;
|
return;
|
||||||
_progress = 100.0f;
|
_progress = 100.0f;
|
||||||
|
|
||||||
|
var commentRect = assetNode.EditorBounds;
|
||||||
|
commentRect.Expand(80f);
|
||||||
|
_surface.Context.CreateComment(ref commentRect, _item.ShortName, Color.Green);
|
||||||
|
|
||||||
// Update UI
|
// Update UI
|
||||||
FlaxEngine.Scripting.InvokeOnUpdate(() =>
|
FlaxEngine.Scripting.InvokeOnUpdate(() =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ namespace FlaxEditor.Windows
|
|||||||
{
|
{
|
||||||
Title = "Content";
|
Title = "Content";
|
||||||
Icon = editor.Icons.Folder32;
|
Icon = editor.Icons.Folder32;
|
||||||
|
var style = Style.Current;
|
||||||
|
|
||||||
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
|
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
|
||||||
|
|
||||||
@@ -164,6 +165,8 @@ namespace FlaxEditor.Windows
|
|||||||
_navigationBar = new NavigationBar
|
_navigationBar = new NavigationBar
|
||||||
{
|
{
|
||||||
Parent = _toolStrip,
|
Parent = _toolStrip,
|
||||||
|
ScrollbarTrackColor = style.Background,
|
||||||
|
ScrollbarThumbColor = style.ForegroundGrey,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Split panel
|
// Split panel
|
||||||
@@ -179,7 +182,7 @@ namespace FlaxEditor.Windows
|
|||||||
var headerPanel = new ContainerControl
|
var headerPanel = new ContainerControl
|
||||||
{
|
{
|
||||||
AnchorPreset = AnchorPresets.HorizontalStretchTop,
|
AnchorPreset = AnchorPresets.HorizontalStretchTop,
|
||||||
BackgroundColor = Style.Current.Background,
|
BackgroundColor = style.Background,
|
||||||
IsScrollable = false,
|
IsScrollable = false,
|
||||||
Offsets = new Margin(0, 0, 0, 18 + 6),
|
Offsets = new Margin(0, 0, 0, 18 + 6),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -666,7 +666,7 @@ void Asset::onLoaded()
|
|||||||
{
|
{
|
||||||
onLoaded_MainThread();
|
onLoaded_MainThread();
|
||||||
}
|
}
|
||||||
else if (OnLoaded.IsBinded())
|
else if (OnLoaded.IsBinded() || _references.HasItems())
|
||||||
{
|
{
|
||||||
Function<void()> action;
|
Function<void()> action;
|
||||||
action.Bind<Asset, &Asset::onLoaded>(this);
|
action.Bind<Asset, &Asset::onLoaded>(this);
|
||||||
|
|||||||
@@ -218,10 +218,14 @@ Asset::LoadResult MaterialInstance::load()
|
|||||||
Guid baseMaterialId;
|
Guid baseMaterialId;
|
||||||
headerStream.Read(baseMaterialId);
|
headerStream.Read(baseMaterialId);
|
||||||
auto baseMaterial = Content::LoadAsync<MaterialBase>(baseMaterialId);
|
auto baseMaterial = Content::LoadAsync<MaterialBase>(baseMaterialId);
|
||||||
|
if (baseMaterial)
|
||||||
|
baseMaterial->AddReference();
|
||||||
|
|
||||||
// Load parameters
|
// Load parameters
|
||||||
if (Params.Load(&headerStream))
|
if (Params.Load(&headerStream))
|
||||||
{
|
{
|
||||||
|
if (baseMaterial)
|
||||||
|
baseMaterial->RemoveReference();
|
||||||
LOG(Warning, "Cannot load material parameters.");
|
LOG(Warning, "Cannot load material parameters.");
|
||||||
return LoadResult::CannotLoadData;
|
return LoadResult::CannotLoadData;
|
||||||
}
|
}
|
||||||
@@ -239,6 +243,7 @@ Asset::LoadResult MaterialInstance::load()
|
|||||||
ParamsChanged();
|
ParamsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
baseMaterial->RemoveReference();
|
||||||
return LoadResult::Ok;
|
return LoadResult::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,10 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
double LastAccessTime = 0.0;
|
double LastAccessTime = 0.0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flag set to indicate that chunk is during loading (atomic access to sync multiple reading threads).
|
||||||
|
/// </summary>
|
||||||
|
int64 IsLoading = 0;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The chunk data.
|
/// The chunk data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -146,7 +150,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE bool IsLoaded() const
|
FORCE_INLINE bool IsLoaded() const
|
||||||
{
|
{
|
||||||
return Data.IsValid();
|
return Data.IsValid() && Platform::AtomicRead(&IsLoading) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -154,7 +158,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE bool IsMissing() const
|
FORCE_INLINE bool IsMissing() const
|
||||||
{
|
{
|
||||||
return Data.IsInvalid();
|
return !IsLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "FlaxPackage.h"
|
#include "FlaxPackage.h"
|
||||||
#include "ContentStorageManager.h"
|
#include "ContentStorageManager.h"
|
||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
|
#include "Engine/Core/ScopeExit.h"
|
||||||
#include "Engine/Core/Types/TimeSpan.h"
|
#include "Engine/Core/Types/TimeSpan.h"
|
||||||
#include "Engine/Platform/File.h"
|
#include "Engine/Platform/File.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
@@ -246,6 +247,7 @@ FlaxStorage::~FlaxStorage()
|
|||||||
ASSERT(IsDisposed());
|
ASSERT(IsDisposed());
|
||||||
CHECK(_chunksLock == 0);
|
CHECK(_chunksLock == 0);
|
||||||
CHECK(_refCount == 0);
|
CHECK(_refCount == 0);
|
||||||
|
CHECK(_isUnloadingData == 0);
|
||||||
ASSERT(_chunks.IsEmpty());
|
ASSERT(_chunks.IsEmpty());
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
@@ -261,6 +263,22 @@ FlaxStorage::~FlaxStorage()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FlaxStorage::LockChunks()
|
||||||
|
{
|
||||||
|
RETRY:
|
||||||
|
Platform::InterlockedIncrement(&_chunksLock);
|
||||||
|
if (Platform::AtomicRead(&_isUnloadingData) != 0)
|
||||||
|
{
|
||||||
|
// Someone else is closing file handles or freeing chunks so wait for it to finish and retry
|
||||||
|
Platform::InterlockedDecrement(&_chunksLock);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Platform::Sleep(1);
|
||||||
|
} while (Platform::AtomicRead(&_isUnloadingData) != 0);
|
||||||
|
goto RETRY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FlaxStorage::LockData FlaxStorage::LockSafe()
|
FlaxStorage::LockData FlaxStorage::LockSafe()
|
||||||
{
|
{
|
||||||
auto lock = LockData(this);
|
auto lock = LockData(this);
|
||||||
@@ -689,7 +707,6 @@ bool FlaxStorage::LoadAssetHeader(const Guid& id, AssetInitData& data)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load header
|
|
||||||
return LoadAssetHeader(e, data);
|
return LoadAssetHeader(e, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,7 +716,10 @@ bool FlaxStorage::LoadAssetChunk(FlaxChunk* chunk)
|
|||||||
ASSERT(IsLoaded());
|
ASSERT(IsLoaded());
|
||||||
ASSERT(chunk != nullptr && _chunks.Contains(chunk));
|
ASSERT(chunk != nullptr && _chunks.Contains(chunk));
|
||||||
|
|
||||||
// Check if already loaded
|
// Protect against loading the same chunk from multiple threads at once
|
||||||
|
while (Platform::InterlockedCompareExchange(&chunk->IsLoading, 1, 0) != 0)
|
||||||
|
Platform::Sleep(1);
|
||||||
|
SCOPE_EXIT{ Platform::AtomicStore(&chunk->IsLoading, 0); };
|
||||||
if (chunk->IsLoaded())
|
if (chunk->IsLoaded())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -776,12 +796,10 @@ bool FlaxStorage::LoadAssetChunk(FlaxChunk* chunk)
|
|||||||
// Raw data
|
// Raw data
|
||||||
chunk->Data.Read(stream, size);
|
chunk->Data.Read(stream, size);
|
||||||
}
|
}
|
||||||
ASSERT(chunk->IsLoaded());
|
|
||||||
chunk->RegisterUsage();
|
chunk->RegisterUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
UnlockChunks();
|
UnlockChunks();
|
||||||
|
|
||||||
return failed;
|
return failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1420,10 +1438,12 @@ FileReadStream* FlaxStorage::OpenFile()
|
|||||||
|
|
||||||
bool FlaxStorage::CloseFileHandles()
|
bool FlaxStorage::CloseFileHandles()
|
||||||
{
|
{
|
||||||
|
// Guard the whole process so if new thread wants to lock the chunks will need to wait for this to end
|
||||||
|
Platform::InterlockedIncrement(&_isUnloadingData);
|
||||||
|
SCOPE_EXIT{ Platform::InterlockedDecrement(&_isUnloadingData); };
|
||||||
|
|
||||||
if (Platform::AtomicRead(&_chunksLock) == 0 && Platform::AtomicRead(&_files) == 0)
|
if (Platform::AtomicRead(&_chunksLock) == 0 && Platform::AtomicRead(&_files) == 0)
|
||||||
{
|
return false; // Early out when no files are opened
|
||||||
return false;
|
|
||||||
}
|
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
PROFILE_MEM(ContentFiles);
|
PROFILE_MEM(ContentFiles);
|
||||||
|
|
||||||
@@ -1496,9 +1516,21 @@ void FlaxStorage::Tick(double time)
|
|||||||
{
|
{
|
||||||
auto chunk = _chunks.Get()[i];
|
auto chunk = _chunks.Get()[i];
|
||||||
const bool wasUsed = (time - chunk->LastAccessTime) < unusedDataChunksLifetime;
|
const bool wasUsed = (time - chunk->LastAccessTime) < unusedDataChunksLifetime;
|
||||||
if (!wasUsed && chunk->IsLoaded() && EnumHasNoneFlags(chunk->Flags, FlaxChunkFlags::KeepInMemory))
|
if (!wasUsed &&
|
||||||
|
chunk->IsLoaded() &&
|
||||||
|
EnumHasNoneFlags(chunk->Flags, FlaxChunkFlags::KeepInMemory) &&
|
||||||
|
Platform::AtomicRead(&chunk->IsLoading) == 0)
|
||||||
{
|
{
|
||||||
|
// Guard the unloading so if other thread wants to lock the chunks will need to wait for this to end
|
||||||
|
Platform::InterlockedIncrement(&_isUnloadingData);
|
||||||
|
if (Platform::AtomicRead(&_chunksLock) != 0 || Platform::AtomicRead(&chunk->IsLoading) != 0)
|
||||||
|
{
|
||||||
|
// Someone started loading so skip ticking
|
||||||
|
Platform::InterlockedDecrement(&_isUnloadingData);
|
||||||
|
return;
|
||||||
|
}
|
||||||
chunk->Unload();
|
chunk->Unload();
|
||||||
|
Platform::InterlockedDecrement(&_isUnloadingData);
|
||||||
}
|
}
|
||||||
wasAnyUsed |= wasUsed;
|
wasAnyUsed |= wasUsed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ protected:
|
|||||||
int64 _refCount = 0;
|
int64 _refCount = 0;
|
||||||
int64 _chunksLock = 0;
|
int64 _chunksLock = 0;
|
||||||
int64 _files = 0;
|
int64 _files = 0;
|
||||||
|
int64 _isUnloadingData = 0;
|
||||||
double _lastRefLostTime;
|
double _lastRefLostTime;
|
||||||
CriticalSection _loadLocker;
|
CriticalSection _loadLocker;
|
||||||
|
|
||||||
@@ -129,10 +130,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Locks the storage chunks data to prevent disposing them. Also ensures that file handles won't be closed while chunks are locked.
|
/// Locks the storage chunks data to prevent disposing them. Also ensures that file handles won't be closed while chunks are locked.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE void LockChunks()
|
void LockChunks();
|
||||||
{
|
|
||||||
Platform::InterlockedIncrement(&_chunksLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unlocks the storage chunks data.
|
/// Unlocks the storage chunks data.
|
||||||
|
|||||||
@@ -338,10 +338,10 @@ public:
|
|||||||
StreamTextureMipTask(StreamingTexture* texture, int32 mipIndex, Task* rootTask)
|
StreamTextureMipTask(StreamingTexture* texture, int32 mipIndex, Task* rootTask)
|
||||||
: GPUUploadTextureMipTask(texture->GetTexture(), mipIndex, Span<byte>(nullptr, 0), 0, 0, false)
|
: GPUUploadTextureMipTask(texture->GetTexture(), mipIndex, Span<byte>(nullptr, 0), 0, 0, false)
|
||||||
, _streamingTexture(texture)
|
, _streamingTexture(texture)
|
||||||
, _rootTask(rootTask ? rootTask : this)
|
, _rootTask(rootTask)
|
||||||
, _dataLock(_streamingTexture->GetOwner()->LockData())
|
, _dataLock(_streamingTexture->GetOwner()->LockData())
|
||||||
{
|
{
|
||||||
_streamingTexture->_streamingTasks.Add(_rootTask);
|
_streamingTexture->_streamingTasks.Add(this);
|
||||||
_texture.Released.Bind<StreamTextureMipTask, &StreamTextureMipTask::OnResourceReleased2>(this);
|
_texture.Released.Bind<StreamTextureMipTask, &StreamTextureMipTask::OnResourceReleased2>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,7 +357,7 @@ private:
|
|||||||
if (_streamingTexture)
|
if (_streamingTexture)
|
||||||
{
|
{
|
||||||
ScopeLock lock(_streamingTexture->GetOwner()->GetOwnerLocker());
|
ScopeLock lock(_streamingTexture->GetOwner()->GetOwnerLocker());
|
||||||
_streamingTexture->_streamingTasks.Remove(_rootTask);
|
_streamingTexture->_streamingTasks.Remove(this);
|
||||||
_streamingTexture = nullptr;
|
_streamingTexture = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -422,6 +422,15 @@ protected:
|
|||||||
|
|
||||||
GPUUploadTextureMipTask::OnFail();
|
GPUUploadTextureMipTask::OnFail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnCancel() override
|
||||||
|
{
|
||||||
|
GPUUploadTextureMipTask::OnCancel();
|
||||||
|
|
||||||
|
// Cancel the root task too (eg. mip loading from asset)
|
||||||
|
if (_rootTask != nullptr)
|
||||||
|
_rootTask->Cancel();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Task* StreamingTexture::CreateStreamingTask(int32 residency)
|
Task* StreamingTexture::CreateStreamingTask(int32 residency)
|
||||||
|
|||||||
@@ -42,38 +42,38 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The reflections texture resolution.
|
/// The reflections texture resolution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(Attributes="EditorOrder(0), EditorDisplay(\"Probe\")")
|
API_FIELD(Attributes="EditorOrder(0), EditorDisplay(\"Quality\")")
|
||||||
ProbeCubemapResolution CubemapResolution = ProbeCubemapResolution::UseGraphicsSettings;
|
ProbeCubemapResolution CubemapResolution = ProbeCubemapResolution::UseGraphicsSettings;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The probe update mode.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(Attributes = "EditorOrder(10), EditorDisplay(\"Quality\")")
|
||||||
|
ProbeUpdateMode UpdateMode = ProbeUpdateMode::Manual;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The reflections brightness.
|
/// The reflections brightness.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(Attributes="EditorOrder(10), Limit(0, 1000, 0.01f), EditorDisplay(\"Probe\")")
|
API_FIELD(Attributes="EditorOrder(0), Limit(0, 1000, 0.01f), EditorDisplay(\"Probe\")")
|
||||||
float Brightness = 1.0f;
|
float Brightness = 1.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The probe rendering order. The higher values are render later (on top).
|
/// The probe rendering order. The higher values are render later (on top).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(Attributes = "EditorOrder(25), EditorDisplay(\"Probe\")")
|
API_FIELD(Attributes = "EditorOrder(20), EditorDisplay(\"Probe\")")
|
||||||
int32 SortOrder = 0;
|
int32 SortOrder = 0;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The probe update mode.
|
|
||||||
/// </summary>
|
|
||||||
API_FIELD(Attributes="EditorOrder(30), EditorDisplay(\"Probe\")")
|
|
||||||
ProbeUpdateMode UpdateMode = ProbeUpdateMode::Manual;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The probe capture camera near plane distance.
|
/// The probe capture camera near plane distance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(Attributes="EditorOrder(30), Limit(0, float.MaxValue, 0.01f), EditorDisplay(\"Probe\")")
|
API_FIELD(Attributes="EditorOrder(25), Limit(0, float.MaxValue, 0.01f), EditorDisplay(\"Probe\")")
|
||||||
float CaptureNearPlane = 10.0f;
|
float CaptureNearPlane = 10.0f;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the probe radius.
|
/// Gets the probe radius.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_PROPERTY(Attributes="EditorOrder(20), DefaultValue(3000.0f), Limit(0), EditorDisplay(\"Probe\")")
|
API_PROPERTY(Attributes="EditorOrder(15), DefaultValue(3000.0f), Limit(0), EditorDisplay(\"Probe\")")
|
||||||
float GetRadius() const;
|
float GetRadius() const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
#include "Engine/Core/Types/StringView.h"
|
#include "Engine/Core/Types/StringView.h"
|
||||||
#include "Engine/Core/Types/Guid.h"
|
#include "Engine/Core/Types/Guid.h"
|
||||||
|
#if PLATFORM_ARCH_ARM64
|
||||||
|
#include "Engine/Core/Core.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
class MMethod;
|
class MMethod;
|
||||||
class BinaryModule;
|
class BinaryModule;
|
||||||
|
|||||||
@@ -37,22 +37,22 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Ionic.Zip.Reduced">
|
<Reference Include="Ionic.Zip.Reduced">
|
||||||
<HintPath>..\..\..\Source\Platforms\DotNet\Ionic.Zip.Reduced.dll</HintPath>
|
<HintPath>..\..\Platforms\DotNet\Ionic.Zip.Reduced.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System.Text.Encoding.CodePages">
|
<Reference Include="System.Text.Encoding.CodePages">
|
||||||
<HintPath>..\..\..\Source\Platforms\DotNet\System.Text.Encoding.CodePages.dll</HintPath>
|
<HintPath>..\..\Platforms\DotNet\System.Text.Encoding.CodePages.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Mono.Cecil">
|
<Reference Include="Mono.Cecil">
|
||||||
<HintPath>..\..\..\Source\Platforms\DotNet\Mono.Cecil.dll</HintPath>
|
<HintPath>..\..\Platforms\DotNet\Mono.Cecil.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Microsoft.VisualStudio.Setup.Configuration.Interop">
|
<Reference Include="Microsoft.VisualStudio.Setup.Configuration.Interop">
|
||||||
<HintPath>..\..\..\Source\Platforms\DotNet\Microsoft.VisualStudio.Setup.Configuration.Interop.dll</HintPath>
|
<HintPath>..\..\Platforms\DotNet\Microsoft.VisualStudio.Setup.Configuration.Interop.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Microsoft.CodeAnalysis.CSharp">
|
<Reference Include="Microsoft.CodeAnalysis.CSharp">
|
||||||
<HintPath>..\..\..\Source\Platforms\DotNet\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
|
<HintPath>..\..\Platforms\DotNet\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Microsoft.CodeAnalysis">
|
<Reference Include="Microsoft.CodeAnalysis">
|
||||||
<HintPath>..\..\..\Source\Platforms\DotNet\Microsoft.CodeAnalysis.dll</HintPath>
|
<HintPath>..\..\Platforms\DotNet\Microsoft.CodeAnalysis.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace Flax.Build
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Specifies the minimum CPU architecture type to support (on x86/x64).
|
/// Specifies the minimum CPU architecture type to support (on x86/x64).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[CommandLine("winCpuArch", "<arch>", "Specifies the minimum CPU architecture type to support (om x86/x64).")]
|
[CommandLine("winCpuArch", "<arch>", "Specifies the minimum CPU architecture type to support (on x86/x64).")]
|
||||||
public static CpuArchitecture WindowsCpuArch = CpuArchitecture.SSE4_2; // 99.78% support on PC according to Steam Hardware & Software Survey: September 2025 (https://store.steampowered.com/hwsurvey/)
|
public static CpuArchitecture WindowsCpuArch = CpuArchitecture.SSE4_2; // 99.78% support on PC according to Steam Hardware & Software Survey: September 2025 (https://store.steampowered.com/hwsurvey/)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,22 +76,27 @@ namespace Flax.Build.Platforms
|
|||||||
options.LinkEnv.InputLibraries.Add("oleaut32.lib");
|
options.LinkEnv.InputLibraries.Add("oleaut32.lib");
|
||||||
options.LinkEnv.InputLibraries.Add("delayimp.lib");
|
options.LinkEnv.InputLibraries.Add("delayimp.lib");
|
||||||
|
|
||||||
if (options.Architecture == TargetArchitecture.ARM64)
|
options.CompileEnv.CpuArchitecture = Configuration.WindowsCpuArch;
|
||||||
|
|
||||||
|
if (options.Architecture == TargetArchitecture.x64)
|
||||||
|
{
|
||||||
|
if (_minVersion.Major <= 7 && options.CompileEnv.CpuArchitecture == CpuArchitecture.AVX2)
|
||||||
|
{
|
||||||
|
// Old Windows had lower support ratio for latest CPU features
|
||||||
|
options.CompileEnv.CpuArchitecture = CpuArchitecture.AVX;
|
||||||
|
}
|
||||||
|
if (_minVersion.Major >= 11 && options.CompileEnv.CpuArchitecture == CpuArchitecture.AVX)
|
||||||
|
{
|
||||||
|
// Windows 11 has hard requirement on SSE4.2
|
||||||
|
options.CompileEnv.CpuArchitecture = CpuArchitecture.SSE4_2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (options.Architecture == TargetArchitecture.ARM64)
|
||||||
{
|
{
|
||||||
options.CompileEnv.PreprocessorDefinitions.Add("USE_SOFT_INTRINSICS");
|
options.CompileEnv.PreprocessorDefinitions.Add("USE_SOFT_INTRINSICS");
|
||||||
options.LinkEnv.InputLibraries.Add("softintrin.lib");
|
options.LinkEnv.InputLibraries.Add("softintrin.lib");
|
||||||
}
|
if (options.CompileEnv.CpuArchitecture != CpuArchitecture.None)
|
||||||
|
options.CompileEnv.CpuArchitecture = CpuArchitecture.NEON;
|
||||||
options.CompileEnv.CpuArchitecture = Configuration.WindowsCpuArch;
|
|
||||||
if (_minVersion.Major <= 7 && options.CompileEnv.CpuArchitecture == CpuArchitecture.AVX2)
|
|
||||||
{
|
|
||||||
// Old Windows had lower support ratio for latest CPU features
|
|
||||||
options.CompileEnv.CpuArchitecture = CpuArchitecture.AVX;
|
|
||||||
}
|
|
||||||
if (_minVersion.Major >= 11 && options.CompileEnv.CpuArchitecture == CpuArchitecture.AVX)
|
|
||||||
{
|
|
||||||
// Windows 11 has hard requirement on SSE4.2
|
|
||||||
options.CompileEnv.CpuArchitecture = CpuArchitecture.SSE4_2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user