From 36ba1d995306006f965d9fea7e2f521b4d3d8ba6 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 2 Feb 2023 13:05:54 +0100 Subject: [PATCH] Add play/pause widget and keybind for particles preview in asset Editor --- .../Previews/ParticleSystemPreview.cs | 63 +++++++++++++++++-- Source/Engine/Particles/ParticleEffect.cpp | 4 +- Source/Engine/Particles/ParticleEffect.h | 3 +- 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs b/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs index e845ae62c..78c44f654 100644 --- a/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs +++ b/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs @@ -2,8 +2,10 @@ using FlaxEditor.GUI.ContextMenu; using FlaxEditor.Viewport.Cameras; +using FlaxEditor.Viewport.Widgets; using FlaxEngine; using FlaxEngine.GUI; +using System; using Object = FlaxEngine.Object; namespace FlaxEditor.Viewport.Previews @@ -14,10 +16,12 @@ namespace FlaxEditor.Viewport.Previews /// public class ParticleSystemPreview : AssetPreview { + private bool _playSimulation = false; private ParticleEffect _previewEffect; private ContextMenuButton _showBoundsButton; private ContextMenuButton _showOriginButton; private ContextMenuButton _showParticleCounterButton; + private ViewportWidgetButton _playPauseButton; private StaticModel _boundsModel; private StaticModel _originModel; private bool _showParticlesCounter; @@ -39,7 +43,25 @@ namespace FlaxEditor.Viewport.Previews /// /// Gets or sets a value indicating whether to play the particles simulation in editor. /// - public bool PlaySimulation { get; set; } = false; + public bool PlaySimulation + { + get => _playSimulation; + set + { + if (_playSimulation == value) + return; + _playSimulation = value; + PlaySimulationChanged?.Invoke(); + + if (_playPauseButton != null) + _playPauseButton.Icon = value ? Editor.Instance.Icons.Pause64 : Editor.Instance.Icons.Play64; + } + } + + /// + /// Occurs when particles simulation playback state gets changed. + /// + public event Action PlaySimulationChanged; /// /// Gets or sets a value indicating whether to show particle effect bounding box. @@ -161,11 +183,22 @@ namespace FlaxEditor.Viewport.Previews // Link actors for rendering Task.AddCustomActor(_previewEffect); - if (useWidgets) + if (!useWidgets) + return; + _showBoundsButton = ViewWidgetShowMenu.AddButton("Bounds", () => ShowBounds = !ShowBounds); + _showOriginButton = ViewWidgetShowMenu.AddButton("Origin", () => ShowOrigin = !ShowOrigin); + _showParticleCounterButton = ViewWidgetShowMenu.AddButton("Particles Counter", () => ShowParticlesCounter = !ShowParticlesCounter); + + // Play/Pause widget { - _showBoundsButton = ViewWidgetShowMenu.AddButton("Bounds", () => ShowBounds = !ShowBounds); - _showOriginButton = ViewWidgetShowMenu.AddButton("Origin", () => ShowOrigin = !ShowOrigin); - _showParticleCounterButton = ViewWidgetShowMenu.AddButton("Particles Counter", () => ShowParticlesCounter = !ShowParticlesCounter); + var playPauseWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); + _playPauseButton = new ViewportWidgetButton(null, Editor.Instance.Icons.Pause64) + { + TooltipText = "Simulation playback play (F5) or pause (F6)", + Parent = playPauseWidget, + }; + _playPauseButton.Clicked += button => PlaySimulation = !PlaySimulation; + playPauseWidget.Parent = this; } } @@ -200,7 +233,7 @@ namespace FlaxEditor.Viewport.Previews // Manually update simulation if (PlaySimulation) { - _previewEffect.UpdateSimulation(); + _previewEffect.UpdateSimulation(true); } // Keep bounds matching the model @@ -228,6 +261,23 @@ namespace FlaxEditor.Viewport.Previews } } + /// + public override bool OnKeyDown(KeyboardKeys key) + { + var inputOptions = Editor.Instance.Options.Options.Input; + if (inputOptions.Play.Process(this, key)) + { + PlaySimulation = true; + return true; + } + if (inputOptions.Pause.Process(this, key)) + { + PlaySimulation = false; + return true; + } + return base.OnKeyDown(key); + } + /// public override void OnDestroy() { @@ -239,6 +289,7 @@ namespace FlaxEditor.Viewport.Previews _showBoundsButton = null; _showOriginButton = null; _showParticleCounterButton = null; + _playPauseButton = null; base.OnDestroy(); } diff --git a/Source/Engine/Particles/ParticleEffect.cpp b/Source/Engine/Particles/ParticleEffect.cpp index 4b8cec37a..4b7923439 100644 --- a/Source/Engine/Particles/ParticleEffect.cpp +++ b/Source/Engine/Particles/ParticleEffect.cpp @@ -258,7 +258,7 @@ void ParticleEffect::ResetSimulation() Instance.ClearState(); } -void ParticleEffect::UpdateSimulation() +void ParticleEffect::UpdateSimulation(bool singleFrame) { // Skip if need to if (!IsActiveInHierarchy() @@ -270,6 +270,8 @@ void ParticleEffect::UpdateSimulation() // Request update _lastUpdateFrame = Engine::FrameCount; _lastMinDstSqr = MAX_Real; + if (singleFrame) + Instance.LastUpdateTime = (UseTimeScale ? Time::Update.Time : Time::Update.UnscaledTime).GetTotalSeconds(); Particles::UpdateEffect(this); } diff --git a/Source/Engine/Particles/ParticleEffect.h b/Source/Engine/Particles/ParticleEffect.h index 6ace026af..3487a35f4 100644 --- a/Source/Engine/Particles/ParticleEffect.h +++ b/Source/Engine/Particles/ParticleEffect.h @@ -334,7 +334,8 @@ public: /// /// Performs the full particles simulation update (postponed for the next particle manager update). /// - API_FUNCTION() void UpdateSimulation(); + /// True if update animation by a single frame only (time time since last engine update), otherwise will update simulation with delta time since last update. + API_FUNCTION() void UpdateSimulation(bool singleFrame = false); /// /// Updates the actor bounds.