Merge remote-tracking branch 'origin/1.10' into 1.10

This commit is contained in:
Wojtek Figat
2024-10-03 12:37:00 +02:00
78 changed files with 737 additions and 231 deletions

BIN
Content/Shaders/VolumetricFog.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -223,7 +223,7 @@ namespace FlaxEditor.GUI
}
}
private readonly TextBox _searchBox;
private readonly SearchBox _searchBox;
private readonly Panel _scrollPanel;
private List<DropPanel> _categoryPanels;
private bool _waitingForInput;
@@ -260,6 +260,7 @@ namespace FlaxEditor.GUI
Width = Width - 3,
};
_searchBox.TextChanged += OnSearchFilterChanged;
_searchBox.ClearSearchButton.Clicked += () => PerformLayout();
// Panel with scrollbar
_scrollPanel = new Panel(ScrollBars.Vertical)

View File

@@ -197,7 +197,7 @@ namespace FlaxEditor.GUI.Timeline
continue;
var track = (NestedSceneAnimationTrack)timeline.NewTrack(NestedSceneAnimationTrack.GetArchetype());
track.Asset = sceneAnimation;
track.TrackMedia.Duration = sceneAnimation.Duration;
track.TrackMedia.DurationFrames = (int)(sceneAnimation.Duration * timeline.FramesPerSecond);
track.Rename(assetItem.ShortName);
timeline.AddTrack(track);
}
@@ -208,7 +208,7 @@ namespace FlaxEditor.GUI.Timeline
continue;
var track = (AudioTrack)timeline.NewTrack(AudioTrack.GetArchetype());
track.Asset = audioClip;
track.TrackMedia.Duration = audioClip.Length;
track.TrackMedia.DurationFrames = (int)(audioClip.Length * timeline.FramesPerSecond);
track.Rename(assetItem.ShortName);
timeline.AddTrack(track);
}

View File

@@ -1288,10 +1288,7 @@ namespace FlaxEditor.GUI.Timeline
public virtual void AddTrack(Track track, bool withUndo = true)
{
// Ensure name is unique
int idx = 1;
var name = track.Name;
while (!IsTrackNameValid(track.Name))
track.Name = string.Format("{0} {1}", name, idx++);
track.Name = GetValidTrackName(track.Name);
// Add it to the timeline
_tracks.Add(track);
@@ -1843,11 +1840,7 @@ namespace FlaxEditor.GUI.Timeline
/// <returns>The track name.</returns>
public string GetValidTrackName(string name)
{
string newName = name;
int count = 0;
while (!IsTrackNameValid(newName))
newName = string.Format("{0} {1}", name, count++);
return newName;
return Utilities.Utils.IncrementNameNumber(name, IsTrackNameValid);
}
/// <summary>

View File

@@ -854,11 +854,9 @@ namespace FlaxEditor.GUI.Timeline
/// <param name="name">The base name.</param>
public void Rename(string name)
{
string newName = name;
int count = 0;
while (_timeline != null && !_timeline.IsTrackNameValid(newName))
newName = string.Format("{0} {1}", name, count++);
OnRename(newName);
if (_timeline != null)
name = _timeline.GetValidTrackName(name);
OnRename(name);
}
/// <summary>

View File

@@ -107,6 +107,21 @@ namespace FlaxEditor.GUI
return this;
}
/// <summary>
/// Links the tooltip with input binding info.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="inputBinding">The input key binding.</param>
/// <returns>This tooltip.</returns>
public ToolStripButton LinkTooltip(string text, ref Options.InputBinding inputBinding)
{
var input = inputBinding.ToString();
if (input.Length != 0)
text = $"{text} ({input})";
LinkTooltip(text);
return this;
}
/// <inheritdoc />
public override void Draw()
{

View File

@@ -707,18 +707,18 @@ namespace FlaxEditor.Modules
Parent = mainWindow,
};
_toolStripSaveAll = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Save64, Editor.SaveAll).LinkTooltip($"Save all ({inputOptions.Save})");
_toolStripSaveAll = ToolStrip.AddButton(Editor.Icons.Save64, Editor.SaveAll).LinkTooltip("Save all", ref inputOptions.Save);
ToolStrip.AddSeparator();
_toolStripUndo = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Undo64, Editor.PerformUndo).LinkTooltip($"Undo ({inputOptions.Undo})");
_toolStripRedo = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Redo64, Editor.PerformRedo).LinkTooltip($"Redo ({inputOptions.Redo})");
_toolStripUndo = ToolStrip.AddButton(Editor.Icons.Undo64, Editor.PerformUndo).LinkTooltip("Undo", ref inputOptions.Undo);
_toolStripRedo = ToolStrip.AddButton(Editor.Icons.Redo64, Editor.PerformRedo).LinkTooltip("Redo", ref inputOptions.Redo);
ToolStrip.AddSeparator();
_toolStripTranslate = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Translate32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate).LinkTooltip($"Change Gizmo tool mode to Translate ({inputOptions.TranslateMode})");
_toolStripRotate = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Rotate32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate).LinkTooltip($"Change Gizmo tool mode to Rotate ({inputOptions.RotateMode})");
_toolStripScale = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Scale32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale).LinkTooltip($"Change Gizmo tool mode to Scale ({inputOptions.ScaleMode})");
_toolStripTranslate = ToolStrip.AddButton(Editor.Icons.Translate32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate).LinkTooltip("Change Gizmo tool mode to Translate", ref inputOptions.TranslateMode);
_toolStripRotate = ToolStrip.AddButton(Editor.Icons.Rotate32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate).LinkTooltip("Change Gizmo tool mode to Rotate", ref inputOptions.RotateMode);
_toolStripScale = ToolStrip.AddButton(Editor.Icons.Scale32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale).LinkTooltip("Change Gizmo tool mode to Scale", ref inputOptions.ScaleMode);
ToolStrip.AddSeparator();
// Play
_toolStripPlay = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Play64, Editor.Simulation.DelegatePlayOrStopPlayInEditor).LinkTooltip($"Play In Editor ({inputOptions.Play})");
_toolStripPlay = ToolStrip.AddButton(Editor.Icons.Play64, Editor.Simulation.DelegatePlayOrStopPlayInEditor).LinkTooltip("Play In Editor", ref inputOptions.Play);
_toolStripPlay.ContextMenu = new ContextMenu();
var playSubMenu = _toolStripPlay.ContextMenu.AddChildMenu("Play button action");
var playActionGroup = new ContextMenuSingleSelectGroup<InterfaceOptions.PlayAction>();
@@ -739,16 +739,16 @@ namespace FlaxEditor.Modules
windowModesGroup.SelectedChanged = SetGameWindowMode;
Editor.Options.OptionsChanged += options => { windowModesGroup.Selected = options.Interface.DefaultGameWindowMode; };
_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 ({inputOptions.StepFrame})");
_toolStripPause = ToolStrip.AddButton(Editor.Icons.Pause64, Editor.Simulation.RequestResumeOrPause).LinkTooltip("Pause/Resume game", ref inputOptions.Pause);
_toolStripStep = ToolStrip.AddButton(Editor.Icons.Skip64, Editor.Simulation.RequestPlayOneFrame).LinkTooltip("Step one frame in game", ref inputOptions.StepFrame);
ToolStrip.AddSeparator();
// Build 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 ({inputOptions.BuildScenesData})");
_toolStripBuildScenes = ToolStrip.AddButton(Editor.Icons.Build64, Editor.BuildScenesOrCancel).LinkTooltip("Build scenes data - CSG, navmesh, static lighting, env probes - configurable via Build Actions in editor options", ref inputOptions.BuildScenesData);
// Cook and run
_toolStripCook = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.ShipIt64, Editor.Windows.GameCookerWin.BuildAndRun).LinkTooltip($"Cook & Run - build game for the current platform and run it locally ({inputOptions.CookAndRun})");
_toolStripCook = ToolStrip.AddButton(Editor.Icons.ShipIt64, Editor.Windows.GameCookerWin.BuildAndRun).LinkTooltip("Cook & Run - build game for the current platform and run it locally", ref inputOptions.CookAndRun);
_toolStripCook.ContextMenu = new ContextMenu();
_toolStripCook.ContextMenu.AddButton("Run cooked game", Editor.Windows.GameCookerWin.RunCooked);
_toolStripCook.ContextMenu.AddSeparator();

View File

