296 lines
8.5 KiB
C#
296 lines
8.5 KiB
C#
using UnityEditor;
|
|
using UnityEngine;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Obi{
|
|
|
|
/**
|
|
* Custom inspector for ObiSpline component.
|
|
*/
|
|
|
|
[CustomEditor(typeof(ObiCatmullRomCurve))]
|
|
public class ObiCatmullRomCurveEditor : Editor
|
|
{
|
|
|
|
ObiCatmullRomCurve spline;
|
|
|
|
private static int curvePreviewResolution = 10;
|
|
private bool hideSplineHandle;
|
|
|
|
private bool[] selectedStatus;
|
|
private Vector3[] handleVectors;
|
|
Vector3 scale = Vector3.one;
|
|
|
|
Rect uirect;
|
|
|
|
public void OnEnable(){
|
|
spline = (ObiCatmullRomCurve)target;
|
|
hideSplineHandle = false;
|
|
selectedStatus = new bool[spline.controlPoints.Count];
|
|
handleVectors = new Vector3[spline.controlPoints.Count];
|
|
}
|
|
|
|
private void ResizeCPArrays(){
|
|
Array.Resize(ref selectedStatus,spline.controlPoints.Count);
|
|
Array.Resize(ref handleVectors,spline.controlPoints.Count);
|
|
}
|
|
|
|
public override void OnInspectorGUI() {
|
|
|
|
serializedObject.UpdateIfRequiredOrScript();
|
|
|
|
Editor.DrawPropertiesExcluding(serializedObject,"m_Script");
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
bool closed = EditorGUILayout.Toggle("Closed",spline.Closed);
|
|
if (EditorGUI.EndChangeCheck()){
|
|
Undo.RecordObject(spline, "Open/Close curve");
|
|
spline.Closed = closed;
|
|
}
|
|
|
|
hideSplineHandle = EditorGUILayout.Toggle("Hide spline handle",hideSplineHandle);
|
|
|
|
if (GUILayout.Button("Add control point")){
|
|
Undo.RecordObject(spline, "Add control point");
|
|
|
|
for (int i = 0; i < spline.controlPoints.Count; ++i){
|
|
if (selectedStatus[i] || i == spline.controlPoints.Count-1){
|
|
|
|
Vector3 cp = spline.GetPositionAt((i-1+0.5f)/(float)(spline.controlPoints.Count-3));
|
|
|
|
spline.controlPoints.Insert(i+1,cp);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (GUILayout.Button("Remove selected control points")){
|
|
|
|
Undo.RecordObject(spline, "Remove control points");
|
|
List<int> toBeDeleted = new List<int>();
|
|
|
|
for (int i = 0; i < spline.controlPoints.Count; ++i){
|
|
if (selectedStatus[i]){
|
|
toBeDeleted.Add(i);
|
|
selectedStatus[i] = false;
|
|
}
|
|
}
|
|
|
|
if (spline.controlPoints.Count - toBeDeleted.Count < 4)
|
|
EditorUtility.DisplayDialog("Ooops!","Cannot remove that many points. Catmull-Rom splines need at least 4 points to be defined.","Ok");
|
|
else{
|
|
toBeDeleted.Sort();
|
|
toBeDeleted.Reverse();
|
|
foreach(int i in toBeDeleted)
|
|
spline.controlPoints.RemoveAt(i);
|
|
}
|
|
|
|
}
|
|
|
|
// Apply changes to the serializedProperty
|
|
if (GUI.changed){
|
|
serializedObject.ApplyModifiedProperties();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
public void SplineCPTools(Vector3[] controlPoints){
|
|
|
|
// Find center of all selected control points:
|
|
Vector3 averagePos = Vector3.zero;
|
|
int numSelectedCPs = 0;
|
|
for (int i = 0; i < controlPoints.Length; ++i){
|
|
if (selectedStatus[i]){
|
|
averagePos += controlPoints[i];
|
|
numSelectedCPs++;
|
|
}
|
|
}
|
|
averagePos /= numSelectedCPs;
|
|
|
|
// Calculate handle rotation, for local or world pivot modes.
|
|
Quaternion handleRotation = Tools.pivotRotation == PivotRotation.Local ? spline.transform.rotation : Quaternion.identity;
|
|
Tools.hidden = hideSplineHandle;
|
|
|
|
int oldHotControl = GUIUtility.hotControl;
|
|
|
|
// Transform handles:
|
|
if (numSelectedCPs > 0){
|
|
|
|
switch (Tools.current)
|
|
{
|
|
case Tool.Move:{
|
|
EditorGUI.BeginChangeCheck();
|
|
Vector3 newPos = Handles.PositionHandle(averagePos,handleRotation);
|
|
if (EditorGUI.EndChangeCheck()){
|
|
Undo.RecordObject(spline, "Move control point");
|
|
|
|
Vector3 delta = spline.transform.InverseTransformVector(newPos - averagePos);
|
|
|
|
for (int i = 0; i < controlPoints.Length; ++i){
|
|
if (selectedStatus[i]){
|
|
spline.DisplaceControlPoint(i,delta);
|
|
}
|
|
}
|
|
|
|
}
|
|
}break;
|
|
|
|
case Tool.Scale:{
|
|
EditorGUI.BeginChangeCheck();
|
|
scale = Handles.ScaleHandle(scale,averagePos,handleRotation,HandleUtility.GetHandleSize(averagePos));
|
|
|
|
// handle has just been (de)selected:
|
|
if (GUIUtility.hotControl != oldHotControl){
|
|
scale = Vector3.one;
|
|
for (int i = 0; i < controlPoints.Length; ++i){
|
|
if (selectedStatus[i]){
|
|
handleVectors[i] = controlPoints[i] - averagePos;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (EditorGUI.EndChangeCheck()){
|
|
|
|
Undo.RecordObject(spline, "Scale control point");
|
|
for (int i = 0; i < controlPoints.Length; ++i){
|
|
if (selectedStatus[i]){
|
|
Vector3 newPos = averagePos + Vector3.Scale(handleVectors[i],scale);
|
|
Vector3 delta = spline.transform.InverseTransformVector(newPos - controlPoints[i]);
|
|
spline.DisplaceControlPoint(i,delta);
|
|
}
|
|
}
|
|
|
|
}
|
|
}break;
|
|
|
|
case Tool.Rotate:{
|
|
EditorGUI.BeginChangeCheck();
|
|
Quaternion newRotation = Handles.RotationHandle(Quaternion.identity,averagePos);
|
|
|
|
// handle has just been (de)selected:
|
|
if (GUIUtility.hotControl != oldHotControl){
|
|
for (int i = 0; i < controlPoints.Length; ++i){
|
|
if (selectedStatus[i]){
|
|
handleVectors[i] = controlPoints[i] - averagePos;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (EditorGUI.EndChangeCheck()){
|
|
Undo.RecordObject(spline, "Rotate control point");
|
|
|
|
for (int i = 0; i < controlPoints.Length; ++i){
|
|
if (selectedStatus[i]){
|
|
Vector3 newPos = averagePos + newRotation*handleVectors[i];
|
|
Vector3 delta = spline.transform.InverseTransformVector(newPos - controlPoints[i]);
|
|
spline.DisplaceControlPoint(i,delta);
|
|
}
|
|
}
|
|
}
|
|
}break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Draws selected pin constraints in the scene view.
|
|
*/
|
|
public void OnSceneGUI(){
|
|
|
|
ResizeCPArrays();
|
|
|
|
if (spline.controlPoints.Count < 4)
|
|
return;
|
|
|
|
// World space control points:
|
|
Vector3[] controlPoints = new Vector3[spline.controlPoints.Count];
|
|
for (int i = 0; i < controlPoints.Length; ++i)
|
|
controlPoints[i] = spline.transform.TransformPoint(spline.controlPoints[i]);
|
|
|
|
if (Event.current.type == EventType.Repaint){
|
|
|
|
Matrix4x4 prevMatrix = Handles.matrix;
|
|
Handles.color = Color.white;
|
|
Handles.matrix = spline.transform.localToWorldMatrix;
|
|
|
|
// Draw tangents:
|
|
if (!spline.Closed){
|
|
Handles.color = Color.blue;
|
|
Handles.DrawDottedLine(spline.controlPoints[1],spline.controlPoints[0],2);
|
|
Handles.DrawDottedLine(spline.controlPoints[spline.controlPoints.Count-2],
|
|
spline.controlPoints[spline.controlPoints.Count-1],2);
|
|
}
|
|
|
|
Handles.matrix = prevMatrix;
|
|
|
|
// Draw control points:
|
|
for (int i = 0; i < controlPoints.Length; ++i){
|
|
|
|
Handles.color = (!spline.Closed && (i == 0 || i == controlPoints.Length-1)) ? Color.blue : Color.white;
|
|
|
|
if (spline.Closed && (i <= 2 || i >= controlPoints.Length-3)){
|
|
if ((i == 1 || i == controlPoints.Length-2) && (selectedStatus[1] || selectedStatus[controlPoints.Length-2]))
|
|
Handles.color = Color.red;
|
|
else if ((i == 2 || i == controlPoints.Length-1) && (selectedStatus[2] || selectedStatus[controlPoints.Length-1]))
|
|
Handles.color = Color.red;
|
|
else if ((i == 0 || i == controlPoints.Length-3) && (selectedStatus[0] || selectedStatus[controlPoints.Length-3]))
|
|
Handles.color = Color.red;
|
|
}else if (selectedStatus[i]){
|
|
Handles.color = Color.red;
|
|
}
|
|
|
|
float size = HandleUtility.GetHandleSize(controlPoints[i])*0.1f;
|
|
if (!spline.Closed && (i == 0 || i == controlPoints.Length-1))
|
|
Handles.DotHandleCap(0,controlPoints[i],Quaternion.identity,size*0.25f,EventType.Repaint);
|
|
else
|
|
Handles.SphereHandleCap(0,controlPoints[i],Quaternion.identity,size,EventType.Repaint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Control point selection handle:
|
|
if (ObiSplineHandles.SplineCPSelector(controlPoints,selectedStatus))
|
|
Repaint();
|
|
|
|
// Draw cp tool handles:
|
|
SplineCPTools(controlPoints);
|
|
|
|
}
|
|
|
|
|
|
[DrawGizmo(GizmoType.Selected)]
|
|
private static void GizmoTest(ObiCatmullRomCurve spline, GizmoType gizmoType)
|
|
{
|
|
|
|
Matrix4x4 prevMatrix = Handles.matrix;
|
|
Color oldColor = Handles.color;
|
|
|
|
// Draw the curve:
|
|
int curveSegments = spline.GetNumSpans() * curvePreviewResolution;
|
|
Vector3[] samples = new Vector3[curveSegments+1];
|
|
for (int i = 0; i <= curveSegments; ++i){
|
|
samples[i] = spline.GetPositionAt(i/(float)curveSegments);
|
|
}
|
|
|
|
Handles.matrix = spline.transform.localToWorldMatrix;
|
|
Handles.color = Color.white;
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
|
|
Handles.DrawPolyLine(samples);
|
|
|
|
Handles.color = new Color(1,1,1,0.25f);
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
|
|
Handles.DrawPolyLine(samples);
|
|
|
|
Handles.color = oldColor;
|
|
Handles.matrix = prevMatrix;
|
|
}
|
|
|
|
}
|
|
}
|
|
|