using FIMSpace.FEditor; using System; using System.Collections.Generic; using UnityEditor; using UnityEditor.Callbacks; using UnityEngine; namespace FIMSpace.AnimationTools { // ------------------------------------------------- // // OPEN ANIMATION DESIGNER WINDOW BY CLICKING // Window/Fimpossible Creations/ Animation Designer Window // // ------------------------------------------------- public partial class AnimationDesignerWindow : EditorWindow { public static AnimationDesignerWindow Get; public bool EnableExperimentalUndo = false; /// Assign through script inspector window public UnityEngine.Object BaseDirectory; public UnityEngine.Object ModuleSetupsDirectory; public UnityEngine.Object CustomModuleScriptFilesDirectory; [MenuItem("Window/FImpossible Creations/Animation Designer Window", false, 221)] #region Initialize and show window public static void Init() { AnimationDesignerWindow window = (AnimationDesignerWindow)GetWindow(typeof(AnimationDesignerWindow)); window.titleContent = new GUIContent("ADesigner", Resources.Load("AnimationDesigner/SPR_ADes32"), "Animation Designer Window"); // other Icons: "BuildSettings.Android" "Grid.MoveTool@2x" "Preset.Context@2x" "AnimatorState Icon" "BlendTree Icon" d_BlendTree Icon "d_NavMeshAgent Icon" "Animator Icon" window.Show(); Rect p = window.position; if (p.size.x < 340) { p.size = new Vector2(340, p.height); } if (p.size.y < 550) p.size = new Vector2(p.size.x, 550); window.position = p; Get = window; } #endregion #region Open File with double click - open designer window [OnOpenAssetAttribute(1)] public static bool OpenDesignerScriptableFile(int instanceID, int line) { UnityEngine.Object obj = EditorUtility.InstanceIDToObject(instanceID); if (obj is AnimationDesignerSave) { if (Get == null) Init(); else Get.Focus(); Get.SetSetup(obj as AnimationDesignerSave); Get.Repaint(); return true; } return false; } internal void SetSetup(AnimationDesignerSave setup) { ProjectFileSave = setup; } public static bool ContainsProjectFileSave() { if (Get == null) return false; return Get.ProjectFileSave != null; } #endregion #region Saves Related #if UNITY_2019_4_OR_NEWER public static Texture _FolderDir { get { if (__folderdir != null) return __folderdir; __folderdir = EditorGUIUtility.IconContent("d_Folder Icon").image; return __folderdir; } } private static Texture __folderdir = null; #else public static Texture _FolderDir { get { if (__folderdir != null) return __folderdir; __folderdir = EditorGUIUtility.IconContent("Folder Icon").image; return __folderdir; } } private static Texture __folderdir = null; #endif private SerializedObject so_currentSetup = null; private ScriptableObject wasChecked = null; private bool isInDefaultDirectory = false; protected AnimationDesignerSave ProjectFileSave = null; protected AnimationDesignerSave _latest_ProjectFileSave = null; protected AnimationDesignerSave DisplaySave = null; protected AnimationDesignerSave _latest_DisplaySave = null; protected AnimationDesignerSave TempSave = null; #endregion #region Main Utility RuntimeAnimatorController originalAnimatorController = null; int latestFilesInDraft = 0; DateTime latestDraftsCheckTime = new DateTime(); float _reloadingAlpha = 0.2f; float _hourglassAlpha = 1f; public bool IsVisible { get; protected set; } void OnBecameVisible() { IsVisible = true; Get = this; } void OnBecameInvisible() { if (currentMecanim) currentMecanim.runtimeAnimatorController = originalAnimatorController; if (S) ForceTPose(); IsVisible = false; } void CheckDraftsFoldersForFileCount(bool hard = false) { if (!hard) if (DateTime.Now.Subtract(latestDraftsCheckTime).TotalSeconds < 20) return; if (BaseDirectory == null) return; string path = AssetDatabase.GetAssetPath(BaseDirectory); var files = System.IO.Directory.GetFiles(path, "*.asset"); if (files != null) latestFilesInDraft = files.Length; latestDraftsCheckTime = DateTime.Now; } private void OnEnable() { Get = this; CheckDraftsFoldersForFileCount(); EditorPrefs.SetFloat("FimpAutoSaveTime", 0); } protected Color preBG; protected Color preGuiC; #endregion #region Prepare Scene GUI Draw bool wasSceneRepaint = false; void OnFocus() { #if UNITY_2019_1_OR_NEWER SceneView.duringSceneGui -= this.OnSceneGUI; SceneView.duringSceneGui += this.OnSceneGUI; #else SceneView.onSceneGUIDelegate -= this.OnSceneGUI; SceneView.onSceneGUIDelegate += this.OnSceneGUI; #endif } void OnDestroy() { if (S) { if (currentMecanim) currentMecanim.runtimeAnimatorController = originalAnimatorController; ForceTPose(); S.DampSessionSkeletonReferences(); } #if UNITY_2019_1_OR_NEWER SceneView.duringSceneGui -= this.OnSceneGUI; #else SceneView.onSceneGUIDelegate -= this.OnSceneGUI; #endif } void OnSceneGUI(SceneView sceneView) { wasSceneRepaint = true; // Forcing GUI repaint when fading animation if (_reloadingAlpha < 0.99f) { Repaint(); } if (SceneView.currentDrawingSceneView == null) return; if (SceneView.currentDrawingSceneView.camera == null) return; if (!IsVisible) return; //if (focusedWindow != Get && (focusedWindow is SceneView == false)) return; if (DisplaySave == null) return; S.UpdateReferences(); Handles.BeginGUI(); DrawScreenGUI(); Handles.EndGUI(); Handles.BeginGUI(); Handles.SetCamera(SceneView.currentDrawingSceneView.camera); DrawHandles(SceneView.currentDrawingSceneView.camera); Handles.matrix = Matrix4x4.identity; Handles.EndGUI(); } #endregion internal AnimationClip TargetClip; private AnimationClip _latestClip = null; internal AnimationClip LatestSaved; bool IsReady { get { return (S != null && S.Armature != null && S.Armature.BonesSetup.Count > 0 && S.Armature.BonesSetup[0].TempTransform != null); } } bool isReady = false; public AnimationDesignerSave S { get { return DisplaySave; } } public ADArmatureSetup Ar { get { return S.Armature; } } List Limbs { get { return DisplaySave.Limbs; } } Transform latestAnimator = null; Animator currentMecanim = null; public Animator GetMecanim { get { return currentMecanim; } } Animation currentLegacy = null; bool repaintRequest = false; bool restoredTPose = true; bool sectionFocusMode = false; /// Extra animator character on which we can preview different animation clip in sync with animation designer clip time Transform latestSecondaryAnimator = null; AnimationClip latestSecondaryAnimatorClip = null; Vector2 scroll = Vector2.zero; bool _serializationChanges = false; AnimationDesignerSave _toSet_ProjectFileSave = null; AnimationDesignerSave _toSet_TriedReloadWith = null; Avatar _toSet_triedLoadFromDrafts = null; bool _toSet_ProjectFileSave_Clear = false; //string _toSet_AdditionalDesignerSetSwitchTo = ""; public static int _toSet_SetSwitchToHash = 0; public static int _last_toSet_SetSwitchToHash = 0; //int _toSet_ProjectFileSaveDelay = 0; bool _triggerSkeletonRefresh = false; bool _switchingReferences = false; bool _showTip1 = true; GUIStyle _style_horScroll = null; GUIStyle _style_vertScroll = null; Animation selectionLegacyAnimation = null; Animation latestLegacyAnimationComponent = null; public Transform AnimatorTransform { get { if (latestAnimator) return latestAnimator.transform; if (latestLegacyAnimationComponent) return latestLegacyAnimationComponent.transform; return null; } } private void OnGUI() { #region Check for auto-save bool isAutoSave = EditorPrefs.GetInt("FimpAutoSave", 0) == 1; if (isAutoSave) { float lastAutoSaveIn = EditorPrefs.GetFloat("FimpAutoSaveTime", 0); float currentSaveTime = (float)EditorApplication.timeSinceStartup; if ( currentSaveTime - lastAutoSaveIn > 180f) { AssetDatabase.SaveAssets(); EditorPrefs.SetFloat("FimpAutoSaveTime", currentSaveTime); //UnityEngine.Debug.Log("saved"); } } #endregion #region Initial GUI Defines if (currentMecanim) { if (currentMecanim.runtimeAnimatorController != null) { if (currentMecanim.GetLayerName(0) != "0") { originalAnimatorController = currentMecanim.runtimeAnimatorController; } } } if (isBaking) { GUILayout.Space(4); EditorGUILayout.HelpBox("Animation Baking in progress!", MessageType.Warning); GUILayout.Space(10); return; } bool isLayoutEvent = false; //bool isRepaintEvent = false; if (Event.current != null) { if (Event.current.type == EventType.Layout) isLayoutEvent = true; //else if (Event.current.type == EventType.Repaint) isRepaintEvent = true; } if (isLayoutEvent) { UseEditorEvents(); _serializationChanges = false; _switchingReferences = false; } if (_style_horScroll == null) { _style_horScroll = GUI.skin.horizontalScrollbar; _style_vertScroll = new GUIStyle(GUI.skin.verticalScrollbar); _style_vertScroll.fixedWidth = 5; } #endregion #region Scene View Check if (SceneView.lastActiveSceneView == null) { GUILayout.Space(4); EditorGUILayout.HelpBox("NO SCENE VIEW! ANIMATION DESIGNER REQUIRES ACTIVE SCENE VIEW!", MessageType.Warning); GUILayout.Space(10); } #endregion #region Animation Component Check selectionLegacyAnimation = null; if (Selection.activeGameObject) { selectionLegacyAnimation = Selection.activeGameObject.GetComponent(); if (selectionLegacyAnimation != null) latestLegacyAnimationComponent = selectionLegacyAnimation; //if (currentAnimation) //{ // GUILayout.Space(5); // EditorGUILayout.HelpBox("'ANIMATION' component is selected. It's recommended to use 'ANIMATOR' component instead of ANIMATION since ANIMATOR provides much more features for the Animation Designer.\n\nWhen working with GENERIC rig, Animation Designer gives possibility to export animation as Legacy Animation Clip!", MessageType.Info); // GUILayout.Space(5); //} //else //{ //} } else { currentLegacy = null; } #endregion #region Isolated mode check #if UNITY_2020_1_OR_NEWER GameObject targetObj = Selection.activeGameObject; if (latestAnimator) targetObj = latestAnimator.gameObject; if (targetObj) { if (UnityEditor.SceneManagement.EditorSceneManager.IsPreviewScene(targetObj.scene)) { GUILayout.Space(10); EditorGUILayout.HelpBox(" Detected Prefab Isolated Mode!\nAnimation Designer works only on the Scene view!", MessageType.Info); GUILayout.Space(10); return; } } #else #if UNITY_2019_4_OR_NEWER if (UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage() != null) { GUILayout.Space(10); EditorGUILayout.HelpBox(" Detected Prefab Isolated Mode!\nAnimation Designer works only on the Scene view!", MessageType.Info); GUILayout.Space(10); return; } #endif #endif #endregion #region Triggering Sheduled Events if (isLayoutEvent) { if (_Trigger_SoftPrepareArmature) { S.GatherBones(); _Trigger_SoftPrepareArmature = false; _serializationChanges = true; } if (_Trigger_PrepareArmature) { S.GetArmature(); repaintRequest = true; S._SetDirty(); _Trigger_PrepareArmature = false; _serializationChanges = true; } //if (so_currentSetup != null) //{ // SerializedProperty prop = so_currentSetup.GetIterator(); // if (prop.NextVisible(true)) // { // do // { // EditorGUILayout.PropertyField(so_currentSetup.FindProperty(prop.name), true); // } while (prop.NextVisible(false)); // } // so_currentSetup.ApplyModifiedProperties(); //} } #endregion #region Define data to display if (_latestClip != TargetClip) { _latestClip = TargetClip; OnTargetAnimationClipChange(); } if (TargetClip != null) if (currentClipSettings == null) GetTargetClipSettings(); if (_last_toSet_SetSwitchToHash != _toSet_SetSwitchToHash) { _last_toSet_SetSwitchToHash = _toSet_SetSwitchToHash; OnTargetAnimationClipChange(); } // Assigning Designer Save to view through layout event // To avoid annoying Unity events about controls repaint if (isLayoutEvent) if (_toSet_ProjectFileSave != null || _toSet_ProjectFileSave_Clear) { // Can't find a way to fix 'ArgumentException: Getting control 1's position in a group with only 1 controls when doing repaint' // Error when switching between different presets... So many hours wasted, DISAPPOINTEED! if (_toSet_ProjectFileSave_Clear) ProjectFileSave = null; else ProjectFileSave = _toSet_ProjectFileSave; _toSet_ProjectFileSave_Clear = false; _toSet_ProjectFileSave = null; _serializationChanges = true; } // Defining with object scene selection if (Selection.activeGameObject != null) { // Checking if selected scene object or project file // Not supporting working with project assets if (AssetDatabase.Contains(Selection.activeGameObject) == false) { // Getting animator out of current selected game object Animator cAnim = Selection.activeGameObject.GetComponent(); Transform animTr = Selection.activeGameObject.transform; if (cAnim || selectionLegacyAnimation) { // When no project file is selected - we set priority to edit just current selected object if (ProjectFileSave == null) { #region Searching drafts for DesignerSave fitting with current animator avatar if (cAnim) { if (_toSet_triedLoadFromDrafts != cAnim.avatar) { _toSet_triedLoadFromDrafts = cAnim.avatar; if (BaseDirectory) { string path = AssetDatabase.GetAssetPath(BaseDirectory); var files = System.IO.Directory.GetFiles(path, "*.asset"); if (files != null) for (int i = 0; i < files.Length; i++) { AnimationDesignerSave fs = AssetDatabase.LoadAssetAtPath(files[i]); if (fs) if (fs.TargetAvatar == cAnim.avatar) { _foundFittingSave = fs; //AddEditorEvent(() => //{ // ProjectFileSave = fs; // if (fs.LatestCorrect) TargetClip = fs.LatestCorrect; //}); break; } } } } } #endregion if (ProjectFileSave == null) { TempSave = GetTempSaveFor(animTr); DisplaySave = TempSave; if (_latest_DisplaySave != DisplaySave) _serializationChanges = true; _latest_DisplaySave = DisplaySave; latestAnimator = animTr; } } // Project file set or changed with lines above if (ProjectFileSave != null) { Avatar selAv = animTr.GetAvatar(); if (selAv == ProjectFileSave.TargetAvatar) // Selecting Object with same avatar { if (ProjectFileSave.LatestAnimator == animTr) { if (ProjectFileSave != _toSet_TriedReloadWith) { _toSet_TriedReloadWith = ProjectFileSave; if (S.Armature.BonesSetup.Count == 0 || S.Armature.BonesSetup[0].TempTransform == null) { _triggerSkeletonRefresh = true; } } } else // Other Animator but same Avatar { if (animTr != latestAnimator) // Different latest animator - retarget to new active game object required { DrawFocusOnCurrentAnimatorButton(); GUILayout.Space(4); GUI.backgroundColor = Color.green; EditorGUILayout.BeginHorizontal(); EditorGUILayout.HelpBox("Selecting object with different animator! Should Animation Designer Retarget to '" + animTr.name + "' ?", MessageType.None); if (GUILayout.Button("Switch", GUILayout.Height(28))) { AddDampReferencesEvent(true); FrameTarget(animTr.gameObject); } EditorGUILayout.EndHorizontal(); GUI.backgroundColor = preBG; } else // Same latest animator { DrawFocusOnCurrentAnimatorButton(); GUILayout.Space(4); GUI.backgroundColor = Color.green; EditorGUILayout.BeginHorizontal(); EditorGUILayout.HelpBox("Selecting object with different animator! Should Animation Designer Switch to '" + animTr.name + "' ?", MessageType.None); if (GUILayout.Button("Switch", GUILayout.Height(28))) { AddDampReferencesEvent(true); AddEditorEvent(() => { TempSave = GetTempSaveFor(animTr); DisplaySave = TempSave; _latest_DisplaySave = DisplaySave; latestAnimator = animTr.transform; { //ProjectFileSave.DampSessionSkeletonReferences(); //_switchingReferences = true; //ProjectFileSave = null; //TempSave = GetTempSaveFor(cAnim); //DisplaySave = TempSave; //_latest_DisplaySave = DisplaySave; //latestAnimator = cAnim; //_toSet_triedLoadFromDrafts = null; //_serializationChanges = true; } }); FrameTarget(animTr.gameObject); } EditorGUILayout.EndHorizontal(); GUI.backgroundColor = preBG; } } } else // Different Avatars! { DrawFocusOnCurrentAnimatorButton(); GUILayout.Space(4); GUI.backgroundColor = Color.green; EditorGUILayout.BeginHorizontal(); EditorGUILayout.HelpBox("Selecting object with different animator! Should Animation Designer Switch to '" + animTr.name + "' ?", MessageType.None); if (GUILayout.Button("Switch", GUILayout.Height(28))) { ProjectFileSave = null; TempSave = GetTempSaveFor(animTr); DisplaySave = TempSave; _latest_DisplaySave = DisplaySave; latestAnimator = animTr.transform; _serializationChanges = true; FrameTarget(animTr.gameObject); } EditorGUILayout.EndHorizontal(); GUI.backgroundColor = preBG; } } else { _toSet_TriedReloadWith = null; } } // If Animator != null END ----- } else { EditorGUILayout.HelpBox("Selecting Project Asset. Please select Scene Object", MessageType.None); } } else // Not selecting Anything { DrawFocusOnCurrentAnimatorButton(); } // When project file designer save preset changed // we trigger few operations to refresh serialized object if (ProjectFileSave != null) { if (_latest_ProjectFileSave != ProjectFileSave) { if (_latest_ProjectFileSave != null) _latest_ProjectFileSave.DampSessionSkeletonReferences(); if (isLayoutEvent == false) { DisplaySave = ProjectFileSave; if (latestAnimator) if (DisplaySave.TargetAvatar == null) DisplaySave.TargetAvatar = latestAnimator.GetAvatar(); if (_latest_DisplaySave != DisplaySave) _serializationChanges = true; _latest_DisplaySave = DisplaySave; _latest_ProjectFileSave = ProjectFileSave; } } } if (so_currentSetup != null) if (so_currentSetup.targetObject != null) so_currentSetup.Update(); // Generating serialized object to display properties if required if (DisplaySave != null) { if (so_currentSetup == null || so_currentSetup.targetObject != DisplaySave) { so_currentSetup = new SerializedObject(DisplaySave); _serializationChanges = true; } } if (_switchingReferences == false) if (_serializationChanges == false) if (S != null) S.RefreshSkeleton(latestAnimator); if (latestAnimator) { bool checkMec = true; bool checkLegac = true; currentLegacy = null; if (currentMecanim) if (currentMecanim.transform == latestAnimator) { checkMec = false; checkLegac = false; } if (currentLegacy) if (currentLegacy.transform == latestAnimator) { checkMec = false; checkLegac = false; } if (checkMec) currentMecanim = latestAnimator.GetAnimator(); if (checkLegac) if (currentMecanim == null) currentLegacy = latestAnimator.GetComponent(); } #endregion #region Initial GUI Colors and Fading Animation if (_serializationChanges || _switchingReferences) _reloadingAlpha = 0.001f; Color _origGuiC = GUI.color; Color _origGuiBC = GUI.backgroundColor; preGuiC = new Color(_origGuiC.r, _origGuiC.g, _origGuiC.b, _reloadingAlpha); preBG = new Color(_origGuiBC.r, _origGuiBC.g, _origGuiBC.b, _reloadingAlpha); _reloadingAlpha += 0.1f; if (_reloadingAlpha < 0.94f) { if (Event.current != null) if (Event.current.type == EventType.MouseDown) Event.current.Use(); } else if (_reloadingAlpha > 1f) _reloadingAlpha = 1f; #endregion // #region Unity Editor Version Related IFDEFS #if UNITY_2019_4_OR_NEWER #else try { #endif #endregion EditorGUIUtility.wideMode = true; scroll = GUILayout.BeginScrollView(scroll, GUIStyle.none, GUIStyle.none); GUILayout.Space(3); DisplaySaveHeaderTab(); if (latestAnimator == null) { if (!_serializationChanges) { EditorGUILayout.HelpBox("Select some scene object with Animator to start working on it", MessageType.Info); #region Tip Image for Inspector Window GUILayout.Space(14); if (_showTip1) if (_Tex_Tip1 != null) { GUI.color = new Color(1f, 1f, 1f, preGuiC.a * 0.7f); float tipWidth = position.width - 18; float tipHeight = tipWidth * ((float)_Tex_Tip1.height / (float)_Tex_Tip1.width); Rect tipRect = EditorGUILayout.GetControlRect(); tipRect.position += new Vector2(4, 0); tipRect.width = tipWidth * 0.85f; tipRect.height = tipHeight * 0.85f; GUI.DrawTexture(tipRect, _Tex_Tip1, ScaleMode.ScaleToFit); GUI.color = new Color(1f, 1f, 1f, preGuiC.a * 0.01f); if (GUI.Button(tipRect, GUIContent.none)) { _showTip1 = false; } GUI.color = preGuiC; } #endregion } } else // Else - Displaying Designer Window { if (_serializationChanges) { // For some reason this helpbox wasa causing GUI error //EditorGUILayout.HelpBox("Reloading some data, move cursor here to refresh display", MessageType.Info); } else // MAIN GUI BLOCK START { #region Header Panel with Object Title and Foldout GUILayout.Space(4); EditorGUILayout.BeginVertical(FGUI_Resources.HeaderBoxStyle); EditorGUILayout.BeginHorizontal(GUILayout.Height(24)); GUILayout.Space(4); if (sectionFocusMode) { GUILayout.Space(52); } else { if (isReady) { EditorGUILayout.BeginVertical(); GUILayout.Space(4); if (GUILayout.Button(new GUIContent(FGUI_Resources.GetFoldSimbol(debugTabFoldout, true)), EditorStyles.boldLabel, GUILayout.Width(20))) debugTabFoldout = !debugTabFoldout; EditorGUILayout.EndVertical(); } } GUILayout.FlexibleSpace(); if (GUILayout.Button(latestAnimator.gameObject.name, FGUI_Resources.HeaderStyleBig)) if (isReady) { debugTabFoldout = !debugTabFoldout; sectionFocusMode = false; } GUILayout.FlexibleSpace(); if (isReady) { //if (sectionFocusMode) { GUILayout.Space(2); DrawPlaybackButton(); GUILayout.Space(6); } FocusModeSwitchButton(); GizmosModsButton(); } GizmosSwitchButton(); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); #endregion if (sectionFocusMode) { debugTabFoldout = false; updateDesigner = true; } // Framing Designer GUI EditorGUILayout.BeginVertical(FGUI_Resources.BGInBoxBlankStyle); if (S != null && so_currentSetup != null && so_currentSetup.targetObject != null) { if (_triggerSkeletonRefresh) { RefreshArmatureSaveAndSkeletonSetup(); _triggerSkeletonRefresh = false; } // Initial display operations isReady = IsReady; RefreshSave(); ValidateSkeleton(); #region Playback tools and Top Refresh Buttons if (sectionFocusMode == false) { if (latestAnimator) { if (latestAnimator.UsingRootMotion()) { GUILayout.Space(-4); EditorGUILayout.HelpBox("Enabled Root Motion on the Animator can cause changing position of your model on the scene to zero position!", MessageType.None); GUILayout.Space(-1); } } DrawBaseToolsTab(); if (isReady) { GUILayout.Space(12); DrawPlaybackTab(); GUILayout.Space(8); } } else { if (latestAnimator.IsHuman()) { if (!TargetClip.isHumanMotion) sectionFocusMode = false; } else if (TargetClip.isHumanMotion) sectionFocusMode = false; //GUILayout.Space(4); if (!IsReady) RefreshArmatureButton(26); else { EditorGUILayout.BeginHorizontal(); DrawPlaybackStopButton(); DrawPlaybackButton(); GUILayout.Space(6); DrawPlaybackTimeSlider(); EditorGUILayout.EndHorizontal(); } } #endregion if (!isReady) // If skeleton/armature is not prepared { GUILayout.Space(8); EditorGUILayout.HelpBox("First Prepare Your Character Model Armature", MessageType.Info); GUILayout.Space(20); #region Main Info Tooltip Switch and View if (_utilTip_displayArmSetupInfo) GUI.color = new Color(0.6f, 0.6f, 0.6f, 1f); if (GUILayout.Button(new GUIContent(FGUI_Resources.Tex_Info), FGUI_Resources.ButtonStyle, GUILayout.Width(20), GUILayout.Height(18))) _utilTip_displayArmSetupInfo = !_utilTip_displayArmSetupInfo; GUI.color = preGuiC; if (_utilTip_displayArmSetupInfo) EditorGUILayout.HelpBox("\nModel Armature is set of bone transforms of your character/creature model.\n\nIn addition you can prepare 'Limbs' setups of the Armature, which can be used for some additional and very helpful animation motion.\n\nHumanoid rigs are prepared automatically but you can tweak additional limbs after automatic generating if required.\n\nGeneric Rigs can be setted up automatically but it needs review to check if automatic setup done it properly.\nDo it in 'Setup' category - the button with Gear icon which will appear after doing initial setup.\n ", MessageType.Info); #endregion #region Currently Selected Animator Type Info Buttons if (latestAnimator) { if (latestAnimator.IsHuman()) { GUI.color = new Color(.7f, 1f, 0.7f, 1f); GUILayout.Space(10); if (GUILayout.Button("Detected Humanoid Rig", FGUI_Resources.HeaderStyle, GUILayout.Height(20))) RefreshArmatureSaveAndSkeletonSetup(); GUILayout.Space(4); GUI.color = preGuiC; if (S.Armature.BonesSetup.Count == 0) { if (GUILayout.Button("Algorithm will prepare automatic setup\nfor the Armature!", EditorStyles.centeredGreyMiniLabel, GUILayout.Height(30))) RefreshArmatureSaveAndSkeletonSetup(); } else { if (GUILayout.Button("Click to refresh your\nArmature Setup!", EditorStyles.centeredGreyMiniLabel, GUILayout.Height(30))) RefreshArmatureSaveAndSkeletonSetup(); } } else { GUILayout.Space(10); if (currentLegacy) { GUI.color = new Color(0.7f, 0.8f, 0.9f, 1f); if (GUILayout.Button("Detected Legacy Rig", FGUI_Resources.HeaderStyle, GUILayout.Height(20))) RefreshArmatureSaveAndSkeletonSetup(); } else { GUI.color = new Color(1f, 0.7f, 0.5f, 1f); if (GUILayout.Button("Detected Generic Rig", FGUI_Resources.HeaderStyle, GUILayout.Height(20))) RefreshArmatureSaveAndSkeletonSetup(); } GUILayout.Space(4); GUI.color = preGuiC; if (S.Armature.BonesSetup.Count == 0) { if (GUILayout.Button("Algorithm will try setup limbs automatically\nbut please review it manually!", EditorStyles.centeredGreyMiniLabel, GUILayout.Height(30))) RefreshArmatureSaveAndSkeletonSetup(); } else { if (GUILayout.Button("Click to refresh your\nArmature Setup!", EditorStyles.centeredGreyMiniLabel, GUILayout.Height(30))) RefreshArmatureSaveAndSkeletonSetup(); } } } GUI.color = preGuiC; #endregion #region Tutorials Buttons GUILayout.Space(60); GUI.color = new Color(1f, 1f, 1f, 0.75f); GUI.backgroundColor = new Color(1f, 1f, 1f, 0.35f); EditorGUILayout.BeginHorizontal(); GUILayout.Space(40); if (GUILayout.Button(new GUIContent(" Having Troubles? Check Tutorials!", FGUI_Resources.Tex_Tutorials), GUILayout.Height(28))) { Application.OpenURL("https://www.youtube.com/watch?v=Q2ruYQNPHGg&list=PL6MURe5By90n1VWe-Ezs9trtl8KeQennl"); } GUILayout.Space(40); EditorGUILayout.EndHorizontal(); #endregion // Resore Colors GUI.backgroundColor = preBG; GUI.color = preGuiC; } else // Skeleton Ready - View Designer Categories { DrawCategoriesTab(); } // Draw Baking Tab if we work on some clip if (TargetClip != null) { GUILayout.Space(5); GUILayout.FlexibleSpace(); DrawBakingTab(); } so_currentSetup.ApplyModifiedProperties(); EditorGUILayout.EndVertical(); // Remembering all changes to be saved S._SetDirty(); } else // Can't view data { EditorGUILayout.HelpBox("Can't create serialized object for displaying data", MessageType.Info); EditorGUILayout.EndVertical(); } } // Main GUI Block END } GUILayout.Space(3); GUILayout.EndScrollView(); #region Draw Hourglass On Top when reloading if (_reloadingAlpha < 0.11f) _hourglassAlpha += 0.3f; else if (_reloadingAlpha < 0.3f) _hourglassAlpha += 0.2f; else _hourglassAlpha -= 0.1f; if (_hourglassAlpha > 0.9f) _hourglassAlpha = 0.9f; else if (_hourglassAlpha < 0f) _hourglassAlpha = 0f; if (_hourglassAlpha > 0.01f) { GUI.color = new Color(1f, 1f, 1f, _hourglassAlpha); Rect rWait = new Rect(position); rWait.position = Vector2.zero; float xRatio = rWait.width * 0.5f; float yRatio = rWait.height * 0.675f; rWait.width -= xRatio; rWait.height -= yRatio; rWait.position += new Vector2(xRatio, yRatio) * 0.5f; GUI.DrawTexture(rWait, Tex_WaitIMG, ScaleMode.ScaleToFit); GUI.color = preGuiC; } #endregion #region Unity Editor Version Related IFDEFS #if UNITY_2019_4_OR_NEWER #else } catch (Exception e) { if (e.HResult == -2147024809 || e.HResult == -2146233088) // Ignore harmless unity GUI error { } else { UnityEngine.Debug.Log("Info: " + e.HResult + " | "); UnityEngine.Debug.Log("[Animation Designer] Exception when drawing GUI"); UnityEngine.Debug.LogException(e); } } #endif #endregion if (repaintRequest && !_serializationChanges) { SceneView.RepaintAll(); repaintRequest = false; } } AnimationClipSettings currentClipSettings = null; void GetTargetClipSettings() { if (TargetClip == null) { currentClipSettings = null; return; } currentClipSettings = AnimationUtility.GetAnimationClipSettings(TargetClip); } void OnTargetAnimationClipChange() { GetTargetClipSettings(); CheckComponentsInitialization(false); } void RefreshSave() { if (_switchingReferences) return; S.LatestAnimator = latestAnimator; if (S.Armature != null) if (S.Armature.LatestAnimator == null) S.Armature.LatestAnimator = latestAnimator; } public static void ForceTPose() { if (Get) Get.S.RestoreTPose(); } public void DrawFocusOnCurrentAnimatorButton() { if (latestAnimator == null) return; GUILayout.Space(4); GUI.backgroundColor = Color.green; if (GUILayout.Button(new GUIContent(" Focus on current Animator", FGUI_Resources.TexTargetingIcon), GUILayout.Height(26))) { FrameTarget(latestAnimator.gameObject); EditorGUIUtility.PingObject(latestAnimator); } GUI.backgroundColor = preBG; } public void FrameTarget(GameObject g) { Selection.activeGameObject = g; SceneView.FrameLastActiveSceneView(); } public static void ForceZeroFramePose() { if (!Get) return; if (Get.TargetClip == null) { ForceTPose(); return; } float preTime = Get.animationElapsed; Get.animationElapsed = 0f; Get.SampleCurrentAnimation(); Get.animationElapsed = preTime; } } }