@@ -132,7 +132,7 @@ namespace FlaxEditor.Surface
public virtual void OnSurfaceLoaded(SurfaceNodeActions action)
{
// Snap bounds (with ceil) when using grid snapping
if (Surface.GridSnappingEnabled)
if (Surface != null && Surface.GridSnappingEnabled)
{
var bounds = Bounds;
bounds.Location = Surface.SnapToGrid(bounds.Location, false);

View File

@@ -572,12 +572,12 @@ namespace FlaxEditor.Surface
var undo = surface.Undo;
// Toolstrip
saveButton = (ToolStripButton)toolStrip.AddButton(editor.Icons.Save64, window.Save).LinkTooltip("Save");
saveButton = toolStrip.AddButton(editor.Icons.Save64, window.Save).LinkTooltip("Save", ref inputOptions.Save);
toolStrip.AddSeparator();
undoButton = (ToolStripButton)toolStrip.AddButton(editor.Icons.Undo64, undo.PerformUndo).LinkTooltip($"Undo ({inputOptions.Undo})");
redoButton = (ToolStripButton)toolStrip.AddButton(editor.Icons.Redo64, undo.PerformRedo).LinkTooltip($"Redo ({inputOptions.Redo})");
undoButton = toolStrip.AddButton(editor.Icons.Undo64, undo.PerformUndo).LinkTooltip("Undo", ref inputOptions.Undo);
redoButton = toolStrip.AddButton(editor.Icons.Redo64, undo.PerformRedo).LinkTooltip("Redo", ref inputOptions.Redo);
toolStrip.AddSeparator();
toolStrip.AddButton(editor.Icons.Search64, editor.ContentFinding.ShowSearch).LinkTooltip($"Open content search tool ({inputOptions.Search})");
toolStrip.AddButton(editor.Icons.Search64, editor.ContentFinding.ShowSearch).LinkTooltip("Open content search tool", ref inputOptions.Search);
toolStrip.AddButton(editor.Icons.CenterView64, surface.ShowWholeGraph).LinkTooltip("Show whole graph");
var gridSnapButton = toolStrip.AddButton(editor.Icons.Grid32, surface.ToggleGridSnapping);
gridSnapButton.LinkTooltip("Toggle grid snapping for nodes.");

View File

@@ -281,10 +281,10 @@ namespace FlaxEditor.Windows.Assets
_propertiesPresenter.Select(_properties);
// Toolstrip
_saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_saveButton = _toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save", ref inputOptions.Save);
_toolstrip.AddSeparator();
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip($"Undo ({inputOptions.Undo})");
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip($"Redo ({inputOptions.Redo})");
_undoButton = _toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo", ref inputOptions.Undo);
_redoButton = _toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo", ref inputOptions.Redo);
_toolstrip.AddSeparator();
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/animation/index.html")).LinkTooltip("See documentation to learn more");

View File

@@ -422,10 +422,10 @@ namespace FlaxEditor.Windows.Assets
_proxy = new PropertiesProxy();
_propertiesEditor.Select(_proxy);
_saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip($"Save asset ({inputOptions.Save})");
_saveButton = _toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save", ref inputOptions.Save);
_toolstrip.AddSeparator();
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip($"Undo ({inputOptions.Undo})");
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip($"Redo ({inputOptions.Redo})");
_undoButton = _toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo", ref inputOptions.Undo);
_redoButton = _toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo", ref inputOptions.Redo);
_toolstrip.AddSeparator();
_resetButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Rotate32, Reset).LinkTooltip("Resets the variables values to the default values");

View File

@@ -95,10 +95,10 @@ namespace FlaxEditor.Windows.Assets
_undo.ActionDone += OnUndoRedo;
// Toolstrip
_saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save");
_saveButton = _toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save", ref inputOptions.Save);
_toolstrip.AddSeparator();
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip($"Undo ({inputOptions.Undo})");
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip($"Redo ({inputOptions.Redo})");
_undoButton = _toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo", ref inputOptions.Undo);
_redoButton = _toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo", ref inputOptions.Redo);
// Panel
var panel = new Panel(ScrollBars.Vertical)

View File

@@ -135,10 +135,10 @@ namespace FlaxEditor.Windows.Assets
_undo.ActionDone += OnUndoRedo;
// Toolstrip
_saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save");
_saveButton = _toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save", ref inputOptions.Save);
_toolstrip.AddSeparator();
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip($"Undo ({inputOptions.Undo})");
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip($"Redo ({inputOptions.Redo})");
_undoButton = _toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo", ref inputOptions.Undo);
_redoButton = _toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo", ref inputOptions.Redo);
_toolstrip.AddSeparator();
_toolstrip.AddButton(Editor.Icons.Up64, OnExport).LinkTooltip("Export localization table entries for translation to .pot file");

View File

@@ -387,10 +387,10 @@ namespace FlaxEditor.Windows.Assets
_undo.ActionDone += OnAction;
// Toolstrip
_saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_saveButton = _toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save", ref inputOptions.Save);
_toolstrip.AddSeparator();
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip($"Undo ({inputOptions.Undo})");
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip($"Redo ({inputOptions.Redo})");
_undoButton = _toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo", ref inputOptions.Undo);
_redoButton = _toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo", ref inputOptions.Redo);
_toolstrip.AddSeparator();
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/materials/instanced-materials/index.html")).LinkTooltip("See documentation to learn more");

View File

@@ -105,8 +105,10 @@ namespace FlaxEditor.Windows.Assets
protected ModelBaseWindow(Editor editor, AssetItem item)
: base(editor, item)
{
var inputOptions = Editor.Options.Options.Input;
// Toolstrip
_saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save");
_saveButton = _toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save", ref inputOptions.Save);
// Split Panel
_split = new SplitPanel(Orientation.Horizontal, ScrollBars.None, ScrollBars.None)

View File

@@ -359,10 +359,10 @@ namespace FlaxEditor.Windows.Assets
propertiesEditor.Select(new GeneralProxy(this));
// Toolstrip
_saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_saveButton = _toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save", ref inputOptions.Save);
_toolstrip.AddSeparator();
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip($"Undo ({inputOptions.Undo})");
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip($"Redo ({inputOptions.Redo})");
_undoButton = _toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo", ref inputOptions.Undo);
_redoButton = _toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo", ref inputOptions.Redo);
_toolstrip.AddSeparator();
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/particles/index.html")).LinkTooltip("See documentation to learn more");

View File

@@ -181,14 +181,14 @@ namespace FlaxEditor.Windows.Assets
_propertiesEditor.Modified += MarkAsEdited;
// Toolstrip
_saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_saveButton = _toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save", ref inputOptions.Save);
_toolstrip.AddSeparator();
_toolStripUndo = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip($"Undo ({inputOptions.Undo})");
_toolStripRedo = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip($"Redo ({inputOptions.Redo})");
_toolStripUndo = _toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo", ref inputOptions.Undo);
_toolStripRedo = _toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo", ref inputOptions.Redo);
_toolstrip.AddSeparator();
_toolStripTranslate = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Translate32, () => _viewport.TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate).LinkTooltip($"Change Gizmo tool mode to Translate ({inputOptions.TranslateMode})");
_toolStripRotate = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Rotate32, () => _viewport.TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate).LinkTooltip($"Change Gizmo tool mode to Rotate ({inputOptions.RotateMode})");
_toolStripScale = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Scale32, () => _viewport.TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale).LinkTooltip($"Change Gizmo tool mode to Scale ({inputOptions.ScaleMode})");
_toolStripTranslate = _toolstrip.AddButton(Editor.Icons.Translate32, () => _viewport.TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate).LinkTooltip("Change Gizmo tool mode to Translate", ref inputOptions.TranslateMode);
_toolStripRotate = _toolstrip.AddButton(Editor.Icons.Rotate32, () => _viewport.TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate).LinkTooltip("Change Gizmo tool mode to Rotate", ref inputOptions.RotateMode);
_toolStripScale = _toolstrip.AddButton(Editor.Icons.Scale32, () => _viewport.TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale).LinkTooltip("Change Gizmo tool mode to Scale", ref inputOptions.ScaleMode);
_toolstrip.AddSeparator();
_toolStripLiveReload = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Refresh64, () => LiveReload = !LiveReload).SetChecked(true).SetAutoCheck(true).LinkTooltip("Live changes preview (applies prefab changes on modification by auto)");

View File

@@ -652,10 +652,10 @@ namespace FlaxEditor.Windows.Assets
_timeline.SetNoTracksText("Loading...");
// Toolstrip
_saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_saveButton = _toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save", ref inputOptions.Save);
_toolstrip.AddSeparator();
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip($"Undo ({inputOptions.Undo})");
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip($"Redo ({inputOptions.Redo})");
_undoButton = _toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo", ref inputOptions.Undo);
_redoButton = _toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo", ref inputOptions.Redo);
_toolstrip.AddSeparator();
_previewButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Refresh64, OnPreviewButtonClicked).SetAutoCheck(true).LinkTooltip("If checked, enables live-preview of the animation on a scene while editing");
_renderButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Build64, OnRenderButtonClicked).LinkTooltip("Open the scene animation rendering utility...");

View File

