421 lines
16 KiB
C#
421 lines
16 KiB
C#
|
namespace Dreamteck.Splines.Editor
|
||
|
{
|
||
|
using UnityEngine;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using UnityEditor;
|
||
|
|
||
|
[CustomEditor(typeof(SplineUser), true)]
|
||
|
[CanEditMultipleObjects]
|
||
|
public class SplineUserEditor : Editor
|
||
|
{
|
||
|
protected bool showClip = true;
|
||
|
protected bool showAveraging = true;
|
||
|
protected bool showUpdateMethod = true;
|
||
|
protected bool showMultithreading = true;
|
||
|
private bool settingsFoldout = false;
|
||
|
protected RotationModifierEditor rotationModifierEditor;
|
||
|
protected OffsetModifierEditor offsetModifierEditor;
|
||
|
protected ColorModifierEditor colorModifierEditor;
|
||
|
protected SizeModifierEditor sizeModifierEditor;
|
||
|
protected SplineUser[] users = new SplineUser[0];
|
||
|
SerializedProperty multithreadedProperty, updateMethodProperty, buildOnAwakeProperty, buildOnEnableProperty, autoUpdateProperty, loopSamplesProperty, clipFromProperty, clipToProperty;
|
||
|
protected GUIStyle foldoutHeaderStyle;
|
||
|
|
||
|
bool doRebuild = false;
|
||
|
protected SerializedProperty spline;
|
||
|
|
||
|
public int editIndex
|
||
|
{
|
||
|
get { return _editIndex; }
|
||
|
set
|
||
|
{
|
||
|
if(value == 0)
|
||
|
{
|
||
|
Debug.LogError("Cannot set edit index to 0. 0 is reserved.");
|
||
|
return;
|
||
|
}
|
||
|
if (value < -1) value = -1;
|
||
|
_editIndex = value;
|
||
|
}
|
||
|
}
|
||
|
private int _editIndex = -1; //0 is reserved for editing clip values
|
||
|
|
||
|
protected GUIContent editButtonContent = new GUIContent("Edit", "Enable edit mode in scene view");
|
||
|
|
||
|
protected virtual void HeaderGUI()
|
||
|
{
|
||
|
SplineUser user = (SplineUser)target;
|
||
|
Undo.RecordObject(user, "Inspector Change");
|
||
|
SplineComputer lastSpline = (SplineComputer)spline.objectReferenceValue;
|
||
|
EditorGUILayout.PropertyField(spline);
|
||
|
SplineComputer newSpline = (SplineComputer)spline.objectReferenceValue;
|
||
|
if (lastSpline != (SplineComputer)spline.objectReferenceValue)
|
||
|
{
|
||
|
for (int i = 0; i < users.Length; i++)
|
||
|
{
|
||
|
if (lastSpline != null) lastSpline.Unsubscribe(users[i]);
|
||
|
if (newSpline != null) newSpline.Subscribe(users[i]);
|
||
|
}
|
||
|
user.Rebuild();
|
||
|
}
|
||
|
|
||
|
|
||
|
if (user.spline == null) EditorGUILayout.HelpBox("No SplineComputer is referenced. Link a SplineComputer to make this SplineUser work.", MessageType.Error);
|
||
|
|
||
|
settingsFoldout = EditorGUILayout.Foldout(settingsFoldout, "User Configuration", foldoutHeaderStyle);
|
||
|
if (settingsFoldout)
|
||
|
{
|
||
|
EditorGUI.indentLevel++;
|
||
|
if (showClip) InspectorClipEdit();
|
||
|
if (showUpdateMethod) EditorGUILayout.PropertyField(updateMethodProperty);
|
||
|
EditorGUILayout.PropertyField(autoUpdateProperty, new GUIContent("Auto Rebuild"));
|
||
|
if (showMultithreading) EditorGUILayout.PropertyField(multithreadedProperty);
|
||
|
EditorGUILayout.PropertyField(buildOnAwakeProperty);
|
||
|
EditorGUILayout.PropertyField(buildOnEnableProperty);
|
||
|
EditorGUI.indentLevel--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void InspectorClipEdit()
|
||
|
{
|
||
|
bool isClosed = true;
|
||
|
bool loopSamples = true;
|
||
|
for (int i = 0; i < users.Length; i++)
|
||
|
{
|
||
|
if (users[i].spline == null) isClosed = false;
|
||
|
else if (!users[i].spline.isClosed) isClosed = false;
|
||
|
else if (!users[i].loopSamples) loopSamples = false;
|
||
|
}
|
||
|
|
||
|
float clipFrom = clipFromProperty.floatValue;
|
||
|
float clipTo = clipToProperty.floatValue;
|
||
|
|
||
|
if (isClosed && loopSamples)
|
||
|
{
|
||
|
EditorGUILayout.BeginHorizontal();
|
||
|
if (EditButton(_editIndex == 0))
|
||
|
{
|
||
|
if (_editIndex == 0) _editIndex = -1;
|
||
|
else _editIndex = 0;
|
||
|
}
|
||
|
EditorGUILayout.BeginVertical();
|
||
|
clipFrom = EditorGUILayout.Slider("Clip From", clipFrom, 0f, 1f);
|
||
|
clipTo = EditorGUILayout.Slider("Clip To", clipTo, 0f, 1f);
|
||
|
EditorGUILayout.EndVertical();
|
||
|
EditorGUILayout.EndHorizontal();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
EditorGUILayout.BeginHorizontal();
|
||
|
EditorGUILayout.BeginHorizontal();
|
||
|
if (EditButton(_editIndex == 0))
|
||
|
{
|
||
|
if (_editIndex == 0) _editIndex = -1;
|
||
|
else _editIndex = 0;
|
||
|
}
|
||
|
if (GUILayout.Button("Set Distance", GUILayout.Width(85)))
|
||
|
{
|
||
|
ClipRangeWindow w = EditorWindow.GetWindow<ClipRangeWindow>(true);
|
||
|
float length = 0f;
|
||
|
if(users.Length == 1)
|
||
|
{
|
||
|
length = users[0].spline.CalculateLength();
|
||
|
}
|
||
|
float fromDist = 0f;
|
||
|
float toDist = 0f;
|
||
|
int divide = 0;
|
||
|
for (int i = 0; i < users.Length; i++)
|
||
|
{
|
||
|
if(users[i].spline != null)
|
||
|
{
|
||
|
fromDist += users[i].spline.CalculateLength(0.0, users[i].clipFrom);
|
||
|
toDist += users[i].spline.CalculateLength(0.0, users[i].clipTo);
|
||
|
divide++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(divide > 0)
|
||
|
{
|
||
|
fromDist /= divide;
|
||
|
toDist /= divide;
|
||
|
}
|
||
|
w.Init(OnSetClipRangeDistance, fromDist, toDist, length);
|
||
|
|
||
|
}
|
||
|
EditorGUIUtility.labelWidth = 80f;
|
||
|
EditorGUILayout.MinMaxSlider(new GUIContent("Clip Range "), ref clipFrom, ref clipTo, 0f, 1f);
|
||
|
EditorGUIUtility.labelWidth = 0f;
|
||
|
EditorGUILayout.EndHorizontal();
|
||
|
EditorGUILayout.BeginHorizontal(GUILayout.MaxWidth(30));
|
||
|
clipFrom = EditorGUILayout.FloatField(clipFrom);
|
||
|
clipTo = EditorGUILayout.FloatField(clipTo);
|
||
|
EditorGUILayout.EndHorizontal();
|
||
|
EditorGUILayout.EndHorizontal();
|
||
|
|
||
|
}
|
||
|
clipFromProperty.floatValue = clipFrom;
|
||
|
clipToProperty.floatValue = clipTo;
|
||
|
SplineComputerEditor.hold = _editIndex >= 0;
|
||
|
|
||
|
if (isClosed) EditorGUILayout.PropertyField(loopSamplesProperty, new GUIContent("Loop Samples"));
|
||
|
if (!loopSamplesProperty.boolValue || !isClosed)
|
||
|
{
|
||
|
if (clipFromProperty.floatValue > clipToProperty.floatValue)
|
||
|
{
|
||
|
float temp = clipToProperty.floatValue;
|
||
|
clipToProperty.floatValue = clipFromProperty.floatValue;
|
||
|
clipFromProperty.floatValue = temp;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void OnSetClipRangeDistance(float from, float to)
|
||
|
{
|
||
|
int longest = 0;
|
||
|
float max = 0f;
|
||
|
for (int i = 0; i < users.Length; i++)
|
||
|
{
|
||
|
if (users[i].spline == null) continue;
|
||
|
float length = users[i].CalculateLength();
|
||
|
if(length > max)
|
||
|
{
|
||
|
max = length;
|
||
|
longest = i;
|
||
|
}
|
||
|
}
|
||
|
clipFromProperty = serializedObject.FindProperty("_clipFrom");
|
||
|
clipToProperty = serializedObject.FindProperty("_clipTo");
|
||
|
serializedObject.Update();
|
||
|
clipFromProperty.floatValue = (float)users[longest].spline.Travel(0.0, from);
|
||
|
clipToProperty.floatValue = (float)users[longest].spline.Travel(0.0, to);
|
||
|
|
||
|
serializedObject.ApplyModifiedProperties();
|
||
|
|
||
|
for (int i = 0; i < users.Length; i++)
|
||
|
{
|
||
|
if (users[i].spline == null) continue;
|
||
|
users[i].clipFrom = clipFromProperty.floatValue;
|
||
|
users[i].clipTo = clipToProperty.floatValue;
|
||
|
users[i].RebuildImmediate();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected virtual void BodyGUI()
|
||
|
{
|
||
|
EditorGUILayout.Space();
|
||
|
}
|
||
|
|
||
|
protected virtual void FooterGUI()
|
||
|
{
|
||
|
EditorGUILayout.Space();
|
||
|
EditorGUILayout.LabelField("Sample Modifiers", EditorStyles.boldLabel);
|
||
|
if (users.Length == 1)
|
||
|
{
|
||
|
if (offsetModifierEditor != null) offsetModifierEditor.DrawInspector();
|
||
|
if (rotationModifierEditor != null) rotationModifierEditor.DrawInspector();
|
||
|
if (colorModifierEditor != null) colorModifierEditor.DrawInspector();
|
||
|
if (sizeModifierEditor != null) sizeModifierEditor.DrawInspector();
|
||
|
}
|
||
|
else EditorGUILayout.LabelField("Modifiers not available when multiple Spline Users are selected.", EditorStyles.centeredGreyMiniLabel);
|
||
|
|
||
|
EditorGUILayout.Space();
|
||
|
}
|
||
|
|
||
|
protected virtual void DuringSceneGUI(SceneView currentSceneView)
|
||
|
{
|
||
|
if (doRebuild)
|
||
|
{
|
||
|
DoRebuild();
|
||
|
}
|
||
|
SplineUser user = (SplineUser)target;
|
||
|
if (user == null) return;
|
||
|
if (user.spline != null)
|
||
|
{
|
||
|
SplineComputer rootComputer = user.GetComponent<SplineComputer>();
|
||
|
List<SplineComputer> allComputers = user.spline.GetConnectedComputers();
|
||
|
for (int i = 0; i < allComputers.Count; i++)
|
||
|
{
|
||
|
if (allComputers[i] == rootComputer && _editIndex == -1) continue;
|
||
|
if (allComputers[i].editorAlwaysDraw) continue;
|
||
|
DSSplineDrawer.DrawSplineComputer(allComputers[i], 0.0, 1.0, 0.4f);
|
||
|
}
|
||
|
DSSplineDrawer.DrawSplineComputer(user.spline);
|
||
|
}
|
||
|
if (_editIndex == 0) SceneClipEdit();
|
||
|
if (offsetModifierEditor != null) offsetModifierEditor.DrawScene();
|
||
|
if (rotationModifierEditor != null) rotationModifierEditor.DrawScene();
|
||
|
if (colorModifierEditor != null) colorModifierEditor.DrawScene();
|
||
|
if (sizeModifierEditor != null) sizeModifierEditor.DrawScene();
|
||
|
}
|
||
|
|
||
|
void SceneClipEdit()
|
||
|
{
|
||
|
if (users.Length > 1) return;
|
||
|
SplineUser user = (SplineUser)target;
|
||
|
if (user.spline == null) return;
|
||
|
Color col = user.spline.editorPathColor;
|
||
|
Undo.RecordObject(user, "Edit Clip Range");
|
||
|
double val = user.clipFrom;
|
||
|
SplineComputerEditorHandles.Slider(user.spline, ref val, col, "Clip From", SplineComputerEditorHandles.SplineSliderGizmo.ForwardTriangle);
|
||
|
if (val != user.clipFrom) user.clipFrom = val;
|
||
|
val = user.clipTo;
|
||
|
SplineComputerEditorHandles.Slider(user.spline, ref val, col, "Clip To", SplineComputerEditorHandles.SplineSliderGizmo.BackwardTriangle);
|
||
|
if (val != user.clipTo) user.clipTo = val;
|
||
|
}
|
||
|
|
||
|
public override void OnInspectorGUI()
|
||
|
{
|
||
|
base.OnInspectorGUI();
|
||
|
if (doRebuild) DoRebuild();
|
||
|
serializedObject.Update();
|
||
|
|
||
|
EditorGUI.BeginChangeCheck();
|
||
|
HeaderGUI();
|
||
|
if (EditorGUI.EndChangeCheck())
|
||
|
{
|
||
|
ApplyAndRebuild();
|
||
|
}
|
||
|
|
||
|
EditorGUI.BeginChangeCheck();
|
||
|
BodyGUI();
|
||
|
if (EditorGUI.EndChangeCheck())
|
||
|
{
|
||
|
ApplyAndRebuild();
|
||
|
}
|
||
|
|
||
|
EditorGUI.BeginChangeCheck();
|
||
|
FooterGUI();
|
||
|
if (EditorGUI.EndChangeCheck())
|
||
|
{
|
||
|
ApplyAndRebuild();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void ApplyAndRebuild()
|
||
|
{
|
||
|
serializedObject.ApplyModifiedProperties();
|
||
|
DoRebuild();
|
||
|
}
|
||
|
|
||
|
private void DoRebuild()
|
||
|
{
|
||
|
for (int i = 0; i < users.Length; i++)
|
||
|
{
|
||
|
if (users[i] && users[i].isActiveAndEnabled)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
users[i].Rebuild();
|
||
|
}
|
||
|
catch (System.Exception ex)
|
||
|
{
|
||
|
Debug.Log(ex.Message);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
doRebuild = false;
|
||
|
}
|
||
|
|
||
|
protected virtual void OnDestroy()
|
||
|
{
|
||
|
if (Application.isEditor && !Application.isPlaying)
|
||
|
{
|
||
|
if (target == null)
|
||
|
{
|
||
|
OnDelete(); //The object or the component is being deleted
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DoRebuild();
|
||
|
}
|
||
|
}
|
||
|
SplineComputerEditor.hold = false;
|
||
|
|
||
|
#if UNITY_2019_1_OR_NEWER
|
||
|
SceneView.duringSceneGui -= DuringSceneGUI;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
protected virtual void OnDelete()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
protected virtual void Awake()
|
||
|
{
|
||
|
foldoutHeaderStyle = EditorStyles.foldout;
|
||
|
#if UNITY_2019_1_OR_NEWER
|
||
|
SceneView.duringSceneGui += DuringSceneGUI;
|
||
|
#endif
|
||
|
SplineUser user = (SplineUser)target;
|
||
|
user.EditorAwake();
|
||
|
}
|
||
|
|
||
|
#if !UNITY_2019_1_OR_NEWER
|
||
|
protected void OnSceneGUI()
|
||
|
{
|
||
|
DuringSceneGUI(SceneView.currentDrawingSceneView);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
protected virtual void OnEnable()
|
||
|
{
|
||
|
SplineUser user = (SplineUser)target;
|
||
|
|
||
|
settingsFoldout = EditorPrefs.GetBool("Dreamteck.Splines.Editor.SplineUserEditor.settingsFoldout", false);
|
||
|
rotationModifierEditor = new RotationModifierEditor(user, this);
|
||
|
offsetModifierEditor = new OffsetModifierEditor(user, this);
|
||
|
colorModifierEditor = new ColorModifierEditor(user, this);
|
||
|
sizeModifierEditor = new SizeModifierEditor(user, this);
|
||
|
|
||
|
updateMethodProperty = serializedObject.FindProperty("updateMethod");
|
||
|
buildOnAwakeProperty = serializedObject.FindProperty("buildOnAwake");
|
||
|
buildOnEnableProperty = serializedObject.FindProperty("buildOnEnable");
|
||
|
multithreadedProperty = serializedObject.FindProperty("multithreaded");
|
||
|
autoUpdateProperty = serializedObject.FindProperty("_autoUpdate");
|
||
|
loopSamplesProperty = serializedObject.FindProperty("_loopSamples");
|
||
|
clipFromProperty = serializedObject.FindProperty("_clipFrom");
|
||
|
clipToProperty = serializedObject.FindProperty("_clipTo");
|
||
|
spline = serializedObject.FindProperty("_spline");
|
||
|
|
||
|
users = new SplineUser[targets.Length];
|
||
|
for (int i = 0; i < users.Length; i++)
|
||
|
{
|
||
|
users[i] = (SplineUser)targets[i];
|
||
|
}
|
||
|
Undo.undoRedoPerformed += OnUndoRedo;
|
||
|
}
|
||
|
|
||
|
|
||
|
protected virtual void OnDisable()
|
||
|
{
|
||
|
EditorPrefs.SetBool("Dreamteck.Splines.Editor.SplineUserEditor.settingsFoldout", settingsFoldout);
|
||
|
Undo.undoRedoPerformed -= OnUndoRedo;
|
||
|
}
|
||
|
|
||
|
protected virtual void OnUndoRedo()
|
||
|
{
|
||
|
doRebuild = true;
|
||
|
}
|
||
|
|
||
|
public bool EditButton(bool selected)
|
||
|
{
|
||
|
float width = 40f;
|
||
|
editButtonContent.image = ResourceUtility.EditorLoadTexture("Splines/Editor/Icons", "edit_cursor");
|
||
|
if (editButtonContent.image != null)
|
||
|
{
|
||
|
editButtonContent.text = "";
|
||
|
width = 25f;
|
||
|
}
|
||
|
SplineEditorGUI.SetHighlightColors(SplinePrefs.highlightColor, SplinePrefs.highlightContentColor);
|
||
|
if (SplineEditorGUI.EditorLayoutSelectableButton(editButtonContent, true, selected, GUILayout.Width(width)))
|
||
|
{
|
||
|
SceneView.RepaintAll();
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|