|
|
@@ -1,5 +1,7 @@
|
|
|
//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
|
|
|
//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
|
|
|
+
|
|
|
+using System.Collections.Generic;
|
|
|
using BansheeEngine;
|
|
|
|
|
|
namespace BansheeEditor
|
|
|
@@ -13,6 +15,18 @@ namespace BansheeEditor
|
|
|
/// </summary>
|
|
|
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;
|
|
|
@@ -20,9 +34,19 @@ namespace BansheeEditor
|
|
|
private GUIFloatField lengthField;
|
|
|
private GUIIntField fpsField;
|
|
|
private GUIFloatField yRangeField;
|
|
|
+ private GUIButton addKeyframeBtn;
|
|
|
|
|
|
private GUILayout buttonLayout;
|
|
|
|
|
|
+ private EdAnimationCurve[] curves = new EdAnimationCurve[0];
|
|
|
+ private int markedFrameIdx;
|
|
|
+ private List<KeyframeRef> selectedKeyframes = new List<KeyframeRef>();
|
|
|
+
|
|
|
+ // Keyframe drag
|
|
|
+ private bool isMousePressedOverKey;
|
|
|
+ private KeyFrame[] draggedKeyframes;
|
|
|
+ private Vector2 dragStart;
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Opens the animation window.
|
|
|
/// </summary>
|
|
|
@@ -43,6 +67,7 @@ namespace BansheeEditor
|
|
|
lengthField = new GUIFloatField(new LocEdString("Length"), 50);
|
|
|
fpsField = new GUIIntField(new LocEdString("FPS"), 50);
|
|
|
yRangeField = new GUIFloatField(new LocEdString("Y range"), 50);
|
|
|
+ addKeyframeBtn = new GUIButton(new LocEdString("Add keyframe"));
|
|
|
|
|
|
lengthField.Value = 60.0f;
|
|
|
fpsField.Value = 1;
|
|
|
@@ -63,6 +88,10 @@ namespace BansheeEditor
|
|
|
curveDrawing.SetRange(lengthField.Value, x);
|
|
|
sidebar.SetRange(x * -0.5f, x * 0.5f);
|
|
|
};
|
|
|
+ addKeyframeBtn.OnClick += () =>
|
|
|
+ {
|
|
|
+ AddKeyframeAtMarker();
|
|
|
+ };
|
|
|
|
|
|
GUILayout mainLayout = GUI.AddLayoutY();
|
|
|
|
|
|
@@ -74,10 +103,12 @@ namespace BansheeEditor
|
|
|
buttonLayout.AddSpace(5);
|
|
|
buttonLayout.AddElement(fpsField);
|
|
|
buttonLayout.AddSpace(5);
|
|
|
+ buttonLayout.AddElement(addKeyframeBtn);
|
|
|
+ buttonLayout.AddSpace(5);
|
|
|
|
|
|
timeline = new GUIGraphTime(mainLayout, Width, 20);
|
|
|
|
|
|
- EdAnimationCurve[] curves = CreateDummyCurves();
|
|
|
+ curves = CreateDummyCurves();
|
|
|
curveDrawing = new GUICurveDrawing(mainLayout, Width, Height - 20, curves);
|
|
|
curveDrawing.SetRange(60.0f, 20.0f);
|
|
|
|
|
|
@@ -90,12 +121,46 @@ namespace BansheeEditor
|
|
|
curveDrawing.SetSize(Width, Height - 20 - buttonLayout.Bounds.height);
|
|
|
curveDrawing.Rebuild();
|
|
|
|
|
|
- Debug.Log("CURVE DRAWING HEIGHT + " + (Height - 20 - buttonLayout.Bounds.height));
|
|
|
|
|
|
// TODO - Calculate min/max Y and range to set as default
|
|
|
// - Also recalculate whenever curves change and increase as needed
|
|
|
}
|
|
|
|
|
|
+ private void AddKeyframeAtMarker()
|
|
|
+ {
|
|
|
+ ClearSelection();
|
|
|
+
|
|
|
+ foreach (var curve in curves)
|
|
|
+ {
|
|
|
+ float t = curveDrawing.GetTimeForFrame(markedFrameIdx);
|
|
|
+ float value = curve.Native.Evaluate(t);
|
|
|
+
|
|
|
+ curve.AddKeyframe(t, value);
|
|
|
+ }
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ ClearSelection();
|
|
|
+
|
|
|
+ curveDrawing.Rebuild();
|
|
|
+ }
|
|
|
+
|
|
|
private EdAnimationCurve[] CreateDummyCurves()
|
|
|
{
|
|
|
EdAnimationCurve[] curves = new EdAnimationCurve[1];
|
|
|
@@ -118,9 +183,16 @@ namespace BansheeEditor
|
|
|
curveDrawing.Rebuild();
|
|
|
}
|
|
|
|
|
|
+ private void ClearSelection()
|
|
|
+ {
|
|
|
+ curveDrawing.ClearSelectedKeyframes();
|
|
|
+ selectedKeyframes.Clear();
|
|
|
+ isMousePressedOverKey = false;
|
|
|
+ }
|
|
|
+
|
|
|
private void OnEditorUpdate()
|
|
|
{
|
|
|
- if (Input.IsPointerButtonHeld(PointerButton.Left))
|
|
|
+ if (Input.IsPointerButtonDown(PointerButton.Left))
|
|
|
{
|
|
|
Vector2I windowPos = ScreenToWindowPos(Input.PointerPosition);
|
|
|
|
|
|
@@ -129,24 +201,61 @@ namespace BansheeEditor
|
|
|
int keyIdx;
|
|
|
if (curveDrawing.GetCoordInfo(windowPos, out curveCoord, out curveIdx, out keyIdx))
|
|
|
{
|
|
|
- if(keyIdx == -1)
|
|
|
- curveDrawing.ClearSelectedKeyframes();
|
|
|
+ if (keyIdx == -1)
|
|
|
+ ClearSelection();
|
|
|
else
|
|
|
+ {
|
|
|
+ if (!Input.IsButtonHeld(ButtonCode.LeftShift) && !Input.IsButtonHeld(ButtonCode.RightShift))
|
|
|
+ ClearSelection();
|
|
|
+
|
|
|
curveDrawing.SelectKeyframe(curveIdx, keyIdx, true);
|
|
|
|
|
|
+ int existingIdx = selectedKeyframes.FindIndex(x =>
|
|
|
+ {
|
|
|
+ return x.curveIdx == curveIdx && x.keyIdx == keyIdx;
|
|
|
+ });
|
|
|
+
|
|
|
+ if (existingIdx == -1)
|
|
|
+ selectedKeyframes.Add(new KeyframeRef(curveIdx, keyIdx));
|
|
|
+
|
|
|
+ isMousePressedOverKey = true;
|
|
|
+ dragStart = curveCoord;
|
|
|
+ }
|
|
|
+
|
|
|
curveDrawing.Rebuild();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (Input.IsPointerButtonHeld(PointerButton.Left))
|
|
|
+ {
|
|
|
+ Vector2I windowPos = ScreenToWindowPos(Input.PointerPosition);
|
|
|
|
|
|
- Debug.Log("Click coord: " + curveCoord + " - " + curveIdx + " - " + keyIdx);
|
|
|
+ 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);
|
|
|
- timeline.SetMarkedFrame(frameIdx);
|
|
|
- curveDrawing.SetMarkedFrame(frameIdx);
|
|
|
|
|
|
- curveDrawing.Rebuild();
|
|
|
+ if (frameIdx != -1)
|
|
|
+ {
|
|
|
+ timeline.SetMarkedFrame(frameIdx);
|
|
|
+ curveDrawing.SetMarkedFrame(frameIdx);
|
|
|
+
|
|
|
+ markedFrameIdx = frameIdx;
|
|
|
+ curveDrawing.Rebuild();
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+ else if (Input.IsPointerButtonUp(PointerButton.Left))
|
|
|
+ {
|
|
|
+ isMousePressedOverKey = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(Input.IsButtonUp(ButtonCode.Delete))
|
|
|
+ DeleteSelectedKeyframes();
|
|
|
}
|
|
|
}
|
|
|
|