Merge branch 'FlaxEngine:master' into add_spline_edit_options
This commit is contained in:
BIN
Content/Editor/IconsAtlas.flax
(Stored with Git LFS)
BIN
Content/Editor/IconsAtlas.flax
(Stored with Git LFS)
Binary file not shown.
@@ -45,8 +45,14 @@ namespace FlaxEditor.Content.GUI
|
||||
|
||||
private void ImportActors(DragActors actors, ContentFolder location)
|
||||
{
|
||||
// Use only the first actor
|
||||
Editor.Instance.Prefabs.CreatePrefab(actors.Objects[0].Actor);
|
||||
foreach (var actorNode in actors.Objects)
|
||||
{
|
||||
var actor = actorNode.Actor;
|
||||
if (actors.Objects.Contains(actorNode.ParentNode as ActorNode))
|
||||
continue;
|
||||
|
||||
Editor.Instance.Prefabs.CreatePrefab(actor, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -33,7 +33,12 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
[CustomEditor(typeof(Asset)), DefaultEditor]
|
||||
public class AssetRefEditor : CustomEditor
|
||||
{
|
||||
private AssetPicker _picker;
|
||||
/// <summary>
|
||||
/// The asset picker used to get a reference to an asset.
|
||||
/// </summary>
|
||||
public AssetPicker Picker;
|
||||
|
||||
private bool _isRefreshing;
|
||||
private ScriptType _valueType;
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -44,7 +49,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
if (HasDifferentTypes)
|
||||
return;
|
||||
_picker = layout.Custom<AssetPicker>().CustomControl;
|
||||
Picker = layout.Custom<AssetPicker>().CustomControl;
|
||||
|
||||
_valueType = Values.Type.Type != typeof(object) || Values[0] == null ? Values.Type : TypeUtils.GetObjectType(Values[0]);
|
||||
var assetType = _valueType;
|
||||
@@ -66,7 +71,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
// Generic file picker
|
||||
assetType = ScriptType.Null;
|
||||
_picker.FileExtension = assetReference.TypeName;
|
||||
Picker.FileExtension = assetReference.TypeName;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -75,26 +80,30 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
assetType = customType;
|
||||
else if (!Content.Settings.GameSettings.OptionalPlatformSettings.Contains(assetReference.TypeName))
|
||||
Debug.LogWarning(string.Format("Unknown asset type '{0}' to use for asset picker filter.", assetReference.TypeName));
|
||||
else
|
||||
assetType = ScriptType.Void;
|
||||
}
|
||||
}
|
||||
|
||||
_picker.AssetType = assetType;
|
||||
_picker.Height = height;
|
||||
_picker.SelectedItemChanged += OnSelectedItemChanged;
|
||||
Picker.AssetType = assetType;
|
||||
Picker.Height = height;
|
||||
Picker.SelectedItemChanged += OnSelectedItemChanged;
|
||||
}
|
||||
|
||||
private void OnSelectedItemChanged()
|
||||
{
|
||||
if (_isRefreshing)
|
||||
return;
|
||||
if (typeof(AssetItem).IsAssignableFrom(_valueType.Type))
|
||||
SetValue(_picker.SelectedItem);
|
||||
SetValue(Picker.SelectedItem);
|
||||
else if (_valueType.Type == typeof(Guid))
|
||||
SetValue(_picker.SelectedID);
|
||||
SetValue(Picker.SelectedID);
|
||||
else if (_valueType.Type == typeof(SceneReference))
|
||||
SetValue(new SceneReference(_picker.SelectedID));
|
||||
SetValue(new SceneReference(Picker.SelectedID));
|
||||
else if (_valueType.Type == typeof(string))
|
||||
SetValue(_picker.SelectedPath);
|
||||
SetValue(Picker.SelectedPath);
|
||||
else
|
||||
SetValue(_picker.SelectedAsset);
|
||||
SetValue(Picker.SelectedAsset);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -104,16 +113,18 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
if (!HasDifferentValues)
|
||||
{
|
||||
_isRefreshing = true;
|
||||
if (Values[0] is AssetItem assetItem)
|
||||
_picker.SelectedItem = assetItem;
|
||||
Picker.SelectedItem = assetItem;
|
||||
else if (Values[0] is Guid guid)
|
||||
_picker.SelectedID = guid;
|
||||
Picker.SelectedID = guid;
|
||||
else if (Values[0] is SceneReference sceneAsset)
|
||||
_picker.SelectedItem = Editor.Instance.ContentDatabase.FindAsset(sceneAsset.ID);
|
||||
Picker.SelectedItem = Editor.Instance.ContentDatabase.FindAsset(sceneAsset.ID);
|
||||
else if (Values[0] is string path)
|
||||
_picker.SelectedPath = path;
|
||||
Picker.SelectedPath = path;
|
||||
else
|
||||
_picker.SelectedAsset = Values[0] as Asset;
|
||||
Picker.SelectedAsset = Values[0] as Asset;
|
||||
_isRefreshing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEditor.CustomEditors.Elements;
|
||||
using FlaxEditor.CustomEditors.GUI;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
@@ -13,6 +15,11 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
private GroupElement _group;
|
||||
private bool _updateName;
|
||||
private int _entryIndex;
|
||||
private bool _isRefreshing;
|
||||
private MaterialBase _material;
|
||||
private ModelInstanceActor _modelInstance;
|
||||
private AssetRefEditor _materialEditor;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
@@ -21,47 +28,122 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var group = layout.Group("Entry");
|
||||
_group = group;
|
||||
|
||||
if (ParentEditor == null)
|
||||
return;
|
||||
var entry = (ModelInstanceEntry)Values[0];
|
||||
var entryIndex = ParentEditor.ChildrenEditors.IndexOf(this);
|
||||
var materialLabel = new PropertyNameLabel("Material");
|
||||
materialLabel.TooltipText = "The mesh surface material used for the rendering.";
|
||||
if (ParentEditor.ParentEditor?.Values[0] is ModelInstanceActor modelInstance)
|
||||
{
|
||||
_entryIndex = entryIndex;
|
||||
_modelInstance = modelInstance;
|
||||
var slots = modelInstance.MaterialSlots;
|
||||
if (entry.Material == slots[entryIndex].Material)
|
||||
{
|
||||
// Ensure that entry with default material set is set back to null
|
||||
modelInstance.SetMaterial(entryIndex, null);
|
||||
}
|
||||
_material = modelInstance.GetMaterial(entryIndex);
|
||||
var defaultValue = GPUDevice.Instance.DefaultMaterial;
|
||||
if (slots[entryIndex].Material)
|
||||
{
|
||||
// Use default value set on asset (eg. Model Asset)
|
||||
defaultValue = slots[entryIndex].Material;
|
||||
}
|
||||
|
||||
// Create material picker
|
||||
var materialValue = new CustomValueContainer(new ScriptType(typeof(MaterialBase)), _material, (instance, index) => _material, (instance, index, value) => _material = value as MaterialBase);
|
||||
var materialEditor = (AssetRefEditor)_group.Property(materialLabel, materialValue);
|
||||
materialEditor.Values.SetDefaultValue(defaultValue);
|
||||
materialEditor.RefreshDefaultValue();
|
||||
materialEditor.Picker.SelectedItemChanged += OnSelectedMaterialChanged;
|
||||
_materialEditor = materialEditor;
|
||||
}
|
||||
|
||||
base.Initialize(group);
|
||||
}
|
||||
|
||||
private void OnSelectedMaterialChanged()
|
||||
{
|
||||
if (_isRefreshing)
|
||||
return;
|
||||
_isRefreshing = true;
|
||||
var slots = _modelInstance.MaterialSlots;
|
||||
var material = _materialEditor.Picker.SelectedAsset as MaterialBase;
|
||||
var defaultMaterial = GPUDevice.Instance.DefaultMaterial;
|
||||
var value = (ModelInstanceEntry)Values[0];
|
||||
var prevMaterial = value.Material;
|
||||
if (!material)
|
||||
{
|
||||
// Fallback to default material
|
||||
_materialEditor.Picker.SelectedAsset = defaultMaterial;
|
||||
value.Material = defaultMaterial;
|
||||
}
|
||||
else if (material == slots[_entryIndex].Material)
|
||||
{
|
||||
// Asset default material
|
||||
value.Material = null;
|
||||
}
|
||||
else if (material == defaultMaterial && !slots[_entryIndex].Material)
|
||||
{
|
||||
// Default material while asset has no set as well
|
||||
value.Material = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Custom material
|
||||
value.Material = material;
|
||||
}
|
||||
if (prevMaterial != value.Material)
|
||||
SetValue(value);
|
||||
_isRefreshing = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void SpawnProperty(LayoutElementsContainer itemLayout, ValueContainer itemValues, ItemInfo item)
|
||||
{
|
||||
// Skip material member as it is overridden
|
||||
if (item.Info.Name == "Material" && _materialEditor != null)
|
||||
return;
|
||||
base.SpawnProperty(itemLayout, itemValues, item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
// Update panel title to match material slot name
|
||||
if (_updateName &&
|
||||
_group != null &&
|
||||
ParentEditor?.ParentEditor != null &&
|
||||
ParentEditor.ParentEditor.Values.Count > 0)
|
||||
{
|
||||
var entryIndex = ParentEditor.ChildrenEditors.IndexOf(this);
|
||||
if (ParentEditor.ParentEditor.Values[0] is StaticModel staticModel)
|
||||
if (ParentEditor.ParentEditor.Values[0] is ModelInstanceActor modelInstance)
|
||||
{
|
||||
var model = staticModel.Model;
|
||||
if (model && model.IsLoaded)
|
||||
var slots = modelInstance.MaterialSlots;
|
||||
if (slots != null && slots.Length > entryIndex)
|
||||
{
|
||||
var slots = model.MaterialSlots;
|
||||
if (slots != null && slots.Length > entryIndex)
|
||||
{
|
||||
_group.Panel.HeaderText = "Entry " + slots[entryIndex].Name;
|
||||
_updateName = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ParentEditor.ParentEditor.Values[0] is AnimatedModel animatedModel)
|
||||
{
|
||||
var model = animatedModel.SkinnedModel;
|
||||
if (model && model.IsLoaded)
|
||||
{
|
||||
var slots = model.MaterialSlots;
|
||||
if (slots != null && slots.Length > entryIndex)
|
||||
{
|
||||
_group.Panel.HeaderText = "Entry " + slots[entryIndex].Name;
|
||||
_updateName = false;
|
||||
}
|
||||
_updateName = false;
|
||||
_group.Panel.HeaderText = "Entry " + slots[entryIndex].Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh currently selected material
|
||||
_material = _modelInstance.GetMaterial(_entryIndex);
|
||||
|
||||
base.Refresh();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
_material = null;
|
||||
_modelInstance = null;
|
||||
_materialEditor = null;
|
||||
|
||||
base.Deinitialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ namespace FlaxEditor
|
||||
public SpriteHandle Link64;
|
||||
public SpriteHandle Build64;
|
||||
public SpriteHandle Add64;
|
||||
public SpriteHandle ShipIt64;
|
||||
|
||||
// 96px
|
||||
public SpriteHandle Toolbox96;
|
||||
|
||||
@@ -475,22 +475,31 @@ namespace FlaxEditor.GUI
|
||||
if (_type != ScriptType.Null)
|
||||
{
|
||||
// Show asset picker popup
|
||||
AssetSearchPopup.Show(this, Button1Rect.BottomLeft, IsValid, item =>
|
||||
var popup = AssetSearchPopup.Show(this, Button1Rect.BottomLeft, IsValid, item =>
|
||||
{
|
||||
SelectedItem = item;
|
||||
RootWindow.Focus();
|
||||
Focus();
|
||||
});
|
||||
if (_selected != null)
|
||||
{
|
||||
var selectedAssetName = Path.GetFileNameWithoutExtension(_selected.Path);
|
||||
popup.ScrollToAndHighlightItemByName(selectedAssetName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show content item picker popup
|
||||
ContentSearchPopup.Show(this, Button1Rect.BottomLeft, IsValid, item =>
|
||||
var popup = ContentSearchPopup.Show(this, Button1Rect.BottomLeft, IsValid, item =>
|
||||
{
|
||||
SelectedItem = item;
|
||||
RootWindow.Focus();
|
||||
Focus();
|
||||
});
|
||||
if (_selectedItem != null)
|
||||
{
|
||||
popup.ScrollToAndHighlightItemByName(_selectedItem.ShortName);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_selected != null || _selectedItem != null)
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.GUI.ContextMenu
|
||||
{
|
||||
/// <summary>
|
||||
/// Context menu for a single selectable option from range of values (eg. enum).
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
class ContextMenuSingleSelectGroup<T>
|
||||
{
|
||||
private struct SingleSelectGroupItem
|
||||
{
|
||||
public string Text;
|
||||
public string Tooltip;
|
||||
public T Value;
|
||||
public Action Selected;
|
||||
public List<ContextMenuButton> Buttons;
|
||||
}
|
||||
|
||||
private List<ContextMenu> _menus = new List<ContextMenu>();
|
||||
private List<SingleSelectGroupItem> _items = new List<SingleSelectGroupItem>();
|
||||
private SingleSelectGroupItem _selectedItem;
|
||||
|
||||
public T Selected
|
||||
{
|
||||
get => _selectedItem.Value;
|
||||
set
|
||||
{
|
||||
var index = _items.FindIndex(x => x.Value.Equals(value));
|
||||
if (index != -1 && !_selectedItem.Value.Equals(value))
|
||||
{
|
||||
SetSelected(_items[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Action<T> SelectedChanged;
|
||||
|
||||
public ContextMenuSingleSelectGroup<T> AddItem(string text, T value, Action selected = null, string tooltip = null)
|
||||
{
|
||||
var item = new SingleSelectGroupItem
|
||||
{
|
||||
Text = text,
|
||||
Tooltip = tooltip,
|
||||
Value = value,
|
||||
Selected = selected,
|
||||
Buttons = new List<ContextMenuButton>()
|
||||
};
|
||||
_items.Add(item);
|
||||
foreach (var contextMenu in _menus)
|
||||
AddItemToContextMenu(contextMenu, item);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ContextMenuSingleSelectGroup<T> AddItemsToContextMenu(ContextMenu contextMenu)
|
||||
{
|
||||
_menus.Add(contextMenu);
|
||||
for (int i = 0; i < _items.Count; i++)
|
||||
AddItemToContextMenu(contextMenu, _items[i]);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void AddItemToContextMenu(ContextMenu contextMenu, SingleSelectGroupItem item)
|
||||
{
|
||||
var btn = contextMenu.AddButton(item.Text, () => { SetSelected(item); });
|
||||
if (item.Tooltip != null)
|
||||
btn.TooltipText = item.Tooltip;
|
||||
item.Buttons.Add(btn);
|
||||
if (item.Equals(_selectedItem))
|
||||
btn.Checked = true;
|
||||
}
|
||||
|
||||
private void SetSelected(SingleSelectGroupItem item)
|
||||
{
|
||||
foreach (var e in _items)
|
||||
{
|
||||
foreach (var btn in e.Buttons)
|
||||
btn.Checked = false;
|
||||
}
|
||||
_selectedItem = item;
|
||||
|
||||
SelectedChanged?.Invoke(item.Value);
|
||||
item.Selected?.Invoke();
|
||||
|
||||
foreach (var btn in item.Buttons)
|
||||
btn.Checked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -265,6 +265,35 @@ namespace FlaxEditor.GUI
|
||||
_searchBox.Focus();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls the scroll panel to a specific Item
|
||||
/// </summary>
|
||||
/// <param name="item">The item to scroll to.</param>
|
||||
public void ScrollViewTo(Item item)
|
||||
{
|
||||
_scrollPanel.ScrollViewTo(item, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls to the item and focuses it by name.
|
||||
/// </summary>
|
||||
/// <param name="itemName">The item name.</param>
|
||||
public void ScrollToAndHighlightItemByName(string itemName)
|
||||
{
|
||||
foreach (var child in ItemsPanel.Children)
|
||||
{
|
||||
if (child is not ItemsListContextMenu.Item item)
|
||||
continue;
|
||||
if (string.Equals(item.Name, itemName, StringComparison.Ordinal))
|
||||
{
|
||||
// Highlight and scroll to item
|
||||
item.Focus();
|
||||
ScrollViewTo(item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts the items list (by item name by default).
|
||||
/// </summary>
|
||||
|
||||
@@ -23,10 +23,15 @@ namespace FlaxEditor.GUI
|
||||
public const int DefaultMarginH = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when button gets clicked.
|
||||
/// Event fired when button gets clicked with the primary mouse button.
|
||||
/// </summary>
|
||||
public Action<ToolStripButton> ButtonClicked;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when button gets clicked with the secondary mouse button.
|
||||
/// </summary>
|
||||
public Action<ToolStripButton> SecondaryButtonClicked;
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the last button.
|
||||
/// </summary>
|
||||
@@ -146,6 +151,11 @@ namespace FlaxEditor.GUI
|
||||
ButtonClicked?.Invoke(button);
|
||||
}
|
||||
|
||||
internal void OnSecondaryButtonClicked(ToolStripButton button)
|
||||
{
|
||||
SecondaryButtonClicked?.Invoke(button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void PerformLayoutBeforeChildren()
|
||||
{
|
||||
|
||||
@@ -20,13 +20,19 @@ namespace FlaxEditor.GUI
|
||||
|
||||
private SpriteHandle _icon;
|
||||
private string _text;
|
||||
private bool _mouseDown;
|
||||
private bool _primaryMouseDown;
|
||||
private bool _secondaryMouseDown;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when user clicks the button.
|
||||
/// </summary>
|
||||
public Action Clicked;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when user clicks the button.
|
||||
/// </summary>
|
||||
public Action SecondaryClicked;
|
||||
|
||||
/// <summary>
|
||||
/// The checked state.
|
||||
/// </summary>
|
||||
@@ -63,6 +69,11 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A reference to a context menu to raise when the secondary mouse button is pressed.
|
||||
/// </summary>
|
||||
public ContextMenu.ContextMenu ContextMenu;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ToolStripButton"/> class.
|
||||
/// </summary>
|
||||
@@ -108,10 +119,11 @@ namespace FlaxEditor.GUI
|
||||
var iconRect = new Rectangle(DefaultMargin, DefaultMargin, iconSize, iconSize);
|
||||
var textRect = new Rectangle(DefaultMargin, 0, 0, Height);
|
||||
bool enabled = EnabledInHierarchy;
|
||||
bool mouseButtonDown = _primaryMouseDown || _secondaryMouseDown;
|
||||
|
||||
// Draw background
|
||||
if (enabled && (IsMouseOver || IsNavFocused || Checked))
|
||||
Render2D.FillRectangle(clientRect, Checked ? style.BackgroundSelected : _mouseDown ? style.BackgroundHighlighted : (style.LightBackground * 1.3f));
|
||||
Render2D.FillRectangle(clientRect, Checked ? style.BackgroundSelected : mouseButtonDown ? style.BackgroundHighlighted : (style.LightBackground * 1.3f));
|
||||
|
||||
// Draw icon
|
||||
if (_icon.IsValid)
|
||||
@@ -124,13 +136,7 @@ namespace FlaxEditor.GUI
|
||||
if (!string.IsNullOrEmpty(_text))
|
||||
{
|
||||
textRect.Size.X = Width - DefaultMargin - textRect.Left;
|
||||
Render2D.DrawText(
|
||||
style.FontMedium,
|
||||
_text,
|
||||
textRect,
|
||||
enabled ? style.Foreground : style.ForegroundDisabled,
|
||||
TextAlignment.Near,
|
||||
TextAlignment.Center);
|
||||
Render2D.DrawText(style.FontMedium, _text, textRect, enabled ? style.Foreground : style.ForegroundDisabled, TextAlignment.Near, TextAlignment.Center);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,9 +161,13 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
// Set flag
|
||||
_mouseDown = true;
|
||||
|
||||
_primaryMouseDown = true;
|
||||
Focus();
|
||||
return true;
|
||||
}
|
||||
if (button == MouseButton.Right)
|
||||
{
|
||||
_secondaryMouseDown = true;
|
||||
Focus();
|
||||
return true;
|
||||
}
|
||||
@@ -168,12 +178,9 @@ namespace FlaxEditor.GUI
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _mouseDown)
|
||||
if (button == MouseButton.Left && _primaryMouseDown)
|
||||
{
|
||||
// Clear flag
|
||||
_mouseDown = false;
|
||||
|
||||
// Fire events
|
||||
_primaryMouseDown = false;
|
||||
if (AutoCheck)
|
||||
Checked = !Checked;
|
||||
Clicked?.Invoke();
|
||||
@@ -181,6 +188,14 @@ namespace FlaxEditor.GUI
|
||||
|
||||
return true;
|
||||
}
|
||||
if (button == MouseButton.Right && _secondaryMouseDown)
|
||||
{
|
||||
_secondaryMouseDown = false;
|
||||
SecondaryClicked?.Invoke();
|
||||
(Parent as ToolStrip)?.OnSecondaryButtonClicked(this);
|
||||
ContextMenu?.Show(this, new Float2(0, Height));
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
@@ -188,8 +203,8 @@ namespace FlaxEditor.GUI
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseLeave()
|
||||
{
|
||||
// Clear flag
|
||||
_mouseDown = false;
|
||||
_primaryMouseDown = false;
|
||||
_secondaryMouseDown = false;
|
||||
|
||||
base.OnMouseLeave();
|
||||
}
|
||||
@@ -197,8 +212,8 @@ namespace FlaxEditor.GUI
|
||||
/// <inheritdoc />
|
||||
public override void OnLostFocus()
|
||||
{
|
||||
// Clear flag
|
||||
_mouseDown = false;
|
||||
_primaryMouseDown = false;
|
||||
_secondaryMouseDown = false;
|
||||
|
||||
base.OnLostFocus();
|
||||
}
|
||||
|
||||
@@ -46,20 +46,19 @@ namespace FlaxEditor.Gizmo
|
||||
var plane = new Plane(Vector3.Zero, Vector3.UnitY);
|
||||
var dst = CollisionsHelper.DistancePlanePoint(ref plane, ref viewPos);
|
||||
|
||||
float space, size;
|
||||
float space = Editor.Instance.Options.Options.Viewport.ViewportGridScale, size;
|
||||
if (dst <= 500.0f)
|
||||
{
|
||||
space = 50;
|
||||
size = 8000;
|
||||
}
|
||||
else if (dst <= 2000.0f)
|
||||
{
|
||||
space = 100;
|
||||
space *= 2;
|
||||
size = 8000;
|
||||
}
|
||||
else
|
||||
{
|
||||
space = 1000;
|
||||
space *= 20;
|
||||
size = 100000;
|
||||
}
|
||||
|
||||
|
||||
@@ -178,6 +178,8 @@ namespace FlaxEditor.Gizmo
|
||||
if (selection[i] is ActorNode actorNode && actorNode.Actor != null)
|
||||
CollectActors(actorNode.Actor);
|
||||
}
|
||||
if (_actors.Count == 0)
|
||||
return;
|
||||
|
||||
// Render selected objects depth
|
||||
Renderer.DrawSceneDepth(context, task, customDepth, _actors);
|
||||
|
||||
@@ -469,7 +469,7 @@ namespace FlaxEditor.Gizmo
|
||||
}
|
||||
|
||||
// Apply transformation (but to the parents, not whole selection pool)
|
||||
if (anyValid || (!_isTransforming && Owner.UseDuplicate))
|
||||
if (anyValid || (_isTransforming && Owner.UseDuplicate))
|
||||
{
|
||||
StartTransforming();
|
||||
LastDelta = new Transform(translationDelta, rotationDelta, scaleDelta);
|
||||
|
||||
@@ -37,6 +37,11 @@ namespace FlaxEditor.Modules
|
||||
/// </summary>
|
||||
public event Action<Prefab, Actor> PrefabApplied;
|
||||
|
||||
/// <summary>
|
||||
/// Locally cached actor for prefab creation.
|
||||
/// </summary>
|
||||
private Actor _prefabCreationActor;
|
||||
|
||||
internal PrefabsModule(Editor editor)
|
||||
: base(editor)
|
||||
{
|
||||
@@ -78,6 +83,16 @@ namespace FlaxEditor.Modules
|
||||
/// </remarks>
|
||||
/// <param name="actor">The root prefab actor.</param>
|
||||
public void CreatePrefab(Actor actor)
|
||||
{
|
||||
CreatePrefab(actor, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the creating prefab for the given actor by showing the new item creation dialog in <see cref="ContentWindow"/>.
|
||||
/// </summary>
|
||||
/// <param name="actor">The root prefab actor.</param>
|
||||
/// <param name="rename">Allow renaming or not</param>
|
||||
public void CreatePrefab(Actor actor, bool rename)
|
||||
{
|
||||
// Skip in invalid states
|
||||
if (!Editor.StateMachine.CurrentState.CanEditContent)
|
||||
@@ -90,7 +105,8 @@ namespace FlaxEditor.Modules
|
||||
PrefabCreating?.Invoke(actor);
|
||||
|
||||
var proxy = Editor.ContentDatabase.GetProxy<Prefab>();
|
||||
Editor.Windows.ContentWin.NewItem(proxy, actor, OnPrefabCreated, actor.Name);
|
||||
_prefabCreationActor = actor;
|
||||
Editor.Windows.ContentWin.NewItem(proxy, actor, OnPrefabCreated, actor.Name, rename);
|
||||
}
|
||||
|
||||
private void OnPrefabCreated(ContentItem contentItem)
|
||||
@@ -107,25 +123,21 @@ namespace FlaxEditor.Modules
|
||||
// Record undo for prefab creating (backend links the target instance with the prefab)
|
||||
if (Editor.Undo.Enabled)
|
||||
{
|
||||
var selection = Editor.SceneEditing.Selection.Where(x => x is ActorNode).ToList().BuildNodesParents();
|
||||
if (selection.Count == 0)
|
||||
if (!_prefabCreationActor)
|
||||
return;
|
||||
|
||||
if (selection.Count == 1)
|
||||
var actorsList = new List<Actor>();
|
||||
Utilities.Utils.GetActorsTree(actorsList, _prefabCreationActor);
|
||||
|
||||
var actions = new IUndoAction[actorsList.Count];
|
||||
for (int i = 0; i < actorsList.Count; i++)
|
||||
{
|
||||
var action = BreakPrefabLinkAction.Linked(((ActorNode)selection[0]).Actor);
|
||||
Undo.AddAction(action);
|
||||
}
|
||||
else
|
||||
{
|
||||
var actions = new IUndoAction[selection.Count];
|
||||
for (int i = 0; i < selection.Count; i++)
|
||||
{
|
||||
var action = BreakPrefabLinkAction.Linked(((ActorNode)selection[i]).Actor);
|
||||
actions[i] = action;
|
||||
}
|
||||
Undo.AddAction(new MultiUndoAction(actions));
|
||||
var action = BreakPrefabLinkAction.Linked(actorsList[i]);
|
||||
actions[i] = action;
|
||||
}
|
||||
Undo.AddAction(new MultiUndoAction(actions));
|
||||
|
||||
_prefabCreationActor = null;
|
||||
}
|
||||
|
||||
Editor.Instance.Windows.PropertiesWin.Presenter.BuildLayout();
|
||||
|
||||
@@ -20,6 +20,8 @@ using FlaxEngine.GUI;
|
||||
using FlaxEngine.Json;
|
||||
using DockHintWindow = FlaxEditor.GUI.Docking.DockHintWindow;
|
||||
using MasterDockPanel = FlaxEditor.GUI.Docking.MasterDockPanel;
|
||||
using FlaxEditor.Content.Settings;
|
||||
using FlaxEditor.Options;
|
||||
|
||||
namespace FlaxEditor.Modules
|
||||
{
|
||||
@@ -36,6 +38,9 @@ namespace FlaxEditor.Modules
|
||||
private ContentStats _contentStats;
|
||||
private bool _progressFailed;
|
||||
|
||||
ContextMenuSingleSelectGroup<int> _numberOfClientsGroup = new ContextMenuSingleSelectGroup<int>();
|
||||
private Scene[] _scenesToReload;
|
||||
|
||||
private ContextMenuButton _menuFileSaveScenes;
|
||||
private ContextMenuButton _menuFileCloseScenes;
|
||||
private ContextMenuButton _menuFileGenerateScriptsProjectFiles;
|
||||
@@ -54,7 +59,9 @@ namespace FlaxEditor.Modules
|
||||
private ContextMenuButton _menuSceneAlignViewportWithActor;
|
||||
private ContextMenuButton _menuScenePilotActor;
|
||||
private ContextMenuButton _menuSceneCreateTerrain;
|
||||
private ContextMenuButton _menuGamePlay;
|
||||
private ContextMenuButton _menuGamePlayGame;
|
||||
private ContextMenuButton _menuGamePlayCurrentScenes;
|
||||
private ContextMenuButton _menuGameStop;
|
||||
private ContextMenuButton _menuGamePause;
|
||||
private ContextMenuButton _menuToolsBuildScenes;
|
||||
private ContextMenuButton _menuToolsBakeLightmaps;
|
||||
@@ -74,6 +81,7 @@ namespace FlaxEditor.Modules
|
||||
private ToolStripButton _toolStripRotate;
|
||||
private ToolStripButton _toolStripScale;
|
||||
private ToolStripButton _toolStripBuildScenes;
|
||||
private ToolStripButton _toolStripCook;
|
||||
private ToolStripButton _toolStripPlay;
|
||||
private ToolStripButton _toolStripPause;
|
||||
private ToolStripButton _toolStripStep;
|
||||
@@ -195,6 +203,7 @@ namespace FlaxEditor.Modules
|
||||
_toolStripScale.Checked = gizmoMode == TransformGizmoBase.Mode.Scale;
|
||||
//
|
||||
_toolStripBuildScenes.Enabled = (canEditScene && !isPlayMode) || Editor.StateMachine.BuildingScenesState.IsActive;
|
||||
_toolStripCook.Enabled = Editor.Windows.GameCookerWin.CanBuild(Platform.PlatformType) && !GameCooker.IsRunning;
|
||||
//
|
||||
var play = _toolStripPlay;
|
||||
var pause = _toolStripPause;
|
||||
@@ -351,6 +360,7 @@ namespace FlaxEditor.Modules
|
||||
// Update window background
|
||||
mainWindow.BackgroundColor = Style.Current.Background;
|
||||
|
||||
InitSharedMenus();
|
||||
InitMainMenu(mainWindow);
|
||||
InitToolstrip(mainWindow);
|
||||
InitStatusBar(mainWindow);
|
||||
@@ -409,6 +419,7 @@ namespace FlaxEditor.Modules
|
||||
Editor.Undo.UndoDone += OnUndoEvent;
|
||||
Editor.Undo.RedoDone += OnUndoEvent;
|
||||
Editor.Undo.ActionDone += OnUndoEvent;
|
||||
GameCooker.Event += OnGameCookerEvent;
|
||||
|
||||
UpdateToolstrip();
|
||||
}
|
||||
@@ -424,6 +435,11 @@ namespace FlaxEditor.Modules
|
||||
UpdateStatusBar();
|
||||
}
|
||||
|
||||
private void OnGameCookerEvent(GameCooker.EventType type)
|
||||
{
|
||||
UpdateToolstrip();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnExit()
|
||||
{
|
||||
@@ -466,6 +482,22 @@ namespace FlaxEditor.Modules
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private void InitSharedMenus()
|
||||
{
|
||||
for (int i = 1; i <= 4; i++)
|
||||
_numberOfClientsGroup.AddItem(i.ToString(), i);
|
||||
|
||||
_numberOfClientsGroup.Selected = Editor.Options.Options.Interface.NumberOfGameClientsToLaunch;
|
||||
_numberOfClientsGroup.SelectedChanged = value =>
|
||||
{
|
||||
var options = Editor.Options.Options;
|
||||
options.Interface.NumberOfGameClientsToLaunch = value;
|
||||
Editor.Options.Apply(options);
|
||||
};
|
||||
|
||||
Editor.Options.OptionsChanged += options => { _numberOfClientsGroup.Selected = options.Interface.NumberOfGameClientsToLaunch; };
|
||||
}
|
||||
|
||||
private void InitMainMenu(RootControl mainWindow)
|
||||
{
|
||||
MainMenu = new MainMenu(mainWindow)
|
||||
@@ -523,11 +555,19 @@ namespace FlaxEditor.Modules
|
||||
MenuGame = MainMenu.AddButton("Game");
|
||||
cm = MenuGame.ContextMenu;
|
||||
cm.VisibleChanged += OnMenuGameShowHide;
|
||||
_menuGamePlay = cm.AddButton("Play", inputOptions.Play.ToString(), Editor.Simulation.RequestStartPlay);
|
||||
|
||||
_menuGamePlayGame = cm.AddButton("Play Game", PlayGame);
|
||||
_menuGamePlayCurrentScenes = cm.AddButton("Play Current Scenes", inputOptions.Play.ToString(), PlayScenes);
|
||||
_menuGameStop = cm.AddButton("Stop Game", Editor.Simulation.RequestStopPlay);
|
||||
_menuGamePause = cm.AddButton("Pause", inputOptions.Pause.ToString(), Editor.Simulation.RequestPausePlay);
|
||||
|
||||
cm.AddSeparator();
|
||||
cm.AddButton("Cook & Run", Editor.Windows.GameCookerWin.BuildAndRun).LinkTooltip("Runs Game Cooker to build the game for this platform and runs the game after.");
|
||||
cm.AddButton("Run cooked game", Editor.Windows.GameCookerWin.RunCooked).LinkTooltip("Runs the game build from the last cooking output. Use Cook&Play or Game Cooker first.");
|
||||
var numberOfClientsMenu = cm.AddChildMenu("Number of game clients");
|
||||
_numberOfClientsGroup.AddItemsToContextMenu(numberOfClientsMenu.ContextMenu);
|
||||
|
||||
cm.AddSeparator();
|
||||
cm.AddButton("Cook & Run", CookAndRun).LinkTooltip("Runs Game Cooker to build the game for this platform and runs the game after.");
|
||||
cm.AddButton("Run cooked game", RunCookedGame).LinkTooltip("Runs the game build from the last cooking output. Use Cook&Play or Game Cooker first.");
|
||||
|
||||
// Tools
|
||||
MenuTools = MainMenu.AddButton("Tools");
|
||||
@@ -603,7 +643,7 @@ namespace FlaxEditor.Modules
|
||||
_menuEditDuplicate.ShortKeys = inputOptions.Duplicate.ToString();
|
||||
_menuEditSelectAll.ShortKeys = inputOptions.SelectAll.ToString();
|
||||
_menuEditFind.ShortKeys = inputOptions.Search.ToString();
|
||||
_menuGamePlay.ShortKeys = inputOptions.Play.ToString();
|
||||
_menuGamePlayCurrentScenes.ShortKeys = inputOptions.Play.ToString();
|
||||
_menuGamePause.ShortKeys = inputOptions.Pause.ToString();
|
||||
|
||||
MainMenuShortcutKeysUpdated?.Invoke();
|
||||
@@ -611,6 +651,8 @@ namespace FlaxEditor.Modules
|
||||
|
||||
private void InitToolstrip(RootControl mainWindow)
|
||||
{
|
||||
var inputOptions = Editor.Options.Options.Input;
|
||||
|
||||
ToolStrip = new ToolStrip(34.0f, MainMenu.Bottom)
|
||||
{
|
||||
Parent = mainWindow,
|
||||
@@ -625,10 +667,33 @@ namespace FlaxEditor.Modules
|
||||
_toolStripRotate = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Rotate32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate).LinkTooltip("Change Gizmo tool mode to Rotate (2)");
|
||||
_toolStripScale = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Scale32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale).LinkTooltip("Change Gizmo tool mode to Scale (3)");
|
||||
ToolStrip.AddSeparator();
|
||||
|
||||
// Cook scenes
|
||||
_toolStripBuildScenes = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Build64, Editor.BuildScenesOrCancel).LinkTooltip("Build scenes data - CSG, navmesh, static lighting, env probes - configurable via Build Actions in editor options (Ctrl+F10)");
|
||||
|
||||
// Cook and run
|
||||
_toolStripCook = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.ShipIt64, CookAndRun).LinkTooltip("Cook & Run - build game for the current platform and run it locally");
|
||||
_toolStripCook.ContextMenu = new ContextMenu();
|
||||
_toolStripCook.ContextMenu.AddButton("Run cooked game", RunCookedGame);
|
||||
_toolStripCook.ContextMenu.AddSeparator();
|
||||
var numberOfClientsMenu = _toolStripCook.ContextMenu.AddChildMenu("Number of game clients");
|
||||
_numberOfClientsGroup.AddItemsToContextMenu(numberOfClientsMenu.ContextMenu);
|
||||
|
||||
ToolStrip.AddSeparator();
|
||||
_toolStripPlay = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Play64, Editor.Simulation.RequestPlayOrStopPlay).LinkTooltip("Start/Stop game (F5)");
|
||||
_toolStripPause = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Pause64, Editor.Simulation.RequestResumeOrPause).LinkTooltip("Pause/Resume game(F6)");
|
||||
|
||||
// Play
|
||||
_toolStripPlay = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Play64, OnPlayPressed).LinkTooltip("Play Game");
|
||||
_toolStripPlay.ContextMenu = new ContextMenu();
|
||||
var playSubMenu = _toolStripPlay.ContextMenu.AddChildMenu("Play button action");
|
||||
var playActionGroup = new ContextMenuSingleSelectGroup<InterfaceOptions.PlayAction>();
|
||||
playActionGroup.AddItem("Play Game", InterfaceOptions.PlayAction.PlayGame, null, "Launches the game from the First Scene defined in the project settings.");
|
||||
playActionGroup.AddItem("Play Scenes", InterfaceOptions.PlayAction.PlayScenes, null, "Launches the game using the scenes currently loaded in the editor.");
|
||||
playActionGroup.AddItemsToContextMenu(playSubMenu.ContextMenu);
|
||||
playActionGroup.Selected = Editor.Options.Options.Interface.PlayButtonAction;
|
||||
playActionGroup.SelectedChanged = SetPlayAction;
|
||||
Editor.Options.OptionsChanged += options => { playActionGroup.Selected = options.Interface.PlayButtonAction; };
|
||||
|
||||
_toolStripPause = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Pause64, Editor.Simulation.RequestResumeOrPause).LinkTooltip($"Pause/Resume game({inputOptions.Pause})");
|
||||
_toolStripStep = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Skip64, Editor.Simulation.RequestPlayOneFrame).LinkTooltip("Step one frame in game");
|
||||
|
||||
UpdateToolstrip();
|
||||
@@ -663,10 +728,7 @@ namespace FlaxEditor.Modules
|
||||
var defaultTextColor = StatusBar.TextColor;
|
||||
_outputLogButton.HoverBegin += () => StatusBar.TextColor = Style.Current.BackgroundSelected;
|
||||
_outputLogButton.HoverEnd += () => StatusBar.TextColor = defaultTextColor;
|
||||
_outputLogButton.Clicked += () =>
|
||||
{
|
||||
Editor.Windows.OutputLogWin.FocusOrShow();
|
||||
};
|
||||
_outputLogButton.Clicked += () => { Editor.Windows.OutputLogWin.FocusOrShow(); };
|
||||
|
||||
// Progress bar with label
|
||||
const float progressBarWidth = 120.0f;
|
||||
@@ -786,7 +848,9 @@ namespace FlaxEditor.Modules
|
||||
var isPlayMode = Editor.StateMachine.IsPlayMode;
|
||||
var canPlay = Level.IsAnySceneLoaded;
|
||||
|
||||
_menuGamePlay.Enabled = !isPlayMode && canPlay;
|
||||
_menuGamePlayGame.Enabled = !isPlayMode && canPlay;
|
||||
_menuGamePlayCurrentScenes.Enabled = !isPlayMode && canPlay;
|
||||
_menuGameStop.Enabled = isPlayMode && canPlay;
|
||||
_menuGamePause.Enabled = isPlayMode && canPlay;
|
||||
|
||||
c.PerformLayout();
|
||||
@@ -968,6 +1032,72 @@ namespace FlaxEditor.Modules
|
||||
projectInfo.Save();
|
||||
}
|
||||
|
||||
private void SetPlayAction(InterfaceOptions.PlayAction newPlayAction)
|
||||
{
|
||||
var options = Editor.Options.Options;
|
||||
options.Interface.PlayButtonAction = newPlayAction;
|
||||
Editor.Options.Apply(options);
|
||||
}
|
||||
|
||||
private void OnPlayPressed()
|
||||
{
|
||||
switch (Editor.Options.Options.Interface.PlayButtonAction)
|
||||
{
|
||||
case InterfaceOptions.PlayAction.PlayGame:
|
||||
if (Editor.IsPlayMode)
|
||||
Editor.Simulation.RequestStopPlay();
|
||||
else
|
||||
PlayGame();
|
||||
return;
|
||||
case InterfaceOptions.PlayAction.PlayScenes:
|
||||
PlayScenes();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void PlayGame()
|
||||
{
|
||||
var firstScene = GameSettings.Load().FirstScene;
|
||||
if (firstScene == Guid.Empty)
|
||||
{
|
||||
if (Level.IsAnySceneLoaded)
|
||||
Editor.Simulation.RequestStartPlay();
|
||||
return;
|
||||
}
|
||||
|
||||
_scenesToReload = Level.Scenes;
|
||||
Level.UnloadAllScenes();
|
||||
Level.LoadScene(firstScene);
|
||||
|
||||
Editor.PlayModeEnd += OnPlayGameSceneEnding;
|
||||
Editor.Simulation.RequestPlayOrStopPlay();
|
||||
}
|
||||
|
||||
private void OnPlayGameSceneEnding()
|
||||
{
|
||||
Editor.PlayModeEnd -= OnPlayGameSceneEnding;
|
||||
|
||||
Level.UnloadAllScenes();
|
||||
|
||||
foreach (var scene in _scenesToReload)
|
||||
Level.LoadScene(scene.ID);
|
||||
}
|
||||
|
||||
private void PlayScenes()
|
||||
{
|
||||
Editor.Simulation.RequestPlayOrStopPlay();
|
||||
}
|
||||
|
||||
private void CookAndRun()
|
||||
{
|
||||
Editor.Windows.GameCookerWin.BuildAndRun();
|
||||
}
|
||||
|
||||
private void RunCookedGame()
|
||||
{
|
||||
Editor.Windows.GameCookerWin.RunCooked();
|
||||
}
|
||||
|
||||
private void OnMainWindowClosing()
|
||||
{
|
||||
// Clear UI references (GUI cannot be used after window closing)
|
||||
|
||||
@@ -74,6 +74,22 @@ namespace FlaxEditor.Options
|
||||
DockBottom = DockState.DockBottom
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Options for the action taken by the play button.
|
||||
/// </summary>
|
||||
public enum PlayAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Launches the game from the First Scene defined in the project settings.
|
||||
/// </summary>
|
||||
PlayGame,
|
||||
|
||||
/// <summary>
|
||||
/// Launches the game using the scenes currently loaded in the editor.
|
||||
/// </summary>
|
||||
PlayScenes,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Editor User Interface scale. Applied to all UI elements, windows and text. Can be used to scale the interface up on a bigger display. Editor restart required.
|
||||
/// </summary>
|
||||
@@ -82,14 +98,12 @@ namespace FlaxEditor.Options
|
||||
public float InterfaceScale { get; set; } = 1.0f;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether use native window title bar. Editor restart required.
|
||||
/// </summary>
|
||||
[DefaultValue(false)]
|
||||
[EditorDisplay("Interface"), EditorOrder(70), Tooltip("Determines whether use native window title bar. Editor restart required.")]
|
||||
public bool UseNativeWindowSystem { get; set; } = false;
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
@@ -196,30 +210,44 @@ namespace FlaxEditor.Options
|
||||
[EditorDisplay("Play In-Editor", "Focus Game Window On Play"), EditorOrder(400), Tooltip("Determines whether auto-focus game window on play mode start.")]
|
||||
public bool FocusGameWinOnPlay { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating what action should be taken upon pressing the play button.
|
||||
/// </summary>
|
||||
[DefaultValue(PlayAction.PlayScenes)]
|
||||
[EditorDisplay("Play In-Editor", "Play Button Action"), EditorOrder(410)]
|
||||
public PlayAction PlayButtonAction { get; set; } = PlayAction.PlayScenes;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating the number of game clients to launch when building and/or running cooked game.
|
||||
/// </summary>
|
||||
[DefaultValue(1), Range(1, 4)]
|
||||
[EditorDisplay("Cook & Run"), EditorOrder(500)]
|
||||
public int NumberOfGameClientsToLaunch = 1;
|
||||
|
||||
private static FontAsset DefaultFont => FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.PrimaryFont);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the title font for editor UI.
|
||||
/// </summary>
|
||||
[EditorDisplay("Fonts"), EditorOrder(500), Tooltip("The title font for editor UI.")]
|
||||
[EditorDisplay("Fonts"), EditorOrder(600), Tooltip("The title font for editor UI.")]
|
||||
public FontReference TitleFont { get; set; } = new FontReference(DefaultFont, 18);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the large font for editor UI.
|
||||
/// </summary>
|
||||
[EditorDisplay("Fonts"), EditorOrder(510), Tooltip("The large font for editor UI.")]
|
||||
[EditorDisplay("Fonts"), EditorOrder(610), Tooltip("The large font for editor UI.")]
|
||||
public FontReference LargeFont { get; set; } = new FontReference(DefaultFont, 14);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the medium font for editor UI.
|
||||
/// </summary>
|
||||
[EditorDisplay("Fonts"), EditorOrder(520), Tooltip("The medium font for editor UI.")]
|
||||
[EditorDisplay("Fonts"), EditorOrder(620), Tooltip("The medium font for editor UI.")]
|
||||
public FontReference MediumFont { get; set; } = new FontReference(DefaultFont, 9);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the small font for editor UI.
|
||||
/// </summary>
|
||||
[EditorDisplay("Fonts"), EditorOrder(530), Tooltip("The small font for editor UI.")]
|
||||
[EditorDisplay("Fonts"), EditorOrder(630), Tooltip("The small font for editor UI.")]
|
||||
public FontReference SmallFont { get; set; } = new FontReference(DefaultFont, 9);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,5 +59,12 @@ namespace FlaxEditor.Options
|
||||
[DefaultValue(false)]
|
||||
[EditorDisplay("Defaults"), EditorOrder(150), Tooltip("Invert the panning direction for the viewport camera.")]
|
||||
public bool DefaultInvertPanning { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Scales editor viewport grid.
|
||||
/// </summary>
|
||||
[DefaultValue(50.0f), Limit(25.0f, 500.0f, 5.0f)]
|
||||
[EditorDisplay("Defaults"), EditorOrder(160), Tooltip("Scales editor viewport grid.")]
|
||||
public float ViewportGridScale { get; set; } = 50.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +292,6 @@ void FoliageTools::Paint(Foliage* foliage, Span<int32> foliageTypesIndices, cons
|
||||
{
|
||||
PROFILE_CPU_NAMED("Place Instances");
|
||||
|
||||
Matrix matrix;
|
||||
FoliageInstance instance;
|
||||
Quaternion tmp;
|
||||
Matrix world;
|
||||
|
||||
@@ -80,6 +80,7 @@ namespace FlaxEditor.Windows
|
||||
public LogGroup Group;
|
||||
public LogEntryDescription Desc;
|
||||
public SpriteHandle Icon;
|
||||
public int LogCount = 1;
|
||||
|
||||
public LogEntry(DebugLogWindow window, ref LogEntryDescription desc)
|
||||
: base(0, 0, 120, DefaultHeight)
|
||||
@@ -137,7 +138,14 @@ namespace FlaxEditor.Windows
|
||||
// Title
|
||||
var textRect = new Rectangle(38, 2, clientRect.Width - 40, clientRect.Height - 10);
|
||||
Render2D.PushClip(ref clientRect);
|
||||
Render2D.DrawText(style.FontMedium, Desc.Title, textRect, style.Foreground);
|
||||
if (LogCount == 1)
|
||||
{
|
||||
Render2D.DrawText(style.FontMedium, Desc.Title, textRect, style.Foreground);
|
||||
}
|
||||
else if (LogCount > 1)
|
||||
{
|
||||
Render2D.DrawText(style.FontMedium, $"{Desc.Title} ({LogCount})", textRect, style.Foreground);
|
||||
}
|
||||
Render2D.PopClip();
|
||||
}
|
||||
|
||||
@@ -289,6 +297,7 @@ namespace FlaxEditor.Windows
|
||||
private readonly List<LogEntry> _pendingEntries = new List<LogEntry>(32);
|
||||
|
||||
private readonly ToolStripButton _clearOnPlayButton;
|
||||
private readonly ToolStripButton _collapseLogsButton;
|
||||
private readonly ToolStripButton _pauseOnErrorButton;
|
||||
private readonly ToolStripButton[] _groupButtons = new ToolStripButton[3];
|
||||
|
||||
@@ -316,6 +325,7 @@ namespace FlaxEditor.Windows
|
||||
};
|
||||
toolstrip.AddButton("Clear", Clear).LinkTooltip("Clears all log entries");
|
||||
_clearOnPlayButton = (ToolStripButton)toolstrip.AddButton("Clear on Play").SetAutoCheck(true).SetChecked(true).LinkTooltip("Clears all log entries on enter playmode");
|
||||
_collapseLogsButton = (ToolStripButton)toolstrip.AddButton("Collapse").SetAutoCheck(true).SetChecked(true).LinkTooltip("Collapses similar logs.");
|
||||
_pauseOnErrorButton = (ToolStripButton)toolstrip.AddButton("Pause on Error").SetAutoCheck(true).LinkTooltip("Performs auto pause on error");
|
||||
toolstrip.AddSeparator();
|
||||
_groupButtons[0] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Error32, () => UpdateLogTypeVisibility(LogGroup.Error, _groupButtons[0].Checked)).SetAutoCheck(true).SetChecked(true).LinkTooltip("Shows/hides error messages");
|
||||
@@ -612,6 +622,30 @@ namespace FlaxEditor.Windows
|
||||
var top = _entriesPanel.Children.Count != 0 ? _entriesPanel.Children[_entriesPanel.Children.Count - 1].Bottom + spacing : margin.Top;
|
||||
for (int i = 0; i < _pendingEntries.Count; i++)
|
||||
{
|
||||
if (_collapseLogsButton.Checked)
|
||||
{
|
||||
bool logExists = false;
|
||||
foreach (var child in _entriesPanel.Children)
|
||||
{
|
||||
if (child is LogEntry entry)
|
||||
{
|
||||
var pendingEntry = _pendingEntries[i];
|
||||
if (string.Equals(entry.Desc.Title, pendingEntry.Desc.Title, StringComparison.Ordinal) &&
|
||||
string.Equals(entry.Desc.LocationFile, pendingEntry.Desc.LocationFile, StringComparison.Ordinal) &&
|
||||
entry.Desc.Level == pendingEntry.Desc.Level &&
|
||||
string.Equals(entry.Desc.Description, pendingEntry.Desc.Description, StringComparison.Ordinal) &&
|
||||
entry.Desc.LocationLine == pendingEntry.Desc.LocationLine)
|
||||
{
|
||||
entry.LogCount += 1;
|
||||
newEntry = entry;
|
||||
logExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (logExists)
|
||||
continue;
|
||||
}
|
||||
newEntry = _pendingEntries[i];
|
||||
newEntry.Visible = _groupButtons[(int)newEntry.Group].Checked;
|
||||
anyVisible |= newEntry.Visible;
|
||||
|
||||
@@ -238,6 +238,7 @@ namespace FlaxEditor.Windows
|
||||
{
|
||||
[EditorDisplay(null, "arm64")]
|
||||
ARM64,
|
||||
|
||||
[EditorDisplay(null, "x64")]
|
||||
x64,
|
||||
}
|
||||
@@ -614,6 +615,18 @@ namespace FlaxEditor.Windows
|
||||
_exitOnBuildEnd = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if can build for the given platform (both supported and available).
|
||||
/// </summary>
|
||||
/// <param name="platformType">The platform.</param>
|
||||
/// <returns>True if can build, otherwise false.</returns>
|
||||
public bool CanBuild(PlatformType platformType)
|
||||
{
|
||||
if (_buildTabProxy.PerPlatformOptions.TryGetValue(platformType, out var platform))
|
||||
return platform.IsAvailable && platform.IsSupported;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds all the targets from the given preset.
|
||||
/// </summary>
|
||||
@@ -659,16 +672,24 @@ namespace FlaxEditor.Windows
|
||||
{
|
||||
Editor.Log("Building and running");
|
||||
GameCooker.GetCurrentPlatform(out var platform, out var buildPlatform, out var buildConfiguration);
|
||||
_buildingQueue.Enqueue(new QueueItem
|
||||
var numberOfClients = Editor.Options.Options.Interface.NumberOfGameClientsToLaunch;
|
||||
for (int i = 0; i < numberOfClients; i++)
|
||||
{
|
||||
Target = new BuildTarget
|
||||
var buildOptions = BuildOptions.AutoRun;
|
||||
if (i > 0)
|
||||
buildOptions |= BuildOptions.NoCook;
|
||||
|
||||
_buildingQueue.Enqueue(new QueueItem
|
||||
{
|
||||
Output = _buildTabProxy.PerPlatformOptions[platform].Output,
|
||||
Platform = buildPlatform,
|
||||
Mode = buildConfiguration,
|
||||
},
|
||||
Options = BuildOptions.AutoRun,
|
||||
});
|
||||
Target = new BuildTarget
|
||||
{
|
||||
Output = _buildTabProxy.PerPlatformOptions[platform].Output,
|
||||
Platform = buildPlatform,
|
||||
Mode = buildConfiguration,
|
||||
},
|
||||
Options = buildOptions,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -678,16 +699,20 @@ namespace FlaxEditor.Windows
|
||||
{
|
||||
Editor.Log("Running cooked build");
|
||||
GameCooker.GetCurrentPlatform(out var platform, out var buildPlatform, out var buildConfiguration);
|
||||
_buildingQueue.Enqueue(new QueueItem
|
||||
var numberOfClients = Editor.Options.Options.Interface.NumberOfGameClientsToLaunch;
|
||||
for (int i = 0; i < numberOfClients; i++)
|
||||
{
|
||||
Target = new BuildTarget
|
||||
_buildingQueue.Enqueue(new QueueItem
|
||||
{
|
||||
Output = _buildTabProxy.PerPlatformOptions[platform].Output,
|
||||
Platform = buildPlatform,
|
||||
Mode = buildConfiguration,
|
||||
},
|
||||
Options = BuildOptions.AutoRun | BuildOptions.NoCook,
|
||||
});
|
||||
Target = new BuildTarget
|
||||
{
|
||||
Output = _buildTabProxy.PerPlatformOptions[platform].Output,
|
||||
Platform = buildPlatform,
|
||||
Mode = buildConfiguration,
|
||||
},
|
||||
Options = BuildOptions.AutoRun | BuildOptions.NoCook,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildTarget()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
|
||||
@@ -94,9 +93,11 @@ namespace FlaxEngine
|
||||
public AnimatedModel Instance;
|
||||
}
|
||||
|
||||
[HideInEditor]
|
||||
[CustomMarshaller(typeof(Context), MarshalMode.Default, typeof(ContextMarshaller))]
|
||||
internal static class ContextMarshaller
|
||||
{
|
||||
[HideInEditor]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ContextNative
|
||||
{
|
||||
@@ -116,7 +117,7 @@ namespace FlaxEngine
|
||||
|
||||
internal static Context ToManaged(ContextNative managed)
|
||||
{
|
||||
return new Context()
|
||||
return new Context
|
||||
{
|
||||
Graph = managed.Graph,
|
||||
GraphExecutor = managed.GraphExecutor,
|
||||
@@ -129,9 +130,10 @@ namespace FlaxEngine
|
||||
Instance = AnimatedModelMarshaller.ConvertToManaged(managed.Instance),
|
||||
};
|
||||
}
|
||||
|
||||
internal static ContextNative ToNative(Context managed)
|
||||
{
|
||||
return new ContextNative()
|
||||
return new ContextNative
|
||||
{
|
||||
Graph = managed.Graph,
|
||||
GraphExecutor = managed.GraphExecutor,
|
||||
@@ -144,6 +146,7 @@ namespace FlaxEngine
|
||||
Instance = AnimatedModelMarshaller.ConvertToUnmanaged(managed.Instance),
|
||||
};
|
||||
}
|
||||
|
||||
internal static void Free(ContextNative unmanaged)
|
||||
{
|
||||
}
|
||||
@@ -243,6 +246,12 @@ namespace FlaxEngine
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
if (destination == null)
|
||||
throw new ArgumentNullException(nameof(destination));
|
||||
if (source->NodesCount <= 0 || source->NodesCount > 4096)
|
||||
throw new ArgumentOutOfRangeException(nameof(source));
|
||||
if (destination->NodesCount <= 0 || destination->NodesCount > 4096)
|
||||
throw new ArgumentOutOfRangeException(nameof(destination));
|
||||
if (source->NodesCount != destination->NodesCount)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
destination->NodesCount = source->NodesCount;
|
||||
destination->Unused = source->Unused;
|
||||
Utils.MemoryCopy(new IntPtr(destination->Nodes), new IntPtr(source->Nodes), (ulong)(source->NodesCount * sizeof(Transform)));
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/BinaryModule.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MCore.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MDomain.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MMethod.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||
@@ -189,12 +188,8 @@ bool AnimGraph::InitCustomNode(Node* node)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create node values managed array
|
||||
// Initialization can happen on Content Thread so ensure to have runtime attached
|
||||
MCore::Thread::Attach();
|
||||
MArray* values = MCore::Array::New( MCore::TypeCache::Object, node->Values.Count());
|
||||
MObject** valuesPtr = MCore::Array::GetAddress<MObject*>(values);
|
||||
for (int32 i = 0; i < node->Values.Count(); i++)
|
||||
valuesPtr[i] = MUtils::BoxVariant(node->Values[i]);
|
||||
|
||||
// Allocate managed node object (create GC handle to prevent destruction)
|
||||
MObject* obj = type->CreateInstance();
|
||||
@@ -202,7 +197,7 @@ bool AnimGraph::InitCustomNode(Node* node)
|
||||
|
||||
// Initialize node
|
||||
InternalInitData initData;
|
||||
initData.Values = values;
|
||||
initData.Values = MUtils::ToArray(node->Values, MCore::TypeCache::Object);
|
||||
initData.BaseModel = BaseModel.GetManagedInstance();
|
||||
void* params[1];
|
||||
params[0] = &initData;
|
||||
@@ -211,7 +206,6 @@ bool AnimGraph::InitCustomNode(Node* node)
|
||||
if (exception)
|
||||
{
|
||||
MCore::GCHandle::Free(handleGC);
|
||||
|
||||
MException ex(exception);
|
||||
ex.Log(LogType::Warning, TEXT("AnimGraph"));
|
||||
return false;
|
||||
|
||||
@@ -235,8 +235,9 @@ void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode*
|
||||
const float nestedAnimLength = nestedAnim.Anim->GetLength();
|
||||
const float nestedAnimDuration = nestedAnim.Anim->GetDuration();
|
||||
const float nestedAnimSpeed = nestedAnim.Speed * speed;
|
||||
nestedAnimPos = nestedAnimPos / nestedAnimDuration * nestedAnimSpeed;
|
||||
nestedAnimPrevPos = nestedAnimPrevPos / nestedAnimDuration * nestedAnimSpeed;
|
||||
const float frameRateMatchScale = (float)nestedAnim.Anim->Data.FramesPerSecond / (float)anim->Data.FramesPerSecond;
|
||||
nestedAnimPos = nestedAnimPos / nestedAnimDuration * nestedAnimSpeed * frameRateMatchScale;
|
||||
nestedAnimPrevPos = nestedAnimPrevPos / nestedAnimDuration * nestedAnimSpeed * frameRateMatchScale;
|
||||
GetAnimSamplePos(nestedAnim.Loop, nestedAnimLength, nestedAnim.StartTime, nestedAnimPrevPos, nestedAnimPos, nestedAnimPos, nestedAnimPrevPos);
|
||||
|
||||
ProcessAnimation(nodes, node, true, nestedAnimLength, nestedAnimPos, nestedAnimPrevPos, nestedAnim.Anim, 1.0f, weight, mode);
|
||||
|
||||
@@ -27,7 +27,6 @@ public:
|
||||
/// <summary>
|
||||
/// Returns true if material is an material instance.
|
||||
/// </summary>
|
||||
/// <returns>True if it's a material instance, otherwise false.</returns>
|
||||
virtual bool IsMaterialInstance() const = 0;
|
||||
|
||||
public:
|
||||
|
||||
@@ -205,9 +205,6 @@ FlaxStorage::~FlaxStorage()
|
||||
{
|
||||
// Validate if has been disposed
|
||||
ASSERT(IsDisposed());
|
||||
|
||||
// Validate other fields
|
||||
// Note: disposed storage has no open files
|
||||
CHECK(_chunksLock == 0);
|
||||
CHECK(_refCount == 0);
|
||||
ASSERT(_chunks.IsEmpty());
|
||||
@@ -216,7 +213,6 @@ FlaxStorage::~FlaxStorage()
|
||||
// Ensure to close any outstanding file handles to prevent file locking in case it failed to load
|
||||
_file.DeleteAll();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
FlaxStorage::LockData FlaxStorage::LockSafe()
|
||||
@@ -550,11 +546,9 @@ bool FlaxStorage::Load()
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
LOG(Warning, "Unsupported storage format version: {1}. {0}", ToString(), _version);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark as loaded (version number describes 'isLoaded' state)
|
||||
_version = version;
|
||||
@@ -573,7 +567,7 @@ bool FlaxStorage::Reload()
|
||||
|
||||
// Perform clean reloading
|
||||
Dispose();
|
||||
bool failed = Load();
|
||||
const bool failed = Load();
|
||||
|
||||
OnReloaded(this, failed);
|
||||
|
||||
@@ -1434,10 +1428,8 @@ void FlaxFile::GetEntries(Array<Entry>& output) const
|
||||
|
||||
void FlaxFile::Dispose()
|
||||
{
|
||||
// Base
|
||||
FlaxStorage::Dispose();
|
||||
|
||||
// Clean
|
||||
_asset.ID = Guid::Empty;
|
||||
}
|
||||
|
||||
@@ -1482,7 +1474,7 @@ bool FlaxPackage::HasAsset(const Guid& id) const
|
||||
bool FlaxPackage::HasAsset(const AssetInfo& info) const
|
||||
{
|
||||
ASSERT(_path == info.Path);
|
||||
Entry* e = _entries.TryGet(info.ID);
|
||||
const Entry* e = _entries.TryGet(info.ID);
|
||||
return e && e->TypeName == info.TypeName;
|
||||
}
|
||||
|
||||
@@ -1511,10 +1503,8 @@ void FlaxPackage::GetEntries(Array<Entry>& output) const
|
||||
|
||||
void FlaxPackage::Dispose()
|
||||
{
|
||||
// Base
|
||||
FlaxStorage::Dispose();
|
||||
|
||||
// Clean
|
||||
_entries.Clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -38,9 +38,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
BoundingBox()
|
||||
{
|
||||
}
|
||||
BoundingBox() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BoundingBox"/> struct.
|
||||
|
||||
@@ -34,9 +34,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
BoundingFrustum()
|
||||
{
|
||||
}
|
||||
BoundingFrustum() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BoundingFrustum"/> struct.
|
||||
|
||||
@@ -34,9 +34,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
BoundingSphere()
|
||||
{
|
||||
}
|
||||
BoundingSphere() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BoundingSphere"/> struct.
|
||||
|
||||
@@ -50,9 +50,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
Color()
|
||||
{
|
||||
}
|
||||
Color() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Color"/> struct.
|
||||
|
||||
@@ -53,9 +53,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
Color32()
|
||||
{
|
||||
}
|
||||
Color32() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new Color32 with given r, g, b, a components.
|
||||
|
||||
@@ -121,9 +121,7 @@ public:
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
Half2()
|
||||
{
|
||||
}
|
||||
Half2() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Init
|
||||
@@ -185,9 +183,7 @@ public:
|
||||
Half Z;
|
||||
|
||||
public:
|
||||
Half3()
|
||||
{
|
||||
}
|
||||
Half3() = default;
|
||||
|
||||
Half3(Half x, Half y, Half z)
|
||||
: X(x)
|
||||
@@ -242,9 +238,7 @@ public:
|
||||
Half W;
|
||||
|
||||
public:
|
||||
Half4()
|
||||
{
|
||||
}
|
||||
Half4() = default;
|
||||
|
||||
Half4(Half x, Half y, Half z, Half w)
|
||||
: X(x)
|
||||
|
||||
@@ -876,38 +876,54 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Given a heading which may be outside the +/- PI range, 'unwind' it back into that range.
|
||||
/// </summary>
|
||||
/// <remarks>Optimized version of <see cref="UnwindRadiansAccurate"/> that is it faster and has fixed cost but with large angle values (100 for example) starts to lose accuracy floating point problem.</remarks>
|
||||
/// <param name="angle">Angle in radians to unwind.</param>
|
||||
/// <returns>Valid angle in radians.</returns>
|
||||
public static double UnwindRadians(double angle)
|
||||
{
|
||||
// TODO: make it faster?
|
||||
var a = angle - Math.Floor(angle / TwoPi) * TwoPi; // Loop function between 0 and TwoPi
|
||||
return a > Pi ? a - TwoPi : a; // Change range so it become Pi and -Pi
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The same as <see cref="UnwindRadians"/> but is more computation intensive with large <see href="angle"/> and has better accuracy with large <see href="angle"/>.
|
||||
/// <br>cost of this function is <see href="angle"/> % <see cref="Pi"/></br>
|
||||
/// </summary>
|
||||
/// <param name="angle">Angle in radians to unwind.</param>
|
||||
/// <returns>Valid angle in radians.</returns>
|
||||
public static double UnwindRadiansAccurate(double angle)
|
||||
{
|
||||
while (angle > Pi)
|
||||
{
|
||||
angle -= TwoPi;
|
||||
}
|
||||
while (angle < -Pi)
|
||||
{
|
||||
angle += TwoPi;
|
||||
}
|
||||
return angle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Utility to ensure angle is between +/- 180 degrees by unwinding
|
||||
/// Utility to ensure angle is between +/- 180 degrees by unwinding.
|
||||
/// </summary>
|
||||
/// <remarks>Optimized version of <see cref="UnwindDegreesAccurate"/> that is it faster and has fixed cost but with large angle values (100 for example) starts to lose accuracy floating point problem.</remarks>
|
||||
/// <param name="angle">Angle in degrees to unwind.</param>
|
||||
/// <returns>Valid angle in degrees.</returns>
|
||||
public static double UnwindDegrees(double angle)
|
||||
{
|
||||
// TODO: make it faster?
|
||||
while (angle > 180.0f)
|
||||
{
|
||||
angle -= 360.0f;
|
||||
}
|
||||
while (angle < -180.0f)
|
||||
{
|
||||
angle += 360.0f;
|
||||
}
|
||||
var a = angle - Math.Floor(angle / 360.0) * 360.0; // Loop function between 0 and 360
|
||||
return a > 180 ? a - 360.0 : a; // Change range so it become 180 and -180
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The same as <see cref="UnwindDegrees"/> but is more computation intensive with large <see href="angle"/> and has better accuracy with large <see href="angle"/>.
|
||||
/// <br>cost of this function is <see href="angle"/> % 180.0f</br>
|
||||
/// </summary>
|
||||
/// <param name="angle">Angle in radians to unwind.</param>
|
||||
/// <returns>Valid angle in radians.</returns>
|
||||
public static double UnwindDegreesAccurate(double angle)
|
||||
{
|
||||
while (angle > 180.0)
|
||||
angle -= 360.0;
|
||||
while (angle < -180.0)
|
||||
angle += 360.0;
|
||||
return angle;
|
||||
}
|
||||
|
||||
@@ -927,8 +943,9 @@ namespace FlaxEngine
|
||||
/// Interpolates between two values using a linear function by a given amount.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See http://www.encyclopediaofmath.org/index.php/Linear_interpolation and
|
||||
/// http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
|
||||
/// See:
|
||||
/// <br><seealso href="http://www.encyclopediaofmath.org/index.php/Linear_interpolation"/></br>
|
||||
/// <br><seealso href="http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/"/></br>
|
||||
/// </remarks>
|
||||
/// <param name="from">Value to interpolate from.</param>
|
||||
/// <param name="to">Value to interpolate to.</param>
|
||||
@@ -944,7 +961,8 @@ namespace FlaxEngine
|
||||
/// Performs smooth (cubic Hermite) interpolation between 0 and 1.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://en.wikipedia.org/wiki/Smoothstep
|
||||
/// See:
|
||||
/// <br><seealso href="https://en.wikipedia.org/wiki/Smoothstep"/></br>
|
||||
/// </remarks>
|
||||
/// <param name="amount">Value between 0 and 1 indicating interpolation amount.</param>
|
||||
public static double SmoothStep(double amount)
|
||||
@@ -956,7 +974,8 @@ namespace FlaxEngine
|
||||
/// Performs a smooth(er) interpolation between 0 and 1 with 1st and 2nd order derivatives of zero at endpoints.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://en.wikipedia.org/wiki/Smoothstep
|
||||
/// See:
|
||||
/// <br><seealso href="https://en.wikipedia.org/wiki/Smoothstep"/></br>
|
||||
/// </remarks>
|
||||
/// <param name="amount">Value between 0 and 1 indicating interpolation amount.</param>
|
||||
public static double SmootherStep(double amount)
|
||||
@@ -1013,7 +1032,7 @@ namespace FlaxEngine
|
||||
|
||||
/// <summary>
|
||||
/// Gauss function.
|
||||
/// http://en.wikipedia.org/wiki/Gaussian_function#Two-dimensional_Gaussian_function
|
||||
/// <br><seealso href="http://en.wikipedia.org/wiki/Gaussian_function#Two-dimensional_Gaussian_function"/></br>
|
||||
/// </summary>
|
||||
/// <param name="amplitude">Curve amplitude.</param>
|
||||
/// <param name="x">Position X.</param>
|
||||
|
||||
@@ -1176,38 +1176,54 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Given a heading which may be outside the +/- PI range, 'unwind' it back into that range.
|
||||
/// </summary>
|
||||
/// <remarks>Optimized version of <see cref="UnwindRadiansAccurate"/> that is it faster and has fixed cost but with large angle values (100 for example) starts to lose accuracy floating point problem.</remarks>
|
||||
/// <param name="angle">Angle in radians to unwind.</param>
|
||||
/// <returns>Valid angle in radians.</returns>
|
||||
public static float UnwindRadians(float angle)
|
||||
{
|
||||
// TODO: make it faster?
|
||||
var a = angle - (float)Math.Floor(angle / TwoPi) * TwoPi; // Loop function between 0 and TwoPi
|
||||
return a > Pi ? a - TwoPi : a; // Change range so it become Pi and -Pi
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The same as <see cref="UnwindRadians"/> but is more computation intensive with large <see href="angle"/> and has better accuracy with large <see href="angle"/>.
|
||||
/// <br>cost of this function is <see href="angle"/> % <see cref="Pi"/></br>
|
||||
/// </summary>
|
||||
/// <param name="angle">Angle in radians to unwind.</param>
|
||||
/// <returns>Valid angle in radians.</returns>
|
||||
public static float UnwindRadiansAccurate(float angle)
|
||||
{
|
||||
while (angle > Pi)
|
||||
{
|
||||
angle -= TwoPi;
|
||||
}
|
||||
while (angle < -Pi)
|
||||
{
|
||||
angle += TwoPi;
|
||||
}
|
||||
return angle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Utility to ensure angle is between +/- 180 degrees by unwinding
|
||||
/// Utility to ensure angle is between +/- 180 degrees by unwinding.
|
||||
/// </summary>
|
||||
/// <remarks>Optimized version of <see cref="UnwindDegreesAccurate"/> that is it faster and has fixed cost but with large angle values (100 for example) starts to lose accuracy floating point problem.</remarks>
|
||||
/// <param name="angle">Angle in degrees to unwind.</param>
|
||||
/// <returns>Valid angle in degrees.</returns>
|
||||
public static float UnwindDegrees(float angle)
|
||||
{
|
||||
// TODO: make it faster?
|
||||
var a = angle - (float)Math.Floor(angle / 360.0f) * 360.0f; // Loop function between 0 and 360
|
||||
return a > 180 ? a - 360.0f : a; // Change range so it become 180 and -180
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The same as <see cref="UnwindDegrees"/> but is more computation intensive with large <see href="angle"/> and has better accuracy with large <see href="angle"/>.
|
||||
/// <br>cost of this function is <see href="angle"/> % 180.0f</br>
|
||||
/// </summary>
|
||||
/// <param name="angle">Angle in radians to unwind.</param>
|
||||
/// <returns>Valid angle in radians.</returns>
|
||||
public static float UnwindDegreesAccurate(float angle)
|
||||
{
|
||||
while (angle > 180.0f)
|
||||
{
|
||||
angle -= 360.0f;
|
||||
}
|
||||
while (angle < -180.0f)
|
||||
{
|
||||
angle += 360.0f;
|
||||
}
|
||||
return angle;
|
||||
}
|
||||
|
||||
@@ -1299,8 +1315,12 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Interpolates between two values using a linear function by a given amount.
|
||||
/// </summary>
|
||||
/// <remarks>See http://www.encyclopediaofmath.org/index.php/Linear_interpolation and http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/</remarks>
|
||||
/// <param name="from">Value to interpolate from.</param>
|
||||
/// <remarks>
|
||||
/// See:
|
||||
/// <br><seealso href="http://www.encyclopediaofmath.org/index.php/Linear_interpolation"/></br>
|
||||
/// <br><seealso href="http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/"/></br>
|
||||
/// </remarks>
|
||||
/// /// <param name="from">Value to interpolate from.</param>
|
||||
/// <param name="to">Value to interpolate to.</param>
|
||||
/// <param name="amount">Interpolation amount.</param>
|
||||
/// <returns>The result of linear interpolation of values based on the amount.</returns>
|
||||
@@ -1312,8 +1332,12 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Interpolates between two values using a linear function by a given amount.
|
||||
/// </summary>
|
||||
/// <remarks>See http://www.encyclopediaofmath.org/index.php/Linear_interpolation and http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/</remarks>
|
||||
/// <param name="from">Value to interpolate from.</param>
|
||||
/// <remarks>
|
||||
/// See:
|
||||
/// <br><seealso href="http://www.encyclopediaofmath.org/index.php/Linear_interpolation"/></br>
|
||||
/// <br><seealso href="http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/"/></br>
|
||||
/// </remarks>
|
||||
/// /// <param name="from">Value to interpolate from.</param>
|
||||
/// <param name="to">Value to interpolate to.</param>
|
||||
/// <param name="amount">Interpolation amount.</param>
|
||||
/// <returns>The result of linear interpolation of values based on the amount.</returns>
|
||||
@@ -1325,8 +1349,12 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Interpolates between two values using a linear function by a given amount.
|
||||
/// </summary>
|
||||
/// <remarks>See http://www.encyclopediaofmath.org/index.php/Linear_interpolation and http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/</remarks>
|
||||
/// <param name="from">Value to interpolate from.</param>
|
||||
/// <remarks>
|
||||
/// See:
|
||||
/// <br><seealso href="http://www.encyclopediaofmath.org/index.php/Linear_interpolation"/></br>
|
||||
/// <br><seealso href="http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/"/></br>
|
||||
/// </remarks>
|
||||
/// /// <param name="from">Value to interpolate from.</param>
|
||||
/// <param name="to">Value to interpolate to.</param>
|
||||
/// <param name="amount">Interpolation amount.</param>
|
||||
/// <returns>The result of linear interpolation of values based on the amount.</returns>
|
||||
@@ -1338,7 +1366,10 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Performs smooth (cubic Hermite) interpolation between 0 and 1.
|
||||
/// </summary>
|
||||
/// <remarks>See https://en.wikipedia.org/wiki/Smoothstep</remarks>
|
||||
/// <remarks>
|
||||
/// See:
|
||||
/// <br><seealso href="https://en.wikipedia.org/wiki/Smoothstep"/></br>
|
||||
/// </remarks>
|
||||
/// <param name="amount">Value between 0 and 1 indicating interpolation amount.</param>
|
||||
public static float SmoothStep(float amount)
|
||||
{
|
||||
@@ -1348,7 +1379,10 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Performs smooth (cubic Hermite) interpolation between 0 and 1.
|
||||
/// </summary>
|
||||
/// <remarks>See https://en.wikipedia.org/wiki/Smoothstep</remarks>
|
||||
/// <remarks>
|
||||
/// See:
|
||||
/// <br><seealso href="https://en.wikipedia.org/wiki/Smoothstep"/></br>
|
||||
/// </remarks>
|
||||
/// <param name="amount">Value between 0 and 1 indicating interpolation amount.</param>
|
||||
public static double SmoothStep(double amount)
|
||||
{
|
||||
@@ -1358,7 +1392,10 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Performs a smooth(er) interpolation between 0 and 1 with 1st and 2nd order derivatives of zero at endpoints.
|
||||
/// </summary>
|
||||
/// <remarks>See https://en.wikipedia.org/wiki/Smoothstep</remarks>
|
||||
/// <remarks>
|
||||
/// See:
|
||||
/// <br><seealso href="https://en.wikipedia.org/wiki/Smoothstep"/></br>
|
||||
/// </remarks>
|
||||
/// <param name="amount">Value between 0 and 1 indicating interpolation amount.</param>
|
||||
public static float SmootherStep(float amount)
|
||||
{
|
||||
@@ -1368,7 +1405,10 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Performs a smooth(er) interpolation between 0 and 1 with 1st and 2nd order derivatives of zero at endpoints.
|
||||
/// </summary>
|
||||
/// <remarks>See https://en.wikipedia.org/wiki/Smoothstep</remarks>
|
||||
/// <remarks>
|
||||
/// See:
|
||||
/// <br><seealso href="https://en.wikipedia.org/wiki/Smoothstep"/></br>
|
||||
/// </remarks>
|
||||
/// <param name="amount">Value between 0 and 1 indicating interpolation amount.</param>
|
||||
public static double SmootherStep(double amount)
|
||||
{
|
||||
@@ -1446,7 +1486,7 @@ namespace FlaxEngine
|
||||
|
||||
/// <summary>
|
||||
/// Gauss function.
|
||||
/// http://en.wikipedia.org/wiki/Gaussian_function#Two-dimensional_Gaussian_function
|
||||
/// <br><seealso href="http://en.wikipedia.org/wiki/Gaussian_function#Two-dimensional_Gaussian_function"/></br>
|
||||
/// </summary>
|
||||
/// <param name="amplitude">Curve amplitude.</param>
|
||||
/// <param name="x">Position X.</param>
|
||||
@@ -1463,7 +1503,7 @@ namespace FlaxEngine
|
||||
|
||||
/// <summary>
|
||||
/// Gauss function.
|
||||
/// http://en.wikipedia.org/wiki/Gaussian_function#Two-dimensional_Gaussian_function
|
||||
/// <br><seealso href="http://en.wikipedia.org/wiki/Gaussian_function#Two-dimensional_Gaussian_function"/></br>
|
||||
/// </summary>
|
||||
/// <param name="amplitude">Curve amplitude.</param>
|
||||
/// <param name="x">Position X.</param>
|
||||
|
||||
@@ -83,9 +83,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
Matrix()
|
||||
{
|
||||
}
|
||||
Matrix() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Matrix"/> struct.
|
||||
|
||||
@@ -63,9 +63,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
Matrix3x3()
|
||||
{
|
||||
}
|
||||
Matrix3x3() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Matrix3x3"/> struct.
|
||||
|
||||
@@ -30,9 +30,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
Plane()
|
||||
{
|
||||
}
|
||||
Plane() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Init
|
||||
|
||||
@@ -67,9 +67,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
Quaternion()
|
||||
{
|
||||
}
|
||||
Quaternion() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Init
|
||||
|
||||
@@ -35,9 +35,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
Ray()
|
||||
{
|
||||
}
|
||||
Ray() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Ray"/> struct.
|
||||
|
||||
@@ -31,9 +31,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
Rectangle()
|
||||
{
|
||||
}
|
||||
Rectangle() = default;
|
||||
|
||||
// Init
|
||||
// @param x Rectangle location X coordinate
|
||||
|
||||
@@ -40,9 +40,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
Transform()
|
||||
{
|
||||
}
|
||||
Transform() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Transform"/> struct.
|
||||
|
||||
@@ -30,9 +30,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
Triangle()
|
||||
{
|
||||
}
|
||||
Triangle() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Triangle"/> struct.
|
||||
|
||||
@@ -60,9 +60,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
Vector2Base()
|
||||
{
|
||||
}
|
||||
Vector2Base() = default;
|
||||
|
||||
FORCE_INLINE Vector2Base(T xy)
|
||||
: X(xy)
|
||||
|
||||
@@ -89,9 +89,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
Vector3Base()
|
||||
{
|
||||
}
|
||||
Vector3Base() = default;
|
||||
|
||||
FORCE_INLINE Vector3Base(T xyz)
|
||||
: X(xyz)
|
||||
|
||||
@@ -76,9 +76,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
Vector4Base()
|
||||
{
|
||||
}
|
||||
Vector4Base() = default;
|
||||
|
||||
FORCE_INLINE Vector4Base(T xyzw)
|
||||
: X(xyzw)
|
||||
|
||||
@@ -52,9 +52,7 @@ public:
|
||||
/// <summary>
|
||||
/// Empty constructor.
|
||||
/// </summary>
|
||||
Viewport()
|
||||
{
|
||||
}
|
||||
Viewport() = default;
|
||||
|
||||
// Init
|
||||
// @param x The x coordinate of the upper-left corner of the viewport in pixels
|
||||
|
||||
@@ -115,6 +115,12 @@ inline Span<T> ToSpan(const T* ptr, int32 length)
|
||||
return Span<T>(ptr, length);
|
||||
}
|
||||
|
||||
template<typename T, typename U = T, typename AllocationType = HeapAllocation>
|
||||
inline Span<U> ToSpan(const Array<T, AllocationType>& data)
|
||||
{
|
||||
return Span<U>((U*)data.Get(), data.Count());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool SpanContains(const Span<T> span, const T& value)
|
||||
{
|
||||
|
||||
@@ -2796,6 +2796,122 @@ String Variant::ToString() const
|
||||
}
|
||||
}
|
||||
|
||||
void Variant::Inline()
|
||||
{
|
||||
VariantType::Types type = VariantType::Null;
|
||||
byte data[sizeof(Matrix)];
|
||||
if (Type.Type == VariantType::Structure && AsBlob.Data && AsBlob.Length <= sizeof(Matrix))
|
||||
{
|
||||
for (int32 i = 2; i < VariantType::MAX; i++)
|
||||
{
|
||||
if (StringUtils::Compare(Type.TypeName, InBuiltTypesTypeNames[i]) == 0)
|
||||
{
|
||||
type = (VariantType::Types)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (type == VariantType::Null)
|
||||
{
|
||||
// Aliases
|
||||
if (StringUtils::Compare(Type.TypeName, "FlaxEngine.Vector2") == 0)
|
||||
type = VariantType::Types::Vector2;
|
||||
else if (StringUtils::Compare(Type.TypeName, "FlaxEngine.Vector3") == 0)
|
||||
type = VariantType::Types::Vector3;
|
||||
else if (StringUtils::Compare(Type.TypeName, "FlaxEngine.Vector4") == 0)
|
||||
type = VariantType::Types::Vector4;
|
||||
}
|
||||
if (type != VariantType::Null)
|
||||
Platform::MemoryCopy(data, AsBlob.Data, AsBlob.Length);
|
||||
}
|
||||
if (type != VariantType::Null)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case VariantType::Bool:
|
||||
*this = *(bool*)data;
|
||||
break;
|
||||
case VariantType::Int:
|
||||
*this = *(int32*)data;
|
||||
break;
|
||||
case VariantType::Uint:
|
||||
*this = *(uint32*)data;
|
||||
break;
|
||||
case VariantType::Int64:
|
||||
*this = *(int64*)data;
|
||||
break;
|
||||
case VariantType::Uint64:
|
||||
*this = *(uint64*)data;
|
||||
break;
|
||||
case VariantType::Float:
|
||||
*this = *(float*)data;
|
||||
break;
|
||||
case VariantType::Double:
|
||||
*this = *(double*)data;
|
||||
break;
|
||||
case VariantType::Float2:
|
||||
*this = *(Float2*)data;
|
||||
break;
|
||||
case VariantType::Float3:
|
||||
*this = *(Float3*)data;
|
||||
break;
|
||||
case VariantType::Float4:
|
||||
*this = *(Float4*)data;
|
||||
break;
|
||||
case VariantType::Color:
|
||||
*this = *(Color*)data;
|
||||
break;
|
||||
case VariantType::Guid:
|
||||
*this = *(Guid*)data;
|
||||
break;
|
||||
case VariantType::BoundingBox:
|
||||
*this = Variant(*(BoundingBox*)data);
|
||||
break;
|
||||
case VariantType::BoundingSphere:
|
||||
*this = *(BoundingSphere*)data;
|
||||
break;
|
||||
case VariantType::Quaternion:
|
||||
*this = *(Quaternion*)data;
|
||||
break;
|
||||
case VariantType::Transform:
|
||||
*this = Variant(*(Transform*)data);
|
||||
break;
|
||||
case VariantType::Rectangle:
|
||||
*this = *(Rectangle*)data;
|
||||
break;
|
||||
case VariantType::Ray:
|
||||
*this = Variant(*(Ray*)data);
|
||||
break;
|
||||
case VariantType::Matrix:
|
||||
*this = Variant(*(Matrix*)data);
|
||||
break;
|
||||
case VariantType::Int2:
|
||||
*this = *(Int2*)data;
|
||||
break;
|
||||
case VariantType::Int3:
|
||||
*this = *(Int3*)data;
|
||||
break;
|
||||
case VariantType::Int4:
|
||||
*this = *(Int4*)data;
|
||||
break;
|
||||
case VariantType::Int16:
|
||||
*this = *(int16*)data;
|
||||
break;
|
||||
case VariantType::Uint16:
|
||||
*this = *(uint16*)data;
|
||||
break;
|
||||
case VariantType::Double2:
|
||||
*this = *(Double2*)data;
|
||||
break;
|
||||
case VariantType::Double3:
|
||||
*this = *(Double3*)data;
|
||||
break;
|
||||
case VariantType::Double4:
|
||||
*this = *(Double4*)data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Variant::CanCast(const Variant& v, const VariantType& to)
|
||||
{
|
||||
if (v.Type == to)
|
||||
@@ -3682,6 +3798,7 @@ void Variant::AllocStructure()
|
||||
const ScriptingType& type = typeHandle.GetType();
|
||||
AsBlob.Length = type.Size;
|
||||
AsBlob.Data = Allocator::Allocate(AsBlob.Length);
|
||||
Platform::MemoryClear(AsBlob.Data, AsBlob.Length);
|
||||
type.Struct.Ctor(AsBlob.Data);
|
||||
}
|
||||
else if (typeName == "System.Int16" || typeName == "System.UInt16")
|
||||
|
||||
@@ -359,6 +359,9 @@ public:
|
||||
void SetAsset(Asset* asset);
|
||||
String ToString() const;
|
||||
|
||||
// Inlines potential value type into in-built format (eg. Vector3 stored as Structure, or String stored as ManagedObject).
|
||||
void Inline();
|
||||
|
||||
FORCE_INLINE Variant Cast(const VariantType& to) const
|
||||
{
|
||||
return Cast(*this, to);
|
||||
|
||||
@@ -72,15 +72,6 @@ public:
|
||||
return _major;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the high 16 bits of the revision number.
|
||||
/// </summary>
|
||||
/// <returns>A 16-bit signed integer.</returns>
|
||||
FORCE_INLINE int16 MajorRevision() const
|
||||
{
|
||||
return static_cast<int16>(_revision >> 16);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the minor component of the version number for the current Version object.
|
||||
/// </summary>
|
||||
@@ -90,15 +81,6 @@ public:
|
||||
return _minor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the low 16 bits of the revision number.
|
||||
/// </summary>
|
||||
/// <returns>A 16-bit signed integer.</returns>
|
||||
FORCE_INLINE int16 MinorRevision() const
|
||||
{
|
||||
return static_cast<int16>(_revision & 65535);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the revision component of the version number for the current Version object.
|
||||
/// </summary>
|
||||
@@ -126,61 +108,26 @@ public:
|
||||
return _major == obj._major && _minor == obj._minor && _build == obj._build && _revision == obj._revision;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether two specified Version objects are equal.
|
||||
/// </summary>
|
||||
/// <param name="other">The other Version object.</param>
|
||||
/// <returns>True if <paramref name="v1" /> equals <paramref name="v2" />; otherwise, false.</returns>
|
||||
FORCE_INLINE bool operator==(const Version& other) const
|
||||
{
|
||||
return Equals(other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the first specified Version object is greater than the second specified Version object.
|
||||
/// </summary>
|
||||
/// <param name="other">The first Version object.</param>
|
||||
/// <returns>True if <paramref name="v1" /> is greater than <paramref name="v2" />; otherwise, false.</returns>
|
||||
FORCE_INLINE bool operator >(const Version& other) const
|
||||
FORCE_INLINE bool operator>(const Version& other) const
|
||||
{
|
||||
return other < *this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the first specified Version object is greater than or equal to the second specified Version object.
|
||||
/// /summary>
|
||||
/// <param name="other">The other Version object.</param>
|
||||
/// <returns>True if <paramref name="v1" /> is greater than or equal to <paramref name="v2" />; otherwise, false.</returns>
|
||||
FORCE_INLINE bool operator >=(const Version& other) const
|
||||
FORCE_INLINE bool operator>=(const Version& other) const
|
||||
{
|
||||
return other <= *this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether two specified Version objects are not equal.
|
||||
/// </summary>
|
||||
/// <param name="other">The other Version object.</param>
|
||||
/// <returns>True if <paramref name="v1" /> does not equal <paramref name="v2" />; otherwise, false.</returns>
|
||||
FORCE_INLINE bool operator!=(const Version& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the first specified Version object is less than the second specified Version object.
|
||||
/// </summary>
|
||||
/// <param name="other">The first other object.</param>
|
||||
/// <returns>True if <paramref name="v1" /> is less than <paramref name="v2" />; otherwise, false.</returns>
|
||||
FORCE_INLINE bool operator<(const Version& other) const
|
||||
{
|
||||
return CompareTo(other) < 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the first specified Version object is less than or equal to the second Version object.
|
||||
/// </summary>
|
||||
/// <param name="other">The other Version object.</param>
|
||||
/// <returns>True if <paramref name="v1" /> is less than or equal to <paramref name="v2" />; otherwise, false.</returns>
|
||||
FORCE_INLINE bool operator<=(const Version& other) const
|
||||
{
|
||||
return CompareTo(other) <= 0;
|
||||
|
||||
@@ -274,12 +274,12 @@ namespace FlaxEngine.Interop
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
internal static class ManagedString
|
||||
public static class ManagedString
|
||||
{
|
||||
internal static ManagedHandle EmptyStringHandle = ManagedHandle.Alloc(string.Empty);
|
||||
|
||||
[System.Diagnostics.DebuggerStepThrough]
|
||||
internal static unsafe IntPtr ToNative(string str)
|
||||
public static unsafe IntPtr ToNative(string str)
|
||||
{
|
||||
if (str == null)
|
||||
return IntPtr.Zero;
|
||||
@@ -290,7 +290,7 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
|
||||
[System.Diagnostics.DebuggerStepThrough]
|
||||
internal static unsafe IntPtr ToNativeWeak(string str)
|
||||
public static unsafe IntPtr ToNativeWeak(string str)
|
||||
{
|
||||
if (str == null)
|
||||
return IntPtr.Zero;
|
||||
@@ -301,7 +301,7 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
|
||||
[System.Diagnostics.DebuggerStepThrough]
|
||||
internal static string ToManaged(IntPtr ptr)
|
||||
public static string ToManaged(IntPtr ptr)
|
||||
{
|
||||
if (ptr == IntPtr.Zero)
|
||||
return null;
|
||||
@@ -309,7 +309,7 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
|
||||
[System.Diagnostics.DebuggerStepThrough]
|
||||
internal static void Free(IntPtr ptr)
|
||||
public static void Free(IntPtr ptr)
|
||||
{
|
||||
if (ptr == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
@@ -244,7 +244,25 @@ namespace FlaxEngine.Interop
|
||||
@namespace = NativeAllocStringAnsi(type.Namespace ?? ""),
|
||||
typeAttributes = (uint)type.Attributes,
|
||||
};
|
||||
*assemblyHandle = GetAssemblyHandle(type.Assembly);
|
||||
|
||||
Assembly assembly = null;
|
||||
if (type.IsGenericType && !type.Assembly.IsCollectible)
|
||||
{
|
||||
// The owning assembly of a generic type with type arguments referencing
|
||||
// collectible assemblies must be one of the collectible assemblies.
|
||||
foreach (var genericType in type.GetGenericArguments())
|
||||
{
|
||||
if (genericType.Assembly.IsCollectible)
|
||||
{
|
||||
assembly = genericType.Assembly;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (assembly == null)
|
||||
assembly = type.Assembly;
|
||||
|
||||
*assemblyHandle = GetAssemblyHandle(assembly);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
|
||||
@@ -444,7 +444,7 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
else
|
||||
{
|
||||
toManagedFieldMethod = typeof(MarshalHelper<>.ReferenceTypeField<>).MakeGenericType(type, fieldType).GetMethod(nameof(MarshalHelper<T>.ReferenceTypeField<ReferenceTypePlaceholder>.ToManagedField), bindingFlags);
|
||||
toManagedFieldMethod = typeof(MarshalHelper<>.ReferenceTypeField<>).MakeGenericType(type, arrayElementType).GetMethod(nameof(MarshalHelper<T>.ReferenceTypeField<ReferenceTypePlaceholder>.ToManagedFieldArray), bindingFlags);
|
||||
toNativeFieldMethod = typeof(MarshalHelper<>.ReferenceTypeField<>).MakeGenericType(type, fieldType).GetMethod(nameof(MarshalHelper<T>.ReferenceTypeField<ReferenceTypePlaceholder>.ToNativeField), bindingFlags);
|
||||
}
|
||||
}
|
||||
@@ -663,6 +663,17 @@ namespace FlaxEngine.Interop
|
||||
MarshalHelperReferenceType<TField>.ToManaged(ref fieldValueRef, Unsafe.Read<IntPtr>(fieldPtr.ToPointer()), false);
|
||||
}
|
||||
|
||||
internal static void ToManagedFieldArray(FieldInfo field, ref T fieldOwner, IntPtr fieldPtr, out int fieldOffset)
|
||||
{
|
||||
fieldOffset = Unsafe.SizeOf<IntPtr>();
|
||||
IntPtr fieldStartPtr = fieldPtr;
|
||||
fieldPtr = EnsureAlignment(fieldPtr, IntPtr.Size);
|
||||
fieldOffset += (fieldPtr - fieldStartPtr).ToInt32();
|
||||
|
||||
ref TField[] fieldValueRef = ref GetFieldReference<TField[]>(field, ref fieldOwner);
|
||||
MarshalHelperReferenceType<TField>.ToManagedArray(ref fieldValueRef, Unsafe.Read<IntPtr>(fieldPtr.ToPointer()), false);
|
||||
}
|
||||
|
||||
internal static void ToNativeField(FieldInfo field, ref T fieldOwner, IntPtr fieldPtr, out int fieldOffset)
|
||||
{
|
||||
fieldOffset = Unsafe.SizeOf<IntPtr>();
|
||||
@@ -691,14 +702,15 @@ namespace FlaxEngine.Interop
|
||||
internal static void ToManaged(ref T managedValue, IntPtr nativePtr, bool byRef)
|
||||
{
|
||||
Type type = typeof(T);
|
||||
if (type.IsByRef || byRef)
|
||||
byRef |= type.IsByRef;
|
||||
if (byRef)
|
||||
{
|
||||
if (type.IsByRef)
|
||||
type = type.GetElementType();
|
||||
Assert.IsTrue(type.IsValueType);
|
||||
}
|
||||
|
||||
if (type == typeof(IntPtr))
|
||||
if (type == typeof(IntPtr) && byRef)
|
||||
managedValue = (T)(object)nativePtr;
|
||||
else if (type == typeof(ManagedHandle))
|
||||
managedValue = (T)(object)ManagedHandle.FromIntPtr(nativePtr);
|
||||
@@ -778,10 +790,12 @@ namespace FlaxEngine.Interop
|
||||
|
||||
if (type == typeof(string))
|
||||
managedValue = Unsafe.As<T>(ManagedString.ToManaged(nativePtr));
|
||||
else if (nativePtr == IntPtr.Zero)
|
||||
managedValue = null;
|
||||
else if (type.IsClass)
|
||||
managedValue = nativePtr != IntPtr.Zero ? Unsafe.As<T>(ManagedHandle.FromIntPtr(nativePtr).Target) : null;
|
||||
managedValue = Unsafe.As<T>(ManagedHandle.FromIntPtr(nativePtr).Target);
|
||||
else if (type.IsInterface) // Dictionary
|
||||
managedValue = nativePtr != IntPtr.Zero ? Unsafe.As<T>(ManagedHandle.FromIntPtr(nativePtr).Target) : null;
|
||||
managedValue = Unsafe.As<T>(ManagedHandle.FromIntPtr(nativePtr).Target);
|
||||
else
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the default material.
|
||||
/// </summary>
|
||||
MaterialBase* GetDefaultMaterial() const;
|
||||
API_PROPERTY() MaterialBase* GetDefaultMaterial() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default material (Deformable domain).
|
||||
|
||||
@@ -788,7 +788,9 @@ void Actor::BreakPrefabLink()
|
||||
|
||||
void Actor::Initialize()
|
||||
{
|
||||
ASSERT(!IsDuringPlay());
|
||||
#if ENABLE_ASSERTION
|
||||
CHECK(!IsDuringPlay());
|
||||
#endif
|
||||
|
||||
// Cache
|
||||
if (_parent)
|
||||
@@ -802,7 +804,9 @@ void Actor::Initialize()
|
||||
|
||||
void Actor::BeginPlay(SceneBeginData* data)
|
||||
{
|
||||
ASSERT(!IsDuringPlay());
|
||||
#if ENABLE_ASSERTION
|
||||
CHECK(!IsDuringPlay());
|
||||
#endif
|
||||
|
||||
// Set flag
|
||||
Flags |= ObjectFlags::IsDuringPlay;
|
||||
@@ -832,7 +836,9 @@ void Actor::BeginPlay(SceneBeginData* data)
|
||||
|
||||
void Actor::EndPlay()
|
||||
{
|
||||
ASSERT(IsDuringPlay());
|
||||
#if ENABLE_ASSERTION
|
||||
CHECK(IsDuringPlay());
|
||||
#endif
|
||||
|
||||
// Fire event for scripting
|
||||
if (IsActiveInHierarchy() && GetScene())
|
||||
@@ -1059,7 +1065,9 @@ void Actor::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
|
||||
|
||||
void Actor::OnEnable()
|
||||
{
|
||||
ASSERT(!_isEnabled);
|
||||
#if ENABLE_ASSERTION
|
||||
CHECK(!_isEnabled);
|
||||
#endif
|
||||
_isEnabled = true;
|
||||
|
||||
for (int32 i = 0; i < Scripts.Count(); i++)
|
||||
@@ -1079,7 +1087,9 @@ void Actor::OnEnable()
|
||||
|
||||
void Actor::OnDisable()
|
||||
{
|
||||
ASSERT(_isEnabled);
|
||||
#if ENABLE_ASSERTION
|
||||
CHECK(_isEnabled);
|
||||
#endif
|
||||
_isEnabled = false;
|
||||
|
||||
for (int32 i = Scripts.Count() - 1; i >= 0; i--)
|
||||
|
||||
@@ -898,6 +898,14 @@ void AnimatedModel::Deserialize(DeserializeStream& stream, ISerializeModifier* m
|
||||
DrawModes |= DrawPass::GlobalSurfaceAtlas;
|
||||
}
|
||||
|
||||
const Span<MaterialSlot> AnimatedModel::GetMaterialSlots() const
|
||||
{
|
||||
const auto model = SkinnedModel.Get();
|
||||
if (model && !model->WaitForLoaded())
|
||||
return ToSpan(model->MaterialSlots);
|
||||
return Span<MaterialSlot>();
|
||||
}
|
||||
|
||||
MaterialBase* AnimatedModel::GetMaterial(int32 entryIndex)
|
||||
{
|
||||
if (SkinnedModel)
|
||||
|
||||
@@ -373,6 +373,7 @@ public:
|
||||
bool IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) override;
|
||||
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
||||
const Span<MaterialSlot> GetMaterialSlots() const override;
|
||||
MaterialBase* GetMaterial(int32 entryIndex) override;
|
||||
bool IntersectsEntry(int32 entryIndex, const Ray& ray, Real& distance, Vector3& normal) override;
|
||||
bool IntersectsEntry(const Ray& ray, Real& distance, Vector3& normal, int32& entryIndex) override;
|
||||
|
||||
@@ -35,6 +35,11 @@ public:
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetEntries(const Array<ModelInstanceEntry>& value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the material slots array set on the asset (eg. model or skinned model asset).
|
||||
/// </summary>
|
||||
API_PROPERTY(Sealed) virtual const Span<class MaterialSlot> GetMaterialSlots() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the material used to draw the meshes which are assigned to that slot (set in Entries or model's default).
|
||||
/// </summary>
|
||||
|
||||
@@ -341,6 +341,14 @@ void SplineModel::OnParentChanged()
|
||||
OnSplineUpdated();
|
||||
}
|
||||
|
||||
const Span<MaterialSlot> SplineModel::GetMaterialSlots() const
|
||||
{
|
||||
const auto model = Model.Get();
|
||||
if (model && !model->WaitForLoaded())
|
||||
return ToSpan(model->MaterialSlots);
|
||||
return Span<MaterialSlot>();
|
||||
}
|
||||
|
||||
MaterialBase* SplineModel::GetMaterial(int32 entryIndex)
|
||||
{
|
||||
if (Model)
|
||||
|
||||
@@ -115,6 +115,7 @@ public:
|
||||
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
||||
void OnParentChanged() override;
|
||||
const Span<MaterialSlot> GetMaterialSlots() const override;
|
||||
MaterialBase* GetMaterial(int32 entryIndex) override;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -535,6 +535,14 @@ void StaticModel::Deserialize(DeserializeStream& stream, ISerializeModifier* mod
|
||||
}
|
||||
}
|
||||
|
||||
const Span<MaterialSlot> StaticModel::GetMaterialSlots() const
|
||||
{
|
||||
const auto model = Model.Get();
|
||||
if (model && !model->WaitForLoaded())
|
||||
return ToSpan(model->MaterialSlots);
|
||||
return Span<MaterialSlot>();
|
||||
}
|
||||
|
||||
MaterialBase* StaticModel::GetMaterial(int32 entryIndex)
|
||||
{
|
||||
if (Model)
|
||||
|
||||
@@ -166,6 +166,7 @@ public:
|
||||
bool IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) override;
|
||||
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
||||
const Span<MaterialSlot> GetMaterialSlots() const override;
|
||||
MaterialBase* GetMaterial(int32 entryIndex) override;
|
||||
bool IntersectsEntry(int32 entryIndex, const Ray& ray, Real& distance, Vector3& normal) override;
|
||||
bool IntersectsEntry(const Ray& ray, Real& distance, Vector3& normal, int32& entryIndex) override;
|
||||
|
||||
@@ -189,7 +189,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupTools(Box* box, Node* node, Va
|
||||
const Matrix viewProjection = context.ViewTask ? context.ViewTask->View.PrevViewProjection : Matrix::Identity;
|
||||
const Float3 position = (Float3)TryGetValue(node->GetBox(0), Value::Zero);
|
||||
Float4 projPos;
|
||||
Float3::Transform(position, viewProjection);
|
||||
Float3::Transform(position, viewProjection, projPos);
|
||||
projPos /= projPos.W;
|
||||
value = Float2(projPos.X * 0.5f + 0.5f, projPos.Y * 0.5f + 0.5f);
|
||||
break;
|
||||
|
||||
@@ -56,36 +56,94 @@ DialogResult MessageBox::Show(Window* parent, const StringView& text, const Stri
|
||||
{
|
||||
if (CommandLine::Options.Headless)
|
||||
return DialogResult::None;
|
||||
CFStringRef textRef = AppleUtils::ToString(text);
|
||||
CFStringRef captionRef = AppleUtils::ToString(caption);
|
||||
CFOptionFlags flags = 0;
|
||||
NSAlert* alert = [[NSAlert alloc] init];
|
||||
ASSERT(alert);
|
||||
switch (buttons)
|
||||
{
|
||||
case MessageBoxButtons::AbortRetryIgnore:
|
||||
[alert addButtonWithTitle:@"Abort"];
|
||||
[alert addButtonWithTitle:@"Retry"];
|
||||
[alert addButtonWithTitle:@"Ignore"];
|
||||
break;
|
||||
case MessageBoxButtons::OK:
|
||||
[alert addButtonWithTitle:@"OK"];
|
||||
break;
|
||||
case MessageBoxButtons::OKCancel:
|
||||
[alert addButtonWithTitle:@"OK"];
|
||||
[alert addButtonWithTitle:@"Cancel"];
|
||||
break;
|
||||
case MessageBoxButtons::RetryCancel:
|
||||
[alert addButtonWithTitle:@"Retry"];
|
||||
[alert addButtonWithTitle:@"Cancel"];
|
||||
break;
|
||||
case MessageBoxButtons::YesNo:
|
||||
[alert addButtonWithTitle:@"Yes"];
|
||||
[alert addButtonWithTitle:@"No"];
|
||||
break;
|
||||
case MessageBoxButtons::YesNoCancel:
|
||||
flags |= kCFUserNotificationCancelResponse;
|
||||
[alert addButtonWithTitle:@"Yes"];
|
||||
[alert addButtonWithTitle:@"No"];
|
||||
[alert addButtonWithTitle:@"Cancel"];
|
||||
break;
|
||||
}
|
||||
switch (icon)
|
||||
{
|
||||
case MessageBoxIcon::Information:
|
||||
flags |= kCFUserNotificationNoteAlertLevel;
|
||||
[alert setAlertStyle:NSAlertStyleCritical];
|
||||
break;
|
||||
case MessageBoxIcon::Error:
|
||||
case MessageBoxIcon::Stop:
|
||||
flags |= kCFUserNotificationStopAlertLevel;
|
||||
[alert setAlertStyle:NSAlertStyleInformational];
|
||||
break;
|
||||
case MessageBoxIcon::Warning:
|
||||
flags |= kCFUserNotificationCautionAlertLevel;
|
||||
[alert setAlertStyle:NSAlertStyleWarning];
|
||||
break;
|
||||
}
|
||||
SInt32 result = CFUserNotificationDisplayNotice(0, flags, nullptr, nullptr, nullptr, captionRef, textRef, nullptr);
|
||||
CFRelease(captionRef);
|
||||
CFRelease(textRef);
|
||||
return DialogResult::OK;
|
||||
[alert setMessageText:(NSString*)AppleUtils::ToString(caption)];
|
||||
[alert setInformativeText:(NSString*)AppleUtils::ToString(text)];
|
||||
NSInteger button = [alert runModal];
|
||||
DialogResult result = DialogResult::OK;
|
||||
switch (buttons)
|
||||
{
|
||||
case MessageBoxButtons::AbortRetryIgnore:
|
||||
if (button == NSAlertFirstButtonReturn)
|
||||
result = DialogResult::Abort;
|
||||
else if (button == NSAlertSecondButtonReturn)
|
||||
result = DialogResult::Retry;
|
||||
else
|
||||
result = DialogResult::Ignore;
|
||||
break;
|
||||
case MessageBoxButtons::OK:
|
||||
result = DialogResult::OK;
|
||||
break;
|
||||
case MessageBoxButtons::OKCancel:
|
||||
if (button == NSAlertFirstButtonReturn)
|
||||
result = DialogResult::OK;
|
||||
else
|
||||
result = DialogResult::Cancel;
|
||||
break;
|
||||
case MessageBoxButtons::RetryCancel:
|
||||
if (button == NSAlertFirstButtonReturn)
|
||||
result = DialogResult::Retry;
|
||||
else
|
||||
result = DialogResult::Cancel;
|
||||
break;
|
||||
case MessageBoxButtons::YesNo:
|
||||
if (button == NSAlertFirstButtonReturn)
|
||||
result = DialogResult::Yes;
|
||||
else
|
||||
result = DialogResult::No;
|
||||
break;
|
||||
case MessageBoxButtons::YesNoCancel:
|
||||
if (button == NSAlertFirstButtonReturn)
|
||||
result = DialogResult::Yes;
|
||||
else if (button == NSAlertSecondButtonReturn)
|
||||
result = DialogResult::No;
|
||||
else
|
||||
result = DialogResult::Cancel;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Float2 AppleUtils::PosToCoca(const Float2& pos)
|
||||
@@ -301,15 +359,16 @@ Float2 MacPlatform::GetMousePosition()
|
||||
CGEventRef event = CGEventCreate(nullptr);
|
||||
CGPoint cursor = CGEventGetLocation(event);
|
||||
CFRelease(event);
|
||||
return Float2((float)cursor.x, (float)cursor.y);
|
||||
return Float2((float)cursor.x, (float)cursor.y) * MacPlatform::ScreenScale;
|
||||
}
|
||||
|
||||
void MacPlatform::SetMousePosition(const Float2& pos)
|
||||
{
|
||||
CGPoint cursor;
|
||||
cursor.x = (CGFloat)pos.X;
|
||||
cursor.y = (CGFloat)pos.Y;
|
||||
cursor.x = (CGFloat)(pos.X / MacPlatform::ScreenScale);
|
||||
cursor.y = (CGFloat)(pos.Y / MacPlatform::ScreenScale);
|
||||
CGWarpMouseCursorPosition(cursor);
|
||||
CGAssociateMouseAndMouseCursorPosition(true);
|
||||
}
|
||||
|
||||
Float2 MacPlatform::GetDesktopSize()
|
||||
|
||||
@@ -72,11 +72,11 @@ KeyboardKeys GetKey(NSEvent* event)
|
||||
case 0x30: return KeyboardKeys::Tab;
|
||||
case 0x31: return KeyboardKeys::Spacebar;
|
||||
case 0x32: return KeyboardKeys::BackQuote;
|
||||
case 0x33: return KeyboardKeys::Delete;
|
||||
case 0x33: return KeyboardKeys::Backspace;
|
||||
//case 0x34:
|
||||
case 0x35: return KeyboardKeys::Escape;
|
||||
//case 0x36:
|
||||
//case 0x37: Command
|
||||
case 0x36: return KeyboardKeys::Control; // Command (right)
|
||||
case 0x37: return KeyboardKeys::Control; // Command (left)
|
||||
case 0x38: return KeyboardKeys::Shift;
|
||||
case 0x39: return KeyboardKeys::Capital;
|
||||
case 0x3A: return KeyboardKeys::Alt;
|
||||
@@ -378,7 +378,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
||||
{
|
||||
KeyboardKeys key = GetKey(event);
|
||||
if (key != KeyboardKeys::None)
|
||||
Input::Keyboard->OnKeyDown(key);
|
||||
Input::Keyboard->OnKeyDown(key, Window);
|
||||
|
||||
// Send a text input event
|
||||
switch (key)
|
||||
@@ -400,7 +400,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
||||
if (length >= 16)
|
||||
length = 15;
|
||||
[text getCharacters:buffer range:NSMakeRange(0, length)];
|
||||
Input::Keyboard->OnCharInput((Char)buffer[0]);
|
||||
Input::Keyboard->OnCharInput((Char)buffer[0], Window);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,7 +408,32 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
||||
{
|
||||
KeyboardKeys key = GetKey(event);
|
||||
if (key != KeyboardKeys::None)
|
||||
Input::Keyboard->OnKeyUp(key);
|
||||
Input::Keyboard->OnKeyUp(key, Window);
|
||||
}
|
||||
|
||||
- (void)flagsChanged:(NSEvent*)event
|
||||
{
|
||||
int32 modMask;
|
||||
int32 keyCode = [event keyCode];
|
||||
if (keyCode == 0x36 || keyCode == 0x37)
|
||||
modMask = NSEventModifierFlagCommand;
|
||||
else if (keyCode == 0x38 || keyCode == 0x3c)
|
||||
modMask = NSEventModifierFlagShift;
|
||||
else if (keyCode == 0x3a || keyCode == 0x3d)
|
||||
modMask = NSEventModifierFlagOption;
|
||||
else if (keyCode == 0x3b || keyCode == 0x3e)
|
||||
modMask = NSEventModifierFlagControl;
|
||||
else
|
||||
return;
|
||||
KeyboardKeys key = GetKey(event);
|
||||
if (key != KeyboardKeys::None)
|
||||
{
|
||||
int32 modifierFlags = [event modifierFlags];
|
||||
if ((modifierFlags & modMask) == modMask)
|
||||
Input::Keyboard->OnKeyDown(key, Window);
|
||||
else
|
||||
Input::Keyboard->OnKeyUp(key, Window);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollWheel:(NSEvent*)event
|
||||
@@ -643,7 +668,6 @@ MacWindow::MacWindow(const CreateWindowSettings& settings)
|
||||
// TODO: impl StartPosition for MacWindow
|
||||
// TODO: impl Fullscreen for MacWindow
|
||||
// TODO: impl ShowInTaskbar for MacWindow
|
||||
// TODO: impl AllowInput for MacWindow
|
||||
// TODO: impl IsTopmost for MacWindow
|
||||
}
|
||||
|
||||
|
||||
@@ -17,10 +17,13 @@ namespace FlaxEngine
|
||||
[Unmanaged]
|
||||
public static void DrawSceneDepth(GPUContext context, SceneRenderTask task, GPUTexture output, List<Actor> customActors)
|
||||
{
|
||||
if (customActors.Count == 0)
|
||||
return;
|
||||
var temp = CollectionsMarshal.AsSpan(customActors).ToArray(); // FIXME
|
||||
var tempCount = temp.Length;
|
||||
Actor[] temp = null;
|
||||
int tempCount = 0;
|
||||
if (customActors != null && customActors.Count != 0)
|
||||
{
|
||||
temp = CollectionsMarshal.AsSpan(customActors).ToArray(); // FIXME
|
||||
tempCount = temp.Length;
|
||||
}
|
||||
Internal_DrawSceneDepth(FlaxEngine.Object.GetUnmanagedPtr(context), FlaxEngine.Object.GetUnmanagedPtr(task), FlaxEngine.Object.GetUnmanagedPtr(output), temp, ref tempCount);
|
||||
}
|
||||
|
||||
@@ -32,7 +35,14 @@ namespace FlaxEngine
|
||||
[Unmanaged]
|
||||
public static void DrawActors(ref RenderContext renderContext, List<Actor> customActors)
|
||||
{
|
||||
DrawActors(ref renderContext, Utils.ExtractArrayFromList(customActors));
|
||||
Actor[] temp = null;
|
||||
int tempCount = 0;
|
||||
if (customActors != null && customActors.Count != 0)
|
||||
{
|
||||
temp = CollectionsMarshal.AsSpan(customActors).ToArray(); // FIXME
|
||||
tempCount = temp.Length;
|
||||
}
|
||||
Internal_DrawActors(ref renderContext, temp, ref tempCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,4 +53,23 @@ namespace FlaxEngine
|
||||
UseSmallPicker = useSmallPicker;
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_NETCORE
|
||||
/// <summary>
|
||||
/// Specifies a options for an asset reference picker in the editor. Allows to customize view or provide custom value assign policy.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.Attribute" />
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class AssetReferenceAttribute<T> : AssetReferenceAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AssetReferenceAttribute"/> class for generic type T.
|
||||
/// </summary>
|
||||
/// <param name="useSmallPicker">True if use asset picker with a smaller height (single line), otherwise will use with full icon.</param>
|
||||
public AssetReferenceAttribute(bool useSmallPicker = false)
|
||||
: base(typeof(T), useSmallPicker)
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ void ManagedSerialization::Deserialize(const StringAnsiView& data, MObject* obje
|
||||
// Prepare arguments
|
||||
void* args[3];
|
||||
args[0] = object;
|
||||
args[1] = (void*)str;
|
||||
args[1] = (void*)&str;
|
||||
args[2] = (void*)&len;
|
||||
|
||||
// Call serialization tool
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "MUtils.h"
|
||||
#include "MClass.h"
|
||||
#include "MCore.h"
|
||||
#include "MDomain.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Types/DataContainer.h"
|
||||
#include "Engine/Core/Types/Version.h"
|
||||
@@ -449,7 +448,7 @@ Variant MUtils::UnboxVariant(MObject* value)
|
||||
{
|
||||
auto& a = array[i];
|
||||
a.SetType(elementType);
|
||||
Platform::MemoryCopy(&a.AsData,(byte*)ptr + elementSize * i, elementSize);
|
||||
Platform::MemoryCopy(&a.AsData, (byte*)ptr + elementSize * i, elementSize);
|
||||
}
|
||||
break;
|
||||
case VariantType::Transform:
|
||||
@@ -1004,11 +1003,11 @@ MClass* MUtils::GetClass(const Variant& value)
|
||||
case VariantType::Enum:
|
||||
return Scripting::FindClass(StringAnsiView(value.Type.TypeName));
|
||||
case VariantType::ManagedObject:
|
||||
{
|
||||
MObject* obj = (MObject*)value;
|
||||
if (obj)
|
||||
return MCore::Object::GetClass(obj);
|
||||
}
|
||||
{
|
||||
MObject* obj = (MObject*)value;
|
||||
if (obj)
|
||||
return MCore::Object::GetClass(obj);
|
||||
}
|
||||
default: ;
|
||||
}
|
||||
return GetClass(value.Type);
|
||||
@@ -1224,10 +1223,10 @@ MObject* MUtils::ToManaged(const Version& value)
|
||||
auto versionToManaged = scriptingClass->GetMethod("VersionToManaged", 4);
|
||||
CHECK_RETURN(versionToManaged, nullptr);
|
||||
|
||||
int major = value.Major();
|
||||
int minor = value.Minor();
|
||||
int build = value.Build();
|
||||
int revision = value.Revision();
|
||||
int32 major = value.Major();
|
||||
int32 minor = value.Minor();
|
||||
int32 build = value.Build();
|
||||
int32 revision = value.Revision();
|
||||
|
||||
void* params[4];
|
||||
params[0] = &major;
|
||||
@@ -1244,26 +1243,29 @@ MObject* MUtils::ToManaged(const Version& value)
|
||||
|
||||
Version MUtils::ToNative(MObject* value)
|
||||
{
|
||||
Version result;
|
||||
if (value)
|
||||
#if USE_NETCORE
|
||||
{
|
||||
auto ver = Version();
|
||||
|
||||
auto scriptingClass = Scripting::GetStaticClass();
|
||||
CHECK_RETURN(scriptingClass, ver);
|
||||
auto versionToNative = scriptingClass->GetMethod("VersionToNative", 2);
|
||||
CHECK_RETURN(versionToNative, ver);
|
||||
CHECK_RETURN(scriptingClass, result);
|
||||
auto versionToNative = scriptingClass->GetMethod("VersionToNative", 5);
|
||||
CHECK_RETURN(versionToNative, result);
|
||||
|
||||
void* params[2];
|
||||
void* params[5];
|
||||
params[0] = value;
|
||||
params[1] = &ver;
|
||||
params[1] = (byte*)&result;
|
||||
params[2] = (byte*)&result + sizeof(int32);
|
||||
params[3] = (byte*)&result + sizeof(int32) * 2;
|
||||
params[4] = (byte*)&result + sizeof(int32) * 3;
|
||||
versionToNative->Invoke(nullptr, params, nullptr);
|
||||
return ver;
|
||||
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
return *(Version*)MCore::Object::Unbox(value);
|
||||
#endif
|
||||
return Version();
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,10 +17,29 @@ public class Scripting : EngineModule
|
||||
{
|
||||
if (EngineConfiguration.WithDotNet(options))
|
||||
{
|
||||
void AddFrameworkDefines(string template, int major, int latestMinor)
|
||||
{
|
||||
for (int minor = latestMinor; minor >= 0; minor--)
|
||||
{
|
||||
options.ScriptingAPI.Defines.Add(string.Format(template, major, minor));
|
||||
options.ScriptingAPI.Defines.Add(string.Format($"{template}_OR_GREATER", major, minor));
|
||||
}
|
||||
}
|
||||
|
||||
// .NET
|
||||
options.PrivateDependencies.Add("nethost");
|
||||
options.ScriptingAPI.Defines.Add("USE_NETCORE");
|
||||
|
||||
// .NET SDK
|
||||
AddFrameworkDefines("NET{0}_{1}", 7, 0); // "NET7_0" and "NET7_0_OR_GREATER"
|
||||
AddFrameworkDefines("NET{0}_{1}", 6, 0);
|
||||
AddFrameworkDefines("NET{0}_{1}", 5, 0);
|
||||
options.ScriptingAPI.Defines.Add("NET");
|
||||
AddFrameworkDefines("NETCOREAPP{0}_{1}", 3, 1); // "NETCOREAPP3_1" and "NETCOREAPP3_1_OR_GREATER"
|
||||
AddFrameworkDefines("NETCOREAPP{0}_{1}", 2, 2);
|
||||
AddFrameworkDefines("NETCOREAPP{0}_{1}", 1, 1);
|
||||
options.ScriptingAPI.Defines.Add("NETCOREAPP");
|
||||
|
||||
if (options.Target is EngineTarget engineTarget && engineTarget.UseSeparateMainExecutable(options))
|
||||
{
|
||||
// Build target doesn't support linking again main executable (eg. Linux) thus additional shared library is used for the engine (eg. libFlaxEditor.so)
|
||||
|
||||
@@ -476,12 +476,28 @@ bool Scripting::Load()
|
||||
|
||||
// Load FlaxEngine
|
||||
const String flaxEnginePath = Globals::BinariesFolder / TEXT("FlaxEngine.CSharp.dll");
|
||||
if (((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->Load(flaxEnginePath))
|
||||
auto* flaxEngineModule = (NativeBinaryModule*)GetBinaryModuleFlaxEngine();
|
||||
if (flaxEngineModule->Assembly->Load(flaxEnginePath))
|
||||
{
|
||||
LOG(Error, "Failed to load FlaxEngine C# assembly.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Insert type aliases for vector types that don't exist in C++ but are just typedef (properly redirect them to actual types)
|
||||
// TODO: add support for automatic typedef aliases setup for scripting module to properly lookup type from the alias typename
|
||||
#if USE_LARGE_WORLDS
|
||||
flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector2"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Double2"];
|
||||
flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector3"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Double3"];
|
||||
flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector4"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Double4"];
|
||||
#else
|
||||
flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector2"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Float2"];
|
||||
flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector3"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Float3"];
|
||||
flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector4"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Float4"];
|
||||
#endif
|
||||
flaxEngineModule->ClassToTypeIndex[flaxEngineModule->Assembly->GetClass("FlaxEngine.Vector2")] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector2"];
|
||||
flaxEngineModule->ClassToTypeIndex[flaxEngineModule->Assembly->GetClass("FlaxEngine.Vector3")] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector3"];
|
||||
flaxEngineModule->ClassToTypeIndex[flaxEngineModule->Assembly->GetClass("FlaxEngine.Vector4")] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector4"];
|
||||
|
||||
#if USE_EDITOR
|
||||
// Skip loading game modules in Editor on startup - Editor loads them later during splash screen (eg. after first compilation)
|
||||
static bool SkipFirstLoad = true;
|
||||
|
||||
@@ -229,22 +229,24 @@ namespace FlaxEngine
|
||||
return ManagedHandle.Alloc(new CultureInfo(lcid));
|
||||
}
|
||||
|
||||
internal static void VersionToNative(ManagedHandle versionHandle, IntPtr nativePtr)
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct VersionNative
|
||||
{
|
||||
public int Major;
|
||||
public int Minor;
|
||||
public int Build;
|
||||
public int Revision;
|
||||
}
|
||||
|
||||
internal static void VersionToNative(ManagedHandle versionHandle, ref int major, ref int minor, ref int build, ref int revision)
|
||||
{
|
||||
Version version = Unsafe.As<Version>(versionHandle.Target);
|
||||
if (version != null)
|
||||
{
|
||||
Marshal.WriteInt32(nativePtr, 0, version.Major);
|
||||
Marshal.WriteInt32(nativePtr, 4, version.Minor);
|
||||
Marshal.WriteInt32(nativePtr, 8, version.Build);
|
||||
Marshal.WriteInt32(nativePtr, 12, version.Revision);
|
||||
}
|
||||
else
|
||||
{
|
||||
Marshal.WriteInt32(nativePtr, 0, 0);
|
||||
Marshal.WriteInt32(nativePtr, 4, 0);
|
||||
Marshal.WriteInt32(nativePtr, 8, -1);
|
||||
Marshal.WriteInt32(nativePtr, 12, -1);
|
||||
major = version.Major;
|
||||
minor = version.Minor;
|
||||
build = version.Build;
|
||||
revision = version.Revision;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -151,6 +151,13 @@ void ShadowsOfMordor::Builder::onJobRender(GPUContext* context)
|
||||
auto patch = terrain->GetPatch(entry.AsTerrain.PatchIndex);
|
||||
auto chunk = &patch->Chunks[entry.AsTerrain.ChunkIndex];
|
||||
auto chunkSize = terrain->GetChunkSize();
|
||||
if (!patch->Heightmap)
|
||||
{
|
||||
LOG(Error, "Terrain actor {0} is missing heightmap for baking, skipping baking stage.", terrain->GetName());
|
||||
_wasStageDone = true;
|
||||
scene->EntriesLocker.Unlock();
|
||||
return;
|
||||
}
|
||||
const auto heightmap = patch->Heightmap.Get()->GetTexture();
|
||||
|
||||
Matrix world;
|
||||
@@ -171,7 +178,7 @@ void ShadowsOfMordor::Builder::onJobRender(GPUContext* context)
|
||||
|
||||
DrawCall drawCall;
|
||||
if (TerrainManager::GetChunkGeometry(drawCall, chunkSize, 0))
|
||||
return;
|
||||
break;
|
||||
|
||||
context->UpdateCB(cb, &shaderData);
|
||||
context->BindCB(0, cb);
|
||||
|
||||
48
Source/Engine/Tests/TestMath.cs
Normal file
48
Source/Engine/Tests/TestMath.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if FLAX_TESTS
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace FlaxEngine.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests for <see cref="Mathf"/> and <see cref="Mathd"/>.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class TestMath
|
||||
{
|
||||
/// <summary>
|
||||
/// Test unwinding angles.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestUnwind()
|
||||
{
|
||||
Assert.AreEqual(0.0f, Mathf.UnwindDegreesAccurate(0.0f));
|
||||
Assert.AreEqual(45.0f, Mathf.UnwindDegreesAccurate(45.0f));
|
||||
Assert.AreEqual(90.0f, Mathf.UnwindDegreesAccurate(90.0f));
|
||||
Assert.AreEqual(180.0f, Mathf.UnwindDegreesAccurate(180.0f));
|
||||
Assert.AreEqual(0.0f, Mathf.UnwindDegreesAccurate(360.0f));
|
||||
Assert.AreEqual(0.0f, Mathf.UnwindDegrees(0.0f));
|
||||
Assert.AreEqual(45.0f, Mathf.UnwindDegrees(45.0f));
|
||||
Assert.AreEqual(90.0f, Mathf.UnwindDegrees(90.0f));
|
||||
Assert.AreEqual(180.0f, Mathf.UnwindDegrees(180.0f));
|
||||
Assert.AreEqual(0.0f, Mathf.UnwindDegrees(360.0f));
|
||||
var fError = 0.001f;
|
||||
var dError = 0.00001;
|
||||
for (float f = -400.0f; f <= 400.0f; f += 0.1f)
|
||||
{
|
||||
var f1 = Mathf.UnwindDegreesAccurate(f);
|
||||
var f2 = Mathf.UnwindDegrees(f);
|
||||
if (Mathf.Abs(f1 - f2) >= fError)
|
||||
throw new Exception($"Failed on angle={f}, {f1} != {f2}");
|
||||
var d = (double)f;
|
||||
var d1 = Mathd.UnwindDegreesAccurate(d);
|
||||
var d2 = Mathd.UnwindDegrees(d);
|
||||
if (Mathd.Abs(d1 - d2) >= dError)
|
||||
throw new Exception($"Failed on angle={d}, {d1} != {d2}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -675,6 +675,10 @@ void VisjectExecutor::ProcessGroupPacking(Box* box, Node* node, Value& value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For in-built structures try to convert it into internal format for better comparability with the scripting
|
||||
value.Inline();
|
||||
|
||||
break;
|
||||
}
|
||||
// Unpack Structure
|
||||
|
||||
@@ -246,6 +246,7 @@ public:
|
||||
void ProcessGroupCollections(Box* box, Node* node, Value& value);
|
||||
|
||||
protected:
|
||||
void InlineVariantStruct(Variant& v);
|
||||
virtual Value eatBox(Node* caller, Box* box) = 0;
|
||||
virtual Graph* GetCurrentGraph() const = 0;
|
||||
|
||||
|
||||
1
Source/ThirdParty/fmt/core.h
vendored
1
Source/ThirdParty/fmt/core.h
vendored
@@ -30,6 +30,7 @@ Customizations done to fmt lib:
|
||||
#define FMT_USE_USER_DEFINED_LITERALS 0
|
||||
#define FMT_USE_STRING 0
|
||||
#define FMT_USE_LONG_DOUBLE 0
|
||||
#define FMT_USE_FLOAT128 0
|
||||
#define FMT_USE_ITERATOR 0
|
||||
#define FMT_USE_LOCALE_GROUPING 0
|
||||
#define FMT_EXCEPTIONS 0
|
||||
|
||||
@@ -1203,6 +1203,8 @@ namespace Flax.Build.Bindings
|
||||
contents.Append("ref ");
|
||||
else if (parameterInfo.IsThis)
|
||||
contents.Append("this ");
|
||||
else if (parameterInfo.IsParams)
|
||||
contents.Append("params ");
|
||||
contents.Append(managedType);
|
||||
contents.Append(' ');
|
||||
contents.Append(parameterInfo.Name);
|
||||
@@ -1263,6 +1265,8 @@ namespace Flax.Build.Bindings
|
||||
contents.Append("ref ");
|
||||
else if (parameterInfo.IsThis)
|
||||
contents.Append("this ");
|
||||
else if (parameterInfo.IsParams)
|
||||
contents.Append("params ");
|
||||
contents.Append(managedType);
|
||||
contents.Append(' ');
|
||||
contents.Append(parameterInfo.Name);
|
||||
@@ -1988,6 +1992,8 @@ namespace Flax.Build.Bindings
|
||||
contents.Append("ref ");
|
||||
else if (parameterInfo.IsThis)
|
||||
contents.Append("this ");
|
||||
else if (parameterInfo.IsParams)
|
||||
contents.Append("params ");
|
||||
contents.Append(managedType);
|
||||
contents.Append(' ');
|
||||
contents.Append(parameterInfo.Name);
|
||||
@@ -2053,7 +2059,7 @@ namespace Flax.Build.Bindings
|
||||
if (code.StartsWith("using"))
|
||||
CSharpUsedNamespaces.Add(code.Substring(6));
|
||||
else if (code.Length > 0)
|
||||
contents.Append(injectCodeInfo.Code).AppendLine(";");
|
||||
contents.Append(code).AppendLine(";");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Flax.Build.Bindings
|
||||
partial class BindingsGenerator
|
||||
{
|
||||
private static readonly Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
|
||||
private const int CacheVersion = 18;
|
||||
private const int CacheVersion = 19;
|
||||
|
||||
internal static void Write(BinaryWriter writer, string e)
|
||||
{
|
||||
|
||||
@@ -337,6 +337,9 @@ namespace Flax.Build.Bindings
|
||||
case "this":
|
||||
currentParam.IsThis = true;
|
||||
break;
|
||||
case "params":
|
||||
currentParam.IsParams = true;
|
||||
break;
|
||||
case "attributes":
|
||||
currentParam.Attributes = tag.Value;
|
||||
break;
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace Flax.Build.Bindings
|
||||
public bool IsRef;
|
||||
public bool IsOut;
|
||||
public bool IsThis;
|
||||
public bool IsParams;
|
||||
|
||||
public bool HasDefaultValue => !string.IsNullOrEmpty(DefaultValue);
|
||||
|
||||
@@ -37,6 +38,7 @@ namespace Flax.Build.Bindings
|
||||
writer.Write(IsRef);
|
||||
writer.Write(IsOut);
|
||||
writer.Write(IsThis);
|
||||
writer.Write(IsParams);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader reader)
|
||||
@@ -49,6 +51,7 @@ namespace Flax.Build.Bindings
|
||||
IsRef = reader.ReadBoolean();
|
||||
IsOut = reader.ReadBoolean();
|
||||
IsThis = reader.ReadBoolean();
|
||||
IsParams = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
||||
@@ -159,6 +159,7 @@ namespace Flax.Build
|
||||
var outputPath = Path.GetDirectoryName(buildData.Target.GetOutputFilePath(buildOptions));
|
||||
var outputFile = Path.Combine(outputPath, name + ".dll");
|
||||
var outputDocFile = Path.Combine(outputPath, name + ".xml");
|
||||
var outputGeneratedFiles = Path.Combine(buildOptions.IntermediateFolder);
|
||||
string cscPath, referenceAssemblies;
|
||||
#if USE_NETCORE
|
||||
var dotnetSdk = DotNetSdk.Instance;
|
||||
@@ -263,6 +264,9 @@ namespace Flax.Build
|
||||
#endif
|
||||
args.Add(string.Format("/out:\"{0}\"", outputFile));
|
||||
args.Add(string.Format("/doc:\"{0}\"", outputDocFile));
|
||||
#if USE_NETCORE
|
||||
args.Add(string.Format("/generatedfilesout:\"{0}\"", outputGeneratedFiles));
|
||||
#endif
|
||||
if (buildOptions.ScriptingAPI.Defines.Count != 0)
|
||||
args.Add("/define:" + string.Join(";", buildOptions.ScriptingAPI.Defines));
|
||||
if (buildData.Configuration == TargetConfiguration.Debug)
|
||||
@@ -272,8 +276,10 @@ namespace Flax.Build
|
||||
foreach (var reference in fileReferences)
|
||||
args.Add(string.Format("/reference:\"{0}\"", reference));
|
||||
#if USE_NETCORE
|
||||
foreach (var analyzer in buildOptions.ScriptingAPI.SystemAnalyzers)
|
||||
args.Add(string.Format("/analyzer:\"{0}{1}.dll\"", referenceAnalyzers, analyzer));
|
||||
foreach (var systemAnalyzer in buildOptions.ScriptingAPI.SystemAnalyzers)
|
||||
args.Add(string.Format("/analyzer:\"{0}{1}.dll\"", referenceAnalyzers, systemAnalyzer));
|
||||
foreach (var analyzer in buildOptions.ScriptingAPI.Analyzers)
|
||||
args.Add(string.Format("/analyzer:\"{0}\"", analyzer));
|
||||
#endif
|
||||
foreach (var sourceFile in sourceFiles)
|
||||
args.Add("\"" + sourceFile + "\"");
|
||||
|
||||
@@ -200,14 +200,19 @@ namespace Flax.Build.NativeCpp
|
||||
public HashSet<string> SystemReferences;
|
||||
|
||||
/// <summary>
|
||||
/// The .Net libraries references (dll or exe files paths).
|
||||
/// The system analyzers/source generators.
|
||||
/// </summary>
|
||||
public HashSet<string> SystemAnalyzers;
|
||||
|
||||
/// <summary>
|
||||
/// The .NET libraries references (dll or exe files paths).
|
||||
/// </summary>
|
||||
public HashSet<string> FileReferences;
|
||||
|
||||
/// <summary>
|
||||
/// The .Net libraries references (dll or exe files paths).
|
||||
/// The .NET analyzers (dll or exe files paths).
|
||||
/// </summary>
|
||||
public HashSet<string> SystemAnalyzers;
|
||||
public HashSet<string> Analyzers;
|
||||
|
||||
/// <summary>
|
||||
/// True if ignore compilation warnings due to missing code documentation comments.
|
||||
@@ -232,6 +237,7 @@ namespace Flax.Build.NativeCpp
|
||||
Defines.AddRange(other.Defines);
|
||||
SystemReferences.AddRange(other.SystemReferences);
|
||||
FileReferences.AddRange(other.FileReferences);
|
||||
Analyzers.AddRange(other.Analyzers);
|
||||
IgnoreMissingDocumentationWarnings |= other.IgnoreMissingDocumentationWarnings;
|
||||
}
|
||||
}
|
||||
@@ -305,6 +311,7 @@ namespace Flax.Build.NativeCpp
|
||||
"Microsoft.Interop.SourceGeneration",
|
||||
},
|
||||
FileReferences = new HashSet<string>(),
|
||||
Analyzers = new HashSet<string>(),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -247,6 +247,14 @@ namespace Flax.Build.Projects.VisualStudio
|
||||
csProjectFileContent.AppendLine(" </ItemGroup>");
|
||||
}
|
||||
}
|
||||
foreach (var analyzer in configuration.TargetBuildOptions.ScriptingAPI.Analyzers)
|
||||
{
|
||||
csProjectFileContent.AppendLine(string.Format(" <ItemGroup Condition=\" '$(Configuration)|$(Platform)' == '{0}' \">", configuration.Name));
|
||||
csProjectFileContent.AppendLine(string.Format(" <Analyzer Include=\"{0}\">", Path.GetFileNameWithoutExtension(analyzer)));
|
||||
csProjectFileContent.AppendLine(string.Format(" <HintPath>{0}</HintPath>", Utilities.MakePathRelativeTo(analyzer, projectDirectory).Replace('/', '\\')));
|
||||
csProjectFileContent.AppendLine(" </Analyzer>");
|
||||
csProjectFileContent.AppendLine(" </ItemGroup>");
|
||||
}
|
||||
|
||||
csProjectFileContent.AppendLine("");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user