123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- using System.Collections;
- using System.Collections.Generic;
- using UnityEditor;
- using UnityEngine;
- namespace SplineMesh {
- [CustomEditor(typeof(Spline))]
- public class SplineEditor : Editor {
- private const int QUAD_SIZE = 12;
- private static Color CURVE_COLOR = new Color(0.8f, 0.8f, 0.8f);
- private static Color CURVE_BUTTON_COLOR = new Color(0.8f, 0.8f, 0.8f);
- private static Color DIRECTION_COLOR = Color.red;
- private static Color DIRECTION_BUTTON_COLOR = Color.red;
- private static Color UP_BUTTON_COLOR = Color.green;
- private static bool showUpVector = false;
- private enum SelectionType {
- Node,
- Direction,
- InverseDirection,
- Up
- }
- private SplineNode selection;
- private SelectionType selectionType;
- private bool mustCreateNewNode = false;
- private SerializedProperty nodesProp { get { return serializedObject.FindProperty("nodes"); } }
- private Spline spline { get { return (Spline)serializedObject.targetObject; } }
- private GUIStyle nodeButtonStyle, directionButtonStyle, upButtonStyle;
- private void OnEnable() {
- Texture2D t = new Texture2D(1, 1);
- t.SetPixel(0, 0, CURVE_BUTTON_COLOR);
- t.Apply();
- nodeButtonStyle = new GUIStyle();
- nodeButtonStyle.normal.background = t;
- t = new Texture2D(1, 1);
- t.SetPixel(0, 0, DIRECTION_BUTTON_COLOR);
- t.Apply();
- directionButtonStyle = new GUIStyle();
- directionButtonStyle.normal.background = t;
- t = new Texture2D(1, 1);
- t.SetPixel(0, 0, UP_BUTTON_COLOR);
- t.Apply();
- upButtonStyle = new GUIStyle();
- upButtonStyle.normal.background = t;
- selection = null;
-
- Undo.undoRedoPerformed -= spline.RefreshCurves;
- Undo.undoRedoPerformed += spline.RefreshCurves;
- }
- SplineNode AddClonedNode(SplineNode node) {
- int index = spline.nodes.IndexOf(node);
- SplineNode res = new SplineNode(node.Position, node.Direction);
- if (index == spline.nodes.Count - 1) {
- spline.AddNode(res);
- } else {
- spline.InsertNode(index + 1, res);
- }
- return res;
- }
- void OnSceneGUI() {
- // disable game object transform gyzmo
- // if the spline script is active
- if (Selection.activeGameObject == spline.gameObject) {
- if (!spline.enabled) {
- Tools.current = Tool.Move;
- } else {
- Tools.current = Tool.None;
- if (selection == null && spline.nodes.Count > 0)
- selection = spline.nodes[0];
- }
- }
- // draw a bezier curve for each curve in the spline
- foreach (CubicBezierCurve curve in spline.GetCurves()) {
- Handles.DrawBezier(spline.transform.TransformPoint(curve.n1.Position),
- spline.transform.TransformPoint(curve.n2.Position),
- spline.transform.TransformPoint(curve.n1.Direction),
- spline.transform.TransformPoint(curve.GetInverseDirection()),
- CURVE_COLOR,
- null,
- 3);
- }
- if (!spline.enabled)
- return;
- // draw the selection handles
- switch (selectionType) {
- case SelectionType.Node:
- // place a handle on the node and manage position change
- // TODO place the handle depending on user params (local or world)
- Vector3 newPosition = spline.transform.InverseTransformPoint(Handles.PositionHandle(spline.transform.TransformPoint(selection.Position), spline.transform.rotation));
- if (newPosition != selection.Position) {
- // position handle has been moved
- if (mustCreateNewNode) {
- mustCreateNewNode = false;
- selection = AddClonedNode(selection);
- selection.Direction += newPosition - selection.Position;
- selection.Position = newPosition;
- } else {
- selection.Direction += newPosition - selection.Position;
- selection.Position = newPosition;
- }
- }
- break;
- case SelectionType.Direction:
- var result = Handles.PositionHandle(spline.transform.TransformPoint(selection.Direction), Quaternion.identity);
- selection.Direction = spline.transform.InverseTransformPoint(result);
- break;
- case SelectionType.InverseDirection:
- result = Handles.PositionHandle(2 * spline.transform.TransformPoint(selection.Position) - spline.transform.TransformPoint(selection.Direction), Quaternion.identity);
- selection.Direction = 2 * selection.Position - spline.transform.InverseTransformPoint(result);
- break;
- case SelectionType.Up:
- result = Handles.PositionHandle(spline.transform.TransformPoint(selection.Position + selection.Up), Quaternion.LookRotation(selection.Direction - selection.Position));
- selection.Up = (spline.transform.InverseTransformPoint(result) - selection.Position).normalized;
- break;
- }
- // draw the handles of all nodes, and manage selection motion
- Handles.BeginGUI();
- foreach (SplineNode n in spline.nodes) {
- var dir = spline.transform.TransformPoint(n.Direction);
- var pos = spline.transform.TransformPoint(n.Position);
- var invDir = spline.transform.TransformPoint(2 * n.Position - n.Direction);
- var up = spline.transform.TransformPoint(n.Position + n.Up);
- // first we check if at least one thing is in the camera field of view
- if (!(CameraUtility.IsOnScreen(pos) ||
- CameraUtility.IsOnScreen(dir) ||
- CameraUtility.IsOnScreen(invDir) ||
- (showUpVector && CameraUtility.IsOnScreen(up)))) {
- continue;
- }
- Vector3 guiPos = HandleUtility.WorldToGUIPoint(pos);
- if (n == selection) {
- Vector3 guiDir = HandleUtility.WorldToGUIPoint(dir);
- Vector3 guiInvDir = HandleUtility.WorldToGUIPoint(invDir);
- Vector3 guiUp = HandleUtility.WorldToGUIPoint(up);
- // for the selected node, we also draw a line and place two buttons for directions
- Handles.color = DIRECTION_COLOR;
- Handles.DrawLine(guiDir, guiInvDir);
- // draw quads direction and inverse direction if they are not selected
- if (selectionType != SelectionType.Node) {
- if (Button(guiPos, directionButtonStyle)) {
- selectionType = SelectionType.Node;
- }
- }
- if (selectionType != SelectionType.Direction) {
- if (Button(guiDir, directionButtonStyle)) {
- selectionType = SelectionType.Direction;
- }
- }
- if (selectionType != SelectionType.InverseDirection) {
- if (Button(guiInvDir, directionButtonStyle)) {
- selectionType = SelectionType.InverseDirection;
- }
- }
- if (showUpVector) {
- Handles.color = Color.green;
- Handles.DrawLine(guiPos, guiUp);
- if (selectionType != SelectionType.Up) {
- if (Button(guiUp, upButtonStyle)) {
- selectionType = SelectionType.Up;
- }
- }
- }
- } else {
- if (Button(guiPos, nodeButtonStyle)) {
- selection = n;
- selectionType = SelectionType.Node;
- }
- }
- }
- Handles.EndGUI();
- if (GUI.changed)
- EditorUtility.SetDirty(target);
- }
- bool Button(Vector2 position, GUIStyle style) {
- return GUI.Button(new Rect(position - new Vector2(QUAD_SIZE / 2, QUAD_SIZE / 2), new Vector2(QUAD_SIZE, QUAD_SIZE)), GUIContent.none, style);
- }
- public override void OnInspectorGUI() {
- serializedObject.Update();
- if(spline.nodes.IndexOf(selection) < 0) {
- selection = null;
- }
- // add button
- if (selection == null) {
- GUI.enabled = false;
- }
- if (GUILayout.Button("Add node after selected")) {
- Undo.RecordObject(spline, "add spline node");
- SplineNode newNode = new SplineNode(selection.Direction, selection.Direction + selection.Direction - selection.Position);
- var index = spline.nodes.IndexOf(selection);
- if(index == spline.nodes.Count - 1) {
- spline.AddNode(newNode);
- } else {
- spline.InsertNode(index + 1, newNode);
- }
- selection = newNode;
- serializedObject.Update();
- }
- GUI.enabled = true;
- // delete button
- if (selection == null || spline.nodes.Count <= 2) {
- GUI.enabled = false;
- }
- if (GUILayout.Button("Delete selected node")) {
- Undo.RecordObject(spline, "delete spline node");
- spline.RemoveNode(selection);
- selection = null;
- serializedObject.Update();
- }
- GUI.enabled = true;
- showUpVector = GUILayout.Toggle(showUpVector, "Show up vector");
- spline.IsLoop = GUILayout.Toggle(spline.IsLoop, "Is loop");
- // nodes
- GUI.enabled = false;
- EditorGUILayout.PropertyField(nodesProp);
- GUI.enabled = true;
- if (selection != null) {
- int index = spline.nodes.IndexOf(selection);
- SerializedProperty nodeProp = nodesProp.GetArrayElementAtIndex(index);
- EditorGUILayout.LabelField("Selected node (node " + index + ")");
- EditorGUI.indentLevel++;
- DrawNodeData(nodeProp, selection);
- EditorGUI.indentLevel--;
- } else {
- EditorGUILayout.LabelField("No selected node");
- }
- }
- private void DrawNodeData(SerializedProperty nodeProperty, SplineNode node) {
- var positionProp = nodeProperty.FindPropertyRelative("position");
- var directionProp = nodeProperty.FindPropertyRelative("direction");
- var upProp = nodeProperty.FindPropertyRelative("up");
- var scaleProp = nodeProperty.FindPropertyRelative("scale");
- var rollProp = nodeProperty.FindPropertyRelative("roll");
- EditorGUI.BeginChangeCheck();
- EditorGUILayout.PropertyField(positionProp, new GUIContent("Position"));
- EditorGUILayout.PropertyField(directionProp, new GUIContent("Direction"));
- EditorGUILayout.PropertyField(upProp, new GUIContent("Up"));
- EditorGUILayout.PropertyField(scaleProp, new GUIContent("Scale"));
- EditorGUILayout.PropertyField(rollProp, new GUIContent("Roll"));
- if (EditorGUI.EndChangeCheck()) {
- node.Position = positionProp.vector3Value;
- node.Direction = directionProp.vector3Value;
- node.Up = upProp.vector3Value;
- node.Scale = scaleProp.vector2Value;
- node.Roll = rollProp.floatValue;
- serializedObject.Update();
- }
- }
- [MenuItem("GameObject/3D Object/Spline")]
- public static void CreateSpline() {
- new GameObject("Spline", typeof(Spline));
- }
- [DrawGizmo(GizmoType.InSelectionHierarchy)]
- static void DisplayUnselected(Spline spline, GizmoType gizmoType) {
- foreach (CubicBezierCurve curve in spline.GetCurves()) {
- Handles.DrawBezier(spline.transform.TransformPoint(curve.n1.Position),
- spline.transform.TransformPoint(curve.n2.Position),
- spline.transform.TransformPoint(curve.n1.Direction),
- spline.transform.TransformPoint(curve.GetInverseDirection()),
- CURVE_COLOR,
- null,
- 3);
- }
- }
- }
- }
|