@@ -195,8 +195,10 @@ namespace FlaxEditor.Windows.Assets
public SkeletonMaskWindow(Editor editor, AssetItem item)
: base(editor, item)
{
var inputOptions = Editor.Options.Options.Input;
// Toolstrip
_saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save asset to the file");
_saveButton = _toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save", ref inputOptions.Save);
_toolstrip.AddSeparator();
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/skeleton-mask.html")).LinkTooltip("See documentation to learn more");

View File

@@ -273,6 +273,8 @@ namespace FlaxEditor.Windows.Assets
public SpriteAtlasWindow(Editor editor, AssetItem item)
: base(editor, item)
{
var inputOptions = Editor.Options.Options.Input;
// Split Panel
_split = new SplitPanel(Orientation.Horizontal, ScrollBars.None, ScrollBars.Vertical)
{
@@ -296,7 +298,7 @@ namespace FlaxEditor.Windows.Assets
_propertiesEditor.Modified += MarkAsEdited;
// Toolstrip
_saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save");
_saveButton = _toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save", ref inputOptions.Save);
_toolstrip.AddButton(editor.Icons.Import64, () => Editor.ContentImporting.Reimport((BinaryAssetItem)Item)).LinkTooltip("Reimport");
_toolstrip.AddSeparator();
_toolstrip.AddButton(editor.Icons.AddFile64, () =>

View File

@@ -27,7 +27,7 @@ namespace FlaxEditor.Windows.Assets
public class PropertiesProxyBase
{
internal TextureWindow _window;
/// <summary>
/// Gathers parameters from the specified texture.
/// </summary>
@@ -37,7 +37,7 @@ namespace FlaxEditor.Windows.Assets
// Link
_window = window;
}
/// <summary>
/// Clears temporary data.
/// </summary>
@@ -83,7 +83,7 @@ namespace FlaxEditor.Windows.Assets
}
}
}
/// <summary>
/// The texture import properties proxy object.
/// </summary>
@@ -129,7 +129,7 @@ namespace FlaxEditor.Windows.Assets
public void DiscardChanges()
{
}
private sealed class ProxyEditor : GenericEditor
{
public override void Initialize(LayoutElementsContainer layout)
@@ -151,7 +151,7 @@ namespace FlaxEditor.Windows.Assets
/// The presenter to use in the tab.
/// </summary>
public CustomEditorPresenter Presenter;
/// <summary>
/// The proxy to use in the tab.
/// </summary>
@@ -214,6 +214,8 @@ namespace FlaxEditor.Windows.Assets
public TextureWindow(Editor editor, AssetItem item)
: base(editor, item)
{
var inputOptions = Editor.Options.Options.Input;
// Split Panel
_split = new SplitPanel(Orientation.Horizontal, ScrollBars.None, ScrollBars.Vertical)
{
@@ -228,7 +230,7 @@ namespace FlaxEditor.Windows.Assets
{
Parent = _split.Panel1
};
// Properties tabs
_tabs = new()
{
@@ -244,7 +246,7 @@ namespace FlaxEditor.Windows.Assets
_tabs.AddTab(new ImportTab(this));
// Toolstrip
_saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save", ref inputOptions.Save);
_toolstrip.AddButton(Editor.Icons.Import64, () => Editor.ContentImporting.Reimport((BinaryAssetItem)Item)).LinkTooltip("Reimport");
_toolstrip.AddSeparator();
_toolstrip.AddButton(Editor.Icons.CenterView64, _preview.CenterView).LinkTooltip("Center view");

View File

@@ -603,11 +603,11 @@ namespace FlaxEditor.Windows.Assets
_debugToolstripControls = new[]
{
_toolstrip.AddSeparator(),
_toolstrip.AddButton(editor.Icons.Play64, OnDebuggerContinue).LinkTooltip($"Continue ({inputOptions.DebuggerContinue})"),
_toolstrip.AddButton(editor.Icons.Play64, OnDebuggerContinue).LinkTooltip("Continue", ref inputOptions.DebuggerContinue),
_toolstrip.AddButton(editor.Icons.Search64, OnDebuggerNavigateToCurrentNode).LinkTooltip("Navigate to the current stack trace node"),
_toolstrip.AddButton(editor.Icons.Right64, OnDebuggerStepOver).LinkTooltip($"Step Over ({inputOptions.DebuggerStepOver})"),
_toolstrip.AddButton(editor.Icons.Down64, OnDebuggerStepInto).LinkTooltip($"Step Into ({inputOptions.DebuggerStepInto})"),
_toolstrip.AddButton(editor.Icons.Up64, OnDebuggerStepOut).LinkTooltip($"Step Out ({inputOptions.DebuggerStepOut})"),
_toolstrip.AddButton(editor.Icons.Right64, OnDebuggerStepOver).LinkTooltip("Step Over", ref inputOptions.DebuggerStepOver),
_toolstrip.AddButton(editor.Icons.Down64, OnDebuggerStepInto).LinkTooltip("Step Into", ref inputOptions.DebuggerStepInto),
_toolstrip.AddButton(editor.Icons.Up64, OnDebuggerStepOut).LinkTooltip("Step Out", ref inputOptions.DebuggerStepOut),
_toolstrip.AddButton(editor.Icons.Stop64, OnDebuggerStop).LinkTooltip("Stop debugging"),
};
foreach (var control in _debugToolstripControls)

View File

@@ -65,11 +65,6 @@ namespace FlaxEditor.Windows
/// </summary>
public OutputLogWindow Window;
/// <summary>
/// The input actions collection to processed during user input.
/// </summary>
public InputActionsContainer InputActions = new InputActionsContainer();
/// <summary>
/// The default text style.
/// </summary>
@@ -88,7 +83,7 @@ namespace FlaxEditor.Windows
/// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key)
{
if (InputActions.Process(Editor.Instance, this, key))
if (Window.InputActions.Process(Editor.Instance, this, key))
return true;
return base.OnKeyDown(key);
}
@@ -214,9 +209,8 @@ namespace FlaxEditor.Windows
// Setup editor options
Editor.Options.OptionsChanged += OnEditorOptionsChanged;
OnEditorOptionsChanged(Editor.Options.Options);
_output.InputActions.Add(options => options.Search, () => _searchBox.Focus());
InputActions.Add(options => options.Search, () => _searchBox.Focus());
InputActions.Add(options => options.Search, _searchBox.Focus);
GameCooker.Event += OnGameCookerEvent;
ScriptsBuilder.CompilationFailed += OnScriptsCompilationFailed;

View File

@@ -409,7 +409,7 @@ namespace FlaxEditor.Windows
_debugToolstripControls = new[]
{
toolstrip.AddSeparator(),
toolstrip.AddButton(editor.Icons.Play64, OnDebuggerContinue).LinkTooltip($"Continue ({inputOptions.DebuggerContinue})"),
toolstrip.AddButton(editor.Icons.Play64, OnDebuggerContinue).LinkTooltip("Continue", ref inputOptions.DebuggerContinue),
toolstrip.AddButton(editor.Icons.Search64, OnDebuggerNavigateToCurrentNode).LinkTooltip("Navigate to the current stack trace node"),
toolstrip.AddButton(editor.Icons.Stop64, OnDebuggerStop).LinkTooltip("Stop debugging"),
};

View File

@@ -444,7 +444,6 @@ BehaviorUpdateResult BehaviorTreeMoveToNode::Update(const BehaviorUpdateContext&
else
goalLocation = TargetLocation.Get(context.Knowledge);
repath |= Vector3::Distance(goalLocation, state->GoalLocation) > TargetGoalUpdateTolerance;
state->GoalLocation = goalLocation;
}
if (repath)
@@ -490,6 +489,7 @@ BehaviorUpdateResult BehaviorTreeMoveToNode::Update(const BehaviorUpdateContext&
state->HasPath = true;
state->TargetPathIndex = 1;
state->Result = BehaviorUpdateResult::Running;
state->GoalLocation = goalLocation;
// TODO: add path debugging in Editor (eg. via BT window)

View File

@@ -35,7 +35,7 @@ StringView StringView::Left(int32 count) const
StringView StringView::Right(int32 count) const
{
const int32 countClamped = count < 0 ? 0 : count < Length() ? count : Length();
return StringView(**this + Length() - countClamped);
return StringView(**this + countClamped, Length() - countClamped);
}
StringView StringView::Substring(int32 startIndex) const

View File

@@ -2449,7 +2449,9 @@ void Variant::SetType(const VariantType& type)
case VariantType::Structure:
AllocStructure();
break;
default: ;
default:
AsUint64 = 0;
break;
}
}
@@ -3065,6 +3067,69 @@ void Variant::DeleteValue()
SetType(VariantType(VariantType::Null));
}
Variant Variant::Parse(const StringView& text, const VariantType& type)
{
Variant result;
result.SetType(type);
if (text.IsEmpty())
return result;
if (type != VariantType())
{
switch (type.Type)
{
case VariantType::Bool:
if (text == TEXT("1") || text.Compare(StringView(TEXT("true"), 4), StringSearchCase::IgnoreCase) == 0)
result.AsBool = true;
break;
case VariantType::Int16:
StringUtils::Parse(text.Get(), &result.AsInt16);
break;
case VariantType::Uint16:
StringUtils::Parse(text.Get(), &result.AsUint16);
break;
case VariantType::Int:
StringUtils::Parse(text.Get(), &result.AsInt);
break;
case VariantType::Uint:
StringUtils::Parse(text.Get(), &result.AsUint);
break;
case VariantType::Int64:
StringUtils::Parse(text.Get(), &result.AsInt64);
break;
case VariantType::Uint64:
case VariantType::Enum:
StringUtils::Parse(text.Get(), &result.AsUint64);
break;
case VariantType::Float:
StringUtils::Parse(text.Get(), &result.AsFloat);
break;
case VariantType::Double:
StringUtils::Parse(text.Get(), &result.AsFloat);
result.AsDouble = (float)result.AsFloat;
break;
case VariantType::String:
result.SetString(text);
default:
break;
}
}
else
{
// Parse as number
int32 valueInt;
if (!StringUtils::Parse(text.Get(), text.Length(), &valueInt))
{
result = valueInt;
}
else
{
// Fallback to string
result.SetString(text);
}
}
return result;
}
bool Variant::CanCast(const Variant& v, const VariantType& to)
{
if (v.Type == to)

View File

@@ -381,6 +381,9 @@ public:
// Frees the object or data owned by this Variant container (eg. structure or object).
void DeleteValue();
// Parses the text into the Variant value. Allows to specify explicit value type.
static Variant Parse(const StringView& text, const VariantType& type = VariantType());
FORCE_INLINE Variant Cast(const VariantType& to) const
{
return Cast(*this, to);

View File

@@ -0,0 +1,293 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
#include "DebugCommands.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Engine/EngineService.h"
#include "Engine/Threading/Threading.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Scripting/BinaryModule.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MMethod.h"
#include "Engine/Scripting/ManagedCLR/MField.h"
#include "Engine/Scripting/ManagedCLR/MProperty.h"
#include "FlaxEngine.Gen.h"
struct CommandData
{
String Name;
BinaryModule* Module;
void* Method = nullptr;
void* MethodGet = nullptr;
void* MethodSet = nullptr;
void* Field = nullptr;
void Invoke(StringView args) const
{
PROFILE_CPU();
// Get command signature
Array<ScriptingTypeMethodSignature::Param, InlinedAllocation<16>> sigParams;
if (Method)
{
ScriptingTypeMethodSignature sig;
Module->GetMethodSignature(Method, sig);
sigParams = MoveTemp(sig.Params);
}
else if (Field)
{
ScriptingTypeFieldSignature sig;
Module->GetFieldSignature(Field, sig);
auto& p = sigParams.AddOne();
p.IsOut = false;
p.Type = sig.ValueType;
}
else if (MethodSet && args.HasChars())
{
ScriptingTypeMethodSignature sig;
Module->GetMethodSignature(MethodSet, sig);
sigParams = MoveTemp(sig.Params);
sigParams.Resize(1);
}
// Parse arguments
Array<Variant> params;
params.Resize(sigParams.Count());
Array<String> argsSeparated;
String argsStr(args);
argsStr.Split(' ', argsSeparated);
for (int32 i = 0; i < argsSeparated.Count() && i < params.Count(); i++)
{
params[i] = Variant::Parse(argsSeparated[i], sigParams[i].Type);
}
// Call command
Variant result;
if (Method)
{
Module->InvokeMethod(Method, Variant::Null, ToSpan(params), result);
}
else if (Field)
{
if (args.IsEmpty())
Module->GetFieldValue(Field, Variant::Null, result);
else
Module->SetFieldValue(Field, Variant::Null, params[0]);
}
else if (MethodGet && args.IsEmpty())
{
Module->InvokeMethod(MethodGet, Variant::Null, ToSpan(params), result);
}
else if (MethodSet && args.HasChars())
{
Module->InvokeMethod(MethodSet, Variant::Null, ToSpan(params), result);
}
// Print result
if (result != Variant())
{
LOG_STR(Info, result.ToString());
}
}
};
namespace
{
CriticalSection Locker;
bool Inited = false;
Array<CommandData> Commands;
void OnBinaryModuleLoaded(BinaryModule* module)
{
if (module == GetBinaryModuleCorlib())
return;
#if USE_CSHARP
if (auto* managedModule = dynamic_cast<ManagedBinaryModule*>(module))
{
const MClass* attribute = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEngine.DebugCommand");
ASSERT_LOW_LAYER(attribute);
const auto& classes = managedModule->Assembly->GetClasses();
for (auto e : classes)
{
MClass* mclass = e.Value;
if (mclass->IsGeneric() ||
mclass->IsInterface() ||
mclass->IsEnum())
continue;
const bool useClass = mclass->HasAttribute(attribute);
// TODO: optimize this via stack-based format buffer and then convert Ansi to UTF16
#define BUILD_NAME(commandData, itemName) commandData.Name = String(mclass->GetName()) + TEXT(".") + String(itemName)
// Process methods
const auto& methods = mclass->GetMethods();
for (MMethod* method : methods)
{
if (!method->IsStatic())
continue;
const StringAnsi& name = method->GetName();
if (name.Contains("Internal_") ||
mclass->GetFullName().Contains(".Interop."))
continue;
if (name.StartsWith("get_") ||
name.StartsWith("set_") ||
name.StartsWith("op_") ||
name.StartsWith("add_") ||
name.StartsWith("remove_"))
continue;
if (!useClass && !method->HasAttribute(attribute))
continue;
auto& commandData = Commands.AddOne();
BUILD_NAME(commandData, method->GetName());
commandData.Module = module;
commandData.Method = method;
}
// Process fields
const auto& fields = mclass->GetFields();
for (MField* field : fields)
{
if (!field->IsStatic())
continue;
if (!useClass && !field->HasAttribute(attribute))
continue;
auto& commandData = Commands.AddOne();
BUILD_NAME(commandData, field->GetName());
commandData.Module = module;
commandData.Field = field;
}
// Process properties
const auto& properties = mclass->GetProperties();
for (MProperty* property : properties)
{
if (!property->IsStatic())
continue;
if (!useClass && !property->HasAttribute(attribute))
continue;
auto& commandData = Commands.AddOne();
BUILD_NAME(commandData, property->GetName());
commandData.Module = module;
commandData.MethodGet = property->GetGetMethod();
commandData.MethodSet = property->GetSetMethod();
}
}
#undef BUILD_NAME
}
else
#endif
{
// TODO: implement generic search for other modules (eg. Visual Scripts)
}
}
void OnScriptsReloading()
{
// Reset
Inited = false;
Commands.Clear();
}
void InitCommands()
{
PROFILE_CPU();
Inited = true;
const auto& modules = BinaryModule::GetModules();
for (BinaryModule* module : modules)
{
OnBinaryModuleLoaded(module);
}
Scripting::BinaryModuleLoaded.Bind(&OnBinaryModuleLoaded);
Scripting::ScriptsReloading.Bind(&OnScriptsReloading);
}
}
class DebugCommandsService : public EngineService
{
public:
DebugCommandsService()
: EngineService(TEXT("DebugCommands"), 0)
{
}
void Dispose() override
{
// Cleanup
ScopeLock lock(Locker);
Scripting::BinaryModuleLoaded.Unbind(&OnBinaryModuleLoaded);
Scripting::ScriptsReloading.Unbind(&OnScriptsReloading);
Commands.Clear();
Inited = true;
}
};
DebugCommandsService DebugCommandsServiceInstance;
void DebugCommands::Execute(StringView command)
{
// Preprocess command text
while (command.HasChars() && StringUtils::IsWhitespace(command[0]))
command = StringView(command.Get() + 1, command.Length() - 1);
while (command.HasChars() && StringUtils::IsWhitespace(command[command.Length() - 1]))
command = StringView(command.Get(), command.Length() - 1);
if (command.IsEmpty())
return;
StringView name = command;
StringView args;
int32 argsStart = name.Find(' ');
if (argsStart != -1)
{
name = command.Left(argsStart);
args = command.Right(argsStart + 1);
}
// Ensure that commands cache has been created
ScopeLock lock(Locker);
if (!Inited)
InitCommands();
// Find command to run
for (const CommandData& command : Commands)
{
if (name.Length() == command.Name.Length() &&
StringUtils::CompareIgnoreCase(name.Get(), command.Name.Get(), name.Length()) == 0)
{
command.Invoke(args);
return;
}
}
LOG(Error, "Unknown command '{}'", name);
}
bool DebugCommands::Iterate(const StringView& searchText, int32& index)
{
ScopeLock lock(Locker);
if (index >= 0)
{
if (!Inited)
InitCommands();
while (index < Commands.Count())
{
auto& command = Commands.Get()[index];
if (command.Name.StartsWith(searchText, StringSearchCase::IgnoreCase))
{
return true;
}
index++;
}
}
return false;
}
String DebugCommands::GetCommandName(int32 index)
{
ScopeLock lock(Locker);
CHECK_RETURN(Commands.IsValidIndex(index), String::Empty);
return Commands.Get()[index].Name;
}

View File

@@ -0,0 +1,15 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System;
namespace FlaxEngine
{
/// <summary>
/// Marks static method as debug command that can be executed from the command line or via console.
/// </summary>
[Serializable]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class DebugCommand : Attribute
{
}
}

View File

@@ -0,0 +1,24 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Scripting/ScriptingType.h"
/// <summary>
/// Debug commands and console variables system.
/// </summary>
API_CLASS(static) class FLAXENGINE_API DebugCommands
{
DECLARE_SCRIPTING_TYPE_MINIMAL(DebugCommands);
public:
/// <summary>
/// Executees the command.
/// </summary>
/// <param name="command">The command line (optionally with arguments).</param>
API_FUNCTION() static void Execute(StringView command);
public:
static bool Iterate(const StringView& searchText, int32& index);
static String GetCommandName(int32 index);
};

View File

@@ -97,7 +97,7 @@ public:
/// Exits the engine.
/// </summary>
/// <param name="exitCode">The exit code.</param>
static void Exit(int32 exitCode = -1);
API_FUNCTION(Attributes="DebugCommand") static void Exit(int32 exitCode = -1);
/// <summary>
/// Requests normal engine exit.

View File

@@ -775,7 +775,7 @@ void Foliage::OnFoliageTypeModelLoaded(int32 index)
}
BoundingSphere::FromBox(_box, _sphere);
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Bounds);
}
{
PROFILE_CPU_NAMED("Create Clusters");
@@ -912,7 +912,7 @@ void Foliage::RebuildClusters()
_box = totalBounds;
BoundingSphere::FromBox(_box, _sphere);
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Bounds);
}
// Insert all instances to the clusters
@@ -986,6 +986,12 @@ void Foliage::UpdateCullDistance()
#endif
}
void Foliage::RemoveAllInstances()
{
Instances.Clear();
RebuildClusters();
}
static float GlobalDensityScale = 1.0f;
float Foliage::GetGlobalDensityScale()
@@ -1441,7 +1447,7 @@ void Foliage::Deserialize(DeserializeStream& stream, ISerializeModifier* modifie
void Foliage::OnLayerChanged()
{
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Layer);
}
void Foliage::OnEnable()

