using System; using System.Linq; using UnityEngine; using UnityEngine.Splines; namespace UnityEditor.Splines { [CustomEditor(typeof(SplineExtrude))] [CanEditMultipleObjects] class SplineExtrudeEditor : SplineComponentEditor { SerializedProperty m_Container; SerializedProperty m_RebuildOnSplineChange; SerializedProperty m_RebuildFrequency; SerializedProperty m_Sides; SerializedProperty m_SegmentsPerUnit; SerializedProperty m_Capped; SerializedProperty m_Radius; SerializedProperty m_Range; SerializedProperty m_UpdateColliders; static readonly GUIContent k_RangeContent = new GUIContent("Range", "The section of the Spline to extrude."); static readonly GUIContent k_AdvancedContent = new GUIContent("Advanced", "Advanced Spline Extrude settings."); static readonly GUIContent k_PercentageContent = new GUIContent("Percentage", "The section of the Spline to extrude in percentages."); static readonly string k_Spline = "Spline"; static readonly string k_Geometry = L10n.Tr("Geometry"); static readonly string k_ProfileEdges = "Profile Edges"; static readonly string k_CapEnds = "Cap Ends"; static readonly string k_AutoRegenGeo = "Auto-Regen Geometry"; static readonly string k_To = L10n.Tr("to"); static readonly string k_From = L10n.Tr("from"); SplineExtrude[] m_Components; bool m_AnyMissingMesh; protected override void OnEnable() { base.OnEnable(); m_Container = serializedObject.FindProperty("m_Container"); m_RebuildOnSplineChange = serializedObject.FindProperty("m_RebuildOnSplineChange"); m_RebuildFrequency = serializedObject.FindProperty("m_RebuildFrequency"); m_Sides = serializedObject.FindProperty("m_Sides"); m_SegmentsPerUnit = serializedObject.FindProperty("m_SegmentsPerUnit"); m_Capped = serializedObject.FindProperty("m_Capped"); m_Radius = serializedObject.FindProperty("m_Radius"); m_Range = serializedObject.FindProperty("m_Range"); m_UpdateColliders = serializedObject.FindProperty("m_UpdateColliders"); m_Components = targets.Select(x => x as SplineExtrude).Where(y => y != null).ToArray(); m_AnyMissingMesh = m_Components.Any(x => x.TryGetComponent(out var filter) && filter.sharedMesh == null); EditorSplineUtility.afterSplineWasModified += OnSplineModified; } void OnDisable() { EditorSplineUtility.afterSplineWasModified -= OnSplineModified; } void OnSplineModified(Spline spline) { if (EditorApplication.isPlayingOrWillChangePlaymode) return; foreach (var extrude in m_Components) { if (extrude.container != null && extrude.container.Spline == spline) extrude.Rebuild(); } } public override void OnInspectorGUI() { serializedObject.Update(); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(m_Container, new GUIContent(k_Spline, m_Container.tooltip)); HorizontalLine(Color.grey); EditorGUILayout.LabelField(k_Geometry, EditorStyles.boldLabel); if(m_AnyMissingMesh) { GUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(" "); if(GUILayout.Button("Create Mesh Asset")) CreateMeshAssets(m_Components); GUILayout.EndHorizontal(); } EditorGUI.indentLevel++; EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(m_Radius); if(EditorGUI.EndChangeCheck()) m_Radius.floatValue = Mathf.Clamp(m_Radius.floatValue, .00001f, 1000f); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(m_Sides, new GUIContent(k_ProfileEdges, m_Sides.tooltip)); if(EditorGUI.EndChangeCheck()) m_Sides.intValue = Mathf.Clamp(m_Sides.intValue, 3, 2048); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(m_SegmentsPerUnit); if(EditorGUI.EndChangeCheck()) m_SegmentsPerUnit.floatValue = Mathf.Clamp(m_SegmentsPerUnit.floatValue, .00001f, 4096f); EditorGUILayout.PropertyField(m_Capped, new GUIContent(k_CapEnds, m_Capped.tooltip)); EditorGUI.indentLevel--; HorizontalLine(Color.grey); m_Range.isExpanded = Foldout(m_Range.isExpanded, k_AdvancedContent); if (m_Range.isExpanded) { EditorGUI.indentLevel++; EditorGUI.showMixedValue = m_Range.hasMultipleDifferentValues; var range = m_Range.vector2Value; EditorGUI.BeginChangeCheck(); EditorGUILayout.MinMaxSlider(k_RangeContent, ref range.x, ref range.y, 0f, 1f); if (EditorGUI.EndChangeCheck()) m_Range.vector2Value = range; EditorGUI.indentLevel++; EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(k_PercentageContent); EditorGUI.indentLevel--; EditorGUI.indentLevel--; EditorGUI.BeginChangeCheck(); var newRange = new Vector2(range.x, range.y); using (new LabelWidthScope(30f)) newRange.x = EditorGUILayout.FloatField(k_From, range.x * 100f) / 100f; using (new LabelWidthScope(15f)) newRange.y = EditorGUILayout.FloatField(k_To, range.y * 100f) / 100f; if (EditorGUI.EndChangeCheck()) { newRange.x = Mathf.Min(Mathf.Clamp(newRange.x, 0f, 1f), range.y); newRange.y = Mathf.Max(newRange.x, Mathf.Clamp(newRange.y, 0f, 1f)); m_Range.vector2Value = newRange; } EditorGUILayout.EndHorizontal(); EditorGUI.showMixedValue = false; EditorGUI.indentLevel++; EditorGUILayout.PropertyField(m_RebuildOnSplineChange, new GUIContent(k_AutoRegenGeo, m_RebuildOnSplineChange.tooltip)); if (m_RebuildOnSplineChange.boolValue) { EditorGUI.indentLevel++; EditorGUI.BeginDisabledGroup(!m_RebuildOnSplineChange.boolValue); EditorGUILayout.PropertyField(m_RebuildFrequency); EditorGUI.EndDisabledGroup(); EditorGUI.indentLevel--; } EditorGUILayout.PropertyField(m_UpdateColliders); EditorGUI.indentLevel--; } serializedObject.ApplyModifiedProperties(); if(EditorGUI.EndChangeCheck()) foreach(var extrude in m_Components) extrude.Rebuild(); } void CreateMeshAssets(SplineExtrude[] components) { foreach (var extrude in components) { if (!extrude.TryGetComponent(out var filter) || filter.sharedMesh != null) filter.sharedMesh = extrude.CreateMeshAsset(); } m_AnyMissingMesh = false; } } }