BITFALL/Assets/Polaris - Low Poly Ecosystem/Polaris - Low Poly Terrain .../Editor/Scripts/SplineTool/GSplineEditingGUIDrawer.cs

377 lines
16 KiB
C#

#if GRIFFIN
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.EditorTools;
using UnityEditor;
namespace Pinwheel.Griffin.SplineTool
{
public class GSplineEditingGUIDrawer
{
private const float BEZIER_SELECT_DISTANCE = 10;
private const float BEZIER_WIDTH = 5;
public int selectedAnchorIndex = -1;
public int selectedSegmentIndex = -1;
private GSplineCreator splineCreator;
bool autoTangent;
bool showTransformGizmos;
public GSplineEditingGUIDrawer(GSplineCreator splineCreator)
{
this.splineCreator = splineCreator;
}
public void Draw()
{
if (Event.current == null)
return;
autoTangent = GEditorSettings.Instance.splineTools.autoTangent;
showTransformGizmos = GEditorSettings.Instance.splineTools.showTransformGizmos;
//DrawDebug();
HandleSelectTransformRemoveAnchor();
HandleSelectTransformRemoveSegment();
HandleAddAnchor();
//DrawMesh();
DrawPivot();
//DrawInstruction();
CatchHotControl();
}
private void HandleSelectTransformRemoveAnchor()
{
List<GSplineAnchor> anchors = splineCreator.Spline.Anchors;
for (int i = 0; i < anchors.Count; ++i)
{
GSplineAnchor a = anchors[i];
Vector3 localPos = a.Position;
Vector3 worldPos = splineCreator.transform.TransformPoint(localPos);
float handleSize = HandleUtility.GetHandleSize(worldPos) * 0.2f;
if (i == selectedAnchorIndex && !showTransformGizmos)
{
Handles.color = GEditorSettings.Instance.splineTools.selectedElementColor;
Handles.SphereHandleCap(0, worldPos, Quaternion.identity, handleSize, EventType.Repaint);
bool isGlobalRotation = Tools.pivotRotation == PivotRotation.Global;
EditorGUI.BeginChangeCheck();
if (Tools.current == Tool.Move)
{
worldPos = Handles.PositionHandle(worldPos, isGlobalRotation ? Quaternion.identity : a.Rotation);
localPos = splineCreator.transform.InverseTransformPoint(worldPos);
a.Position = localPos;
}
else if (Tools.current == Tool.Rotate && !GEditorSettings.Instance.splineTools.autoTangent)
{
a.Rotation = Handles.RotationHandle(a.Rotation, worldPos);
}
else if (Tools.current == Tool.Scale)
{
a.Scale = Handles.ScaleHandle(a.Scale, worldPos, isGlobalRotation ? Quaternion.identity : a.Rotation, HandleUtility.GetHandleSize(worldPos));
}
anchors[i] = a;
if (EditorGUI.EndChangeCheck())
{
if (autoTangent)
{
splineCreator.Spline.SmoothTangents(selectedAnchorIndex);
GUI.changed = true;
}
List<int> segmentIndices = splineCreator.Spline.FindSegments(selectedAnchorIndex);
splineCreator.UpdateMesh(segmentIndices);
}
}
else
{
Handles.color = GEditorSettings.Instance.splineTools.anchorColor;
if (Handles.Button(worldPos, Quaternion.identity, handleSize, handleSize * 0.5f, Handles.SphereHandleCap) && !showTransformGizmos)
{
if (!Event.current.alt)
{
if (Event.current.control)
{
selectedAnchorIndex = -1;
selectedSegmentIndex = -1;
splineCreator.Spline.RemoveAnchor(i);
GUI.changed = true;
}
else if (Event.current.shift)
{
if (selectedAnchorIndex != i &&
selectedAnchorIndex >= 0 &&
selectedAnchorIndex < anchors.Count)
{
splineCreator.Spline.AddSegment(selectedAnchorIndex, i);
if (autoTangent)
{
int[] segmentsIndices = splineCreator.Spline.SmoothTangents(selectedAnchorIndex, i);
splineCreator.UpdateMesh(segmentsIndices);
}
else
{
splineCreator.UpdateMesh(splineCreator.Spline.Segments.Count - 1);
}
selectedAnchorIndex = i;
selectedSegmentIndex = -1;
GUI.changed = true;
}
}
else
{
selectedAnchorIndex = i;
selectedSegmentIndex = -1;
GUI.changed = true;
}
Event.current.Use();
}
}
}
}
}
private void HandleAddAnchor()
{
if (showTransformGizmos)
return;
bool isLeftMouseUp = Event.current.type == EventType.MouseUp && Event.current.button == 0;
bool isShift = Event.current.shift;
bool isAlt = Event.current.alt;
if (!isLeftMouseUp)
return;
LayerMask raycastLayers = GEditorSettings.Instance.splineTools.raycastLayers;
Ray r = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
RaycastHit hit;
if (Physics.Raycast(r, out hit, 10000, raycastLayers))
{
if (isAlt)
{
return;
}
if (!isShift)
{
selectedAnchorIndex = -1;
return;
}
Vector3 offset = splineCreator.PositionOffset;
Vector3 worldPos = hit.point + offset;
Vector3 localPos = splineCreator.transform.InverseTransformPoint(worldPos);
GSplineAnchor a = new GSplineAnchor(localPos);
splineCreator.Spline.AddAnchor(a);
if (selectedAnchorIndex >= 0 && selectedAnchorIndex < splineCreator.Spline.Anchors.Count - 1)
{
splineCreator.Spline.AddSegment(selectedAnchorIndex, splineCreator.Spline.Anchors.Count - 1);
if (autoTangent)
{
int[] segmentIndices = splineCreator.Spline.SmoothTangents(selectedAnchorIndex, splineCreator.Spline.Anchors.Count - 1);
splineCreator.UpdateMesh(segmentIndices);
}
else
{
splineCreator.UpdateMesh(splineCreator.Spline.Segments.Count - 1);
}
}
selectedAnchorIndex = splineCreator.Spline.Anchors.Count - 1;
GUI.changed = true;
Event.current.Use();
}
else
{
selectedAnchorIndex = -1;
}
}
private void HandleSelectTransformRemoveSegment()
{
List<GSplineSegment> segments = splineCreator.Spline.Segments;
List<GSplineAnchor> anchors = splineCreator.Spline.Anchors;
for (int i = 0; i < segments.Count; ++i)
{
if (!splineCreator.Spline.IsSegmentValid(i))
continue;
if (i == selectedSegmentIndex && !autoTangent && !showTransformGizmos)
HandleSelectedSegmentModifications();
int i0 = segments[i].StartIndex;
int i1 = segments[i].EndIndex;
GSplineAnchor a0 = anchors[i0];
GSplineAnchor a1 = anchors[i1];
Vector3 startPosition = splineCreator.transform.TransformPoint(a0.Position);
Vector3 endPosition = splineCreator.transform.TransformPoint(a1.Position);
Vector3 startTangent = splineCreator.transform.TransformPoint(segments[i].StartTangent);
Vector3 endTangent = splineCreator.transform.TransformPoint(segments[i].EndTangent);
Color color = (i == selectedSegmentIndex) ?
GEditorSettings.Instance.splineTools.selectedElementColor :
GEditorSettings.Instance.splineTools.segmentColor; ;
Color colorFade = new Color(color.r, color.g, color.b, color.a * 0.3f);
Vector3[] bezierPoints = Handles.MakeBezierPoints(startPosition, endPosition, startTangent, endTangent, Mathf.Min(5, splineCreator.Smoothness));
Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
Handles.color = color;
Handles.DrawPolyLine(bezierPoints);
Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
Handles.color = colorFade;
Handles.DrawPolyLine(bezierPoints);
if (Event.current.type == EventType.MouseUp && Event.current.button == 0 && !showTransformGizmos && !Event.current.alt)
{
float d0 = DistanceMouseToSpline(Event.current.mousePosition, bezierPoints);
float d1 = DistanceMouseToPoint(Event.current.mousePosition, bezierPoints[0]);
float d2 = DistanceMouseToPoint(Event.current.mousePosition, bezierPoints[bezierPoints.Length - 1]);
if (d0 <= BEZIER_SELECT_DISTANCE &&
d1 > BEZIER_SELECT_DISTANCE &&
d2 > BEZIER_SELECT_DISTANCE)
{
selectedSegmentIndex = i;
if (Event.current.control)
{
splineCreator.Spline.RemoveSegment(selectedSegmentIndex);
selectedSegmentIndex = -1;
GUI.changed = true;
}
//don't Use() the event here
}
else
{
if (selectedSegmentIndex == i)
{
selectedSegmentIndex = -1;
}
}
}
}
Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
}
private void HandleSelectedSegmentModifications()
{
if (selectedSegmentIndex < 0 || selectedSegmentIndex >= splineCreator.Spline.Segments.Count)
return;
if (!splineCreator.Spline.IsSegmentValid(selectedSegmentIndex))
return;
GSplineSegment segment = splineCreator.Spline.Segments[selectedSegmentIndex];
GSplineAnchor startAnchor = splineCreator.Spline.Anchors[segment.StartIndex];
GSplineAnchor endAnchor = splineCreator.Spline.Anchors[segment.EndIndex];
Vector3 worldStartPosition = splineCreator.transform.TransformPoint(startAnchor.Position);
Vector3 worldEndPosition = splineCreator.transform.TransformPoint(endAnchor.Position);
Vector3 worldStartTangent = splineCreator.transform.TransformPoint(segment.StartTangent);
Vector3 worldEndTangent = splineCreator.transform.TransformPoint(segment.EndTangent);
EditorGUI.BeginChangeCheck();
Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
worldStartTangent = Handles.PositionHandle(worldStartTangent, Quaternion.identity);
worldEndTangent = Handles.PositionHandle(worldEndTangent, Quaternion.identity);
segment.StartTangent = splineCreator.transform.InverseTransformPoint(worldStartTangent);
segment.EndTangent = splineCreator.transform.InverseTransformPoint(worldEndTangent);
if (EditorGUI.EndChangeCheck())
{
splineCreator.UpdateMesh(selectedSegmentIndex);
GUI.changed = true;
}
Handles.color = Color.white;
Handles.DrawLine(worldStartPosition, worldStartTangent);
Handles.DrawLine(worldEndPosition, worldEndTangent);
}
private void DrawPivot()
{
if (!showTransformGizmos)
{
Vector3 pivot = splineCreator.transform.position;
float size = HandleUtility.GetHandleSize(pivot);
Vector3 xStart = pivot + Vector3.left * size;
Vector3 xEnd = pivot + Vector3.right * size;
Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
Handles.color = Handles.xAxisColor;
Handles.DrawLine(xStart, xEnd);
Vector3 yStart = pivot + Vector3.down * size;
Vector3 yEnd = pivot + Vector3.up * size;
Handles.color = Handles.yAxisColor;
Handles.DrawLine(yStart, yEnd);
Vector3 zStart = pivot + Vector3.back * size;
Vector3 zEnd = pivot + Vector3.forward * size;
Handles.color = Handles.zAxisColor;
Handles.DrawLine(zStart, zEnd);
}
else
{
if (Tools.current == Tool.Move)
{
splineCreator.transform.position = Handles.PositionHandle(splineCreator.transform.position, splineCreator.transform.rotation);
}
else if (Tools.current == Tool.Rotate)
{
splineCreator.transform.rotation = Handles.RotationHandle(splineCreator.transform.rotation, splineCreator.transform.position);
}
else if (Tools.current == Tool.Scale)
{
splineCreator.transform.localScale = Handles.ScaleHandle(splineCreator.transform.localScale, splineCreator.transform.position, splineCreator.transform.rotation, HandleUtility.GetHandleSize(splineCreator.transform.position));
}
}
}
private void CatchHotControl()
{
if (Event.current.alt)
return;
int controlId = GUIUtility.GetControlID(this.GetHashCode(), FocusType.Passive);
if (Event.current.type == EventType.MouseDown)
{
if (Event.current.button == 0)
{
GUIUtility.hotControl = controlId;
//OnMouseDown(Event.current);
}
}
else if (Event.current.type == EventType.MouseUp)
{
if (GUIUtility.hotControl == controlId)
{
//OnMouseUp(Event.current);
//Return the hot control back to Unity, use the default
GUIUtility.hotControl = 0;
}
}
else if (Event.current.type == EventType.KeyDown)
{
//OnKeyDown(Event.current);
}
}
public static float DistanceMouseToSpline(Vector2 mousePosition, params Vector3[] splinePoint)
{
float d = float.MaxValue;
for (int i = 0; i < splinePoint.Length - 1; ++i)
{
float d1 = HandleUtility.DistancePointToLineSegment(
mousePosition,
HandleUtility.WorldToGUIPoint(splinePoint[i]),
HandleUtility.WorldToGUIPoint(splinePoint[i + 1]));
if (d1 < d)
d = d1;
}
return d;
}
public static float DistanceMouseToPoint(Vector2 mousePosition, Vector3 worldPoint)
{
float d = Vector2.Distance(
mousePosition,
HandleUtility.WorldToGUIPoint(worldPoint));
return d;
}
}
}
#endif