A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using UnityEngine;
5using UnityEngine.Timeline;
6
7namespace UnityEditor.Timeline
8{
9 enum CurveChangeType
10 {
11 None,
12 CurveModified,
13 CurveAddedOrRemoved
14 }
15
16 abstract class CurveDataSource
17 {
18 public static CurveDataSource Create(IRowGUI trackGUI)
19 {
20 if (trackGUI.asset is AnimationTrack)
21 return new InfiniteClipCurveDataSource(trackGUI);
22
23 return new TrackParametersCurveDataSource(trackGUI);
24 }
25
26 public static CurveDataSource Create(TimelineClipGUI clipGUI)
27 {
28 if (clipGUI.clip.animationClip != null)
29 return new ClipAnimationCurveDataSource(clipGUI);
30
31 return new ClipParametersCurveDataSource(clipGUI);
32 }
33
34 int? m_ID = null;
35 public int id
36 {
37 get
38 {
39 if (!m_ID.HasValue)
40 m_ID = CreateHashCode();
41
42 return m_ID.Value;
43 }
44 }
45
46 readonly IRowGUI m_TrackGUI;
47 protected CurveDataSource(IRowGUI trackGUI)
48 {
49 m_TrackGUI = trackGUI;
50 }
51
52 public abstract AnimationClip animationClip { get; }
53
54 public abstract float start { get; }
55 public abstract float timeScale { get; }
56 public abstract string groupingName { get; }
57
58 // Applies changes from the visual curve in the curve wrapper back to the animation clips
59 public virtual void ApplyCurveChanges(IEnumerable<CurveWrapper> updatedCurves)
60 {
61 Undo.RegisterCompleteObjectUndo(animationClip, "Edit Clip Curve");
62 foreach (CurveWrapper c in updatedCurves)
63 {
64 if (c.curve.length > 0)
65 AnimationUtility.SetEditorCurve(animationClip, c.binding, c.curve);
66 else
67 RemoveCurves(new[] { c.binding });
68 c.changed = false;
69 }
70 }
71
72 /// <summary>The clip version is a value that will change when a curve gets updated.
73 /// it's used to detect when an animation clip has been changed externally </summary>
74 /// <returns>A versioning value indicating the state of the curve. If the curve is updated externally this value will change. </returns>
75 public virtual UInt64 GetClipVersion()
76 {
77 return animationClip.ClipVersion();
78 }
79
80 /// <summary>Call this method to check if the underlying clip has changed</summary>
81 /// <param name="curveVersion">A versioning value. This will be updated to the latest version</param>
82 /// <returns>A value indicating how the clip has changed</returns>
83 public virtual CurveChangeType UpdateExternalChanges(ref UInt64 curveVersion)
84 {
85 return animationClip.GetChangeType(ref curveVersion);
86 }
87
88 public virtual string ModifyPropertyDisplayName(string path, string propertyName) => propertyName;
89
90 public virtual void RemoveCurves(IEnumerable<EditorCurveBinding> bindings)
91 {
92 Undo.RegisterCompleteObjectUndo(animationClip, "Remove Curve(s)");
93 foreach (var binding in bindings)
94 {
95 if (binding.isPPtrCurve)
96 AnimationUtility.SetObjectReferenceCurve(animationClip, binding, null);
97 else
98 AnimationUtility.SetEditorCurve(animationClip, binding, null);
99 }
100 }
101
102 public Rect GetBackgroundRect(WindowState state)
103 {
104 var trackRect = m_TrackGUI.boundingRect;
105 return new Rect(
106 state.timeAreaTranslation.x + trackRect.xMin,
107 trackRect.y,
108 (float)state.editSequence.asset.duration * state.timeAreaScale.x,
109 trackRect.height
110 );
111 }
112
113 public List<CurveWrapper> GenerateWrappers(IEnumerable<EditorCurveBinding> bindings)
114 {
115 var wrappers = new List<CurveWrapper>(bindings.Count());
116 int curveWrapperId = 0;
117
118 foreach (EditorCurveBinding b in bindings)
119 {
120 // General configuration
121 var wrapper = new CurveWrapper
122 {
123 id = curveWrapperId++,
124 binding = b,
125 groupId = -1,
126 hidden = false,
127 readOnly = false,
128 getAxisUiScalarsCallback = () => new Vector2(1, 1)
129 };
130
131 // Specific configuration
132 ConfigureCurveWrapper(wrapper);
133
134 wrappers.Add(wrapper);
135 }
136
137 return wrappers;
138 }
139
140 protected virtual void ConfigureCurveWrapper(CurveWrapper wrapper)
141 {
142 wrapper.color = CurveUtility.GetPropertyColor(wrapper.binding.propertyName);
143 wrapper.renderer = new NormalCurveRenderer(AnimationUtility.GetEditorCurve(animationClip, wrapper.binding));
144 wrapper.renderer.SetCustomRange(0.0f, animationClip.length);
145 }
146
147 protected virtual int CreateHashCode()
148 {
149 return m_TrackGUI.asset.GetHashCode();
150 }
151 }
152
153 class ClipAnimationCurveDataSource : CurveDataSource
154 {
155 static readonly string k_GroupingName = L10n.Tr("Animated Values");
156
157 readonly TimelineClipGUI m_ClipGUI;
158
159 public ClipAnimationCurveDataSource(TimelineClipGUI clipGUI) : base(clipGUI.parent)
160 {
161 m_ClipGUI = clipGUI;
162 }
163
164 public override AnimationClip animationClip
165 {
166 get { return m_ClipGUI.clip.animationClip; }
167 }
168
169 public override float start
170 {
171 get { return (float)m_ClipGUI.clip.FromLocalTimeUnbound(0.0); }
172 }
173
174 public override float timeScale
175 {
176 get { return (float)m_ClipGUI.clip.timeScale; }
177 }
178
179 public override string groupingName
180 {
181 get { return k_GroupingName; }
182 }
183
184 protected override int CreateHashCode()
185 {
186 return base.CreateHashCode().CombineHash(m_ClipGUI.clip.GetHashCode());
187 }
188
189 public override string ModifyPropertyDisplayName(string path, string propertyName)
190 {
191 if (!AnimatedPropertyUtility.IsMaterialProperty(propertyName))
192 return propertyName;
193
194 var track = m_ClipGUI.clip.GetParentTrack();
195 if (track == null)
196 return propertyName;
197
198 var gameObjectBinding = TimelineUtility.GetSceneGameObject(TimelineEditor.inspectedDirector, track);
199 if (gameObjectBinding == null)
200 return propertyName;
201
202 if (!string.IsNullOrEmpty(path))
203 {
204 var transform = gameObjectBinding.transform.Find(path);
205 if (transform == null)
206 return propertyName;
207 gameObjectBinding = transform.gameObject;
208 }
209
210 return AnimatedPropertyUtility.RemapMaterialName(gameObjectBinding, propertyName);
211 }
212 }
213
214 class ClipParametersCurveDataSource : CurveDataSource
215 {
216 static readonly string k_GroupingName = L10n.Tr("Clip Properties");
217
218 readonly TimelineClipGUI m_ClipGUI;
219 readonly CurvesProxy m_CurvesProxy;
220
221 private int m_ClipDirtyVersion;
222
223 public ClipParametersCurveDataSource(TimelineClipGUI clipGUI) : base(clipGUI.parent)
224 {
225 m_ClipGUI = clipGUI;
226 m_CurvesProxy = new CurvesProxy(clipGUI.clip);
227 }
228
229 public override AnimationClip animationClip
230 {
231 get { return m_CurvesProxy.curves; }
232 }
233
234 public override UInt64 GetClipVersion()
235 {
236 return sourceAnimationClip.ClipVersion();
237 }
238
239 public override CurveChangeType UpdateExternalChanges(ref ulong curveVersion)
240 {
241 if (m_ClipGUI == null || m_ClipGUI.clip == null)
242 return CurveChangeType.None;
243
244 var changeType = sourceAnimationClip.GetChangeType(ref curveVersion);
245 if (changeType != CurveChangeType.None)
246 {
247 m_CurvesProxy.ApplyExternalChangesToProxy();
248 }
249 else if (m_ClipDirtyVersion != m_ClipGUI.clip.DirtyIndex)
250 {
251 m_CurvesProxy.UpdateProxyCurves();
252 if (changeType == CurveChangeType.None)
253 changeType = CurveChangeType.CurveModified;
254 }
255 m_ClipDirtyVersion = m_ClipGUI.clip.DirtyIndex;
256 return changeType;
257 }
258
259 public override float start
260 {
261 get { return (float)m_ClipGUI.clip.FromLocalTimeUnbound(0.0); }
262 }
263
264 public override float timeScale
265 {
266 get { return (float)m_ClipGUI.clip.timeScale; }
267 }
268
269 public override string groupingName
270 {
271 get { return k_GroupingName; }
272 }
273
274 public override void RemoveCurves(IEnumerable<EditorCurveBinding> bindings)
275 {
276 m_CurvesProxy.RemoveCurves(bindings);
277 }
278
279 public override void ApplyCurveChanges(IEnumerable<CurveWrapper> updatedCurves)
280 {
281 m_CurvesProxy.UpdateCurves(updatedCurves);
282 }
283
284 protected override void ConfigureCurveWrapper(CurveWrapper wrapper)
285 {
286 m_CurvesProxy.ConfigureCurveWrapper(wrapper);
287 }
288
289 protected override int CreateHashCode()
290 {
291 return base.CreateHashCode().CombineHash(m_ClipGUI.clip.GetHashCode());
292 }
293
294 private AnimationClip sourceAnimationClip
295 {
296 get
297 {
298 if (m_ClipGUI == null || m_ClipGUI.clip == null || m_ClipGUI.clip.curves == null)
299 return null;
300 return m_ClipGUI.clip.curves;
301 }
302 }
303 }
304
305 class InfiniteClipCurveDataSource : CurveDataSource
306 {
307 static readonly string k_GroupingName = L10n.Tr("Animated Values");
308
309 readonly AnimationTrack m_AnimationTrack;
310
311 public InfiniteClipCurveDataSource(IRowGUI trackGui) : base(trackGui)
312 {
313 m_AnimationTrack = trackGui.asset as AnimationTrack;
314 }
315
316 public override AnimationClip animationClip
317 {
318 get { return m_AnimationTrack.infiniteClip; }
319 }
320
321 public override float start
322 {
323 get { return 0.0f; }
324 }
325
326 public override float timeScale
327 {
328 get { return 1.0f; }
329 }
330
331 public override string groupingName
332 {
333 get { return k_GroupingName; }
334 }
335
336 public override string ModifyPropertyDisplayName(string path, string propertyName)
337 {
338 if (m_AnimationTrack == null || !AnimatedPropertyUtility.IsMaterialProperty(propertyName))
339 return propertyName;
340
341 var binding = m_AnimationTrack.GetBinding(TimelineEditor.inspectedDirector);
342 if (binding == null)
343 return propertyName;
344
345 var target = binding.transform;
346 if (!string.IsNullOrEmpty(path))
347 target = target.Find(path);
348
349 if (target == null)
350 return propertyName;
351
352 return AnimatedPropertyUtility.RemapMaterialName(target.gameObject, propertyName);
353 }
354 }
355
356 class TrackParametersCurveDataSource : CurveDataSource
357 {
358 static readonly string k_GroupingName = L10n.Tr("Track Properties");
359
360 readonly CurvesProxy m_CurvesProxy;
361 private int m_TrackDirtyVersion;
362
363 public TrackParametersCurveDataSource(IRowGUI trackGui) : base(trackGui)
364 {
365 m_CurvesProxy = new CurvesProxy(trackGui.asset);
366 }
367
368 public override AnimationClip animationClip
369 {
370 get { return m_CurvesProxy.curves; }
371 }
372
373 public override UInt64 GetClipVersion()
374 {
375 return sourceAnimationClip.ClipVersion();
376 }
377
378 public override CurveChangeType UpdateExternalChanges(ref ulong curveVersion)
379 {
380 if (m_CurvesProxy.targetTrack == null)
381 return CurveChangeType.None;
382
383 var changeType = sourceAnimationClip.GetChangeType(ref curveVersion);
384 if (changeType != CurveChangeType.None)
385 {
386 m_CurvesProxy.ApplyExternalChangesToProxy();
387 }
388 // track property has changed externally, update the curve proxies
389 else if (m_TrackDirtyVersion != m_CurvesProxy.targetTrack.DirtyIndex)
390 {
391 if (changeType == CurveChangeType.None)
392 changeType = CurveChangeType.CurveModified;
393 m_CurvesProxy.UpdateProxyCurves();
394 }
395 m_TrackDirtyVersion = m_CurvesProxy.targetTrack.DirtyIndex;
396 return changeType;
397 }
398
399 public override float start
400 {
401 get { return 0.0f; }
402 }
403
404 public override float timeScale
405 {
406 get { return 1.0f; }
407 }
408
409 public override string groupingName
410 {
411 get { return k_GroupingName; }
412 }
413
414 public override void RemoveCurves(IEnumerable<EditorCurveBinding> bindings)
415 {
416 m_CurvesProxy.RemoveCurves(bindings);
417 }
418
419 public override void ApplyCurveChanges(IEnumerable<CurveWrapper> updatedCurves)
420 {
421 m_CurvesProxy.UpdateCurves(updatedCurves);
422 }
423
424 protected override void ConfigureCurveWrapper(CurveWrapper wrapper)
425 {
426 m_CurvesProxy.ConfigureCurveWrapper(wrapper);
427 }
428
429 private AnimationClip sourceAnimationClip
430 {
431 get
432 {
433 if (m_CurvesProxy.targetTrack == null || m_CurvesProxy.targetTrack.curves == null)
434 return null;
435 return m_CurvesProxy.targetTrack.curves;
436 }
437 }
438 }
439}