View File

@@ -134,6 +134,11 @@ public:
/// </summary>
API_FUNCTION() void UpdateCullDistance();
/// <summary>
/// Clears all foliage instances. Preserves the foliage types and other properties.
/// </summary>
API_FUNCTION() void RemoveAllInstances();
public:
/// <summary>
/// Gets the global density scale for all foliage instances. The default value is 1. Use values from range 0-1. Lower values decrease amount of foliage instances in-game. Use it to tweak game performance for slower devices.

View File

@@ -9,7 +9,7 @@
/// <summary>
/// Graphics device manager that creates, manages and releases graphics device and related objects.
/// </summary>
API_CLASS(Static) class FLAXENGINE_API Graphics
API_CLASS(Static, Attributes="DebugCommand") class FLAXENGINE_API Graphics
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Graphics);
public:

View File

@@ -87,6 +87,7 @@ void IMaterial::BindParameters::BindViewData()
void IMaterial::BindParameters::BindDrawData()
{
// Write draw call to the object buffer
ASSERT(DrawCall);
auto& objectBuffer = RenderContext.List->TempObjectBuffer;
objectBuffer.Clear();
ShaderObjectData objData;

View File

@@ -758,7 +758,7 @@ void AnimatedModel::UpdateBounds()
}
BoundingSphere::FromBox(_box, _sphere);
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Bounds);
}
void AnimatedModel::UpdateSockets()

View File

@@ -64,7 +64,7 @@ BoundingBox Decal::GetEditorBox() const
void Decal::OnLayerChanged()
{
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Layer);
}
void Decal::Draw(RenderContext& renderContext)

View File

@@ -166,7 +166,7 @@ void EnvironmentProbe::UpdateBounds()
_sphere = BoundingSphere(GetPosition(), GetScaledRadius());
BoundingBox::FromSphere(_sphere, _box);
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Bounds);
}
void EnvironmentProbe::Draw(RenderContext& renderContext)
@@ -220,7 +220,7 @@ void EnvironmentProbe::OnDebugDrawSelected()
void EnvironmentProbe::OnLayerChanged()
{
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Layer);
}
void EnvironmentProbe::Serialize(SerializeStream& stream, const void* otherObj)

View File

