private void OnGUI()
        {
            var currentClip = _accessCommands.ActiveClip();

            GUILayout.BeginHorizontal();
            GUILayout.Box(_accessCommands.ActivePreview(), GUILayout.Width(StandardWidth), GUILayout.Height(StandardHeight));
            GUILayout.BeginVertical();

            GUILayout.BeginHorizontal();
            if (!_accessCommands.HasActiveClip())
            {
                EditorGUILayout.TextField("No animation selected.", GUILayout.ExpandWidth(true));
            }
            else
            {
                _currentClipAssetRename = EditorGUILayout.TextField(_currentClipAssetRename, GUILayout.ExpandWidth(true));
            }
            EditorGUI.BeginDisabledGroup(!_accessCommands.HasActiveClip() || _currentClipAssetRename == currentClip.name || File.Exists(NewPath(currentClip)));
            if (GUILayout.Button("Rename", GUILayout.Width(70)))
            {
                AssetDatabase.MoveAsset(AssetDatabase.GetAssetPath(currentClip), NewPath(currentClip));
            }
            EditorGUI.EndDisabledGroup();
            GUILayout.EndHorizontal();

            UiPreviewSetup();
            UiPreviewCamera();
            if (!_accessCommands.HasActiveClip())
            {
                return;
            }

            if (_accessCommands.AllPreviewSetups().Count > 0)
            {
                if (ColoredBackground(_accessCommands.IsMaintaining(), Color.green, () => GUILayout.Button("Preview animation in Scene")))
                {
                    _previewCommands.ToggleMaintainPreview();
                }

                EditorGUI.BeginDisabledGroup(!_accessCommands.IsMaintaining());
                var scenePreviewMode = (EeAnimationEditorScenePreviewMode)EditorGUILayout.EnumPopup("Scene previews", _accessCommands.GetScenePreviewMode());
                if (scenePreviewMode != _accessCommands.GetScenePreviewMode())
                {
                    _previewCommands.SetForcePreviewGeneration(scenePreviewMode);
                }
                EditorGUI.EndDisabledGroup();

                var dummy = _accessCommands.DummyNullable();
                EditorGUI.BeginDisabledGroup(!dummy.HasValue);
                if (GUILayout.Button("Select animator to edit Animation"))
                {
                    Selection.SetActiveObjectWithContext(dummy.Value.Dummy.gameObject, null);
                }
                EditorGUI.EndDisabledGroup();

                if (GUILayout.Button("Generate previews"))
                {
                    OnNewSweepRequested();
                }
            }

            GUILayout.EndVertical();
            GUILayout.EndHorizontal();

            _scrollPos = GUILayout.BeginScrollView(_scrollPos, GUILayout.Height(Screen.height - StandardHeight - EditorGUIUtility.singleLineHeight * 2));
            GUILayout.BeginHorizontal();

            var widthRun           = HalfWidth + TempBorder;
            var editableProperties = _accessCommands.Editables();

            for (var index = 0; index < editableProperties.Count; index++)
            {
                var editableProperty = editableProperties[index];
                GUILayout.BeginVertical();
                GUILayout.Box(editableProperty.BoundaryTexture, GUIStyle.none, GUILayout.Width(HalfWidth), GUILayout.Height(HalfHeight));
                var blendshapePrefix = "blendShape.";
                GUILayout.Label(editableProperty.Property.StartsWith(blendshapePrefix) ? editableProperty.Property.Substring(blendshapePrefix.Length) : editableProperty.Property, GUILayout.Width(HalfWidth));

                if (editableProperty.IsVaryingOverTime)
                {
                    GUILayout.Label($"(between {editableProperty.VaryingMinValue.ToString(CultureInfo.InvariantCulture)} and {editableProperty.Value.ToString(CultureInfo.InvariantCulture)})", GUILayout.Width(HalfWidth));
                }
                else
                {
                    var newValue = EditorGUILayout.Slider(editableProperty.Value, 0, 100, GUILayout.Width(HalfWidth));
                    if (newValue != editableProperty.Value)
                    {
                        _editCommands.UpdateBlendshape(editableProperty.Path, editableProperty.Property, newValue);
                    }
                }

                GUILayout.BeginHorizontal();
                GUILayout.Label("", GUILayout.ExpandWidth(true));
                GUILayout.Label(_accessCommands.GetBasedOnWhat(editableProperty.Property) != null ? "Based" : "", GUILayout.Width(40));
                if (GUILayout.Button("Delete", GUILayout.Width(StandardWidth / 5)))
                {
                    _editCommands.DeleteBlendshape(editableProperty.Path, editableProperty.Property);
                }
                GUILayout.EndHorizontal();
                GUILayout.EndVertical();

                widthRun += HalfWidth + TempBorder;
                if (Screen.width < widthRun)
                {
                    widthRun = HalfWidth + TempBorder;
                    GUILayout.FlexibleSpace();
                    GUILayout.EndHorizontal();
                    GUILayout.BeginHorizontal();
                }
            }

            if (GUILayout.Button("+", GUILayout.Width(HalfWidth / 2), GUILayout.Height(HalfHeight)))
            {
                EePropertyExplorerWindow.OpenEditor();
            }
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();

            var stats = _accessCommands.NonEditableStats();

            if (stats.SmrMimicBlendshapes.Count > 0)
            {
                GUILayout.Label($"{stats.SmrMimicBlendshapes.Count} reset blendshapes are not shown above.", EditorStyles.boldLabel);
                _foldoutMassEdit = EditorGUILayout.Foldout(_foldoutMassEdit, "Show/Delete reset blendshapes");
                if (_foldoutMassEdit)
                {
                    if (ColoredBackground(true, Color.red, () => GUILayout.Button("Delete 0-values")))
                    {
                        _editCommands.DeleteAllNeutralizedBlendshapes();
                    }

                    var smrToBlendshape = stats.SmrMimicBlendshapes
                                          .ToLookup(binding => binding.path, binding => binding.propertyName.Substring("blendShape.".Length))
                                          .ToDictionary(grouping => grouping.Key, grouping => grouping.ToList());
                    EditorGUILayout.HelpBox(string.Join("\n\n", smrToBlendshape.Select(pair => $"{pair.Key} ({pair.Value.Count}):\n{string.Join(", ", pair.Value)}").ToList()), MessageType.Info);
                }
            }
            if (stats.HasAnyOtherStats)
            {
                GUILayout.Label("This animation has additional properties not shown here:");
                LookupLabel(stats, EeNonEditableLookup.Transform, "transform-related");
                LookupLabel(stats, EeNonEditableLookup.Animator, "finger posing, other muscles, or Animator-related");
                LookupLabel(stats, EeNonEditableLookup.MaterialSwap, "material swaps");
                LookupLabel(stats, EeNonEditableLookup.Shader, "shader properties");
                LookupLabel(stats, EeNonEditableLookup.GameObjectToggle, "game object toggles");
                LookupLabel(stats, EeNonEditableLookup.Other, "other properties not cited above");
            }

            if (_isCgeInstalled)
            {
                if (stats.Quirk != EeQuirk.EmptyIssue && stats.Quirk != EeQuirk.FirstFrameIssue && stats.EffectiveFrameDuration > 1)
                {
                    GUILayout.Label($"This animation lasts {stats.EffectiveFrameDuration} keyframes.", EditorStyles.boldLabel);
                }
            }
            else
            {
                if (stats.Quirk != EeQuirk.EmptyIssue && stats.EffectiveFrameDuration > 1)
                {
                    GUILayout.Label($"This animation lasts {stats.EffectiveFrameDuration} keyframes.", EditorStyles.boldLabel);
                }
                switch (stats.Quirk)
                {
                case EeQuirk.EmptyIssue:
                    EditorGUILayout.HelpBox($"This animation is empty. This will cause the animation to last {stats.EffectiveFrameDuration} keyframes.", MessageType.Warning);
                    break;

                case EeQuirk.FirstFrameIssue:
                    EditorGUILayout.HelpBox($"All of the keyframes are located on frame 0. This will cause the animation to last {stats.EffectiveFrameDuration} keyframes.", MessageType.Warning);
                    break;

                case EeQuirk.OneFrame:
                case EeQuirk.MoreThanOneFrame:
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            if (editableProperties.Any(info => info.IsVaryingOverTime))
            {
                EditorGUILayout.HelpBox("This animation contains blendshapes that are animated differently over time.\nThey cannot be edited in Expressions Editor. Preview may not be accurate.", MessageType.Info);
            }

            var clipName = _accessCommands.ActiveClip().name;

            if (clipName.Contains("Autogenerated") || clipName.Contains("DO_NOT_EDIT"))
            {
                EditorGUILayout.HelpBox("This animation is likely auto-generated and may be overwritten at any time. You should probably not edit it.", MessageType.Error);
            }

            #if VRC_SDK_VRCSDK3
            if (editableProperties.Any(info => info.Property.ToLowerInvariant().StartsWith("blendshape.vrc.v_")))
            {
                EditorGUILayout.HelpBox("This animation animates blendshapes that begin with vrc.v_, usually designed for Visemes.\nIf any animation contains those, the mouth may not animate properly.", MessageType.Warning);
            }
            if (editableProperties.Any(info => info.Property.ToLowerInvariant().Equals("blendshape.blink")))
            {
                EditorGUILayout.HelpBox("This animation animates a blendshape called Blink, usually selected to make the avatar blink automatically.\nIf any animation contains it, the avatar may not blink properly.\nMany avatar bases have blendshapes to close each eye separately; they should be used instead.", MessageType.Warning);
            }
            #endif

            GUILayout.EndScrollView();
        }
예제 #2
0
        private void OnGUI()
        {
            var e = Event.current;

            if (e != null && e.type == EventType.KeyDown && e.keyCode == KeyCode.Space)
            {
                _hotspotMode = !_hotspotMode;
                Repaint();
            }

            GUILayout.BeginHorizontal();
            GUILayout.BeginVertical();
            _hotspotMode = GUILayout.Toggle(_hotspotMode, "Show Hotspots (press SPACE key)");

            if (GUILayout.Button("Generate previews"))
            {
                OnNewScanRequested();
            }

            _foldoutMoreTools = EditorGUILayout.Foldout(_foldoutMoreTools, "Other tools");
            if (_foldoutMoreTools)
            {
                GUILayout.BeginHorizontal();
                GUILayout.Space(20);
                if (EeAnimationEditorWindow.ColoredBackground(_basedOnSomethingElseMode, Color.green, () => GUILayout.Button("Fix Tooth and other hidden blendshapes")))
                {
                    _basedOnSomethingElseMode = !_basedOnSomethingElseMode;
                }
                GUILayout.Space(20);
                GUILayout.EndHorizontal();
            }

            GUILayout.EndVertical();
            GUILayout.EndHorizontal();

            _scrollPos = GUILayout.BeginScrollView(_scrollPos, GUILayout.Height(Screen.height - EditorGUIUtility.singleLineHeight * 6));
            GUILayout.BeginHorizontal();

            var widthRun = HalfWidth + TempBorder;
            var smrBlendShapeProperties     = _accessCommands.SmrBlendShapeProperties() ?? new List <EeExplorerBlendshape>();
            var activeCouldDeleteValidables = _accessCommands.AllCurveBindingsCache();
            var nonResetBlendshapes         = _accessCommands.AllNonResetBlendshapes(_accessCommands.AllCurveBindingsCache());

            foreach (var info in smrBlendShapeProperties)
            {
                GUILayout.BeginVertical();
                GUILayout.Box(_hotspotMode ? info.HotspotTexture : info.BoundaryTexture, GUIStyle.none, GUILayout.Width(HalfWidth), GUILayout.Height(HalfHeight));
                GUILayout.Label(info.Property.StartsWith(BlendshapePrefix) ? info.Property.Substring(BlendshapePrefix.Length) : info.Property, GUILayout.Width(HalfWidth));

                GUILayout.BeginHorizontal();
                var onWhat = _accessCommands.GetBasedOnWhat(info.Property);
                if (!IsInBasedOnSomethingElseMode())
                {
                    EditorGUI.BeginDisabledGroup(!_accessCommands.HasActiveClip());
                    var blendshapeExistsAndIsNotReset = _accessCommands.ActiveHas(nonResetBlendshapes, info.Path, info.Property);
                    EditorGUI.BeginDisabledGroup(blendshapeExistsAndIsNotReset);
                    if (GUILayout.Button("+", GUILayout.ExpandWidth(true)))
                    {
                        _editCommands.AddBlendshape(info.Path, info.Property);
                    }
                    EditorGUI.EndDisabledGroup();

                    var blendshapeIsRemovable = _accessCommands.ActiveCouldDelete(activeCouldDeleteValidables, info.Path, info.Property);
                    EditorGUI.BeginDisabledGroup(!blendshapeIsRemovable);
                    if (EeAnimationEditorWindow.ColoredBackground(blendshapeIsRemovable, !blendshapeExistsAndIsNotReset ? Color.yellow : Color.red, () => GUILayout.Button("-", GUILayout.ExpandWidth(true))))
                    {
                        _editCommands.DeleteBlendshape(info.Path, info.Property);
                    }
                    EditorGUI.EndDisabledGroup();
                    EditorGUI.EndDisabledGroup();

                    if (onWhat != null)
                    {
                        EditorGUI.BeginDisabledGroup(true);
                        GUILayout.Label("Based", GUILayout.Width(40));
                        EditorGUI.EndDisabledGroup();
                    }
                }
                else
                {
                    if (onWhat != null)
                    {
                        EditorGUI.BeginDisabledGroup(true);
                        GUILayout.TextField(onWhat.Substring(BlendshapePrefix.Length), GUILayout.ExpandWidth(true));
                        EditorGUI.EndDisabledGroup();
                        if (EeAnimationEditorWindow.ColoredBackground(true, Color.red, () => GUILayout.Button("Forget", GUILayout.Width(70))))
                        {
                            _editCommands.DeleteBasedSubject(info.Property);
                        }
                    }
                    else
                    {
                        var isSelected = _basedOnSomethingElseSelection.Contains(info.Property);
                        EditorGUI.BeginDisabledGroup(_accessCommands.IsOnWhat(info.Property));
                        if (EeAnimationEditorWindow.ColoredBackground(isSelected, Color.green, () => GUILayout.Button("Select", GUILayout.Width(70))))
                        {
                            if (isSelected)
                            {
                                _basedOnSomethingElseSelection.Remove(info.Property);
                            }
                            else
                            {
                                _basedOnSomethingElseSelection.Add(info.Property);
                            }
                        }
                        EditorGUI.EndDisabledGroup();
                        EditorGUI.BeginDisabledGroup(isSelected || _basedOnSomethingElseSelection.Count == 0);
                        if (GUILayout.Button("Assign"))
                        {
                            _editCommands.AssignBased(info.Property, _basedOnSomethingElseSelection.ToList());
                            _basedOnSomethingElseSelection.Clear();
                            _basedOnSomethingElseMode = false;
                        }
                        EditorGUI.EndDisabledGroup();
                    }
                }
                GUILayout.EndHorizontal();
                GUILayout.EndVertical();

                widthRun += HalfWidth + TempBorder;
                if (Screen.width < widthRun)
                {
                    widthRun = HalfWidth + TempBorder;
                    GUILayout.FlexibleSpace();
                    GUILayout.EndHorizontal();
                    GUILayout.BeginHorizontal();
                }
            }

            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();
            GUILayout.EndScrollView();
        }