/// <summary> /// Draw the UI controls for animation playback, e.g. /// the drop-down menu for selecting the active /// animation clip. These UI controls are only shown /// when the currently glTF model has one or more /// animations. /// </summary> public void AnimationControlsOnGui() { Animation anim = ModelManager.Instance.Animation; var clipKeys = ModelManager.Instance.AnimationClipKeys; var clipNames = ModelManager.Instance.AnimationClipNames; var animationControlsAreaHeight = _styles.DropDownButton.CalcSize( new GUIContent("Dummy Text")).y; var dropdownWidth = ScaleInt(300); GUILayout.BeginHorizontal(GUILayout.Height(animationControlsAreaHeight)); // Get a reference to the currently selected animation clip. // We use a value of null to indicate that the special // "Static Pose" clip is currently selected. AnimationState selectedClip = null; if (_dropDownState.selectedIndex != STATIC_POSE_INDEX) { selectedClip = anim[clipKeys[_dropDownState.selectedIndex]]; } // play/pause button GUILayout.BeginVertical(); GUILayout.FlexibleSpace(); var playButtonRect = GUILayoutUtility.GetRect( new GUIContent(""), _styles.PlayButton, GUILayout.Width(animationControlsAreaHeight), GUILayout.Height(animationControlsAreaHeight)); if (GUI.Button(playButtonRect, "", _styles.PlayButton) && selectedClip != null) { selectedClip.speed = selectedClip.speed == 0f ? 1f : 0f; } var origColor = GUI.color; GUI.color = selectedClip != null ? Color.black : Color.gray; float playIconMargin = ScaleInt(10); var playIconRect = new Rect( playButtonRect.x + playIconMargin, playButtonRect.y + playIconMargin, playButtonRect.width - 2 * playIconMargin, playButtonRect.width - 2 * playIconMargin); GUI.DrawTexture(playIconRect, selectedClip != null && selectedClip.speed > 0f ? _pauseIcon : _playIcon, ScaleMode.ScaleToFit); GUI.color = origColor; GUILayout.FlexibleSpace(); GUILayout.EndVertical(); // timeline slider GUILayout.FlexibleSpace(); GUILayout.BeginVertical(); GUILayout.FlexibleSpace(); var time = 0f; var length = 0f; if (selectedClip != null) { length = selectedClip.length; time = selectedClip.time % length; } // Workaround: GUI.LayoutSlider does not expand // its width to fill the available space, so we must manually // calculate the available width here. I'm pretty sure this is a // bug, since other GUI elements (e.g. GUILayout.Label) // are capable of automatically expanding their width. var sliderWidth = Screen.width - _screenMargin.left - animationControlsAreaHeight - _styles.PlayButton.margin.right - _styles.DropDownButton.margin.left - dropdownWidth - _screenMargin.right; var prevTime = time; time = GUILayout.HorizontalSlider(time, 0f, length, GUILayout.Width(sliderWidth)); // if the user clicked on the slider, set the time to // the clicked location and pause playback if (selectedClip != null && time != prevTime) { selectedClip.time = time; selectedClip.speed = 0f; } GUILayout.FlexibleSpace(); GUILayout.EndVertical(); GUILayout.FlexibleSpace(); // drop-down menu for selecting animation clip GUILayout.BeginVertical(); GUILayout.FlexibleSpace(); var dropdownRect = GUILayoutUtility.GetRect( new GUIContent(""), _styles.DropDownButton, GUILayout.Width(dropdownWidth), GUILayout.Height(animationControlsAreaHeight)); var prevSelectedIndex = _dropDownState.selectedIndex; _dropDownState = GuiEx.DropDownMenu( dropdownRect, clipNames, _dropDownState, _dropDownIcon, _styles.DropDownButton, _styles.DropDownListBackground, _styles.DropDownListForeground, _styles.DropDownListItem); // if a new animation clip has been selected, stop the // current clip and start playing the new one if (_dropDownState.selectedIndex != prevSelectedIndex) { anim.Stop(); if (selectedClip != null) { selectedClip.speed = 1f; selectedClip.time = 0f; } // Restore the static pose before we start playing the // new animation clip. This is necessary because // an animation clip will not necessarily reset // all position/rotation/scale values for // all game objects in the model. Any unspecified // transform values are assumed to come from the // default static pose. anim.Play(clipKeys[STATIC_POSE_INDEX]); anim.Sample(); // start playing the new clip var newClipKey = clipKeys[_dropDownState.selectedIndex]; var newClip = anim[newClipKey]; newClip.time = 0f; newClip.speed = 1f; anim.Play(newClipKey); } GUILayout.FlexibleSpace(); GUILayout.EndVertical(); GUILayout.EndHorizontal(); }
/// <summary> /// Draw the UI controls for animation playback, e.g. /// the drop-down menu for selecting the active /// animation clip. These UI controls are only shown /// when the currently glTF model has one or more /// animations. /// </summary> public void AnimationControlsOnGui() { Animation anim = ModelManager.Instance.Animation; var clipKeys = ModelManager.Instance.AnimationClipKeys; var clipNames = ModelManager.Instance.AnimationClipNames; const float animationControlsAreaHeight = 75; // Get a reference to the currently selected animation clip. // We use a value of null to indicate that the special // "Static Pose" clip is currently selected. AnimationState selectedClip = null; if (_dropDownState.selectedIndex != STATIC_POSE_INDEX) { selectedClip = anim[clipKeys[_dropDownState.selectedIndex]]; } // play/pause button const float playButtonSize = 50; var playButtonRect = new Rect( _screenEdgePadding, Screen.height - animationControlsAreaHeight + (animationControlsAreaHeight - playButtonSize) / 2, playButtonSize, playButtonSize); if (GUI.Button(playButtonRect, "", _styles.PlayButton) && selectedClip != null) { selectedClip.speed = selectedClip.speed == 0f ? 1f : 0f; } var origColor = GUI.color; GUI.color = selectedClip != null ? Color.black : Color.gray; const float playIconMargin = 10; var playIconRect = new Rect( playButtonRect.x + playIconMargin, playButtonRect.y + playIconMargin, playButtonRect.width - 2 * playIconMargin, playButtonRect.width - 2 * playIconMargin); GUI.DrawTexture(playIconRect, selectedClip != null && selectedClip.speed > 0f ? _pauseIcon : _playIcon, ScaleMode.ScaleToFit); GUI.color = origColor; // drop-down menu for selecting animation clip const float buttonWidth = 300; var buttonHeight = _styles.DropDownButton.CalcSize( new GUIContent("Dummy Text")).y; var buttonRect = new Rect( Screen.width - _screenEdgePadding - buttonWidth, Screen.height - animationControlsAreaHeight + (animationControlsAreaHeight - buttonHeight) / 2, buttonWidth, buttonHeight); var prevSelectedIndex = _dropDownState.selectedIndex; _dropDownState = GuiEx.DropDownMenu( buttonRect, clipNames, _dropDownState, _dropDownIcon, _styles.DropDownButton, _styles.DropDownListBackground, _styles.DropDownListForeground, _styles.DropDownListItem); // if a new animation clip has been selected, stop the // current clip and start playing the new one if (_dropDownState.selectedIndex != prevSelectedIndex) { anim.Stop(); if (selectedClip != null) { selectedClip.speed = 1f; selectedClip.time = 0f; } // Restore the static pose before we start playing the // new animation clip. This is necessary because // an animation clip will not necessarily reset // all position/rotation/scale values for // all game objects in the model. Any unspecified // transform values are assumed to come from the // default static pose. anim.Play(clipKeys[STATIC_POSE_INDEX]); anim.Sample(); // start playing the new clip var newClipKey = clipKeys[_dropDownState.selectedIndex]; var newClip = anim[newClipKey]; newClip.time = 0f; newClip.speed = 1f; anim.Play(newClipKey); } // timeline slider const float sliderMargin = 20; const float sliderHeight = 10; var sliderX1 = playButtonRect.x + playButtonRect.width + sliderMargin; var sliderX2 = buttonRect.x - sliderMargin; var sliderRect = new Rect( sliderX1, Screen.height - animationControlsAreaHeight + (animationControlsAreaHeight - sliderHeight) / 2, sliderX2 - sliderX1, sliderHeight); var time = 0f; var length = 0f; if (selectedClip != null) { length = selectedClip.length; time = selectedClip.time % length; } var prevTime = time; time = GUI.HorizontalSlider(sliderRect, time, 0f, length); // if the user clicked on the slider, set the time to // the clicked location and pause playback if (selectedClip != null && time != prevTime) { selectedClip.time = time; selectedClip.speed = 0f; } }