namespace Dreamteck.Splines.Editor { using UnityEngine; using UnityEditor; public class SplineSampleModifierEditor : SplineUserSubEditor { protected int selected = -1; protected bool drawAllKeys = false; protected virtual SerializedProperty _keysProperty => _keys; protected SerializedProperty _keys; protected SerializedProperty _blend; protected SerializedProperty _useClipped; protected SerializedProperty _modifier; protected virtual string _keysPropertyName => "keys"; private int _deleteElement = -1; protected SerializedObject _serializedObject; public SplineSampleModifierEditor(SplineUser user, SplineUserEditor editor, string modifierPropertyPath = "") : base(user, editor) { title = "Sample Modifier"; _serializedObject = new SerializedObject(user); string[] propertyPath = modifierPropertyPath.Split('/'); var property = _serializedObject.FindProperty(propertyPath[0]); for (int i = 1; i < propertyPath.Length; i++) { if(propertyPath[i].StartsWith("[") && propertyPath[i].EndsWith("]")) { var num = propertyPath[i].Substring(1, propertyPath[i].Length - 2); property = property.GetArrayElementAtIndex(int.Parse(num)); continue; } property = property.FindPropertyRelative(propertyPath[i]); } _modifier = property; _keys = _modifier.FindPropertyRelative(_keysPropertyName); _blend = _modifier.FindPropertyRelative("blend"); _useClipped = _modifier.FindPropertyRelative("useClippedPercent"); } public override void DrawInspector() { base.DrawInspector(); if (!isOpen) return; if (_keysProperty.arraySize > 0) { drawAllKeys = EditorGUILayout.Toggle("Draw all Modules", drawAllKeys); } _serializedObject.Update(); EditorGUI.BeginChangeCheck(); for (int i = 0; i < _keysProperty.arraySize; i++) { EditorGUILayout.BeginVertical(EditorStyles.helpBox); SerializedProperty keyProperty = _keysProperty.GetArrayElementAtIndex(i); if (selected == i) { EditorGUI.BeginChangeCheck(); KeyGUI(keyProperty); if (EditorGUI.EndChangeCheck()) user.Rebuild(); } else { SerializedProperty start = keyProperty.FindPropertyRelative("_featherStart"); SerializedProperty end = keyProperty.FindPropertyRelative("_featherEnd"); EditorGUILayout.LabelField(i + " [" + (Mathf.Round(start.floatValue * 10) / 10f) + " - " + (Mathf.Round(end.floatValue * 10) / 10f) + "]"); } EditorGUILayout.EndVertical(); Rect lastRect = GUILayoutUtility.GetLastRect(); if (lastRect.Contains(Event.current.mousePosition)) { if(Event.current.type == EventType.MouseDown) { if(Event.current.button == 0) { selected = i; editor.Repaint(); } else if (Event.current.button == 1) { int index = i; GenericMenu menu = new GenericMenu(); menu.AddItem(new GUIContent("Delete"), false, delegate { _deleteElement = index; }); menu.ShowAsContext(); UpdateValues(); _serializedObject.Update(); } } } } EditorGUILayout.Space(); if (_keysProperty.arraySize > 0) { EditorGUILayout.PropertyField(_blend); EditorGUILayout.PropertyField(_useClipped, new GUIContent("Use Clipped Percents", "Whether the percentages relate to the clip range of the user or not.")); } if(_deleteElement >= 0) { _keysProperty.DeleteArrayElementAtIndex(_deleteElement); _deleteElement = -1; UpdateValues(); } else { if (EditorGUI.EndChangeCheck()) { UpdateValues(); } } } public override void DrawScene() { base.DrawScene(); _serializedObject.Update(); bool changed = false; for (int i = 0; i < _keysProperty.arraySize; i++) { if (selected == i || drawAllKeys) { if(KeyHandles(_keysProperty.GetArrayElementAtIndex(i), selected == i)) { changed = true; } } } if (changed) { UpdateValues(); } } protected void UpdateValues() { if (_serializedObject != null) { _serializedObject.ApplyModifiedProperties(); } user.Rebuild(); editor.Repaint(); } protected virtual SerializedProperty AddKey(float f, float t) { _keys.InsertArrayElementAtIndex(_keys.arraySize); var key = _keys.GetArrayElementAtIndex(_keys.arraySize - 1); SerializedProperty start = key.FindPropertyRelative("_featherStart"); SerializedProperty end = key.FindPropertyRelative("_featherEnd"); SerializedProperty centerStart = key.FindPropertyRelative("_centerStart"); SerializedProperty centerEnd = key.FindPropertyRelative("_centerEnd"); SerializedProperty blend = key.FindPropertyRelative("blend"); SerializedProperty interpolation = key.FindPropertyRelative("interpolation"); start.floatValue = Mathf.Clamp01(f); end.floatValue = Mathf.Clamp01(t); blend.floatValue = 1f; interpolation.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f); centerStart.floatValue = 0.1f; centerEnd.floatValue = 0.9f; return key; } protected virtual void KeyGUI(SerializedProperty keyProperty) { SerializedProperty start = keyProperty.FindPropertyRelative("_featherStart"); SerializedProperty end = keyProperty.FindPropertyRelative("_featherEnd"); SerializedProperty centerStart = keyProperty.FindPropertyRelative("_centerStart"); SerializedProperty centerEnd = keyProperty.FindPropertyRelative("_centerEnd"); SerializedProperty interpolation = keyProperty.FindPropertyRelative("interpolation"); SerializedProperty blend = keyProperty.FindPropertyRelative("blend"); EditorGUILayout.BeginHorizontal(); EditorGUIUtility.labelWidth = 50f; start.floatValue = EditorGUILayout.Slider("Start", start.floatValue, 0f, 1f); end.floatValue = EditorGUILayout.Slider("End", end.floatValue, 0f, 1f); EditorGUILayout.EndHorizontal(); EditorGUIUtility.labelWidth = 0f; float cs = centerStart.floatValue; float ce = centerEnd.floatValue; EditorGUILayout.MinMaxSlider("Center", ref cs, ref ce, 0f, 1f); centerStart.floatValue = cs; centerEnd.floatValue = ce; EditorGUILayout.PropertyField(interpolation); EditorGUILayout.PropertyField(blend); } protected static float GlobalToLocalPercent(float start, float end, float t) { if (start > end) { if (t > start) return Mathf.InverseLerp(start, start + (1f - start) + end, t); else if (t < end) return Mathf.InverseLerp(-(1f - start), end, t); else return 0f; } return Mathf.InverseLerp(start, end, t); } protected static float LocalToGlobalPercent(float start, float end, float t) { if (start > end) { t = Mathf.Lerp(start, start + (1f - start) + end, t); if (t > 1f) { t -= Mathf.Floor(t); } return t; } return Mathf.Lerp(start, end, t); } protected static float GetPosition(float start, float end, float centerStart, float centerEnd) { float center = Mathf.Lerp(centerStart, centerEnd, 0.5f); if (start > end) { float fromToEndDistance = 1f - start; float centerDistance = center * (fromToEndDistance + end); float pos = start + centerDistance; if (pos > 1f) { pos -= Mathf.Floor(pos); } return pos; } return Mathf.Lerp(start, end, center); } protected virtual bool KeyHandles(SerializedProperty key, bool edit) { if (!isOpen) return false; bool useClip = _useClipped.boolValue; SerializedProperty start = key.FindPropertyRelative("_featherStart"); SerializedProperty end = key.FindPropertyRelative("_featherEnd"); SerializedProperty centerStart = key.FindPropertyRelative("_centerStart"); SerializedProperty centerEnd = key.FindPropertyRelative("_centerEnd"); bool changed = false; double value = start.floatValue; if (useClip) { user.UnclipPercent(ref value); } SplineComputerEditorHandles.Slider(user.spline, ref value, user.spline.editorPathColor, "Start", SplineComputerEditorHandles.SplineSliderGizmo.ForwardTriangle, 0.8f); if (useClip) { user.ClipPercent(ref value); } if (start.floatValue != value) { start.floatValue = (float)value; changed = true; } value = LocalToGlobalPercent(start.floatValue, end.floatValue, centerStart.floatValue); if (useClip) { user.UnclipPercent(ref value); } SplineComputerEditorHandles.Slider(user.spline, ref value, user.spline.editorPathColor, "", SplineComputerEditorHandles.SplineSliderGizmo.Rectangle, 0.6f); if (useClip) { user.ClipPercent(ref value); } if (LocalToGlobalPercent(start.floatValue, end.floatValue, centerStart.floatValue) != value) { centerStart.floatValue = GlobalToLocalPercent(start.floatValue, end.floatValue, (float)value); changed = true; } value = LocalToGlobalPercent(start.floatValue, end.floatValue, centerEnd.floatValue); if (useClip) { user.UnclipPercent(ref value); } SplineComputerEditorHandles.Slider(user.spline, ref value, user.spline.editorPathColor, "", SplineComputerEditorHandles.SplineSliderGizmo.Rectangle, 0.6f); if (useClip) { user.ClipPercent(ref value); } if (LocalToGlobalPercent(start.floatValue, end.floatValue, centerEnd.floatValue) != value) { centerEnd.floatValue = GlobalToLocalPercent(start.floatValue, end.floatValue, (float)value); changed = true; } value = end.floatValue; if (useClip) { user.UnclipPercent(ref value); } SplineComputerEditorHandles.Slider(user.spline, ref value, user.spline.editorPathColor, "End", SplineComputerEditorHandles.SplineSliderGizmo.BackwardTriangle, 0.8f); if (useClip) { user.ClipPercent(ref value); } if (end.floatValue != value) { end.floatValue = (float)value; changed = true; } if (Event.current.control) { value = GetPosition(start.floatValue, end.floatValue, centerStart.floatValue, centerEnd.floatValue); double lastValue = value; if (useClip) { user.UnclipPercent(ref value); } SplineComputerEditorHandles.Slider(user.spline, ref value, user.spline.editorPathColor, "", SplineComputerEditorHandles.SplineSliderGizmo.Circle, 0.4f); if (useClip) { user.ClipPercent(ref value); } if (value != lastValue) { double delta = value - lastValue; start.floatValue += (float)delta; end.floatValue += (float)delta; start.floatValue = Mathf.Clamp01(start.floatValue); end.floatValue = Mathf.Clamp(end.floatValue, start.floatValue, 1f); changed = true; } } return changed; } } }