暫無描述
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.

WindowState.cs 39KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEditorInternal;
  5. #if UNITY_2021_2_OR_NEWER
  6. using UnityEditor.SceneManagement;
  7. #else
  8. using UnityEditor.Experimental.SceneManagement;
  9. #endif
  10. using UnityEngine;
  11. using UnityEngine.Playables;
  12. using UnityEngine.Timeline;
  13. #if !UNITY_2020_2_OR_NEWER
  14. using UnityEngine.Experimental.Animations;
  15. #endif
  16. using UnityEngine.Animations;
  17. using Object = System.Object;
  18. namespace UnityEditor.Timeline
  19. {
  20. delegate bool PendingUpdateDelegate(WindowState state, Event currentEvent);
  21. /// <summary>
  22. /// Interface for faking purposes
  23. /// </summary>
  24. interface IWindowState
  25. {
  26. ISequenceState masterSequence { get; }
  27. ISequenceState editSequence { get; }
  28. IEnumerable<ISequenceState> allSequences { get; }
  29. PlayRange playRange { get; set; }
  30. void SetCurrentSequence(TimelineAsset timelineAsset, PlayableDirector director, TimelineClip hostClip);
  31. void PopSequencesUntilCount(int count);
  32. IEnumerable<SequenceContext> GetSubSequences();
  33. void SetPlaying(bool start);
  34. }
  35. class WindowState : IWindowState
  36. {
  37. const int k_TimeCodeTextFieldId = 3790;
  38. readonly TimelineWindow m_Window;
  39. bool m_Recording;
  40. readonly SpacePartitioner m_SpacePartitioner = new SpacePartitioner();
  41. readonly SpacePartitioner m_HeaderSpacePartitioner = new SpacePartitioner();
  42. readonly List<Manipulator> m_CaptureSession = new List<Manipulator>();
  43. int m_DirtyStamp;
  44. float m_BindingAreaWidth = WindowConstants.defaultBindingAreaWidth;
  45. bool m_MustRebuildGraph;
  46. float m_LastTime;
  47. readonly PropertyCollector m_PropertyCollector = new PropertyCollector();
  48. static AnimationModeDriver s_PreviewDriver;
  49. PreviewedBindings<Animator> m_PreviewedAnimators;
  50. List<Component> m_PreviewedComponents;
  51. IEnumerable<IAnimationWindowPreview> previewedComponents =>
  52. m_PreviewedComponents.Where(component => component != null).Cast<IAnimationWindowPreview>();
  53. public static double kTimeEpsilon { get { return TimeUtility.kTimeEpsilon; } }
  54. public static readonly float kMaxShownTime = (float)TimeUtility.k_MaxTimelineDurationInSeconds;
  55. static readonly ISequenceState k_NullSequenceState = new NullSequenceState();
  56. // which tracks are armed for record - only one allowed per 'actor'
  57. Dictionary<TrackAsset, TrackAsset> m_ArmedTracks = new Dictionary<TrackAsset, TrackAsset>();
  58. TimelineWindow.TimelineWindowPreferences m_Preferences;
  59. List<PendingUpdateDelegate> m_OnStartFrameUpdates;
  60. List<PendingUpdateDelegate> m_OnEndFrameUpdates;
  61. readonly SequenceHierarchy m_SequenceHierarchy;
  62. public event Action<WindowState, Event> windowOnGuiStarted;
  63. public event Action<bool> OnPlayStateChange;
  64. public event System.Action OnDirtyStampChange;
  65. public event System.Action OnRebuildGraphChange;
  66. public event System.Action OnTimeChange;
  67. public event System.Action OnRecordingChange;
  68. public event System.Action OnBeforeSequenceChange;
  69. public event System.Action OnAfterSequenceChange;
  70. public WindowState(TimelineWindow w, SequenceHierarchy hierarchy)
  71. {
  72. m_Window = w;
  73. m_Preferences = w.preferences;
  74. hierarchy.Init(this);
  75. m_SequenceHierarchy = hierarchy;
  76. TimelinePlayable.muteAudioScrubbing = muteAudioScrubbing;
  77. }
  78. public static AnimationModeDriver previewDriver
  79. {
  80. get
  81. {
  82. if (s_PreviewDriver == null)
  83. {
  84. s_PreviewDriver = ScriptableObject.CreateInstance<AnimationModeDriver>();
  85. AnimationPreviewUtilities.s_PreviewDriver = s_PreviewDriver;
  86. }
  87. return s_PreviewDriver;
  88. }
  89. }
  90. public EditorWindow editorWindow
  91. {
  92. get { return m_Window; }
  93. }
  94. public ISequenceState editSequence
  95. {
  96. get
  97. {
  98. // Using "null" ISequenceState to avoid checking against null all the time.
  99. // This *should* be removed in a phase 2 of refactoring, where we make sure
  100. // to pass around the correct state object instead of letting clients dig
  101. // into the WindowState for whatever they want.
  102. return m_SequenceHierarchy.editSequence ?? k_NullSequenceState;
  103. }
  104. }
  105. public ISequenceState masterSequence
  106. {
  107. get { return m_SequenceHierarchy.masterSequence ?? k_NullSequenceState; }
  108. }
  109. public ISequenceState referenceSequence
  110. {
  111. get { return timeReferenceMode == TimeReferenceMode.Local ? editSequence : masterSequence; }
  112. }
  113. public IEnumerable<ISequenceState> allSequences
  114. {
  115. get { return m_SequenceHierarchy.allSequences; }
  116. }
  117. public bool rebuildGraph
  118. {
  119. get { return m_MustRebuildGraph; }
  120. set { SyncNotifyValue(ref m_MustRebuildGraph, value, OnRebuildGraphChange); }
  121. }
  122. public float mouseDragLag { get; set; }
  123. public SpacePartitioner spacePartitioner
  124. {
  125. get { return m_SpacePartitioner; }
  126. }
  127. public SpacePartitioner headerSpacePartitioner
  128. {
  129. get { return m_HeaderSpacePartitioner; }
  130. }
  131. public List<Manipulator> captured
  132. {
  133. get { return m_CaptureSession; }
  134. }
  135. public void AddCaptured(Manipulator manipulator)
  136. {
  137. if (!m_CaptureSession.Contains(manipulator))
  138. m_CaptureSession.Add(manipulator);
  139. }
  140. public void RemoveCaptured(Manipulator manipulator)
  141. {
  142. m_CaptureSession.Remove(manipulator);
  143. }
  144. public bool isJogging { get; set; }
  145. public int viewStateHash { get; private set; }
  146. public float bindingAreaWidth
  147. {
  148. get { return m_BindingAreaWidth; }
  149. set { m_BindingAreaWidth = value; }
  150. }
  151. public float sequencerHeaderWidth
  152. {
  153. get { return editSequence.viewModel.sequencerHeaderWidth; }
  154. set
  155. {
  156. editSequence.viewModel.sequencerHeaderWidth = Mathf.Clamp(value, WindowConstants.minHeaderWidth, WindowConstants.maxHeaderWidth);
  157. }
  158. }
  159. public float mainAreaWidth { get; set; }
  160. public float trackScale
  161. {
  162. get { return editSequence.viewModel.trackScale; }
  163. set
  164. {
  165. editSequence.viewModel.trackScale = value;
  166. m_Window.treeView.CalculateRowRects();
  167. }
  168. }
  169. public int dirtyStamp
  170. {
  171. get { return m_DirtyStamp; }
  172. private set { SyncNotifyValue(ref m_DirtyStamp, value, OnDirtyStampChange); }
  173. }
  174. public bool showQuadTree { get; set; }
  175. public bool canRecord
  176. {
  177. get { return AnimationMode.InAnimationMode(previewDriver) || !AnimationMode.InAnimationMode(); }
  178. }
  179. public bool recording
  180. {
  181. get
  182. {
  183. if (!previewMode)
  184. m_Recording = false;
  185. return m_Recording;
  186. }
  187. // set can only be used to disable recording
  188. set
  189. {
  190. if (ignorePreview)
  191. return;
  192. // force preview mode on
  193. if (value)
  194. previewMode = true;
  195. bool newValue = value;
  196. if (!previewMode)
  197. newValue = false;
  198. if (newValue && m_ArmedTracks.Count == 0)
  199. {
  200. Debug.LogError("Cannot enable recording without an armed track");
  201. newValue = false;
  202. }
  203. if (!newValue)
  204. m_ArmedTracks.Clear();
  205. if (newValue != m_Recording)
  206. {
  207. if (newValue)
  208. AnimationMode.StartAnimationRecording();
  209. else
  210. AnimationMode.StopAnimationRecording();
  211. InspectorWindow.RepaintAllInspectors();
  212. }
  213. SyncNotifyValue(ref m_Recording, newValue, OnRecordingChange);
  214. }
  215. }
  216. public bool previewMode
  217. {
  218. get { return ignorePreview || AnimationMode.InAnimationMode(previewDriver); }
  219. set
  220. {
  221. if (ignorePreview)
  222. return;
  223. bool inAnimationMode = AnimationMode.InAnimationMode(previewDriver);
  224. if (!value)
  225. {
  226. if (inAnimationMode)
  227. {
  228. Stop();
  229. OnStopPreview();
  230. AnimationMode.StopAnimationMode(previewDriver);
  231. AnimationPropertyContextualMenu.Instance.SetResponder(null);
  232. previewedDirectors = null;
  233. }
  234. }
  235. else if (!inAnimationMode)
  236. {
  237. editSequence.time = editSequence.viewModel.windowTime;
  238. EvaluateImmediate(); // does appropriate caching prior to enabling
  239. }
  240. }
  241. }
  242. public bool playing
  243. {
  244. get
  245. {
  246. return masterSequence.director != null && masterSequence.director.state == PlayState.Playing;
  247. }
  248. }
  249. public float playbackSpeed { get; set; }
  250. public bool frameSnap
  251. {
  252. get { return TimelinePreferences.instance.snapToFrame; }
  253. set { TimelinePreferences.instance.snapToFrame = value; }
  254. }
  255. public bool edgeSnaps
  256. {
  257. get { return TimelinePreferences.instance.edgeSnap; }
  258. set { TimelinePreferences.instance.edgeSnap = value; }
  259. }
  260. public bool muteAudioScrubbing
  261. {
  262. get { return !TimelinePreferences.instance.audioScrubbing; }
  263. set
  264. {
  265. TimelinePreferences.instance.audioScrubbing = !value;
  266. TimelinePlayable.muteAudioScrubbing = value;
  267. RebuildPlayableGraph();
  268. }
  269. }
  270. public TimeReferenceMode timeReferenceMode
  271. {
  272. get { return m_Preferences.timeReferenceMode; }
  273. set { m_Preferences.timeReferenceMode = value; }
  274. }
  275. public TimeFormat timeFormat
  276. {
  277. get { return TimelinePreferences.instance.timeFormat; }
  278. set { TimelinePreferences.instance.timeFormat = value; }
  279. }
  280. public bool showAudioWaveform
  281. {
  282. get { return TimelinePreferences.instance.showAudioWaveform; }
  283. set { TimelinePreferences.instance.showAudioWaveform = value; }
  284. }
  285. public PlayRange playRange
  286. {
  287. get { return masterSequence.viewModel.timeAreaPlayRange; }
  288. set { masterSequence.viewModel.timeAreaPlayRange = ValidatePlayRange(value, masterSequence); }
  289. }
  290. public bool showMarkerHeader
  291. {
  292. get { return editSequence.asset != null && editSequence.asset.markerTrack != null && editSequence.asset.markerTrack.GetShowMarkers(); }
  293. set { GetWindow().SetShowMarkerHeader(value); }
  294. }
  295. public EditMode.EditType editType
  296. {
  297. get { return m_Preferences.editType; }
  298. set { m_Preferences.editType = value; }
  299. }
  300. public PlaybackScrollMode autoScrollMode
  301. {
  302. get { return TimelinePreferences.instance.playbackScrollMode; }
  303. set { TimelinePreferences.instance.playbackScrollMode = value; }
  304. }
  305. public List<PlayableDirector> previewedDirectors { get; private set; }
  306. public void OnDestroy()
  307. {
  308. if (!ignorePreview)
  309. Stop();
  310. if (m_OnStartFrameUpdates != null)
  311. m_OnStartFrameUpdates.Clear();
  312. if (m_OnEndFrameUpdates != null)
  313. m_OnEndFrameUpdates.Clear();
  314. m_SequenceHierarchy.Clear();
  315. windowOnGuiStarted = null;
  316. }
  317. public void OnSceneSaved()
  318. {
  319. // the director will reset it's time when the scene is saved.
  320. EnsureWindowTimeConsistency();
  321. }
  322. public void SetCurrentSequence(TimelineAsset timelineAsset, PlayableDirector director, TimelineClip hostClip)
  323. {
  324. if (OnBeforeSequenceChange != null)
  325. OnBeforeSequenceChange.Invoke();
  326. OnCurrentDirectorWillChange();
  327. if (hostClip == null || timelineAsset == null)
  328. {
  329. m_PropertyCollector.Clear();
  330. m_SequenceHierarchy.Clear();
  331. }
  332. if (timelineAsset != null)
  333. m_SequenceHierarchy.Add(timelineAsset, director, hostClip);
  334. if (OnAfterSequenceChange != null)
  335. OnAfterSequenceChange.Invoke();
  336. }
  337. public void PopSequencesUntilCount(int count)
  338. {
  339. if (count >= m_SequenceHierarchy.count) return;
  340. if (count < 1) return;
  341. if (OnBeforeSequenceChange != null)
  342. OnBeforeSequenceChange.Invoke();
  343. var nextDirector = m_SequenceHierarchy.GetStateAtIndex(count - 1).director;
  344. OnCurrentDirectorWillChange();
  345. m_SequenceHierarchy.RemoveUntilCount(count);
  346. EnsureWindowTimeConsistency();
  347. if (OnAfterSequenceChange != null)
  348. OnAfterSequenceChange.Invoke();
  349. }
  350. public SequencePath GetCurrentSequencePath()
  351. {
  352. return m_SequenceHierarchy.ToSequencePath();
  353. }
  354. public void SetCurrentSequencePath(SequencePath path, bool forceRebuild)
  355. {
  356. if (!m_SequenceHierarchy.NeedsUpdate(path, forceRebuild))
  357. return;
  358. if (OnBeforeSequenceChange != null)
  359. OnBeforeSequenceChange.Invoke();
  360. m_SequenceHierarchy.FromSequencePath(path, forceRebuild);
  361. if (OnAfterSequenceChange != null)
  362. OnAfterSequenceChange.Invoke();
  363. }
  364. public IEnumerable<ISequenceState> GetAllSequences()
  365. {
  366. return m_SequenceHierarchy.allSequences;
  367. }
  368. public IEnumerable<SequenceContext> GetSubSequences()
  369. {
  370. var contexts =
  371. editSequence.asset?.flattenedTracks
  372. .SelectMany(x => x.clips)
  373. .Where((TimelineUtility.HasCustomEditor))
  374. .SelectMany((clip =>
  375. TimelineUtility.GetSubTimelines(clip, TimelineEditor.inspectedDirector)
  376. .Select(director => new SequenceContext(director, clip))));
  377. return contexts;
  378. }
  379. public void Reset()
  380. {
  381. recording = false;
  382. previewMode = false;
  383. }
  384. public double GetSnappedTimeAtMousePosition(Vector2 mousePos)
  385. {
  386. return TimeReferenceUtility.SnapToFrameIfRequired(ScreenSpacePixelToTimeAreaTime(mousePos.x));
  387. }
  388. static void SyncNotifyValue<T>(ref T oldValue, T newValue, System.Action changeStateCallback)
  389. {
  390. var stateChanged = false;
  391. if (oldValue == null)
  392. {
  393. oldValue = newValue;
  394. stateChanged = true;
  395. }
  396. else
  397. {
  398. if (!oldValue.Equals(newValue))
  399. {
  400. oldValue = newValue;
  401. stateChanged = true;
  402. }
  403. }
  404. if (stateChanged && changeStateCallback != null)
  405. {
  406. changeStateCallback.Invoke();
  407. }
  408. }
  409. public TimelineWindowAnalytics analytics = new TimelineWindowAnalytics();
  410. public void SetTimeAreaTransform(Vector2 newTranslation, Vector2 newScale)
  411. {
  412. m_Window.timeArea.SetTransform(newTranslation, newScale);
  413. TimeAreaChanged();
  414. }
  415. public void SetTimeAreaShownRange(float min, float max)
  416. {
  417. m_Window.timeArea.SetShownHRange(min, max);
  418. TimeAreaChanged();
  419. }
  420. internal void TimeAreaChanged()
  421. {
  422. if (editSequence.asset != null)
  423. {
  424. editSequence.viewModel.timeAreaShownRange = new Vector2(m_Window.timeArea.shownArea.x, m_Window.timeArea.shownArea.xMax);
  425. }
  426. }
  427. public void ResetPreviewMode()
  428. {
  429. var mode = previewMode;
  430. previewMode = false;
  431. previewMode = mode;
  432. }
  433. public bool TimeIsInRange(float value)
  434. {
  435. Rect shownArea = m_Window.timeArea.shownArea;
  436. return value >= shownArea.x && value <= shownArea.xMax;
  437. }
  438. public bool RangeIsVisible(Range range)
  439. {
  440. var shownArea = m_Window.timeArea.shownArea;
  441. return range.start < shownArea.xMax && range.end > shownArea.xMin;
  442. }
  443. public void EnsurePlayHeadIsVisible()
  444. {
  445. double minDisplayedTime = PixelToTime(timeAreaRect.xMin);
  446. double maxDisplayedTime = PixelToTime(timeAreaRect.xMax);
  447. double currentTime = editSequence.time;
  448. if (currentTime >= minDisplayedTime && currentTime <= maxDisplayedTime)
  449. return;
  450. float displayedTimeRange = (float)(maxDisplayedTime - minDisplayedTime);
  451. float minimumTimeToDisplay = (float)currentTime - displayedTimeRange / 2.0f;
  452. float maximumTimeToDisplay = (float)currentTime + displayedTimeRange / 2.0f;
  453. SetTimeAreaShownRange(minimumTimeToDisplay, maximumTimeToDisplay);
  454. }
  455. public void SetPlayHeadToMiddle()
  456. {
  457. double minDisplayedTime = PixelToTime(timeAreaRect.xMin);
  458. double maxDisplayedTime = PixelToTime(timeAreaRect.xMax);
  459. double currentTime = editSequence.time;
  460. float displayedTimeRange = (float)(maxDisplayedTime - minDisplayedTime);
  461. if (currentTime >= minDisplayedTime && currentTime <= maxDisplayedTime)
  462. {
  463. if (currentTime < minDisplayedTime + displayedTimeRange / 2)
  464. return;
  465. }
  466. const float kCatchUpSpeed = 3f;
  467. float realDelta = Mathf.Clamp(Time.realtimeSinceStartup - m_LastTime, 0f, 1f) * kCatchUpSpeed;
  468. float scrollCatchupAmount = kCatchUpSpeed * realDelta * displayedTimeRange / 2;
  469. if (currentTime < minDisplayedTime)
  470. {
  471. SetTimeAreaShownRange((float)currentTime, (float)currentTime + displayedTimeRange);
  472. }
  473. else if (currentTime > maxDisplayedTime)
  474. {
  475. SetTimeAreaShownRange((float)currentTime - displayedTimeRange + scrollCatchupAmount, (float)currentTime + scrollCatchupAmount);
  476. }
  477. else if (currentTime > minDisplayedTime + displayedTimeRange / 2)
  478. {
  479. float targetMinDisplayedTime = Mathf.Min((float)minDisplayedTime + scrollCatchupAmount,
  480. (float)(currentTime - displayedTimeRange / 2));
  481. SetTimeAreaShownRange(targetMinDisplayedTime, targetMinDisplayedTime + displayedTimeRange);
  482. }
  483. }
  484. internal void UpdateLastFrameTime()
  485. {
  486. m_LastTime = Time.realtimeSinceStartup;
  487. }
  488. public Vector2 timeAreaShownRange
  489. {
  490. get
  491. {
  492. if (m_Window.state.editSequence.asset != null)
  493. return editSequence.viewModel.timeAreaShownRange;
  494. return TimelineAssetViewModel.TimeAreaDefaultRange;
  495. }
  496. set
  497. {
  498. SetTimeAreaShownRange(value.x, value.y);
  499. }
  500. }
  501. public Vector2 timeAreaTranslation
  502. {
  503. get { return m_Window.timeArea.translation; }
  504. }
  505. public Vector2 timeAreaScale
  506. {
  507. get { return m_Window.timeArea.scale; }
  508. }
  509. public Rect timeAreaRect
  510. {
  511. get
  512. {
  513. var sequenceContentRect = m_Window.sequenceContentRect;
  514. return new Rect(
  515. sequenceContentRect.x,
  516. WindowConstants.timeAreaYPosition,
  517. Mathf.Max(sequenceContentRect.width, WindowConstants.timeAreaMinWidth),
  518. WindowConstants.timeAreaHeight
  519. );
  520. }
  521. }
  522. public float windowHeight
  523. {
  524. get { return m_Window.position.height; }
  525. }
  526. public bool playRangeEnabled
  527. {
  528. get { return !ignorePreview && masterSequence.viewModel.playRangeEnabled && !IsEditingASubTimeline(); }
  529. set
  530. {
  531. if (!ignorePreview)
  532. masterSequence.viewModel.playRangeEnabled = value;
  533. }
  534. }
  535. public bool ignorePreview
  536. {
  537. get
  538. {
  539. var shouldIgnorePreview = masterSequence.asset != null && !masterSequence.asset.editorSettings.scenePreview;
  540. return Application.isPlaying || shouldIgnorePreview;
  541. }
  542. }
  543. public TimelineWindow GetWindow()
  544. {
  545. return m_Window;
  546. }
  547. public void Play()
  548. {
  549. if (masterSequence.director == null)
  550. return;
  551. if (!previewMode)
  552. previewMode = true;
  553. if (previewMode)
  554. {
  555. if (masterSequence.time > masterSequence.duration)
  556. masterSequence.time = 0;
  557. #if TIMELINE_FRAMEACCURATE
  558. if (TimelinePreferences.instance.playbackLockedToFrame)
  559. {
  560. FrameRate frameRate = FrameRate.DoubleToFrameRate(masterSequence.asset.editorSettings.frameRate);
  561. masterSequence.director.Play(frameRate);
  562. }
  563. else
  564. {
  565. masterSequence.director.Play();
  566. }
  567. #else
  568. masterSequence.director.Play();
  569. #endif
  570. masterSequence.director.ProcessPendingGraphChanges();
  571. PlayableDirector.ResetFrameTiming();
  572. InvokePlayStateChangeCallback(true);
  573. }
  574. }
  575. public void Pause()
  576. {
  577. if (masterSequence.director != null)
  578. {
  579. masterSequence.director.Pause();
  580. masterSequence.director.ProcessPendingGraphChanges();
  581. SynchronizeSequencesAfterPlayback();
  582. InvokePlayStateChangeCallback(false);
  583. }
  584. }
  585. public void SetPlaying(bool start)
  586. {
  587. if (start && !playing)
  588. {
  589. Play();
  590. }
  591. if (!start && playing)
  592. {
  593. Pause();
  594. }
  595. analytics.SendPlayEvent(start);
  596. }
  597. public void Stop()
  598. {
  599. if (masterSequence.director != null)
  600. {
  601. masterSequence.director.Stop();
  602. masterSequence.director.ProcessPendingGraphChanges();
  603. InvokePlayStateChangeCallback(false);
  604. }
  605. }
  606. void InvokePlayStateChangeCallback(bool isPlaying)
  607. {
  608. if (OnPlayStateChange != null)
  609. OnPlayStateChange.Invoke(isPlaying);
  610. }
  611. public void RebuildPlayableGraph()
  612. {
  613. if (masterSequence.director != null)
  614. {
  615. masterSequence.director.RebuildGraph();
  616. // rebuild both the parent and the edit sequences. control tracks don't necessary
  617. // rebuild the subdirector on recreation
  618. if (editSequence.director != null && editSequence.director != masterSequence.director)
  619. {
  620. editSequence.director.RebuildGraph();
  621. }
  622. }
  623. }
  624. public void Evaluate()
  625. {
  626. if (masterSequence.director != null)
  627. {
  628. if (!EditorApplication.isPlaying && !previewMode)
  629. GatherProperties(masterSequence.director);
  630. ForceTimeOnDirector(masterSequence.director);
  631. masterSequence.director.DeferredEvaluate();
  632. if (EditorApplication.isPlaying == false)
  633. {
  634. PlayModeView.RepaintAll();
  635. SceneView.RepaintAll();
  636. AudioMixerWindow.RepaintAudioMixerWindow();
  637. }
  638. }
  639. }
  640. public void EvaluateImmediate()
  641. {
  642. if (masterSequence.director != null && masterSequence.director.isActiveAndEnabled)
  643. {
  644. if (!EditorApplication.isPlaying && !previewMode)
  645. GatherProperties(masterSequence.director);
  646. if (previewMode)
  647. {
  648. ForceTimeOnDirector(masterSequence.director);
  649. masterSequence.director.ProcessPendingGraphChanges();
  650. masterSequence.director.Evaluate();
  651. }
  652. }
  653. }
  654. public void Refresh()
  655. {
  656. CheckRecordingState();
  657. dirtyStamp = dirtyStamp + 1;
  658. rebuildGraph = true;
  659. }
  660. public void UpdateViewStateHash()
  661. {
  662. viewStateHash = timeAreaTranslation.GetHashCode()
  663. .CombineHash(timeAreaScale.GetHashCode())
  664. .CombineHash(trackScale.GetHashCode());
  665. }
  666. public bool IsEditingASubTimeline()
  667. {
  668. return editSequence != masterSequence;
  669. }
  670. public bool IsEditingAnEmptyTimeline()
  671. {
  672. return editSequence.asset == null;
  673. }
  674. public bool IsEditingAPrefabAsset()
  675. {
  676. var stage = PrefabStageUtility.GetCurrentPrefabStage();
  677. return stage != null && editSequence.director != null && stage.IsPartOfPrefabContents(editSequence.director.gameObject);
  678. }
  679. public bool IsCurrentEditingASequencerTextField()
  680. {
  681. if (editSequence.asset == null)
  682. return false;
  683. if (k_TimeCodeTextFieldId == GUIUtility.keyboardControl)
  684. return true;
  685. return editSequence.asset.flattenedTracks.Count(t => t.GetInstanceID() == GUIUtility.keyboardControl) != 0;
  686. }
  687. public float TimeToTimeAreaPixel(double t) // TimeToTimeAreaPixel
  688. {
  689. float pixelX = (float)t;
  690. pixelX *= timeAreaScale.x;
  691. pixelX += timeAreaTranslation.x + sequencerHeaderWidth;
  692. return pixelX;
  693. }
  694. public float TimeToScreenSpacePixel(double time)
  695. {
  696. float pixelX = (float)time;
  697. pixelX *= timeAreaScale.x;
  698. pixelX += timeAreaTranslation.x;
  699. return pixelX;
  700. }
  701. public float TimeToPixel(double time)
  702. {
  703. return m_Window.timeArea.TimeToPixel((float)time, timeAreaRect);
  704. }
  705. public float PixelToTime(float pixel)
  706. {
  707. return m_Window.timeArea.PixelToTime(pixel, timeAreaRect);
  708. }
  709. public float PixelDeltaToDeltaTime(float p)
  710. {
  711. return PixelToTime(p) - PixelToTime(0);
  712. }
  713. public float TimeAreaPixelToTime(float pixel)
  714. {
  715. return PixelToTime(pixel);
  716. }
  717. public float ScreenSpacePixelToTimeAreaTime(float p)
  718. {
  719. // transform into track space by offsetting the pixel by the screen-space offset of the time area
  720. p -= timeAreaRect.x;
  721. return TrackSpacePixelToTimeAreaTime(p);
  722. }
  723. public float TrackSpacePixelToTimeAreaTime(float p)
  724. {
  725. p -= timeAreaTranslation.x;
  726. if (timeAreaScale.x > 0.0f)
  727. return p / timeAreaScale.x;
  728. return p;
  729. }
  730. public void OffsetTimeArea(int pixels)
  731. {
  732. Vector3 tx = timeAreaTranslation;
  733. tx.x += pixels;
  734. SetTimeAreaTransform(tx, timeAreaScale);
  735. }
  736. public GameObject GetSceneReference(TrackAsset asset)
  737. {
  738. if (editSequence.director == null)
  739. return null; // no player bound
  740. return TimelineUtility.GetSceneGameObject(editSequence.director, asset);
  741. }
  742. public void CalculateRowRects()
  743. {
  744. // arming a track might add inline curve tracks, recalc track heights
  745. if (m_Window != null && m_Window.treeView != null)
  746. m_Window.treeView.CalculateRowRects();
  747. }
  748. // Only one track within a 'track' hierarchy can be armed
  749. public void ArmForRecord(TrackAsset track)
  750. {
  751. m_ArmedTracks[TimelineUtility.GetSceneReferenceTrack(track)] = track;
  752. if (track != null && !recording)
  753. recording = true;
  754. if (!recording)
  755. return;
  756. track.OnRecordingArmed(editSequence.director);
  757. CalculateRowRects();
  758. }
  759. public void UnarmForRecord(TrackAsset track)
  760. {
  761. m_ArmedTracks.Remove(TimelineUtility.GetSceneReferenceTrack(track));
  762. if (m_ArmedTracks.Count == 0)
  763. recording = false;
  764. track.OnRecordingUnarmed(editSequence.director);
  765. }
  766. public void UpdateRecordingState()
  767. {
  768. if (recording)
  769. {
  770. foreach (var track in m_ArmedTracks.Values)
  771. {
  772. if (track != null)
  773. track.OnRecordingTimeChanged(editSequence.director);
  774. }
  775. }
  776. }
  777. public bool IsTrackRecordable(TrackAsset track)
  778. {
  779. // A track with animated parameters can always be recorded to
  780. return IsArmedForRecord(track) || track.HasAnyAnimatableParameters();
  781. }
  782. public bool IsArmedForRecord(TrackAsset track)
  783. {
  784. return track == GetArmedTrack(track);
  785. }
  786. public TrackAsset GetArmedTrack(TrackAsset track)
  787. {
  788. TrackAsset outTrack;
  789. m_ArmedTracks.TryGetValue(TimelineUtility.GetSceneReferenceTrack(track), out outTrack);
  790. return outTrack;
  791. }
  792. void CheckRecordingState()
  793. {
  794. // checks for deleted tracks, and makes sure the recording state matches
  795. if (m_ArmedTracks.Any(t => t.Value == null))
  796. {
  797. m_ArmedTracks = m_ArmedTracks.Where(t => t.Value != null).ToDictionary(t => t.Key, t => t.Value);
  798. if (m_ArmedTracks.Count == 0)
  799. recording = false;
  800. }
  801. }
  802. void OnCurrentDirectorWillChange()
  803. {
  804. if (ignorePreview)
  805. return;
  806. SynchronizeViewModelTime(editSequence);
  807. Stop();
  808. rebuildGraph = true; // needed for asset previews
  809. }
  810. public void GatherProperties(PlayableDirector director)
  811. {
  812. if (director == null || Application.isPlaying)
  813. return;
  814. var asset = director.playableAsset as TimelineAsset;
  815. if (asset != null && !asset.editorSettings.scenePreview)
  816. return;
  817. if (!previewMode)
  818. {
  819. AnimationMode.StartAnimationMode(previewDriver);
  820. OnStartPreview(director);
  821. AnimationPropertyContextualMenu.Instance.SetResponder(new TimelineRecordingContextualResponder(this));
  822. if (!previewMode)
  823. return;
  824. EnsureWindowTimeConsistency();
  825. }
  826. if (asset != null)
  827. {
  828. m_PropertyCollector.Reset();
  829. m_PropertyCollector.PushActiveGameObject(null); // avoid overflow on unbound tracks
  830. asset.GatherProperties(director, m_PropertyCollector);
  831. }
  832. }
  833. void OnStartPreview(PlayableDirector director)
  834. {
  835. previewedDirectors = TimelineUtility.GetAllDirectorsInHierarchy(director).ToList();
  836. if (previewedDirectors == null)
  837. return;
  838. m_PreviewedAnimators = PreviewedBindings<Animator>.GetPreviewedBindings(previewedDirectors);
  839. m_PreviewedComponents = m_PreviewedAnimators.GetUniqueBindings()
  840. .SelectMany(animator => animator.GetComponents<IAnimationWindowPreview>()
  841. .Cast<Component>())
  842. .ToList();
  843. foreach (var previewedComponent in previewedComponents)
  844. {
  845. previewedComponent.StartPreview();
  846. }
  847. #if UNITY_2022_2_OR_NEWER
  848. PrefabUtility.allowRecordingPrefabPropertyOverridesFor += AllowRecordingPrefabPropertyOverridesFor;
  849. #endif //UNITY_2022_2_OR_NEWER
  850. }
  851. internal bool AllowRecordingPrefabPropertyOverridesFor(Object componentOrGameObject)
  852. {
  853. if (componentOrGameObject == null)
  854. throw new ArgumentNullException(nameof(componentOrGameObject));
  855. if (previewMode == false)
  856. return true;
  857. if (m_ArmedTracks.Count == 0)
  858. return true;
  859. GameObject inputGameObject = null;
  860. if (componentOrGameObject is Component component)
  861. {
  862. inputGameObject = component.gameObject;
  863. }
  864. else if (componentOrGameObject is GameObject gameObject)
  865. {
  866. inputGameObject = gameObject;
  867. }
  868. if (inputGameObject == null)
  869. return true;
  870. var armedTracks = m_ArmedTracks.Keys;
  871. foreach (var track in armedTracks)
  872. {
  873. var animators = m_PreviewedAnimators.GetBindingsForObject(track);
  874. foreach (var animator in animators)
  875. {
  876. if (animator == null)
  877. continue;
  878. if (inputGameObject.transform.IsChildOf(animator.transform))
  879. return false;
  880. }
  881. }
  882. return true;
  883. }
  884. void OnStopPreview()
  885. {
  886. if (m_PreviewedComponents != null)
  887. {
  888. foreach (var previewComponent in previewedComponents)
  889. {
  890. previewComponent.StopPreview();
  891. }
  892. m_PreviewedComponents = null;
  893. }
  894. foreach (var previewAnimator in m_PreviewedAnimators.GetUniqueBindings())
  895. {
  896. if (previewAnimator != null)
  897. previewAnimator.UnbindAllHandles();
  898. }
  899. m_PreviewedAnimators = default;
  900. #if UNITY_2022_2_OR_NEWER
  901. PrefabUtility.allowRecordingPrefabPropertyOverridesFor -= AllowRecordingPrefabPropertyOverridesFor;
  902. #endif //UNITY_2022_2_OR_NEWER
  903. }
  904. internal void ProcessStartFramePendingUpdates()
  905. {
  906. if (m_OnStartFrameUpdates != null)
  907. m_OnStartFrameUpdates.RemoveAll(callback => callback.Invoke(this, Event.current));
  908. }
  909. internal void ProcessEndFramePendingUpdates()
  910. {
  911. if (m_OnEndFrameUpdates != null)
  912. m_OnEndFrameUpdates.RemoveAll(callback => callback.Invoke(this, Event.current));
  913. }
  914. public void AddStartFrameDelegate(PendingUpdateDelegate updateDelegate)
  915. {
  916. if (m_OnStartFrameUpdates == null)
  917. m_OnStartFrameUpdates = new List<PendingUpdateDelegate>();
  918. if (m_OnStartFrameUpdates.Contains(updateDelegate))
  919. return;
  920. m_OnStartFrameUpdates.Add(updateDelegate);
  921. }
  922. public void AddEndFrameDelegate(PendingUpdateDelegate updateDelegate)
  923. {
  924. if (m_OnEndFrameUpdates == null)
  925. m_OnEndFrameUpdates = new List<PendingUpdateDelegate>();
  926. if (m_OnEndFrameUpdates.Contains(updateDelegate))
  927. return;
  928. m_OnEndFrameUpdates.Add(updateDelegate);
  929. }
  930. internal void InvokeWindowOnGuiStarted(Event evt)
  931. {
  932. if (windowOnGuiStarted != null)
  933. windowOnGuiStarted.Invoke(this, evt);
  934. }
  935. public void UpdateRootPlayableDuration(double duration)
  936. {
  937. if (editSequence.director != null)
  938. {
  939. if (editSequence.director.playableGraph.IsValid())
  940. {
  941. if (editSequence.director.playableGraph.GetRootPlayableCount() > 0)
  942. {
  943. var rootPlayable = editSequence.director.playableGraph.GetRootPlayable(0);
  944. if (rootPlayable.IsValid())
  945. rootPlayable.SetDuration(duration);
  946. }
  947. }
  948. }
  949. }
  950. public void InvokeTimeChangeCallback()
  951. {
  952. if (OnTimeChange != null)
  953. OnTimeChange.Invoke();
  954. }
  955. PlayRange ValidatePlayRange(PlayRange range, ISequenceState sequenceState)
  956. {
  957. if (range == TimelineAssetViewModel.NoPlayRangeSet)
  958. return range;
  959. double minimumPlayRangeTime = (0.01 / Math.Max(1.0, sequenceState.frameRate));
  960. // Validate min
  961. if (range.end - range.start < minimumPlayRangeTime)
  962. range.start = range.end - minimumPlayRangeTime;
  963. if (range.start < 0.0)
  964. range.start = 0.0;
  965. // Validate max
  966. if (range.end > sequenceState.duration)
  967. range.end = sequenceState.duration;
  968. if (range.end - range.start < minimumPlayRangeTime)
  969. range.end = Math.Min(range.start + minimumPlayRangeTime, sequenceState.duration);
  970. return range;
  971. }
  972. void EnsureWindowTimeConsistency()
  973. {
  974. if (masterSequence.director != null && masterSequence.viewModel != null && !ignorePreview)
  975. masterSequence.time = masterSequence.viewModel.windowTime;
  976. }
  977. void SynchronizeSequencesAfterPlayback()
  978. {
  979. // Synchronizing editSequence will synchronize all view models up to the master
  980. SynchronizeViewModelTime(editSequence);
  981. }
  982. static void SynchronizeViewModelTime(ISequenceState state)
  983. {
  984. if (state.director == null || state.viewModel == null)
  985. return;
  986. var t = state.time;
  987. state.time = t;
  988. }
  989. // because we may be evaluating outside the duration of the root playable
  990. // we explicitly set the time - this causes the graph to not 'advance' the time
  991. // because advancing it can force it to change due to wrapping to the duration
  992. // This can happen if the graph is force evaluated outside it's duration
  993. // case 910114, 936844 and 943377
  994. static void ForceTimeOnDirector(PlayableDirector director)
  995. {
  996. var directorTime = director.time;
  997. director.time = directorTime;
  998. }
  999. public bool IsPlayableGraphDone()
  1000. {
  1001. return masterSequence.director != null
  1002. && masterSequence.director.playableGraph.IsValid()
  1003. && masterSequence.director.playableGraph.IsDone();
  1004. }
  1005. }
  1006. }