|
@@ -1,6 +1,6 @@
|
|
|
//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
|
|
//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
|
|
|
//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
|
|
//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
|
|
|
-
|
|
|
|
|
|
|
+using System;
|
|
|
using System.Collections.Generic;
|
|
using System.Collections.Generic;
|
|
|
using BansheeEngine;
|
|
using BansheeEngine;
|
|
|
|
|
|
|
@@ -15,41 +15,16 @@ namespace BansheeEditor
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
internal class AnimationWindow : EditorWindow
|
|
internal class AnimationWindow : EditorWindow
|
|
|
{
|
|
{
|
|
|
- public struct KeyframeRef
|
|
|
|
|
- {
|
|
|
|
|
- public KeyframeRef(int curveIdx, int keyIdx)
|
|
|
|
|
- {
|
|
|
|
|
- this.curveIdx = curveIdx;
|
|
|
|
|
- this.keyIdx = keyIdx;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public int curveIdx;
|
|
|
|
|
- public int keyIdx;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private GUIGraphTime timeline;
|
|
|
|
|
- private GUICurveDrawing curveDrawing;
|
|
|
|
|
- private GUIGraphValues sidebar;
|
|
|
|
|
-
|
|
|
|
|
private GUIFloatField lengthField;
|
|
private GUIFloatField lengthField;
|
|
|
private GUIIntField fpsField;
|
|
private GUIIntField fpsField;
|
|
|
private GUIFloatField yRangeField;
|
|
private GUIFloatField yRangeField;
|
|
|
private GUIButton addKeyframeBtn;
|
|
private GUIButton addKeyframeBtn;
|
|
|
|
|
|
|
|
private GUILayout buttonLayout;
|
|
private GUILayout buttonLayout;
|
|
|
|
|
+ private int buttonLayoutHeight;
|
|
|
|
|
|
|
|
- private EdAnimationCurve[] curves = new EdAnimationCurve[0];
|
|
|
|
|
- private int markedFrameIdx;
|
|
|
|
|
- private List<KeyframeRef> selectedKeyframes = new List<KeyframeRef>();
|
|
|
|
|
-
|
|
|
|
|
- private ContextMenu blankContextMenu;
|
|
|
|
|
- private ContextMenu keyframeContextMenu;
|
|
|
|
|
- private Vector2I contextClickPosition;
|
|
|
|
|
-
|
|
|
|
|
- // Keyframe drag
|
|
|
|
|
- private bool isMousePressedOverKey;
|
|
|
|
|
- private KeyFrame[] draggedKeyframes;
|
|
|
|
|
- private Vector2 dragStart;
|
|
|
|
|
|
|
+ private GUIPanel editorPanel;
|
|
|
|
|
+ private GUICurveEditor guiCurveEditor;
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
/// Opens the animation window.
|
|
/// Opens the animation window.
|
|
@@ -79,22 +54,19 @@ namespace BansheeEditor
|
|
|
|
|
|
|
|
lengthField.OnChanged += x =>
|
|
lengthField.OnChanged += x =>
|
|
|
{
|
|
{
|
|
|
- timeline.SetRange(lengthField.Value);
|
|
|
|
|
- curveDrawing.SetRange(lengthField.Value, yRangeField.Value);
|
|
|
|
|
|
|
+ guiCurveEditor.SetRange(lengthField.Value, yRangeField.Value);
|
|
|
};
|
|
};
|
|
|
fpsField.OnChanged += x =>
|
|
fpsField.OnChanged += x =>
|
|
|
{
|
|
{
|
|
|
- timeline.SetFPS(x);
|
|
|
|
|
- curveDrawing.SetFPS(x);
|
|
|
|
|
|
|
+ guiCurveEditor.SetFPS(x);
|
|
|
};
|
|
};
|
|
|
yRangeField.OnChanged += x =>
|
|
yRangeField.OnChanged += x =>
|
|
|
{
|
|
{
|
|
|
- curveDrawing.SetRange(lengthField.Value, x);
|
|
|
|
|
- sidebar.SetRange(x * -0.5f, x * 0.5f);
|
|
|
|
|
|
|
+ guiCurveEditor.SetRange(lengthField.Value, yRangeField.Value);
|
|
|
};
|
|
};
|
|
|
addKeyframeBtn.OnClick += () =>
|
|
addKeyframeBtn.OnClick += () =>
|
|
|
{
|
|
{
|
|
|
- AddKeyframeAtMarker();
|
|
|
|
|
|
|
+ guiCurveEditor.AddKeyFrameAtMarker();
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
GUILayout mainLayout = GUI.AddLayoutY();
|
|
GUILayout mainLayout = GUI.AddLayoutY();
|
|
@@ -110,94 +82,12 @@ namespace BansheeEditor
|
|
|
buttonLayout.AddElement(addKeyframeBtn);
|
|
buttonLayout.AddElement(addKeyframeBtn);
|
|
|
buttonLayout.AddSpace(5);
|
|
buttonLayout.AddSpace(5);
|
|
|
|
|
|
|
|
- timeline = new GUIGraphTime(mainLayout, Width, 20);
|
|
|
|
|
-
|
|
|
|
|
- curves = CreateDummyCurves();
|
|
|
|
|
- curveDrawing = new GUICurveDrawing(mainLayout, Width, Height - 20, curves);
|
|
|
|
|
- curveDrawing.SetRange(60.0f, 20.0f);
|
|
|
|
|
-
|
|
|
|
|
- GUIPanel sidebarPanel = GUI.AddPanel(-10);
|
|
|
|
|
- sidebarPanel.SetPosition(0, 20 + buttonLayout.Bounds.height);
|
|
|
|
|
-
|
|
|
|
|
- sidebar = new GUIGraphValues(sidebarPanel, 30, Height - 20 - buttonLayout.Bounds.height);
|
|
|
|
|
- sidebar.SetRange(-10.0f, 10.0f);
|
|
|
|
|
-
|
|
|
|
|
- curveDrawing.SetSize(Width, Height - 20 - buttonLayout.Bounds.height);
|
|
|
|
|
- curveDrawing.Rebuild();
|
|
|
|
|
-
|
|
|
|
|
- blankContextMenu = new ContextMenu();
|
|
|
|
|
- blankContextMenu.AddItem("Add keyframe", AddKeyframeAtPosition);
|
|
|
|
|
- blankContextMenu.AddItem("Add event", AddEventAtPosition);
|
|
|
|
|
-
|
|
|
|
|
- keyframeContextMenu = new ContextMenu();
|
|
|
|
|
- keyframeContextMenu.AddItem("Delete", DeleteSelectedKeyframes);
|
|
|
|
|
- keyframeContextMenu.AddItem("Tangents/Auto", () => { ChangeSelectionTangentMode(TangentMode.Auto); });
|
|
|
|
|
- keyframeContextMenu.AddItem("Tangents/Free", () => { ChangeSelectionTangentMode(TangentMode.Free); });
|
|
|
|
|
- keyframeContextMenu.AddItem("Tangents/In/Auto", () => { ChangeSelectionTangentMode(TangentMode.InAuto); });
|
|
|
|
|
- keyframeContextMenu.AddItem("Tangents/In/Free", () => { ChangeSelectionTangentMode(TangentMode.InFree); });
|
|
|
|
|
- keyframeContextMenu.AddItem("Tangents/In/Linear", () => { ChangeSelectionTangentMode(TangentMode.InLinear); });
|
|
|
|
|
- keyframeContextMenu.AddItem("Tangents/In/Step", () => { ChangeSelectionTangentMode(TangentMode.InStep); });
|
|
|
|
|
- keyframeContextMenu.AddItem("Tangents/Out/Auto", () => { ChangeSelectionTangentMode(TangentMode.OutAuto); });
|
|
|
|
|
- keyframeContextMenu.AddItem("Tangents/Out/Free", () => { ChangeSelectionTangentMode(TangentMode.OutFree); });
|
|
|
|
|
- keyframeContextMenu.AddItem("Tangents/Out/Linear", () => { ChangeSelectionTangentMode(TangentMode.OutLinear); });
|
|
|
|
|
- keyframeContextMenu.AddItem("Tangents/Out/Step", () => { ChangeSelectionTangentMode(TangentMode.OutStep); });
|
|
|
|
|
-
|
|
|
|
|
- // TODO - Calculate min/max Y and range to set as default
|
|
|
|
|
- // - Also recalculate whenever curves change and increase as needed
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void ChangeSelectionTangentMode(TangentMode mode)
|
|
|
|
|
- {
|
|
|
|
|
- // TODO - When changing just left or right, make sure to persist opposite tangent mode (or switch to equivalent broken mode if it wasn't broken)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void AddKeyframeAtPosition()
|
|
|
|
|
- {
|
|
|
|
|
- // TODO
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void AddEventAtPosition()
|
|
|
|
|
- {
|
|
|
|
|
- // TODO
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void AddKeyframeAtMarker()
|
|
|
|
|
- {
|
|
|
|
|
- ClearSelection();
|
|
|
|
|
-
|
|
|
|
|
- foreach (var curve in curves)
|
|
|
|
|
- {
|
|
|
|
|
- float t = curveDrawing.GetTimeForFrame(markedFrameIdx);
|
|
|
|
|
- float value = curve.Native.Evaluate(t);
|
|
|
|
|
-
|
|
|
|
|
- curve.AddKeyframe(t, value);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // TODO - UNDOREDO
|
|
|
|
|
|
|
+ editorPanel = mainLayout.AddPanel();
|
|
|
|
|
+ buttonLayoutHeight = lengthField.Bounds.height;
|
|
|
|
|
|
|
|
- curveDrawing.Rebuild();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void DeleteSelectedKeyframes()
|
|
|
|
|
- {
|
|
|
|
|
- // Sort keys from highest to lowest so they can be removed without changing the indices of the keys
|
|
|
|
|
- // after them
|
|
|
|
|
- selectedKeyframes.Sort((x, y) =>
|
|
|
|
|
- {
|
|
|
|
|
- if (x.curveIdx.Equals(y.curveIdx))
|
|
|
|
|
- return y.keyIdx.CompareTo(x.keyIdx);
|
|
|
|
|
-
|
|
|
|
|
- return x.curveIdx.CompareTo(y.curveIdx);
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- foreach (var keyframe in selectedKeyframes)
|
|
|
|
|
- curves[keyframe.curveIdx].RemoveKeyframe(keyframe.keyIdx);
|
|
|
|
|
-
|
|
|
|
|
- // TODO - UNDOREDO
|
|
|
|
|
-
|
|
|
|
|
- ClearSelection();
|
|
|
|
|
-
|
|
|
|
|
- curveDrawing.Rebuild();
|
|
|
|
|
|
|
+ guiCurveEditor = new GUICurveEditor(editorPanel, Width, Height - buttonLayoutHeight);
|
|
|
|
|
+ guiCurveEditor.SetCurves(CreateDummyCurves());
|
|
|
|
|
+ guiCurveEditor.Redraw();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private EdAnimationCurve[] CreateDummyCurves()
|
|
private EdAnimationCurve[] CreateDummyCurves()
|
|
@@ -215,129 +105,17 @@ namespace BansheeEditor
|
|
|
|
|
|
|
|
protected override void WindowResized(int width, int height)
|
|
protected override void WindowResized(int width, int height)
|
|
|
{
|
|
{
|
|
|
- timeline.SetSize(width, 20);
|
|
|
|
|
- curveDrawing.SetSize(width, height - 20 - buttonLayout.Bounds.height);
|
|
|
|
|
- sidebar.SetSize(30, height - 20 - buttonLayout.Bounds.height);
|
|
|
|
|
-
|
|
|
|
|
- curveDrawing.Rebuild();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void ClearSelection()
|
|
|
|
|
- {
|
|
|
|
|
- curveDrawing.ClearSelectedKeyframes();
|
|
|
|
|
- selectedKeyframes.Clear();
|
|
|
|
|
- isMousePressedOverKey = false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void SelectKeyframe(int curveIdx, int keyIdx)
|
|
|
|
|
- {
|
|
|
|
|
- curveDrawing.SelectKeyframe(curveIdx, keyIdx, true);
|
|
|
|
|
-
|
|
|
|
|
- if (!IsSelected(curveIdx, keyIdx))
|
|
|
|
|
- selectedKeyframes.Add(new KeyframeRef(curveIdx, keyIdx));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private bool IsSelected(int curveIdx, int keyIdx)
|
|
|
|
|
- {
|
|
|
|
|
- int existingIdx = selectedKeyframes.FindIndex(x =>
|
|
|
|
|
- {
|
|
|
|
|
- return x.curveIdx == curveIdx && x.keyIdx == keyIdx;
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- return (existingIdx != -1);
|
|
|
|
|
|
|
+ guiCurveEditor.SetSize(width, height - buttonLayoutHeight);
|
|
|
|
|
+ guiCurveEditor.Redraw();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private void OnEditorUpdate()
|
|
private void OnEditorUpdate()
|
|
|
{
|
|
{
|
|
|
- if (Input.IsPointerButtonDown(PointerButton.Left))
|
|
|
|
|
- {
|
|
|
|
|
- Vector2I windowPos = ScreenToWindowPos(Input.PointerPosition);
|
|
|
|
|
-
|
|
|
|
|
- Vector2 curveCoord;
|
|
|
|
|
- int curveIdx;
|
|
|
|
|
- int keyIdx;
|
|
|
|
|
- if (curveDrawing.GetCoordInfo(windowPos, out curveCoord, out curveIdx, out keyIdx))
|
|
|
|
|
- {
|
|
|
|
|
- if (keyIdx == -1)
|
|
|
|
|
- ClearSelection();
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- if (!Input.IsButtonHeld(ButtonCode.LeftShift) && !Input.IsButtonHeld(ButtonCode.RightShift))
|
|
|
|
|
- ClearSelection();
|
|
|
|
|
-
|
|
|
|
|
- SelectKeyframe(curveIdx, keyIdx);
|
|
|
|
|
-
|
|
|
|
|
- isMousePressedOverKey = true;
|
|
|
|
|
- dragStart = curveCoord;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- curveDrawing.Rebuild();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else if (Input.IsPointerButtonHeld(PointerButton.Left))
|
|
|
|
|
- {
|
|
|
|
|
- Vector2I windowPos = ScreenToWindowPos(Input.PointerPosition);
|
|
|
|
|
-
|
|
|
|
|
- if (isMousePressedOverKey)
|
|
|
|
|
- {
|
|
|
|
|
- // TODO - Check if pointer moves some minimal amount
|
|
|
|
|
- // - If so, start drag. Record all current positions
|
|
|
|
|
- // - Calculate offset in curve space and apply to all keyframes
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- int frameIdx = timeline.GetFrame(windowPos);
|
|
|
|
|
-
|
|
|
|
|
- if (frameIdx != -1)
|
|
|
|
|
- {
|
|
|
|
|
- timeline.SetMarkedFrame(frameIdx);
|
|
|
|
|
- curveDrawing.SetMarkedFrame(frameIdx);
|
|
|
|
|
-
|
|
|
|
|
- markedFrameIdx = frameIdx;
|
|
|
|
|
- curveDrawing.Rebuild();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else if (Input.IsPointerButtonUp(PointerButton.Left))
|
|
|
|
|
- {
|
|
|
|
|
- isMousePressedOverKey = false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (Input.IsPointerButtonDown(PointerButton.Right))
|
|
|
|
|
- {
|
|
|
|
|
- Vector2I windowPos = ScreenToWindowPos(Input.PointerPosition);
|
|
|
|
|
-
|
|
|
|
|
- Vector2 curveCoord;
|
|
|
|
|
- int curveIdx;
|
|
|
|
|
- int keyIdx;
|
|
|
|
|
- if (curveDrawing.GetCoordInfo(windowPos, out curveCoord, out curveIdx, out keyIdx))
|
|
|
|
|
- {
|
|
|
|
|
- contextClickPosition = windowPos;
|
|
|
|
|
-
|
|
|
|
|
- if (keyIdx == -1)
|
|
|
|
|
- {
|
|
|
|
|
- ClearSelection();
|
|
|
|
|
-
|
|
|
|
|
- blankContextMenu.Open(contextClickPosition, GUI);
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- // If clicked outside of current selection, just select the one keyframe
|
|
|
|
|
- if (!IsSelected(curveIdx, keyIdx))
|
|
|
|
|
- {
|
|
|
|
|
- ClearSelection();
|
|
|
|
|
- SelectKeyframe(curveIdx, keyIdx);
|
|
|
|
|
-
|
|
|
|
|
- curveDrawing.Rebuild();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- keyframeContextMenu.Open(contextClickPosition, GUI);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ Vector2I windowPos = ScreenToWindowPos(Input.PointerPosition);
|
|
|
|
|
+ Rect2I curveEditorBounds = editorPanel.Bounds;
|
|
|
|
|
|
|
|
- if(Input.IsButtonUp(ButtonCode.Delete))
|
|
|
|
|
- DeleteSelectedKeyframes();
|
|
|
|
|
|
|
+ Vector2I offset = new Vector2I(curveEditorBounds.x, curveEditorBounds.y);
|
|
|
|
|
+ guiCurveEditor.HandleInput(windowPos - offset);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|