203 lines
8.2 KiB
C#
203 lines
8.2 KiB
C#
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Linq;
|
||
|
using UnityEditor;
|
||
|
using UnityEngine;
|
||
|
using UnityObject = UnityEngine.Object;
|
||
|
|
||
|
namespace Unity.Mathematics.Editor
|
||
|
{
|
||
|
[CustomPropertyDrawer(typeof(PostNormalizeAttribute))]
|
||
|
class PostNormalizedVectorDrawer : PrimitiveVectorDrawer
|
||
|
{
|
||
|
static class Content
|
||
|
{
|
||
|
public static readonly string tooltip =
|
||
|
L10n.Tr("Values you enter will be post-normalized. You will see the normalized result if you change selection and view the values again.");
|
||
|
}
|
||
|
|
||
|
class VectorPropertyGUIData
|
||
|
{
|
||
|
const int k_MaxElements = 4;
|
||
|
|
||
|
public readonly bool Valid;
|
||
|
|
||
|
// parent property
|
||
|
readonly SerializedProperty m_VectorProperty;
|
||
|
// relative paths of element child properties
|
||
|
readonly IReadOnlyList<string> m_ElementPaths;
|
||
|
// the number of element child properties
|
||
|
readonly int m_NumElements;
|
||
|
// per child property; value is null if there are multiple different values
|
||
|
readonly double?[] m_PreNormalizedValues;
|
||
|
// per target; used to revert actual values for each object after displaying pre-normalized values
|
||
|
readonly Dictionary<SerializedProperty, double4> m_PostNormalizedValues = new Dictionary<SerializedProperty, double4>();
|
||
|
|
||
|
public VectorPropertyGUIData(SerializedProperty property)
|
||
|
{
|
||
|
m_VectorProperty = property;
|
||
|
var parentPath = m_VectorProperty.propertyPath;
|
||
|
var i = 0;
|
||
|
var elementPaths = new List<string>(k_MaxElements);
|
||
|
var iterator = m_VectorProperty.Copy();
|
||
|
while (iterator.Next(true) && iterator.propertyPath.StartsWith(parentPath))
|
||
|
{
|
||
|
if (i >= k_MaxElements || iterator.propertyType != SerializedPropertyType.Float)
|
||
|
return;
|
||
|
elementPaths.Add(iterator.propertyPath.Substring(parentPath.Length + 1));
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
Valid = true;
|
||
|
m_NumElements = elementPaths.Count;
|
||
|
m_ElementPaths = elementPaths;
|
||
|
m_PreNormalizedValues = elementPaths.Select(p => (double?)null).ToArray();
|
||
|
|
||
|
UpdatePreNormalizedValues();
|
||
|
UpdatePostNormalizedValues();
|
||
|
}
|
||
|
|
||
|
void UpdatePostNormalizedValues()
|
||
|
{
|
||
|
m_PostNormalizedValues.Clear();
|
||
|
foreach (var target in m_VectorProperty.serializedObject.targetObjects)
|
||
|
{
|
||
|
var postNormalizedValue = new double4();
|
||
|
var parentProperty = new SerializedObject(target).FindProperty(m_VectorProperty.propertyPath);
|
||
|
for (var i = 0; i < m_NumElements; ++i)
|
||
|
postNormalizedValue[i] = parentProperty.FindPropertyRelative(m_ElementPaths[i]).doubleValue;
|
||
|
m_PostNormalizedValues[parentProperty] = postNormalizedValue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void UpdatePreNormalizedValues()
|
||
|
{
|
||
|
for (var i = 0; i < m_NumElements; ++i)
|
||
|
{
|
||
|
var p = m_VectorProperty.FindPropertyRelative(m_ElementPaths[i]);
|
||
|
m_PreNormalizedValues[i] = p.hasMultipleDifferentValues ? (double?)null : p.doubleValue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void ApplyPreNormalizedValues()
|
||
|
{
|
||
|
m_VectorProperty.serializedObject.ApplyModifiedProperties();
|
||
|
for (var i = 0; i < m_NumElements; ++i)
|
||
|
{
|
||
|
if (m_PreNormalizedValues[i] != null)
|
||
|
m_VectorProperty.FindPropertyRelative(m_ElementPaths[i]).doubleValue = m_PreNormalizedValues[i].Value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void UnapplyPreNormalizedValues()
|
||
|
{
|
||
|
foreach (var target in m_PostNormalizedValues)
|
||
|
{
|
||
|
target.Key.serializedObject.Update();
|
||
|
for (var i = 0; i < m_NumElements; ++i)
|
||
|
{
|
||
|
target.Key.FindPropertyRelative(m_ElementPaths[i]).doubleValue = target.Value[i];
|
||
|
target.Key.serializedObject.ApplyModifiedProperties();
|
||
|
}
|
||
|
}
|
||
|
m_VectorProperty.serializedObject.Update();
|
||
|
}
|
||
|
|
||
|
public void PostNormalize(Func<double4, double4> normalize)
|
||
|
{
|
||
|
m_VectorProperty.serializedObject.ApplyModifiedProperties();
|
||
|
foreach (var target in m_PostNormalizedValues)
|
||
|
{
|
||
|
target.Key.serializedObject.Update();
|
||
|
var postNormalizedValue = new double4();
|
||
|
for (var i = 0; i < m_NumElements; ++i)
|
||
|
postNormalizedValue[i] = target.Key.FindPropertyRelative(m_ElementPaths[i]).doubleValue;
|
||
|
postNormalizedValue = normalize(normalize(postNormalizedValue));
|
||
|
for (var i = 0; i < m_NumElements; ++i)
|
||
|
target.Key.FindPropertyRelative(m_ElementPaths[i]).doubleValue = postNormalizedValue[i];
|
||
|
target.Key.serializedObject.ApplyModifiedProperties();
|
||
|
}
|
||
|
UpdatePostNormalizedValues();
|
||
|
m_VectorProperty.serializedObject.Update();
|
||
|
}
|
||
|
|
||
|
public void RebuildIfDirty()
|
||
|
{
|
||
|
foreach (var target in m_PostNormalizedValues)
|
||
|
{
|
||
|
target.Key.serializedObject.Update();
|
||
|
for (var i = 0; i < m_NumElements; ++i)
|
||
|
{
|
||
|
var serialized = target.Key.FindPropertyRelative(m_ElementPaths[i]).doubleValue;
|
||
|
if (target.Value[i] != serialized)
|
||
|
{
|
||
|
UpdatePreNormalizedValues();
|
||
|
UpdatePostNormalizedValues();
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Dictionary<string, VectorPropertyGUIData> m_GUIDataPerPropertyPath = new Dictionary<string, VectorPropertyGUIData>();
|
||
|
|
||
|
protected virtual SerializedProperty GetVectorProperty(SerializedProperty property)
|
||
|
{
|
||
|
return property;
|
||
|
}
|
||
|
|
||
|
protected virtual double4 Normalize(double4 value)
|
||
|
{
|
||
|
return math.normalizesafe(value);
|
||
|
}
|
||
|
|
||
|
VectorPropertyGUIData GetGUIData(SerializedProperty property)
|
||
|
{
|
||
|
VectorPropertyGUIData guiData;
|
||
|
if (!m_GUIDataPerPropertyPath.TryGetValue(property.propertyPath, out guiData))
|
||
|
{
|
||
|
guiData = new VectorPropertyGUIData(GetVectorProperty(property));
|
||
|
m_GUIDataPerPropertyPath[property.propertyPath] = guiData;
|
||
|
}
|
||
|
return guiData;
|
||
|
}
|
||
|
|
||
|
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||
|
{
|
||
|
return GetGUIData(property).Valid ? base.GetPropertyHeight(property, label) : EditorGUIUtility.singleLineHeight;
|
||
|
}
|
||
|
|
||
|
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||
|
{
|
||
|
var guiData = GetGUIData(property);
|
||
|
if (!guiData.Valid)
|
||
|
{
|
||
|
EditorGUI.HelpBox(
|
||
|
EditorGUI.PrefixLabel(position, label),
|
||
|
L10n.Tr($"{typeof(PostNormalizeAttribute).Name} only works with decimal vector types."),
|
||
|
MessageType.None
|
||
|
);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (string.IsNullOrEmpty(label.tooltip))
|
||
|
label.tooltip = Content.tooltip;
|
||
|
|
||
|
guiData.RebuildIfDirty();
|
||
|
guiData.ApplyPreNormalizedValues();
|
||
|
EditorGUI.BeginChangeCheck();
|
||
|
base.OnGUI(position, property, label);
|
||
|
if (EditorGUI.EndChangeCheck())
|
||
|
{
|
||
|
guiData.UpdatePreNormalizedValues();
|
||
|
guiData.PostNormalize(Normalize);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
guiData.UnapplyPreNormalizedValues();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|