No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AnimationClipCurveCache.cs 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using UnityEngine;
  4. using UnityEditor;
  5. using UnityEditorInternal;
  6. namespace UnityEditor.Timeline
  7. {
  8. struct CurveBindingPair
  9. {
  10. public EditorCurveBinding binding;
  11. public AnimationCurve curve;
  12. public ObjectReferenceKeyframe[] objectCurve;
  13. }
  14. class CurveBindingGroup
  15. {
  16. public CurveBindingPair[] curveBindingPairs { get; set; }
  17. public Vector2 timeRange { get; set; }
  18. public Vector2 valueRange { get; set; }
  19. public bool isFloatCurve
  20. {
  21. get
  22. {
  23. return curveBindingPairs != null && curveBindingPairs.Length > 0 &&
  24. curveBindingPairs[0].curve != null;
  25. }
  26. }
  27. public bool isObjectCurve
  28. {
  29. get
  30. {
  31. return curveBindingPairs != null && curveBindingPairs.Length > 0 &&
  32. curveBindingPairs[0].objectCurve != null;
  33. }
  34. }
  35. public int count
  36. {
  37. get
  38. {
  39. if (curveBindingPairs == null)
  40. return 0;
  41. return curveBindingPairs.Length;
  42. }
  43. }
  44. }
  45. class AnimationClipCurveInfo
  46. {
  47. bool m_CurveDirty = true;
  48. bool m_KeysDirty = true;
  49. public bool dirty
  50. {
  51. get { return m_CurveDirty; }
  52. set
  53. {
  54. m_CurveDirty = value;
  55. if (m_CurveDirty)
  56. {
  57. m_KeysDirty = true;
  58. if (m_groupings != null)
  59. m_groupings.Clear();
  60. }
  61. }
  62. }
  63. public AnimationCurve[] curves;
  64. public EditorCurveBinding[] bindings;
  65. public EditorCurveBinding[] objectBindings;
  66. public List<ObjectReferenceKeyframe[]> objectCurves;
  67. Dictionary<string, CurveBindingGroup> m_groupings;
  68. // to tell whether the cache has changed
  69. public int version { get; private set; }
  70. float[] m_KeyTimes;
  71. Dictionary<EditorCurveBinding, float[]> m_individualBindinsKey;
  72. public float[] keyTimes
  73. {
  74. get
  75. {
  76. if (m_KeysDirty || m_KeyTimes == null)
  77. {
  78. RebuildKeyCache();
  79. }
  80. return m_KeyTimes;
  81. }
  82. }
  83. public float[] GetCurveTimes(EditorCurveBinding curve)
  84. {
  85. return GetCurveTimes(new[] { curve });
  86. }
  87. public float[] GetCurveTimes(EditorCurveBinding[] curves)
  88. {
  89. if (m_KeysDirty || m_KeyTimes == null)
  90. {
  91. RebuildKeyCache();
  92. }
  93. var keyTimes = new List<float>();
  94. for (int i = 0; i < curves.Length; i++)
  95. {
  96. var c = curves[i];
  97. if (m_individualBindinsKey.ContainsKey(c))
  98. {
  99. keyTimes.AddRange(m_individualBindinsKey[c]);
  100. }
  101. }
  102. return keyTimes.ToArray();
  103. }
  104. void RebuildKeyCache()
  105. {
  106. m_individualBindinsKey = new Dictionary<EditorCurveBinding, float[]>();
  107. List<float> keys = curves.SelectMany(y => y.keys).Select(z => z.time).ToList();
  108. for (int i = 0; i < objectCurves.Count; i++)
  109. {
  110. var kf = objectCurves[i];
  111. keys.AddRange(kf.Select(x => x.time));
  112. }
  113. for (int b = 0; b < bindings.Count(); b++)
  114. {
  115. m_individualBindinsKey.Add(bindings[b], curves[b].keys.Select(k => k.time).Distinct().ToArray());
  116. }
  117. m_KeyTimes = keys.OrderBy(x => x).Distinct().ToArray();
  118. m_KeysDirty = false;
  119. }
  120. public void Update(AnimationClip clip)
  121. {
  122. List<EditorCurveBinding> postfilter = new List<EditorCurveBinding>();
  123. var clipBindings = AnimationUtility.GetCurveBindings(clip);
  124. for (int i = 0; i < clipBindings.Length; i++)
  125. {
  126. var bind = clipBindings[i];
  127. if (!bind.propertyName.Contains("LocalRotation.w"))
  128. postfilter.Add(RotationCurveInterpolation.RemapAnimationBindingForRotationCurves(bind, clip));
  129. }
  130. bindings = postfilter.ToArray();
  131. curves = new AnimationCurve[bindings.Length];
  132. for (int i = 0; i < bindings.Length; i++)
  133. {
  134. curves[i] = AnimationUtility.GetEditorCurve(clip, bindings[i]);
  135. }
  136. objectBindings = AnimationUtility.GetObjectReferenceCurveBindings(clip);
  137. objectCurves = new List<ObjectReferenceKeyframe[]>(objectBindings.Length);
  138. for (int i = 0; i < objectBindings.Length; i++)
  139. {
  140. objectCurves.Add(AnimationUtility.GetObjectReferenceCurve(clip, objectBindings[i]));
  141. }
  142. m_CurveDirty = false;
  143. m_KeysDirty = true;
  144. version = version + 1;
  145. }
  146. public bool GetBindingForCurve(AnimationCurve curve, ref EditorCurveBinding binding)
  147. {
  148. for (int i = 0; i < curves.Length; i++)
  149. {
  150. if (curve == curves[i])
  151. {
  152. binding = bindings[i];
  153. return true;
  154. }
  155. }
  156. return false;
  157. }
  158. public AnimationCurve GetCurveForBinding(EditorCurveBinding binding)
  159. {
  160. for (int i = 0; i < curves.Length; i++)
  161. {
  162. if (binding.Equals(bindings[i]))
  163. {
  164. return curves[i];
  165. }
  166. }
  167. return null;
  168. }
  169. public ObjectReferenceKeyframe[] GetObjectCurveForBinding(EditorCurveBinding binding)
  170. {
  171. if (objectCurves == null)
  172. return null;
  173. for (int i = 0; i < objectCurves.Count; i++)
  174. {
  175. if (binding.Equals(objectBindings[i]))
  176. {
  177. return objectCurves[i];
  178. }
  179. }
  180. return null;
  181. }
  182. // given a groupID, get the list of curve bindings
  183. public CurveBindingGroup GetGroupBinding(string groupID)
  184. {
  185. if (m_groupings == null)
  186. m_groupings = new Dictionary<string, CurveBindingGroup>();
  187. CurveBindingGroup result = null;
  188. if (!m_groupings.TryGetValue(groupID, out result))
  189. {
  190. result = new CurveBindingGroup();
  191. result.timeRange = new Vector2(float.MaxValue, float.MinValue);
  192. result.valueRange = new Vector2(float.MaxValue, float.MinValue);
  193. List<CurveBindingPair> found = new List<CurveBindingPair>();
  194. for (int i = 0; i < bindings.Length; i++)
  195. {
  196. if (bindings[i].GetGroupID() == groupID)
  197. {
  198. CurveBindingPair pair = new CurveBindingPair();
  199. pair.binding = bindings[i];
  200. pair.curve = curves[i];
  201. found.Add(pair);
  202. for (int k = 0; k < curves[i].keys.Length; k++)
  203. {
  204. var key = curves[i].keys[k];
  205. result.timeRange = new Vector2(Mathf.Min(key.time, result.timeRange.x), Mathf.Max(key.time, result.timeRange.y));
  206. result.valueRange = new Vector2(Mathf.Min(key.value, result.valueRange.x), Mathf.Max(key.value, result.valueRange.y));
  207. }
  208. }
  209. }
  210. for (int i = 0; i < objectBindings.Length; i++)
  211. {
  212. if (objectBindings[i].GetGroupID() == groupID)
  213. {
  214. CurveBindingPair pair = new CurveBindingPair();
  215. pair.binding = objectBindings[i];
  216. pair.objectCurve = objectCurves[i];
  217. found.Add(pair);
  218. for (int k = 0; k < objectCurves[i].Length; k++)
  219. {
  220. var key = objectCurves[i][k];
  221. result.timeRange = new Vector2(Mathf.Min(key.time, result.timeRange.x), Mathf.Max(key.time, result.timeRange.y));
  222. }
  223. }
  224. }
  225. result.curveBindingPairs = found.OrderBy(x => AnimationWindowUtility.GetComponentIndex(x.binding.propertyName)).ToArray();
  226. m_groupings.Add(groupID, result);
  227. }
  228. return result;
  229. }
  230. }
  231. // Cache for storing the animation clip data
  232. class AnimationClipCurveCache
  233. {
  234. static AnimationClipCurveCache s_Instance;
  235. Dictionary<AnimationClip, AnimationClipCurveInfo> m_ClipCache = new Dictionary<AnimationClip, AnimationClipCurveInfo>();
  236. bool m_IsEnabled;
  237. public static AnimationClipCurveCache Instance
  238. {
  239. get
  240. {
  241. if (s_Instance == null)
  242. {
  243. s_Instance = new AnimationClipCurveCache();
  244. }
  245. return s_Instance;
  246. }
  247. }
  248. public void OnEnable()
  249. {
  250. if (!m_IsEnabled)
  251. {
  252. AnimationUtility.onCurveWasModified += OnCurveWasModified;
  253. m_IsEnabled = true;
  254. }
  255. }
  256. public void OnDisable()
  257. {
  258. if (m_IsEnabled)
  259. {
  260. AnimationUtility.onCurveWasModified -= OnCurveWasModified;
  261. m_IsEnabled = false;
  262. }
  263. }
  264. // callback when a curve is edited. Force the cache to update next time it's accessed
  265. void OnCurveWasModified(AnimationClip clip, EditorCurveBinding binding, AnimationUtility.CurveModifiedType modification)
  266. {
  267. AnimationClipCurveInfo data;
  268. if (m_ClipCache.TryGetValue(clip, out data))
  269. {
  270. data.dirty = true;
  271. }
  272. }
  273. public AnimationClipCurveInfo GetCurveInfo(AnimationClip clip)
  274. {
  275. AnimationClipCurveInfo data;
  276. if (clip == null)
  277. return null;
  278. if (!m_ClipCache.TryGetValue(clip, out data))
  279. {
  280. data = new AnimationClipCurveInfo();
  281. data.dirty = true;
  282. m_ClipCache[clip] = data;
  283. }
  284. if (data.dirty)
  285. {
  286. data.Update(clip);
  287. }
  288. return data;
  289. }
  290. public void ClearCachedProxyClips()
  291. {
  292. var toRemove = new List<AnimationClip>();
  293. foreach (var entry in m_ClipCache)
  294. {
  295. var clip = entry.Key;
  296. if (clip != null && (clip.hideFlags & HideFlags.HideAndDontSave) == HideFlags.HideAndDontSave)
  297. toRemove.Add(clip);
  298. }
  299. foreach (var clip in toRemove)
  300. {
  301. m_ClipCache.Remove(clip);
  302. Object.DestroyImmediate(clip, true);
  303. }
  304. }
  305. public void Clear()
  306. {
  307. ClearCachedProxyClips();
  308. m_ClipCache.Clear();
  309. }
  310. }
  311. static class EditorCurveBindingExtension
  312. {
  313. // identifier to generate an id thats the same for all curves in the same group
  314. public static string GetGroupID(this EditorCurveBinding binding)
  315. {
  316. return binding.type + AnimationWindowUtility.GetPropertyGroupName(binding.propertyName);
  317. }
  318. }
  319. static class CurveBindingGroupExtensions
  320. {
  321. // Extentions to determine curve types
  322. public static bool IsEnableGroup(this CurveBindingGroup curves)
  323. {
  324. return curves.isFloatCurve && curves.count == 1 && curves.curveBindingPairs[0].binding.propertyName == "m_Enabled";
  325. }
  326. public static bool IsVectorGroup(this CurveBindingGroup curves)
  327. {
  328. if (!curves.isFloatCurve)
  329. return false;
  330. if (curves.count <= 1 || curves.count > 4)
  331. return false;
  332. char l = curves.curveBindingPairs[0].binding.propertyName.Last();
  333. return l == 'x' || l == 'y' || l == 'z' || l == 'w';
  334. }
  335. public static bool IsColorGroup(this CurveBindingGroup curves)
  336. {
  337. if (!curves.isFloatCurve)
  338. return false;
  339. if (curves.count != 3 && curves.count != 4)
  340. return false;
  341. char l = curves.curveBindingPairs[0].binding.propertyName.Last();
  342. return l == 'r' || l == 'g' || l == 'b' || l == 'a';
  343. }
  344. public static string GetDescription(this CurveBindingGroup group, float t)
  345. {
  346. string result = string.Empty;
  347. if (group.isFloatCurve)
  348. {
  349. if (group.count > 1)
  350. {
  351. result += "(" + group.curveBindingPairs[0].curve.Evaluate(t).ToString("0.##");
  352. for (int j = 1; j < group.curveBindingPairs.Length; j++)
  353. {
  354. result += "," + group.curveBindingPairs[j].curve.Evaluate(t).ToString("0.##");
  355. }
  356. result += ")";
  357. }
  358. else
  359. {
  360. result = group.curveBindingPairs[0].curve.Evaluate(t).ToString("0.##");
  361. }
  362. }
  363. else if (group.isObjectCurve)
  364. {
  365. Object obj = null;
  366. if (group.curveBindingPairs[0].objectCurve.Length > 0)
  367. obj = CurveEditUtility.Evaluate(group.curveBindingPairs[0].objectCurve, t);
  368. result = (obj == null ? "None" : obj.name);
  369. }
  370. return result;
  371. }
  372. }
  373. }