rimworld-animation-studio/Library/PackageCache/com.unity.timeline@1.2.18/Editor/Animation/CurvesProxy.cs
2022-09-13 00:36:34 -05:00

302 lines
9.5 KiB
C#

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;
}
}
List<SerializedProperty> m_AllAnimatableParameters;
List<SerializedProperty> allAnimatableParameters
{
get
{
var so = AnimatedParameterUtility.GetSerializedPlayableAsset(m_OriginalOwner.asset);
if (so == null)
return null;
so.UpdateIfRequiredOrScript();
if (m_AllAnimatableParameters == null)
m_AllAnimatableParameters = m_OriginalOwner.GetAllAnimatableParameters().ToList();
return m_AllAnimatableParameters;
}
}
public CurvesProxy([NotNull] ICurvesOwner originalOwner)
{
m_OriginalOwner = originalOwner;
m_IsAnimatable = originalOwner.HasAnyAnimatableParameters();
RebuildProxyCurves();
}
public void CreateCurves(string curvesClipName)
{
m_OriginalOwner.CreateCurves(curvesClipName);
}
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 UpdateCurves(List<CurveWrapper> updatedCurves)
{
if (m_ProxyIsRebuilding > 0)
return;
Undo.RegisterCompleteObjectUndo(m_OriginalOwner.asset, "Edit Clip Curve");
if (m_OriginalOwner.curves != null)
Undo.RegisterCompleteObjectUndo(m_OriginalOwner.curves, "Edit Clip Curve");
foreach (var curve in updatedCurves)
{
UpdateCurve(curve.binding, curve.curve);
}
AnimatedParameterUtility.UpdateSerializedPlayableAsset(m_OriginalOwner.asset);
}
void UpdateCurve(EditorCurveBinding binding, AnimationCurve curve)
{
ApplyConstraints(binding, curve);
if (curve.length == 0)
{
HandleAllKeysDeleted(binding);
}
else if (curve.length == 1)
{
HandleConstantCurveValueChanged(binding, curve);
}
else
{
HandleCurveUpdated(binding, curve);
}
}
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)
m_OriginalOwner.CreateCurves(null);
AnimationUtility.SetEditorCurve(m_OriginalOwner.curves, binding, updatedCurve);
}
void HandleConstantCurveValueChanged(EditorCurveBinding binding, AnimationCurve updatedCurve)
{
var prop = m_PropertiesMap[binding];
if (prop == null)
return;
Undo.RegisterCompleteObjectUndo(prop.serializedObject.targetObject, "Edit Clip Curve");
prop.serializedObject.UpdateIfRequiredOrScript();
CurveEditUtility.SetFromKeyValue(prop, updatedCurve.keys[0].value);
prop.serializedObject.ApplyModifiedProperties();
}
void HandleAllKeysDeleted(EditorCurveBinding binding)
{
if (m_OriginalOwner.hasCurves)
{
// Remove curve from original asset
AnimationUtility.SetEditorCurve(m_OriginalOwner.curves, binding, null);
m_OriginalOwner.SanitizeCurvesData();
}
// Ensure proxy still has constant value
RebuildProxyCurves();
}
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
? TimelineAsset.EditorSettings.kDefaultFps
: m_OriginalOwner.targetTrack.timelineAsset.editorSettings.fps
};
}
else
{
m_ProxyCurves.ClearCurves();
}
m_OriginalOwner.SanitizeCurvesData();
AnimatedParameterUtility.UpdateSerializedPlayableAsset(m_OriginalOwner.asset);
foreach (var param in allAnimatableParameters)
CreateProxyCurve(param, m_ProxyCurves, 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
{
var curve = new AnimationCurve();
CurveEditUtility.AddKeyFrameToCurve(
curve, 0.0f, clip.frameRate, CurveEditUtility.GetKeyValue(prop),
prop.propertyType == SerializedPropertyType.Boolean);
AnimationUtility.SetEditorCurve(clip, binding, curve);
}
m_PropertiesMap[binding] = prop;
}
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;
}
}
}
}