modular-avatar/Packages/net.fushizen.modular-avatar/Editor/Inspector/BlendshapeSyncEditor.cs

134 lines
4.3 KiB
C#
Raw Normal View History

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using UnityEditor;
using UnityEditorInternal;
2022-10-20 10:42:33 +08:00
using UnityEngine;
using UnityEngine.PlayerLoop;
2022-10-20 10:42:33 +08:00
namespace net.fushizen.modular_avatar.core.editor
{
[CustomEditor(typeof(ModularAvatarBlendshapeSync))]
[CanEditMultipleObjects]
2022-10-20 10:42:33 +08:00
internal class BlendshapeSyncEditor : Editor
{
private static FieldInfo f_m_SerializedObject;
2022-10-20 10:42:33 +08:00
private BlendshapeSelectWindow _window;
private ReorderableList _list;
private SerializedProperty _bindings;
2022-10-20 10:42:33 +08:00
static BlendshapeSyncEditor()
{
f_m_SerializedObject =
typeof(Editor).GetField("m_SerializedObject", BindingFlags.Instance | BindingFlags.NonPublic);
}
// Workaround unity bug: When we modify the number of array elements via the underlying objects, the serialized
// object will throw exceptions trying to access the new element, even after calling Update() and recreating all
// serialized properties. So force the serialized object to be recreated as a workaround.
private void ClearSerializedObject()
{
f_m_SerializedObject.SetValue(this, null);
}
private void OnDisable()
{
if (_window != null) DestroyImmediate(_window);
}
private void OnDestroy()
{
if (_window != null) DestroyImmediate(_window);
}
private void OnEnable()
{
InitList();
}
private void InitList()
{
_bindings = serializedObject.FindProperty(nameof(ModularAvatarBlendshapeSync.Bindings));
_list = new ReorderableList(serializedObject,
_bindings,
true, true, true, true
);
_list.drawHeaderCallback = DrawHeader;
_list.drawElementCallback = DrawElement;
_list.onAddCallback = list => OpenAddWindow();
_list.elementHeight += 2;
}
private void DrawHeader(Rect rect)
2022-10-20 10:42:33 +08:00
{
var leftHalf = rect;
leftHalf.width /= 2;
2022-10-20 10:42:33 +08:00
var rightHalf = rect;
rightHalf.width /= 2;
rightHalf.x += rightHalf.width;
EditorGUI.LabelField(leftHalf, "Mesh");
EditorGUI.LabelField(rightHalf, "Blendshape");
}
private void DrawElement(Rect rect, int index, bool isactive, bool isfocused)
{
rect.height -= 2;
rect.y += 1;
var leftHalf = rect;
leftHalf.width /= 2;
leftHalf.width -= 12;
var rightHalf = rect;
rightHalf.width /= 2;
rightHalf.x += rightHalf.width;
var item = _bindings.GetArrayElementAtIndex(index);
var mesh = item.FindPropertyRelative(nameof(BlendshapeBinding.ReferenceMesh));
var blendshape = item.FindPropertyRelative(nameof(BlendshapeBinding.Blendshape));
using (var scope = new ZeroIndentScope())
2022-10-20 10:42:33 +08:00
{
EditorGUI.PropertyField(leftHalf, mesh, GUIContent.none);
EditorGUI.PropertyField(rightHalf, blendshape, GUIContent.none);
2022-10-20 10:42:33 +08:00
}
}
public override void OnInspectorGUI()
{
2022-10-23 04:31:10 +08:00
LogoDisplay.DisplayLogo();
serializedObject.Update();
_list.DoLayoutList();
serializedObject.ApplyModifiedProperties();
}
private void OpenAddWindow()
{
if (_window != null) DestroyImmediate(_window);
_window = ScriptableObject.CreateInstance<BlendshapeSelectWindow>();
_window.AvatarRoot = RuntimeUtil.FindAvatarInParents(((ModularAvatarBlendshapeSync) target).transform)
.gameObject;
_window.OfferBinding += OfferBinding;
_window.Show();
}
2022-10-20 10:42:33 +08:00
private void OfferBinding(BlendshapeBinding binding)
{
foreach (var obj in targets)
{
var sync = (ModularAvatarBlendshapeSync) obj;
Undo.RecordObject(sync, "Adding blendshape binding");
if (!sync.Bindings.Contains(binding)) sync.Bindings.Add(binding);
EditorUtility.SetDirty(sync);
}
ClearSerializedObject();
InitList();
2022-10-20 10:42:33 +08:00
}
}
}