AnimationWindow.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Runtime.InteropServices;
  6. using BansheeEngine;
  7. namespace BansheeEditor
  8. {
  9. /** @addtogroup Windows
  10. * @{
  11. */
  12. /// <summary>
  13. /// Displays animation curve editor window.
  14. /// </summary>
  15. [DefaultSize(900, 500)]
  16. internal class AnimationWindow : EditorWindow
  17. {
  18. /// <summary>
  19. /// A set of animation curves for a field of a certain type.
  20. /// </summary>
  21. private struct FieldCurves
  22. {
  23. public SerializableProperty.FieldType type;
  24. public EdAnimationCurve[] curves;
  25. }
  26. private const int FIELD_DISPLAY_WIDTH = 200;
  27. private const int DRAG_START_DISTANCE = 3;
  28. private const float DRAG_SCALE = 10.0f;
  29. private const float ZOOM_SCALE = 15.0f;
  30. private bool isInitialized;
  31. private GUIButton playButton;
  32. private GUIButton recordButton;
  33. private GUIButton prevFrameButton;
  34. private GUIIntField frameInputField;
  35. private GUIButton nextFrameButton;
  36. private GUIButton addKeyframeButton;
  37. private GUIButton addEventButton;
  38. private GUIButton optionsButton;
  39. private GUIButton addPropertyBtn;
  40. private GUIButton delPropertyBtn;
  41. private GUILayout buttonLayout;
  42. private int buttonLayoutHeight;
  43. private int scrollBarWidth;
  44. private int scrollBarHeight;
  45. private GUIResizeableScrollBarH horzScrollBar;
  46. private GUIResizeableScrollBarV vertScrollBar;
  47. private GUIPanel editorPanel;
  48. private GUIAnimFieldDisplay guiFieldDisplay;
  49. private GUICurveEditor guiCurveEditor;
  50. private SceneObject selectedSO;
  51. private int currentFrameIdx;
  52. private int fps = 1;
  53. private Vector2I dragStartPos;
  54. private bool isButtonHeld;
  55. private bool isDragInProgress;
  56. private Vector2 minimalRange;
  57. private Vector2 visibleOffset;
  58. private Dictionary<string, FieldCurves> curves = new Dictionary<string, FieldCurves>();
  59. private List<string> selectedFields = new List<string>();
  60. internal int FPS
  61. {
  62. get { return fps; }
  63. set { guiCurveEditor.SetFPS(value); fps = MathEx.Max(value, 1); }
  64. }
  65. /// <summary>
  66. /// Opens the animation window.
  67. /// </summary>
  68. [MenuItem("Windows/Animation", ButtonModifier.CtrlAlt, ButtonCode.A, 6000)]
  69. private static void OpenGameWindow()
  70. {
  71. OpenWindow<AnimationWindow>();
  72. }
  73. /// <inheritdoc/>
  74. protected override LocString GetDisplayName()
  75. {
  76. return new LocEdString("Animation");
  77. }
  78. private void OnInitialize()
  79. {
  80. Selection.OnSelectionChanged += OnSelectionChanged;
  81. EditorInput.OnPointerPressed += OnPointerPressed;
  82. EditorInput.OnPointerMoved += OnPointerMoved;
  83. EditorInput.OnPointerReleased += OnPointerReleased;
  84. EditorInput.OnButtonUp += OnButtonUp;
  85. Rebuild();
  86. }
  87. private Vector2 GetVisibleRange()
  88. {
  89. float unitsPerXPixel = guiCurveEditor.XRange / guiCurveEditor.Width;
  90. float unitsPerYPixel = guiCurveEditor.YRange / guiCurveEditor.Height;
  91. Vector2I visibleSize = GetCurveEditorSize();
  92. return new Vector2(unitsPerXPixel * visibleSize.x, unitsPerYPixel * visibleSize.y);
  93. }
  94. private void SetVisibleOffset(Vector2 offset)
  95. {
  96. visibleOffset = offset;
  97. float pixelsPerXUnit = guiCurveEditor.Width / guiCurveEditor.XRange;
  98. float pixelsPerYUnit = guiCurveEditor.Height / (guiCurveEditor.YRange * 2.0f);
  99. int x = (int) (pixelsPerXUnit*visibleOffset.x);
  100. int y = (int) (pixelsPerYUnit*visibleOffset.y);
  101. guiCurveEditor.SetPosition(x, y);
  102. }
  103. // Increases range without zooming in (increasing width/height accordingly)
  104. private void SetTotalRange(float x, float y)
  105. {
  106. float pixelsPerXUnit = guiCurveEditor.Width / guiCurveEditor.XRange;
  107. float pixelsPerYUnit = guiCurveEditor.Height / (guiCurveEditor.YRange * 2.0f);
  108. int width = (int) (pixelsPerXUnit * x);
  109. int height = (int) (pixelsPerYUnit * y);
  110. guiCurveEditor.SetRange(x, y);
  111. guiCurveEditor.SetSize(width, height);
  112. UpdateScrollBarSize();
  113. }
  114. private void UpdateScrollBarSize()
  115. {
  116. Vector2 visibleRange = GetVisibleRange();
  117. Vector2 totalRange = new Vector2(guiCurveEditor.XRange, guiCurveEditor.YRange);
  118. horzScrollBar.HandleSize = visibleRange.x / totalRange.x;
  119. vertScrollBar.HandleSize = visibleRange.y / totalRange.y;
  120. }
  121. private void UpdateScrollBarPosition()
  122. {
  123. Vector2 visibleRange = GetVisibleRange();
  124. Vector2 totalRange = new Vector2(guiCurveEditor.XRange, guiCurveEditor.YRange);
  125. Vector2 scrollableRange = totalRange - visibleRange;
  126. horzScrollBar.Position = visibleOffset.x / scrollableRange.x;
  127. vertScrollBar.Position = visibleOffset.y / scrollableRange.y;
  128. }
  129. private void Zoom(Vector2 curvePos, float amount)
  130. {
  131. Vector2 relativePos = curvePos - visibleOffset;
  132. Vector2 visibleRange = GetVisibleRange();
  133. relativePos.x /= visibleRange.x;
  134. relativePos.y /= visibleRange.y;
  135. relativePos.x = relativePos.x * 2.0f - 1.0f;
  136. relativePos.y = relativePos.y * 2.0f - 1.0f;
  137. Vector2 offset = visibleOffset;
  138. offset.x += relativePos.x * amount;
  139. offset.y += relativePos.y * amount;
  140. offset.x = Math.Max(0.0f, offset.x);
  141. SetVisibleOffset(offset);
  142. UpdateScrollBarPosition();
  143. int width = guiCurveEditor.Width + (int)amount;
  144. int height = guiCurveEditor.Height + (int)amount;
  145. // If we aren't at the minimum size, modify size and offset
  146. Vector2I visibleSize = GetCurveEditorSize();
  147. if (width > visibleSize.x || height > visibleSize.y)
  148. {
  149. width = Math.Max(width, visibleSize.x);
  150. height = Math.Max(height, visibleSize.y);
  151. guiCurveEditor.SetSize(width, height);
  152. UpdateScrollBarSize();
  153. }
  154. else // Otherwise start increasing range for zoom in
  155. {
  156. float unitsPerXPixel = guiCurveEditor.XRange / guiCurveEditor.Width;
  157. float unitsPerYPixel = guiCurveEditor.YRange / guiCurveEditor.Height;
  158. float rangeX = guiCurveEditor.XRange + unitsPerXPixel * amount;
  159. float rangeY = guiCurveEditor.YRange + unitsPerYPixel * amount;
  160. SetTotalRange(rangeX, rangeY);
  161. }
  162. }
  163. private void OnEditorUpdate()
  164. {
  165. if (!isInitialized)
  166. return;
  167. // Handle middle mouse dragging
  168. if (isDragInProgress)
  169. {
  170. float dragX = Input.GetAxisValue(InputAxis.MouseX) * DRAG_SCALE;
  171. float dragY = Input.GetAxisValue(InputAxis.MouseY) * DRAG_SCALE;
  172. Vector2 totalRange = new Vector2(guiCurveEditor.XRange, guiCurveEditor.YRange);
  173. Vector2 visibleRange = GetVisibleRange();
  174. Vector2 offset = visibleOffset;
  175. if (dragX > 0.0f)
  176. {
  177. offset.x += dragX;
  178. float visibleRight = offset.x + visibleRange.x;
  179. if (visibleRight > totalRange.x)
  180. totalRange.x = visibleRight;
  181. }
  182. else
  183. {
  184. float actualDragX = offset.x - Math.Max(0.0f, offset.x + dragX);
  185. offset.x -= actualDragX;
  186. float visibleRight = offset.x + visibleRange.x;
  187. totalRange.x = Math.Max(minimalRange.x, visibleRight);
  188. }
  189. if (dragY > 0.0f)
  190. {
  191. offset.y += dragY;
  192. float visibleTop = offset.y + visibleRange.y;
  193. if (visibleTop > totalRange.y)
  194. totalRange.y = visibleTop;
  195. }
  196. else
  197. {
  198. offset.y += dragY;
  199. float visibleYMax = Math.Abs(offset.y) + visibleRange.y;
  200. totalRange.y = Math.Max(minimalRange.y, visibleYMax);
  201. }
  202. SetTotalRange(totalRange.x, totalRange.y);
  203. SetVisibleOffset(offset);
  204. UpdateScrollBarPosition();
  205. }
  206. // Handle zoom in/out
  207. float scroll = Input.GetAxisValue(InputAxis.MouseZ);
  208. if (scroll != 0.0f)
  209. {
  210. Vector2I windowPos = ScreenToWindowPos(Input.PointerPosition);
  211. Vector2 curvePos;
  212. if (guiCurveEditor.WindowToCurveSpace(windowPos, out curvePos))
  213. {
  214. float zoom = scroll*ZOOM_SCALE;
  215. Zoom(curvePos, zoom);
  216. }
  217. }
  218. }
  219. private void OnDestroy()
  220. {
  221. Selection.OnSelectionChanged -= OnSelectionChanged;
  222. EditorInput.OnPointerPressed -= OnPointerPressed;
  223. EditorInput.OnPointerMoved -= OnPointerMoved;
  224. EditorInput.OnPointerReleased -= OnPointerReleased;
  225. EditorInput.OnButtonUp -= OnButtonUp;
  226. }
  227. protected override void WindowResized(int width, int height)
  228. {
  229. if (!isInitialized)
  230. return;
  231. guiFieldDisplay.SetSize(FIELD_DISPLAY_WIDTH, height - buttonLayoutHeight*2);
  232. Vector2I curveEditorSize = GetCurveEditorSize();
  233. guiCurveEditor.SetSize(curveEditorSize.x, curveEditorSize.y);
  234. guiCurveEditor.Redraw();
  235. horzScrollBar.SetWidth(curveEditorSize.x);
  236. vertScrollBar.SetHeight(curveEditorSize.y);
  237. UpdateScrollBarSize();
  238. UpdateScrollBarPosition();
  239. }
  240. private void Rebuild()
  241. {
  242. GUI.Clear();
  243. selectedFields.Clear();
  244. curves.Clear();
  245. isInitialized = false;
  246. selectedSO = Selection.SceneObject;
  247. if (selectedSO == null)
  248. {
  249. GUILabel warningLbl = new GUILabel(new LocEdString("Select an object to animate in the Hierarchy or Scene windows."));
  250. GUILayoutY vertLayout = GUI.AddLayoutY();
  251. vertLayout.AddFlexibleSpace();
  252. GUILayoutX horzLayout = vertLayout.AddLayoutX();
  253. vertLayout.AddFlexibleSpace();
  254. horzLayout.AddFlexibleSpace();
  255. horzLayout.AddElement(warningLbl);
  256. horzLayout.AddFlexibleSpace();
  257. return;
  258. }
  259. // TODO - Retrieve Animation & AnimationClip from the selected object, fill curves dictionary
  260. // - If not available, show a button to create new animation clip
  261. // Top button row
  262. GUIContent playIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.Play),
  263. new LocEdString("Play"));
  264. GUIContent recordIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.Record),
  265. new LocEdString("Record"));
  266. GUIContent prevFrameIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.FrameBack),
  267. new LocEdString("Previous frame"));
  268. GUIContent nextFrameIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.FrameForward),
  269. new LocEdString("Next frame"));
  270. GUIContent addKeyframeIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.AddKeyframe),
  271. new LocEdString("Add keyframe"));
  272. GUIContent addEventIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.AddEvent),
  273. new LocEdString("Add event"));
  274. GUIContent optionsIcon = new GUIContent(EditorBuiltin.GetLibraryWindowIcon(LibraryWindowIcon.Options),
  275. new LocEdString("Options"));
  276. playButton = new GUIButton(playIcon);
  277. recordButton = new GUIButton(recordIcon);
  278. prevFrameButton = new GUIButton(prevFrameIcon);
  279. frameInputField = new GUIIntField();
  280. nextFrameButton = new GUIButton(nextFrameIcon);
  281. addKeyframeButton = new GUIButton(addKeyframeIcon);
  282. addEventButton = new GUIButton(addEventIcon);
  283. optionsButton = new GUIButton(optionsIcon);
  284. playButton.OnClick += () =>
  285. {
  286. // TODO
  287. // - Record current state of the scene object hierarchy
  288. // - Evaluate all curves manually and update them
  289. // - On end, restore original values of the scene object hierarchy
  290. };
  291. recordButton.OnClick += () =>
  292. {
  293. // TODO
  294. // - Every frame read back current values of all the current curve's properties and assign it to the current frame
  295. };
  296. prevFrameButton.OnClick += () =>
  297. {
  298. SetCurrentFrame(currentFrameIdx - 1);
  299. };
  300. frameInputField.OnChanged += SetCurrentFrame;
  301. nextFrameButton.OnClick += () =>
  302. {
  303. SetCurrentFrame(currentFrameIdx + 1);
  304. };
  305. addKeyframeButton.OnClick += () =>
  306. {
  307. guiCurveEditor.AddKeyFrameAtMarker();
  308. // TODO - Update local curves?
  309. };
  310. addEventButton.OnClick += () =>
  311. {
  312. // TODO - Add event
  313. };
  314. optionsButton.OnClick += () =>
  315. {
  316. Vector2I openPosition = ScreenToWindowPos(Input.PointerPosition);
  317. AnimationOptions dropDown = DropDownWindow.Open<AnimationOptions>(this, openPosition);
  318. dropDown.Initialize(this);
  319. };
  320. // Property buttons
  321. addPropertyBtn = new GUIButton(new LocEdString("Add property"));
  322. delPropertyBtn = new GUIButton(new LocEdString("Delete selected"));
  323. addPropertyBtn.OnClick += () =>
  324. {
  325. Vector2I windowPos = ScreenToWindowPos(Input.PointerPosition);
  326. FieldSelectionWindow fieldSelection = DropDownWindow.Open<FieldSelectionWindow>(this, windowPos);
  327. fieldSelection.OnFieldSelected += OnFieldAdded;
  328. };
  329. delPropertyBtn.OnClick += () =>
  330. {
  331. LocEdString title = new LocEdString("Warning");
  332. LocEdString message = new LocEdString("Are you sure you want to remove all selected fields?");
  333. DialogBox.Open(title, message, DialogBox.Type.YesNo, x =>
  334. {
  335. if (x == DialogBox.ResultType.Yes)
  336. {
  337. RemoveSelectedFields();
  338. }
  339. });
  340. };
  341. GUILayout mainLayout = GUI.AddLayoutY();
  342. buttonLayout = mainLayout.AddLayoutX();
  343. buttonLayout.AddSpace(5);
  344. buttonLayout.AddElement(playButton);
  345. buttonLayout.AddElement(recordButton);
  346. buttonLayout.AddSpace(5);
  347. buttonLayout.AddElement(prevFrameButton);
  348. buttonLayout.AddElement(frameInputField);
  349. buttonLayout.AddElement(nextFrameButton);
  350. buttonLayout.AddSpace(5);
  351. buttonLayout.AddElement(addKeyframeButton);
  352. buttonLayout.AddElement(addEventButton);
  353. buttonLayout.AddSpace(5);
  354. buttonLayout.AddElement(optionsButton);
  355. buttonLayout.AddFlexibleSpace();
  356. buttonLayoutHeight = playButton.Bounds.height;
  357. GUILayout contentLayout = mainLayout.AddLayoutX();
  358. GUILayout fieldDisplayLayout = contentLayout.AddLayoutY(GUIOption.FixedWidth(FIELD_DISPLAY_WIDTH));
  359. guiFieldDisplay = new GUIAnimFieldDisplay(fieldDisplayLayout, FIELD_DISPLAY_WIDTH,
  360. Height - buttonLayoutHeight * 2, selectedSO);
  361. guiFieldDisplay.OnEntrySelected += OnFieldSelected;
  362. GUILayout bottomButtonLayout = fieldDisplayLayout.AddLayoutX();
  363. bottomButtonLayout.AddElement(addPropertyBtn);
  364. bottomButtonLayout.AddElement(delPropertyBtn);
  365. horzScrollBar = new GUIResizeableScrollBarH();
  366. horzScrollBar.OnScrollOrResize += OnHorzScrollOrResize;
  367. vertScrollBar = new GUIResizeableScrollBarV();
  368. vertScrollBar.OnScrollOrResize += OnVertScrollOrResize;
  369. GUILayout curveLayout = contentLayout.AddLayoutY();
  370. GUILayout curveLayoutHorz = curveLayout.AddLayoutX();
  371. GUILayout horzScrollBarLayout = curveLayout.AddLayoutX();
  372. horzScrollBarLayout.AddElement(horzScrollBar);
  373. horzScrollBarLayout.AddFlexibleSpace();
  374. editorPanel = curveLayoutHorz.AddPanel();
  375. curveLayoutHorz.AddElement(vertScrollBar);
  376. curveLayoutHorz.AddFlexibleSpace();
  377. scrollBarHeight = horzScrollBar.Bounds.height;
  378. scrollBarWidth = vertScrollBar.Bounds.width;
  379. Vector2I curveEditorSize = GetCurveEditorSize();
  380. guiCurveEditor = new GUICurveEditor(this, editorPanel, curveEditorSize.x, curveEditorSize.y);
  381. guiCurveEditor.OnFrameSelected += OnFrameSelected;
  382. guiCurveEditor.Redraw();
  383. horzScrollBar.SetWidth(curveEditorSize.x);
  384. vertScrollBar.SetHeight(curveEditorSize.y);
  385. SetCurrentFrame(currentFrameIdx);
  386. UpdateScrollBarSize();
  387. visibleOffset = new Vector2(0.0f, 0.0f);
  388. isInitialized = true;
  389. }
  390. private void SetCurrentFrame(int frameIdx)
  391. {
  392. currentFrameIdx = Math.Max(0, frameIdx);
  393. frameInputField.Value = currentFrameIdx;
  394. guiCurveEditor.SetMarkedFrame(currentFrameIdx);
  395. float time = guiCurveEditor.GetTimeForFrame(currentFrameIdx);
  396. List<GUIAnimFieldPathValue> values = new List<GUIAnimFieldPathValue>();
  397. foreach (var kvp in curves)
  398. {
  399. SerializableProperty property = GUIAnimFieldDisplay.FindProperty(selectedSO, kvp.Key);
  400. if (property != null)
  401. {
  402. GUIAnimFieldPathValue fieldValue = new GUIAnimFieldPathValue();
  403. fieldValue.path = kvp.Key;
  404. switch (kvp.Value.type)
  405. {
  406. case SerializableProperty.FieldType.Vector2:
  407. {
  408. Vector2 value = new Vector2();
  409. for(int i = 0; i < 2; i++)
  410. value[i] = kvp.Value.curves[i].Evaluate(time, false);
  411. fieldValue.value = value;
  412. }
  413. break;
  414. case SerializableProperty.FieldType.Vector3:
  415. {
  416. Vector3 value = new Vector3();
  417. for (int i = 0; i < 3; i++)
  418. value[i] = kvp.Value.curves[i].Evaluate(time, false);
  419. fieldValue.value = value;
  420. }
  421. break;
  422. case SerializableProperty.FieldType.Vector4:
  423. {
  424. Vector4 value = new Vector4();
  425. for (int i = 0; i < 4; i++)
  426. value[i] = kvp.Value.curves[i].Evaluate(time, false);
  427. fieldValue.value = value;
  428. }
  429. break;
  430. case SerializableProperty.FieldType.Color:
  431. {
  432. Color value = new Color();
  433. for (int i = 0; i < 4; i++)
  434. value[i] = kvp.Value.curves[i].Evaluate(time, false);
  435. fieldValue.value = value;
  436. }
  437. break;
  438. case SerializableProperty.FieldType.Bool:
  439. case SerializableProperty.FieldType.Int:
  440. case SerializableProperty.FieldType.Float:
  441. fieldValue.value = kvp.Value.curves[0].Evaluate(time, false); ;
  442. break;
  443. }
  444. values.Add(fieldValue);
  445. }
  446. }
  447. guiFieldDisplay.SetDisplayValues(values.ToArray());
  448. }
  449. private void OnPointerPressed(PointerEvent ev)
  450. {
  451. if (!isInitialized)
  452. return;
  453. guiCurveEditor.OnPointerPressed(ev);
  454. if (ev.button == PointerButton.Middle)
  455. {
  456. Vector2I windowPos = ScreenToWindowPos(ev.ScreenPos);
  457. Vector2 curvePos;
  458. if (guiCurveEditor.WindowToCurveSpace(windowPos, out curvePos))
  459. {
  460. dragStartPos = windowPos;
  461. isButtonHeld = true;
  462. }
  463. }
  464. }
  465. private void OnPointerMoved(PointerEvent ev)
  466. {
  467. if (!isInitialized)
  468. return;
  469. guiCurveEditor.OnPointerMoved(ev);
  470. if (isButtonHeld)
  471. {
  472. Vector2I windowPos = ScreenToWindowPos(ev.ScreenPos);
  473. int distance = Vector2I.Distance(dragStartPos, windowPos);
  474. if (distance >= DRAG_START_DISTANCE)
  475. {
  476. isDragInProgress = true;
  477. Cursor.Hide();
  478. Rect2I clipRect;
  479. clipRect.x = ev.ScreenPos.x - 2;
  480. clipRect.y = ev.ScreenPos.y - 2;
  481. clipRect.width = 4;
  482. clipRect.height = 4;
  483. Cursor.ClipToRect(clipRect);
  484. }
  485. }
  486. }
  487. private void OnPointerReleased(PointerEvent ev)
  488. {
  489. if (isDragInProgress)
  490. {
  491. Cursor.Show();
  492. Cursor.ClipDisable();
  493. }
  494. isButtonHeld = false;
  495. isDragInProgress = false;
  496. if (!isInitialized)
  497. return;
  498. guiCurveEditor.OnPointerReleased(ev);
  499. }
  500. private void OnButtonUp(ButtonEvent ev)
  501. {
  502. if (!isInitialized)
  503. return;
  504. guiCurveEditor.OnButtonUp(ev);
  505. }
  506. private void UpdateDisplayedCurves()
  507. {
  508. List<EdAnimationCurve> curvesToDisplay = new List<EdAnimationCurve>();
  509. for (int i = 0; i < selectedFields.Count; i++)
  510. {
  511. EdAnimationCurve curve;
  512. if(TryGetCurve(selectedFields[i], out curve))
  513. curvesToDisplay.Add(curve);
  514. }
  515. guiCurveEditor.SetCurves(curvesToDisplay.ToArray());
  516. float xRange;
  517. float yRange;
  518. CalculateRange(curvesToDisplay, out xRange, out yRange);
  519. // Don't allow zero range
  520. if (xRange == 0.0f)
  521. xRange = 60.0f;
  522. if (yRange == 0.0f)
  523. yRange = 10.0f;
  524. // Add padding to y range
  525. yRange *= 1.05f;
  526. // Don't reduce visible range
  527. minimalRange.x = Math.Max(xRange, minimalRange.x);
  528. minimalRange.y = Math.Max(yRange, minimalRange.y);
  529. xRange = Math.Max(xRange, guiCurveEditor.XRange);
  530. yRange = Math.Max(yRange, guiCurveEditor.YRange);
  531. guiCurveEditor.SetRange(xRange, yRange);
  532. UpdateScrollBarSize();
  533. }
  534. private Vector2I GetCurveEditorSize()
  535. {
  536. Vector2I output = new Vector2I();
  537. output.x = Math.Max(0, Width - FIELD_DISPLAY_WIDTH - scrollBarWidth);
  538. output.y = Math.Max(0, Height - buttonLayoutHeight - scrollBarHeight);
  539. return output;
  540. }
  541. private static void CalculateRange(List<EdAnimationCurve> curves, out float xRange, out float yRange)
  542. {
  543. xRange = 0.0f;
  544. yRange = 0.0f;
  545. foreach (var curve in curves)
  546. {
  547. KeyFrame[] keyframes = curve.KeyFrames;
  548. foreach (var key in keyframes)
  549. {
  550. xRange = Math.Max(xRange, key.time);
  551. yRange = Math.Max(yRange, Math.Abs(key.value));
  552. }
  553. }
  554. }
  555. private bool TryGetCurve(string path, out EdAnimationCurve curve)
  556. {
  557. int index = path.LastIndexOf(".");
  558. string parentPath;
  559. string subPathSuffix = null;
  560. if (index == -1)
  561. {
  562. parentPath = path;
  563. }
  564. else
  565. {
  566. parentPath = path.Substring(0, index);
  567. subPathSuffix = path.Substring(index, path.Length - index);
  568. }
  569. FieldCurves fieldCurves;
  570. if (curves.TryGetValue(parentPath, out fieldCurves))
  571. {
  572. if (!string.IsNullOrEmpty(subPathSuffix))
  573. {
  574. if (subPathSuffix == ".x" || subPathSuffix == ".r")
  575. {
  576. curve = fieldCurves.curves[0];
  577. return true;
  578. }
  579. else if (subPathSuffix == ".y" || subPathSuffix == ".g")
  580. {
  581. curve = fieldCurves.curves[1];
  582. return true;
  583. }
  584. else if (subPathSuffix == ".z" || subPathSuffix == ".b")
  585. {
  586. curve = fieldCurves.curves[2];
  587. return true;
  588. }
  589. else if (subPathSuffix == ".w" || subPathSuffix == ".a")
  590. {
  591. curve = fieldCurves.curves[3];
  592. return true;
  593. }
  594. }
  595. else
  596. {
  597. curve = fieldCurves.curves[0];
  598. return true;
  599. }
  600. }
  601. curve = null;
  602. return false;
  603. }
  604. private void OnFieldAdded(string path, SerializableProperty.FieldType type)
  605. {
  606. guiFieldDisplay.AddField(path);
  607. switch (type)
  608. {
  609. case SerializableProperty.FieldType.Vector4:
  610. {
  611. FieldCurves fieldCurves = new FieldCurves();
  612. fieldCurves.type = type;
  613. fieldCurves.curves = new EdAnimationCurve[4];
  614. string[] subPaths = { ".x", ".y", ".z", ".w" };
  615. for (int i = 0; i < subPaths.Length; i++)
  616. {
  617. string subFieldPath = path + subPaths[i];
  618. fieldCurves.curves[i] = new EdAnimationCurve();
  619. selectedFields.Add(subFieldPath);
  620. }
  621. curves[path] = fieldCurves;
  622. }
  623. break;
  624. case SerializableProperty.FieldType.Vector3:
  625. {
  626. FieldCurves fieldCurves = new FieldCurves();
  627. fieldCurves.type = type;
  628. fieldCurves.curves = new EdAnimationCurve[3];
  629. string[] subPaths = { ".x", ".y", ".z" };
  630. for (int i = 0; i < subPaths.Length; i++)
  631. {
  632. string subFieldPath = path + subPaths[i];
  633. fieldCurves.curves[i] = new EdAnimationCurve();
  634. selectedFields.Add(subFieldPath);
  635. }
  636. curves[path] = fieldCurves;
  637. }
  638. break;
  639. case SerializableProperty.FieldType.Vector2:
  640. {
  641. FieldCurves fieldCurves = new FieldCurves();
  642. fieldCurves.type = type;
  643. fieldCurves.curves = new EdAnimationCurve[2];
  644. string[] subPaths = { ".x", ".y" };
  645. for (int i = 0; i < subPaths.Length; i++)
  646. {
  647. string subFieldPath = path + subPaths[i];
  648. fieldCurves.curves[i] = new EdAnimationCurve();
  649. selectedFields.Add(subFieldPath);
  650. }
  651. curves[path] = fieldCurves;
  652. }
  653. break;
  654. case SerializableProperty.FieldType.Color:
  655. {
  656. FieldCurves fieldCurves = new FieldCurves();
  657. fieldCurves.type = type;
  658. fieldCurves.curves = new EdAnimationCurve[4];
  659. string[] subPaths = { ".r", ".g", ".b", ".a" };
  660. for (int i = 0; i < subPaths.Length; i++)
  661. {
  662. string subFieldPath = path + subPaths[i];
  663. fieldCurves.curves[i] = new EdAnimationCurve();
  664. selectedFields.Add(subFieldPath);
  665. }
  666. curves[path] = fieldCurves;
  667. }
  668. break;
  669. default: // Primitive type
  670. {
  671. FieldCurves fieldCurves = new FieldCurves();
  672. fieldCurves.type = type;
  673. fieldCurves.curves = new EdAnimationCurve[1];
  674. fieldCurves.curves[0] = new EdAnimationCurve();
  675. selectedFields.Add(path);
  676. curves[path] = fieldCurves;
  677. }
  678. break;
  679. }
  680. UpdateDisplayedCurves();
  681. }
  682. private bool IsPathParent(string child, string parent)
  683. {
  684. string[] childEntries = child.Split('/', '.');
  685. string[] parentEntries = parent.Split('/', '.');
  686. if (parentEntries.Length >= child.Length)
  687. return false;
  688. int compareLength = Math.Min(childEntries.Length, parentEntries.Length);
  689. for (int i = 0; i < compareLength; i++)
  690. {
  691. if (childEntries[i] != parentEntries[i])
  692. return false;
  693. }
  694. return true;
  695. }
  696. private string GetSubPathParent(string path)
  697. {
  698. int index = path.LastIndexOf(".");
  699. if (index == -1)
  700. return path;
  701. return path.Substring(0, index);
  702. }
  703. private void OnHorzScrollOrResize(float position, float size)
  704. {
  705. Vector2 visibleRange = GetVisibleRange();
  706. float scrollableRange = guiCurveEditor.XRange - visibleRange.x;
  707. Vector2 offset = visibleOffset;
  708. offset.x = scrollableRange * position;
  709. SetVisibleOffset(offset);
  710. int width = (int)(guiCurveEditor.Width / size);
  711. guiCurveEditor.SetSize(width, guiCurveEditor.Height);
  712. }
  713. private void OnVertScrollOrResize(float position, float size)
  714. {
  715. Vector2 visibleRange = GetVisibleRange();
  716. float scrollableRange = guiCurveEditor.YRange - visibleRange.y;
  717. Vector2 offset = visibleOffset;
  718. offset.y = scrollableRange*position;
  719. SetVisibleOffset(offset);
  720. int height = (int)(guiCurveEditor.Height / size);
  721. guiCurveEditor.SetSize(guiCurveEditor.Width, height);
  722. }
  723. private void OnFieldSelected(string path)
  724. {
  725. if (!Input.IsButtonHeld(ButtonCode.LeftShift) && !Input.IsButtonHeld(ButtonCode.RightShift))
  726. selectedFields.Clear();
  727. if (!string.IsNullOrEmpty(path))
  728. {
  729. selectedFields.RemoveAll(x => { return x == path || IsPathParent(x, path); });
  730. selectedFields.Add(path);
  731. }
  732. guiFieldDisplay.SetSelection(selectedFields.ToArray());
  733. UpdateDisplayedCurves();
  734. }
  735. private void RemoveSelectedFields()
  736. {
  737. for (int i = 0; i < selectedFields.Count; i++)
  738. {
  739. selectedFields.Remove(selectedFields[i]);
  740. curves.Remove(GetSubPathParent(selectedFields[i]));
  741. }
  742. List<string> existingFields = new List<string>();
  743. foreach(var KVP in curves)
  744. existingFields.Add(KVP.Key);
  745. guiFieldDisplay.SetFields(existingFields.ToArray());
  746. selectedFields.Clear();
  747. UpdateDisplayedCurves();
  748. }
  749. private void OnSelectionChanged(SceneObject[] sceneObjects, string[] resourcePaths)
  750. {
  751. Rebuild();
  752. }
  753. private void OnFrameSelected(int frameIdx)
  754. {
  755. SetCurrentFrame(frameIdx);
  756. }
  757. }
  758. /// <summary>
  759. /// Drop down window that displays options used by the animation window.
  760. /// </summary>
  761. [DefaultSize(100, 50)]
  762. internal class AnimationOptions : DropDownWindow
  763. {
  764. /// <summary>
  765. /// Initializes the drop down window by creating the necessary GUI. Must be called after construction and before
  766. /// use.
  767. /// </summary>
  768. /// <param name="parent">Animation window that this drop down window is a part of.</param>
  769. internal void Initialize(AnimationWindow parent)
  770. {
  771. GUIIntField fpsField = new GUIIntField(new LocEdString("FPS"), 40);
  772. fpsField.Value = parent.FPS;
  773. fpsField.OnChanged += x => { parent.FPS = x; };
  774. GUILayoutY vertLayout = GUI.AddLayoutY();
  775. vertLayout.AddFlexibleSpace();
  776. GUILayoutX contentLayout = vertLayout.AddLayoutX();
  777. contentLayout.AddFlexibleSpace();
  778. contentLayout.AddElement(fpsField);
  779. contentLayout.AddFlexibleSpace();
  780. vertLayout.AddFlexibleSpace();
  781. }
  782. }
  783. /** @} */
  784. }