CurvesProxy.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using JetBrains.Annotations;
  5. using UnityEngine;
  6. using UnityEngine.Timeline;
  7. using UnityObject = UnityEngine.Object;
  8. namespace UnityEditor.Timeline
  9. {
  10. class CurvesProxy : ICurvesOwner
  11. {
  12. public AnimationClip curves
  13. {
  14. get { return proxyCurves != null ? proxyCurves : m_OriginalOwner.curves; }
  15. }
  16. public bool hasCurves
  17. {
  18. get { return m_IsAnimatable || m_OriginalOwner.hasCurves; }
  19. }
  20. public double duration
  21. {
  22. get { return m_OriginalOwner.duration; }
  23. }
  24. public string defaultCurvesName
  25. {
  26. get { return m_OriginalOwner.defaultCurvesName; }
  27. }
  28. public UnityObject asset
  29. {
  30. get { return m_OriginalOwner.asset; }
  31. }
  32. public UnityObject assetOwner
  33. {
  34. get { return m_OriginalOwner.assetOwner; }
  35. }
  36. public TrackAsset targetTrack
  37. {
  38. get { return m_OriginalOwner.targetTrack; }
  39. }
  40. readonly ICurvesOwner m_OriginalOwner;
  41. readonly bool m_IsAnimatable;
  42. readonly Dictionary<EditorCurveBinding, SerializedProperty> m_PropertiesMap = new Dictionary<EditorCurveBinding, SerializedProperty>();
  43. int m_ProxyIsRebuilding = 0;
  44. AnimationClip m_ProxyCurves;
  45. AnimationClip proxyCurves
  46. {
  47. get
  48. {
  49. if (!m_IsAnimatable) return null;
  50. if (m_ProxyCurves == null)
  51. RebuildProxyCurves();
  52. return m_ProxyCurves;
  53. }
  54. }
  55. List<SerializedProperty> m_AllAnimatableParameters;
  56. List<SerializedProperty> allAnimatableParameters
  57. {
  58. get
  59. {
  60. var so = AnimatedParameterUtility.GetSerializedPlayableAsset(m_OriginalOwner.asset);
  61. if (so == null)
  62. return null;
  63. so.UpdateIfRequiredOrScript();
  64. if (m_AllAnimatableParameters == null)
  65. m_AllAnimatableParameters = m_OriginalOwner.GetAllAnimatableParameters().ToList();
  66. return m_AllAnimatableParameters;
  67. }
  68. }
  69. public CurvesProxy([NotNull] ICurvesOwner originalOwner)
  70. {
  71. m_OriginalOwner = originalOwner;
  72. m_IsAnimatable = originalOwner.HasAnyAnimatableParameters();
  73. RebuildProxyCurves();
  74. }
  75. public void CreateCurves(string curvesClipName)
  76. {
  77. m_OriginalOwner.CreateCurves(curvesClipName);
  78. }
  79. public void ConfigureCurveWrapper(CurveWrapper wrapper)
  80. {
  81. var color = CurveUtility.GetPropertyColor(wrapper.binding.propertyName);
  82. wrapper.color = color;
  83. float h, s, v;
  84. Color.RGBToHSV(color, out h, out s, out v);
  85. wrapper.wrapColorMultiplier = Color.HSVToRGB(h, s * 0.33f, v * 1.15f);
  86. var curve = AnimationUtility.GetEditorCurve(proxyCurves, wrapper.binding);
  87. wrapper.renderer = new NormalCurveRenderer(curve);
  88. // Use curve length instead of animation clip length
  89. wrapper.renderer.SetCustomRange(0.0f, curve.keys.Last().time);
  90. }
  91. public void RebuildCurves()
  92. {
  93. RebuildProxyCurves();
  94. }
  95. public void UpdateCurves(List<CurveWrapper> updatedCurves)
  96. {
  97. if (m_ProxyIsRebuilding > 0)
  98. return;
  99. Undo.RegisterCompleteObjectUndo(m_OriginalOwner.asset, "Edit Clip Curve");
  100. if (m_OriginalOwner.curves != null)
  101. Undo.RegisterCompleteObjectUndo(m_OriginalOwner.curves, "Edit Clip Curve");
  102. foreach (var curve in updatedCurves)
  103. {
  104. UpdateCurve(curve.binding, curve.curve);
  105. }
  106. AnimatedParameterUtility.UpdateSerializedPlayableAsset(m_OriginalOwner.asset);
  107. }
  108. void UpdateCurve(EditorCurveBinding binding, AnimationCurve curve)
  109. {
  110. ApplyConstraints(binding, curve);
  111. if (curve.length == 0)
  112. {
  113. HandleAllKeysDeleted(binding);
  114. }
  115. else if (curve.length == 1)
  116. {
  117. HandleConstantCurveValueChanged(binding, curve);
  118. }
  119. else
  120. {
  121. HandleCurveUpdated(binding, curve);
  122. }
  123. }
  124. void ApplyConstraints(EditorCurveBinding binding, AnimationCurve curve)
  125. {
  126. if (curve.length == 0)
  127. return;
  128. var curveUpdated = false;
  129. var property = m_PropertiesMap[binding];
  130. if (property.propertyType == SerializedPropertyType.Boolean)
  131. {
  132. TimelineAnimationUtilities.ConstrainCurveToBooleanValues(curve);
  133. curveUpdated = true;
  134. }
  135. else
  136. {
  137. var range = AnimatedParameterUtility.GetAttributeForProperty<RangeAttribute>(property);
  138. if (range != null)
  139. {
  140. TimelineAnimationUtilities.ConstrainCurveToRange(curve, range.min, range.max);
  141. curveUpdated = true;
  142. }
  143. }
  144. if (!curveUpdated)
  145. return;
  146. using (new RebuildGuard(this))
  147. {
  148. AnimationUtility.SetEditorCurve(m_ProxyCurves, binding, curve);
  149. }
  150. }
  151. void HandleCurveUpdated(EditorCurveBinding binding, AnimationCurve updatedCurve)
  152. {
  153. if (!m_OriginalOwner.hasCurves)
  154. m_OriginalOwner.CreateCurves(null);
  155. AnimationUtility.SetEditorCurve(m_OriginalOwner.curves, binding, updatedCurve);
  156. }
  157. void HandleConstantCurveValueChanged(EditorCurveBinding binding, AnimationCurve updatedCurve)
  158. {
  159. var prop = m_PropertiesMap[binding];
  160. if (prop == null)
  161. return;
  162. Undo.RegisterCompleteObjectUndo(prop.serializedObject.targetObject, "Edit Clip Curve");
  163. prop.serializedObject.UpdateIfRequiredOrScript();
  164. CurveEditUtility.SetFromKeyValue(prop, updatedCurve.keys[0].value);
  165. prop.serializedObject.ApplyModifiedProperties();
  166. }
  167. void HandleAllKeysDeleted(EditorCurveBinding binding)
  168. {
  169. if (m_OriginalOwner.hasCurves)
  170. {
  171. // Remove curve from original asset
  172. AnimationUtility.SetEditorCurve(m_OriginalOwner.curves, binding, null);
  173. m_OriginalOwner.SanitizeCurvesData();
  174. }
  175. // Ensure proxy still has constant value
  176. RebuildProxyCurves();
  177. }
  178. void RebuildProxyCurves()
  179. {
  180. if (!m_IsAnimatable)
  181. return;
  182. using (new RebuildGuard(this))
  183. {
  184. if (m_ProxyCurves == null)
  185. {
  186. m_ProxyCurves = new AnimationClip
  187. {
  188. legacy = true,
  189. name = "Constant Curves",
  190. hideFlags = HideFlags.HideAndDontSave,
  191. frameRate = m_OriginalOwner.targetTrack.timelineAsset == null
  192. ? TimelineAsset.EditorSettings.kDefaultFps
  193. : m_OriginalOwner.targetTrack.timelineAsset.editorSettings.fps
  194. };
  195. }
  196. else
  197. {
  198. m_ProxyCurves.ClearCurves();
  199. }
  200. m_OriginalOwner.SanitizeCurvesData();
  201. AnimatedParameterUtility.UpdateSerializedPlayableAsset(m_OriginalOwner.asset);
  202. foreach (var param in allAnimatableParameters)
  203. CreateProxyCurve(param, m_ProxyCurves, m_OriginalOwner.asset, param.propertyPath);
  204. AnimationClipCurveCache.Instance.GetCurveInfo(m_ProxyCurves).dirty = true;
  205. }
  206. }
  207. void CreateProxyCurve(SerializedProperty prop, AnimationClip clip, UnityObject owner, string propertyName)
  208. {
  209. var binding = AnimatedParameterUtility.GetCurveBinding(owner, propertyName);
  210. var originalCurve = m_OriginalOwner.hasCurves
  211. ? AnimationUtility.GetEditorCurve(m_OriginalOwner.curves, binding)
  212. : null;
  213. if (originalCurve != null)
  214. {
  215. AnimationUtility.SetEditorCurve(clip, binding, originalCurve);
  216. }
  217. else
  218. {
  219. var curve = new AnimationCurve();
  220. CurveEditUtility.AddKeyFrameToCurve(
  221. curve, 0.0f, clip.frameRate, CurveEditUtility.GetKeyValue(prop),
  222. prop.propertyType == SerializedPropertyType.Boolean);
  223. AnimationUtility.SetEditorCurve(clip, binding, curve);
  224. }
  225. m_PropertiesMap[binding] = prop;
  226. }
  227. struct RebuildGuard : IDisposable
  228. {
  229. CurvesProxy m_Owner;
  230. AnimationUtility.OnCurveWasModified m_Callback;
  231. public RebuildGuard(CurvesProxy owner)
  232. {
  233. m_Callback = AnimationUtility.onCurveWasModified;
  234. AnimationUtility.onCurveWasModified = null;
  235. m_Owner = owner;
  236. m_Owner.m_ProxyIsRebuilding++;
  237. }
  238. public void Dispose()
  239. {
  240. AnimationUtility.onCurveWasModified = m_Callback;
  241. m_Owner.m_ProxyIsRebuilding--;
  242. m_Owner = null;
  243. }
  244. }
  245. }
  246. }