261 lines
9.1 KiB
C#
261 lines
9.1 KiB
C#
|
using System;
|
|||
|
using System.Reflection;
|
|||
|
using Unity.Mathematics;
|
|||
|
using UnityEngine;
|
|||
|
using UnityEngine.Splines;
|
|||
|
|
|||
|
namespace UnityEditor.Splines
|
|||
|
{
|
|||
|
static class SplineDataHandlesDrawer
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// LabelType used to define if label must be displayed along the handle and how it should be formatted
|
|||
|
/// </summary>
|
|||
|
internal enum LabelType
|
|||
|
{
|
|||
|
None,
|
|||
|
Index,
|
|||
|
Time
|
|||
|
};
|
|||
|
|
|||
|
const float k_HandleSize = 0.15f;
|
|||
|
|
|||
|
const int k_PickRes = 2;
|
|||
|
|
|||
|
internal static void InitCustomHandles<T>(
|
|||
|
SplineData<T> splineData,
|
|||
|
ISplineDataHandle drawerInstance)
|
|||
|
{
|
|||
|
var ids = new int[splineData.Count];
|
|||
|
for(int kfIndex = 0; kfIndex < splineData.Count; kfIndex++)
|
|||
|
ids[kfIndex] = GUIUtility.GetControlID(FocusType.Passive);
|
|||
|
|
|||
|
( (SplineDataHandle<T>)drawerInstance ).m_ControlIDs = ids;
|
|||
|
}
|
|||
|
|
|||
|
internal static void DrawCustomHandles<T>(
|
|||
|
SplineData<T> splineData,
|
|||
|
Component component,
|
|||
|
Spline spline,
|
|||
|
Matrix4x4 localToWorld,
|
|||
|
Color color,
|
|||
|
ISplineDataHandle drawerInstance,
|
|||
|
MethodInfo splineDataDrawMethodInfo,
|
|||
|
MethodInfo keyframeDrawMethodInfo)
|
|||
|
{
|
|||
|
if(splineData.Count == 0)
|
|||
|
return;
|
|||
|
|
|||
|
Undo.RecordObject(component, "Modifying Spline Data Points");
|
|||
|
|
|||
|
//Invoke if existing the custom drawer for the whole spline
|
|||
|
splineDataDrawMethodInfo?.Invoke(drawerInstance,
|
|||
|
new object[]
|
|||
|
{
|
|||
|
splineData,
|
|||
|
spline,
|
|||
|
localToWorld,
|
|||
|
color
|
|||
|
});
|
|||
|
|
|||
|
if (keyframeDrawMethodInfo == null)
|
|||
|
return;
|
|||
|
|
|||
|
var native = new NativeSpline(spline, localToWorld);
|
|||
|
var ids = ( (SplineDataHandle<T>)drawerInstance ).controlIDs;
|
|||
|
|
|||
|
for(int splineDataIndex = 0; splineDataIndex < splineData.Count; splineDataIndex++)
|
|||
|
{
|
|||
|
var keyframe = splineData[splineDataIndex];
|
|||
|
var normalizedT = SplineUtility.GetNormalizedInterpolation(native, keyframe.Index, splineData.PathIndexUnit);
|
|||
|
|
|||
|
native.Evaluate(normalizedT, out float3 dataPosition, out float3 dataDirection, out float3 dataUp);
|
|||
|
using(new Handles.DrawingScope(color))
|
|||
|
{
|
|||
|
//Invoke if existing the custom drawer for each keyframe
|
|||
|
keyframeDrawMethodInfo?.Invoke(drawerInstance,
|
|||
|
new object[]
|
|||
|
{
|
|||
|
ids[splineDataIndex],
|
|||
|
(Vector3)dataPosition,
|
|||
|
(Vector3)dataDirection,
|
|||
|
(Vector3)dataUp,
|
|||
|
splineData,
|
|||
|
splineDataIndex
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
native.Dispose();
|
|||
|
}
|
|||
|
|
|||
|
internal static void DrawSplineDataHandles<T>(
|
|||
|
SplineData<T> splineData,
|
|||
|
Component component,
|
|||
|
Spline spline,
|
|||
|
Matrix4x4 localToWorld,
|
|||
|
Color color,
|
|||
|
LabelType labelType)
|
|||
|
{
|
|||
|
Undo.RecordObject(component, "Modifying Spline Data Points");
|
|||
|
using var native = new NativeSpline(spline, localToWorld);
|
|||
|
|
|||
|
using(new Handles.DrawingScope(color))
|
|||
|
{
|
|||
|
for(int keyframeIndex = 0; keyframeIndex < splineData.Count; keyframeIndex++)
|
|||
|
{
|
|||
|
var keyframe = splineData[keyframeIndex];
|
|||
|
var inUse = SplineDataHandle(splineData, keyframe, native, labelType, keyframeIndex, out float time);
|
|||
|
|
|||
|
if(inUse)
|
|||
|
{
|
|||
|
keyframe.Index = time;
|
|||
|
splineData.SetDataPointNoSort(keyframeIndex, keyframe);
|
|||
|
|
|||
|
//OnMouseUp event
|
|||
|
if(GUIUtility.hotControl == 0)
|
|||
|
splineData.SortIfNecessary();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal static bool SplineDataHandle<T>(
|
|||
|
SplineData<T> splineData,
|
|||
|
IDataPoint dataPoint,
|
|||
|
NativeSpline spline,
|
|||
|
LabelType labelType,
|
|||
|
int keyframeIndex,
|
|||
|
out float newTime)
|
|||
|
{
|
|||
|
int id = GUIUtility.GetControlID(FocusType.Passive);
|
|||
|
Event evt = Event.current;
|
|||
|
EventType eventType = evt.GetTypeForControl(id);
|
|||
|
|
|||
|
var normalizedT = SplineUtility.GetNormalizedInterpolation(spline, dataPoint.Index, splineData.PathIndexUnit);
|
|||
|
var dataPosition = SplineUtility.EvaluatePosition(spline, normalizedT);
|
|||
|
|
|||
|
switch (eventType)
|
|||
|
{
|
|||
|
case EventType.Layout:
|
|||
|
{
|
|||
|
if(!Tools.viewToolActive)
|
|||
|
{
|
|||
|
var dist = HandleUtility.DistanceToCircle(dataPosition, k_HandleSize * HandleUtility.GetHandleSize(dataPosition));
|
|||
|
HandleUtility.AddControl(id, dist);
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case EventType.Repaint:
|
|||
|
DrawSplineDataHandle(dataPosition, id);
|
|||
|
DrawSplineDataLabel(dataPosition, labelType, dataPoint, keyframeIndex);
|
|||
|
break;
|
|||
|
|
|||
|
case EventType.MouseDown:
|
|||
|
if (evt.button == 0
|
|||
|
&& HandleUtility.nearestControl == id
|
|||
|
&& GUIUtility.hotControl == 0)
|
|||
|
{
|
|||
|
GUIUtility.hotControl = id;
|
|||
|
|
|||
|
evt.Use();
|
|||
|
newTime = GetClosestSplineDataT(spline, splineData);
|
|||
|
return true;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case EventType.MouseDrag:
|
|||
|
if (GUIUtility.hotControl == id)
|
|||
|
{
|
|||
|
evt.Use();
|
|||
|
newTime = GetClosestSplineDataT(spline, splineData);
|
|||
|
return true;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case EventType.MouseUp:
|
|||
|
if (GUIUtility.hotControl == id)
|
|||
|
{
|
|||
|
evt.Use();
|
|||
|
if(evt.button == 0)
|
|||
|
{
|
|||
|
GUIUtility.hotControl = 0;
|
|||
|
newTime = GetClosestSplineDataT(spline, splineData);
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case EventType.MouseMove:
|
|||
|
HandleUtility.Repaint();
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
newTime = dataPoint.Index;
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
static void DrawSplineDataHandle(Vector3 position, int controlID)
|
|||
|
{
|
|||
|
var handleColor = Handles.color;
|
|||
|
if(controlID == GUIUtility.hotControl)
|
|||
|
handleColor = Handles.selectedColor;
|
|||
|
else if(GUIUtility.hotControl == 0 && controlID == HandleUtility.nearestControl)
|
|||
|
handleColor = Handles.preselectionColor;
|
|||
|
|
|||
|
// to avoid affecting the sphere dimensions with the handles matrix, we'll just use the position and reset
|
|||
|
// the matrix to identity when drawing.
|
|||
|
position = Handles.matrix * position;
|
|||
|
|
|||
|
using(new Handles.DrawingScope(handleColor, Matrix4x4.identity))
|
|||
|
{
|
|||
|
Handles.SphereHandleCap(
|
|||
|
controlID,
|
|||
|
position,
|
|||
|
Quaternion.identity,
|
|||
|
k_HandleSize * HandleUtility.GetHandleSize(position),
|
|||
|
EventType.Repaint
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void DrawSplineDataLabel(Vector3 position, LabelType labelType, IDataPoint dataPoint, int keyframeIndex)
|
|||
|
{
|
|||
|
if(labelType == LabelType.None)
|
|||
|
return;
|
|||
|
|
|||
|
float labelVal = dataPoint.Index;
|
|||
|
if(labelType == LabelType.Index && keyframeIndex >= 0)
|
|||
|
labelVal = keyframeIndex;
|
|||
|
|
|||
|
var label = ( Mathf.RoundToInt(labelVal * 100) / 100f ).ToString();
|
|||
|
label = labelType == LabelType.Index ? "[" + label + "]" : "t: "+label;
|
|||
|
Handles.Label(position - 0.1f * Vector3.up, label);
|
|||
|
}
|
|||
|
|
|||
|
// Spline must be in world space
|
|||
|
static float GetClosestSplineDataT<T>(NativeSpline spline, SplineData<T> splineData)
|
|||
|
{
|
|||
|
var evt = Event.current;
|
|||
|
var ray = HandleUtility.GUIPointToWorldRay(evt.mousePosition);
|
|||
|
|
|||
|
SplineUtility.GetNearestPoint(spline,
|
|||
|
ray,
|
|||
|
out float3 _,
|
|||
|
out float t,
|
|||
|
k_PickRes);
|
|||
|
|
|||
|
var time = SplineUtility.ConvertIndexUnit(
|
|||
|
spline,
|
|||
|
t,
|
|||
|
PathIndexUnit.Normalized,
|
|||
|
splineData.PathIndexUnit);
|
|||
|
|
|||
|
return time;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|