@@ -20,7 +20,7 @@ void ModelInstanceActor::SetEntries(const Array<ModelInstanceEntry>& value)
Entries[i] = value[i];
}
if (anyChanged && _sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Visual);
}
void ModelInstanceActor::SetMaterial(int32 entryIndex, MaterialBase* material)
@@ -33,7 +33,7 @@ void ModelInstanceActor::SetMaterial(int32 entryIndex, MaterialBase* material)
return;
Entries[entryIndex].Material = material;
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Visual);
}
MaterialInstance* ModelInstanceActor::CreateAndSetVirtualMaterialInstance(int32 entryIndex)
@@ -44,7 +44,7 @@ MaterialInstance* ModelInstanceActor::CreateAndSetVirtualMaterialInstance(int32
MaterialInstance* result = material->CreateVirtualInstance();
Entries[entryIndex].Material = result;
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Visual);
return result;
}
@@ -55,7 +55,13 @@ void ModelInstanceActor::WaitForModelLoad()
void ModelInstanceActor::OnLayerChanged()
{
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Layer);
}
void ModelInstanceActor::OnStaticFlagsChanged()
{
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::StaticFlags);
}
void ModelInstanceActor::OnTransformChanged()

View File

@@ -142,6 +142,7 @@ protected:
public:
// [Actor]
void OnLayerChanged() override;
void OnStaticFlagsChanged() override;
void OnTransformChanged() override;
protected:

View File

@@ -67,7 +67,7 @@ void PointLight::UpdateBounds()
BoundingBox::FromSphere(_sphere, _box);
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Bounds);
}
void PointLight::OnTransformChanged()
@@ -163,7 +163,7 @@ void PointLight::DrawLightsDebug(RenderView& view)
void PointLight::OnLayerChanged()
{
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Layer);
}
void PointLight::Serialize(SerializeStream& stream, const void* otherObj)

View File

@@ -101,7 +101,7 @@ void SkyLight::UpdateBounds()
_sphere = BoundingSphere(GetPosition(), GetScaledRadius());
BoundingBox::FromSphere(_sphere, _box);
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Bounds);
}
void SkyLight::Draw(RenderContext& renderContext)

View File

@@ -115,7 +115,7 @@ void SpotLight::UpdateBounds()
BoundingBox::FromSphere(_sphere, _box);
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Bounds);
}
void SpotLight::OnTransformChanged()

View File

@@ -283,7 +283,7 @@ void StaticModel::UpdateBounds()
}
BoundingSphere::FromBox(_box, _sphere);
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Bounds);
}
void StaticModel::FlushVertexColors()

View File

@@ -162,7 +162,7 @@ void SceneRendering::AddActor(Actor* a, int32& key)
listener->OnSceneRenderingAddActor(a);
}
void SceneRendering::UpdateActor(Actor* a, int32& key)
void SceneRendering::UpdateActor(Actor* a, int32& key, ISceneRenderingListener::UpdateFlags flags)
{
const int32 category = a->_drawCategory;
ScopeLock lock(Locker);
@@ -173,9 +173,11 @@ void SceneRendering::UpdateActor(Actor* a, int32& key)
if (e.Actor == a)
{
for (auto* listener : _listeners)
listener->OnSceneRenderingUpdateActor(a, e.Bounds);
e.LayerMask = a->GetLayerMask();
e.Bounds = a->GetSphere();
listener->OnSceneRenderingUpdateActor(a, e.Bounds, flags);
if (flags & ISceneRenderingListener::Layer)
e.LayerMask = a->GetLayerMask();
if (flags & ISceneRenderingListener::Bounds)
e.Bounds = a->GetSphere();
}
}

View File

@@ -48,12 +48,22 @@ private:
public:
~ISceneRenderingListener();
// Actor properties that were modified.
enum UpdateFlags
{
Visual = 1,
Bounds = 2,
Layer = 4,
StaticFlags = 8,
Auto = Visual | Bounds | Layer,
};
// Starts listening to the scene rendering events.
void ListenSceneRendering(SceneRendering* scene);
// Events called by Scene Rendering
virtual void OnSceneRenderingAddActor(Actor* a) = 0;
virtual void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds) = 0;
virtual void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags = Auto) = 0;
virtual void OnSceneRenderingRemoveActor(Actor* a) = 0;
virtual void OnSceneRenderingClear(SceneRendering* scene) = 0;
};
@@ -125,7 +135,7 @@ public:
public:
void AddActor(Actor* a, int32& key);
void UpdateActor(Actor* a, int32& key);
void UpdateActor(Actor* a, int32& key, ISceneRenderingListener::UpdateFlags flags = ISceneRenderingListener::Auto);
void RemoveActor(Actor* a, int32& key);
FORCE_INLINE void AddPostFxProvider(IPostFxSettingsProvider* obj)

View File

@@ -132,9 +132,10 @@ void NetworkLagDriver::SendMessage(const NetworkChannelType channelType, const N
auto& msg = _messages.AddOne();
msg.Lag = (double)Lag;
msg.ChannelType = channelType;
msg.Type = 0;
msg.Message = message;
msg.MessageData.Set(message.Buffer, message.Length);
msg.MessageLength = message.Length;
}
void NetworkLagDriver::SendMessage(NetworkChannelType channelType, const NetworkMessage& message, NetworkConnection target)
@@ -147,10 +148,11 @@ void NetworkLagDriver::SendMessage(NetworkChannelType channelType, const Network
auto& msg = _messages.AddOne();
msg.Lag = (double)Lag;
msg.ChannelType = channelType;
msg.Type = 1;
msg.Message = message;
msg.Target = target;
msg.MessageData.Set(message.Buffer, message.Length);
msg.MessageLength = message.Length;
}
void NetworkLagDriver::SendMessage(const NetworkChannelType channelType, const NetworkMessage& message, const Array<NetworkConnection, HeapAllocation>& targets)
@@ -163,10 +165,11 @@ void NetworkLagDriver::SendMessage(const NetworkChannelType channelType, const N
auto& msg = _messages.AddOne();
msg.Lag = (double)Lag;
msg.ChannelType = channelType;
msg.Type = 2;
msg.Message = message;
msg.Targets = targets;
msg.MessageData.Set(message.Buffer, message.Length);
msg.MessageLength = message.Length;
}
NetworkDriverStats NetworkLagDriver::GetStats()
@@ -197,19 +200,21 @@ void NetworkLagDriver::OnUpdate()
if (msg.Lag > 0.0)
continue;
// Fix message to point to the current buffer
msg.Message.Buffer = msg.MessageData.Get();
// Use this helper message as a container to send the stored data and length to the ENet driver
NetworkMessage message;
message.Buffer = msg.MessageData.Get();
message.Length = msg.MessageLength;
switch (msg.Type)
{
case 0:
_driver->SendMessage(msg.ChannelType, msg.Message);
_driver->SendMessage(msg.ChannelType, message);
break;
case 1:
_driver->SendMessage(msg.ChannelType, msg.Message, msg.Target);
_driver->SendMessage(msg.ChannelType, message, msg.Target);
break;
case 2:
_driver->SendMessage(msg.ChannelType, msg.Message, msg.Targets);
_driver->SendMessage(msg.ChannelType, message, msg.Targets);
break;
}
_messages.RemoveAt(i);

View File

@@ -22,10 +22,10 @@ private:
double Lag;
int32 Type;
NetworkChannelType ChannelType;
NetworkMessage Message;
NetworkConnection Target;
Array<NetworkConnection> Targets;
Array<byte> MessageData; // TODO: use message buffers cache (of size config.MessageSize) to reduce dynamic memory allocations
uint32 MessageLength;
};
struct LagEvent

View File

@@ -74,6 +74,17 @@ bool NetworkReplicationNode::GetObject(ScriptingObject* obj, NetworkReplicationH
return false;
}
bool NetworkReplicationNode::SetObject(const NetworkReplicationHierarchyObject& value)
{
const int32 index = Objects.Find(value.Object.Get());
if (index != -1)
{
Objects[index] = value;
return true;
}
return false;
}
bool NetworkReplicationNode::DirtyObject(ScriptingObject* obj)
{
const int32 index = Objects.Find(obj);
@@ -212,11 +223,17 @@ bool NetworkReplicationGridNode::GetObject(ScriptingObject* obj, NetworkReplicat
{
return false;
}
if (_children[coord].Node->GetObject(obj, result))
return _children[coord].Node->GetObject(obj, result);
}
bool NetworkReplicationGridNode::SetObject(const NetworkReplicationHierarchyObject& value)
{
Int3 coord;
if (!_objectToCell.TryGet(value.Object.Get(), coord))
{
return true;
return false;
}
return false;
return _children[coord].Node->SetObject(value);
}
bool NetworkReplicationGridNode::DirtyObject(ScriptingObject* obj)

View File

@@ -206,7 +206,14 @@ API_CLASS(Abstract, Namespace = "FlaxEngine.Networking") class FLAXENGINE_API Ne
/// <param name="obj">The object to get.</param>
/// <param name="result">The hierarchy object to retrieve.</param>
/// <returns>True on successful retrieval, otherwise false.</returns>
API_FUNCTION() virtual bool GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result);
API_FUNCTION() virtual bool GetObject(ScriptingObject* obj, API_PARAM(Out) NetworkReplicationHierarchyObject& result);
/// <summary>
/// Sets object properties in the hierarchy. Can be used to modify replication settings at runtime.
/// </summary>
/// <param name="value">The object data to update.</param>
/// <returns>True on successful update, otherwise false (eg, if specific object has not been added to this node).</returns>
API_FUNCTION() virtual bool SetObject(const NetworkReplicationHierarchyObject& value);
/// <summary>
/// Force replicates the object during the next update. Resets any internal tracking state to force the synchronization.
@@ -257,6 +264,7 @@ public:
void AddObject(NetworkReplicationHierarchyObject obj) override;
bool RemoveObject(ScriptingObject* obj) override;
bool GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result) override;
bool SetObject(const NetworkReplicationHierarchyObject& value) override;
bool DirtyObject(ScriptingObject* obj) override;
void Update(NetworkReplicationHierarchyUpdateResult* result) override;
};

View File

@@ -16,6 +16,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupParameters(Box* box, Node* nod
switch (node->TypeID)
{
// Get
case 1:
case 2:
{
int32 paramIndex;

View File

@@ -589,7 +589,7 @@ void ParticleEffect::OnDebugDrawSelected()
void ParticleEffect::OnLayerChanged()
{
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Layer);
}
void ParticleEffect::Serialize(SerializeStream& stream, const void* otherObj)

View File

@@ -80,7 +80,7 @@ namespace
// Determinate a full path of an entry
char full_path[256];
ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(full_path));
strcpy(full_path, path);
strcpy(full_path, pathStr);
strcat(full_path, "/");
strcat(full_path, entry->d_name);

View File

@@ -227,7 +227,7 @@ bool DeleteUnixPathTree(const char* path)
// Determinate a full path of an entry
char full_path[256];
ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(full_path));
strcpy(full_path, path);
strcpy(full_path, pathStr);
strcat(full_path, "/");
strcat(full_path, entry->d_name);

