init
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 671f4a431b4054141ac528dc52c4772e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,434 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
public class ComputerEditor : SplineEditorBase
|
||||
{
|
||||
SplineComputer spline = null;
|
||||
SplineComputer[] splines = new SplineComputer[0];
|
||||
SerializedObject serializedObject;
|
||||
bool pathToolsFoldout = false, interpolationFoldout = false;
|
||||
public bool drawComputer = true;
|
||||
public bool drawConnectedComputers = true;
|
||||
DreamteckSplinesEditor pathEditor;
|
||||
int operation = -1, module = -1, transformTool = 1;
|
||||
ComputerEditorModule[] modules = new ComputerEditorModule[0];
|
||||
Dreamteck.Editor.Toolbar utilityToolbar;
|
||||
Dreamteck.Editor.Toolbar operationsToolbar;
|
||||
Dreamteck.Editor.Toolbar transformToolbar;
|
||||
|
||||
public ComputerEditor(SplineComputer[] splines, SerializedObject serializedObject, DreamteckSplinesEditor pathEditor) : base()
|
||||
{
|
||||
spline = splines[0];
|
||||
this.splines = splines;
|
||||
this.pathEditor = pathEditor;
|
||||
this.serializedObject = serializedObject;
|
||||
modules = new ComputerEditorModule[2];
|
||||
modules[0] = new ComputerMergeModule(spline);
|
||||
modules[1] = new ComputerSplitModule(spline);
|
||||
GUIContent[] utilityContents = new GUIContent[modules.Length], utilityContentsSelected = new GUIContent[modules.Length];
|
||||
for (int i = 0; i < modules.Length; i++)
|
||||
{
|
||||
utilityContents[i] = modules[i].GetIconOff();
|
||||
utilityContentsSelected[i] = modules[i].GetIconOn();
|
||||
modules[i].undoHandler += OnRecordUndo;
|
||||
modules[i].repaintHandler += OnRepaint;
|
||||
}
|
||||
utilityToolbar = new Dreamteck.Editor.Toolbar(utilityContents, utilityContentsSelected, 35f);
|
||||
utilityToolbar.newLine = false;
|
||||
|
||||
|
||||
int index = 0;
|
||||
GUIContent[] transformContents = new GUIContent[4], transformContentsSelected = new GUIContent[4];
|
||||
transformContents[index] = new GUIContent("OFF");
|
||||
transformContentsSelected[index++] = new GUIContent("OFF");
|
||||
|
||||
transformContents[index] = EditorGUIUtility.IconContent("MoveTool");
|
||||
transformContentsSelected[index++] = EditorGUIUtility.IconContent("MoveTool On");
|
||||
|
||||
transformContents[index] = EditorGUIUtility.IconContent("RotateTool");
|
||||
transformContentsSelected[index++] = EditorGUIUtility.IconContent("RotateTool On");
|
||||
|
||||
transformContents[index] = EditorGUIUtility.IconContent("ScaleTool");
|
||||
transformContentsSelected[index] = EditorGUIUtility.IconContent("ScaleTool On");
|
||||
|
||||
transformToolbar = new Dreamteck.Editor.Toolbar(transformContents, transformContentsSelected, 35f);
|
||||
transformToolbar.newLine = false;
|
||||
|
||||
index = 0;
|
||||
GUIContent[] operationContents = new GUIContent[3], operationContentsSelected = new GUIContent[3];
|
||||
for (int i = 0; i < operationContents.Length; i++)
|
||||
{
|
||||
operationContents[i] = new GUIContent("");
|
||||
operationContentsSelected[i] = new GUIContent("");
|
||||
}
|
||||
operationsToolbar = new Dreamteck.Editor.Toolbar(operationContents, operationContentsSelected, 64f);
|
||||
operationsToolbar.newLine = false;
|
||||
}
|
||||
|
||||
void OnRecordUndo(string title)
|
||||
{
|
||||
if (undoHandler != null) undoHandler(title);
|
||||
}
|
||||
|
||||
void OnRepaint()
|
||||
{
|
||||
if (repaintHandler != null) repaintHandler();
|
||||
}
|
||||
|
||||
protected override void Load()
|
||||
{
|
||||
base.Load();
|
||||
pathToolsFoldout = LoadBool("DreamteckSplinesEditor.pathToolsFoldout", false);
|
||||
interpolationFoldout = LoadBool("DreamteckSplinesEditor.interpolationFoldout", false);
|
||||
transformTool = LoadInt("DreamteckSplinesEditor.transformTool", 0);
|
||||
}
|
||||
|
||||
protected override void Save()
|
||||
{
|
||||
base.Save();
|
||||
SaveBool("DreamteckSplinesEditor.pathToolsFoldout", pathToolsFoldout);
|
||||
SaveBool("DreamteckSplinesEditor.interpolationFoldout", interpolationFoldout);
|
||||
SaveInt("DreamteckSplinesEditor.transformTool", transformTool);
|
||||
}
|
||||
|
||||
public override void Destroy()
|
||||
{
|
||||
base.Destroy();
|
||||
for (int i = 0; i < modules.Length; i++) modules[i].Deselect();
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
base.DrawInspector();
|
||||
if (spline == null) return;
|
||||
SplineEditorGUI.SetHighlightColors(SplinePrefs.highlightColor, SplinePrefs.highlightContentColor);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
EditorGUI.BeginChangeCheck();
|
||||
operationsToolbar.SetContent(0, new GUIContent(spline.isClosed ? "Break" : "Close"));
|
||||
operationsToolbar.SetContent(1, new GUIContent("Reverse"));
|
||||
operationsToolbar.SetContent(2, new GUIContent(spline.is2D ? "3D Mode" : "2D Mode"));
|
||||
operationsToolbar.Draw(ref operation);
|
||||
//operation = GUILayout.Toolbar(operation, new string[] { , "Reverse", text2D }, GUILayout.Width(220f));
|
||||
if (EditorGUI.EndChangeCheck()) PerformOperation();
|
||||
EditorGUI.BeginChangeCheck();
|
||||
if (splines.Length == 1)
|
||||
{
|
||||
int mod = module;
|
||||
utilityToolbar.Draw(ref mod);
|
||||
if (EditorGUI.EndChangeCheck()) ToggleModule(mod);
|
||||
}
|
||||
GUILayout.FlexibleSpace();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
if (module >= 0 && module < modules.Length) modules[module].DrawInspector();
|
||||
EditorGUILayout.Space();
|
||||
DreamteckEditorGUI.DrawSeparator();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
serializedObject.Update();
|
||||
SerializedProperty splineProperty = serializedObject.FindProperty("spline");
|
||||
SerializedProperty sampleRate = serializedObject.FindProperty("spline").FindPropertyRelative("sampleRate");
|
||||
SerializedProperty type = serializedObject.FindProperty("spline").FindPropertyRelative("type");
|
||||
SerializedProperty linearAverageDirection = splineProperty.FindPropertyRelative("linearAverageDirection");
|
||||
SerializedProperty space = serializedObject.FindProperty("_space");
|
||||
SerializedProperty sampleMode = serializedObject.FindProperty("_sampleMode");
|
||||
SerializedProperty optimizeAngleThreshold = serializedObject.FindProperty("_optimizeAngleThreshold");
|
||||
SerializedProperty updateMode = serializedObject.FindProperty("updateMode");
|
||||
SerializedProperty rebuildOnAwake = serializedObject.FindProperty("rebuildOnAwake");
|
||||
SerializedProperty multithreaded = serializedObject.FindProperty("multithreaded");
|
||||
SerializedProperty customNormalInterpolation = splineProperty.FindPropertyRelative("customNormalInterpolation");
|
||||
SerializedProperty customValueInterpolation = splineProperty.FindPropertyRelative("customValueInterpolation");
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Spline.Type lastType = (Spline.Type)type.intValue;
|
||||
EditorGUILayout.PropertyField(type);
|
||||
if(lastType == Spline.Type.Hermite && type.intValue == (int)Spline.Type.Bezier)
|
||||
{
|
||||
if(EditorUtility.DisplayDialog("Hermite to Bezier", "Would you like to retain the Hermite shape in Bezier mode?", "Yes", "No"))
|
||||
{
|
||||
for (int i = 0; i < splines.Length; i++) splines[i].HermiteToBezierTangents();
|
||||
|
||||
serializedObject.Update();
|
||||
pathEditor.Refresh();
|
||||
}
|
||||
}
|
||||
if(spline.type == Spline.Type.Linear) EditorGUILayout.PropertyField(linearAverageDirection);
|
||||
int lastSpace = space.intValue;
|
||||
EditorGUILayout.PropertyField(space, new GUIContent("Space"));
|
||||
EditorGUILayout.PropertyField(sampleMode, new GUIContent("Sample Mode"));
|
||||
if (sampleMode.intValue == (int)SplineComputer.SampleMode.Optimized) EditorGUILayout.PropertyField(optimizeAngleThreshold);
|
||||
EditorGUILayout.PropertyField(updateMode);
|
||||
if (updateMode.intValue == (int)SplineComputer.UpdateMode.None)
|
||||
{
|
||||
if (GUILayout.Button("Manual Update"))
|
||||
{
|
||||
for (int i = 0; i < splines.Length; i++) splines[i].RebuildImmediate(true, true);
|
||||
}
|
||||
}
|
||||
if (spline.type != Spline.Type.Linear) EditorGUILayout.PropertyField(sampleRate, new GUIContent("Sample Rate"));
|
||||
EditorGUILayout.PropertyField(rebuildOnAwake);
|
||||
EditorGUILayout.PropertyField(multithreaded);
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
bool curveUpdate = false;
|
||||
interpolationFoldout = EditorGUILayout.Foldout(interpolationFoldout, "Custom interpolation");
|
||||
if (interpolationFoldout)
|
||||
{
|
||||
if (customValueInterpolation.animationCurveValue == null || customValueInterpolation.animationCurveValue.keys.Length == 0)
|
||||
{
|
||||
if (GUILayout.Button("Add Value Interpolation"))
|
||||
{
|
||||
AnimationCurve curve = new AnimationCurve();
|
||||
curve.AddKey(new Keyframe(0, 0, 0, 0));
|
||||
curve.AddKey(new Keyframe(1, 1, 0, 0));
|
||||
for (int i = 0; i < splines.Length; i++) splines[i].customValueInterpolation = curve;
|
||||
serializedObject.Update();
|
||||
curveUpdate = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PropertyField(customValueInterpolation, new GUIContent("Value Interpolation"));
|
||||
if (GUILayout.Button("x", GUILayout.MaxWidth(25)))
|
||||
{
|
||||
customValueInterpolation.animationCurveValue = null;
|
||||
for (int i = 0; i < splines.Length; i++) splines[i].customValueInterpolation = null;
|
||||
serializedObject.Update();
|
||||
curveUpdate = true;
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
if (customNormalInterpolation.animationCurveValue == null || customNormalInterpolation.animationCurveValue.keys.Length == 0)
|
||||
{
|
||||
if (GUILayout.Button("Add Normal Interpolation"))
|
||||
{
|
||||
AnimationCurve curve = new AnimationCurve();
|
||||
curve.AddKey(new Keyframe(0, 0));
|
||||
curve.AddKey(new Keyframe(1, 1));
|
||||
for (int i = 0; i < splines.Length; i++) splines[i].customNormalInterpolation = curve;
|
||||
serializedObject.Update();
|
||||
curveUpdate = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PropertyField(customNormalInterpolation, new GUIContent("Normal Interpolation"));
|
||||
if (GUILayout.Button("x", GUILayout.MaxWidth(25)))
|
||||
{
|
||||
customNormalInterpolation.animationCurveValue = null;
|
||||
for (int i = 0; i < splines.Length; i++) splines[i].customNormalInterpolation = null;
|
||||
serializedObject.Update();
|
||||
curveUpdate = true;
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
if (EditorGUI.EndChangeCheck() || curveUpdate)
|
||||
{
|
||||
if (sampleRate.intValue < 2) sampleRate.intValue = 2;
|
||||
if (lastSpace != space.intValue)
|
||||
{
|
||||
for (int i = 0; i < splines.Length; i++) splines[i].space = (SplineComputer.Space)space.intValue;
|
||||
serializedObject.Update();
|
||||
if (splines.Length == 1) pathEditor.Refresh();
|
||||
}
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
for (int i = 0; i < splines.Length; i++) splines[i].Rebuild(true);
|
||||
}
|
||||
|
||||
if (space.intValue == (int)SplineComputer.Space.Local)
|
||||
{
|
||||
if (pathEditor.currentModule != null) transformTool = 0;
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Edit Transform");
|
||||
GUILayout.FlexibleSpace();
|
||||
int lastTool = transformTool;
|
||||
transformToolbar.Draw(ref transformTool);
|
||||
if (lastTool != transformTool && transformTool > 0) pathEditor.UntoggleCurrentModule();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
void PerformOperation()
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case 0:
|
||||
if (spline.isClosed) BreakSpline();
|
||||
else CloseSpline();
|
||||
operation = -1;
|
||||
break;
|
||||
case 1:
|
||||
ReversePointOrder();
|
||||
operation = -1;
|
||||
break;
|
||||
case 2:
|
||||
spline.is2D = !spline.is2D;
|
||||
operation = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ToggleModule(int index)
|
||||
{
|
||||
if (module >= 0 && module < modules.Length) modules[module].Deselect();
|
||||
if (module == index) index = -1;
|
||||
module = index;
|
||||
if (module >= 0 && module < modules.Length) modules[module].Select();
|
||||
}
|
||||
|
||||
public void BreakSpline()
|
||||
{
|
||||
RecordUndo("Break path");
|
||||
if (splines.Length == 1 && pathEditor.selectedPoints.Count == 1) spline.Break(pathEditor.selectedPoints[0]);
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < splines.Length; i++) splines[i].Break();
|
||||
}
|
||||
}
|
||||
|
||||
public void CloseSpline()
|
||||
{
|
||||
RecordUndo("Close path");
|
||||
for (int i = 0; i < splines.Length; i++)
|
||||
{
|
||||
splines[i].Close();
|
||||
}
|
||||
}
|
||||
|
||||
void ReversePointOrder()
|
||||
{
|
||||
for (int i = 0; i < splines.Length; i++)
|
||||
{
|
||||
ReversePointOrder(splines[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ReversePointOrder(SplineComputer spline)
|
||||
{
|
||||
SplinePoint[] points = spline.GetPoints();
|
||||
for (int i = 0; i < Mathf.FloorToInt(points.Length / 2); i++)
|
||||
{
|
||||
SplinePoint temp = points[i];
|
||||
points[i] = points[(points.Length - 1) - i];
|
||||
Vector3 tempTan = points[i].tangent;
|
||||
points[i].tangent = points[i].tangent2;
|
||||
points[i].tangent2 = tempTan;
|
||||
int opposideIndex = (points.Length - 1) - i;
|
||||
points[opposideIndex] = temp;
|
||||
tempTan = points[opposideIndex].tangent;
|
||||
points[opposideIndex].tangent = points[opposideIndex].tangent2;
|
||||
points[opposideIndex].tangent2 = tempTan;
|
||||
}
|
||||
if (points.Length % 2 != 0)
|
||||
{
|
||||
Vector3 tempTan = points[Mathf.CeilToInt(points.Length / 2)].tangent;
|
||||
points[Mathf.CeilToInt(points.Length / 2)].tangent = points[Mathf.CeilToInt(points.Length / 2)].tangent2;
|
||||
points[Mathf.CeilToInt(points.Length / 2)].tangent2 = tempTan;
|
||||
}
|
||||
spline.SetPoints(points);
|
||||
}
|
||||
|
||||
public override void DrawScene()
|
||||
{
|
||||
base.DrawScene();
|
||||
if (drawComputer)
|
||||
{
|
||||
for (int i = 0; i < splines.Length; i++)
|
||||
{
|
||||
SplineDrawer.DrawSplineComputer(splines[i]);
|
||||
}
|
||||
|
||||
}
|
||||
if (drawConnectedComputers)
|
||||
{
|
||||
for (int i = 0; i < splines.Length; i++)
|
||||
{
|
||||
List<SplineComputer> computers = splines[i].GetConnectedComputers();
|
||||
for (int j = 1; j < computers.Count; j++)
|
||||
{
|
||||
SplineDrawer.DrawSplineComputer(computers[j], 0.0, 1.0, 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (pathEditor.currentModule == null)
|
||||
{
|
||||
switch (transformTool)
|
||||
{
|
||||
case 1:
|
||||
for (int i = 0; i < splines.Length; i++)
|
||||
{
|
||||
Vector3 position = splines[i].transform.position;
|
||||
position = Handles.PositionHandle(position, splines[i].transform.rotation);
|
||||
if (position != splines[i].transform.position)
|
||||
{
|
||||
RecordUndo("Move spline computer");
|
||||
Undo.RecordObject(splines[i].transform, "Move spline computer");
|
||||
splines[i].transform.position = position;
|
||||
splines[i].SetPoints(pathEditor.points);
|
||||
pathEditor.Refresh();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (int i = 0; i < splines.Length; i++)
|
||||
{
|
||||
Quaternion rotation = splines[i].transform.rotation;
|
||||
rotation = Handles.RotationHandle(rotation, splines[i].transform.position);
|
||||
if (rotation != splines[i].transform.rotation)
|
||||
{
|
||||
RecordUndo("Rotate spline computer");
|
||||
Undo.RecordObject(splines[i].transform, "Rotate spline computer");
|
||||
splines[i].transform.rotation = rotation;
|
||||
splines[i].SetPoints(pathEditor.points);
|
||||
pathEditor.Refresh();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
for (int i = 0; i < splines.Length; i++)
|
||||
{
|
||||
Vector3 scale = splines[i].transform.localScale;
|
||||
scale = Handles.ScaleHandle(scale, splines[i].transform.position, splines[i].transform.rotation,
|
||||
HandleUtility.GetHandleSize(splines[i].transform.position));
|
||||
if (scale != splines[i].transform.localScale)
|
||||
{
|
||||
RecordUndo("Scale spline computer");
|
||||
Undo.RecordObject(splines[i].transform, "Scale spline computer");
|
||||
splines[i].transform.localScale = scale;
|
||||
splines[i].SetPoints(pathEditor.points);
|
||||
pathEditor.Refresh();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (transformTool > 0)
|
||||
{
|
||||
for (int i = 0; i < splines.Length; i++)
|
||||
{
|
||||
Vector2 screenPosition = HandleUtility.WorldToGUIPoint(splines[i].transform.position);
|
||||
screenPosition.y += 20f;
|
||||
Handles.BeginGUI();
|
||||
DreamteckEditorGUI.Label(new Rect(screenPosition.x - 120 + splines[i].name.Length * 4, screenPosition.y, 120, 25), splines[i].name);
|
||||
Handles.EndGUI();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (module >= 0 && module < modules.Length) modules[module].DrawScene();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e59af6b243fa55640b014783bedaaae3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
public class ComputerEditorModule : EditorModule
|
||||
{
|
||||
protected SplineComputer spline;
|
||||
public SplineEditorBase.UndoHandler undoHandler;
|
||||
public EmptySplineHandler repaintHandler;
|
||||
|
||||
public ComputerEditorModule(SplineComputer spline)
|
||||
{
|
||||
this.spline = spline;
|
||||
}
|
||||
|
||||
protected override void RecordUndo(string title)
|
||||
{
|
||||
base.RecordUndo(title);
|
||||
if (undoHandler != null) undoHandler(title);
|
||||
}
|
||||
|
||||
protected override void Repaint()
|
||||
{
|
||||
base.Repaint();
|
||||
if (repaintHandler != null) repaintHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17f0469145b8d194f8e96c0e083d5b72
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,209 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
|
||||
public class ComputerMergeModule : ComputerEditorModule
|
||||
{
|
||||
SplineComputer[] availableMergeComputers = new SplineComputer[0];
|
||||
public enum MergeSide { Start, End }
|
||||
public MergeSide mergeSide = MergeSide.End;
|
||||
public bool mergeEndpoints = false;
|
||||
|
||||
public ComputerMergeModule(SplineComputer spline) : base(spline)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOff()
|
||||
{
|
||||
return IconContent("Merge", "merge", "Merge Splines");
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOn()
|
||||
{
|
||||
return IconContent("Merge", "merge_on", "Merge Splines");
|
||||
}
|
||||
|
||||
public override void LoadState()
|
||||
{
|
||||
mergeEndpoints = LoadBool("mergeEndpoints");
|
||||
mergeSide = (MergeSide)LoadInt("mergeSide");
|
||||
}
|
||||
|
||||
public override void SaveState()
|
||||
{
|
||||
SaveBool("mergeEndpoints", mergeEndpoints);
|
||||
SaveInt("mergeSide", (int)mergeSide);
|
||||
}
|
||||
|
||||
public override void Select()
|
||||
{
|
||||
base.Select();
|
||||
FindAvailableComputers();
|
||||
}
|
||||
|
||||
void FindAvailableComputers()
|
||||
{
|
||||
SplineComputer[] found = Object.FindObjectsOfType<SplineComputer>();
|
||||
List<SplineComputer> available = new List<SplineComputer>();
|
||||
for (int i = 0; i < found.Length; i++)
|
||||
{
|
||||
if (found[i] != spline && !found[i].isClosed && spline.pointCount >= 2) available.Add(found[i]);
|
||||
}
|
||||
availableMergeComputers = available.ToArray();
|
||||
}
|
||||
|
||||
public override void DrawScene()
|
||||
{
|
||||
base.DrawScene();
|
||||
if (spline.isClosed) return;
|
||||
Camera editorCamera = SceneView.currentDrawingSceneView.camera;
|
||||
for (int i = 0; i < availableMergeComputers.Length; i++)
|
||||
{
|
||||
SplineDrawer.DrawSplineComputer(availableMergeComputers[i]);
|
||||
SplinePoint startPoint = availableMergeComputers[i].GetPoint(0);
|
||||
SplinePoint endPoint = availableMergeComputers[i].GetPoint(availableMergeComputers[i].pointCount - 1);
|
||||
Handles.color = availableMergeComputers[i].editorPathColor;
|
||||
|
||||
if (SplineEditorHandles.CircleButton(startPoint.position, Quaternion.LookRotation(editorCamera.transform.position - startPoint.position), HandleUtility.GetHandleSize(startPoint.position) * 0.15f, 1f, availableMergeComputers[i].editorPathColor))
|
||||
{
|
||||
Merge(i, MergeSide.Start);
|
||||
break;
|
||||
}
|
||||
if (SplineEditorHandles.CircleButton(endPoint.position, Quaternion.LookRotation(editorCamera.transform.position - endPoint.position), HandleUtility.GetHandleSize(endPoint.position) * 0.15f, 1f, availableMergeComputers[i].editorPathColor))
|
||||
{
|
||||
Merge(i, MergeSide.End);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Handles.color = Color.white;
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
base.DrawInspector();
|
||||
if (spline.isClosed)
|
||||
{
|
||||
EditorGUILayout.LabelField("Closed splines cannot be merged with others.", EditorStyles.centeredGreyMiniLabel);
|
||||
return;
|
||||
}
|
||||
mergeSide = (MergeSide)EditorGUILayout.EnumPopup("Merge:", mergeSide);
|
||||
mergeEndpoints = EditorGUILayout.Toggle("Merge Endpoints", mergeEndpoints);
|
||||
}
|
||||
|
||||
void Merge(int index, MergeSide mergingSide)
|
||||
{
|
||||
RecordUndo("Merge Splines");
|
||||
SplineComputer mergedSpline = availableMergeComputers[index];
|
||||
SplinePoint[] mergedPoints = mergedSpline.GetPoints();
|
||||
SplinePoint[] original = spline.GetPoints();
|
||||
List<SplinePoint> pointsList = new List<SplinePoint>();
|
||||
SplinePoint[] points;
|
||||
if (!mergeEndpoints) points = new SplinePoint[mergedPoints.Length + original.Length];
|
||||
else points = new SplinePoint[mergedPoints.Length + original.Length - 1];
|
||||
|
||||
if(mergeSide == MergeSide.End)
|
||||
{
|
||||
if(mergingSide == MergeSide.Start)
|
||||
{
|
||||
for (int i = 0; i < original.Length; i++) pointsList.Add(original[i]);
|
||||
for (int i = mergeEndpoints ? 1 : 0; i < mergedPoints.Length; i++) pointsList.Add(mergedPoints[i]);
|
||||
} else
|
||||
{
|
||||
for (int i = 0; i < original.Length; i++) pointsList.Add(original[i]);
|
||||
for (int i = 0; i < mergedPoints.Length - (mergeEndpoints ? 1 : 0); i++) pointsList.Add(mergedPoints[(mergedPoints.Length-1)-i]);
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (mergingSide == MergeSide.Start)
|
||||
{
|
||||
for (int i = 0; i < mergedPoints.Length - (mergeEndpoints ? 1 : 0); i++) pointsList.Add(mergedPoints[(mergedPoints.Length - 1) - i]);
|
||||
for (int i = 0; i < original.Length; i++) pointsList.Add(original[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = mergeEndpoints ? 1 : 0; i < mergedPoints.Length; i++) pointsList.Add(mergedPoints[i]);
|
||||
for (int i = 0; i < original.Length; i++) pointsList.Add(original[i]);
|
||||
}
|
||||
}
|
||||
points = pointsList.ToArray();
|
||||
double mergedPercent = (double)(mergedPoints.Length-1) / (points.Length-1);
|
||||
double from = 0.0;
|
||||
double to = 1.0;
|
||||
if (mergeSide == MergeSide.End)
|
||||
{
|
||||
from = 1.0 - mergedPercent;
|
||||
to = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
from = 0.0;
|
||||
to = mergedPercent;
|
||||
}
|
||||
|
||||
|
||||
List<Node> mergedNodes = new List<Node>();
|
||||
List<int> mergedIndices = new List<int>();
|
||||
|
||||
for (int i = 0; i < mergedSpline.pointCount; i++)
|
||||
{
|
||||
Node node = mergedSpline.GetNode(i);
|
||||
if (node != null)
|
||||
{
|
||||
mergedNodes.Add(node);
|
||||
mergedIndices.Add(i);
|
||||
Undo.RecordObject(node, "Disconnect Node");
|
||||
mergedSpline.DisconnectNode(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
SplineUser[] subs = mergedSpline.GetSubscribers();
|
||||
for (int i = 0; i < subs.Length; i++)
|
||||
{
|
||||
mergedSpline.Unsubscribe(subs[i]);
|
||||
subs[i].spline = spline;
|
||||
subs[i].clipFrom = DMath.Lerp(from, to, subs[i].clipFrom);
|
||||
subs[i].clipTo = DMath.Lerp(from, to, subs[i].clipTo);
|
||||
}
|
||||
spline.SetPoints(points);
|
||||
|
||||
if (mergeSide == MergeSide.Start)
|
||||
{
|
||||
spline.ShiftNodes(0, spline.pointCount - 1, mergedSpline.pointCount);
|
||||
for (int i = 0; i < mergedNodes.Count; i++)
|
||||
{
|
||||
spline.ConnectNode(mergedNodes[i], mergedIndices[i]);
|
||||
}
|
||||
} else
|
||||
{
|
||||
for (int i = 0; i < mergedNodes.Count; i++)
|
||||
{
|
||||
int connectIndex = mergedIndices[i] + original.Length;
|
||||
if (mergeEndpoints) connectIndex--;
|
||||
spline.ConnectNode(mergedNodes[i], connectIndex);
|
||||
}
|
||||
}
|
||||
if (EditorUtility.DisplayDialog("Keep merged computer's GameObject?", "Do you want to keep the merged computer's game object?", "Yes", "No"))
|
||||
{
|
||||
Undo.DestroyObjectImmediate(mergedSpline);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < mergedNodes.Count; i++)
|
||||
{
|
||||
if(TransformUtility.IsParent(mergedNodes[i].transform, mergedSpline.transform))
|
||||
{
|
||||
Undo.SetTransformParent(mergedNodes[i].transform, mergedSpline.transform.parent, "Reparent Node");
|
||||
}
|
||||
}
|
||||
Undo.DestroyObjectImmediate(mergedSpline.gameObject);
|
||||
}
|
||||
|
||||
FindAvailableComputers();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50db3c9801774b24cbb81bdf47a3f852
|
||||
timeCreated: 1476814299
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,114 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
public class DSCreatePointModule : CreatePointModule
|
||||
{
|
||||
DreamteckSplinesEditor dsEditor;
|
||||
private bool createNode = false;
|
||||
|
||||
|
||||
public DSCreatePointModule(SplineEditor editor) : base(editor)
|
||||
{
|
||||
dsEditor = (DreamteckSplinesEditor)editor;
|
||||
}
|
||||
|
||||
public override void LoadState()
|
||||
{
|
||||
base.LoadState();
|
||||
createNode = LoadBool("createNode");
|
||||
}
|
||||
|
||||
public override void SaveState()
|
||||
{
|
||||
base.SaveState();
|
||||
SaveBool("createNode", createNode);
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
base.DrawInspector();
|
||||
createNode = EditorGUILayout.Toggle("Create Node", createNode);
|
||||
}
|
||||
|
||||
protected override void CreateSplinePoint(Vector3 position, Vector3 normal)
|
||||
{
|
||||
RecordUndo("Create Point");
|
||||
GUIUtility.hotControl = GUIUtility.GetControlID(FocusType.Passive);
|
||||
List<int> indices = new List<int>();
|
||||
List<Node> nodes = new List<Node>();
|
||||
SplineComputer spline = dsEditor.spline;
|
||||
AddPoint();
|
||||
bool closeSpline = false;
|
||||
if (!isClosed && points.Length >= 3)
|
||||
{
|
||||
Vector2 first = HandleUtility.WorldToGUIPoint(points[0].position);
|
||||
Vector2 last = HandleUtility.WorldToGUIPoint(points[points.Length - 1].position);
|
||||
if (Vector2.Distance(first, last) <= 20f) if (EditorUtility.DisplayDialog("Close spline?", "Do you want to make the spline path closed ?", "Yes", "No")) closeSpline = true;
|
||||
}
|
||||
|
||||
if (appendMode == AppendMode.End)
|
||||
{
|
||||
for (int i = 0; i < indices.Count; i++) nodes[i].AddConnection(spline, indices[i] + 1);
|
||||
}
|
||||
|
||||
if (createNode)
|
||||
{
|
||||
if (appendMode == 0) CreateNodeForPoint(points.Length - 1);
|
||||
else CreateNodeForPoint(0);
|
||||
}
|
||||
if (closeSpline) editor.isClosed = true;
|
||||
dsEditor.UpdateSpline();
|
||||
if (appendMode == AppendMode.Beginning) spline.ShiftNodes(0, spline.pointCount-1, 1);
|
||||
}
|
||||
|
||||
protected override void InsertMode(Vector3 screenCoordinates)
|
||||
{
|
||||
base.InsertMode(screenCoordinates);
|
||||
double percent = ProjectScreenSpace(screenCoordinates);
|
||||
editor.evaluate(percent, evalResult);
|
||||
if (editor.eventModule.mouseRight)
|
||||
{
|
||||
SplineEditorHandles.DrawCircle(evalResult.position, Quaternion.LookRotation(editorCamera.transform.position - evalResult.position), HandleUtility.GetHandleSize(evalResult.position) * 0.2f);
|
||||
return;
|
||||
}
|
||||
if (SplineEditorHandles.CircleButton(evalResult.position, Quaternion.LookRotation(editorCamera.transform.position - evalResult.position), HandleUtility.GetHandleSize(evalResult.position) * 0.2f, 1.5f, color))
|
||||
{
|
||||
RecordUndo("Create Point");
|
||||
SplinePoint newPoint = new SplinePoint(evalResult.position, evalResult.position);
|
||||
newPoint.size = evalResult.size;
|
||||
newPoint.color = evalResult.color;
|
||||
newPoint.normal = evalResult.up;
|
||||
SplinePoint[] newPoints = new SplinePoint[points.Length + 1];
|
||||
double floatIndex = (points.Length - 1) * percent;
|
||||
int pointIndex = Mathf.Clamp(DMath.FloorInt(floatIndex), 0, points.Length - 2);
|
||||
for (int i = 0; i < newPoints.Length; i++)
|
||||
{
|
||||
if (i <= pointIndex) newPoints[i] = points[i];
|
||||
else if (i == pointIndex + 1) newPoints[i] = newPoint;
|
||||
else newPoints[i] = points[i - 1];
|
||||
}
|
||||
SplineComputer spline = dsEditor.spline;
|
||||
points = newPoints;
|
||||
lastCreated = points.Length - 1;
|
||||
dsEditor.UpdateSpline();
|
||||
spline.ShiftNodes(pointIndex + 1, spline.pointCount - 1, 1);
|
||||
if (createNode) CreateNodeForPoint(pointIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void CreateNodeForPoint(int index)
|
||||
{
|
||||
dsEditor.UpdateSpline();
|
||||
GameObject obj = new GameObject("Node_" + (points.Length - 1));
|
||||
obj.transform.parent = dsEditor.spline.transform;
|
||||
Node node = obj.AddComponent<Node>();
|
||||
node.transform.localRotation = Quaternion.identity;
|
||||
node.transform.position = points[index].position;
|
||||
node.AddConnection(dsEditor.spline, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 870db4c17be74374e93a8dbc31114a05
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,164 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
public class DreamteckSplinesEditor : SplineEditor
|
||||
{
|
||||
public SplineComputer spline = null;
|
||||
|
||||
public DreamteckSplinesEditor(SplineComputer spline, string name) : base (spline.transform, name)
|
||||
{
|
||||
this.spline = spline;
|
||||
evaluate = spline.Evaluate;
|
||||
evaluateAtPoint = spline.Evaluate;
|
||||
evaluatePosition = spline.EvaluatePosition;
|
||||
calculateLength = spline.CalculateLength;
|
||||
travel = spline.Travel;
|
||||
undoHandler = HandleUndo;
|
||||
mainModule.onBeforeDeleteSelectedPoints += OnBeforeDeleteSelectedPoints;
|
||||
mainModule.onDuplicatePoint += OnDuplicatePoint;
|
||||
if (spline.isNewlyCreated)
|
||||
{
|
||||
if (SplinePrefs.startInCreationMode)
|
||||
{
|
||||
open = true;
|
||||
ToggleModule(0);
|
||||
}
|
||||
spline.isNewlyCreated = false;
|
||||
}
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void OnDuplicatePoint(int[] points)
|
||||
{
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
spline.ShiftNodes(points[i], spline.pointCount - 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBeforeDeleteSelectedPoints()
|
||||
{
|
||||
string nodeString = "";
|
||||
List <Node> deleteNodes = new List<Node>();
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
spline.DisconnectNode(selectedPoints[i]);
|
||||
Node node = spline.GetNode(selectedPoints[i]);
|
||||
if (node != null && node.GetConnections().Length == 0)
|
||||
{
|
||||
deleteNodes.Add(node);
|
||||
if (nodeString != "") nodeString += ", ";
|
||||
string trimmed = node.name.Trim();
|
||||
if (nodeString.Length + trimmed.Length > 80) nodeString += "...";
|
||||
else nodeString += node.name.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
if (deleteNodes.Count > 0)
|
||||
{
|
||||
string message = "The following nodes:\r\n" + nodeString + "\r\n were only connected to the currently selected points. Would you like to remove them from the scene?";
|
||||
if (EditorUtility.DisplayDialog("Remove nodes?", message, "Yes", "No"))
|
||||
{
|
||||
for (int i = 0; i < deleteNodes.Count; i++) Undo.DestroyObjectImmediate(deleteNodes[i].gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
int min = spline.pointCount - 1;
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
if (selectedPoints[i] < min) min = selectedPoints[i];
|
||||
}
|
||||
for (int i = min+1; i < spline.pointCount; i++)
|
||||
{
|
||||
Node node = spline.GetNode(i);
|
||||
if(node != null)
|
||||
{
|
||||
int pointsDeletedBefore = 0;
|
||||
for (int j = 0; j < selectedPoints.Count; j++)
|
||||
{
|
||||
if (selectedPoints[j] >= min) pointsDeletedBefore++;
|
||||
}
|
||||
spline.ShiftNodes(i, spline.pointCount-1, -pointsDeletedBefore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override void OnModuleList(List<PointModule> list)
|
||||
{
|
||||
list.Add(new DSCreatePointModule(this));
|
||||
list.Add(new DeletePointModule(this));
|
||||
list.Add(new PointMoveModule(this));
|
||||
list.Add(new PointRotateModule(this));
|
||||
list.Add(new PointScaleModule(this));
|
||||
list.Add(new PointNormalModule(this));
|
||||
list.Add(new PointMirrorModule(this));
|
||||
#if DREAMTECK_SPLINES
|
||||
list.Add(new PrimitivesModule(this));
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void Destroy()
|
||||
{
|
||||
base.Destroy();
|
||||
UpdateSpline();
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
Refresh();
|
||||
base.DrawInspector();
|
||||
UpdateSpline();
|
||||
}
|
||||
|
||||
public override void DrawScene()
|
||||
{
|
||||
Refresh();
|
||||
base.DrawScene();
|
||||
UpdateSpline();
|
||||
}
|
||||
|
||||
public override void BeforeSceneGUI(SceneView current)
|
||||
{
|
||||
Refresh();
|
||||
base.BeforeSceneGUI(current);
|
||||
UpdateSpline();
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
points = spline.GetPoints();
|
||||
isClosed = spline.isClosed;
|
||||
splineType = spline.type;
|
||||
sampleRate = spline.sampleRate;
|
||||
is2D = spline.is2D;
|
||||
color = spline.editorPathColor;
|
||||
}
|
||||
|
||||
public void UpdateSpline()
|
||||
{
|
||||
if (spline == null) return;
|
||||
if (!isClosed && spline.isClosed) spline.Break();
|
||||
else if(spline.isClosed && points.Length < 4)
|
||||
{
|
||||
spline.Break();
|
||||
isClosed = false;
|
||||
}
|
||||
spline.SetPoints(points);
|
||||
if (isClosed && !spline.isClosed) spline.Close();
|
||||
spline.type = splineType;
|
||||
spline.sampleRate = sampleRate;
|
||||
spline.is2D = is2D;
|
||||
spline.EditorUpdateConnectedNodes();
|
||||
}
|
||||
|
||||
void HandleUndo(string title)
|
||||
{
|
||||
Undo.RecordObject(spline, title);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45538fa443017094faf75943a969938d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,254 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
#if DREAMTECK_SPLINES
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Dreamteck.Splines;
|
||||
using Dreamteck.Splines.Primitives;
|
||||
using UnityEditor;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class PrimitivesModule : PointTransformModule
|
||||
{
|
||||
DreamteckSplinesEditor dsEditor = null;
|
||||
private PrimitiveEditor[] primitiveEditors;
|
||||
private string[] primitiveNames;
|
||||
private SplinePreset[] presets;
|
||||
private string[] presetNames;
|
||||
int mode = 0, selectedPrimitive = 0, selectedPreset = 0;
|
||||
bool createPresetMode = false;
|
||||
GUIContent[] toolbarContents = new GUIContent[2];
|
||||
Dreamteck.Editor.Toolbar toolbar;
|
||||
|
||||
private string savePresetName = "", savePresetDescription = "";
|
||||
|
||||
private bool lastClosed = false;
|
||||
private Spline.Type lastType = Spline.Type.Bezier;
|
||||
|
||||
|
||||
public PrimitivesModule(SplineEditor editor) : base(editor)
|
||||
{
|
||||
dsEditor = ((DreamteckSplinesEditor)editor);
|
||||
toolbarContents[0] = new GUIContent("Primitives", "Procedural Primitives");
|
||||
toolbarContents[1] = new GUIContent("Presets", "Saved spline presets");
|
||||
toolbar = new Dreamteck.Editor.Toolbar(toolbarContents, toolbarContents);
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOff()
|
||||
{
|
||||
return IconContent("*", "primitives", "Spline Primitives");
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOn()
|
||||
{
|
||||
return IconContent("*", "primitives_on", "Spline Primitives");
|
||||
}
|
||||
|
||||
public override void LoadState()
|
||||
{
|
||||
base.LoadState();
|
||||
selectedPrimitive = LoadInt("selectedPrimitive");
|
||||
mode = LoadInt("mode");
|
||||
createPresetMode = LoadBool("createPresetMode");
|
||||
}
|
||||
|
||||
public override void SaveState()
|
||||
{
|
||||
base.SaveState();
|
||||
SaveInt("selectedPrimitive", selectedPrimitive);
|
||||
SaveInt("mode", mode);
|
||||
SaveBool("createPresetMode", createPresetMode);
|
||||
}
|
||||
|
||||
public override void Select()
|
||||
{
|
||||
base.Select();
|
||||
lastClosed = editor.isClosed;
|
||||
lastType = editor.splineType;
|
||||
Apply();
|
||||
if(mode == 0) LoadPrimitives();
|
||||
else if(!createPresetMode) LoadPresets();
|
||||
}
|
||||
|
||||
public override void Deselect()
|
||||
{
|
||||
base.Deselect();
|
||||
ApplyDialog();
|
||||
}
|
||||
|
||||
void ApplyDialog()
|
||||
{
|
||||
if (!IsDirty()) return;
|
||||
if (EditorUtility.DisplayDialog("Unapplied Primitives", "There is an unapplied primitive. Do you want to apply the changes?", "Apply", "Revert")) Apply();
|
||||
else Revert();
|
||||
}
|
||||
|
||||
public override void Revert()
|
||||
{
|
||||
base.Revert();
|
||||
editor.splineType = lastType;
|
||||
editor.isClosed = lastClosed;
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
toolbar.Draw(ref mode);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
if (mode == 0) LoadPrimitives();
|
||||
else if (!createPresetMode) LoadPresets();
|
||||
|
||||
}
|
||||
if (selectedPoints.Count > 0) ClearSelection();
|
||||
if (mode == 0) PrimitivesGUI();
|
||||
else PresetsGUI();
|
||||
|
||||
if (IsDirty() && (!createPresetMode || mode == 0))
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Apply")) Apply();
|
||||
if (GUILayout.Button("Revert")) Revert();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
void PrimitivesGUI()
|
||||
{
|
||||
int last = selectedPrimitive;
|
||||
selectedPrimitive = EditorGUILayout.Popup(selectedPrimitive, primitiveNames);
|
||||
if (last != selectedPrimitive)
|
||||
{
|
||||
primitiveEditors[selectedPrimitive].Open(dsEditor);
|
||||
primitiveEditors[selectedPrimitive].Update();
|
||||
TransformPoints();
|
||||
}
|
||||
EditorGUI.BeginChangeCheck();
|
||||
primitiveEditors[selectedPrimitive].Draw();
|
||||
if (EditorGUI.EndChangeCheck()) TransformPoints();
|
||||
}
|
||||
|
||||
void PresetsGUI()
|
||||
{
|
||||
if (createPresetMode)
|
||||
{
|
||||
savePresetName = EditorGUILayout.TextField("Preset name", savePresetName);
|
||||
EditorGUILayout.LabelField("Description");
|
||||
savePresetDescription = EditorGUILayout.TextArea(savePresetDescription);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Save"))
|
||||
{
|
||||
string lower = savePresetName.ToLower();
|
||||
string noSlashes = lower.Replace('/', '_');
|
||||
noSlashes = noSlashes.Replace('\\', '_');
|
||||
string noSpaces = noSlashes.Replace(' ', '_');
|
||||
SplinePreset preset = new SplinePreset(points, isClosed, splineType);
|
||||
preset.name = savePresetName;
|
||||
preset.description = savePresetDescription;
|
||||
preset.Save(noSpaces);
|
||||
createPresetMode = false;
|
||||
LoadPresets();
|
||||
savePresetName = savePresetDescription = "";
|
||||
}
|
||||
if (GUILayout.Button("Cancel")) createPresetMode = false;
|
||||
EditorGUILayout.EndHorizontal();
|
||||
return;
|
||||
}
|
||||
if (GUILayout.Button("Create New")) createPresetMode = true;
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
selectedPreset = EditorGUILayout.Popup(selectedPreset, presetNames, GUILayout.MaxWidth(Screen.width / 3f));
|
||||
if (selectedPreset >= 0 && selectedPreset < presets.Length)
|
||||
{
|
||||
if (GUILayout.Button("Use"))
|
||||
{
|
||||
LoadPreset(selectedPreset);
|
||||
}
|
||||
if (GUILayout.Button("Delete", GUILayout.MaxWidth(80)))
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("Delete Preset", "This will permanently delete the preset file. Continue?", "Yes", "No"))
|
||||
{
|
||||
SplinePreset.Delete(presets[selectedPreset].filename);
|
||||
LoadPresets();
|
||||
if (selectedPreset >= presets.Length) selectedPreset = presets.Length - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
}
|
||||
|
||||
void TransformPoints()
|
||||
{
|
||||
for (int i = 0; i < editor.points.Length; i++)
|
||||
{
|
||||
editor.points[i].position = dsEditor.spline.transform.TransformPoint(editor.points[i].position);
|
||||
editor.points[i].tangent = dsEditor.spline.transform.TransformPoint(editor.points[i].tangent);
|
||||
editor.points[i].tangent2 = dsEditor.spline.transform.TransformPoint(editor.points[i].tangent2);
|
||||
editor.points[i].normal = dsEditor.spline.transform.TransformDirection(editor.points[i].normal);
|
||||
}
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
void LoadPrimitives()
|
||||
{
|
||||
RecordUndo("Spline Primitive");
|
||||
List<Type> types = FindDerivedClasses.GetAllDerivedClasses(typeof(PrimitiveEditor));
|
||||
primitiveEditors = new PrimitiveEditor[types.Count];
|
||||
int count = 0;
|
||||
primitiveNames = new string[types.Count];
|
||||
foreach (Type t in types)
|
||||
{
|
||||
primitiveEditors[count] = (PrimitiveEditor)Activator.CreateInstance(t);
|
||||
primitiveNames[count] = primitiveEditors[count].GetName();
|
||||
count++;
|
||||
}
|
||||
|
||||
if (selectedPrimitive >= 0 && selectedPrimitive < primitiveEditors.Length)
|
||||
{
|
||||
ClearSelection();
|
||||
primitiveEditors[selectedPrimitive].Open(dsEditor);
|
||||
primitiveEditors[selectedPrimitive].Update();
|
||||
TransformPoints();
|
||||
FramePoints();
|
||||
}
|
||||
}
|
||||
|
||||
void LoadPresets()
|
||||
{
|
||||
ApplyDialog();
|
||||
RecordUndo("Spline Preset");
|
||||
presets = SplinePreset.LoadAll();
|
||||
presetNames = new string[presets.Length];
|
||||
for (int i = 0; i < presets.Length; i++) presetNames[i] = presets[i].name;
|
||||
ClearSelection();
|
||||
}
|
||||
|
||||
void LoadPreset(int index)
|
||||
{
|
||||
if (index >= 0 && index < presets.Length)
|
||||
{
|
||||
points = presets[index].points;
|
||||
editor.isClosed = presets[index].isClosed;
|
||||
editor.splineType = presets[index].type;
|
||||
TransformPoints();
|
||||
FramePoints();
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 GetOrigin(SplineComputer comp)
|
||||
{
|
||||
Vector3 avg = Vector3.zero;
|
||||
SplinePoint[] points = comp.GetPoints(SplineComputer.Space.Local);
|
||||
for (int i = 0; i < comp.pointCount; i++)
|
||||
{
|
||||
avg += points[i].position;
|
||||
}
|
||||
if (points.Length > 0) avg /= points.Length;
|
||||
return avg;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a63f089fd77344408647fe340cc2cf5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
public class SplineDebugEditor : SplineEditorBase
|
||||
{
|
||||
SplineComputer spline;
|
||||
float length = 0f;
|
||||
|
||||
|
||||
public SplineDebugEditor(SplineComputer spline) : base()
|
||||
{
|
||||
this.spline = spline;
|
||||
GetSplineLength();
|
||||
}
|
||||
|
||||
void GetSplineLength()
|
||||
{
|
||||
length = Mathf.RoundToInt(spline.CalculateLength() * 100f) / 100f;
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
base.DrawInspector();
|
||||
if (Event.current.type == EventType.MouseUp) GetSplineLength();
|
||||
|
||||
spline.editorPathColor = EditorGUILayout.ColorField("Color in Scene", spline.editorPathColor);
|
||||
bool lastAlwaysDraw = spline.alwaysDraw;
|
||||
spline.alwaysDraw = EditorGUILayout.Toggle("Always Draw Spline", spline.alwaysDraw);
|
||||
if (lastAlwaysDraw != spline.alwaysDraw)
|
||||
{
|
||||
if (spline.alwaysDraw) SplineDrawer.RegisterComputer(spline);
|
||||
else SplineDrawer.UnregisterComputer(spline);
|
||||
}
|
||||
spline.drawThinckness = EditorGUILayout.Toggle("Draw thickness", spline.drawThinckness);
|
||||
if (spline.drawThinckness)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
spline.billboardThickness = EditorGUILayout.Toggle("Always face camera", spline.billboardThickness);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.HelpBox("Samples: " + spline.samples.Length + "\n\r" + "Length: " + length, MessageType.Info);
|
||||
}
|
||||
|
||||
public override void DrawScene()
|
||||
{
|
||||
base.DrawScene();
|
||||
if (Event.current.type == EventType.MouseUp) GetSplineLength();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79246ce5388cae549b7ae6bf61b912f3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,286 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
public class SplineTriggersEditor : SplineEditorBase
|
||||
{
|
||||
private int selected = -1, selectedGroup = -1;
|
||||
private bool renameTrigger = false, renameGroup = false;
|
||||
SplineComputer spline;
|
||||
SplineTrigger.Type addTriggerType = SplineTrigger.Type.Double;
|
||||
private int setDistanceGroup, setDistanceTrigger;
|
||||
|
||||
public SplineTriggersEditor(SplineComputer spline) : base()
|
||||
{
|
||||
this.spline = spline;
|
||||
}
|
||||
|
||||
protected override void Load()
|
||||
{
|
||||
base.Load();
|
||||
addTriggerType = (SplineTrigger.Type)LoadInt("addTriggerType");
|
||||
}
|
||||
|
||||
protected override void Save()
|
||||
{
|
||||
base.Save();
|
||||
SaveInt("addTriggerType", (int)addTriggerType);
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
base.DrawInspector();
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUILayout.BeginVertical();
|
||||
for (int i = 0; i < spline.triggerGroups.Length; i++) DrawGroupGUI(i);
|
||||
EditorGUILayout.Space();
|
||||
if(GUILayout.Button("New Group"))
|
||||
{
|
||||
RecordUndo("Add Trigger Group");
|
||||
TriggerGroup group = new TriggerGroup();
|
||||
group.name = "Trigger Group " + (spline.triggerGroups.Length+1);
|
||||
ArrayUtility.Add(ref spline.triggerGroups, group);
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
if (EditorGUI.EndChangeCheck()) SceneView.RepaintAll();
|
||||
}
|
||||
|
||||
public override void DrawScene()
|
||||
{
|
||||
base.DrawScene();
|
||||
for (int i = 0; i < spline.triggerGroups.Length; i++)
|
||||
{
|
||||
if (!spline.triggerGroups[i].open) continue;
|
||||
DrawGroupScene(i);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawGroupScene(int index)
|
||||
{
|
||||
TriggerGroup group = spline.triggerGroups[index];
|
||||
for (int i = 0; i < group.triggers.Length; i++)
|
||||
{
|
||||
SplineEditorHandles.SplineSliderGizmo gizmo = SplineEditorHandles.SplineSliderGizmo.DualArrow;
|
||||
switch (group.triggers[i].type)
|
||||
{
|
||||
case SplineTrigger.Type.Backward: gizmo = SplineEditorHandles.SplineSliderGizmo.BackwardTriangle; break;
|
||||
case SplineTrigger.Type.Forward: gizmo = SplineEditorHandles.SplineSliderGizmo.ForwardTriangle; break;
|
||||
case SplineTrigger.Type.Double: gizmo = SplineEditorHandles.SplineSliderGizmo.DualArrow; break;
|
||||
}
|
||||
double last = group.triggers[i].position;
|
||||
if (SplineEditorHandles.Slider(spline, ref group.triggers[i].position, group.triggers[i].color, group.triggers[i].name, gizmo) || last != group.triggers[i].position)
|
||||
{
|
||||
Select(index, i);
|
||||
Repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnSetDistance(float distance)
|
||||
{
|
||||
SerializedObject serializedObject = new SerializedObject(spline);
|
||||
SerializedProperty groups = serializedObject.FindProperty("triggerGroups");
|
||||
SerializedProperty groupProperty = groups.GetArrayElementAtIndex(setDistanceGroup);
|
||||
|
||||
SerializedProperty triggersProperty = groupProperty.FindPropertyRelative("triggers");
|
||||
SerializedProperty triggerProperty = triggersProperty.GetArrayElementAtIndex(setDistanceTrigger);
|
||||
|
||||
SerializedProperty position = triggerProperty.FindPropertyRelative("position");
|
||||
|
||||
double travel = spline.Travel(0.0, distance, Spline.Direction.Forward);
|
||||
position.floatValue = (float)travel;
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
void DrawGroupGUI(int index)
|
||||
{
|
||||
TriggerGroup group = spline.triggerGroups[index];
|
||||
SerializedObject serializedObject = new SerializedObject(spline);
|
||||
SerializedProperty groups = serializedObject.FindProperty("triggerGroups");
|
||||
SerializedProperty groupProperty = groups.GetArrayElementAtIndex(index);
|
||||
EditorGUI.indentLevel += 2;
|
||||
if(selectedGroup == index && renameGroup)
|
||||
{
|
||||
if (Event.current.type == EventType.KeyDown && (Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.KeypadEnter))
|
||||
{
|
||||
renameGroup = false;
|
||||
Repaint();
|
||||
}
|
||||
group.name = EditorGUILayout.TextField(group.name);
|
||||
} else group.open = EditorGUILayout.Foldout(group.open, index + " - " + group.name);
|
||||
Rect lastRect = GUILayoutUtility.GetLastRect();
|
||||
if(lastRect.Contains(Event.current.mousePosition) && Event.current.type == EventType.MouseDown && Event.current.button == 1)
|
||||
{
|
||||
GenericMenu menu = new GenericMenu();
|
||||
menu.AddItem(new GUIContent("Rename"), false, delegate { RecordUndo("Rename Trigger Group"); selectedGroup = index; renameGroup = true; renameTrigger = false; Repaint(); });
|
||||
menu.AddItem(new GUIContent("Delete"), false, delegate {
|
||||
RecordUndo("Delete Trigger Group");
|
||||
ArrayUtility.RemoveAt(ref spline.triggerGroups, index);
|
||||
Repaint();
|
||||
});
|
||||
menu.ShowAsContext();
|
||||
}
|
||||
EditorGUI.indentLevel -= 2;
|
||||
if (!group.open) return;
|
||||
|
||||
for (int i = 0; i < group.triggers.Length; i++) DrawTriggerGUI(i, index, groupProperty);
|
||||
if (GUI.changed) serializedObject.ApplyModifiedProperties();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Add Trigger"))
|
||||
{
|
||||
RecordUndo("Add Trigger");
|
||||
SplineTrigger newTrigger = new SplineTrigger(addTriggerType);
|
||||
newTrigger.name = "Trigger " + (group.triggers.Length + 1);
|
||||
ArrayUtility.Add(ref group.triggers, newTrigger);
|
||||
}
|
||||
addTriggerType = (SplineTrigger.Type)EditorGUILayout.EnumPopup(addTriggerType);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
void Select(int group, int trigger)
|
||||
{
|
||||
selected = trigger;
|
||||
selectedGroup = group;
|
||||
renameTrigger = false;
|
||||
renameGroup = false;
|
||||
Repaint();
|
||||
}
|
||||
|
||||
void DrawTriggerGUI(int index, int groupIndex, SerializedProperty groupProperty)
|
||||
{
|
||||
bool isSelected = selected == index && selectedGroup == groupIndex;
|
||||
TriggerGroup group = spline.triggerGroups[groupIndex];
|
||||
SplineTrigger trigger = group.triggers[index];
|
||||
SerializedProperty triggersProperty = groupProperty.FindPropertyRelative("triggers");
|
||||
SerializedProperty triggerProperty = triggersProperty.GetArrayElementAtIndex(index);
|
||||
SerializedProperty eventProperty = triggerProperty.FindPropertyRelative("onCross");
|
||||
SerializedProperty positionProperty = triggerProperty.FindPropertyRelative("position");
|
||||
SerializedProperty colorProperty = triggerProperty.FindPropertyRelative("color");
|
||||
SerializedProperty nameProperty = triggerProperty.FindPropertyRelative("name");
|
||||
SerializedProperty enabledProperty = triggerProperty.FindPropertyRelative("enabled");
|
||||
SerializedProperty workOnceProperty = triggerProperty.FindPropertyRelative("workOnce");
|
||||
SerializedProperty typeProperty = triggerProperty.FindPropertyRelative("type");
|
||||
|
||||
Color col = colorProperty.colorValue;
|
||||
if (isSelected) col.a = 1f;
|
||||
else col.a = 0.6f;
|
||||
GUI.backgroundColor = col;
|
||||
|
||||
EditorGUILayout.BeginVertical(GUI.skin.box);
|
||||
GUI.backgroundColor = Color.white;
|
||||
if (trigger == null)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.Label("NULL");
|
||||
if (GUILayout.Button("x")) ArrayUtility.RemoveAt(ref group.triggers, index);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.EndVertical();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (isSelected && renameTrigger)
|
||||
{
|
||||
if (Event.current.type == EventType.KeyDown && (Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.KeypadEnter))
|
||||
{
|
||||
renameTrigger = false;
|
||||
Repaint();
|
||||
}
|
||||
nameProperty.stringValue = EditorGUILayout.TextField(nameProperty.stringValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField(nameProperty.stringValue);
|
||||
}
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.PropertyField(enabledProperty);
|
||||
EditorGUILayout.PropertyField(colorProperty);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
positionProperty.floatValue = EditorGUILayout.Slider("Position", positionProperty.floatValue, 0f, 1f);
|
||||
if (GUILayout.Button("Set Distance", GUILayout.Width(85)))
|
||||
{
|
||||
DistanceWindow w = EditorWindow.GetWindow<DistanceWindow>(true);
|
||||
w.Init(OnSetDistance, spline.CalculateLength());
|
||||
setDistanceGroup = groupIndex;
|
||||
setDistanceTrigger = index;
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.PropertyField(typeProperty);
|
||||
EditorGUILayout.PropertyField(workOnceProperty);
|
||||
|
||||
EditorGUILayout.PropertyField(eventProperty);
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
Rect lastRect = GUILayoutUtility.GetLastRect();
|
||||
if (lastRect.Contains(Event.current.mousePosition) && Event.current.type == EventType.MouseDown)
|
||||
{
|
||||
if (Event.current.button == 0) Select(groupIndex, index);
|
||||
else if (Event.current.button == 1)
|
||||
{
|
||||
GenericMenu menu = new GenericMenu();
|
||||
menu.AddItem(new GUIContent("Deselect"), false, delegate { Select(-1, -1); });
|
||||
menu.AddItem(new GUIContent("Rename"), false, delegate { Select(groupIndex, index); renameTrigger = true; renameGroup = false; });
|
||||
if (index > 0)
|
||||
{
|
||||
menu.AddItem(new GUIContent("Move Up"), false, delegate {
|
||||
RecordUndo("Move Trigger Up");
|
||||
SplineTrigger temp = group.triggers[index - 1];
|
||||
group.triggers[index - 1] = trigger;
|
||||
group.triggers[index] = temp;
|
||||
selected--;
|
||||
renameTrigger = false;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
menu.AddDisabledItem(new GUIContent("Move Up"));
|
||||
}
|
||||
if (index < group.triggers.Length - 1)
|
||||
{
|
||||
menu.AddItem(new GUIContent("Move Down"), false, delegate {
|
||||
RecordUndo("Move Trigger Down");
|
||||
SplineTrigger temp = group.triggers[index + 1];
|
||||
group.triggers[index + 1] = trigger;
|
||||
group.triggers[index] = temp;
|
||||
selected--;
|
||||
renameTrigger = false;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
menu.AddDisabledItem(new GUIContent("Move Down"));
|
||||
}
|
||||
|
||||
menu.AddItem(new GUIContent("Duplicate"), false, delegate {
|
||||
RecordUndo("Duplicate Trigger");
|
||||
SplineTrigger newTrigger = new SplineTrigger(SplineTrigger.Type.Double);
|
||||
newTrigger.color = colorProperty.colorValue;
|
||||
newTrigger.enabled = enabledProperty.boolValue;
|
||||
newTrigger.position = positionProperty.floatValue;
|
||||
newTrigger.type = (SplineTrigger.Type) typeProperty.intValue;
|
||||
newTrigger.name = "Trigger " + (group.triggers.Length + 1);
|
||||
ArrayUtility.Add(ref group.triggers, newTrigger);
|
||||
Select(groupIndex, group.triggers.Length - 1);
|
||||
});
|
||||
menu.AddItem(new GUIContent("Delete"), false, delegate {
|
||||
RecordUndo("Delete Trigger");
|
||||
ArrayUtility.RemoveAt(ref group.triggers, index);
|
||||
Select(-1, -1);
|
||||
});
|
||||
menu.ShowAsContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e0ea2345d361b04b8778234920e3e24
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
129
Assets/Dreamteck/Splines/Editor/SplineEditor/EditorModule.cs
Normal file
129
Assets/Dreamteck/Splines/Editor/SplineEditor/EditorModule.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
public class EditorModule
|
||||
{
|
||||
protected string prefPrefix = "";
|
||||
|
||||
public virtual void Select()
|
||||
{
|
||||
LoadState();
|
||||
}
|
||||
|
||||
public virtual void Deselect()
|
||||
{
|
||||
SaveState();
|
||||
}
|
||||
|
||||
public virtual void BeforeSceneDraw(SceneView current)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void DrawScene()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void OnSceneDraw()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void DrawInspector()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual GUIContent GetIconOff()
|
||||
{
|
||||
return new GUIContent("OFF", "Point Module Off");
|
||||
}
|
||||
|
||||
public virtual GUIContent GetIconOn()
|
||||
{
|
||||
return new GUIContent("ON", "Point Module On");
|
||||
}
|
||||
|
||||
protected virtual void RecordUndo(string title)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void Repaint()
|
||||
{
|
||||
}
|
||||
|
||||
protected void SaveBool(string variableName, bool value)
|
||||
{
|
||||
if (prefPrefix == "") prefPrefix = GetType().ToString();
|
||||
EditorPrefs.SetBool(prefPrefix + "." + variableName, value);
|
||||
}
|
||||
|
||||
protected void SaveInt(string variableName, int value)
|
||||
{
|
||||
if (prefPrefix == "") prefPrefix = GetType().ToString();
|
||||
EditorPrefs.SetInt(prefPrefix + "." + variableName, value);
|
||||
}
|
||||
|
||||
protected void SaveFloat(string variableName, float value)
|
||||
{
|
||||
if (prefPrefix == "") prefPrefix = GetType().ToString();
|
||||
EditorPrefs.SetFloat(prefPrefix + "." + variableName, value);
|
||||
}
|
||||
|
||||
protected void SaveString(string variableName, string value)
|
||||
{
|
||||
if (prefPrefix == "") prefPrefix = GetType().ToString();
|
||||
EditorPrefs.SetString(prefPrefix + "." + variableName, value);
|
||||
}
|
||||
|
||||
protected bool LoadBool(string variableName)
|
||||
{
|
||||
if (prefPrefix == "") prefPrefix = GetType().ToString();
|
||||
return EditorPrefs.GetBool(prefPrefix + "." + variableName, false);
|
||||
}
|
||||
|
||||
protected int LoadInt(string variableName, int defaultValue = 0)
|
||||
{
|
||||
if (prefPrefix == "") prefPrefix = GetType().ToString();
|
||||
return EditorPrefs.GetInt(prefPrefix + "." + variableName, defaultValue);
|
||||
}
|
||||
|
||||
protected float LoadFloat(string variableName, float d = 0f)
|
||||
{
|
||||
if (prefPrefix == "") prefPrefix = GetType().ToString();
|
||||
return EditorPrefs.GetFloat(prefPrefix + "." + variableName, d);
|
||||
}
|
||||
|
||||
protected string LoadString(string variableName)
|
||||
{
|
||||
if (prefPrefix == "") prefPrefix = GetType().ToString();
|
||||
return EditorPrefs.GetString(prefPrefix + "." + variableName, "");
|
||||
}
|
||||
|
||||
public virtual void SaveState()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void LoadState()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
internal static GUIContent IconContent(string title, string iconName, string description)
|
||||
{
|
||||
GUIContent content = new GUIContent(title, description);
|
||||
string path = "Splines/Editor/Icons";
|
||||
if (EditorGUIUtility.isProSkin) iconName += "_dark";
|
||||
Texture2D tex = ImageDB.GetImage(iconName + ".png", path);
|
||||
if (tex != null)
|
||||
{
|
||||
content.image = tex;
|
||||
content.text = "";
|
||||
}
|
||||
return content;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8686a0595fc0a4f439a1a64fb1a4d49a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fbe370f8b912d1341b528bc7a71f4ddf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,420 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class CreatePointModule : PointModule
|
||||
{
|
||||
public enum AppendMode { Beginning, End }
|
||||
public enum PlacementMode { YPlane, XPlane, ZPlane, CameraPlane, Surface, Insert }
|
||||
public enum NormalMode { Default, LookAtCamera, AlignWithCamera, Calculate, Left, Right, Up, Down, Forward, Back }
|
||||
protected PlacementMode placementMode = PlacementMode.YPlane;
|
||||
public AppendMode appendMode = 0;
|
||||
public float offset = 0f;
|
||||
public NormalMode normalMode = NormalMode.Default;
|
||||
public LayerMask surfaceLayerMask = new LayerMask();
|
||||
protected Spline visualizer;
|
||||
protected Camera editorCamera;
|
||||
protected Vector3 createPoint = Vector3.zero, createNormal = Vector3.up;
|
||||
protected SplineSample evalResult = new SplineSample();
|
||||
protected int lastCreated = -1;
|
||||
|
||||
public CreatePointModule(SplineEditor editor) : base(editor)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOff()
|
||||
{
|
||||
return IconContent("+", "add", "Add Points");
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOn()
|
||||
{
|
||||
return IconContent("+", "add_on", "Add Points");
|
||||
}
|
||||
|
||||
public override void LoadState()
|
||||
{
|
||||
base.LoadState();
|
||||
normalMode = (NormalMode)LoadInt("normalMode");
|
||||
placementMode = (PlacementMode)LoadInt("placementMode");
|
||||
appendMode = (AppendMode)LoadInt("appendMode");
|
||||
offset = LoadFloat("offset");
|
||||
surfaceLayerMask = LoadInt("surfaceLayerMask", ~0);
|
||||
}
|
||||
|
||||
public override void SaveState()
|
||||
{
|
||||
base.SaveState();
|
||||
SaveInt("normalMode", (int)normalMode);
|
||||
SaveInt("placementMode", (int)placementMode);
|
||||
SaveInt("appendMode", (int)appendMode);
|
||||
SaveFloat("offset", offset);
|
||||
SaveInt("surfaceLayerMask", surfaceLayerMask);
|
||||
}
|
||||
|
||||
public override void Deselect()
|
||||
{
|
||||
base.Deselect();
|
||||
GUIUtility.hotControl = -1;
|
||||
Event.current.Use();
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
placementMode = (PlacementMode)EditorGUILayout.EnumPopup("Placement Mode", placementMode);
|
||||
if (placementMode != PlacementMode.Insert)
|
||||
{
|
||||
normalMode = (NormalMode)EditorGUILayout.EnumPopup("Normal Mode", normalMode);
|
||||
appendMode = (AppendMode)EditorGUILayout.EnumPopup("Append To", appendMode);
|
||||
}
|
||||
string offsetLabel = "Grid Offset";
|
||||
if (placementMode == PlacementMode.CameraPlane) offsetLabel = "Far Plane";
|
||||
if (placementMode == PlacementMode.Surface) offsetLabel = "Surface Offset";
|
||||
offset = EditorGUILayout.FloatField(offsetLabel, offset);
|
||||
if (placementMode == PlacementMode.Surface)
|
||||
{
|
||||
surfaceLayerMask = DreamteckEditorGUI.LayermaskField("Surface Mask", surfaceLayerMask);
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawScene()
|
||||
{
|
||||
editorCamera = SceneView.currentDrawingSceneView.camera;
|
||||
bool canCreate = false;
|
||||
if (placementMode == PlacementMode.CameraPlane)
|
||||
{
|
||||
GetCreatePointOnPlane(-editorCamera.transform.forward, editorCamera.transform.position + editorCamera.transform.forward * offset, out createPoint);
|
||||
Handles.color = new Color(1f, 0.78f, 0.12f);
|
||||
DrawGrid(createPoint, editorCamera.transform.forward, Vector2.one * 10, 2.5f);
|
||||
Handles.color = Color.white;
|
||||
canCreate = true;
|
||||
createNormal = -editorCamera.transform.forward;
|
||||
}
|
||||
|
||||
if (placementMode == PlacementMode.Surface)
|
||||
{
|
||||
Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
|
||||
RaycastHit hit;
|
||||
if (Physics.Raycast(ray, out hit, Mathf.Infinity, surfaceLayerMask))
|
||||
{
|
||||
canCreate = true;
|
||||
createPoint = hit.point + hit.normal * offset;
|
||||
Handles.color = Color.blue;
|
||||
Handles.DrawLine(hit.point, createPoint);
|
||||
SplineEditorHandles.DrawRectangle(createPoint, Quaternion.LookRotation(-editorCamera.transform.forward, editorCamera.transform.up), HandleUtility.GetHandleSize(createPoint) * 0.1f);
|
||||
Handles.color = Color.white;
|
||||
createNormal = hit.normal;
|
||||
}
|
||||
}
|
||||
|
||||
if (placementMode == PlacementMode.XPlane)
|
||||
{
|
||||
canCreate = AxisGrid(Vector3.right, new Color(0.85f, 0.24f, 0.11f, 0.92f), out createPoint);
|
||||
createNormal = Vector3.right;
|
||||
}
|
||||
|
||||
if (placementMode == PlacementMode.YPlane)
|
||||
{
|
||||
canCreate = AxisGrid(Vector3.up, new Color(0.6f, 0.95f, 0.28f, 0.92f), out createPoint);
|
||||
createNormal = Vector3.up;
|
||||
}
|
||||
|
||||
if (placementMode == PlacementMode.ZPlane)
|
||||
{
|
||||
canCreate = AxisGrid(Vector3.forward, new Color(0.22f, 0.47f, 0.97f, 0.92f), out createPoint);
|
||||
createNormal = Vector3.back;
|
||||
}
|
||||
|
||||
if (placementMode == PlacementMode.Insert)
|
||||
{
|
||||
canCreate = true;
|
||||
if (points.Length < 2) placementMode = PlacementMode.YPlane;
|
||||
else InsertMode(Event.current.mousePosition);
|
||||
}
|
||||
else if (eventModule.mouseLeftDown && canCreate && !eventModule.mouseRight) CreateSplinePoint(createPoint, createNormal);
|
||||
|
||||
if(lastCreated >= 0 && lastCreated < points.Length && editor.eventModule.mouseLeft)
|
||||
{
|
||||
Vector3 tangent = points[lastCreated].position - createPoint;
|
||||
if (appendMode == AppendMode.End) tangent = createPoint - points[lastCreated].position;
|
||||
points[lastCreated].SetTangent2Position(points[lastCreated].position + tangent);
|
||||
} else if (!editor.eventModule.mouseLeft) lastCreated = -1;
|
||||
|
||||
|
||||
if (!canCreate) DrawMouseCross();
|
||||
UpdateVisualizer();
|
||||
SplineDrawer.DrawSpline(visualizer, color);
|
||||
Repaint();
|
||||
}
|
||||
|
||||
protected virtual void CreateSplinePoint(Vector3 position, Vector3 normal)
|
||||
{
|
||||
RecordUndo("Create Point");
|
||||
GUIUtility.hotControl = -1;
|
||||
AddPoint();
|
||||
}
|
||||
|
||||
protected void AddPoint()
|
||||
{
|
||||
SplinePoint newPoint = new SplinePoint(createPoint, createPoint);
|
||||
#if DREAMTECK_SPLINES
|
||||
newPoint.size = SplinePrefs.createPointSize;
|
||||
newPoint.color = SplinePrefs.createPointColor;
|
||||
#endif
|
||||
SplinePoint[] newPoints = new SplinePoint[points.Length];
|
||||
points.CopyTo(newPoints, 0);
|
||||
if (appendMode == AppendMode.End)
|
||||
{
|
||||
if (isClosed)
|
||||
{
|
||||
Dreamteck.ArrayUtility.Insert(ref newPoints, newPoints.Length - 1, newPoint);
|
||||
lastCreated = newPoints.Length - 2;
|
||||
} else
|
||||
{
|
||||
Dreamteck.ArrayUtility.Add(ref newPoints, newPoint);
|
||||
lastCreated = newPoints.Length - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isClosed)
|
||||
{
|
||||
Dreamteck.ArrayUtility.Insert(ref newPoints, 1, newPoint);
|
||||
lastCreated = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Dreamteck.ArrayUtility.Insert(ref newPoints, 0, newPoint);
|
||||
lastCreated = 0;
|
||||
}
|
||||
}
|
||||
if (isClosed) newPoints[newPoints.Length - 1] = newPoints[0];
|
||||
points = newPoints;
|
||||
SetPointNormal(lastCreated, createNormal);
|
||||
SelectPoint(lastCreated);
|
||||
}
|
||||
|
||||
protected void SetPointNormal(int index, Vector3 defaultNormal)
|
||||
{
|
||||
if (editor.is2D)
|
||||
{
|
||||
points[index].normal = Vector3.back;
|
||||
return;
|
||||
}
|
||||
if (normalMode == NormalMode.Default) points[index].normal = defaultNormal;
|
||||
else
|
||||
{
|
||||
Camera editorCamera = SceneView.lastActiveSceneView.camera;
|
||||
switch (normalMode)
|
||||
{
|
||||
case NormalMode.AlignWithCamera: points[index].normal = editorCamera.transform.forward; break;
|
||||
case NormalMode.LookAtCamera: points[index].normal = Vector3.Normalize(editorCamera.transform.position - points[index].position); break;
|
||||
case NormalMode.Calculate: PointNormalModule.CalculatePointNormal(points, index, isClosed); break;
|
||||
case NormalMode.Left: points[index].normal = Vector3.left; break;
|
||||
case NormalMode.Right: points[index].normal = Vector3.right; break;
|
||||
case NormalMode.Up: points[index].normal = Vector3.up; break;
|
||||
case NormalMode.Down: points[index].normal = Vector3.down; break;
|
||||
case NormalMode.Forward: points[index].normal = Vector3.forward; break;
|
||||
case NormalMode.Back: points[index].normal = Vector3.back; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void InsertMode(Vector3 screenCoordinates)
|
||||
{
|
||||
|
||||
double percent = ProjectScreenSpace(screenCoordinates);
|
||||
editor.evaluate(percent, evalResult);
|
||||
if (editor.eventModule.mouseRight)
|
||||
{
|
||||
SplineEditorHandles.DrawCircle(evalResult.position, Quaternion.LookRotation(editorCamera.transform.position - evalResult.position), HandleUtility.GetHandleSize(evalResult.position) * 0.2f);
|
||||
return;
|
||||
}
|
||||
if (SplineEditorHandles.CircleButton(evalResult.position, Quaternion.LookRotation(editorCamera.transform.position - evalResult.position), HandleUtility.GetHandleSize(evalResult.position) * 0.2f, 1.5f, color))
|
||||
{
|
||||
RecordUndo("Create Point");
|
||||
SplinePoint newPoint = new SplinePoint(evalResult.position, evalResult.position);
|
||||
newPoint.size = evalResult.size;
|
||||
newPoint.color = evalResult.color;
|
||||
newPoint.normal = evalResult.up;
|
||||
SplinePoint[] newPoints = new SplinePoint[points.Length + 1];
|
||||
double floatIndex = (points.Length - 1) * percent;
|
||||
int pointIndex = Mathf.Clamp(DMath.FloorInt(floatIndex), 0, points.Length - 2);
|
||||
for (int i = 0; i < newPoints.Length; i++)
|
||||
{
|
||||
if (i <= pointIndex) newPoints[i] = points[i];
|
||||
else if (i == pointIndex + 1) newPoints[i] = newPoint;
|
||||
else newPoints[i] = points[i - 1];
|
||||
}
|
||||
points = newPoints;
|
||||
SelectPoint(pointIndex);
|
||||
}
|
||||
}
|
||||
|
||||
protected double ProjectScreenSpace(Vector2 screenPoint)
|
||||
{
|
||||
float closestDistance = (screenPoint - HandleUtility.WorldToGUIPoint(points[0].position)).sqrMagnitude;
|
||||
double closestPercent = 0.0;
|
||||
double moveStep = 1.0 / ((editor.points.Length - 1) * sampleRate);
|
||||
double add = moveStep;
|
||||
if (splineType == Spline.Type.Linear) add /= 2.0;
|
||||
int count = 0;
|
||||
for (double i = add; i < 1.0; i += add)
|
||||
{
|
||||
editor.evaluate(i, evalResult);
|
||||
Vector2 point = HandleUtility.WorldToGUIPoint(evalResult.position);
|
||||
float dist = (point - screenPoint).sqrMagnitude;
|
||||
if (dist < closestDistance)
|
||||
{
|
||||
closestDistance = dist;
|
||||
closestPercent = i;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return closestPercent;
|
||||
}
|
||||
|
||||
bool GetCreatePointOnPlane(Vector3 normal, Vector3 origin, out Vector3 result)
|
||||
{
|
||||
Plane plane = new Plane(normal, origin);
|
||||
Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
|
||||
float rayDistance;
|
||||
if (plane.Raycast(ray, out rayDistance))
|
||||
{
|
||||
result = ray.GetPoint(rayDistance);
|
||||
return true;
|
||||
}
|
||||
else if (normal == Vector3.zero)
|
||||
{
|
||||
result = origin;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = ray.GetPoint(0f);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool AxisGrid(Vector3 axis, Color color, out Vector3 origin)
|
||||
{
|
||||
float dot = Vector3.Dot(editorCamera.transform.position.normalized, axis);
|
||||
if (dot < 0f) axis = -axis;
|
||||
Plane plane = new Plane(axis, Vector3.zero);
|
||||
Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
|
||||
float rayDistance;
|
||||
if (plane.Raycast(ray, out rayDistance))
|
||||
{
|
||||
origin = ray.GetPoint(rayDistance) + axis * offset;
|
||||
Handles.color = color;
|
||||
float distance = 1f;
|
||||
ray = new Ray(editorCamera.transform.position, -axis);
|
||||
if (!editorCamera.orthographic && plane.Raycast(ray, out rayDistance)) distance = Vector3.Distance(editorCamera.transform.position + axis * offset, origin);
|
||||
else if (editorCamera.orthographic) distance = 2f * editorCamera.orthographicSize;
|
||||
DrawGrid(origin, axis, Vector2.one * distance * 0.3f, distance * 2.5f * 0.03f);
|
||||
Handles.DrawLine(origin, origin - axis * offset);
|
||||
Handles.color = Color.white;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
origin = Vector3.zero;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawGrid(Vector3 center, Vector3 normal, Vector2 size, float scale)
|
||||
{
|
||||
Vector3 right = Vector3.Cross(Vector3.up, normal).normalized;
|
||||
if (Mathf.Abs(Vector3.Dot(Vector3.up, normal)) >= 0.9999f) right = Vector3.Cross(Vector3.forward, normal).normalized;
|
||||
Vector3 up = Vector3.Cross(normal, right).normalized;
|
||||
Vector3 startPoint = center - right * size.x * 0.5f + up * size.y * 0.5f;
|
||||
float i = 0f;
|
||||
float add = scale;
|
||||
while (i <= size.x)
|
||||
{
|
||||
Vector3 point = startPoint + right * i;
|
||||
Handles.DrawLine(point, point - up * size.y);
|
||||
i += add;
|
||||
}
|
||||
|
||||
i = 0f;
|
||||
add = scale;
|
||||
while (i <= size.x)
|
||||
{
|
||||
Vector3 point = startPoint - up * i;
|
||||
Handles.DrawLine(point, point + right * size.x);
|
||||
i += add;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawMouseCross()
|
||||
{
|
||||
Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
|
||||
Vector3 origin = ray.GetPoint(1f);
|
||||
float size = 0.4f * HandleUtility.GetHandleSize(origin);
|
||||
Vector3 a = origin + editorCamera.transform.up * size - editorCamera.transform.right * size;
|
||||
Vector3 b = origin - editorCamera.transform.up * size + editorCamera.transform.right * size;
|
||||
Handles.color = Color.red;
|
||||
Handles.DrawLine(a, b);
|
||||
a = origin - editorCamera.transform.up * size - editorCamera.transform.right * size;
|
||||
b = origin + editorCamera.transform.up * size + editorCamera.transform.right * size;
|
||||
Handles.DrawLine(a, b);
|
||||
Handles.color = Color.white;
|
||||
}
|
||||
|
||||
private void UpdateVisualizer()
|
||||
{
|
||||
if(visualizer == null) visualizer = new Spline(splineType);
|
||||
visualizer.type = splineType;
|
||||
visualizer.sampleRate = sampleRate;
|
||||
if(placementMode == PlacementMode.Insert)
|
||||
{
|
||||
visualizer.points = points;
|
||||
if (isClosed) visualizer.Close();
|
||||
else if (visualizer.isClosed) visualizer.Break();
|
||||
return;
|
||||
}
|
||||
|
||||
if(visualizer.points.Length != points.Length + 1) visualizer.points = new SplinePoint[points.Length + 1];
|
||||
SplinePoint newPoint = new SplinePoint(createPoint, createPoint, createNormal, 1f, Color.white);
|
||||
if (appendMode == AppendMode.End)
|
||||
{
|
||||
if (isClosed)
|
||||
{
|
||||
|
||||
for (int i = 0; i < points.Length; i++) visualizer.points[i] = points[i];
|
||||
visualizer.points[visualizer.points.Length - 2] = newPoint;
|
||||
visualizer.points[visualizer.points.Length - 1] = points[points.Length-1];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < points.Length; i++) visualizer.points[i] = points[i];
|
||||
visualizer.points[visualizer.points.Length - 1] = newPoint;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isClosed)
|
||||
{
|
||||
for (int i = 1; i < points.Length; i++) visualizer.points[i] = points[i-1];
|
||||
visualizer.points[1] = newPoint;
|
||||
visualizer.points[0] = points[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 1; i < visualizer.points.Length; i++) visualizer.points[i] = points[i - 1];
|
||||
visualizer.points[0] = newPoint;
|
||||
}
|
||||
}
|
||||
if (isClosed && !visualizer.isClosed) visualizer.Close();
|
||||
else if (visualizer.isClosed) visualizer.Break();
|
||||
if (visualizer.isClosed) visualizer.points[0].SetPosition(createPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dcb9fe180ed013a44a474b2a4ece59fc
|
||||
timeCreated: 1476219856
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,86 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class DeletePointModule : PointModule
|
||||
{
|
||||
public float deleteRadius = 50f;
|
||||
Vector2 lastMousePos = Vector2.zero;
|
||||
|
||||
|
||||
public DeletePointModule(SplineEditor editor) : base(editor)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOff()
|
||||
{
|
||||
return IconContent("-", "remove", "Delete Points");
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOn()
|
||||
{
|
||||
return IconContent("-", "remove_on", "Delete Points");
|
||||
}
|
||||
|
||||
public override void LoadState()
|
||||
{
|
||||
base.LoadState();
|
||||
deleteRadius = LoadFloat("deleteRadius", 50f);
|
||||
}
|
||||
|
||||
public override void SaveState()
|
||||
{
|
||||
base.SaveState();
|
||||
SaveFloat("deleteRadius", deleteRadius);
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
deleteRadius = EditorGUILayout.FloatField("Brush Radius", deleteRadius);
|
||||
}
|
||||
|
||||
public override void DrawScene()
|
||||
{
|
||||
if (selectedPoints.Count > 0) ClearSelection();
|
||||
Handles.BeginGUI();
|
||||
Handles.color = Color.red;
|
||||
Handles.DrawWireDisc(Event.current.mousePosition, -Vector3.forward, deleteRadius);
|
||||
Handles.color = Color.white;
|
||||
Handles.EndGUI();
|
||||
if (SceneView.currentDrawingSceneView.camera.pixelRect.Contains(Event.current.mousePosition)) {
|
||||
if (editor.eventModule.mouseLeftDown) GUIUtility.hotControl = GUIUtility.GetControlID(FocusType.Passive);
|
||||
if (editor.eventModule.mouseLeft && lastMousePos != Event.current.mousePosition)
|
||||
{
|
||||
lastMousePos = Event.current.mousePosition;
|
||||
RunDeleteMethod();
|
||||
}
|
||||
}
|
||||
Repaint();
|
||||
}
|
||||
|
||||
void RunDeleteMethod()
|
||||
{
|
||||
Camera cam = SceneView.currentDrawingSceneView.camera;
|
||||
Vector3 mousPos = Event.current.mousePosition;
|
||||
Rect mouseRect = new Rect(mousPos.x - deleteRadius, mousPos.y - deleteRadius, deleteRadius * 2f, deleteRadius * 2f);
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
Vector3 localPos = cam.transform.InverseTransformPoint(points[i].position);
|
||||
if (localPos.z < 0f) continue;
|
||||
Vector2 screenPos = HandleUtility.WorldToGUIPoint(points[i].position);
|
||||
if (mouseRect.Contains(screenPos))
|
||||
{
|
||||
if (Vector2.Distance(mousPos, screenPos) <= deleteRadius)
|
||||
{
|
||||
DeletePoint(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 031571ebca44b8a47a9af1984caeeff9
|
||||
timeCreated: 1476219856
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,259 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
|
||||
public class MainPointModule : PointModule
|
||||
{
|
||||
public bool excludeSelected = false;
|
||||
public int minimumRectSize = 5;
|
||||
private Vector2 rectStart = Vector2.zero;
|
||||
private Vector2 rectEnd = Vector2.zero;
|
||||
private Rect rect;
|
||||
private bool drag = false;
|
||||
private bool finalize = false;
|
||||
|
||||
public bool isDragging
|
||||
{
|
||||
get
|
||||
{
|
||||
return drag && rect.width >= minimumRectSize && rect.height >= minimumRectSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public MainPointModule(SplineEditor editor) : base(editor)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
int pointCount = isClosed ? points.Length - 1 : points.Length;
|
||||
string[] options = new string[pointCount + 4];
|
||||
options[0] = "- - -";
|
||||
if (selectedPoints.Count > 1) options[0] = "- Multiple -";
|
||||
options[1] = "All";
|
||||
options[2] = "None";
|
||||
options[3] = "Inverse";
|
||||
for (int i = 0; i < pointCount; i++)
|
||||
{
|
||||
options[i + 4] = "Point " + (i + 1);
|
||||
if (splineType == Spline.Type.Bezier)
|
||||
{
|
||||
switch (points[i].type)
|
||||
{
|
||||
case SplinePoint.Type.Broken: options[i + 4] += " - Broken"; break;
|
||||
case SplinePoint.Type.SmoothFree: options[i + 4] += " - Smooth Free"; break;
|
||||
case SplinePoint.Type.SmoothMirrored: options[i + 4] += " - Smooth Mirrored"; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
int option = 0;
|
||||
if (selectedPoints.Count == 1) {
|
||||
option = selectedPoints[0] + 4;
|
||||
}
|
||||
option = EditorGUILayout.Popup("Select", option, options);
|
||||
switch (option)
|
||||
{
|
||||
case 1:
|
||||
ClearSelection();
|
||||
for (int i = 0; i < points.Length; i++) AddPointSelection(i);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
ClearSelection();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
InverseSelection();
|
||||
break;
|
||||
}
|
||||
if(option >= 4)
|
||||
{
|
||||
SelectPoint(option - 4);
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawScene()
|
||||
{
|
||||
Transform camTransform = SceneView.currentDrawingSceneView.camera.transform;
|
||||
|
||||
if (!drag)
|
||||
{
|
||||
if (finalize)
|
||||
{
|
||||
if (rect.width > 0f && rect.height > 0f)
|
||||
{
|
||||
if (!eventModule.control) ClearSelection();
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
Vector2 guiPoint = HandleUtility.WorldToGUIPoint(points[i].position);
|
||||
if (rect.Contains(guiPoint))
|
||||
{
|
||||
Vector3 local = camTransform.InverseTransformPoint(points[i].position);
|
||||
if (local.z >= 0f)
|
||||
{
|
||||
AddPointSelection(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finalize = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rectEnd = Event.current.mousePosition;
|
||||
rect = new Rect(Mathf.Min(rectStart.x, rectEnd.x), Mathf.Min(rectStart.y, rectEnd.y), Mathf.Abs(rectEnd.x - rectStart.x), Mathf.Abs(rectEnd.y - rectStart.y));
|
||||
if (rect.width >= minimumRectSize && rect.height >= minimumRectSize)
|
||||
{
|
||||
Color col = SplinePrefs.highlightColor;
|
||||
col.a = 0.4f;
|
||||
Handles.BeginGUI();
|
||||
EditorGUI.DrawRect(rect, col);
|
||||
Handles.EndGUI();
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
}
|
||||
TextAnchor originalAlignment = GUI.skin.label.alignment;
|
||||
Color originalColor = GUI.skin.label.normal.textColor;
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||
GUI.skin.label.normal.textColor = color;
|
||||
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
if (isClosed && i == points.Length - 1) break;
|
||||
bool moved = false;
|
||||
bool isSelected = selectedPoints.Contains(i);
|
||||
Vector3 lastPos = points[i].position;
|
||||
Handles.color = Color.clear;
|
||||
if (SplinePrefs.showPointNumbers && camTransform.InverseTransformPoint(points[i].position).z > 0f)
|
||||
{
|
||||
Handles.Label(points[i].position + Camera.current.transform.up * HandleUtility.GetHandleSize(points[i].position) * 0.3f, (i + 1).ToString());
|
||||
}
|
||||
if (excludeSelected && isSelected) SplineEditorHandles.FreeMoveRectangle(points[i].position, HandleUtility.GetHandleSize(points[i].position) * 0.1f);
|
||||
else points[i].SetPosition(SplineEditorHandles.FreeMoveRectangle(points[i].position, HandleUtility.GetHandleSize(points[i].position) * 0.1f));
|
||||
|
||||
if (lastPos != points[i].position)
|
||||
{
|
||||
RecordUndo("Move Points");
|
||||
moved = true;
|
||||
if (isSelected)
|
||||
{
|
||||
for (int n = 0; n < selectedPoints.Count; n++)
|
||||
{
|
||||
if (selectedPoints[n] == i) continue;
|
||||
points[selectedPoints[n]].SetPosition(points[selectedPoints[n]].position + (points[i].position - lastPos));
|
||||
}
|
||||
}
|
||||
else SelectPoint(i);
|
||||
lastPos = points[i].position;
|
||||
}
|
||||
|
||||
|
||||
if (!moved && editor.eventModule.mouseLeftUp)
|
||||
{
|
||||
if(SplineEditorHandles.HoverArea(points[i].position, 0.12f))
|
||||
{
|
||||
if (eventModule.shift) ShiftSelect(i, points.Length);
|
||||
else if (eventModule.control) AddPointSelection(i);
|
||||
else SelectPoint(i);
|
||||
}
|
||||
}
|
||||
if (!excludeSelected || !isSelected)
|
||||
{
|
||||
Handles.color = color;
|
||||
if (isSelected)
|
||||
{
|
||||
Handles.color = SplinePrefs.highlightColor;
|
||||
Handles.DrawWireDisc(points[i].position, -SceneView.currentDrawingSceneView.camera.transform.forward, HandleUtility.GetHandleSize(points[i].position) * 0.14f);
|
||||
} else Handles.color = color;
|
||||
Handles.DrawSolidDisc(points[i].position, -SceneView.currentDrawingSceneView.camera.transform.forward, HandleUtility.GetHandleSize(points[i].position) * 0.09f);
|
||||
Handles.color = Color.white;
|
||||
}
|
||||
moved = false;
|
||||
}
|
||||
GUI.skin.label.alignment = originalAlignment;
|
||||
GUI.skin.label.normal.textColor = originalColor;
|
||||
|
||||
if (splineType == Spline.Type.Bezier)
|
||||
{
|
||||
Handles.color = color;
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
Handles.DrawDottedLine(points[selectedPoints[i]].position, points[selectedPoints[i]].tangent, 4f);
|
||||
Handles.DrawDottedLine(points[selectedPoints[i]].position, points[selectedPoints[i]].tangent2, 4f);
|
||||
Vector3 lastPos = points[selectedPoints[i]].tangent;
|
||||
Vector3 newPos = SplineEditorHandles.FreeMoveCircle(points[selectedPoints[i]].tangent, HandleUtility.GetHandleSize(points[selectedPoints[i]].tangent) * 0.1f);
|
||||
if (lastPos != newPos)
|
||||
{
|
||||
RecordUndo("Move Tangent");
|
||||
points[selectedPoints[i]].SetTangentPosition(newPos);
|
||||
}
|
||||
lastPos = points[selectedPoints[i]].tangent2;
|
||||
newPos = SplineEditorHandles.FreeMoveCircle(points[selectedPoints[i]].tangent2, HandleUtility.GetHandleSize(points[selectedPoints[i]].tangent2) * 0.1f);
|
||||
if (lastPos != newPos)
|
||||
{
|
||||
RecordUndo("Move Tangent");
|
||||
points[selectedPoints[i]].SetTangent2Position(newPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isDragging)
|
||||
{
|
||||
if (eventModule.alt || !SceneView.currentDrawingSceneView.camera.pixelRect.Contains(Event.current.mousePosition) || !eventModule.mouseLeft) FinishDrag();
|
||||
}
|
||||
}
|
||||
|
||||
void ShiftSelect(int index, int pointCount)
|
||||
{
|
||||
if (selectedPoints.Count == 0)
|
||||
{
|
||||
AddPointSelection(index);
|
||||
return;
|
||||
}
|
||||
int minSelected = pointCount-1, maxSelected = 0;
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
if (minSelected > selectedPoints[i]) minSelected = selectedPoints[i];
|
||||
if (maxSelected < selectedPoints[i]) maxSelected = selectedPoints[i];
|
||||
}
|
||||
|
||||
if(index > maxSelected)
|
||||
{
|
||||
for (int i = maxSelected + 1; i <= index; i++) AddPointSelection(i);
|
||||
} else if(index < minSelected)
|
||||
{
|
||||
for (int i = minSelected-1; i >= index; i--) AddPointSelection(i);
|
||||
} else
|
||||
{
|
||||
for (int i = minSelected + 1; i <= index; i++) AddPointSelection(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void StartDrag(Vector2 position)
|
||||
{
|
||||
rectStart = position;
|
||||
drag = true;
|
||||
finalize = false;
|
||||
}
|
||||
|
||||
public void FinishDrag()
|
||||
{
|
||||
if (!drag) return;
|
||||
drag = false;
|
||||
finalize = true;
|
||||
}
|
||||
|
||||
public void CancelDrag()
|
||||
{
|
||||
drag = false;
|
||||
finalize = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 222164afd4e1e1845bca6b747eca74fb
|
||||
timeCreated: 1476960765
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,377 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
|
||||
public class PointMirrorModule : PointTransformModule
|
||||
{
|
||||
public enum Axis { X, Y, Z }
|
||||
public Axis axis = Axis.X;
|
||||
public bool flip = false;
|
||||
public float weldDistance = 0f;
|
||||
Vector3 mirrorCenter = Vector3.zero;
|
||||
|
||||
|
||||
private SplinePoint[] mirrored = new SplinePoint[0];
|
||||
|
||||
|
||||
public PointMirrorModule(SplineEditor editor) : base(editor)
|
||||
{
|
||||
LoadState();
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOff()
|
||||
{
|
||||
return IconContent("||", "mirror", "Mirror Path");
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOn()
|
||||
{
|
||||
return IconContent("||", "mirror_on", "Mirror Path");
|
||||
}
|
||||
|
||||
public override void LoadState()
|
||||
{
|
||||
axis = (Axis)LoadInt("axis");
|
||||
flip = LoadBool("flip");
|
||||
weldDistance = LoadFloat("weldDistance");
|
||||
}
|
||||
|
||||
public override void SaveState()
|
||||
{
|
||||
base.SaveState();
|
||||
SaveInt("axis", (int)axis);
|
||||
SaveBool("flip", flip);
|
||||
SaveFloat("weldDistance", weldDistance);
|
||||
}
|
||||
|
||||
public override void Select()
|
||||
{
|
||||
base.Select();
|
||||
RecordUndo("Mirror Points");
|
||||
ClearSelection();
|
||||
DoMirror();
|
||||
}
|
||||
|
||||
public override void Deselect()
|
||||
{
|
||||
base.Deselect();
|
||||
if (!IsDirty()) return;
|
||||
if (EditorUtility.DisplayDialog("Unapplied Mirror Operation", "There is an unapplied mirror operation. Do you want to apply the changes?", "Apply", "Revert")) Apply();
|
||||
else Revert();
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
if (selectedPoints.Count > 0) ClearSelection();
|
||||
EditorGUI.BeginChangeCheck();
|
||||
axis = (Axis)EditorGUILayout.EnumPopup("Axis", axis);
|
||||
flip = EditorGUILayout.Toggle("Flip", flip);
|
||||
weldDistance = EditorGUILayout.FloatField("Weld Distance", weldDistance);
|
||||
mirrorCenter = EditorGUILayout.Vector3Field("Center", mirrorCenter);
|
||||
if (EditorGUI.EndChangeCheck()) DoMirror();
|
||||
if (IsDirty())
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Apply")) Apply();
|
||||
if (GUILayout.Button("Revert")) Revert();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawScene()
|
||||
{
|
||||
if (selectedPoints.Count > 0) ClearSelection();
|
||||
Vector3 worldCenter = TransformPosition(mirrorCenter);
|
||||
Vector3 lastCenter = worldCenter;
|
||||
worldCenter = Handles.PositionHandle(worldCenter, rotation);
|
||||
mirrorCenter = InverseTransformPosition(worldCenter);
|
||||
DrawMirror();
|
||||
if (lastCenter != worldCenter) DoMirror();
|
||||
selectedPoints.Clear();
|
||||
}
|
||||
|
||||
public void DoMirror()
|
||||
{
|
||||
List<int> half = GetHalf(ref originalPoints);
|
||||
int welded = -1;
|
||||
if (half.Count > 0)
|
||||
{
|
||||
if (flip)
|
||||
{
|
||||
if (IsWeldable(originalPoints[half[0]]))
|
||||
{
|
||||
welded = half[0];
|
||||
half.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsWeldable(originalPoints[half[half.Count - 1]]))
|
||||
{
|
||||
welded = half[half.Count - 1];
|
||||
half.RemoveAt(half.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
int offset = welded >= 0 ? 1 : 0;
|
||||
int additionalSlot = isClosed && half.Count > 0 ? 1 : 0;
|
||||
if (additionalSlot > 0)
|
||||
{
|
||||
if (flip)
|
||||
{
|
||||
if (IsWeldable(originalPoints[half[half.Count - 1]])) additionalSlot = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsWeldable(originalPoints[half[0]])) additionalSlot = 0;
|
||||
}
|
||||
}
|
||||
int mirroredLength = half.Count * 2 + offset + additionalSlot;
|
||||
if(mirrored.Length != mirroredLength) mirrored = new SplinePoint[mirroredLength];
|
||||
for (int i = 0; i < half.Count; i++)
|
||||
{
|
||||
if (flip)
|
||||
{
|
||||
mirrored[i] = new SplinePoint(originalPoints[half[(half.Count - 1) - i]]);
|
||||
mirrored[i + half.Count + offset] = GetMirrored(originalPoints[half[i]]);
|
||||
SwapTangents(ref mirrored[i]);
|
||||
SwapTangents(ref mirrored[i + half.Count + offset]);
|
||||
}
|
||||
else
|
||||
{
|
||||
mirrored[i] = new SplinePoint(originalPoints[half[i]]);
|
||||
mirrored[i + half.Count + offset] = GetMirrored(originalPoints[half[(half.Count - 1) - i]]);
|
||||
}
|
||||
}
|
||||
if (welded >= 0)
|
||||
{
|
||||
mirrored[half.Count] = new SplinePoint(originalPoints[welded]);
|
||||
if (flip) SwapTangents(ref mirrored[half.Count]);
|
||||
MakeMiddlePoint(ref mirrored[half.Count]);
|
||||
}
|
||||
|
||||
if (isClosed && mirrored.Length > 0)
|
||||
{
|
||||
if (additionalSlot == 0) MakeMiddlePoint(ref mirrored[0]);
|
||||
mirrored[mirrored.Length - 1] = new SplinePoint(mirrored[0]);
|
||||
}
|
||||
}
|
||||
else mirrored = new SplinePoint[0];
|
||||
points = mirrored;
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
void SwapTangents(ref SplinePoint point)
|
||||
{
|
||||
Vector3 temp = point.tangent;
|
||||
point.tangent = point.tangent2;
|
||||
point.tangent2 = temp;
|
||||
}
|
||||
|
||||
void MakeMiddlePoint(ref SplinePoint point)
|
||||
{
|
||||
point.type = SplinePoint.Type.Broken;
|
||||
InverseTransformPoint(ref point);
|
||||
Vector3 newPos = point.position;
|
||||
switch (axis)
|
||||
{
|
||||
case Axis.X:
|
||||
|
||||
newPos.x = mirrorCenter.x;
|
||||
point.SetPosition(newPos);
|
||||
if ((point.tangent.x >= mirrorCenter.x && flip) || (point.tangent.x <= mirrorCenter.x && !flip))
|
||||
{
|
||||
point.tangent2 = point.tangent;
|
||||
point.tangent2.x = point.position.x + (point.position.x - point.tangent.x);
|
||||
}
|
||||
else
|
||||
{
|
||||
point.tangent = point.tangent2;
|
||||
point.tangent.x = point.position.x + (point.position.x - point.tangent2.x);
|
||||
}
|
||||
break;
|
||||
case Axis.Y:
|
||||
newPos.y = mirrorCenter.y;
|
||||
point.SetPosition(newPos);
|
||||
if ((point.tangent.y >= mirrorCenter.y && flip) || (point.tangent.y <= mirrorCenter.y && !flip))
|
||||
{
|
||||
point.tangent2 = point.tangent;
|
||||
point.tangent2.y = point.position.y + (point.position.y - point.tangent.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
point.tangent = point.tangent2;
|
||||
point.tangent.y = point.position.y + (point.position.y - point.tangent2.y);
|
||||
}
|
||||
break;
|
||||
case Axis.Z:
|
||||
newPos.z = mirrorCenter.z;
|
||||
point.SetPosition(newPos);
|
||||
if ((point.tangent.z >= mirrorCenter.z && flip) || (point.tangent.z <= mirrorCenter.z && !flip))
|
||||
{
|
||||
point.tangent2 = point.tangent;
|
||||
point.tangent2.z = point.position.z + (point.position.z - point.tangent.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
point.tangent = point.tangent2;
|
||||
point.tangent.z = point.position.z + (point.position.z - point.tangent2.z);
|
||||
}
|
||||
break;
|
||||
}
|
||||
TransformPoint(ref point);
|
||||
}
|
||||
|
||||
bool IsWeldable(SplinePoint point)
|
||||
{
|
||||
switch (axis)
|
||||
{
|
||||
case Axis.X:
|
||||
if (Mathf.Abs(point.position.x - mirrorCenter.x) <= weldDistance) return true;
|
||||
break;
|
||||
case Axis.Y:
|
||||
if (Mathf.Abs(point.position.y - mirrorCenter.y) <= weldDistance) return true;
|
||||
break;
|
||||
case Axis.Z:
|
||||
if (Mathf.Abs(point.position.z - mirrorCenter.z) <= weldDistance) return true;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DrawMirror()
|
||||
{
|
||||
Vector3[] points = new Vector3[4];
|
||||
Color color = Color.white;
|
||||
Vector3 worldCenter = TransformPosition(mirrorCenter);
|
||||
float size = HandleUtility.GetHandleSize(worldCenter);
|
||||
Vector3 forward = rotation * Vector3.forward * size;
|
||||
Vector3 back = -forward;
|
||||
Vector3 right = rotation * Vector3.right * size;
|
||||
Vector3 left = -right;
|
||||
Vector3 up = rotation * Vector3.up * size;
|
||||
Vector3 down = -up;
|
||||
switch (axis)
|
||||
{
|
||||
case Axis.X:
|
||||
points[0] = back + up;
|
||||
points[1] = forward + up;
|
||||
points[2] = forward + down;
|
||||
points[3] = back + down;
|
||||
color = Color.red;
|
||||
break;
|
||||
case Axis.Y:
|
||||
points[0] = back + left;
|
||||
points[1] = forward + left;
|
||||
points[2] = forward + right;
|
||||
points[3] = back + right;
|
||||
color = Color.green;
|
||||
break;
|
||||
case Axis.Z:
|
||||
points[0] = left + up;
|
||||
points[1] = right + up;
|
||||
points[2] = right + down;
|
||||
points[3] = left + down;
|
||||
color = Color.blue;
|
||||
break;
|
||||
}
|
||||
Handles.color = color;
|
||||
Handles.DrawLine(worldCenter + points[0], worldCenter + points[1]);
|
||||
Handles.DrawLine(worldCenter + points[1], worldCenter + points[2]);
|
||||
Handles.DrawLine(worldCenter + points[2], worldCenter + points[3]);
|
||||
Handles.DrawLine(worldCenter + points[3], worldCenter + points[0]);
|
||||
Handles.color = Color.white;
|
||||
}
|
||||
|
||||
SplinePoint GetMirrored(SplinePoint source)
|
||||
{
|
||||
SplinePoint newPoint = new SplinePoint(source);
|
||||
InverseTransformPoint(ref newPoint);
|
||||
switch (axis)
|
||||
{
|
||||
case Axis.X:
|
||||
newPoint.position.x = mirrorCenter.x - (newPoint.position.x - mirrorCenter.x);
|
||||
newPoint.normal.x *= -1f;
|
||||
newPoint.tangent.x = mirrorCenter.x - (newPoint.tangent.x - mirrorCenter.x);
|
||||
newPoint.tangent2.x = mirrorCenter.x - (newPoint.tangent2.x - mirrorCenter.x);
|
||||
SwapTangents(ref newPoint);
|
||||
break;
|
||||
case Axis.Y:
|
||||
newPoint.position.y = mirrorCenter.y - (newPoint.position.y - mirrorCenter.y);
|
||||
newPoint.normal.y *= -1f;
|
||||
newPoint.tangent.y = mirrorCenter.y - (newPoint.tangent.y - mirrorCenter.y);
|
||||
newPoint.tangent2.y = mirrorCenter.y - (newPoint.tangent2.y - mirrorCenter.y);
|
||||
break;
|
||||
case Axis.Z:
|
||||
newPoint.position.z = mirrorCenter.z - (newPoint.position.z - mirrorCenter.z);
|
||||
newPoint.normal.z *= -1f;
|
||||
newPoint.tangent.z = mirrorCenter.z - (newPoint.tangent.z - mirrorCenter.z);
|
||||
newPoint.tangent2.z = mirrorCenter.z - (newPoint.tangent2.z - mirrorCenter.z);
|
||||
break;
|
||||
}
|
||||
TransformPoint(ref newPoint);
|
||||
return newPoint;
|
||||
}
|
||||
|
||||
|
||||
|
||||
List<int> GetHalf(ref SplinePoint[] points)
|
||||
{
|
||||
List<int> found = new List<int>();
|
||||
switch (axis)
|
||||
{
|
||||
case Axis.X:
|
||||
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
if (isClosed && i == points.Length - 1) break;
|
||||
if (flip)
|
||||
{
|
||||
if (InverseTransformPosition(points[i].position).x >= mirrorCenter.x) found.Add(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (InverseTransformPosition(points[i].position).x <= mirrorCenter.x) found.Add(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Axis.Y:
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
if (isClosed && i == points.Length - 1) break;
|
||||
if (flip)
|
||||
{
|
||||
if (InverseTransformPosition(points[i].position).y >= mirrorCenter.y) found.Add(i);
|
||||
else
|
||||
{
|
||||
if (InverseTransformPosition(points[i].position).y <= mirrorCenter.y) found.Add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Axis.Z:
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
if (isClosed && i == points.Length - 1) break;
|
||||
if (flip)
|
||||
{
|
||||
if (InverseTransformPosition(points[i].position).z >= mirrorCenter.z) found.Add(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (InverseTransformPosition(points[i].position).z <= mirrorCenter.z) found.Add(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0562a8339f410c04180d98ba21fdafb3
|
||||
timeCreated: 1476814299
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,327 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class PointModule : EditorModule
|
||||
{
|
||||
protected bool isClosed
|
||||
{
|
||||
get { return editor.isClosed; }
|
||||
}
|
||||
protected int sampleRate
|
||||
{
|
||||
get { return editor.sampleRate; }
|
||||
}
|
||||
protected Spline.Type splineType
|
||||
{
|
||||
get { return editor.splineType; }
|
||||
}
|
||||
protected Color color {
|
||||
get { return editor.color; }
|
||||
}
|
||||
protected SplineEditor editor;
|
||||
|
||||
protected SplinePoint[] points{
|
||||
get { return editor.points; }
|
||||
set { editor.points = value; }
|
||||
}
|
||||
|
||||
protected List<int> selectedPoints
|
||||
{
|
||||
get { return editor.selectedPoints; }
|
||||
set { editor.selectedPoints = value; }
|
||||
}
|
||||
|
||||
public Vector3 center
|
||||
{
|
||||
get
|
||||
{
|
||||
Vector3 avg = Vector3.zero;
|
||||
if (points.Length == 0) return avg;
|
||||
for (int i = 0; i < points.Length; i++) avg += points[i].position;
|
||||
return avg / points.Length;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 selectionCenter
|
||||
{
|
||||
get
|
||||
{
|
||||
Vector3 avg = Vector3.zero;
|
||||
if (selectedPoints.Count == 0) return avg;
|
||||
for (int i = 0; i < selectedPoints.Count; i++) avg += points[selectedPoints[i]].position;
|
||||
return avg / selectedPoints.Count;
|
||||
}
|
||||
}
|
||||
|
||||
protected EditorGUIEvents eventModule;
|
||||
|
||||
public delegate void UndoHandler(string title);
|
||||
public delegate void EmptyHandler();
|
||||
public delegate void IntHandler(int value);
|
||||
public delegate void IntArrayHandler(int[] values);
|
||||
|
||||
public event EmptyHandler onBeforeDeleteSelectedPoints;
|
||||
public event EmptyHandler onSelectionChanged;
|
||||
public event IntArrayHandler onDuplicatePoint;
|
||||
|
||||
private bool movePivot = false;
|
||||
private Vector3 idealPivot = Vector3.zero;
|
||||
|
||||
|
||||
public PointModule(SplineEditor editor)
|
||||
{
|
||||
this.editor = editor;
|
||||
eventModule = editor.eventModule;
|
||||
}
|
||||
|
||||
protected override void RecordUndo(string title)
|
||||
{
|
||||
if (editor.undoHandler != null) editor.undoHandler(title);
|
||||
}
|
||||
|
||||
protected override void Repaint()
|
||||
{
|
||||
if (editor.repaintHandler != null) editor.repaintHandler();
|
||||
}
|
||||
|
||||
public override void BeforeSceneDraw(SceneView current)
|
||||
{
|
||||
base.BeforeSceneDraw(current);
|
||||
Event e = Event.current;
|
||||
|
||||
if (movePivot)
|
||||
{
|
||||
SceneView.lastActiveSceneView.pivot = Vector3.Lerp(SceneView.lastActiveSceneView.pivot, idealPivot, 0.02f);
|
||||
if (e.type == EventType.MouseDown || e.type == EventType.MouseUp) movePivot = false;
|
||||
if (Vector3.Distance(SceneView.lastActiveSceneView.pivot, idealPivot) <= 0.05f)
|
||||
{
|
||||
SceneView.lastActiveSceneView.pivot = idealPivot;
|
||||
movePivot = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (e.type == EventType.KeyDown && e.keyCode == KeyCode.Delete && HasSelection())
|
||||
{
|
||||
DeleteSelectedPoints();
|
||||
e.Use();
|
||||
}
|
||||
|
||||
if(e.type == EventType.ExecuteCommand && Tools.current == Tool.None)
|
||||
{
|
||||
switch (e.commandName)
|
||||
{
|
||||
case "FrameSelected":
|
||||
if (points.Length > 0)
|
||||
{
|
||||
e.commandName = "";
|
||||
FramePoints();
|
||||
e.Use();
|
||||
}
|
||||
break;
|
||||
case "SelectAll":
|
||||
e.commandName = "";
|
||||
ClearSelection();
|
||||
for (int i = 0; i < points.Length; i++) AddPointSelection(i);
|
||||
e.Use();
|
||||
break;
|
||||
|
||||
case "Duplicate":
|
||||
if (points.Length > 0 && selectedPoints.Count > 0)
|
||||
{
|
||||
e.commandName = "";
|
||||
DuplicateSelected();
|
||||
e.Use();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void DuplicateSelected()
|
||||
{
|
||||
if (selectedPoints.Count == 0) return;
|
||||
RecordUndo("Duplicate Points");
|
||||
SplinePoint[] newPoints = new SplinePoint[points.Length + selectedPoints.Count];
|
||||
SplinePoint[] duplicated = new SplinePoint[selectedPoints.Count];
|
||||
int index = 0;
|
||||
for (int i = 0; i < selectedPoints.Count; i++) duplicated[index++] = points[selectedPoints[i]];
|
||||
int min = points.Length - 1, max = 0;
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
if (selectedPoints[i] < min) min = selectedPoints[i];
|
||||
if (selectedPoints[i] > max) max = selectedPoints[i];
|
||||
}
|
||||
int[] selected = selectedPoints.ToArray();
|
||||
selectedPoints.Clear();
|
||||
if (SplinePrefs.duplicationDirection == SplinePrefs.DuplicationDirection.Backward)
|
||||
{
|
||||
for (int i = 0; i < min; i++) newPoints[i] = points[i];
|
||||
for (int i = 0; i < duplicated.Length; i++)
|
||||
{
|
||||
newPoints[i + min] = duplicated[i];
|
||||
selectedPoints.Add(i + min);
|
||||
}
|
||||
for (int i = min; i < points.Length; i++) newPoints[i + duplicated.Length] = points[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i <= max; i++) newPoints[i] = points[i];
|
||||
for (int i = 0; i < duplicated.Length; i++)
|
||||
{
|
||||
newPoints[i + max + 1] = duplicated[i];
|
||||
selectedPoints.Add(i + max + 1);
|
||||
}
|
||||
for (int i = max + 1; i < points.Length; i++) newPoints[i + duplicated.Length] = points[i];
|
||||
}
|
||||
points = newPoints;
|
||||
if (onDuplicatePoint != null) onDuplicatePoint(selected);
|
||||
}
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
}
|
||||
|
||||
public bool HasSelection()
|
||||
{
|
||||
return selectedPoints.Count > 0;
|
||||
}
|
||||
|
||||
public void ClearSelection()
|
||||
{
|
||||
selectedPoints.Clear();
|
||||
Repaint();
|
||||
if (editor.selectionChangeHandler != null) editor.selectionChangeHandler();
|
||||
if (onSelectionChanged != null) onSelectionChanged();
|
||||
}
|
||||
|
||||
protected void DeleteSelectedPoints()
|
||||
{
|
||||
if (onBeforeDeleteSelectedPoints != null) onBeforeDeleteSelectedPoints();
|
||||
if (isClosed && selectedPoints.Count == points.Length - 1)
|
||||
{
|
||||
for (int i = points.Length - 1; i >= 0; i--) DeletePoint(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
DeletePoint(selectedPoints[i]);
|
||||
for (int n = i; n < selectedPoints.Count; n++) selectedPoints[n]--;
|
||||
}
|
||||
}
|
||||
ClearSelection();
|
||||
}
|
||||
|
||||
protected void DeletePoint(int index)
|
||||
{
|
||||
RecordUndo("Delete Point");
|
||||
SplinePoint[] p = points;
|
||||
ArrayUtility.RemoveAt(ref p, index);
|
||||
points = p;
|
||||
}
|
||||
|
||||
|
||||
public void InverseSelection()
|
||||
{
|
||||
List<int> inverse = new List<int>();
|
||||
for (int i = 0; i < (isClosed ? points.Length - 1 : points.Length); i++)
|
||||
{
|
||||
bool found = false;
|
||||
for (int j = 0; j < selectedPoints.Count; j++)
|
||||
{
|
||||
if (selectedPoints[j] == i)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) inverse.Add(i);
|
||||
}
|
||||
selectedPoints = new List<int>(inverse);
|
||||
Repaint();
|
||||
if (editor.selectionChangeHandler != null) editor.selectionChangeHandler();
|
||||
if (onSelectionChanged != null) onSelectionChanged();
|
||||
}
|
||||
|
||||
protected void SelectPoint(int index)
|
||||
{
|
||||
if (isClosed && index == points.Length - 1) return;
|
||||
if (selectedPoints.Count == 1 && selectedPoints[0] == index) return;
|
||||
selectedPoints.Clear();
|
||||
selectedPoints.Add(index);
|
||||
Repaint();
|
||||
if (editor.selectionChangeHandler != null) editor.selectionChangeHandler();
|
||||
if (onSelectionChanged != null) onSelectionChanged();
|
||||
}
|
||||
|
||||
protected void SelectPoints(List<int> indices)
|
||||
{
|
||||
selectedPoints.Clear();
|
||||
for (int i = 0; i < indices.Count; i++)
|
||||
{
|
||||
if (isClosed && i == points.Length - 1) continue;
|
||||
selectedPoints.Add(indices[i]);
|
||||
}
|
||||
Repaint();
|
||||
if (editor.selectionChangeHandler != null) editor.selectionChangeHandler();
|
||||
if (onSelectionChanged != null) onSelectionChanged();
|
||||
}
|
||||
|
||||
protected void AddPointSelection(int index)
|
||||
{
|
||||
if (isClosed && index == points.Length - 1) return;
|
||||
if (selectedPoints.Contains(index)) return;
|
||||
selectedPoints.Add(index);
|
||||
Repaint();
|
||||
if (editor.selectionChangeHandler != null) editor.selectionChangeHandler();
|
||||
if (onSelectionChanged != null) onSelectionChanged();
|
||||
}
|
||||
|
||||
protected void FramePoints()
|
||||
{
|
||||
if (points.Length == 0) return;
|
||||
Vector3 center = Vector3.zero;
|
||||
Camera camera = SceneView.lastActiveSceneView.camera;
|
||||
Transform cam = camera.transform;
|
||||
Vector3 min = Vector3.zero, max = Vector3.zero;
|
||||
if (HasSelection())
|
||||
{
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
center += points[selectedPoints[i]].position;
|
||||
Vector3 local = cam.InverseTransformPoint(points[selectedPoints[i]].position);
|
||||
if (local.x < min.x) min.x = local.x;
|
||||
if (local.y < min.y) min.y = local.y;
|
||||
if (local.z < min.z) min.z = local.z;
|
||||
if (local.x > max.x) max.x = local.x;
|
||||
if (local.y > max.y) max.y = local.y;
|
||||
if (local.z > max.z) max.z = local.z;
|
||||
}
|
||||
center /= selectedPoints.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
center += points[i].position;
|
||||
Vector3 local = cam.InverseTransformPoint(points[i].position);
|
||||
if (local.x < min.x) min.x = local.x;
|
||||
if (local.y < min.y) min.y = local.y;
|
||||
if (local.z < min.z) min.z = local.z;
|
||||
if (local.x > max.x) max.x = local.x;
|
||||
if (local.y > max.y) max.y = local.y;
|
||||
if (local.z > max.z) max.z = local.z;
|
||||
}
|
||||
center /= points.Length;
|
||||
}
|
||||
movePivot = true;
|
||||
idealPivot = center;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b030b7d8eb93a004185129c729549ba8
|
||||
timeCreated: 1476220001
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,129 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class PointMoveModule : PointTransformModule
|
||||
{
|
||||
public bool snap = false;
|
||||
public float snapGridSize = 1f;
|
||||
public bool surfaceMode = false;
|
||||
public float surfaceOffset = 0f;
|
||||
public LayerMask surfaceLayerMask = ~0;
|
||||
|
||||
public PointMoveModule(SplineEditor editor) : base(editor)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOff()
|
||||
{
|
||||
return EditorGUIUtility.IconContent("MoveTool");
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOn()
|
||||
{
|
||||
return EditorGUIUtility.IconContent("MoveTool On");
|
||||
}
|
||||
|
||||
public override void LoadState()
|
||||
{
|
||||
base.LoadState();
|
||||
snap = LoadBool("snap");
|
||||
snapGridSize = LoadFloat("snapGridSize", 0.5f);
|
||||
surfaceOffset = LoadFloat("surfaceOffset", 0f);
|
||||
surfaceMode = LoadBool("surfaceMode");
|
||||
surfaceLayerMask = LoadInt("surfaceLayerMask", ~0);
|
||||
}
|
||||
|
||||
public override void SaveState()
|
||||
{
|
||||
base.SaveState();
|
||||
SaveBool("snap", snap);
|
||||
SaveFloat("snapGridSize", snapGridSize);
|
||||
SaveFloat("surfaceOffset", surfaceOffset);
|
||||
SaveBool("surfaceMode", surfaceMode);
|
||||
SaveInt("surfaceLayerMask", surfaceLayerMask);
|
||||
}
|
||||
|
||||
public override void BeforeSceneDraw(SceneView current)
|
||||
{
|
||||
base.BeforeSceneDraw(current);
|
||||
if (Event.current.type == EventType.MouseUp) GetRotation();
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
editSpace = (EditSpace)EditorGUILayout.EnumPopup("Edit Space", editSpace);
|
||||
surfaceMode = EditorGUILayout.Toggle("Move On Surface", surfaceMode);
|
||||
if (surfaceMode)
|
||||
{
|
||||
surfaceLayerMask = DreamteckEditorGUI.LayermaskField("Surface Mask", surfaceLayerMask);
|
||||
surfaceOffset = EditorGUILayout.FloatField("Surface Offset", surfaceOffset);
|
||||
}
|
||||
snap = EditorGUILayout.Toggle("Snap to Grid", snap);
|
||||
if (snap)
|
||||
{
|
||||
snapGridSize = EditorGUILayout.FloatField("Grid Size", snapGridSize);
|
||||
if (snapGridSize < 0.0001f) snapGridSize = 0.0001f;
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawScene()
|
||||
{
|
||||
if (selectedPoints.Count == 0) return;
|
||||
Vector3 c = selectionCenter;
|
||||
Vector3 lastPos = c;
|
||||
if (surfaceMode)
|
||||
{
|
||||
//var fmh_81_47_638379167653548539 = Quaternion.LookRotation(SceneView.currentDrawingSceneView.camera.transform.position - c); c = Handles.FreeMoveHandle(c, HandleUtility.GetHandleSize(c) * 0.2f, Vector3.zero, Handles.CircleHandleCap);
|
||||
if(lastPos != c)
|
||||
{
|
||||
Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
|
||||
RaycastHit hit;
|
||||
if (Physics.Raycast(ray, out hit, Mathf.Infinity, surfaceLayerMask))
|
||||
{
|
||||
c = hit.point + hit.normal * surfaceOffset;
|
||||
Handles.DrawLine(hit.point, hit.point + hit.normal * HandleUtility.GetHandleSize(hit.point) * 0.5f);
|
||||
}
|
||||
}
|
||||
} else c = Handles.PositionHandle(c, rotation);
|
||||
if (lastPos != c)
|
||||
{
|
||||
RecordUndo("Move Points");
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
if (isClosed && selectedPoints[i] == points.Length - 1) continue;
|
||||
points[selectedPoints[i]].SetPosition(points[selectedPoints[i]].position + (c - lastPos));
|
||||
if (snap) points[selectedPoints[i]].SetPosition(SnapPoint(points[selectedPoints[i]].position));
|
||||
}
|
||||
}
|
||||
|
||||
if (splineType == Spline.Type.Bezier && selectedPoints.Count == 1)
|
||||
{
|
||||
int index = selectedPoints[0];
|
||||
lastPos = points[index].tangent;
|
||||
Vector3 newPos = Handles.PositionHandle(points[index].tangent, rotation);
|
||||
if (snap) newPos = SnapPoint(newPos);
|
||||
if (newPos != lastPos) RecordUndo("Move Tangents");
|
||||
points[index].SetTangentPosition(newPos);
|
||||
|
||||
lastPos = points[index].tangent2;
|
||||
newPos = Handles.PositionHandle(points[index].tangent2, rotation);
|
||||
if (snap) newPos = SnapPoint(newPos);
|
||||
if (newPos != lastPos) RecordUndo("Move Tangents");
|
||||
points[index].SetTangent2Position(newPos);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 SnapPoint(Vector3 point)
|
||||
{
|
||||
point.x = Mathf.RoundToInt(point.x / snapGridSize) * snapGridSize;
|
||||
point.y = Mathf.RoundToInt(point.y / snapGridSize) * snapGridSize;
|
||||
point.z = Mathf.RoundToInt(point.z / snapGridSize) * snapGridSize;
|
||||
return point;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37e5af750f2ba6a49bd760d3a39d1309
|
||||
timeCreated: 1476219856
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,178 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class PointNormalModule : PointModule
|
||||
{
|
||||
public enum NormalMode { Auto, Free }
|
||||
public NormalMode normalMode = NormalMode.Auto;
|
||||
SplineSample evalResult = new SplineSample();
|
||||
public PointNormalModule(SplineEditor editor) : base(editor)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOff()
|
||||
{
|
||||
return IconContent("N", "normal", "Set Point Normals");
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOn()
|
||||
{
|
||||
return IconContent("N", "normal_on", "Set Point Normals");
|
||||
}
|
||||
|
||||
void SetNormals(int mode)
|
||||
{
|
||||
mode--;
|
||||
Vector3 avg = Vector3.zero;
|
||||
for (int i = 0; i < selectedPoints.Count; i++) avg += points[selectedPoints[i]].position;
|
||||
if (selectedPoints.Count > 1) avg /= selectedPoints.Count;
|
||||
Camera editorCamera = SceneView.lastActiveSceneView.camera;
|
||||
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case 0: points[selectedPoints[i]].normal *= -1; break;
|
||||
case 1: points[selectedPoints[i]].normal = Vector3.Normalize(editorCamera.transform.position - points[selectedPoints[i]].position); break;
|
||||
case 2: points[selectedPoints[i]].normal = editorCamera.transform.forward; break;
|
||||
case 3: points[selectedPoints[i]].normal = CalculatePointNormal(points, selectedPoints[i], isClosed); break;
|
||||
case 4: points[selectedPoints[i]].normal = Vector3.left; break;
|
||||
case 5: points[selectedPoints[i]].normal = Vector3.right; break;
|
||||
case 6: points[selectedPoints[i]].normal = Vector3.up; break;
|
||||
case 7: points[selectedPoints[i]].normal = Vector3.down; break;
|
||||
case 8: points[selectedPoints[i]].normal = Vector3.forward; break;
|
||||
case 9: points[selectedPoints[i]].normal = Vector3.back; break;
|
||||
case 10: points[selectedPoints[i]].normal = Vector3.Normalize(avg - points[selectedPoints[i]].position); break;
|
||||
case 11:
|
||||
SplineSample result = new SplineSample();
|
||||
editor.evaluateAtPoint(selectedPoints[i], result);
|
||||
points[selectedPoints[i]].normal = Vector3.Cross(result.forward, result.right).normalized;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3 CalculatePointNormal(SplinePoint[] points, int index, bool isClosed)
|
||||
{
|
||||
if (points.Length < 3)
|
||||
{
|
||||
Debug.Log("Spline needs to have at least 3 control points in order to calculate normals");
|
||||
return Vector3.zero;
|
||||
}
|
||||
Vector3 side1 = Vector3.zero;
|
||||
Vector3 side2 = Vector3.zero;
|
||||
if (index == 0)
|
||||
{
|
||||
if (isClosed)
|
||||
{
|
||||
side1 = points[index].position - points[index + 1].position;
|
||||
side2 = points[index].position - points[points.Length - 2].position;
|
||||
}
|
||||
else
|
||||
{
|
||||
side1 = points[0].position - points[1].position;
|
||||
side2 = points[0].position - points[2].position;
|
||||
}
|
||||
}
|
||||
else if (index == points.Length - 1)
|
||||
{
|
||||
side1 = points[points.Length - 1].position - points[points.Length - 3].position;
|
||||
side2 = points[points.Length - 1].position - points[points.Length - 2].position;
|
||||
}
|
||||
else
|
||||
{
|
||||
side1 = points[index].position - points[index + 1].position;
|
||||
side2 = points[index].position - points[index - 1].position;
|
||||
}
|
||||
return Vector3.Cross(side1.normalized, side2.normalized).normalized;
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
if (editor.is2D)
|
||||
{
|
||||
EditorGUILayout.LabelField("Normal editing unavailable in 2D Mode", EditorStyles.centeredGreyMiniLabel);
|
||||
return;
|
||||
}
|
||||
normalMode = (NormalMode)EditorGUILayout.EnumPopup("Normal Mode", normalMode);
|
||||
|
||||
int setNormals = EditorGUILayout.Popup(0, new string[] {"Normal Operations", "Flip", "Look At Camera", "Align with Camera", "Calculate", "Left", "Right", "Up", "Down", "Forward", "Back", "Look At Avg. Center", "Perpendicular to Spline" });
|
||||
if (setNormals > 0) SetNormals(setNormals);
|
||||
}
|
||||
|
||||
public override void DrawScene()
|
||||
{
|
||||
if (editor.is2D) return;
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
if (isClosed && selectedPoints[i] == points.Length - 1) continue;
|
||||
if (normalMode == NormalMode.Free) FreeNormal(selectedPoints[i]);
|
||||
else AutoNormal(selectedPoints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void AutoNormal(int index)
|
||||
{
|
||||
editor.evaluateAtPoint(index, evalResult);
|
||||
Handles.color = SplinePrefs.highlightColor;
|
||||
Handles.DrawWireDisc(evalResult.position, evalResult.forward, HandleUtility.GetHandleSize(points[index].position) * 0.5f);
|
||||
Handles.color = color;
|
||||
Matrix4x4 matrix = Matrix4x4.TRS(points[index].position, evalResult.rotation, Vector3.one);
|
||||
Vector3 pos = points[index].position + points[index].normal * HandleUtility.GetHandleSize(points[index].position) * 0.5f;
|
||||
Handles.DrawLine(evalResult.position, pos);
|
||||
Vector3 lastPos = pos;
|
||||
Vector3 lastLocalPos = matrix.inverse.MultiplyPoint(pos);
|
||||
//var fmh_130_47_638379167653592347 = Quaternion.identity; pos = Handles.FreeMoveHandle(pos, HandleUtility.GetHandleSize(pos) * 0.1f, Vector3.zero, Handles.CircleHandleCap);
|
||||
if (pos != lastPos)
|
||||
{
|
||||
RecordUndo("Edit Point Normals");
|
||||
pos = matrix.inverse.MultiplyPoint(pos);
|
||||
Vector3 delta = pos - lastLocalPos;
|
||||
for (int n = 0; n < selectedPoints.Count; n++)
|
||||
{
|
||||
if (selectedPoints[n] == index) continue;
|
||||
editor.evaluateAtPoint(selectedPoints[n], evalResult);
|
||||
Matrix4x4 localMatrix = Matrix4x4.TRS(points[selectedPoints[n]].position, evalResult.rotation, Vector3.one);
|
||||
Vector3 localPos = localMatrix.inverse.MultiplyPoint(points[selectedPoints[n]].position + points[selectedPoints[n]].normal * HandleUtility.GetHandleSize(points[selectedPoints[n]].position) * 0.5f);
|
||||
localPos += delta;
|
||||
localPos.z = 0f;
|
||||
points[selectedPoints[n]].normal = (localMatrix.MultiplyPoint(localPos) - points[selectedPoints[n]].position).normalized;
|
||||
}
|
||||
pos.z = 0f;
|
||||
pos = matrix.MultiplyPoint(pos);
|
||||
points[index].normal = (pos - points[index].position).normalized;
|
||||
}
|
||||
}
|
||||
|
||||
void FreeNormal(int index)
|
||||
{
|
||||
Handles.color = SplinePrefs.highlightColor;
|
||||
Handles.DrawWireDisc(points[index].position, points[index].normal, HandleUtility.GetHandleSize(points[index].position) * 0.25f);
|
||||
Handles.DrawWireDisc(points[index].position, points[index].normal, HandleUtility.GetHandleSize(points[index].position) * 0.5f);
|
||||
Handles.color = color;
|
||||
Handles.DrawLine(points[index].position, points[index].position + HandleUtility.GetHandleSize(points[index].position) * points[index].normal);
|
||||
Vector3 normalPos = points[index].position + points[index].normal * HandleUtility.GetHandleSize(points[index].position);
|
||||
Vector3 lastNormal = points[index].normal;
|
||||
normalPos = SplineEditorHandles.FreeMoveCircle(normalPos, HandleUtility.GetHandleSize(normalPos) * 0.1f);
|
||||
normalPos -= points[index].position;
|
||||
normalPos.Normalize();
|
||||
if (normalPos == Vector3.zero) normalPos = Vector3.up;
|
||||
if (lastNormal != normalPos)
|
||||
{
|
||||
RecordUndo("Edit Point Normals");
|
||||
points[index].normal = normalPos;
|
||||
Quaternion delta = Quaternion.FromToRotation(lastNormal, normalPos);
|
||||
for (int n = 0; n < selectedPoints.Count; n++)
|
||||
{
|
||||
if (selectedPoints[n] == index) continue;
|
||||
points[selectedPoints[n]].normal = delta * points[selectedPoints[n]].normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9bb1bdae9d59a748a61453d1696598f
|
||||
timeCreated: 1476219856
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,78 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class PointRotateModule : PointTransformModule
|
||||
{
|
||||
public bool rotateNormals = true;
|
||||
public bool rotateTangents = true;
|
||||
|
||||
public PointRotateModule(SplineEditor editor) : base(editor)
|
||||
{
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOff()
|
||||
{
|
||||
return EditorGUIUtility.IconContent("RotateTool");
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOn()
|
||||
{
|
||||
return EditorGUIUtility.IconContent("RotateTool On");
|
||||
}
|
||||
|
||||
public override void LoadState()
|
||||
{
|
||||
base.LoadState();
|
||||
rotateNormals = LoadBool("rotateNormals");
|
||||
rotateTangents = LoadBool("rotateTangents");
|
||||
}
|
||||
|
||||
public override void SaveState()
|
||||
{
|
||||
base.SaveState();
|
||||
SaveBool("rotateNormals", rotateNormals);
|
||||
SaveBool("rotateTangents", rotateTangents);
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
editSpace = (EditSpace)EditorGUILayout.EnumPopup("Edit Space", editSpace);
|
||||
rotateNormals = EditorGUILayout.Toggle("Rotate Normals", rotateNormals);
|
||||
rotateTangents = EditorGUILayout.Toggle("Rotate Tangents", rotateTangents);
|
||||
}
|
||||
|
||||
public override void DrawScene()
|
||||
{
|
||||
if (selectedPoints.Count == 0) return;
|
||||
if (rotateNormals)
|
||||
{
|
||||
Handles.color = new Color(Color.yellow.r, Color.yellow.g, Color.yellow.b, 0.4f);
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
Vector3 normal = points[selectedPoints[i]].normal;
|
||||
normal *= HandleUtility.GetHandleSize(points[selectedPoints[i]].position);
|
||||
Handles.DrawLine(points[selectedPoints[i]].position, points[selectedPoints[i]].position + normal);
|
||||
SplineEditorHandles.DrawArrowCap(points[selectedPoints[i]].position + normal, Quaternion.LookRotation(normal), HandleUtility.GetHandleSize(points[selectedPoints[i]].position));
|
||||
}
|
||||
}
|
||||
Handles.color = Color.white;
|
||||
Quaternion lastRotation = rotation;
|
||||
rotation = Handles.RotationHandle(lastRotation, selectionCenter);
|
||||
if (lastRotation != rotation)
|
||||
{
|
||||
RecordUndo("Rotate Points");
|
||||
PrepareTransform();
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
points[selectedPoints[i]] = localPoints[selectedPoints[i]];
|
||||
TransformPoint(ref points[selectedPoints[i]], rotateNormals, rotateTangents);
|
||||
}
|
||||
SetDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 241d10a7b944cc44e9a68f8a66f3b04d
|
||||
timeCreated: 1476219856
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,68 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class PointScaleModule : PointTransformModule
|
||||
{
|
||||
public bool scaleSize = true;
|
||||
public bool scaleTangents = true;
|
||||
|
||||
|
||||
public PointScaleModule(SplineEditor editor) : base(editor)
|
||||
{
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOff()
|
||||
{
|
||||
return EditorGUIUtility.IconContent("ScaleTool");
|
||||
}
|
||||
|
||||
public override GUIContent GetIconOn()
|
||||
{
|
||||
return EditorGUIUtility.IconContent("ScaleTool On");
|
||||
}
|
||||
|
||||
public override void LoadState()
|
||||
{
|
||||
base.LoadState();
|
||||
scaleSize = LoadBool("scaleSize");
|
||||
scaleTangents = LoadBool("scaleTangents");
|
||||
}
|
||||
|
||||
public override void SaveState()
|
||||
{
|
||||
base.SaveState();
|
||||
SaveBool("scaleSize", scaleSize);
|
||||
SaveBool("scaleTangents", scaleTangents);
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
editSpace = (EditSpace)EditorGUILayout.EnumPopup("Edit Space", editSpace);
|
||||
scaleSize = EditorGUILayout.Toggle("Scale Sizes", scaleSize);
|
||||
scaleTangents = EditorGUILayout.Toggle("Scale Tangents", scaleTangents);
|
||||
}
|
||||
|
||||
public override void DrawScene()
|
||||
{
|
||||
if (selectedPoints.Count == 0) return;
|
||||
Vector3 lastScale = scale;
|
||||
Vector3 c = selectionCenter;
|
||||
scale = Handles.ScaleHandle(scale, c, rotation, HandleUtility.GetHandleSize(c));
|
||||
if (lastScale != scale)
|
||||
{
|
||||
RecordUndo("Scale Points");
|
||||
PrepareTransform();
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
points[selectedPoints[i]] = localPoints[selectedPoints[i]];
|
||||
TransformPoint(ref points[selectedPoints[i]], false, scaleTangents, scaleSize);
|
||||
}
|
||||
SetDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2efaeffa226557a4183cdcf4cf6142a9
|
||||
timeCreated: 1476219856
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,167 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class PointTransformModule : PointModule
|
||||
{
|
||||
public enum EditSpace { World, Transform, Spline }
|
||||
public EditSpace editSpace = EditSpace.World;
|
||||
public Vector3 scale = Vector3.one, offset = Vector3.zero;
|
||||
protected Quaternion rotation = Quaternion.identity;
|
||||
protected Vector3 origin = Vector3.zero;
|
||||
protected SplinePoint[] originalPoints = new SplinePoint[0];
|
||||
protected SplinePoint[] localPoints = new SplinePoint[0];
|
||||
|
||||
private Matrix4x4 matrix = new Matrix4x4();
|
||||
private Matrix4x4 inverseMatrix = new Matrix4x4();
|
||||
private bool _unapplied = true;
|
||||
SplineSample evalResult = new SplineSample();
|
||||
|
||||
public PointTransformModule(SplineEditor editor) : base(editor)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
GetRotation();
|
||||
origin = selectionCenter;
|
||||
scale = Vector3.one;
|
||||
matrix.SetTRS(origin, rotation, Vector3.one);
|
||||
inverseMatrix = matrix.inverse;
|
||||
localPoints = new SplinePoint[points.Length];
|
||||
points.CopyTo(localPoints, 0);
|
||||
for (int i = 0; i < localPoints.Length; i++) InverseTransformPoint(ref localPoints[i]);
|
||||
}
|
||||
|
||||
protected void GetRotation()
|
||||
{
|
||||
switch (editSpace)
|
||||
{
|
||||
case EditSpace.World: rotation = Quaternion.identity; break;
|
||||
case EditSpace.Transform: rotation = editor.transform.rotation; break;
|
||||
case EditSpace.Spline:
|
||||
if (editor.evaluate == null)
|
||||
{
|
||||
Debug.LogError("Unassigned handler evaluate for Spline Editor.");
|
||||
break;
|
||||
}
|
||||
if (selectedPoints.Count == 1)
|
||||
{
|
||||
editor.evaluate((double)selectedPoints[0] / (points.Length - 1), evalResult);
|
||||
rotation = evalResult.rotation;
|
||||
}
|
||||
else rotation = Quaternion.identity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void LoadState()
|
||||
{
|
||||
base.LoadState();
|
||||
editSpace = (EditSpace)LoadInt("editSpace");
|
||||
}
|
||||
|
||||
public override void SaveState()
|
||||
{
|
||||
base.SaveState();
|
||||
SaveInt("editSpace", (int)editSpace);
|
||||
}
|
||||
|
||||
protected void SetDirty()
|
||||
{
|
||||
_unapplied = true;
|
||||
}
|
||||
|
||||
protected bool IsDirty()
|
||||
{
|
||||
return _unapplied;
|
||||
}
|
||||
|
||||
public virtual void Revert()
|
||||
{
|
||||
points = originalPoints;
|
||||
_unapplied = false;
|
||||
}
|
||||
|
||||
public virtual void Apply()
|
||||
{
|
||||
GetOriginalPoints();
|
||||
_unapplied = false;
|
||||
}
|
||||
|
||||
public override void Select()
|
||||
{
|
||||
base.Select();
|
||||
GetOriginalPoints();
|
||||
}
|
||||
|
||||
void GetOriginalPoints()
|
||||
{
|
||||
originalPoints = new SplinePoint[points.Length];
|
||||
points.CopyTo(originalPoints, 0);
|
||||
}
|
||||
|
||||
protected void PrepareTransform()
|
||||
{
|
||||
matrix.SetTRS(origin + offset, rotation, scale);
|
||||
}
|
||||
|
||||
protected Vector3 TransformPosition(Vector3 position)
|
||||
{
|
||||
return matrix.MultiplyPoint3x4(position);
|
||||
}
|
||||
|
||||
protected Vector3 InverseTransformPosition(Vector3 position)
|
||||
{
|
||||
return inverseMatrix.MultiplyPoint3x4(position);
|
||||
}
|
||||
|
||||
protected Vector3 TransformDirection(Vector3 direction)
|
||||
{
|
||||
return matrix.MultiplyVector(direction);
|
||||
}
|
||||
|
||||
protected Vector3 InverseTransformDirection(Vector3 direction)
|
||||
{
|
||||
return inverseMatrix.MultiplyVector(direction);
|
||||
}
|
||||
|
||||
protected void TransformPoint(ref SplinePoint point, bool normals = true, bool tangents = true, bool size = false)
|
||||
{
|
||||
if (tangents)
|
||||
{
|
||||
point.position = TransformPosition(point.position);
|
||||
point.tangent = TransformPosition(point.tangent);
|
||||
point.tangent2 = TransformPosition(point.tangent2);
|
||||
}
|
||||
else point.SetPosition(TransformPosition(point.position));
|
||||
if(normals) point.normal = TransformDirection(point.normal).normalized;
|
||||
if (size)
|
||||
{
|
||||
float avg = (scale.x + scale.y + scale.z) / 3f;
|
||||
point.size *= avg;
|
||||
}
|
||||
}
|
||||
|
||||
protected void InverseTransformPoint(ref SplinePoint point, bool normals = true, bool tangents = true, bool size = false)
|
||||
{
|
||||
if (tangents)
|
||||
{
|
||||
point.position = InverseTransformPosition(point.position);
|
||||
point.tangent = InverseTransformPosition(point.tangent);
|
||||
point.tangent2 = InverseTransformPosition(point.tangent2);
|
||||
} else point.SetPosition(TransformPosition(point.position));
|
||||
|
||||
if (normals) point.normal = InverseTransformDirection(point.normal).normalized;
|
||||
if (size)
|
||||
{
|
||||
float avg = (scale.x + scale.y + scale.z) / 3f;
|
||||
point.size /= avg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d24553f5bce60b458dabe3b6bca0158
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
743
Assets/Dreamteck/Splines/Editor/SplineEditor/SplineEditor.cs
Normal file
743
Assets/Dreamteck/Splines/Editor/SplineEditor/SplineEditor.cs
Normal file
@@ -0,0 +1,743 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Dreamteck.Editor;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using Dreamteck.Splines;
|
||||
|
||||
public class SplineEditor : SplineEditorBase
|
||||
{
|
||||
protected Transform _transform;
|
||||
protected string editorName = "SplineEditor";
|
||||
public bool isClosed = false;
|
||||
public Spline.Type splineType;
|
||||
public int sampleRate;
|
||||
public Color color = Color.white;
|
||||
public bool is2D = false;
|
||||
|
||||
int module = -1, selectModule = -1, loadedModuleIndex = -1;
|
||||
public MainPointModule mainModule;
|
||||
PointModule[] modules = new PointModule[0];
|
||||
|
||||
protected static string[] operations = new string[] {"Point Operations", "Center to Transform", "Move Transform to", "Flat X", "Flat Y", "Flat Z", "Mirror X", "Mirror Y", "Mirror Z", "Distribute evenly", "Auto Bezier Tangents" };
|
||||
|
||||
public SplinePoint[] points = new SplinePoint[0];
|
||||
public List<int> selectedPoints = new List<int>();
|
||||
protected Vector2 lastClickPoint = Vector2.zero;
|
||||
|
||||
public Tool lastEditorTool = Tool.None;
|
||||
|
||||
float editLabelAlpha = 0f;
|
||||
Vector2 editLabelPosition = Vector2.zero;
|
||||
|
||||
public Transform transform
|
||||
{
|
||||
get { return _transform; }
|
||||
}
|
||||
|
||||
float lastEmptyClickTime = 0f;
|
||||
|
||||
protected GUIContent[] toolContents = new GUIContent[0], toolContentsSelected = new GUIContent[0];
|
||||
|
||||
protected bool pointToolsToggle = false;
|
||||
|
||||
protected Toolbar toolbar;
|
||||
protected SplineSample evalResult = new SplineSample();
|
||||
bool emptyClick = false;
|
||||
|
||||
public delegate void SplineEvaluation(double percent, SplineSample result);
|
||||
public delegate void SplinePointEvaluation(int pointIndex, SplineSample result);
|
||||
public delegate Vector3 SplineEvaluatePosition(double percent);
|
||||
public delegate float SplineCalculateLength(double from, double to);
|
||||
public delegate double SplineTravel(double start, float distance, Spline.Direction direction);
|
||||
|
||||
|
||||
public SplineEvaluation evaluate;
|
||||
public SplinePointEvaluation evaluateAtPoint;
|
||||
public SplineEvaluatePosition evaluatePosition;
|
||||
public SplineCalculateLength calculateLength;
|
||||
public SplineTravel travel;
|
||||
public EmptyHandler selectionChangeHandler;
|
||||
|
||||
public PointModule currentModule
|
||||
{
|
||||
get
|
||||
{
|
||||
if (module < 0 || module >= modules.Length) return null;
|
||||
else return modules[module];
|
||||
}
|
||||
}
|
||||
|
||||
public SplineEditor(Transform transform, string editorName) : base()
|
||||
{
|
||||
_transform = transform;
|
||||
this.editorName = editorName;
|
||||
|
||||
mainModule = new MainPointModule(this);
|
||||
mainModule.onSelectionChanged += OnSelectionChanged;
|
||||
List<PointModule> moduleList = new List<PointModule>();
|
||||
OnModuleList(moduleList);
|
||||
modules = moduleList.ToArray();
|
||||
toolContents = new GUIContent[modules.Length];
|
||||
toolContentsSelected = new GUIContent[modules.Length];
|
||||
for (int i = 0; i < modules.Length; i++)
|
||||
{
|
||||
modules[i].onSelectionChanged += OnSelectionChanged;
|
||||
toolContents[i] = modules[i].GetIconOff();
|
||||
toolContentsSelected[i] = modules[i].GetIconOn();
|
||||
}
|
||||
toolbar = new Toolbar(toolContents, toolContentsSelected, 35f);
|
||||
}
|
||||
|
||||
public override void UndoRedoPerformed()
|
||||
{
|
||||
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
if(selectedPoints[i] >= points.Length)
|
||||
{
|
||||
selectedPoints.RemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
RefreshCurrentModule();
|
||||
}
|
||||
|
||||
protected virtual void OnModuleList(List<PointModule> list)
|
||||
{
|
||||
list.Add(new CreatePointModule(this));
|
||||
list.Add(new DeletePointModule(this));
|
||||
list.Add(new PointMoveModule(this));
|
||||
list.Add(new PointRotateModule(this));
|
||||
list.Add(new PointScaleModule(this));
|
||||
list.Add(new PointNormalModule(this));
|
||||
list.Add(new PointMirrorModule(this));
|
||||
}
|
||||
|
||||
public override void Destroy()
|
||||
{
|
||||
base.Destroy();
|
||||
mainModule.Deselect();
|
||||
if (currentModule != null) currentModule.Deselect();
|
||||
if(lastEditorTool != Tool.None && Tools.current == Tool.None) Tools.current = lastEditorTool;
|
||||
}
|
||||
|
||||
void OnSelectionChanged()
|
||||
{
|
||||
RefreshCurrentModule();
|
||||
Repaint();
|
||||
if (selectionChangeHandler != null) selectionChangeHandler();
|
||||
}
|
||||
|
||||
protected override void Save()
|
||||
{
|
||||
base.Save();
|
||||
EditorPrefs.SetBool(GetSaveName("pointToolsToggle"), pointToolsToggle);
|
||||
EditorPrefs.SetInt(GetSaveName("moduleIndex"), module);
|
||||
}
|
||||
|
||||
protected override void Load()
|
||||
{
|
||||
base.Load();
|
||||
pointToolsToggle = EditorPrefs.GetBool(GetSaveName("pointToolsToggle"), false);
|
||||
loadedModuleIndex = EditorPrefs.GetInt(GetSaveName("moduleIndex"), -1);
|
||||
}
|
||||
|
||||
string GetSaveName(string valueName)
|
||||
{
|
||||
return "SplineEditor_" + editorName + "_" + valueName;
|
||||
}
|
||||
|
||||
public override void DrawInspector()
|
||||
{
|
||||
base.DrawInspector();
|
||||
DrawToolMenu();
|
||||
EditorGUILayout.Space();
|
||||
EditorGUI.BeginChangeCheck();
|
||||
if (currentModule != null) currentModule.DrawInspector();
|
||||
DreamteckEditorGUI.DrawSeparator();
|
||||
PointPanel();
|
||||
if (EditorGUI.EndChangeCheck()) RefreshCurrentModule();
|
||||
}
|
||||
|
||||
void DrawToolMenu()
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (loadedModuleIndex >= 0)
|
||||
{
|
||||
ToggleModule(loadedModuleIndex);
|
||||
loadedModuleIndex = -1;
|
||||
}
|
||||
selectModule = module;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
toolbar.Draw(ref selectModule);
|
||||
if (EditorGUI.EndChangeCheck()) ToggleModule(selectModule);
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
void PointPanel()
|
||||
{
|
||||
if (points.Length == 0)
|
||||
{
|
||||
EditorGUILayout.LabelField("No control points available.", EditorStyles.centeredGreyMiniLabel);
|
||||
return;
|
||||
}
|
||||
mainModule.DrawInspector();
|
||||
PointMenu();
|
||||
if(selectedPoints.Count > 0)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
int pointOperation = EditorGUILayout.Popup(0, operations);
|
||||
if (pointOperation > 0)
|
||||
{
|
||||
switch (pointOperation)
|
||||
{
|
||||
case 1: CenterSelection(); break;
|
||||
case 2: MoveTransformToSelection(); break;
|
||||
case 3: FlatSelection(0); break;
|
||||
case 4: FlatSelection(1); break;
|
||||
case 5: FlatSelection(2); break;
|
||||
case 6: MirrorSelection(0); break;
|
||||
case 7: MirrorSelection(1); break;
|
||||
case 8: MirrorSelection(2); break;
|
||||
case 9: DistributeEvenly(); break;
|
||||
case 10: AutoTangents(); break;
|
||||
}
|
||||
pointOperation = 0;
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void BeforeSceneGUI(SceneView current)
|
||||
{
|
||||
mainModule.BeforeSceneDraw(current);
|
||||
if (module >= 0 && module < modules.Length) modules[module].BeforeSceneDraw(current);
|
||||
}
|
||||
|
||||
public override void DrawScene()
|
||||
{
|
||||
base.DrawScene();
|
||||
Event e = Event.current;
|
||||
if (Tools.current != Tool.None)
|
||||
{
|
||||
lastEditorTool = Tools.current;
|
||||
Tools.current = Tool.None;
|
||||
}
|
||||
int controlID = GUIUtility.GetControlID(FocusType.Passive);
|
||||
if (e.GetTypeForControl(controlID) == EventType.Layout) HandleUtility.AddDefaultControl(controlID);
|
||||
|
||||
if (eventModule.mouseLeftDown) lastClickPoint = e.mousePosition;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
mainModule.DrawScene();
|
||||
if (currentModule != null)
|
||||
{
|
||||
currentModule.DrawScene();
|
||||
if (currentModule is CreatePointModule)
|
||||
{
|
||||
if (eventModule.mouseLeftDown && eventModule.mouseRight)
|
||||
{
|
||||
GUIUtility.hotControl = -1;
|
||||
ToggleModule(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(eventModule.mouseLeftDown) emptyClick = GUIUtility.hotControl == 0;
|
||||
|
||||
if (emptyClick)
|
||||
{
|
||||
if (eventModule.mouseLeft && !mainModule.isDragging && Vector2.Distance(lastClickPoint, e.mousePosition) >= mainModule.minimumRectSize && !eventModule.alt)
|
||||
{
|
||||
mainModule.StartDrag(lastClickPoint);
|
||||
emptyClick = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (eventModule.mouseLeftUp)
|
||||
{
|
||||
if (mainModule.isDragging) mainModule.FinishDrag();
|
||||
else
|
||||
{
|
||||
if (emptyClick)
|
||||
{
|
||||
if(selectedPoints.Count > 0) mainModule.ClearSelection();
|
||||
else
|
||||
{
|
||||
if (Time.realtimeSinceStartup - lastEmptyClickTime <= 0.3f) Selection.activeGameObject = null;
|
||||
else
|
||||
{
|
||||
editLabelAlpha = 1f;
|
||||
editLabelPosition = e.mousePosition;
|
||||
lastEmptyClickTime = Time.realtimeSinceStartup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!eventModule.mouseRight && !eventModule.mouseLeft && e.type == EventType.KeyDown)
|
||||
{
|
||||
switch (e.keyCode)
|
||||
{
|
||||
case KeyCode.Q:
|
||||
if (module == 0) ToggleModule(1);
|
||||
else ToggleModule(0);
|
||||
e.Use(); break;
|
||||
case KeyCode.W: ToggleModule(2); e.Use(); break;
|
||||
case KeyCode.E: ToggleModule(3); e.Use(); break;
|
||||
case KeyCode.R: ToggleModule(4); e.Use(); break;
|
||||
case KeyCode.T: ToggleModule(5); e.Use(); break;
|
||||
case KeyCode.Y: ToggleModule(6); e.Use(); break;
|
||||
}
|
||||
}
|
||||
|
||||
if(editLabelAlpha > 0f)
|
||||
{
|
||||
Handles.BeginGUI();
|
||||
GUI.contentColor = new Color(1f, 1f, 1f, editLabelAlpha);
|
||||
DreamteckEditorGUI.Label(new Rect(editLabelPosition, new Vector2(140, 50)), "Click Again To Exit");
|
||||
Handles.EndGUI();
|
||||
editLabelAlpha = Mathf.MoveTowards(editLabelAlpha, 0f, Time.deltaTime * 0.3f);
|
||||
Repaint();
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleModule(int index)
|
||||
{
|
||||
Tools.current = Tool.None;
|
||||
if (currentModule != null) currentModule.Deselect();
|
||||
if (index == module) module = -1;
|
||||
else
|
||||
{
|
||||
module = index;
|
||||
RefreshCurrentModule();
|
||||
currentModule.Select();
|
||||
}
|
||||
Repaint();
|
||||
}
|
||||
|
||||
public void UntoggleCurrentModule()
|
||||
{
|
||||
if (currentModule != null) currentModule.Deselect();
|
||||
module = -1;
|
||||
Repaint();
|
||||
}
|
||||
|
||||
|
||||
void PointMenu()
|
||||
{
|
||||
if (selectedPoints.Count == 0 || points.Length == 0) return;
|
||||
//Otherwise show the editing menu + the point selection menu
|
||||
Vector3 avgPos = Vector3.zero;
|
||||
Vector3 avgTan = Vector3.zero;
|
||||
Vector3 avgTan2 = Vector3.zero;
|
||||
Vector3 avgNormal = Vector3.zero;
|
||||
float avgSize = 0f;
|
||||
Color avgColor = Color.clear;
|
||||
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
avgPos += points[selectedPoints[i]].position;
|
||||
avgNormal += points[selectedPoints[i]].normal;
|
||||
avgSize += points[selectedPoints[i]].size;
|
||||
avgTan += points[selectedPoints[i]].tangent;
|
||||
avgTan2 += points[selectedPoints[i]].tangent2;
|
||||
avgColor += points[selectedPoints[i]].color;
|
||||
}
|
||||
|
||||
avgPos /= selectedPoints.Count;
|
||||
avgTan /= selectedPoints.Count;
|
||||
avgTan2 /= selectedPoints.Count;
|
||||
avgSize /= selectedPoints.Count;
|
||||
avgColor /= selectedPoints.Count;
|
||||
avgNormal.Normalize();
|
||||
|
||||
SplinePoint avgPoint = new SplinePoint(avgPos, avgPos);
|
||||
avgPoint.tangent = avgTan;
|
||||
avgPoint.tangent2 = avgTan2;
|
||||
avgPoint.size = avgSize;
|
||||
avgPoint.color = avgColor;
|
||||
avgPoint.type = points[selectedPoints[0]].type;
|
||||
SplinePoint.Type lastType = avgPoint.type;
|
||||
|
||||
avgPoint.normal = avgNormal;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
SplineComputer.Space lastSpace = SplinePrefs.pointEditSpace;
|
||||
SplinePrefs.pointEditSpace = (SplineComputer.Space)EditorGUILayout.EnumPopup("Edit Space", SplinePrefs.pointEditSpace);
|
||||
if (lastSpace != SplinePrefs.pointEditSpace) SplinePrefs.SavePrefs();
|
||||
if (splineType == Spline.Type.Bezier)
|
||||
{
|
||||
if (is2D)
|
||||
{
|
||||
avgPoint.SetTangentPosition(TransformedPositionField2D("Tangent 1", avgPoint.tangent));
|
||||
avgPoint.SetTangent2Position(TransformedPositionField2D("Tangent 2", avgPoint.tangent2));
|
||||
}
|
||||
else
|
||||
{
|
||||
avgPoint.SetTangentPosition(TransformedPositionField("Tangent 1", avgPoint.tangent));
|
||||
avgPoint.SetTangent2Position(TransformedPositionField("Tangent 2", avgPoint.tangent2));
|
||||
}
|
||||
}
|
||||
if (is2D) avgPoint.SetPosition(TransformedPositionField2D("Position", avgPoint.position));
|
||||
else avgPoint.SetPosition(TransformedPositionField("Position", avgPoint.position));
|
||||
if (!is2D)
|
||||
{
|
||||
if (SplinePrefs.pointEditSpace == SplineComputer.Space.Local) avgPoint.normal = _transform.InverseTransformDirection(avgPoint.normal);
|
||||
avgPoint.normal = TransformedPositionField("Normal", avgPoint.normal);
|
||||
if (SplinePrefs.pointEditSpace == SplineComputer.Space.Local) avgPoint.normal = _transform.TransformDirection(avgPoint.normal);
|
||||
}
|
||||
avgPoint.size = EditorGUILayout.FloatField("Size", avgPoint.size);
|
||||
avgPoint.color = EditorGUILayout.ColorField("Color", avgPoint.color);
|
||||
if (splineType == Spline.Type.Bezier) avgPoint.type = (SplinePoint.Type)EditorGUILayout.EnumPopup("Point Type", avgPoint.type);
|
||||
|
||||
if (!EditorGUI.EndChangeCheck()) return;
|
||||
RecordUndo("Edit Points");
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
points[selectedPoints[i]].SetPosition(GetChangedVector(avgPos, avgPoint.position, points[selectedPoints[i]].position));
|
||||
points[selectedPoints[i]].normal = GetChangedVector(avgNormal, avgPoint.normal, points[selectedPoints[i]].normal);
|
||||
|
||||
if (splineType == Spline.Type.Bezier)
|
||||
{
|
||||
points[selectedPoints[i]].SetTangentPosition(GetChangedVector(avgTan, avgPoint.tangent, points[selectedPoints[i]].tangent));
|
||||
points[selectedPoints[i]].SetTangent2Position(GetChangedVector(avgTan2, avgPoint.tangent2, points[selectedPoints[i]].tangent2));
|
||||
}
|
||||
if (avgPoint.size != avgSize) points[selectedPoints[i]].size = avgPoint.size;
|
||||
if (avgColor != avgPoint.color) points[selectedPoints[i]].color = avgPoint.color;
|
||||
if (lastType != avgPoint.type) points[selectedPoints[i]].type = avgPoint.type;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 GetChangedVector(Vector3 oldVector, Vector3 newVector, Vector3 original)
|
||||
{
|
||||
if (!Mathf.Approximately(oldVector.x, newVector.x)) original.x = newVector.x;
|
||||
if (!Mathf.Approximately(oldVector.y, newVector.y)) original.y = newVector.y;
|
||||
if (!Mathf.Approximately(oldVector.z, newVector.z)) original.z = newVector.z;
|
||||
return original;
|
||||
}
|
||||
|
||||
Vector3 TransformedPositionField(string title, Vector3 worldPoint)
|
||||
{
|
||||
Vector3 pos = worldPoint;
|
||||
if (SplinePrefs.pointEditSpace == SplineComputer.Space.Local) pos = _transform.InverseTransformPoint(worldPoint);
|
||||
pos = EditorGUILayout.Vector3Field(title, pos);
|
||||
if (SplinePrefs.pointEditSpace == SplineComputer.Space.Local) pos = _transform.TransformPoint(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
Vector2 TransformedPositionField2D(string title, Vector3 worldPoint)
|
||||
{
|
||||
Vector2 pos = worldPoint;
|
||||
if (SplinePrefs.pointEditSpace == SplineComputer.Space.Local) pos = _transform.InverseTransformPoint(worldPoint);
|
||||
pos = EditorGUILayout.Vector2Field(title, pos);
|
||||
if (SplinePrefs.pointEditSpace == SplineComputer.Space.Local) pos = _transform.TransformPoint(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
public void CenterSelection()
|
||||
{
|
||||
RecordUndo("Center Selection");
|
||||
Vector3 avg = Vector3.zero;
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
avg += points[selectedPoints[i]].position;
|
||||
}
|
||||
avg /= selectedPoints.Count;
|
||||
Vector3 delta = _transform.position - avg;
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
points[selectedPoints[i]].SetPosition(points[selectedPoints[i]].position + delta);
|
||||
}
|
||||
RefreshCurrentModule();
|
||||
}
|
||||
|
||||
public void MoveTransformToSelection()
|
||||
{
|
||||
RecordUndo("Move Transform To Selection");
|
||||
Vector3 avg = Vector3.zero;
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
avg += points[selectedPoints[i]].position;
|
||||
}
|
||||
avg /= selectedPoints.Count;
|
||||
_transform.position = avg;
|
||||
RefreshCurrentModule();
|
||||
}
|
||||
|
||||
public void FlatSelection(int axis)
|
||||
{
|
||||
Vector3 avg = Vector3.zero;
|
||||
bool flatTangent = false;
|
||||
bool flatPosition = true;
|
||||
if (splineType == Spline.Type.Bezier)
|
||||
{
|
||||
switch (EditorUtility.DisplayDialogComplex("Flat Bezier", "How do you want to flat the selected Bezier points?", "Points Only", "Tangens Only", "Everything"))
|
||||
{
|
||||
case 0: flatTangent = false; flatPosition = true; break;
|
||||
case 1: flatTangent = true; flatPosition = false; break;
|
||||
case 2: flatTangent = true; flatPosition = true; break;
|
||||
}
|
||||
}
|
||||
RecordUndo("Flat Selection");
|
||||
if (flatPosition)
|
||||
{
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
avg += points[selectedPoints[i]].position;
|
||||
}
|
||||
avg /= selectedPoints.Count;
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
Vector3 pos = points[selectedPoints[i]].position;
|
||||
switch (axis)
|
||||
{
|
||||
case 0: pos.x = avg.x; points[selectedPoints[i]].normal.x = 0f; break;
|
||||
case 1: pos.y = avg.y; points[selectedPoints[i]].normal.y = 0f; break;
|
||||
case 2: pos.z = avg.z; points[selectedPoints[i]].normal.z = 0f; break;
|
||||
}
|
||||
points[selectedPoints[i]].normal.Normalize();
|
||||
if (points[selectedPoints[i]].normal == Vector3.zero) points[selectedPoints[i]].normal = Vector3.up;
|
||||
points[selectedPoints[i]].SetPosition(pos);
|
||||
if (flatTangent)
|
||||
{
|
||||
Vector3 tan = points[selectedPoints[i]].tangent;
|
||||
Vector3 tan2 = points[selectedPoints[i]].tangent2;
|
||||
switch (axis)
|
||||
{
|
||||
case 0: tan.x = avg.x; tan2.x = avg.x; break;
|
||||
case 1: tan.y = avg.y; tan2.y = avg.y; break;
|
||||
case 2: tan.z = avg.z; tan2.z = avg.z; break;
|
||||
}
|
||||
points[selectedPoints[i]].SetTangentPosition(tan);
|
||||
points[selectedPoints[i]].SetTangent2Position(tan2);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
Vector3 tan = points[selectedPoints[i]].tangent;
|
||||
Vector3 tan2 = points[selectedPoints[i]].tangent2;
|
||||
Vector3 pos = points[selectedPoints[i]].position;
|
||||
switch (axis)
|
||||
{
|
||||
case 0: tan.x = pos.x; tan2.x = pos.x; break;
|
||||
case 1: tan.y = pos.y; tan2.y = pos.y; break;
|
||||
case 2: tan.z = pos.z; tan2.z = pos.z; break;
|
||||
}
|
||||
points[selectedPoints[i]].SetTangentPosition(tan);
|
||||
points[selectedPoints[i]].SetTangent2Position(tan2);
|
||||
}
|
||||
}
|
||||
RefreshCurrentModule();
|
||||
}
|
||||
|
||||
public void MirrorSelection(int axis)
|
||||
{
|
||||
bool mirrorTangents = false;
|
||||
if (splineType == Spline.Type.Bezier)
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("Mirror tangents", "Do you want to mirror the tangents too ?", "Yes", "No")) mirrorTangents = true;
|
||||
}
|
||||
float min = 0f, max = 0f;
|
||||
switch (axis)
|
||||
{
|
||||
case 0: min = max = points[selectedPoints[0]].position.x; break;
|
||||
case 1: min = max = points[selectedPoints[0]].position.y; break;
|
||||
case 2: min = max = points[selectedPoints[0]].position.z; break;
|
||||
}
|
||||
RecordUndo("Mirror Selection");
|
||||
if (mirrorTangents)
|
||||
{
|
||||
float value = 0f;
|
||||
switch (axis)
|
||||
{
|
||||
case 0: value = points[selectedPoints[0]].tangent.x; break;
|
||||
case 1: value = points[selectedPoints[0]].tangent.y; break;
|
||||
case 2: value = points[selectedPoints[0]].tangent.z; break;
|
||||
}
|
||||
if (value < min) min = value;
|
||||
if (value > max) max = value;
|
||||
switch (axis)
|
||||
{
|
||||
case 0: value = points[selectedPoints[0]].tangent2.x; break;
|
||||
case 1: value = points[selectedPoints[0]].tangent2.y; break;
|
||||
case 2: value = points[selectedPoints[0]].tangent2.z; break;
|
||||
}
|
||||
if (value < min) min = value;
|
||||
if (value > max) max = value;
|
||||
}
|
||||
for (int i = 1; i < selectedPoints.Count; i++)
|
||||
{
|
||||
float value = 0f;
|
||||
switch (axis)
|
||||
{
|
||||
case 0: value = points[selectedPoints[i]].position.x; break;
|
||||
case 1: value = points[selectedPoints[i]].position.y; break;
|
||||
case 2: value = points[selectedPoints[i]].position.z; break;
|
||||
}
|
||||
if (value < min) min = value;
|
||||
if (value > max) max = value;
|
||||
if (mirrorTangents)
|
||||
{
|
||||
switch (axis)
|
||||
{
|
||||
case 0: value = points[selectedPoints[i]].tangent.x; break;
|
||||
case 1: value = points[selectedPoints[i]].tangent.y; break;
|
||||
case 2: value = points[selectedPoints[i]].tangent.z; break;
|
||||
}
|
||||
if (value < min) min = value;
|
||||
if (value > max) max = value;
|
||||
switch (axis)
|
||||
{
|
||||
case 0: value = points[selectedPoints[i]].tangent2.x; break;
|
||||
case 1: value = points[selectedPoints[i]].tangent2.y; break;
|
||||
case 2: value = points[selectedPoints[i]].tangent2.z; break;
|
||||
}
|
||||
if (value < min) min = value;
|
||||
if (value > max) max = value;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
float value = 0f;
|
||||
if (mirrorTangents)
|
||||
{
|
||||
//Point position
|
||||
switch (axis)
|
||||
{
|
||||
case 0: value = points[selectedPoints[i]].position.x; break;
|
||||
case 1: value = points[selectedPoints[i]].position.y; break;
|
||||
case 2: value = points[selectedPoints[i]].position.z; break;
|
||||
}
|
||||
float percent = Mathf.InverseLerp(min, max, value);
|
||||
value = Mathf.Lerp(max, min, percent);
|
||||
switch (axis)
|
||||
{
|
||||
case 0: points[selectedPoints[i]].position.x = value; break;
|
||||
case 1: points[selectedPoints[i]].position.y = value; break;
|
||||
case 2: points[selectedPoints[i]].position.z = value; break;
|
||||
}
|
||||
//Tangent 1
|
||||
switch (axis)
|
||||
{
|
||||
case 0: value = points[selectedPoints[i]].tangent.x; break;
|
||||
case 1: value = points[selectedPoints[i]].tangent.y; break;
|
||||
case 2: value = points[selectedPoints[i]].tangent.z; break;
|
||||
}
|
||||
percent = Mathf.InverseLerp(min, max, value);
|
||||
value = Mathf.Lerp(max, min, percent);
|
||||
switch (axis)
|
||||
{
|
||||
case 0: points[selectedPoints[i]].tangent.x = value; break;
|
||||
case 1: points[selectedPoints[i]].tangent.y = value; break;
|
||||
case 2: points[selectedPoints[i]].tangent.z = value; break;
|
||||
}
|
||||
//Tangent 2
|
||||
switch (axis)
|
||||
{
|
||||
case 0: value = points[selectedPoints[i]].tangent2.x; break;
|
||||
case 1: value = points[selectedPoints[i]].tangent2.y; break;
|
||||
case 2: value = points[selectedPoints[i]].tangent2.z; break;
|
||||
}
|
||||
percent = Mathf.InverseLerp(min, max, value);
|
||||
value = Mathf.Lerp(max, min, percent);
|
||||
switch (axis)
|
||||
{
|
||||
case 0: points[selectedPoints[i]].tangent2.x = value; break;
|
||||
case 1: points[selectedPoints[i]].tangent2.y = value; break;
|
||||
case 2: points[selectedPoints[i]].tangent2.z = value; break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 pos = points[selectedPoints[i]].position;
|
||||
switch (axis)
|
||||
{
|
||||
case 0: value = pos.x; break;
|
||||
case 1: value = pos.y; break;
|
||||
case 2: value = pos.z; break;
|
||||
}
|
||||
float percent = Mathf.InverseLerp(min, max, value);
|
||||
value = Mathf.Lerp(max, min, percent);
|
||||
switch (axis)
|
||||
{
|
||||
case 0: pos.x = value; break;
|
||||
case 1: pos.y = value; break;
|
||||
case 2: pos.z = value; break;
|
||||
}
|
||||
points[selectedPoints[i]].SetPosition(pos);
|
||||
}
|
||||
//Normal
|
||||
switch (axis)
|
||||
{
|
||||
case 0: points[selectedPoints[i]].normal.x *= -1f; break;
|
||||
case 1: points[selectedPoints[i]].normal.y *= -1f; break;
|
||||
case 2: points[selectedPoints[i]].normal.z *= -1f; break;
|
||||
}
|
||||
points[selectedPoints[i]].normal.Normalize();
|
||||
}
|
||||
RefreshCurrentModule();
|
||||
}
|
||||
|
||||
public void DistributeEvenly()
|
||||
{
|
||||
if (selectedPoints.Count < 3) return;
|
||||
RecordUndo("Distribute Evenly");
|
||||
int min = points.Length-1, max = 0;
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
if (selectedPoints[i] < min) min = selectedPoints[i];
|
||||
if (selectedPoints[i] > max) max = selectedPoints[i];
|
||||
}
|
||||
double minPercent = (double)min / (points.Length - 1);
|
||||
double maxPercent = (double)max / (points.Length - 1);
|
||||
float length = calculateLength(minPercent, maxPercent);
|
||||
float step = length / (max - min);
|
||||
SplineSample evalResult = new SplineSample();
|
||||
evaluate(minPercent, evalResult);
|
||||
for (int i = min + 1; i < max; i++)
|
||||
{
|
||||
double percent = travel(evalResult.percent, step, Spline.Direction.Forward);
|
||||
evaluate(percent, evalResult);
|
||||
points[i].SetPosition(evalResult.position);
|
||||
}
|
||||
RefreshCurrentModule();
|
||||
}
|
||||
|
||||
public void AutoTangents()
|
||||
{
|
||||
RecordUndo("Auto Tangents");
|
||||
for (int i = 0; i < selectedPoints.Count; i++)
|
||||
{
|
||||
int index = selectedPoints[i];
|
||||
Vector3 prevPos = points[index].position, forwardPos = points[index].position;
|
||||
if(index == 0 && points.Length > 1)
|
||||
{
|
||||
prevPos = points[0].position + (points[0].position - points[1].position);
|
||||
} else prevPos = points[index - 1].position;
|
||||
if (index == points.Length-1 && points.Length > 1)
|
||||
{
|
||||
forwardPos = points[points.Length-1].position + (points[points.Length - 1].position - points[points.Length - 2].position);
|
||||
}
|
||||
else forwardPos = points[index + 1].position;
|
||||
Vector3 delta = (forwardPos - prevPos) / 2f;
|
||||
points[index].tangent = points[index].position - delta / 3f;
|
||||
points[index].tangent2 = points[index].position + delta / 3f;
|
||||
}
|
||||
RefreshCurrentModule();
|
||||
}
|
||||
|
||||
void RefreshCurrentModule()
|
||||
{
|
||||
if (module < 0 || module >= modules.Length) return;
|
||||
modules[module].Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb86255f2f032e04297cae0b6fde161f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
105
Assets/Dreamteck/Splines/Editor/SplineEditor/SplineEditorBase.cs
Normal file
105
Assets/Dreamteck/Splines/Editor/SplineEditor/SplineEditorBase.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
namespace Dreamteck.Splines.Editor
|
||||
{
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
public class SplineEditorBase
|
||||
{
|
||||
public bool open = false;
|
||||
public EditorGUIEvents eventModule = null;
|
||||
|
||||
public delegate void UndoHandler(string title);
|
||||
public delegate void EmptyHandler();
|
||||
|
||||
public UndoHandler undoHandler;
|
||||
public EmptyHandler repaintHandler;
|
||||
|
||||
public SplineEditorBase()
|
||||
{
|
||||
Load();
|
||||
eventModule = new EditorGUIEvents();
|
||||
}
|
||||
|
||||
public virtual void Destroy()
|
||||
{
|
||||
Save();
|
||||
}
|
||||
|
||||
protected virtual void Load()
|
||||
{
|
||||
open = LoadBool("open");
|
||||
}
|
||||
|
||||
protected virtual void Save()
|
||||
{
|
||||
SaveBool("open", open);
|
||||
}
|
||||
|
||||
public virtual void DrawInspector()
|
||||
{
|
||||
eventModule.Update(Event.current);
|
||||
}
|
||||
|
||||
public virtual void DrawScene()
|
||||
{
|
||||
eventModule.Update(Event.current);
|
||||
}
|
||||
|
||||
protected virtual void RecordUndo(string title)
|
||||
{
|
||||
if (undoHandler != null) undoHandler(title);
|
||||
}
|
||||
|
||||
protected virtual void Repaint()
|
||||
{
|
||||
if (repaintHandler != null) repaintHandler();
|
||||
}
|
||||
|
||||
public virtual void UndoRedoPerformed()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected void SaveBool(string variableName, bool value)
|
||||
{
|
||||
EditorPrefs.SetBool(GetType().ToString() + "." + variableName, value);
|
||||
}
|
||||
|
||||
protected void SaveInt(string variableName, int value)
|
||||
{
|
||||
EditorPrefs.SetInt(GetType().ToString() + "." + variableName, value);
|
||||
}
|
||||
|
||||
protected void SaveFloat(string variableName, float value)
|
||||
{
|
||||
EditorPrefs.SetFloat(GetType().ToString() + "." + variableName, value);
|
||||
}
|
||||
|
||||
protected void SaveString(string variableName, string value)
|
||||
{
|
||||
EditorPrefs.SetString(GetType().ToString() + "." + variableName, value);
|
||||
}
|
||||
|
||||
protected bool LoadBool(string variableName, bool defaultValue = false)
|
||||
{
|
||||
return EditorPrefs.GetBool(GetType().ToString() + "." + variableName, defaultValue);
|
||||
}
|
||||
|
||||
protected int LoadInt(string variableName, int defaultValue = 0)
|
||||
{
|
||||
return EditorPrefs.GetInt(GetType().ToString() + "." + variableName, defaultValue);
|
||||
}
|
||||
|
||||
protected float LoadFloat(string variableName, float d = 0f)
|
||||
{
|
||||
return EditorPrefs.GetFloat(GetType().ToString() + "." + variableName, d);
|
||||
}
|
||||
|
||||
protected string LoadString(string variableName)
|
||||
{
|
||||
return EditorPrefs.GetString(GetType().ToString() + "." + variableName, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc43fa09ec92d7b4996069786c06b474
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user