add basic options

This commit is contained in:
Ruan Lucas
2023-07-18 16:48:15 -04:00
parent 84c99ea1c3
commit 2be6a6be9e
2 changed files with 328 additions and 2 deletions

View File

@@ -4,6 +4,8 @@ using FlaxEditor.Actions;
using FlaxEditor.SceneGraph.Actors;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEditor.CustomEditors.Elements;
using System;
namespace FlaxEditor.CustomEditors.Dedicated
{
@@ -14,6 +16,214 @@ namespace FlaxEditor.CustomEditors.Dedicated
[CustomEditor(typeof(Spline)), DefaultEditor]
public class SplineEditor : ActorEditor
{
/// <summary>
/// Basis for creating tangent manipulation types for bezier curves.
/// </summary>
public abstract class TangentModeBase
{
/// <summary>
/// Called when user set selected tangent mode.
/// </summary>
/// <param name="spline">Current spline selected on editor viewport.</param>
/// <param name="index">Index of current keyframe selected on spline.</param>
public abstract void OnSetMode(Spline spline, int index);
/// <summary>
/// Called when user select a keyframe (spline point) of current selected spline on editor viewport.
/// </summary>
/// <param name="spline">Current spline selected on editor viewport.</param>
/// <param name="index">Index of current keyframe selected on spline.</param>
public abstract void OnSelectKeyframe(Spline spline, int index);
/// <summary>
/// Called when user select a tangent of current keyframe selected from spline.
/// </summary>
/// <param name="spline">Current spline selected on editor viewport.</param>
/// <param name="index">Index of current keyframe selected on spline.</param>
public abstract void OnSelectTangent(Spline spline, int index);
/// <summary>
/// Called when the tangent in from current keyframe selected from spline is moved on editor viewport.
/// </summary>
/// <param name="spline">Current spline selected on editor viewport.</param>
/// <param name="index">Index of current keyframe selected on spline.</param>
public abstract void OnMoveTangentIn(Spline spline, int index);
/// <summary>
/// Called when the tangent out from current keyframe selected from spline is moved on editor viewport.
/// </summary>
/// <param name="spline">Current spline selected on editor viewport.</param>
/// <param name="index">Current spline selected on editor viewport.</param>
public abstract void OnMoveTangentOut(Spline spline, int index);
}
/// <summary>
/// Edit curve options manipulate the curve as free mode
/// </summary>
public sealed class FreeTangentMode : TangentModeBase
{
/// <inheritdoc/>
public override void OnMoveTangentIn(Spline spline, int index) { }
/// <inheritdoc/>
public override void OnMoveTangentOut(Spline spline, int index) { }
/// <inheritdoc/>
public override void OnSelectKeyframe(Spline spline, int index) { }
/// <inheritdoc/>
public override void OnSelectTangent(Spline spline, int index) { }
/// <inheritdoc/>
public override void OnSetMode(Spline spline, int index) { }
}
/// <summary>
/// Edit curve options to set tangents to linear
/// </summary>
public sealed class LinearTangentMode : TangentModeBase
{
/// <inheritdoc/>
public override void OnMoveTangentIn(Spline spline, int index) { }
/// <inheritdoc/>
public override void OnMoveTangentOut(Spline spline, int index) { }
/// <inheritdoc/>
public override void OnSelectKeyframe(Spline spline, int index) { }
/// <inheritdoc/>
public override void OnSelectTangent(Spline spline, int index) { }
/// <inheritdoc/>
public override void OnSetMode(Spline spline, int index)
{
SetKeyframeLinear(spline, index);
}
private void SetKeyframeLinear(Spline spline, int index)
{
var tangentIn = spline.GetSplineTangent(index, true);
var tangentOut = spline.GetSplineTangent(index, false);
tangentIn.Translation = spline.GetSplinePoint(index);
tangentOut.Translation = spline.GetSplinePoint(index);
spline.SetSplineTangent(index, tangentIn, true, false);
spline.SetSplineTangent(index, tangentOut, false, false);
spline.UpdateSpline();
}
}
/// <summary>
/// Edit curve options to align tangents of selected spline
/// </summary>
public sealed class AlignedTangentMode : TangentModeBase
{
/// <inheritdoc/>
public override void OnSetMode(Spline spline, int index)
{
SmoothIfNotAligned(spline, index);
}
/// <inheritdoc/>
public override void OnSelectKeyframe(Spline spline, int index)
{
SmoothIfNotAligned(spline, index);
}
/// <inheritdoc/>
public override void OnSelectTangent(Spline selectedSpline, int index) { }
/// <inheritdoc/>
public override void OnMoveTangentIn(Spline spline, int index)
{
SetPointAligned(spline, index, true);
}
/// <inheritdoc/>
public override void OnMoveTangentOut(Spline spline, int index)
{
SetPointAligned(spline, index, false);
}
private void SmoothIfNotAligned(Spline spline, int index)
{
var keyframe = spline.GetSplineKeyframe(index);
var isAligned = Vector3.Dot(keyframe.TangentIn.Translation.Normalized, keyframe.TangentOut.Translation.Normalized) == 1f;
if (!isAligned)
{
SetPointSmooth(spline, index);
}
}
private void SetPointSmooth(Spline spline, int index)
{
var keyframe = spline.GetSplineKeyframe(index);
var tangentIn = keyframe.TangentIn;
var tangentOut = keyframe.TangentOut;
var tangentInSize = tangentIn.Translation.Length;
var tangentOutSize = tangentOut.Translation.Length;
var isLastKeyframe = index >= spline.SplinePointsCount - 1;
var isFirstKeyframe = index <= 0;
if (!isLastKeyframe && !isFirstKeyframe)
{
var nextKeyframe = spline.GetSplineKeyframe(++index);
var previousKeyframe = spline.GetSplineKeyframe(--index);
// calc form from Spline.cpp -> SetTangentsSmooth
var slop = (keyframe.Value.Translation - previousKeyframe.Value.Translation + nextKeyframe.Value.Translation - keyframe.Value.Translation).Normalized;
keyframe.TangentIn.Translation = -slop * tangentInSize;
keyframe.TangentOut.Translation = slop * tangentOutSize;
spline.SetSplineKeyframe(index, keyframe);
}
}
private void SetPointAligned(Spline spline, int index, bool isIn)
{
var keyframe = spline.GetSplineKeyframe(index);
var referenceTangent = isIn ? keyframe.TangentIn : keyframe.TangentOut;
var otherTangent = !isIn ? keyframe.TangentIn : keyframe.TangentOut;
// inverse of reference tangent
otherTangent.Translation = -referenceTangent.Translation.Normalized * otherTangent.Translation.Length;
if (isIn) keyframe.TangentOut = otherTangent;
if (!isIn) keyframe.TangentIn = otherTangent;
spline.SetSplineKeyframe(index, keyframe);
}
}
private TangentModeBase _currentTangentMode;
private ButtonElement _freeTangentButton;
private ButtonElement _linearTangentButton;
private ButtonElement _alignedTangentButton;
private bool _tanInChanged;
private bool _tanOutChanged;
private Vector3 _lastTanInPos;
private Vector3 _lastTanOutPos;
private SplineNode.SplinePointNode _lastPointSelected;
private SplineNode.SplinePointTangentNode _selectedTangentIn;
private SplineNode.SplinePointTangentNode _selectedTangentOut;
/// <summary>
/// Current selected spline on editor, if has
/// </summary>
public Spline SelectedSpline => !Values.HasDifferentValues && Values[0] is Spline ? (Spline)Values[0] : null;
/// <summary>
/// Create a Spline editor
/// </summary>
public SplineEditor()
{
_currentTangentMode = new FreeTangentMode();
}
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
{
@@ -22,6 +232,21 @@ namespace FlaxEditor.CustomEditors.Dedicated
if (Values.HasDifferentTypes == false)
{
layout.Space(10);
layout.Header("Selected spline point");
var selectedPointsGrid = layout.CustomContainer<UniformGridPanel>();
selectedPointsGrid.CustomControl.SlotsHorizontally = 3;
selectedPointsGrid.CustomControl.SlotsVertically = 1;
_linearTangentButton = selectedPointsGrid.Button("Linear");
_freeTangentButton = selectedPointsGrid.Button("Free");
_alignedTangentButton = selectedPointsGrid.Button("Aligned");
_linearTangentButton.Button.Clicked += SetModeLinear;
_freeTangentButton.Button.Clicked += SetModeFree;
_alignedTangentButton.Button.Clicked += SetModeAligned;
layout.Header("All spline points");
var grid = layout.CustomContainer<UniformGridPanel>();
grid.CustomControl.SlotsHorizontally = 2;
grid.CustomControl.SlotsVertically = 1;
@@ -30,6 +255,107 @@ namespace FlaxEditor.CustomEditors.Dedicated
}
}
/// <inheritdoc/>
public override void Refresh()
{
base.Refresh();
UpdateSelectedPoint();
UpdateSelectedTangent();
var index = _lastPointSelected.Index;
var currentTangentInPosition = SelectedSpline.GetSplineLocalTangent(index, true).Translation;
var currentTangentOutPosition = SelectedSpline.GetSplineLocalTangent(index, false).Translation;
if (_selectedTangentIn != null)
{
_tanInChanged = _lastTanInPos != currentTangentInPosition;
_lastTanInPos = currentTangentInPosition;
}
if (_selectedTangentOut != null)
{
_tanOutChanged = _lastTanOutPos != currentTangentOutPosition;
_lastTanOutPos = currentTangentOutPosition;
}
if (_tanInChanged) _currentTangentMode.OnMoveTangentIn(SelectedSpline, index);
if (_tanOutChanged) _currentTangentMode.OnMoveTangentOut(SelectedSpline, index);
currentTangentInPosition = SelectedSpline.GetSplineLocalTangent(index, true).Translation;
currentTangentOutPosition = SelectedSpline.GetSplineLocalTangent(index, false).Translation;
// update last tangents position after changes
if (SelectedSpline) _lastTanInPos = currentTangentInPosition;
if (SelectedSpline) _lastTanOutPos = currentTangentOutPosition;
_tanInChanged = false;
_tanOutChanged = false;
}
private void SetModeLinear()
{
_currentTangentMode = new LinearTangentMode();
_currentTangentMode.OnSetMode(SelectedSpline, _lastPointSelected.Index);
}
private void SetModeFree()
{
_currentTangentMode = new FreeTangentMode();
_currentTangentMode.OnSetMode(SelectedSpline, _lastPointSelected.Index);
}
private void SetModeAligned()
{
_currentTangentMode = new AlignedTangentMode();
_currentTangentMode.OnSetMode(SelectedSpline, _lastPointSelected.Index);
}
private void UpdateSelectedPoint()
{
// works only if select one spline
if (Editor.Instance.SceneEditing.SelectionCount != 1) return;
var currentSelected = Editor.Instance.SceneEditing.Selection[0];
if (currentSelected == _lastPointSelected) return;
if (currentSelected is not SplineNode.SplinePointNode) return;
_lastPointSelected = currentSelected as SplineNode.SplinePointNode;
var index = _lastPointSelected.Index;
_currentTangentMode.OnSelectKeyframe(SelectedSpline, index);
}
private void UpdateSelectedTangent()
{
// works only if select one spline
if (_lastPointSelected == null || Editor.Instance.SceneEditing.SelectionCount != 1) return;
var currentSelected = Editor.Instance.SceneEditing.Selection[0];
if (currentSelected is not SplineNode.SplinePointTangentNode) return;
if (currentSelected == _selectedTangentIn) return;
if (currentSelected == _selectedTangentOut) return;
var index = _lastPointSelected.Index;
if (currentSelected.Transform == SelectedSpline.GetSplineTangent(index, true))
{
_selectedTangentIn = currentSelected as SplineNode.SplinePointTangentNode;
_currentTangentMode.OnSelectTangent(SelectedSpline, index);
return;
}
if (currentSelected.Transform == SelectedSpline.GetSplineTangent(index, false))
{
_selectedTangentOut = currentSelected as SplineNode.SplinePointTangentNode;
_currentTangentMode.OnSelectTangent(SelectedSpline, index);
return;
}
_selectedTangentIn = null;
_selectedTangentOut = null;
}
private void OnSetTangentsLinear()
{
var enableUndo = Presenter.Undo != null && Presenter.Undo.Enabled;

View File

@@ -21,7 +21,7 @@ namespace FlaxEditor.SceneGraph.Actors
[HideInEditor]
public sealed class SplineNode : ActorNode
{
private sealed class SplinePointNode : ActorChildNode<SplineNode>
public sealed class SplinePointNode : ActorChildNode<SplineNode>
{
public unsafe SplinePointNode(SplineNode node, Guid id, int index)
: base(node, id, index)
@@ -219,7 +219,7 @@ namespace FlaxEditor.SceneGraph.Actors
}
}
private sealed class SplinePointTangentNode : ActorChildNode
public sealed class SplinePointTangentNode : ActorChildNode
{
private SplineNode _node;
private int _index;