323 lines
8.6 KiB
C#
323 lines
8.6 KiB
C#
using System;
|
|
using UnityEditorInternal;
|
|
using UnityEngine;
|
|
using UnityEngine.Timeline;
|
|
using Object = UnityEngine.Object;
|
|
|
|
namespace UnityEditor.Timeline
|
|
{
|
|
class TimelineWindowTimeControl : IAnimationWindowControl
|
|
{
|
|
[Serializable]
|
|
public struct ClipData
|
|
{
|
|
public double start;
|
|
public double duration;
|
|
public TrackAsset track;
|
|
}
|
|
|
|
#if UNITY_2021_2_OR_NEWER
|
|
const AnimationWindowState.SnapMode k_SnapMode = AnimationWindowState.SnapMode.SnapToFrame;
|
|
#else
|
|
const AnimationWindowState.SnapMode k_SnapMode = AnimationWindowState.SnapMode.SnapToClipFrame;
|
|
#endif
|
|
|
|
[SerializeField] ClipData m_ClipData;
|
|
[SerializeField] TimelineClip m_Clip;
|
|
[SerializeField] AnimationWindowState m_AnimWindowState;
|
|
|
|
TrackAsset track
|
|
{
|
|
get
|
|
{
|
|
if (m_Clip != null)
|
|
{
|
|
return m_Clip.GetParentTrack();
|
|
}
|
|
return m_ClipData.track;
|
|
}
|
|
}
|
|
|
|
static TimelineWindow window
|
|
{
|
|
get
|
|
{
|
|
return TimelineWindow.instance;
|
|
}
|
|
}
|
|
|
|
static WindowState state
|
|
{
|
|
get
|
|
{
|
|
if (window != null)
|
|
return window.state;
|
|
return null;
|
|
}
|
|
}
|
|
|
|
void OnStateChange()
|
|
{
|
|
if (m_AnimWindowState != null)
|
|
m_AnimWindowState.Repaint();
|
|
}
|
|
|
|
public void Init(AnimationWindowState animState, TimelineClip clip)
|
|
{
|
|
m_Clip = clip;
|
|
m_AnimWindowState = animState;
|
|
}
|
|
|
|
public void Init(AnimationWindowState animState, ClipData clip)
|
|
{
|
|
m_ClipData = clip;
|
|
m_AnimWindowState = animState;
|
|
}
|
|
|
|
public override void OnEnable()
|
|
{
|
|
if (state != null)
|
|
state.OnTimeChange += OnStateChange;
|
|
|
|
base.OnEnable();
|
|
}
|
|
|
|
public void OnDisable()
|
|
{
|
|
if (state != null)
|
|
state.OnTimeChange -= OnStateChange;
|
|
}
|
|
|
|
public override AnimationKeyTime time
|
|
{
|
|
get
|
|
{
|
|
if (state == null)
|
|
return AnimationKeyTime.Time(0.0f, 0.0f);
|
|
|
|
return AnimationKeyTime.Time(ToAnimationClipTime(state.editSequence.time), (float)state.referenceSequence.frameRate);
|
|
}
|
|
}
|
|
|
|
void ChangeTime(double newTime)
|
|
{
|
|
if (state != null && state.editSequence.director != null)
|
|
{
|
|
// avoid rounding errors
|
|
var finalTime = ToGlobalTime(newTime);
|
|
if (TimeUtility.OnFrameBoundary(finalTime, state.referenceSequence.frameRate, TimeUtility.kFrameRateEpsilon))
|
|
finalTime = TimeUtility.RoundToFrame(finalTime, state.referenceSequence.frameRate);
|
|
state.editSequence.time = finalTime;
|
|
|
|
window.Repaint();
|
|
}
|
|
}
|
|
|
|
void ChangeFrame(int frame)
|
|
{
|
|
frame = Math.Max(0, frame);
|
|
|
|
if (state != null && state.referenceSequence != null)
|
|
{
|
|
double frameTime = TimeUtility.FromFrames(frame, state.referenceSequence.frameRate);
|
|
ChangeTime(frameTime);
|
|
}
|
|
}
|
|
|
|
public override void GoToTime(float newTime)
|
|
{
|
|
ChangeTime(newTime);
|
|
}
|
|
|
|
public override void GoToFrame(int frame)
|
|
{
|
|
ChangeFrame(frame);
|
|
}
|
|
|
|
public override void StartScrubTime() { }
|
|
|
|
public override void EndScrubTime() { }
|
|
|
|
public override void ScrubTime(float newTime)
|
|
{
|
|
ChangeTime(newTime);
|
|
}
|
|
|
|
public override void GoToPreviousFrame()
|
|
{
|
|
if (state != null)
|
|
ChangeFrame(state.editSequence.frame - 1);
|
|
}
|
|
|
|
public override void GoToNextFrame()
|
|
{
|
|
if (state != null)
|
|
ChangeFrame(state.editSequence.frame + 1);
|
|
}
|
|
|
|
AnimationWindowCurve[] GetCurves()
|
|
{
|
|
var curves =
|
|
(m_AnimWindowState.showCurveEditor &&
|
|
m_AnimWindowState.activeCurves.Count > 0) ? m_AnimWindowState.activeCurves : m_AnimWindowState.allCurves;
|
|
return curves.ToArray();
|
|
}
|
|
|
|
public override void GoToPreviousKeyframe()
|
|
{
|
|
var newTime = AnimationWindowUtility.GetPreviousKeyframeTime(GetCurves(), time.time, m_AnimWindowState.clipFrameRate);
|
|
GoToTime(m_AnimWindowState.SnapToFrame(newTime, k_SnapMode));
|
|
}
|
|
|
|
public override void GoToNextKeyframe()
|
|
{
|
|
var newTime = AnimationWindowUtility.GetNextKeyframeTime(GetCurves(), time.time, m_AnimWindowState.clipFrameRate);
|
|
GoToTime(m_AnimWindowState.SnapToFrame(newTime, k_SnapMode));
|
|
}
|
|
|
|
public override void GoToFirstKeyframe()
|
|
{
|
|
GoToTime(0);
|
|
}
|
|
|
|
public override void GoToLastKeyframe()
|
|
{
|
|
double animClipTime = 0;
|
|
if (m_Clip != null)
|
|
{
|
|
var curves = m_Clip.curves;
|
|
var animAsset = m_Clip.asset as AnimationPlayableAsset;
|
|
if (animAsset != null)
|
|
{
|
|
animClipTime = animAsset.clip != null ? animAsset.clip.length : 0;
|
|
}
|
|
else if (curves != null)
|
|
{
|
|
animClipTime = curves.length;
|
|
}
|
|
else
|
|
{
|
|
animClipTime = m_Clip.clipAssetDuration;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
animClipTime = m_ClipData.duration;
|
|
}
|
|
|
|
GoToTime((float)animClipTime);
|
|
}
|
|
|
|
public override bool canPlay
|
|
{
|
|
get
|
|
{
|
|
return state != null && state.previewMode;
|
|
}
|
|
}
|
|
|
|
public override bool playing
|
|
{
|
|
get
|
|
{
|
|
return state != null && state.playing;
|
|
}
|
|
}
|
|
|
|
static void SetPlaybackState(bool playbackState)
|
|
{
|
|
if (state == null || playbackState == state.playing)
|
|
return;
|
|
|
|
state.SetPlaying(playbackState);
|
|
}
|
|
|
|
public override bool StartPlayback()
|
|
{
|
|
SetPlaybackState(true);
|
|
return state != null && state.playing;
|
|
}
|
|
|
|
public override void StopPlayback()
|
|
{
|
|
SetPlaybackState(false);
|
|
}
|
|
|
|
public override bool PlaybackUpdate() { return state != null && state.playing; }
|
|
|
|
public override bool canRecord
|
|
{
|
|
get { return state != null && state.canRecord; }
|
|
}
|
|
|
|
public override bool recording
|
|
{
|
|
get { return state != null && state.recording; }
|
|
}
|
|
|
|
public override bool canPreview
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
public override bool previewing
|
|
{
|
|
get { return true; }
|
|
}
|
|
|
|
public override bool StartRecording(Object targetObject)
|
|
{
|
|
if (!canRecord)
|
|
return false;
|
|
|
|
if (track != null && state != null && !state.ignorePreview)
|
|
{
|
|
state.ArmForRecord(track);
|
|
return state.recording;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public override void StopRecording()
|
|
{
|
|
if (track != null && state != null && !state.ignorePreview)
|
|
state.UnarmForRecord(track);
|
|
}
|
|
|
|
public override void OnSelectionChanged() { }
|
|
|
|
public override void ResampleAnimation() { }
|
|
|
|
public override bool StartPreview()
|
|
{
|
|
if (state != null)
|
|
state.previewMode = true;
|
|
return state != null && state.previewMode;
|
|
}
|
|
|
|
public override void StopPreview()
|
|
{
|
|
if (state != null)
|
|
state.previewMode = false;
|
|
}
|
|
|
|
public override void ProcessCandidates() { }
|
|
public override void ClearCandidates() { }
|
|
|
|
double ToGlobalTime(double localTime)
|
|
{
|
|
if (m_Clip != null)
|
|
return Math.Max(0, m_Clip.FromLocalTimeUnbound(localTime));
|
|
return Math.Max(0, m_ClipData.start + localTime);
|
|
}
|
|
|
|
float ToAnimationClipTime(double globalTime)
|
|
{
|
|
if (m_Clip != null)
|
|
return (float)m_Clip.ToLocalTimeUnbound(globalTime);
|
|
return (float)(globalTime - m_ClipData.start);
|
|
}
|
|
}
|
|
}
|