View File

@@ -499,7 +499,7 @@ public:
{
}
void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds) override
void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override
{
// Dirty static objects to redraw when changed (eg. material modification)
if (a->HasStaticFlag(StaticFlags::Lightmap))

View File

@@ -399,7 +399,7 @@ public:
}
}
void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds) override
void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override
{
if (GLOBAL_SDF_ACTOR_IS_STATIC(a) && ObjectTypes.Contains(a->GetTypeHandle()))
{

View File

@@ -392,7 +392,7 @@ public:
DirtyStaticBounds(a->GetSphere());
}
void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds) override
void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override
{
// Dirty static objects to redraw when changed (eg. material modification)
if (a->HasStaticFlag(StaticFlags::Shadow))
@@ -400,6 +400,10 @@ public:
DirtyStaticBounds(prevBounds);
DirtyStaticBounds(a->GetSphere());
}
else if (flags & StaticFlags)
{
DirtyStaticBounds(a->GetSphere());
}
}
void OnSceneRenderingRemoveActor(Actor* a) override

View File

@@ -60,9 +60,10 @@ bool VolumetricFogPass::setupResources()
REPORT_INVALID_SHADER_PASS_CB_SIZE(shader, 0, Data);
return true;
}
if (shader->GetCB(1)->GetSize() != sizeof(PerLight))
// CB1 is used for per-draw info (ObjectIndex)
if (shader->GetCB(2)->GetSize() != sizeof(PerLight))
{
REPORT_INVALID_SHADER_PASS_CB_SIZE(shader, 1, PerLight);
REPORT_INVALID_SHADER_PASS_CB_SIZE(shader, 2, PerLight);
return true;
}
@@ -254,7 +255,7 @@ GPUTextureView* VolumetricFogPass::GetLocalShadowedLightScattering(RenderContext
}
template<typename T>
void VolumetricFogPass::RenderRadialLight(RenderContext& renderContext, GPUContext* context, RenderView& view, VolumetricFogOptions& options, T& light, PerLight& perLight, GPUConstantBuffer* cb1)
void VolumetricFogPass::RenderRadialLight(RenderContext& renderContext, GPUContext* context, RenderView& view, VolumetricFogOptions& options, T& light, PerLight& perLight, GPUConstantBuffer* cb2)
{
const Float3 center = light.Position;
const float radius = light.Radius;
@@ -281,8 +282,8 @@ void VolumetricFogPass::RenderRadialLight(RenderContext& renderContext, GPUConte
light.SetShaderData(perLight.LocalLight, withShadow);
// Upload data
context->UpdateCB(cb1, &perLight);
context->BindCB(1, cb1);
context->UpdateCB(cb2, &perLight);
context->BindCB(2, cb2);
// Ensure to have valid buffers created
if (_vbCircleRasterize == nullptr || _ibCircleRasterize == nullptr)
@@ -414,6 +415,8 @@ void VolumetricFogPass::Render(RenderContext& renderContext)
customData.VolumetricFogMaxDistance = cache.Data.VolumetricFogMaxDistance;
bindParams.CustomData = &customData;
bindParams.BindViewData();
bindParams.DrawCall = &renderContext.List->VolumetricFogParticles.First();
bindParams.BindDrawData();
for (auto& drawCall : renderContext.List->VolumetricFogParticles)
{
@@ -439,7 +442,7 @@ void VolumetricFogPass::Render(RenderContext& renderContext)
// Setup volumetric shader data
PerLight perLight;
auto cb1 = _shader->GetShader()->GetCB(1);
auto cb2 = _shader->GetShader()->GetCB(2);
perLight.SliceToDepth.X = cache.Data.GridSize.Z;
perLight.SliceToDepth.Y = cache.Data.VolumetricFogMaxDistance;
perLight.MinZ = volumeZBoundsMin;
@@ -447,8 +450,8 @@ void VolumetricFogPass::Render(RenderContext& renderContext)
Matrix::Transpose(renderContext.View.Projection, perLight.ViewToVolumeClip);
// Upload data
context->UpdateCB(cb1, &perLight);
context->BindCB(1, cb1);
context->UpdateCB(cb2, &perLight);
context->BindCB(2, cb2);
// Call rendering to the volume
const int32 instanceCount = volumeZBoundsMax - volumeZBoundsMin;
@@ -495,7 +498,7 @@ void VolumetricFogPass::Render(RenderContext& renderContext)
PerLight perLight;
perLight.SliceToDepth.X = cache.Data.GridSize.Z;
perLight.SliceToDepth.Y = cache.Data.VolumetricFogMaxDistance;
auto cb1 = _shader->GetShader()->GetCB(1);
auto cb2 = _shader->GetShader()->GetCB(2);
// Bind the output
context->SetRenderTarget(localShadowedLightScattering);
@@ -505,12 +508,12 @@ void VolumetricFogPass::Render(RenderContext& renderContext)
context->BindSR(0, shadowMap);
context->BindSR(1, shadowsBuffer);
for (int32 i = 0; i < pointLights.Count(); i++)
RenderRadialLight(renderContext, context, view, options, renderContext.List->PointLights[pointLights[i]], perLight, cb1);
RenderRadialLight(renderContext, context, view, options, renderContext.List->PointLights[pointLights[i]], perLight, cb2);
for (int32 i = 0; i < spotLights.Count(); i++)
RenderRadialLight(renderContext, context, view, options, renderContext.List->SpotLights[spotLights[i]], perLight, cb1);
RenderRadialLight(renderContext, context, view, options, renderContext.List->SpotLights[spotLights[i]], perLight, cb2);
// Cleanup
context->UnBindCB(1);
context->UnBindCB(2);
context->ResetRenderTarget();
context->FlushState();
}

View File

@@ -157,7 +157,7 @@ private:
GPUTextureView* GetLocalShadowedLightScattering(RenderContext& renderContext, GPUContext* context, VolumetricFogOptions& options) const;
void InitCircleBuffer();
template<typename T>
void RenderRadialLight(RenderContext& renderContext, GPUContext* context, RenderView& view, VolumetricFogOptions& options, T& light, PerLight& perLight, GPUConstantBuffer* cb1);
void RenderRadialLight(RenderContext& renderContext, GPUContext* context, RenderView& view, VolumetricFogOptions& options, T& light, PerLight& perLight, GPUConstantBuffer* cb2);
#if COMPILE_WITH_DEV_ENV
void OnShaderReloading(Asset* obj)
{

View File

@@ -305,9 +305,9 @@ public:
/// <summary>
/// Checks if class has an attribute of the specified type.
/// </summary>
/// <param name="monoClass">The attribute class to check.</param>
/// <param name="klass">The attribute class to check.</param>
/// <returns>True if has attribute of that class type, otherwise false.</returns>
bool HasAttribute(const MClass* monoClass) const;
bool HasAttribute(const MClass* klass) const;
/// <summary>
/// Checks if class has an attribute of any type.
@@ -318,9 +318,9 @@ public:
/// <summary>
/// Returns an instance of an attribute of the specified type. Returns null if the class doesn't have such an attribute.
/// </summary>
/// <param name="monoClass">The attribute class to take.</param>
/// <param name="klass">The attribute class to take.</param>
/// <returns>The attribute object.</returns>
MObject* GetAttribute(const MClass* monoClass) const;
MObject* GetAttribute(const MClass* klass) const;
/// <summary>
/// Returns an instance of all attributes connected with given class. Returns null if the class doesn't have any attributes.

View File

@@ -99,9 +99,9 @@ public:
/// <summary>
/// Checks if event has an attribute of the specified type.
/// </summary>
/// <param name="monoClass">The attribute class to check.</param>
/// <param name="klass">The attribute class to check.</param>
/// <returns>True if has attribute of that class type, otherwise false.</returns>
bool HasAttribute(MClass* monoClass) const;
bool HasAttribute(const MClass* klass) const;
/// <summary>
/// Checks if event has an attribute of any type.
@@ -112,9 +112,9 @@ public:
/// <summary>
/// Returns an instance of an attribute of the specified type. Returns null if the event doesn't have such an attribute.
/// </summary>
/// <param name="monoClass">The attribute class to take.</param>
/// <param name="klass">The attribute class to take.</param>
/// <returns>The attribute object.</returns>
MObject* GetAttribute(MClass* monoClass) const;
MObject* GetAttribute(const MClass* klass) const;
/// <summary>
/// Returns an instance of all attributes connected with given event. Returns null if the event doesn't have any attributes.

View File

@@ -134,9 +134,9 @@ public:
/// <summary>
/// Checks if field has an attribute of the specified type.
/// </summary>
/// <param name="monoClass">The attribute class to check.</param>
/// <param name="klass">The attribute class to check.</param>
/// <returns>True if has attribute of that class type, otherwise false.</returns>
bool HasAttribute(MClass* monoClass) const;
bool HasAttribute(const MClass* klass) const;
/// <summary>
/// Checks if field has an attribute of any type.
@@ -147,9 +147,9 @@ public:
/// <summary>
/// Returns an instance of an attribute of the specified type. Returns null if the field doesn't have such an attribute.
/// </summary>
/// <param name="monoClass">The attribute class to take.</param>
/// <param name="klass">The attribute class to take.</param>
/// <returns>The attribute object.</returns>
MObject* GetAttribute(MClass* monoClass) const;
MObject* GetAttribute(const MClass* klass) const;
/// <summary>
/// Returns an instance of all attributes connected with given field. Returns null if the field doesn't have any attributes.

View File

@@ -175,9 +175,9 @@ public:
/// <summary>
/// Checks if method has an attribute of the specified type.
/// </summary>
/// <param name="monoClass">The attribute class to check.</param>
/// <param name="klass">The attribute class to check.</param>
/// <returns>True if has attribute of that class type, otherwise false.</returns>
bool HasAttribute(MClass* monoClass) const;
bool HasAttribute(const MClass* klass) const;
/// <summary>
/// Checks if method has an attribute of any type.
@@ -188,9 +188,9 @@ public:
/// <summary>
/// Returns an instance of an attribute of the specified type. Returns null if the method doesn't have such an attribute.
/// </summary>
/// <param name="monoClass">The attribute Class to take.</param>
/// <param name="klass">The attribute Class to take.</param>
/// <returns>The attribute object.</returns>
MObject* GetAttribute(MClass* monoClass) const;
MObject* GetAttribute(const MClass* klass) const;
/// <summary>
/// Returns an instance of all attributes connected with given method. Returns null if the method doesn't have any attributes.

View File

@@ -111,9 +111,9 @@ public:
/// <summary>
/// Checks if property has an attribute of the specified type.
/// </summary>
/// <param name="monoClass">The attribute class to check.</param>
/// <param name="klass">The attribute class to check.</param>
/// <returns>True if has attribute of that class type, otherwise false.</returns>
bool HasAttribute(MClass* monoClass) const;
bool HasAttribute(const MClass* klass) const;
/// <summary>
/// Checks if property has an attribute of any type.
@@ -124,9 +124,9 @@ public:
/// <summary>
/// Returns an instance of an attribute of the specified type. Returns null if the property doesn't have such an attribute.
/// </summary>
/// <param name="monoClass">The attribute class to take.</param>
/// <param name="klass">The attribute class to take.</param>
/// <returns>The attribute object.</returns>
MObject* GetAttribute(MClass* monoClass) const;
MObject* GetAttribute(const MClass* klass) const;
/// <summary>
/// Returns an instance of all attributes connected with given property. Returns null if the property doesn't have any attributes.

View File

@@ -1119,9 +1119,9 @@ const Array<MClass*>& MClass::GetInterfaces() const
return _interfaces;
}
bool MClass::HasAttribute(const MClass* monoClass) const
bool MClass::HasAttribute(const MClass* klass) const
{
return GetCustomAttribute(this, monoClass) != nullptr;
return GetCustomAttribute(this, klass) != nullptr;
}
bool MClass::HasAttribute() const
@@ -1129,9 +1129,9 @@ bool MClass::HasAttribute() const
return !GetAttributes().IsEmpty();
}
MObject* MClass::GetAttribute(const MClass* monoClass) const
MObject* MClass::GetAttribute(const MClass* klass) const
{
return (MObject*)GetCustomAttribute(this, monoClass);
return (MObject*)GetCustomAttribute(this, klass);
}
const Array<MObject*>& MClass::GetAttributes() const
@@ -1185,7 +1185,7 @@ MMethod* MEvent::GetRemoveMethod() const
return nullptr; // TODO: implement MEvent in .NET
}
bool MEvent::HasAttribute(MClass* monoClass) const
bool MEvent::HasAttribute(const MClass* klass) const
{
return false; // TODO: implement MEvent in .NET
}
@@ -1195,7 +1195,7 @@ bool MEvent::HasAttribute() const
return false; // TODO: implement MEvent in .NET
}
MObject* MEvent::GetAttribute(MClass* monoClass) const
MObject* MEvent::GetAttribute(const MClass* klass) const
{
return nullptr; // TODO: implement MEvent in .NET
}
@@ -1307,7 +1307,7 @@ void MField::SetValue(MObject* instance, void* value) const
CallStaticMethod<void, void*, void*, void*>(FieldSetValuePtr, instance, _handle, value);
}
bool MField::HasAttribute(MClass* monoClass) const
bool MField::HasAttribute(const MClass* klass) const
{
// TODO: implement MField attributes in .NET
return false;
@@ -1319,7 +1319,7 @@ bool MField::HasAttribute() const
return false;
}
MObject* MField::GetAttribute(MClass* monoClass) const
MObject* MField::GetAttribute(const MClass* klass) const
{
// TODO: implement MField attributes in .NET
return nullptr;
@@ -1469,7 +1469,7 @@ bool MMethod::GetParameterIsOut(int32 paramIdx) const
return CallStaticMethod<bool, void*, int>(GetMethodParameterIsOutPtr, _handle, paramIdx);
}
bool MMethod::HasAttribute(MClass* monoClass) const
bool MMethod::HasAttribute(const MClass* klass) const
{
// TODO: implement MMethod attributes in .NET
return false;
@@ -1481,7 +1481,7 @@ bool MMethod::HasAttribute() const
return false;
}
MObject* MMethod::GetAttribute(MClass* monoClass) const
MObject* MMethod::GetAttribute(const MClass* klass) const
{
// TODO: implement MMethod attributes in .NET
return nullptr;
@@ -1546,7 +1546,7 @@ void MProperty::SetValue(MObject* instance, void* value, MObject** exception) co
_setMethod->Invoke(instance, params, exception);
}
bool MProperty::HasAttribute(MClass* monoClass) const
bool MProperty::HasAttribute(const MClass* klass) const
{
// TODO: implement MProperty attributes in .NET
return false;
@@ -1558,7 +1558,7 @@ bool MProperty::HasAttribute() const
return false;
}
MObject* MProperty::GetAttribute(MClass* monoClass) const
MObject* MProperty::GetAttribute(const MClass* klass) const
{
// TODO: implement MProperty attributes in .NET
return nullptr;

View File

@@ -1517,10 +1517,10 @@ const Array<MClass*>& MClass::GetInterfaces() const
return _interfaces;
}
bool MClass::HasAttribute(const MClass* monoClass) const
bool MClass::HasAttribute(const MClass* klass) const
{
MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR();
return attrInfo != nullptr && mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
return attrInfo != nullptr && mono_custom_attrs_has_attr(attrInfo, klass->GetNative()) != 0;
}
bool MClass::HasAttribute() const
@@ -1529,10 +1529,10 @@ bool MClass::HasAttribute() const
return attrInfo && attrInfo->num_attrs > 0;
}
MObject* MClass::GetAttribute(const MClass* monoClass) const
MObject* MClass::GetAttribute(const MClass* klass) const
{
MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR();
return attrInfo ? mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative()) : nullptr;
return attrInfo ? mono_custom_attrs_get_attr(attrInfo, klass->GetNative()) : nullptr;
}
const Array<MObject*>& MClass::GetAttributes() const
@@ -1618,14 +1618,14 @@ MMethod* MEvent::GetRemoveMethod() const
return _removeMethod;
}
bool MEvent::HasAttribute(MClass* monoClass) const
bool MEvent::HasAttribute(const MClass* klass) const
{
MonoClass* parentClass = mono_event_get_parent(_monoEvent);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent);
if (attrInfo == nullptr)
return false;
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, klass->GetNative()) != 0;
mono_custom_attrs_free(attrInfo);
return hasAttr;
}
@@ -1646,14 +1646,14 @@ bool MEvent::HasAttribute() const
return false;
}
MObject* MEvent::GetAttribute(MClass* monoClass) const
MObject* MEvent::GetAttribute(const MClass* klass) const
{
MonoClass* parentClass = mono_event_get_parent(_monoEvent);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent);
if (attrInfo == nullptr)
return nullptr;
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, klass->GetNative());
mono_custom_attrs_free(attrInfo);
return foundAttr;
}
@@ -1771,14 +1771,14 @@ void MField::SetValue(MObject* instance, void* value) const
mono_field_set_value(instance, _monoField, value);
}
bool MField::HasAttribute(MClass* monoClass) const
bool MField::HasAttribute(const MClass* klass) const
{
MonoClass* parentClass = mono_field_get_parent(_monoField);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField);
if (attrInfo == nullptr)
return false;
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, klass->GetNative()) != 0;
mono_custom_attrs_free(attrInfo);
return hasAttr;
}
@@ -1799,14 +1799,14 @@ bool MField::HasAttribute() const
return false;
}
MObject* MField::GetAttribute(MClass* monoClass) const
MObject* MField::GetAttribute(const MClass* klass) const
{
MonoClass* parentClass = mono_field_get_parent(_monoField);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField);
if (attrInfo == nullptr)
return nullptr;
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, klass->GetNative());
mono_custom_attrs_free(attrInfo);
return foundAttr;
}
@@ -1947,13 +1947,13 @@ bool MMethod::GetParameterIsOut(int32 paramIdx) const
return mono_signature_param_is_out(sig, paramIdx) != 0;
}
bool MMethod::HasAttribute(MClass* monoClass) const
bool MMethod::HasAttribute(const MClass* klass) const
{
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod);
if (attrInfo == nullptr)
return false;
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, klass->GetNative()) != 0;
mono_custom_attrs_free(attrInfo);
return hasAttr;
}
@@ -1973,13 +1973,13 @@ bool MMethod::HasAttribute() const
return false;
}
MObject* MMethod::GetAttribute(MClass* monoClass) const
MObject* MMethod::GetAttribute(const MClass* klass) const
{
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod);
if (attrInfo == nullptr)
return nullptr;
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, klass->GetNative());
mono_custom_attrs_free(attrInfo);
return foundAttr;
}
@@ -2074,14 +2074,14 @@ void MProperty::SetValue(MObject* instance, void* value, MObject** exception) co
mono_property_set_value(_monoProperty, instance, params, exception);
}
bool MProperty::HasAttribute(MClass* monoClass) const
bool MProperty::HasAttribute(const MClass* klass) const
{
MonoClass* parentClass = mono_property_get_parent(_monoProperty);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty);
if (attrInfo == nullptr)
return false;
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, klass->GetNative()) != 0;
mono_custom_attrs_free(attrInfo);
return hasAttr;
}
@@ -2102,14 +2102,14 @@ bool MProperty::HasAttribute() const
return false;
}
MObject* MProperty::GetAttribute(MClass* monoClass) const
MObject* MProperty::GetAttribute(const MClass* klass) const
{
MonoClass* parentClass = mono_property_get_parent(_monoProperty);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty);
if (attrInfo == nullptr)
return nullptr;
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, klass->GetNative());
mono_custom_attrs_free(attrInfo);
return foundAttr;
}

