440 lines
14 KiB
C#
440 lines
14 KiB
C#
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Linq;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.Timeline;
|
||
|
|
||
|
namespace UnityEditor.Timeline
|
||
|
{
|
||
|
enum CurveChangeType
|
||
|
{
|
||
|
None,
|
||
|
CurveModified,
|
||
|
CurveAddedOrRemoved
|
||
|
}
|
||
|
|
||
|
abstract class CurveDataSource
|
||
|
{
|
||
|
public static CurveDataSource Create(IRowGUI trackGUI)
|
||
|
{
|
||
|
if (trackGUI.asset is AnimationTrack)
|
||
|
return new InfiniteClipCurveDataSource(trackGUI);
|
||
|
|
||
|
return new TrackParametersCurveDataSource(trackGUI);
|
||
|
}
|
||
|
|
||
|
public static CurveDataSource Create(TimelineClipGUI clipGUI)
|
||
|
{
|
||
|
if (clipGUI.clip.animationClip != null)
|
||
|
return new ClipAnimationCurveDataSource(clipGUI);
|
||
|
|
||
|
return new ClipParametersCurveDataSource(clipGUI);
|
||
|
}
|
||
|
|
||
|
int? m_ID = null;
|
||
|
public int id
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (!m_ID.HasValue)
|
||
|
m_ID = CreateHashCode();
|
||
|
|
||
|
return m_ID.Value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
readonly IRowGUI m_TrackGUI;
|
||
|
protected CurveDataSource(IRowGUI trackGUI)
|
||
|
{
|
||
|
m_TrackGUI = trackGUI;
|
||
|
}
|
||
|
|
||
|
public abstract AnimationClip animationClip { get; }
|
||
|
|
||
|
public abstract float start { get; }
|
||
|
public abstract float timeScale { get; }
|
||
|
public abstract string groupingName { get; }
|
||
|
|
||
|
// Applies changes from the visual curve in the curve wrapper back to the animation clips
|
||
|
public virtual void ApplyCurveChanges(IEnumerable<CurveWrapper> updatedCurves)
|
||
|
{
|
||
|
Undo.RegisterCompleteObjectUndo(animationClip, "Edit Clip Curve");
|
||
|
foreach (CurveWrapper c in updatedCurves)
|
||
|
{
|
||
|
if (c.curve.length > 0)
|
||
|
AnimationUtility.SetEditorCurve(animationClip, c.binding, c.curve);
|
||
|
else
|
||
|
RemoveCurves(new[] {c.binding});
|
||
|
c.changed = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>The clip version is a value that will change when a curve gets updated.
|
||
|
/// it's used to detect when an animation clip has been changed externally </summary>
|
||
|
/// <returns>A versioning value indicating the state of the curve. If the curve is updated externally this value will change. </returns>
|
||
|
public virtual UInt64 GetClipVersion()
|
||
|
{
|
||
|
return animationClip.ClipVersion();
|
||
|
}
|
||
|
|
||
|
/// <summary>Call this method to check if the underlying clip has changed</summary>
|
||
|
/// <param name="curveVersion">A versioning value. This will be updated to the latest version</param>
|
||
|
/// <returns>A value indicating how the clip has changed</returns>
|
||
|
public virtual CurveChangeType UpdateExternalChanges(ref UInt64 curveVersion)
|
||
|
{
|
||
|
return animationClip.GetChangeType(ref curveVersion);
|
||
|
}
|
||
|
|
||
|
public virtual string ModifyPropertyDisplayName(string path, string propertyName) => propertyName;
|
||
|
|
||
|
public virtual void RemoveCurves(IEnumerable<EditorCurveBinding> bindings)
|
||
|
{
|
||
|
Undo.RegisterCompleteObjectUndo(animationClip, "Remove Curve(s)");
|
||
|
foreach(var binding in bindings)
|
||
|
{
|
||
|
if (binding.isPPtrCurve)
|
||
|
AnimationUtility.SetObjectReferenceCurve(animationClip, binding, null);
|
||
|
else
|
||
|
AnimationUtility.SetEditorCurve(animationClip, binding, null);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Rect GetBackgroundRect(WindowState state)
|
||
|
{
|
||
|
var trackRect = m_TrackGUI.boundingRect;
|
||
|
return new Rect(
|
||
|
state.timeAreaTranslation.x + trackRect.xMin,
|
||
|
trackRect.y,
|
||
|
(float)state.editSequence.asset.duration * state.timeAreaScale.x,
|
||
|
trackRect.height
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public List<CurveWrapper> GenerateWrappers(IEnumerable<EditorCurveBinding> bindings)
|
||
|
{
|
||
|
var wrappers = new List<CurveWrapper>(bindings.Count());
|
||
|
int curveWrapperId = 0;
|
||
|
|
||
|
foreach (EditorCurveBinding b in bindings)
|
||
|
{
|
||
|
// General configuration
|
||
|
var wrapper = new CurveWrapper
|
||
|
{
|
||
|
id = curveWrapperId++,
|
||
|
binding = b,
|
||
|
groupId = -1,
|
||
|
hidden = false,
|
||
|
readOnly = false,
|
||
|
getAxisUiScalarsCallback = () => new Vector2(1, 1)
|
||
|
};
|
||
|
|
||
|
// Specific configuration
|
||
|
ConfigureCurveWrapper(wrapper);
|
||
|
|
||
|
wrappers.Add(wrapper);
|
||
|
}
|
||
|
|
||
|
return wrappers;
|
||
|
}
|
||
|
|
||
|
protected virtual void ConfigureCurveWrapper(CurveWrapper wrapper)
|
||
|
{
|
||
|
wrapper.color = CurveUtility.GetPropertyColor(wrapper.binding.propertyName);
|
||
|
wrapper.renderer = new NormalCurveRenderer(AnimationUtility.GetEditorCurve(animationClip, wrapper.binding));
|
||
|
wrapper.renderer.SetCustomRange(0.0f, animationClip.length);
|
||
|
}
|
||
|
|
||
|
protected virtual int CreateHashCode()
|
||
|
{
|
||
|
return m_TrackGUI.asset.GetHashCode();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class ClipAnimationCurveDataSource : CurveDataSource
|
||
|
{
|
||
|
static readonly string k_GroupingName = L10n.Tr("Animated Values");
|
||
|
|
||
|
readonly TimelineClipGUI m_ClipGUI;
|
||
|
|
||
|
public ClipAnimationCurveDataSource(TimelineClipGUI clipGUI) : base(clipGUI.parent)
|
||
|
{
|
||
|
m_ClipGUI = clipGUI;
|
||
|
}
|
||
|
|
||
|
public override AnimationClip animationClip
|
||
|
{
|
||
|
get { return m_ClipGUI.clip.animationClip; }
|
||
|
}
|
||
|
|
||
|
public override float start
|
||
|
{
|
||
|
get { return (float)m_ClipGUI.clip.FromLocalTimeUnbound(0.0); }
|
||
|
}
|
||
|
|
||
|
public override float timeScale
|
||
|
{
|
||
|
get { return (float)m_ClipGUI.clip.timeScale; }
|
||
|
}
|
||
|
|
||
|
public override string groupingName
|
||
|
{
|
||
|
get { return k_GroupingName; }
|
||
|
}
|
||
|
|
||
|
protected override int CreateHashCode()
|
||
|
{
|
||
|
return base.CreateHashCode().CombineHash(m_ClipGUI.clip.GetHashCode());
|
||
|
}
|
||
|
|
||
|
public override string ModifyPropertyDisplayName(string path, string propertyName)
|
||
|
{
|
||
|
if (!AnimatedPropertyUtility.IsMaterialProperty(propertyName))
|
||
|
return propertyName;
|
||
|
|
||
|
var track = m_ClipGUI.clip.parentTrack;
|
||
|
if (track == null)
|
||
|
return propertyName;
|
||
|
|
||
|
var gameObjectBinding = TimelineUtility.GetSceneGameObject(TimelineEditor.inspectedDirector, track);
|
||
|
if (gameObjectBinding == null)
|
||
|
return propertyName;
|
||
|
|
||
|
if (!string.IsNullOrEmpty(path))
|
||
|
{
|
||
|
var transform = gameObjectBinding.transform.Find(path);
|
||
|
if (transform == null)
|
||
|
return propertyName;
|
||
|
gameObjectBinding = transform.gameObject;
|
||
|
}
|
||
|
|
||
|
return AnimatedPropertyUtility.RemapMaterialName(gameObjectBinding, propertyName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class ClipParametersCurveDataSource : CurveDataSource
|
||
|
{
|
||
|
static readonly string k_GroupingName = L10n.Tr("Clip Properties");
|
||
|
|
||
|
readonly TimelineClipGUI m_ClipGUI;
|
||
|
readonly CurvesProxy m_CurvesProxy;
|
||
|
|
||
|
private int m_ClipDirtyVersion;
|
||
|
|
||
|
public ClipParametersCurveDataSource(TimelineClipGUI clipGUI) : base(clipGUI.parent)
|
||
|
{
|
||
|
m_ClipGUI = clipGUI;
|
||
|
m_CurvesProxy = new CurvesProxy(clipGUI.clip);
|
||
|
}
|
||
|
|
||
|
public override AnimationClip animationClip
|
||
|
{
|
||
|
get { return m_CurvesProxy.curves; }
|
||
|
}
|
||
|
|
||
|
public override UInt64 GetClipVersion()
|
||
|
{
|
||
|
return sourceAnimationClip.ClipVersion();
|
||
|
}
|
||
|
|
||
|
public override CurveChangeType UpdateExternalChanges(ref ulong curveVersion)
|
||
|
{
|
||
|
if (m_ClipGUI == null || m_ClipGUI.clip == null)
|
||
|
return CurveChangeType.None;
|
||
|
|
||
|
var changeType = sourceAnimationClip.GetChangeType(ref curveVersion);
|
||
|
if (changeType != CurveChangeType.None)
|
||
|
{
|
||
|
m_CurvesProxy.ApplyExternalChangesToProxy();
|
||
|
}
|
||
|
else if (m_ClipDirtyVersion != m_ClipGUI.clip.DirtyIndex)
|
||
|
{
|
||
|
m_CurvesProxy.UpdateProxyCurves();
|
||
|
if (changeType == CurveChangeType.None)
|
||
|
changeType = CurveChangeType.CurveModified;
|
||
|
}
|
||
|
m_ClipDirtyVersion = m_ClipGUI.clip.DirtyIndex;
|
||
|
return changeType;
|
||
|
}
|
||
|
|
||
|
public override float start
|
||
|
{
|
||
|
get { return (float)m_ClipGUI.clip.FromLocalTimeUnbound(0.0); }
|
||
|
}
|
||
|
|
||
|
public override float timeScale
|
||
|
{
|
||
|
get { return (float)m_ClipGUI.clip.timeScale; }
|
||
|
}
|
||
|
|
||
|
public override string groupingName
|
||
|
{
|
||
|
get { return k_GroupingName; }
|
||
|
}
|
||
|
|
||
|
public override void RemoveCurves(IEnumerable<EditorCurveBinding> bindings)
|
||
|
{
|
||
|
m_CurvesProxy.RemoveCurves(bindings);
|
||
|
}
|
||
|
|
||
|
public override void ApplyCurveChanges(IEnumerable<CurveWrapper> updatedCurves)
|
||
|
{
|
||
|
m_CurvesProxy.UpdateCurves(updatedCurves);
|
||
|
}
|
||
|
|
||
|
protected override void ConfigureCurveWrapper(CurveWrapper wrapper)
|
||
|
{
|
||
|
m_CurvesProxy.ConfigureCurveWrapper(wrapper);
|
||
|
}
|
||
|
|
||
|
protected override int CreateHashCode()
|
||
|
{
|
||
|
return base.CreateHashCode().CombineHash(m_ClipGUI.clip.GetHashCode());
|
||
|
}
|
||
|
|
||
|
private AnimationClip sourceAnimationClip
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (m_ClipGUI == null || m_ClipGUI.clip == null || m_ClipGUI.clip.curves == null)
|
||
|
return null;
|
||
|
return m_ClipGUI.clip.curves;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class InfiniteClipCurveDataSource : CurveDataSource
|
||
|
{
|
||
|
static readonly string k_GroupingName = L10n.Tr("Animated Values");
|
||
|
|
||
|
readonly AnimationTrack m_AnimationTrack;
|
||
|
|
||
|
public InfiniteClipCurveDataSource(IRowGUI trackGui) : base(trackGui)
|
||
|
{
|
||
|
m_AnimationTrack = trackGui.asset as AnimationTrack;
|
||
|
}
|
||
|
|
||
|
public override AnimationClip animationClip
|
||
|
{
|
||
|
get { return m_AnimationTrack.infiniteClip; }
|
||
|
}
|
||
|
|
||
|
public override float start
|
||
|
{
|
||
|
get { return 0.0f; }
|
||
|
}
|
||
|
|
||
|
public override float timeScale
|
||
|
{
|
||
|
get { return 1.0f; }
|
||
|
}
|
||
|
|
||
|
public override string groupingName
|
||
|
{
|
||
|
get { return k_GroupingName; }
|
||
|
}
|
||
|
|
||
|
public override string ModifyPropertyDisplayName(string path, string propertyName)
|
||
|
{
|
||
|
if (m_AnimationTrack == null || !AnimatedPropertyUtility.IsMaterialProperty(propertyName))
|
||
|
return propertyName;
|
||
|
|
||
|
var binding = m_AnimationTrack.GetBinding(TimelineEditor.inspectedDirector);
|
||
|
if (binding == null)
|
||
|
return propertyName;
|
||
|
|
||
|
var target = binding.transform;
|
||
|
if (!string.IsNullOrEmpty(path))
|
||
|
target = target.Find(path);
|
||
|
|
||
|
if (target == null)
|
||
|
return propertyName;
|
||
|
|
||
|
return AnimatedPropertyUtility.RemapMaterialName(target.gameObject, propertyName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class TrackParametersCurveDataSource : CurveDataSource
|
||
|
{
|
||
|
static readonly string k_GroupingName = L10n.Tr("Track Properties");
|
||
|
|
||
|
readonly CurvesProxy m_CurvesProxy;
|
||
|
private int m_TrackDirtyVersion;
|
||
|
|
||
|
public TrackParametersCurveDataSource(IRowGUI trackGui) : base(trackGui)
|
||
|
{
|
||
|
m_CurvesProxy = new CurvesProxy(trackGui.asset);
|
||
|
}
|
||
|
|
||
|
public override AnimationClip animationClip
|
||
|
{
|
||
|
get { return m_CurvesProxy.curves; }
|
||
|
}
|
||
|
|
||
|
public override UInt64 GetClipVersion()
|
||
|
{
|
||
|
return sourceAnimationClip.ClipVersion();
|
||
|
}
|
||
|
|
||
|
public override CurveChangeType UpdateExternalChanges(ref ulong curveVersion)
|
||
|
{
|
||
|
if (m_CurvesProxy.targetTrack == null)
|
||
|
return CurveChangeType.None;
|
||
|
|
||
|
var changeType = sourceAnimationClip.GetChangeType(ref curveVersion);
|
||
|
if (changeType != CurveChangeType.None)
|
||
|
{
|
||
|
m_CurvesProxy.ApplyExternalChangesToProxy();
|
||
|
}
|
||
|
// track property has changed externally, update the curve proxies
|
||
|
else if (m_TrackDirtyVersion != m_CurvesProxy.targetTrack.DirtyIndex)
|
||
|
{
|
||
|
if (changeType == CurveChangeType.None)
|
||
|
changeType = CurveChangeType.CurveModified;
|
||
|
m_CurvesProxy.UpdateProxyCurves();
|
||
|
}
|
||
|
m_TrackDirtyVersion = m_CurvesProxy.targetTrack.DirtyIndex;
|
||
|
return changeType;
|
||
|
}
|
||
|
|
||
|
public override float start
|
||
|
{
|
||
|
get { return 0.0f; }
|
||
|
}
|
||
|
|
||
|
public override float timeScale
|
||
|
{
|
||
|
get { return 1.0f; }
|
||
|
}
|
||
|
|
||
|
public override string groupingName
|
||
|
{
|
||
|
get { return k_GroupingName; }
|
||
|
}
|
||
|
|
||
|
public override void RemoveCurves(IEnumerable<EditorCurveBinding> bindings)
|
||
|
{
|
||
|
m_CurvesProxy.RemoveCurves(bindings);
|
||
|
}
|
||
|
|
||
|
public override void ApplyCurveChanges(IEnumerable<CurveWrapper> updatedCurves)
|
||
|
{
|
||
|
m_CurvesProxy.UpdateCurves(updatedCurves);
|
||
|
}
|
||
|
|
||
|
protected override void ConfigureCurveWrapper(CurveWrapper wrapper)
|
||
|
{
|
||
|
m_CurvesProxy.ConfigureCurveWrapper(wrapper);
|
||
|
}
|
||
|
|
||
|
private AnimationClip sourceAnimationClip
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (m_CurvesProxy.targetTrack == null || m_CurvesProxy.targetTrack.curves == null)
|
||
|
return null;
|
||
|
return m_CurvesProxy.targetTrack.curves;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|