summaryrefslogtreecommitdiff
path: root/VRCSDK3AvatarsQuestLegacy/Assets/VRCSDK/SDK3A/Editor/Components3/VRCAvatarDescriptorEditor3AnimLayerGui.cs
blob: 07733285ad6c2ae4eb043ae3f6d753af8adddfad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#if VRC_SDK_VRCSDK3
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System.Collections.Generic;
using VRC.SDK3.Avatars.Components;
using System.Reflection;

public partial class AvatarDescriptorEditor3 : Editor
{

    SerializedProperty _baseAnimLayers { get { return serializedObject.FindProperty("baseAnimationLayers"); } }
    SerializedProperty _specialAnimLayers { get { return serializedObject.FindProperty("specialAnimationLayers"); } }
    SerializedProperty _doCustomizeAnimLayers { get { return serializedObject.FindProperty("customizeAnimationLayers"); } }

    Animator _animator
    {
        get
        {
            if (_cachedAnimator == null)
                _cachedAnimator = (target as Component).GetComponent<Animator>();
            return _cachedAnimator;
        }
    }
    private Animator _cachedAnimator = null;

    const float ANIM_LAYER_LIST_MARGIN = 5f;

    void DrawPlayableLayers()
    {
        if (Foldout("VRCSDK3_AvatarDescriptorEditor3_AnimationFoldout", "Playable Layers"))
        {
            if (_doCustomizeAnimLayers.boolValue)
            {
                if (GUILayout.Button("Reset to Default"))
                {
                    if (EditorUtility.DisplayDialog("Reset to Default", "This will erase any custom layer settings. Are you sure?", "OK", "Cancel"))
                    {
                        ResetAnimLayersToDefault();
                        _doCustomizeAnimLayers.boolValue = false;
                    }
                }

                DrawAnimLayerList("Base", _baseAnimLayers, Color.white);
                DrawAnimLayerList("Special", _specialAnimLayers, Color.black);

                GUILayout.Space(10);

                if (GUI.changed)
                    EnforceAnimLayerSetup();
            }
            else
            {
                if (GUILayout.Button("Customize"))
                {
                    ResetAnimLayersToDefault();
                    _doCustomizeAnimLayers.boolValue = true;
                }
            }

            Separator();
        }
    }

    void DrawLowerBodySettings()
    {
        if (_animator && _animator.isHuman)
        {
            if (Foldout("VRCSDK3_AvatarDescriptorEditor3_LowerBodyFoldout", "Lower Body"))
            {
                var autoFoot = serializedObject.FindProperty("autoFootsteps");
                var autoLoco = serializedObject.FindProperty("autoLocomotion");
                autoFoot.boolValue = EditorGUILayout.ToggleLeft("Use Auto-Footsteps for 3 and 4 point tracking", autoFoot.boolValue);
                autoLoco.boolValue = EditorGUILayout.ToggleLeft("Force Locomotion animations for 6 point tracking", autoLoco.boolValue);
            }

            Separator();
        }
    }

    void DrawAnimLayerList(string label, SerializedProperty list, Color boxColor, string buttonProperty = null)
    {
        BeginBox(label);

        bool isBaseLayer = (list.name == "baseAnimationLayers");
        bool isNonHumanBaseLayer = (isBaseLayer && (_animator && !_animator.isHuman));

        for (int v = 0; v < list.arraySize; v++)
        {
            SerializedProperty layer = list.GetArrayElementAtIndex(v);
            var type = layer.FindPropertyRelative("type");

            DrawAnimLayerListElement(" " + System.Enum.GetName(typeof(VRCAvatarDescriptor.AnimLayerType), type.enumValueIndex), layer, isNonHumanBaseLayer);
        }

        GUILayout.Space(10);

        EndBox();
    }

    void DeleteAnimLayers(SerializedProperty list, List<int> layersToDelete)
    {
        for (int v = (list.arraySize - 1); v > -1; v--)
        {
            if(layersToDelete.Contains(v))
                list.DeleteArrayElementAtIndex(v);
        }
    }

    // returns false if layer should be deleted
    bool DrawAnimLayerListElement(string label, SerializedProperty layer, bool isNonHumanBaseLayer = false)
    {
        bool keepLayer = true;

        GUILayout.BeginVertical();
        GUILayout.BeginHorizontal();
        GUILayout.Label(label, GUILayout.Width(100));

        var isDefault = layer.FindPropertyRelative("isDefault");
        var type = layer.FindPropertyRelative("type");
        var controller = layer.FindPropertyRelative("animatorController");

        if (isDefault.boolValue && !isNonHumanBaseLayer)
        {
            // set next control name & focus the button if pressed
            // (this is to reset 'Special' layer buttons to default if left empty in 'EnforceAnimLayerSetup')
            string buttonName = GetAnimLayerButtonName((VRCAvatarDescriptor.AnimLayerType)type.enumValueIndex);
            GUI.SetNextControlName(buttonName);
            if (GUILayout.Button(buttonName, GUILayout.MinWidth(0)))    // minwidth 0 prevents buttons from breaking margin on small inspector size
            {
                isDefault.boolValue = false;
                GUI.FocusControl(buttonName);
            }
        }
        else
        {
            float maxWidth = (Screen.width -170);   // ObjectField with SerializedProperty requires some scaling lore

            GUILayout.BeginHorizontal();
            Object prev = controller.objectReferenceValue;
            EditorGUILayout.ObjectField(controller, typeof(RuntimeAnimatorController), GUIContent.none, GUILayout.MaxWidth(maxWidth));
            if(controller.objectReferenceValue != prev)
                isDefault.boolValue = !controller.objectReferenceValue;
            GUILayout.EndHorizontal();
        }
        if (isDefault.boolValue)
            GUI.enabled = false;
        if (GUILayout.Button("x", EditorStyles.miniButton, GUILayout.Width(20)))
        {
            GUI.FocusControl(null); // resets 'Special' layer buttons to default if left empty in 'EnforceAnimLayerSetup'
            controller.objectReferenceValue = null;
            isDefault.boolValue = true;
        }
        GUI.enabled = true;
        GUILayout.EndHorizontal();
        GUILayout.EndVertical();

        return keepLayer;
    }

}
#endif