Merge branch 'FlaxEngine:master' into material_import

This commit is contained in:
Menotdan
2023-08-09 15:31:44 -04:00
committed by GitHub
41 changed files with 783 additions and 262 deletions

Binary file not shown.

View File

@@ -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 />

View File

@@ -80,6 +80,8 @@ 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;
}
}

View File

@@ -96,6 +96,7 @@ namespace FlaxEditor
public SpriteHandle Link64;
public SpriteHandle Build64;
public SpriteHandle Add64;
public SpriteHandle ShipIt64;
// 96px
public SpriteHandle Toolbox96;

View File

@@ -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)

View File

@@ -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;
}
}
}

View File

@@ -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>

View File

@@ -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()
{

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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();

View File

@@ -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)

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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()

View File

@@ -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)));

View File

@@ -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;

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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--)

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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;
}
}

View File

@@ -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);

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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()

View File

@@ -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 + "\"");

View File

@@ -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>

View File

@@ -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("");
}