A game about forced loneliness, made by TACStudios
at master 202 lines 8.4 kB view raw
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using UnityEditor; 5using UnityEngine; 6using UnityObject = UnityEngine.Object; 7 8namespace Unity.Mathematics.Editor 9{ 10 [CustomPropertyDrawer(typeof(PostNormalizeAttribute))] 11 class PostNormalizedVectorDrawer : PrimitiveVectorDrawer 12 { 13 static class Content 14 { 15 public static readonly string tooltip = 16 L10n.Tr("Values you enter will be post-normalized. You will see the normalized result if you change selection and view the values again."); 17 } 18 19 class VectorPropertyGUIData 20 { 21 const int k_MaxElements = 4; 22 23 public readonly bool Valid; 24 25 // parent property 26 readonly SerializedProperty m_VectorProperty; 27 // relative paths of element child properties 28 readonly IReadOnlyList<string> m_ElementPaths; 29 // the number of element child properties 30 readonly int m_NumElements; 31 // per child property; value is null if there are multiple different values 32 readonly double?[] m_PreNormalizedValues; 33 // per target; used to revert actual values for each object after displaying pre-normalized values 34 readonly Dictionary<SerializedProperty, double4> m_PostNormalizedValues = new Dictionary<SerializedProperty, double4>(); 35 36 public VectorPropertyGUIData(SerializedProperty property) 37 { 38 m_VectorProperty = property; 39 var parentPath = m_VectorProperty.propertyPath; 40 var i = 0; 41 var elementPaths = new List<string>(k_MaxElements); 42 var iterator = m_VectorProperty.Copy(); 43 while (iterator.Next(true) && iterator.propertyPath.StartsWith(parentPath)) 44 { 45 if (i >= k_MaxElements || iterator.propertyType != SerializedPropertyType.Float) 46 return; 47 elementPaths.Add(iterator.propertyPath.Substring(parentPath.Length + 1)); 48 i++; 49 } 50 51 Valid = true; 52 m_NumElements = elementPaths.Count; 53 m_ElementPaths = elementPaths; 54 m_PreNormalizedValues = elementPaths.Select(p => (double?)null).ToArray(); 55 56 UpdatePreNormalizedValues(); 57 UpdatePostNormalizedValues(); 58 } 59 60 void UpdatePostNormalizedValues() 61 { 62 m_PostNormalizedValues.Clear(); 63 foreach (var target in m_VectorProperty.serializedObject.targetObjects) 64 { 65 var postNormalizedValue = new double4(); 66 var parentProperty = new SerializedObject(target).FindProperty(m_VectorProperty.propertyPath); 67 for (var i = 0; i < m_NumElements; ++i) 68 postNormalizedValue[i] = parentProperty.FindPropertyRelative(m_ElementPaths[i]).doubleValue; 69 m_PostNormalizedValues[parentProperty] = postNormalizedValue; 70 } 71 } 72 73 public void UpdatePreNormalizedValues() 74 { 75 for (var i = 0; i < m_NumElements; ++i) 76 { 77 var p = m_VectorProperty.FindPropertyRelative(m_ElementPaths[i]); 78 m_PreNormalizedValues[i] = p.hasMultipleDifferentValues ? (double?)null : p.doubleValue; 79 } 80 } 81 82 public void ApplyPreNormalizedValues() 83 { 84 m_VectorProperty.serializedObject.ApplyModifiedProperties(); 85 for (var i = 0; i < m_NumElements; ++i) 86 { 87 if (m_PreNormalizedValues[i] != null) 88 m_VectorProperty.FindPropertyRelative(m_ElementPaths[i]).doubleValue = m_PreNormalizedValues[i].Value; 89 } 90 } 91 92 public void UnapplyPreNormalizedValues() 93 { 94 foreach (var target in m_PostNormalizedValues) 95 { 96 target.Key.serializedObject.Update(); 97 for (var i = 0; i < m_NumElements; ++i) 98 { 99 target.Key.FindPropertyRelative(m_ElementPaths[i]).doubleValue = target.Value[i]; 100 target.Key.serializedObject.ApplyModifiedProperties(); 101 } 102 } 103 m_VectorProperty.serializedObject.Update(); 104 } 105 106 public void PostNormalize(Func<double4, double4> normalize) 107 { 108 m_VectorProperty.serializedObject.ApplyModifiedProperties(); 109 foreach (var target in m_PostNormalizedValues) 110 { 111 target.Key.serializedObject.Update(); 112 var postNormalizedValue = new double4(); 113 for (var i = 0; i < m_NumElements; ++i) 114 postNormalizedValue[i] = target.Key.FindPropertyRelative(m_ElementPaths[i]).doubleValue; 115 postNormalizedValue = normalize(normalize(postNormalizedValue)); 116 for (var i = 0; i < m_NumElements; ++i) 117 target.Key.FindPropertyRelative(m_ElementPaths[i]).doubleValue = postNormalizedValue[i]; 118 target.Key.serializedObject.ApplyModifiedProperties(); 119 } 120 UpdatePostNormalizedValues(); 121 m_VectorProperty.serializedObject.Update(); 122 } 123 124 public void RebuildIfDirty() 125 { 126 foreach (var target in m_PostNormalizedValues) 127 { 128 target.Key.serializedObject.Update(); 129 for (var i = 0; i < m_NumElements; ++i) 130 { 131 var serialized = target.Key.FindPropertyRelative(m_ElementPaths[i]).doubleValue; 132 if (target.Value[i] != serialized) 133 { 134 UpdatePreNormalizedValues(); 135 UpdatePostNormalizedValues(); 136 return; 137 } 138 } 139 } 140 } 141 } 142 143 Dictionary<string, VectorPropertyGUIData> m_GUIDataPerPropertyPath = new Dictionary<string, VectorPropertyGUIData>(); 144 145 protected virtual SerializedProperty GetVectorProperty(SerializedProperty property) 146 { 147 return property; 148 } 149 150 protected virtual double4 Normalize(double4 value) 151 { 152 return math.normalizesafe(value); 153 } 154 155 VectorPropertyGUIData GetGUIData(SerializedProperty property) 156 { 157 VectorPropertyGUIData guiData; 158 if (!m_GUIDataPerPropertyPath.TryGetValue(property.propertyPath, out guiData)) 159 { 160 guiData = new VectorPropertyGUIData(GetVectorProperty(property)); 161 m_GUIDataPerPropertyPath[property.propertyPath] = guiData; 162 } 163 return guiData; 164 } 165 166 public override float GetPropertyHeight(SerializedProperty property, GUIContent label) 167 { 168 return GetGUIData(property).Valid ? base.GetPropertyHeight(property, label) : EditorGUIUtility.singleLineHeight; 169 } 170 171 public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) 172 { 173 var guiData = GetGUIData(property); 174 if (!guiData.Valid) 175 { 176 EditorGUI.HelpBox( 177 EditorGUI.PrefixLabel(position, label), 178 L10n.Tr($"{typeof(PostNormalizeAttribute).Name} only works with decimal vector types."), 179 MessageType.None 180 ); 181 return; 182 } 183 184 if (string.IsNullOrEmpty(label.tooltip)) 185 label.tooltip = Content.tooltip; 186 187 guiData.RebuildIfDirty(); 188 guiData.ApplyPreNormalizedValues(); 189 EditorGUI.BeginChangeCheck(); 190 base.OnGUI(position, property, label); 191 if (EditorGUI.EndChangeCheck()) 192 { 193 guiData.UpdatePreNormalizedValues(); 194 guiData.PostNormalize(Normalize); 195 } 196 else 197 { 198 guiData.UnapplyPreNormalizedValues(); 199 } 200 } 201 } 202}