View File

@@ -388,7 +388,7 @@ const Array<MProperty*>& MClass::GetProperties() const
return _properties;
}
bool MClass::HasAttribute(const MClass* monoClass) const
bool MClass::HasAttribute(const MClass* klass) const
{
return false;
}
@@ -398,7 +398,7 @@ bool MClass::HasAttribute() const
return false;
}
MObject* MClass::GetAttribute(const MClass* monoClass) const
MObject* MClass::GetAttribute(const MClass* klass) const
{
return nullptr;
}
@@ -430,7 +430,7 @@ MMethod* MEvent::GetRemoveMethod() const
return _removeMethod;
}
bool MEvent::HasAttribute(MClass* monoClass) const
bool MEvent::HasAttribute(const MClass* klass) const
{
return false;
}
@@ -440,7 +440,7 @@ bool MEvent::HasAttribute() const
return false;
}
MObject* MEvent::GetAttribute(MClass* monoClass) const
MObject* MEvent::GetAttribute(const MClass* klass) const
{
return nullptr;
}
@@ -482,7 +482,7 @@ void MField::SetValue(MObject* instance, void* value) const
{
}
bool MField::HasAttribute(MClass* monoClass) const
bool MField::HasAttribute(const MClass* klass) const
{
return false;
}
@@ -492,7 +492,7 @@ bool MField::HasAttribute() const
return false;
}
MObject* MField::GetAttribute(MClass* monoClass) const
MObject* MField::GetAttribute(const MClass* klass) const
{
return nullptr;
}
@@ -537,7 +537,7 @@ bool MMethod::GetParameterIsOut(int32 paramIdx) const
return false;
}
bool MMethod::HasAttribute(MClass* monoClass) const
bool MMethod::HasAttribute(const MClass* klass) const
{
return false;
}
@@ -547,7 +547,7 @@ bool MMethod::HasAttribute() const
return false;
}
MObject* MMethod::GetAttribute(MClass* monoClass) const
MObject* MMethod::GetAttribute(const MClass* klass) const
{
return nullptr;
}
@@ -584,7 +584,7 @@ void MProperty::SetValue(MObject* instance, void* value, MObject** exception) co
{
}
bool MProperty::HasAttribute(MClass* monoClass) const
bool MProperty::HasAttribute(const MClass* klass) const
{
return false;
}
@@ -594,7 +594,7 @@ bool MProperty::HasAttribute() const
return false;
}
MObject* MProperty::GetAttribute(MClass* monoClass) const
MObject* MProperty::GetAttribute(const MClass* klass) const
{
return nullptr;
}

