UnityGame/Library/PackageCache/com.unity.timeline/Editor/Animation/AnimationClipCurveCache.cs

428 lines
14 KiB
C#
Raw Permalink Normal View History

2024-10-27 10:53:47 +03:00
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
namespace UnityEditor.Timeline
{
struct CurveBindingPair
{
public EditorCurveBinding binding;
public AnimationCurve curve;
public ObjectReferenceKeyframe[] objectCurve;
}
class CurveBindingGroup
{
public CurveBindingPair[] curveBindingPairs { get; set; }
public Vector2 timeRange { get; set; }
public Vector2 valueRange { get; set; }
public bool isFloatCurve
{
get
{
return curveBindingPairs != null && curveBindingPairs.Length > 0 &&
curveBindingPairs[0].curve != null;
}
}
public bool isObjectCurve
{
get
{
return curveBindingPairs != null && curveBindingPairs.Length > 0 &&
curveBindingPairs[0].objectCurve != null;
}
}
public int count
{
get
{
if (curveBindingPairs == null)
return 0;
return curveBindingPairs.Length;
}
}
}
class AnimationClipCurveInfo
{
bool m_CurveDirty = true;
bool m_KeysDirty = true;
public bool dirty
{
get { return m_CurveDirty; }
set
{
m_CurveDirty = value;
if (m_CurveDirty)
{
m_KeysDirty = true;
if (m_groupings != null)
m_groupings.Clear();
}
}
}
public AnimationCurve[] curves;
public EditorCurveBinding[] bindings;
public EditorCurveBinding[] objectBindings;
public List<ObjectReferenceKeyframe[]> objectCurves;
Dictionary<string, CurveBindingGroup> m_groupings;
// to tell whether the cache has changed
public int version { get; private set; }
float[] m_KeyTimes;
Dictionary<EditorCurveBinding, float[]> m_individualBindinsKey;
public float[] keyTimes
{
get
{
if (m_KeysDirty || m_KeyTimes == null)
{
RebuildKeyCache();
}
return m_KeyTimes;
}
}
public float[] GetCurveTimes(EditorCurveBinding curve)
{
return GetCurveTimes(new[] { curve });
}
public float[] GetCurveTimes(EditorCurveBinding[] curves)
{
if (m_KeysDirty || m_KeyTimes == null)
{
RebuildKeyCache();
}
var keyTimes = new List<float>();
for (int i = 0; i < curves.Length; i++)
{
var c = curves[i];
if (m_individualBindinsKey.ContainsKey(c))
{
keyTimes.AddRange(m_individualBindinsKey[c]);
}
}
return keyTimes.ToArray();
}
void RebuildKeyCache()
{
m_individualBindinsKey = new Dictionary<EditorCurveBinding, float[]>();
List<float> keys = curves.SelectMany(y => y.keys).Select(z => z.time).ToList();
for (int i = 0; i < objectCurves.Count; i++)
{
var kf = objectCurves[i];
keys.AddRange(kf.Select(x => x.time));
}
for (int b = 0; b < bindings.Count(); b++)
{
m_individualBindinsKey.Add(bindings[b], curves[b].keys.Select(k => k.time).Distinct().ToArray());
}
m_KeyTimes = keys.OrderBy(x => x).Distinct().ToArray();
m_KeysDirty = false;
}
public void Update(AnimationClip clip)
{
List<EditorCurveBinding> postfilter = new List<EditorCurveBinding>();
var clipBindings = AnimationUtility.GetCurveBindings(clip);
for (int i = 0; i < clipBindings.Length; i++)
{
var bind = clipBindings[i];
if (!bind.propertyName.Contains("LocalRotation.w"))
postfilter.Add(RotationCurveInterpolation.RemapAnimationBindingForRotationCurves(bind, clip));
}
bindings = postfilter.ToArray();
curves = new AnimationCurve[bindings.Length];
for (int i = 0; i < bindings.Length; i++)
{
curves[i] = AnimationUtility.GetEditorCurve(clip, bindings[i]);
}
objectBindings = AnimationUtility.GetObjectReferenceCurveBindings(clip);
objectCurves = new List<ObjectReferenceKeyframe[]>(objectBindings.Length);
for (int i = 0; i < objectBindings.Length; i++)
{
objectCurves.Add(AnimationUtility.GetObjectReferenceCurve(clip, objectBindings[i]));
}
m_CurveDirty = false;
m_KeysDirty = true;
version = version + 1;
}
public bool GetBindingForCurve(AnimationCurve curve, ref EditorCurveBinding binding)
{
for (int i = 0; i < curves.Length; i++)
{
if (curve == curves[i])
{
binding = bindings[i];
return true;
}
}
return false;
}
public AnimationCurve GetCurveForBinding(EditorCurveBinding binding)
{
for (int i = 0; i < curves.Length; i++)
{
if (binding.Equals(bindings[i]))
{
return curves[i];
}
}
return null;
}
public ObjectReferenceKeyframe[] GetObjectCurveForBinding(EditorCurveBinding binding)
{
if (objectCurves == null)
return null;
for (int i = 0; i < objectCurves.Count; i++)
{
if (binding.Equals(objectBindings[i]))
{
return objectCurves[i];
}
}
return null;
}
// given a groupID, get the list of curve bindings
public CurveBindingGroup GetGroupBinding(string groupID)
{
if (m_groupings == null)
m_groupings = new Dictionary<string, CurveBindingGroup>();
CurveBindingGroup result = null;
if (!m_groupings.TryGetValue(groupID, out result))
{
result = new CurveBindingGroup();
result.timeRange = new Vector2(float.MaxValue, float.MinValue);
result.valueRange = new Vector2(float.MaxValue, float.MinValue);
List<CurveBindingPair> found = new List<CurveBindingPair>();
for (int i = 0; i < bindings.Length; i++)
{
if (bindings[i].GetGroupID() == groupID)
{
CurveBindingPair pair = new CurveBindingPair();
pair.binding = bindings[i];
pair.curve = curves[i];
found.Add(pair);
for (int k = 0; k < curves[i].keys.Length; k++)
{
var key = curves[i].keys[k];
result.timeRange = new Vector2(Mathf.Min(key.time, result.timeRange.x), Mathf.Max(key.time, result.timeRange.y));
result.valueRange = new Vector2(Mathf.Min(key.value, result.valueRange.x), Mathf.Max(key.value, result.valueRange.y));
}
}
}
for (int i = 0; i < objectBindings.Length; i++)
{
if (objectBindings[i].GetGroupID() == groupID)
{
CurveBindingPair pair = new CurveBindingPair();
pair.binding = objectBindings[i];
pair.objectCurve = objectCurves[i];
found.Add(pair);
for (int k = 0; k < objectCurves[i].Length; k++)
{
var key = objectCurves[i][k];
result.timeRange = new Vector2(Mathf.Min(key.time, result.timeRange.x), Mathf.Max(key.time, result.timeRange.y));
}
}
}
result.curveBindingPairs = found.OrderBy(x => AnimationWindowUtility.GetComponentIndex(x.binding.propertyName)).ToArray();
m_groupings.Add(groupID, result);
}
return result;
}
}
// Cache for storing the animation clip data
class AnimationClipCurveCache
{
static AnimationClipCurveCache s_Instance;
Dictionary<AnimationClip, AnimationClipCurveInfo> m_ClipCache = new Dictionary<AnimationClip, AnimationClipCurveInfo>();
bool m_IsEnabled;
public static AnimationClipCurveCache Instance
{
get
{
if (s_Instance == null)
{
s_Instance = new AnimationClipCurveCache();
}
return s_Instance;
}
}
public void OnEnable()
{
if (!m_IsEnabled)
{
AnimationUtility.onCurveWasModified += OnCurveWasModified;
m_IsEnabled = true;
}
}
public void OnDisable()
{
if (m_IsEnabled)
{
AnimationUtility.onCurveWasModified -= OnCurveWasModified;
m_IsEnabled = false;
}
}
// callback when a curve is edited. Force the cache to update next time it's accessed
void OnCurveWasModified(AnimationClip clip, EditorCurveBinding binding, AnimationUtility.CurveModifiedType modification)
{
AnimationClipCurveInfo data;
if (m_ClipCache.TryGetValue(clip, out data))
{
data.dirty = true;
}
}
public AnimationClipCurveInfo GetCurveInfo(AnimationClip clip)
{
AnimationClipCurveInfo data;
if (clip == null)
return null;
if (!m_ClipCache.TryGetValue(clip, out data))
{
data = new AnimationClipCurveInfo();
data.dirty = true;
m_ClipCache[clip] = data;
}
if (data.dirty)
{
data.Update(clip);
}
return data;
}
public void ClearCachedProxyClips()
{
var toRemove = new List<AnimationClip>();
foreach (var entry in m_ClipCache)
{
var clip = entry.Key;
if (clip != null && (clip.hideFlags & HideFlags.HideAndDontSave) == HideFlags.HideAndDontSave)
toRemove.Add(clip);
}
foreach (var clip in toRemove)
{
m_ClipCache.Remove(clip);
Object.DestroyImmediate(clip, true);
}
}
public void Clear()
{
ClearCachedProxyClips();
m_ClipCache.Clear();
}
}
static class EditorCurveBindingExtension
{
// identifier to generate an id thats the same for all curves in the same group
public static string GetGroupID(this EditorCurveBinding binding)
{
return binding.type + AnimationWindowUtility.GetPropertyGroupName(binding.propertyName);
}
}
static class CurveBindingGroupExtensions
{
// Extentions to determine curve types
public static bool IsEnableGroup(this CurveBindingGroup curves)
{
return curves.isFloatCurve && curves.count == 1 && curves.curveBindingPairs[0].binding.propertyName == "m_Enabled";
}
public static bool IsVectorGroup(this CurveBindingGroup curves)
{
if (!curves.isFloatCurve)
return false;
if (curves.count <= 1 || curves.count > 4)
return false;
char l = curves.curveBindingPairs[0].binding.propertyName.Last();
return l == 'x' || l == 'y' || l == 'z' || l == 'w';
}
public static bool IsColorGroup(this CurveBindingGroup curves)
{
if (!curves.isFloatCurve)
return false;
if (curves.count != 3 && curves.count != 4)
return false;
char l = curves.curveBindingPairs[0].binding.propertyName.Last();
return l == 'r' || l == 'g' || l == 'b' || l == 'a';
}
public static string GetDescription(this CurveBindingGroup group, float t)
{
string result = string.Empty;
if (group.isFloatCurve)
{
if (group.count > 1)
{
result += "(" + group.curveBindingPairs[0].curve.Evaluate(t).ToString("0.##");
for (int j = 1; j < group.curveBindingPairs.Length; j++)
{
result += "," + group.curveBindingPairs[j].curve.Evaluate(t).ToString("0.##");
}
result += ")";
}
else
{
result = group.curveBindingPairs[0].curve.Evaluate(t).ToString("0.##");
}
}
else if (group.isObjectCurve)
{
Object obj = null;
if (group.curveBindingPairs[0].objectCurve.Length > 0)
obj = CurveEditUtility.Evaluate(group.curveBindingPairs[0].objectCurve, t);
result = (obj == null ? "None" : obj.name);
}
return result;
}
}
}