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(); }
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(); }