@@ -231,7 +231,6 @@ namespace FlaxEditor.GUI.Timeline
|
||||
state = PlaybackStates.Disabled;
|
||||
|
||||
PlaybackState = state;
|
||||
CanPlayPauseStop = Editor.IsPlayMode;
|
||||
|
||||
if (_player && _player.Animation)
|
||||
{
|
||||
|
||||
@@ -221,7 +221,7 @@ namespace FlaxEditor.GUI.Timeline
|
||||
private Vector2 _rightMouseButtonMovePos;
|
||||
private float _zoom = 1.0f;
|
||||
private bool _isMovingPositionHandle;
|
||||
private bool _canPlayPauseStop = true;
|
||||
private bool _canPlayPause = true, _canStop = true;
|
||||
private List<IUndoAction> _batchedUndoActions;
|
||||
|
||||
/// <summary>
|
||||
@@ -290,7 +290,11 @@ namespace FlaxEditor.GUI.Timeline
|
||||
/// <summary>
|
||||
/// Gets the current animation time position (in seconds).
|
||||
/// </summary>
|
||||
public float CurrentTime => _currentFrame / _framesPerSecond;
|
||||
public float CurrentTime
|
||||
{
|
||||
get => _currentFrame / _framesPerSecond;
|
||||
set => CurrentFrame = (int)(value * _framesPerSecond);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when current playback animation frame gets changed.
|
||||
@@ -511,16 +515,31 @@ namespace FlaxEditor.GUI.Timeline
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether user can use Play/Pause/Stop buttons, otherwise those should be disabled.
|
||||
/// Gets or sets a value indicating whether user can use Play and Pause buttons, otherwise those should be disabled.
|
||||
/// </summary>
|
||||
public bool CanPlayPauseStop
|
||||
public bool CanPlayPause
|
||||
{
|
||||
get => _canPlayPauseStop;
|
||||
get => _canPlayPause;
|
||||
set
|
||||
{
|
||||
if (_canPlayPauseStop == value)
|
||||
if (_canPlayPause == value)
|
||||
return;
|
||||
_canPlayPauseStop = value;
|
||||
_canPlayPause = value;
|
||||
UpdatePlaybackButtons();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether user can use Stop button, otherwise those should be disabled.
|
||||
/// </summary>
|
||||
public bool CanPlayStop
|
||||
{
|
||||
get => _canStop;
|
||||
set
|
||||
{
|
||||
if (_canStop == value)
|
||||
return;
|
||||
_canStop = value;
|
||||
UpdatePlaybackButtons();
|
||||
}
|
||||
}
|
||||
@@ -1146,7 +1165,7 @@ namespace FlaxEditor.GUI.Timeline
|
||||
if (_playbackPlay != null)
|
||||
{
|
||||
_playbackPlay.Visible = true;
|
||||
_playbackPlay.Enabled = _canPlayPauseStop;
|
||||
_playbackPlay.Enabled = _canPlayPause;
|
||||
_playbackPlay.Brush = new SpriteBrush(icons.Play64);
|
||||
_playbackPlay.Tag = false;
|
||||
}
|
||||
@@ -1167,12 +1186,12 @@ namespace FlaxEditor.GUI.Timeline
|
||||
if (_playbackStop != null)
|
||||
{
|
||||
_playbackStop.Visible = true;
|
||||
_playbackStop.Enabled = _canPlayPauseStop;
|
||||
_playbackStop.Enabled = _canStop;
|
||||
}
|
||||
if (_playbackPlay != null)
|
||||
{
|
||||
_playbackPlay.Visible = true;
|
||||
_playbackPlay.Enabled = _canPlayPauseStop;
|
||||
_playbackPlay.Enabled = _canPlayPause;
|
||||
_playbackPlay.Brush = new SpriteBrush(icons.Pause64);
|
||||
_playbackPlay.Tag = true;
|
||||
}
|
||||
@@ -1193,12 +1212,12 @@ namespace FlaxEditor.GUI.Timeline
|
||||
if (_playbackStop != null)
|
||||
{
|
||||
_playbackStop.Visible = true;
|
||||
_playbackStop.Enabled = _canPlayPauseStop;
|
||||
_playbackStop.Enabled = _canStop;
|
||||
}
|
||||
if (_playbackPlay != null)
|
||||
{
|
||||
_playbackPlay.Visible = true;
|
||||
_playbackPlay.Enabled = _canPlayPauseStop;
|
||||
_playbackPlay.Enabled = _canPlayPause;
|
||||
_playbackPlay.Brush = new SpriteBrush(icons.Play64);
|
||||
_playbackPlay.Tag = false;
|
||||
}
|
||||
@@ -2038,7 +2057,7 @@ namespace FlaxEditor.GUI.Timeline
|
||||
}
|
||||
break;
|
||||
case KeyboardKeys.Spacebar:
|
||||
if (CanPlayPauseStop)
|
||||
if (CanPlayPause)
|
||||
{
|
||||
if (PlaybackState == PlaybackStates.Playing)
|
||||
OnPause();
|
||||
|
||||
@@ -592,8 +592,10 @@ namespace FlaxEditor.Windows.Assets
|
||||
private ToolStripButton _saveButton;
|
||||
private ToolStripButton _undoButton;
|
||||
private ToolStripButton _redoButton;
|
||||
private ToolStripButton _previewButton;
|
||||
private ToolStripButton _renderButton;
|
||||
private FlaxObjectRefPickerControl _previewPlayerPicker;
|
||||
private SceneAnimationPlayer _previewPlayer;
|
||||
private Undo _undo;
|
||||
private bool _tmpSceneAnimationIsDirty;
|
||||
private bool _isWaitingForTimelineLoad;
|
||||
@@ -628,7 +630,9 @@ namespace FlaxEditor.Windows.Assets
|
||||
AnchorPreset = AnchorPresets.StretchAll,
|
||||
Offsets = new Margin(0, 0, _toolstrip.Bottom, 0),
|
||||
Parent = this,
|
||||
Enabled = false
|
||||
CanPlayPause = Editor.IsPlayMode,
|
||||
CanPlayStop = Editor.IsPlayMode,
|
||||
Enabled = false,
|
||||
};
|
||||
_timeline.Modified += OnTimelineModified;
|
||||
_timeline.PlayerChanged += OnTimelinePlayerChanged;
|
||||
@@ -640,6 +644,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
|
||||
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
|
||||
_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...");
|
||||
_toolstrip.AddSeparator();
|
||||
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/scene-animations/index.html")).LinkTooltip("See documentation to learn more");
|
||||
@@ -680,6 +685,54 @@ namespace FlaxEditor.Windows.Assets
|
||||
UpdateToolstrip();
|
||||
}
|
||||
|
||||
private void OnPreviewButtonClicked()
|
||||
{
|
||||
if (_previewButton.Checked)
|
||||
{
|
||||
// Use utility player actor for live-preview
|
||||
if (!_previewPlayer)
|
||||
{
|
||||
_previewPlayer = new SceneAnimationPlayer
|
||||
{
|
||||
Animation = Asset,
|
||||
HideFlags = HideFlags.FullyHidden,
|
||||
RestoreStateOnStop = true,
|
||||
PlayOnStart = false,
|
||||
RandomStartTime = false,
|
||||
UseTimeScale = false,
|
||||
UpdateMode = SceneAnimationPlayer.UpdateModes.Manual,
|
||||
};
|
||||
Level.SpawnActor(_previewPlayer);
|
||||
|
||||
// Live-preview player is in pause or play mode (stopped on the usage end)
|
||||
_previewPlayer.Play();
|
||||
_previewPlayer.Pause();
|
||||
}
|
||||
var time = _timeline.CurrentTime;
|
||||
_timeline.Player = _previewPlayer;
|
||||
_previewPlayerPicker.Value = null;
|
||||
_cachedPlayerId = Guid.Empty;
|
||||
_previewPlayer.Time = time;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_timeline.Player == _previewPlayer)
|
||||
{
|
||||
_timeline.Player = null;
|
||||
_previewPlayerPicker.Value = null;
|
||||
_cachedPlayerId = Guid.Empty;
|
||||
}
|
||||
if (_previewPlayer)
|
||||
{
|
||||
_previewPlayer.Stop();
|
||||
Object.Destroy(_previewPlayer);
|
||||
_previewPlayer = null;
|
||||
}
|
||||
}
|
||||
_previewPlayerPicker.Visible = !_previewButton.Checked;
|
||||
_timeline.CanPlayPause = _previewButton.Checked || Editor.IsPlayMode;
|
||||
}
|
||||
|
||||
private void OnRenderButtonClicked()
|
||||
{
|
||||
if (_popup != null)
|
||||
@@ -713,16 +766,29 @@ namespace FlaxEditor.Windows.Assets
|
||||
_timeline.Player = null;
|
||||
_cachedPlayerId = id;
|
||||
}
|
||||
if (actor == _previewPlayer)
|
||||
{
|
||||
_previewPlayer = null;
|
||||
if (_previewButton.Checked)
|
||||
{
|
||||
_previewButton.Checked = false;
|
||||
OnPreviewButtonClicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTimelinePlayerChanged()
|
||||
{
|
||||
if (_previewButton.Checked)
|
||||
return;
|
||||
_previewPlayerPicker.Value = _timeline.Player;
|
||||
_cachedPlayerId = _timeline.Player?.ID ?? Guid.Empty;
|
||||
}
|
||||
|
||||
private void OnPreviewPlayerPickerChanged()
|
||||
{
|
||||
if (_previewButton.Checked)
|
||||
return;
|
||||
_timeline.Player = _previewPlayerPicker.Value as SceneAnimationPlayer;
|
||||
}
|
||||
|
||||
@@ -743,7 +809,19 @@ namespace FlaxEditor.Windows.Assets
|
||||
|
||||
if (_timeline.IsModified)
|
||||
{
|
||||
var time = _timeline.CurrentTime;
|
||||
var isPlaying = _previewPlayer?.IsPlaying ?? false;
|
||||
_timeline.Save(_asset);
|
||||
if (_previewButton.Checked && _previewPlayer != null)
|
||||
{
|
||||
// Preserve playback time in live-preview mode when editing the asset
|
||||
_asset.WaitForLoaded();
|
||||
_previewPlayer.Play();
|
||||
if (!isPlaying)
|
||||
_previewPlayer.Pause();
|
||||
_previewPlayer.Time = time;
|
||||
_timeline.CurrentTime = time;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -770,6 +848,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
_saveButton.Enabled = IsEdited;
|
||||
_undoButton.Enabled = _undo.CanUndo;
|
||||
_redoButton.Enabled = _undo.CanRedo;
|
||||
_previewButton.Enabled = Level.IsAnySceneLoaded && Editor.StateMachine.IsEditMode;
|
||||
_renderButton.Enabled = Level.IsAnySceneLoaded && (Editor.IsPlayMode || Editor.StateMachine.IsEditMode);
|
||||
|
||||
base.UpdateToolstrip();
|
||||
@@ -813,6 +892,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
base.OnPlayBegin();
|
||||
|
||||
UpdateToolstrip();
|
||||
_timeline.CanPlayPause = true;
|
||||
_timeline.CanPlayStop = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -821,6 +902,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
base.OnPlayEnd();
|
||||
|
||||
UpdateToolstrip();
|
||||
_timeline.CanPlayPause = _previewButton.Checked;
|
||||
_timeline.CanPlayStop = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -839,24 +922,16 @@ namespace FlaxEditor.Windows.Assets
|
||||
// Check if temporary asset need to be updated
|
||||
if (_tmpSceneAnimationIsDirty)
|
||||
{
|
||||
// Clear flag
|
||||
_tmpSceneAnimationIsDirty = false;
|
||||
|
||||
// Update
|
||||
RefreshTempAsset();
|
||||
}
|
||||
|
||||
// Check if need to load timeline
|
||||
if (_isWaitingForTimelineLoad && _asset.IsLoaded)
|
||||
{
|
||||
// Clear flag
|
||||
_isWaitingForTimelineLoad = false;
|
||||
|
||||
// Load timeline data from the asset
|
||||
_timeline._id = OriginalAsset.ID;
|
||||
_timeline.Load(_asset);
|
||||
|
||||
// Setup
|
||||
_undo.Clear();
|
||||
_timeline.SetNoTracksText(null);
|
||||
_timeline.Enabled = true;
|
||||
@@ -874,6 +949,27 @@ namespace FlaxEditor.Windows.Assets
|
||||
_timeline.Player = obj;
|
||||
}
|
||||
}
|
||||
|
||||
// Manually tick the live-preview animation player
|
||||
if (_previewButton.Checked && _previewPlayer != null)
|
||||
{
|
||||
if (_previewPlayer.IsPlaying)
|
||||
{
|
||||
// Preview is playing
|
||||
_previewPlayer.Tick(Time.UnscaledDeltaTime);
|
||||
}
|
||||
else if (Mathf.NearEqual(_previewPlayer.Time, _timeline.CurrentFrame))
|
||||
{
|
||||
// Preview is paused
|
||||
_previewPlayer.Time = _timeline.CurrentTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
// User is seeking
|
||||
_previewPlayer.Time = _timeline.CurrentTime;
|
||||
_previewPlayer.Tick(0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -884,7 +980,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
writer.WriteAttributeString("TimelineSplitter", _timeline.Splitter.SplitterValue.ToString());
|
||||
writer.WriteAttributeString("TimeShowMode", _timeline.TimeShowMode.ToString());
|
||||
var id = _timeline.Player?.ID ?? _cachedPlayerId;
|
||||
var id = _previewButton.Checked ? Guid.Empty : (_timeline.Player?.ID ?? _cachedPlayerId);
|
||||
writer.WriteAttributeString("SelectedPlayer", id.ToString());
|
||||
writer.WriteAttributeString("ShowPreviewValues", _timeline.ShowPreviewValues.ToString());
|
||||
writer.WriteAttributeString("ShowSelected3dTrack", _timeline.ShowSelected3dTrack.ToString());
|
||||
@@ -920,6 +1016,11 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
Level.ActorDeleted -= OnActorDeleted;
|
||||
|
||||
if (_previewButton.Checked)
|
||||
{
|
||||
_previewButton.Checked = false;
|
||||
OnPreviewButtonClicked();
|
||||
}
|
||||
if (_popup != null)
|
||||
{
|
||||
_popup.Dispose();
|
||||
|
||||
Reference in New Issue
Block a user