View File

@@ -277,10 +277,10 @@ void ScriptingObject::ChangeID(const Guid& newId)
// Update managed instance
const auto managedInstance = GetManagedInstance();
const auto monoClass = GetClass();
if (managedInstance && monoClass)
const auto klass = GetClass();
if (managedInstance && klass)
{
const MField* monoIdField = monoClass->GetField(ScriptingObject_id);
const MField* monoIdField = klass->GetField(ScriptingObject_id);
if (monoIdField)
monoIdField->SetValue(managedInstance, &_id);
}
@@ -344,10 +344,10 @@ bool ScriptingObject::CreateManaged()
#endif
{
// Other thread already created the object before
if (const auto monoClass = GetClass())
if (const auto klass = GetClass())
{
// Reset managed to unmanaged pointer
MCore::ScriptingObject::SetInternalValues(monoClass, managedInstance, nullptr, nullptr);
MCore::ScriptingObject::SetInternalValues(klass, managedInstance, nullptr, nullptr);
}
MCore::GCHandle::Free(handle);
return true;
@@ -366,17 +366,17 @@ bool ScriptingObject::CreateManaged()
MObject* ScriptingObject::CreateManagedInternal()
{
// Get class
MClass* monoClass = GetClass();
if (monoClass == nullptr)
MClass* klass = GetClass();
if (klass == nullptr)
{
LOG(Warning, "Missing managed class for object with id {0}", GetID());
return nullptr;
}
MObject* managedInstance = MCore::ScriptingObject::CreateScriptingObject(monoClass, this, &_id);
MObject* managedInstance = MCore::ScriptingObject::CreateScriptingObject(klass, this, &_id);
if (managedInstance == nullptr)
{
LOG(Warning, "Failed to create new instance of the object of type {0}", String(monoClass->GetFullName()));
LOG(Warning, "Failed to create new instance of the object of type {0}", String(klass->GetFullName()));
}
return managedInstance;
@@ -393,9 +393,9 @@ void ScriptingObject::DestroyManaged()
// Reset managed to unmanaged pointer
if (managedInstance)
{
if (const auto monoClass = GetClass())
if (const auto klass = GetClass())
{
MCore::ScriptingObject::SetInternalValues(monoClass, managedInstance, nullptr, nullptr);
MCore::ScriptingObject::SetInternalValues(klass, managedInstance, nullptr, nullptr);
}
}
@@ -522,10 +522,10 @@ bool ManagedScriptingObject::CreateManaged()
#endif
{
// Other thread already created the object before
if (const auto monoClass = GetClass())
if (const auto klass = GetClass())
{
// Reset managed to unmanaged pointer
MCore::ScriptingObject::SetInternalValues(monoClass, managedInstance, nullptr, nullptr);
MCore::ScriptingObject::SetInternalValues(klass, managedInstance, nullptr, nullptr);
}
MCore::GCHandle::Free(handle);
return true;
@@ -684,9 +684,9 @@ DEFINE_INTERNAL_CALL(void) ObjectInternal_ManagedInstanceCreated(MObject* manage
actor->SetName(String(typeClass->GetName()));
}
MClass* monoClass = obj->GetClass();
MClass* klass = obj->GetClass();
const Guid id = obj->GetID();
MCore::ScriptingObject::SetInternalValues(monoClass, managedInstance, obj, &id);
MCore::ScriptingObject::SetInternalValues(klass, managedInstance, obj, &id);
// Register object
if (!obj->IsRegistered())

View File

@@ -52,7 +52,7 @@ void Terrain::UpdateBounds()
}
BoundingSphere::FromBox(_box, _sphere);
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Bounds);
}
void Terrain::CacheNeighbors()
@@ -905,7 +905,7 @@ void Terrain::OnLayerChanged()
UpdateLayerBits();
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Layer);
}
void Terrain::OnActiveInTreeChanged()

View File

@@ -233,7 +233,8 @@ namespace FlaxEngine.GUI
if (IsMouseOver || IsNavFocused)
backColor = BackgroundSelectedColor;
Render2D.FillRectangle(rect, backColor);
Render2D.DrawRectangle(rect, IsFocused ? BorderSelectedColor : BorderColor);
if (HasBorder)
Render2D.DrawRectangle(rect, IsFocused ? BorderSelectedColor : BorderColor, BorderThickness);
// Apply view offset and clip mask
if (ClipText)

View File

@@ -186,7 +186,7 @@ void SpriteRender::Deserialize(DeserializeStream& stream, ISerializeModifier* mo
void SpriteRender::OnLayerChanged()
{
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Layer);
}
void SpriteRender::OnEndPlay()

View File

@@ -415,7 +415,7 @@ void TextRender::OnDebugDrawSelected()
void TextRender::OnLayerChanged()
{
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Layer);
}
bool TextRender::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal)

View File

@@ -152,6 +152,18 @@ int32 VideoPlayer::GetFramesCount() const
return _player.FramesCount;
}
#if USE_EDITOR
#include "Engine/Debug/DebugDraw.h"
void VideoPlayer::OnDebugDrawSelected()
{
// Draw influence range
if (_isSpatial)
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(_transform.Translation, _minDistance), Color::CornflowerBlue, 0, true);
Actor::OnDebugDrawSelected();
}
#endif
bool VideoPlayer::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal)
{
return false;

View File

@@ -221,6 +221,8 @@ public:
const Vector3 size(50);
return BoundingBox(_transform.Translation - size, _transform.Translation + size);
}
void OnDebugDrawSelected() override;
#endif
bool IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) override;

View File

@@ -60,7 +60,7 @@ SkyLightData SkyLight;
DDGIData DDGI;
META_CB_END
META_CB_BEGIN(1, PerLight)
META_CB_BEGIN(2, PerLight)
float2 SliceToDepth;
int MinZ;
float LocalLightScatteringIntensity;

View File

@@ -50,6 +50,9 @@ namespace Flax.Build
var platform = Platform.BuildPlatform;
var architecture = TargetArchitecture.AnyCPU;
var architectureName = "AnyCPU";
if (!platform.CanBuildArchitecture(architecture))
continue;
var toolchain = platform.TryGetToolchain(architecture);
var configuration = TargetConfiguration.Debug;

View File

@@ -433,7 +433,12 @@ namespace Flax.Build.Platforms
{
case WindowsPlatformToolset.v140:
{
if (hostArchitecture != TargetArchitecture.x86)
if (architecture == TargetArchitecture.ARM64)
{
Log.Verbose(string.Format("Unsupported {0} architecture for v140 toolset", hostArchitecture.ToString()));
return null;
}
else if (hostArchitecture == TargetArchitecture.x64)
{
string nativeCompilerPath = Path.Combine(vcToolChainDir, "bin", "amd64", "cl.exe");
if (File.Exists(nativeCompilerPath))
@@ -446,12 +451,17 @@ namespace Flax.Build.Platforms
Log.Verbose(string.Format("No {0} host compiler toolchain found in {1} or {2}", hostArchitecture.ToString(), nativeCompilerPath, crossCompilerPath));
return null;
}
else
else if (hostArchitecture == TargetArchitecture.x86)
{
string compilerPath = Path.Combine(vcToolChainDir, "bin", "cl.exe");
if (File.Exists(compilerPath))
return Path.GetDirectoryName(compilerPath);
Log.Verbose(string.Format("No {0} host compiler toolchain found in {1}", hostArchitecture.ToString()));
Log.Verbose(string.Format("No {0} host compiler toolchain found in {1}", hostArchitecture.ToString(), compilerPath));
return null;
}
else
{
Log.Verbose(string.Format("Unsupported {0} host compiler for v140 toolset", hostArchitecture.ToString()));
return null;
}
}