Files
FlaxEngine/Source/Editor/GUI/Timeline/EditCurveTrackGizmo.cs

204 lines
6.5 KiB
C#

// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEditor.Gizmo;
using FlaxEditor.GUI.Timeline.Tracks;
using FlaxEditor.GUI.Timeline.Undo;
using FlaxEditor.SceneGraph;
using FlaxEngine;
namespace FlaxEditor.GUI.Timeline
{
/// <summary>
/// Gizmo for editing position curve. Managed by the <see cref="SceneAnimationTimeline"/>.
/// </summary>
sealed class EditCurveTrackGizmo : TransformGizmoBase
{
public const float KeyframeSize = 10.0f;
public const float TangentSize = 6.0f;
private readonly SceneAnimationTimeline _timeline;
private CurvePropertyTrack _track;
private int _keyframe = -1;
private int _item = -1;
private byte[] _curveEditingStartData;
public int Keyframe => _keyframe;
public int Item => _item;
public EditCurveTrackGizmo(IGizmoOwner owner, SceneAnimationTimeline timeline)
: base(owner)
{
_timeline = timeline;
}
public void SelectKeyframe(CurvePropertyTrack track, int keyframe, int item)
{
_track = track;
_keyframe = keyframe;
_item = item;
}
public override BoundingSphere FocusBounds
{
get
{
if (_track == null)
return BoundingSphere.Empty;
var curve = (BezierCurveEditor<Vector3>)_track.Curve;
var keyframes = curve.Keyframes;
var k = keyframes[_keyframe];
if (_item == 1)
k.Value += k.TangentIn;
else if (_item == 2)
k.Value += k.TangentOut;
return new BoundingSphere(k.Value, KeyframeSize);
}
}
protected override int SelectionCount => _track != null ? 1 : 0;
protected override SceneGraphNode GetSelectedObject(int index)
{
return null;
}
protected override Transform GetSelectedTransform(int index)
{
if (_track == null)
return Transform.Identity;
var curve = (BezierCurveEditor<Vector3>)_track.Curve;
var keyframes = curve.Keyframes;
var k = keyframes[_keyframe];
if (_item == 1)
k.Value += k.TangentIn;
else if (_item == 2)
k.Value += k.TangentOut;
return new Transform(k.Value);
}
protected override void GetSelectedObjectsBounds(out BoundingBox bounds, out bool navigationDirty)
{
bounds = BoundingBox.Empty;
navigationDirty = false;
if (_track == null)
return;
var curve = (BezierCurveEditor<Vector3>)_track.Curve;
var keyframes = curve.Keyframes;
var k = keyframes[_keyframe];
if (_item == 1)
k.Value += k.TangentIn;
else if (_item == 2)
k.Value += k.TangentOut;
bounds = new BoundingBox(k.Value - KeyframeSize, k.Value + KeyframeSize);
}
protected override bool IsSelected(SceneGraphNode obj)
{
return false;
}
protected override void OnStartTransforming()
{
base.OnStartTransforming();
// Start undo
_curveEditingStartData = EditTrackAction.CaptureData(_track);
}
protected override void OnEndTransforming()
{
base.OnEndTransforming();
// End undo
var after = EditTrackAction.CaptureData(_track);
if (!Utils.ArraysEqual(_curveEditingStartData, after))
_track.Timeline.AddBatchedUndoAction(new EditTrackAction(_track.Timeline, _track, _curveEditingStartData, after));
_curveEditingStartData = null;
}
protected override void OnApplyTransformation(ref Vector3 translationDelta, ref Quaternion rotationDelta, ref Vector3 scaleDelta)
{
base.OnApplyTransformation(ref translationDelta, ref rotationDelta, ref scaleDelta);
var curve = (BezierCurveEditor<Vector3>)_track.Curve;
var keyframes = curve.Keyframes;
var k = keyframes[_keyframe];
if (_item == 0)
k.Value += translationDelta;
else if (_item == 1)
k.TangentIn += translationDelta;
else if (_item == 2)
k.TangentOut += translationDelta;
curve.SetKeyframeValue(_keyframe, k.Value, k.TangentIn, k.TangentOut);
}
public override void Pick()
{
if (_track == null)
return;
var selectRay = Owner.MouseRay;
var curve = (BezierCurveEditor<Vector3>)_track.Curve;
var keyframes = curve.Keyframes;
for (var i = 0; i < keyframes.Count; i++)
{
var k = keyframes[i];
var sphere = new BoundingSphere(k.Value, KeyframeSize);
if (sphere.Intersects(selectRay))
{
SelectKeyframe(_track, i, 0);
return;
}
if (!k.TangentIn.IsZero)
{
var t = k.Value + k.TangentIn;
var box = BoundingBox.FromSphere(new BoundingSphere(t, TangentSize));
if (box.Intersects(selectRay))
{
SelectKeyframe(_track, i, 1);
return;
}
}
if (!k.TangentOut.IsZero)
{
var t = k.Value + k.TangentOut;
var box = BoundingBox.FromSphere(new BoundingSphere(t, TangentSize));
if (box.Intersects(selectRay))
{
SelectKeyframe(_track, i, 2);
return;
}
}
}
}
public override void Update(float dt)
{
base.Update(dt);
// Deactivate when track gets deselected
if (_track != null && !_timeline.SelectedTracks.Contains(_track))
Owner.Gizmos.Active = Owner.Gizmos.Get<TransformGizmo>();
}
public override void OnActivated()
{
base.OnActivated();
ActiveMode = Mode.Translate;
}
public override void OnDeactivated()
{
// Clear selection
_track = null;
_keyframe = -1;
_item = -1;
base.OnDeactivated();
}
}
}