| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- using UnityEngine;
- using UnityEditor;
- using System.Collections.Generic;
- namespace Cinemachine.Editor
- {
- [CustomPropertyDrawer(typeof(CinemachineImpulseDefinition))]
- internal sealed class CinemachineImpulseDefinitionPropertyDrawer : PropertyDrawer
- {
- const int vSpace = 2;
- const int kGraphHeight = 8; // lines
- #pragma warning disable 649 // variable never used
- CinemachineImpulseDefinition m_MyClass;
- #pragma warning restore 649
- GUIContent m_TimeText = null;
- float m_TimeTextWidth;
- SerializedProperty m_ShapeProperty;
- float m_ShapePropertyHeight;
- SerializedProperty m_ImpulseTypeProperty;
-
- SerializedProperty m_DissipationRateProperty;
- float m_SpreadPropertyHeight;
- public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
- {
- m_ImpulseTypeProperty = property.FindPropertyRelative(() => m_MyClass.m_ImpulseType);
- var mode = (CinemachineImpulseDefinition.ImpulseTypes)m_ImpulseTypeProperty.intValue;
- if (mode == CinemachineImpulseDefinition.ImpulseTypes.Legacy)
- return LegacyModeGetPropertyHeight(property, label);
- int lines = 3;
- m_ShapePropertyHeight = EditorGUIUtility.singleLineHeight + vSpace;
- m_ShapeProperty = property.FindPropertyRelative(() => m_MyClass.m_ImpulseShape);
- if (m_ShapeProperty.isExpanded)
- {
- lines += kGraphHeight;
- m_ShapePropertyHeight *= 1 + kGraphHeight;
- }
- m_ShapePropertyHeight -= vSpace;
- m_DissipationRateProperty = property.FindPropertyRelative(() => m_MyClass.m_DissipationRate);
- if (mode != CinemachineImpulseDefinition.ImpulseTypes.Uniform)
- {
- m_SpreadPropertyHeight = EditorGUIUtility.singleLineHeight + vSpace;
- if (m_DissipationRateProperty.isExpanded)
- {
- lines += kGraphHeight;
- m_SpreadPropertyHeight *= 1 + kGraphHeight;
- }
- m_SpreadPropertyHeight -= vSpace;
- lines += 2;
- if (mode == CinemachineImpulseDefinition.ImpulseTypes.Propagating)
- ++lines;
- }
- return lines * (EditorGUIUtility.singleLineHeight + vSpace);
- }
- public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label)
- {
- // Using BeginProperty / EndProperty on the parent property means that
- // prefab override logic works on the entire property.
- EditorGUI.BeginProperty(rect, label, property);
- var mode = (CinemachineImpulseDefinition.ImpulseTypes)m_ImpulseTypeProperty.intValue;
- if (mode == CinemachineImpulseDefinition.ImpulseTypes.Legacy)
- {
- LegacyModeOnGUI(rect, property, label);
- return;
- }
- rect.height = EditorGUIUtility.singleLineHeight;
- EditorGUI.PropertyField(rect, property.FindPropertyRelative(() => m_MyClass.m_ImpulseChannel));
- rect.y += rect.height + vSpace;
- // Impulse type
- EditorGUI.PropertyField(rect, m_ImpulseTypeProperty);
- rect.y += rect.height + vSpace;
- if (mode != CinemachineImpulseDefinition.ImpulseTypes.Uniform)
- {
- // Propaation speed
- if (mode == CinemachineImpulseDefinition.ImpulseTypes.Propagating)
- {
- EditorGUI.PropertyField(rect, property.FindPropertyRelative(() => m_MyClass.m_PropagationSpeed));
- rect.y += rect.height + vSpace;
- }
- // Dissipation
- EditorGUI.PropertyField(rect, property.FindPropertyRelative(() => m_MyClass.m_DissipationDistance));
- rect.y += rect.height + vSpace;
- // Spread combo
- rect.height = m_SpreadPropertyHeight;
- DrawSpreadCombo(rect, property);
- rect.y += rect.height + vSpace; rect.height = EditorGUIUtility.singleLineHeight;
- }
- // Impulse Shape combo
- rect.height = m_ShapePropertyHeight;
- DrawImpulseShapeCombo(rect, property);
- rect.y += rect.height + vSpace; rect.height = EditorGUIUtility.singleLineHeight;
- EditorGUI.EndProperty();
- }
- void DrawImpulseShapeCombo(Rect fullRect, SerializedProperty property)
- {
- float floatFieldWidth = EditorGUIUtility.fieldWidth + 2;
- SerializedProperty timeProp = property.FindPropertyRelative(() => m_MyClass.m_ImpulseDuration);
- if (m_TimeText == null)
- {
- m_TimeText = new GUIContent(" s", timeProp.tooltip);
- m_TimeTextWidth = GUI.skin.label.CalcSize(m_TimeText).x;
- }
- var graphRect = fullRect;
- graphRect.y += EditorGUIUtility.singleLineHeight + vSpace;
- graphRect.height -= EditorGUIUtility.singleLineHeight + vSpace;
- var indentLevel = EditorGUI.indentLevel;
- Rect r = fullRect; r.height = EditorGUIUtility.singleLineHeight;
- r = EditorGUI.PrefixLabel(r, EditorGUI.BeginProperty(
- r, new GUIContent(m_ShapeProperty.displayName, m_ShapeProperty.tooltip), property));
- m_ShapeProperty.isExpanded = EditorGUI.Foldout(r, m_ShapeProperty.isExpanded, GUIContent.none);
- bool isCustom = m_ShapeProperty.intValue == (int)CinemachineImpulseDefinition.ImpulseShapes.Custom;
- r.width -= floatFieldWidth + m_TimeTextWidth;
- if (isCustom)
- r.width -= 2 * r.height;
- EditorGUI.BeginChangeCheck();
- {
- EditorGUI.PropertyField(r, m_ShapeProperty, GUIContent.none);
- if (EditorGUI.EndChangeCheck())
- InvalidateImpulseGraphSample();
- if (!isCustom && Event.current.type == EventType.Repaint && m_ShapeProperty.isExpanded)
- DrawImpulseGraph(graphRect, CinemachineImpulseDefinition.GetStandardCurve(
- (CinemachineImpulseDefinition.ImpulseShapes)m_ShapeProperty.intValue));
- }
- if (isCustom)
- {
- SerializedProperty curveProp = property.FindPropertyRelative(() => m_MyClass.m_CustomImpulseShape);
- r.x += r.width;
- r.width = 2 * r.height;
- EditorGUI.BeginChangeCheck();
- EditorGUI.PropertyField(r, curveProp, GUIContent.none);
- if (EditorGUI.EndChangeCheck())
- {
- curveProp.animationCurveValue = RuntimeUtility.NormalizeCurve(curveProp.animationCurveValue, true, false);
- curveProp.serializedObject.ApplyModifiedProperties();
- InvalidateImpulseGraphSample();
- }
- if (Event.current.type == EventType.Repaint && m_ShapeProperty.isExpanded)
- DrawImpulseGraph(graphRect, curveProp.animationCurveValue);
- }
- // Time
- float oldWidth = EditorGUIUtility.labelWidth;
- EditorGUIUtility.labelWidth = m_TimeTextWidth;
- r.x += r.width; r.width = floatFieldWidth + EditorGUIUtility.labelWidth;
- EditorGUI.BeginChangeCheck();
- EditorGUI.PropertyField(r, timeProp, m_TimeText);
- if (EditorGUI.EndChangeCheck())
- timeProp.floatValue = Mathf.Max(timeProp.floatValue, 0);
- EditorGUIUtility.labelWidth = oldWidth;
-
- EditorGUI.indentLevel = indentLevel;
- }
- const int kNumSamples = 100;
- Vector3[] m_ImpulseGraphSnapshot = new Vector3[kNumSamples+1];
- float m_ImpulseGraphZero;
- Vector2 m_ImpulseGraphSize;
- void InvalidateImpulseGraphSample() { m_ImpulseGraphSize = Vector2.zero; }
- void DrawImpulseGraph(Rect rect, AnimationCurve curve)
- {
- // Resample if necessary
- if (m_ImpulseGraphSize != rect.size)
- {
- m_ImpulseGraphSize = rect.size;
- float minY = 0;
- float maxY = 0.1f;
- for (int i = 0; i <= kNumSamples; ++i)
- {
- var x = (float)i / kNumSamples;
- var y = curve.Evaluate(x);
- minY = Mathf.Min(y, minY);
- maxY = Mathf.Max(y, maxY);
- m_ImpulseGraphSnapshot[i] = new Vector2(x * rect.width, y);
- }
- var range = maxY - minY;
- m_ImpulseGraphZero = -minY / range;
- m_ImpulseGraphZero = rect.height * (1f - m_ImpulseGraphZero);
- // Apply scale
- for (int i = 0; i <= kNumSamples; ++i)
- m_ImpulseGraphSnapshot[i].y = rect.height * (1f - (m_ImpulseGraphSnapshot[i].y - minY) / range);
- }
- EditorGUI.DrawRect(rect, new Color(0.2f, 0.2f, 0.2f, 1));
- var oldMatrix = Handles.matrix;
- Handles.matrix = Handles.matrix * Matrix4x4.Translate(rect.position);
- Handles.color = new Color(0, 0, 0, 1);
- Handles.DrawLine(new Vector3(0, m_ImpulseGraphZero, 0), new Vector3(rect.width, m_ImpulseGraphZero, 0));
- Handles.color = new Color(1, 0.8f, 0, 1);
- Handles.DrawPolyLine(m_ImpulseGraphSnapshot);
- Handles.matrix = oldMatrix;
- }
- void DrawSpreadCombo(Rect fullRect, SerializedProperty property)
- {
- var graphRect = fullRect;
- graphRect.y += EditorGUIUtility.singleLineHeight + vSpace;
- graphRect.height -= EditorGUIUtility.singleLineHeight + vSpace;
- var indentLevel = EditorGUI.indentLevel;
- Rect r = fullRect; r.height = EditorGUIUtility.singleLineHeight;
- r = EditorGUI.PrefixLabel(r, EditorGUI.BeginProperty(
- r, new GUIContent(m_DissipationRateProperty.displayName, m_DissipationRateProperty.tooltip), property));
- m_DissipationRateProperty.isExpanded = EditorGUI.Foldout(r, m_DissipationRateProperty.isExpanded, GUIContent.none);
- EditorGUI.BeginChangeCheck();
- EditorGUI.Slider(r, m_DissipationRateProperty, 0, 1, GUIContent.none);
- if (EditorGUI.EndChangeCheck())
- InvalidateSpreadGraphSample();
- if (Event.current.type == EventType.Repaint && m_DissipationRateProperty.isExpanded)
- DrawSpreadGraph(graphRect, m_DissipationRateProperty.floatValue);
- EditorGUI.indentLevel = indentLevel;
- }
- Vector3[] m_SpreadGraphSnapshot = new Vector3[kNumSamples+1];
- Vector2 m_SpreadGraphSize;
- void InvalidateSpreadGraphSample() { m_SpreadGraphSize = Vector2.zero; }
- void DrawSpreadGraph(Rect rect, float spread)
- {
- // Resample if necessary
- if (m_SpreadGraphSize != rect.size)
- {
- m_SpreadGraphSize = rect.size;
- for (int i = 0; i <= kNumSamples >> 1; ++i)
- {
- var x = (float)i / kNumSamples;
- var y = CinemachineImpulseManager.EvaluateDissipationScale(spread, Mathf.Abs(1 - x * 2));
- m_SpreadGraphSnapshot[i] = new Vector2(x * rect.width, rect.height * (1 - y));
- m_SpreadGraphSnapshot[kNumSamples - i] = new Vector2((1 - x) * rect.width, rect.height * (1 - y));
- }
- }
- EditorGUI.DrawRect(rect, new Color(0.2f, 0.2f, 0.2f, 1));
- var oldMatrix = Handles.matrix;
- Handles.matrix = Handles.matrix * Matrix4x4.Translate(rect.position);
- Handles.color = new Color(0, 0, 0, 1);
- Handles.DrawLine(new Vector3(rect.width * 0.5f, 0, 0), new Vector3(rect.width * 0.5f, rect.height, 0));
- Handles.color = new Color(0, 0.6f, 1, 1);
- Handles.DrawPolyLine(m_SpreadGraphSnapshot);
- Handles.matrix = oldMatrix;
- }
- // Legacy mode
- float HeaderHeight { get { return EditorGUIUtility.singleLineHeight * 1.5f; } }
- float DrawHeader(Rect rect, string text)
- {
- float delta = HeaderHeight - EditorGUIUtility.singleLineHeight;
- rect.y += delta; rect.height -= delta;
- EditorGUI.LabelField(rect, new GUIContent(text), EditorStyles.boldLabel);
- return HeaderHeight;
- }
- string HeaderText(SerializedProperty property)
- {
- var attrs = property.serializedObject.targetObject.GetType()
- .GetCustomAttributes(typeof(HeaderAttribute), false);
- if (attrs != null && attrs.Length > 0)
- return ((HeaderAttribute)attrs[0]).header;
- return null;
- }
-
- List<string> mHideProperties = new List<string>();
- float LegacyModeGetPropertyHeight(SerializedProperty prop, GUIContent label)
- {
- SignalSourceAsset asset = null;
- float height = 0;
- mHideProperties.Clear();
- string prefix = prop.name;
- prop.NextVisible(true); // Skip outer foldout
- do
- {
- if (!prop.propertyPath.Contains(prefix)) // if it is part of an array, then it won't StartWith prefix
- break;
- string header = HeaderText(prop);
- if (header != null)
- height += HeaderHeight + vSpace;
- // Do we hide this property?
- bool hide = false;
- if (prop.name == SerializedPropertyHelper.PropertyName(() => m_MyClass.m_RawSignal))
- asset = prop.objectReferenceValue as SignalSourceAsset;
- if (prop.name == SerializedPropertyHelper.PropertyName(() => m_MyClass.m_RepeatMode))
- hide = asset == null || asset.SignalDuration <= 0;
- else if (prop.name == SerializedPropertyHelper.PropertyName(() => m_MyClass.m_Randomize))
- hide = asset == null || asset.SignalDuration > 0;
- else
- {
- hide = prop.name == SerializedPropertyHelper.PropertyName(() => m_MyClass.m_ImpulseShape)
- || prop.name == SerializedPropertyHelper.PropertyName(() => m_MyClass.m_CustomImpulseShape)
- || prop.name == SerializedPropertyHelper.PropertyName(() => m_MyClass.m_ImpulseDuration)
- || prop.name == SerializedPropertyHelper.PropertyName(() => m_MyClass.m_DissipationRate);
- }
- if (hide)
- mHideProperties.Add(prop.name);
- else
- height += EditorGUI.GetPropertyHeight(prop, false) + vSpace;
- } while (prop.NextVisible(prop.isExpanded));
- return height;
- }
- void LegacyModeOnGUI(Rect rect, SerializedProperty prop, GUIContent label)
- {
- string prefix = prop.name;
- prop.NextVisible(true); // Skip outer foldout
- do
- {
- if (!prop.propertyPath.Contains(prefix)) // if it is part of an array, then it won't StartWith prefix
- break;
- string header = HeaderText(prop);
- if (header != null)
- {
- rect.height = HeaderHeight;
- DrawHeader(rect, header);
- rect.y += HeaderHeight + vSpace;
- }
- if (mHideProperties.Contains(prop.name))
- continue;
- rect.height = EditorGUI.GetPropertyHeight(prop, false);
- EditorGUI.PropertyField(rect, prop);
- rect.y += rect.height + vSpace;
- } while (prop.NextVisible(prop.isExpanded));
- }
- }
- }
|