123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using JetBrains.Annotations;
- using UnityEngine;
- using UnityEngine.Timeline;
- using UnityObject = UnityEngine.Object;
-
- namespace UnityEditor.Timeline
- {
- class CurvesProxy : ICurvesOwner
- {
- public AnimationClip curves
- {
- get { return proxyCurves != null ? proxyCurves : m_OriginalOwner.curves; }
- }
-
- public bool hasCurves
- {
- get { return m_IsAnimatable || m_OriginalOwner.hasCurves; }
- }
-
- public double duration
- {
- get { return m_OriginalOwner.duration; }
- }
-
- public string defaultCurvesName
- {
- get { return m_OriginalOwner.defaultCurvesName; }
- }
-
- public UnityObject asset
- {
- get { return m_OriginalOwner.asset; }
- }
-
- public UnityObject assetOwner
- {
- get { return m_OriginalOwner.assetOwner; }
- }
-
- public TrackAsset targetTrack
- {
- get { return m_OriginalOwner.targetTrack; }
- }
-
- readonly ICurvesOwner m_OriginalOwner;
- readonly bool m_IsAnimatable;
- readonly Dictionary<EditorCurveBinding, SerializedProperty> m_PropertiesMap = new Dictionary<EditorCurveBinding, SerializedProperty>();
- int m_ProxyIsRebuilding = 0;
-
- AnimationClip m_ProxyCurves;
- AnimationClip proxyCurves
- {
- get
- {
- if (!m_IsAnimatable) return null;
-
- if (m_ProxyCurves == null)
- RebuildProxyCurves();
-
- return m_ProxyCurves;
- }
- }
-
- public CurvesProxy([NotNull] ICurvesOwner originalOwner)
- {
- m_OriginalOwner = originalOwner;
- m_IsAnimatable = originalOwner.HasAnyAnimatableParameters();
-
- RebuildProxyCurves();
- }
-
- public void CreateCurves(string curvesClipName)
- {
- m_OriginalOwner.CreateCurves(curvesClipName);
- TimelineEditor.window.state.rebuildGraph = true;
- }
-
- public void ConfigureCurveWrapper(CurveWrapper wrapper)
- {
- var color = CurveUtility.GetPropertyColor(wrapper.binding.propertyName);
- wrapper.color = color;
-
- float h, s, v;
- Color.RGBToHSV(color, out h, out s, out v);
- wrapper.wrapColorMultiplier = Color.HSVToRGB(h, s * 0.33f, v * 1.15f);
-
- var curve = AnimationUtility.GetEditorCurve(proxyCurves, wrapper.binding);
-
- wrapper.renderer = new NormalCurveRenderer(curve);
-
- // Use curve length instead of animation clip length
- wrapper.renderer.SetCustomRange(0.0f, curve.keys.Last().time);
- }
-
- public void RebuildCurves()
- {
- RebuildProxyCurves();
- }
-
- public void RemoveCurves(IEnumerable<EditorCurveBinding> bindings)
- {
- if (m_ProxyIsRebuilding > 0 || !m_OriginalOwner.hasCurves)
- return;
-
- Undo.RegisterCompleteObjectUndo(m_OriginalOwner.curves, L10n.Tr("Remove Clip Curve"));
- foreach (var binding in bindings)
- AnimationUtility.SetEditorCurve(m_OriginalOwner.curves, binding, null);
- m_OriginalOwner.SanitizeCurvesData();
- RebuildProxyCurves();
- }
-
- public void UpdateCurves(IEnumerable<CurveWrapper> updatedCurves)
- {
- if (m_ProxyIsRebuilding > 0)
- return;
-
- Undo.RegisterCompleteObjectUndo(m_OriginalOwner.asset, L10n.Tr("Edit Clip Curve"));
- if (m_OriginalOwner.curves != null)
- Undo.RegisterCompleteObjectUndo(m_OriginalOwner.curves, L10n.Tr("Edit Clip Curve"));
-
- var requireRebuild = false;
- foreach (var curve in updatedCurves)
- {
- requireRebuild |= curve.curve.length == 0;
- UpdateCurve(curve.binding, curve.curve);
- }
-
- if (requireRebuild)
- m_OriginalOwner.SanitizeCurvesData();
-
- AnimatedParameterUtility.UpdateSerializedPlayableAsset(m_OriginalOwner.asset);
- }
-
- public void ApplyExternalChangesToProxy()
- {
- using (new RebuildGuard(this))
- {
- if (m_OriginalOwner.curves == null)
- return;
-
- var curveInfo = AnimationClipCurveCache.Instance.GetCurveInfo(m_OriginalOwner.curves);
- for (int i = 0; i < curveInfo.bindings.Length; i++)
- {
- if (curveInfo.curves[i] != null && curveInfo.curves.Length != 0)
- {
- if (m_PropertiesMap.TryGetValue(curveInfo.bindings[i], out var prop) && AnimatedParameterUtility.IsParameterAnimatable(prop))
- AnimationUtility.SetEditorCurve(m_ProxyCurves, curveInfo.bindings[i], curveInfo.curves[i]);
- }
- }
- }
- }
-
- void UpdateCurve(EditorCurveBinding binding, AnimationCurve curve)
- {
- ApplyConstraints(binding, curve);
-
- if (curve.length == 0)
- {
- HandleAllKeysDeleted(binding);
- return;
- }
-
- // there is no curve in the animation clip, this is a proxy curve
- if (IsConstantCurve(binding, curve))
- HandleConstantCurveValueChanged(binding, curve);
- else
- HandleCurveUpdated(binding, curve);
- }
-
- bool IsConstantCurve(EditorCurveBinding binding, AnimationCurve curve)
- {
- if (curve.length != 1)
- return false;
- return m_OriginalOwner.curves == null || AnimationUtility.GetEditorCurve(m_OriginalOwner.curves, binding) == null;
- }
-
- void ApplyConstraints(EditorCurveBinding binding, AnimationCurve curve)
- {
- if (curve.length == 0)
- return;
-
- var curveUpdated = false;
-
- var property = m_PropertiesMap[binding];
- if (property.propertyType == SerializedPropertyType.Boolean)
- {
- TimelineAnimationUtilities.ConstrainCurveToBooleanValues(curve);
- curveUpdated = true;
- }
- else
- {
- var range = AnimatedParameterUtility.GetAttributeForProperty<RangeAttribute>(property);
- if (range != null)
- {
- TimelineAnimationUtilities.ConstrainCurveToRange(curve, range.min, range.max);
- curveUpdated = true;
- }
- }
-
- if (!curveUpdated)
- return;
-
- using (new RebuildGuard(this))
- {
- AnimationUtility.SetEditorCurve(m_ProxyCurves, binding, curve);
- }
- }
-
- void HandleCurveUpdated(EditorCurveBinding binding, AnimationCurve updatedCurve)
- {
- if (!m_OriginalOwner.hasCurves)
- CreateCurves(String.Empty);
-
- AnimationUtility.SetEditorCurve(m_OriginalOwner.curves, binding, updatedCurve);
- AnimationUtility.SetEditorCurve(m_ProxyCurves, binding, updatedCurve);
- }
-
- void HandleConstantCurveValueChanged(EditorCurveBinding binding, AnimationCurve updatedCurve)
- {
- var prop = m_PropertiesMap[binding];
- if (prop == null)
- return;
-
- Undo.RegisterCompleteObjectUndo(prop.serializedObject.targetObject, L10n.Tr("Edit Clip Curve"));
- prop.serializedObject.UpdateIfRequiredOrScript();
- CurveEditUtility.SetFromKeyValue(prop, updatedCurve.keys[0].value);
- prop.serializedObject.ApplyModifiedProperties();
-
- AnimationUtility.SetEditorCurve(m_ProxyCurves, binding, updatedCurve);
- }
-
- void HandleAllKeysDeleted(EditorCurveBinding binding)
- {
- if (m_OriginalOwner.hasCurves)
- {
- // Remove curve from original asset
- AnimationUtility.SetEditorCurve(m_OriginalOwner.curves, binding, null);
- SetProxyCurve(m_PropertiesMap[binding], binding);
- }
- }
-
- void RebuildProxyCurves()
- {
- if (!m_IsAnimatable)
- return;
-
- using (new RebuildGuard(this))
- {
- if (m_ProxyCurves == null)
- {
- m_ProxyCurves = new AnimationClip
- {
- legacy = true,
- name = "Constant Curves",
- hideFlags = HideFlags.HideAndDontSave,
- frameRate = m_OriginalOwner.targetTrack.timelineAsset == null
- ? (float)TimelineAsset.EditorSettings.kDefaultFrameRate
- : (float)m_OriginalOwner.targetTrack.timelineAsset.editorSettings.frameRate
- };
- }
- else
- {
- m_ProxyCurves.ClearCurves();
- }
-
- m_OriginalOwner.SanitizeCurvesData();
- AnimatedParameterUtility.UpdateSerializedPlayableAsset(m_OriginalOwner.asset);
- var parameters = m_OriginalOwner.GetAllAnimatableParameters().ToArray();
- foreach (var param in parameters)
- CreateProxyCurve(param, m_ProxyCurves, m_OriginalOwner.asset, param.propertyPath);
-
- AnimationClipCurveCache.Instance.GetCurveInfo(m_ProxyCurves).dirty = true;
- }
- }
-
- // updates the just the proxied values. This can be called when the asset changes, so the proxy values are properly updated
- public void UpdateProxyCurves()
- {
- if (!m_IsAnimatable || m_ProxyCurves == null || m_ProxyCurves.empty)
- return;
-
- AnimatedParameterUtility.UpdateSerializedPlayableAsset(m_OriginalOwner.asset);
- var parameters = m_OriginalOwner.GetAllAnimatableParameters().ToArray();
- using (new RebuildGuard(this))
- {
- if (m_OriginalOwner.hasCurves)
- {
- var bindingInfo = AnimationClipCurveCache.Instance.GetCurveInfo(m_OriginalOwner.curves);
- foreach (var param in parameters)
- {
- var binding = AnimatedParameterUtility.GetCurveBinding(m_OriginalOwner.asset, param.propertyPath);
- if (!bindingInfo.bindings.Contains(binding, AnimationPreviewUtilities.EditorCurveBindingComparer.Instance))
- SetProxyCurve(param, AnimatedParameterUtility.GetCurveBinding(m_OriginalOwner.asset, param.propertyPath));
- }
- }
- else
- {
- foreach (var param in parameters)
- SetProxyCurve(param, AnimatedParameterUtility.GetCurveBinding(m_OriginalOwner.asset, param.propertyPath));
- }
- }
-
- AnimationClipCurveCache.Instance.GetCurveInfo(m_ProxyCurves).dirty = true;
- }
-
- void CreateProxyCurve(SerializedProperty prop, AnimationClip clip, UnityObject owner, string propertyName)
- {
- var binding = AnimatedParameterUtility.GetCurveBinding(owner, propertyName);
-
- var originalCurve = m_OriginalOwner.hasCurves
- ? AnimationUtility.GetEditorCurve(m_OriginalOwner.curves, binding)
- : null;
-
- if (originalCurve != null)
- {
- AnimationUtility.SetEditorCurve(clip, binding, originalCurve);
- }
- else
- {
- SetProxyCurve(prop, binding);
- }
-
- m_PropertiesMap[binding] = prop;
- }
-
- void SetProxyCurve(SerializedProperty prop, EditorCurveBinding binding)
- {
- var curve = new AnimationCurve();
- CurveEditUtility.AddKeyFrameToCurve(
- curve, 0.0f, m_ProxyCurves.frameRate, CurveEditUtility.GetKeyValue(prop),
- prop.propertyType == SerializedPropertyType.Boolean);
- AnimationUtility.SetEditorCurve(m_ProxyCurves, binding, curve);
- }
-
- struct RebuildGuard : IDisposable
- {
- CurvesProxy m_Owner;
- AnimationUtility.OnCurveWasModified m_Callback;
-
- public RebuildGuard(CurvesProxy owner)
- {
- m_Callback = AnimationUtility.onCurveWasModified;
- AnimationUtility.onCurveWasModified = null;
- m_Owner = owner;
- m_Owner.m_ProxyIsRebuilding++;
- }
-
- public void Dispose()
- {
- AnimationUtility.onCurveWasModified = m_Callback;
- m_Owner.m_ProxyIsRebuilding--;
- m_Owner = null;
- }
- }
- }
- }
|