/// <summary> /// The custom inspector. /// </summary> public override void OnInspectorGUI() { int i = 0; ////// RESTORE SAVED ////// //restore and delete clipboard mecanimNode = target as MecanimNode; if (mecanimNode != null) { Motion motion = null; ////////////////////////////////////////////////////////////// /// PRESEVE RESTORE // if (EditorApplication.isPlaying || EditorApplication.isPaused) { if (GUILayout.Button("Preserve")) { serializedNode.ApplyModifiedProperties(); UnityVariable.SetDirty(mecanimNode.blendX); UnityVariable.SetDirty(mecanimNode.blendY); UnityVariable.SetDirty(mecanimNode.motionOverride); // if (variablesBindedToCurves != null) { // UnityVariable[] varArray = variablesBindedToCurves; // // int varNumber = varArray.Length; // for (int varCurrent=0; varCurrent<varNumber; varCurrent++) { // varArray [varCurrent].OnBeforeSerialize (); // // } // } EditorUtilityEx.Clipboard.preserve(mecanimNode.instanceID, mecanimNode, mecanimNode.GetType().GetFields()); } } else { if (EditorUtilityEx.Clipboard.HasBeenPreseved(mecanimNode.instanceID) && GUILayout.Button("Apply Playmode Changes")) { EditorUtilityEx.Clipboard.restore(mecanimNode.instanceID, mecanimNode); animatorStateSerialized = null; NodePropertyIterator iterator = serializedNode.GetIterator(); while (iterator.Next(true)) { if (iterator.current.value is UnityVariable) { //Debug.Log("OnBeforeDeserialize:"+((UnityVariable)iterator.current.value).Value); ((UnityVariable)iterator.current.value).OnAfterDeserialize(); //Debug.Log("OnAfterDeserialize:"+((UnityVariable)iterator.current.value).Value); } else if (iterator.current.value is UnityVariable[]) { UnityVariable[] varArray = (UnityVariable[])iterator.current.value; int varNumber = varArray.Length; for (int varCurrent = 0; varCurrent < varNumber; varCurrent++) { varArray [varCurrent].OnAfterDeserialize(); } } iterator.current.ValueChanged(); this.serializedNode.Update(); iterator.current.ApplyModifiedValue(); } } } ////////////////////// if (Event.current.type == EventType.Layout) { this.serializedNode.Update(); } DrawDefaultInspector(); // // if (EditorGUILayoutEx.ANIMATION_STYLES == null) // EditorGUILayoutEx.ANIMATION_STYLES = new EditorGUILayoutEx.AnimationStyles (); /////////////////////////////// ANIMATOR STATE ///////////////////////////////// if (animatorStateSerialized == null) { NodePropertyIterator iterator = this.serializedNode.GetIterator(); if (iterator.Find("animatorStateSelected")) { animatorStateSerialized = iterator.current; } if (iterator.Find("motionOverride")) { motionOverrideSerialized = iterator.current; } } ////////// MOTION OVERRIDE HANDLING ////////// if (animatorStateSerialized.value != null) { UnityVariable motionOverridVariable = (UnityVariable)motionOverrideSerialized.value; //if there are no override use motion of selected AnimationState //Debug.Log(((UnityEngine.Object)mecanimNode.motionOverride.Value).); if (motionOverridVariable == null || motionOverridVariable.Value == null || motionOverridVariable.ValueType != typeof(AnimationClip)) { motion = ((ws.winx.unity.AnimatorState)animatorStateSerialized.value).motion; } else // { motion = (Motion)motionOverridVariable.Value; } if (motionOverridVariable != null && motionOverridVariable.Value != null && ((ws.winx.unity.AnimatorState)animatorStateSerialized.value).motion == null) { Debug.LogError("Can't override state that doesn't contain motion"); } } /////////////////////////////////////////////////// if (GUILayout.Button("BindEditor") && motion != null) { MecanimNodeEditorWindow.Show(mecanimNode.self, motion as AnimationClip, this.serializedNode, null); } ///////////// TIME CONTROL OF ANIMATION (SLIDER) ///////// if (Application.isPlaying) { if (animatorStateRuntimeControlEnabledSerialized == null) { NodePropertyIterator iterator = this.serializedNode.GetIterator(); if (iterator.Find("animationRunTimeControlEnabled")) { animatorStateRuntimeControlEnabledSerialized = iterator.current; } if (iterator.Find("animatorStateRunTimeControl")) { animatorStateRunTimeControlSerialized = iterator.current; } } if (animatorStateRuntimeControlEnabledSerialized != null && animatorStateRunTimeControlSerialized != null && (bool)animatorStateRuntimeControlEnabledSerialized.value) { Rect timeControlRect = GUILayoutUtility.GetRect(Screen.width - 16f, 26f); timeControlRect.xMin += 38f; timeControlRect.xMax -= 70f; animatorStateRunTimeControlSerialized.value = EditorGUILayoutEx.CustomHSlider(timeControlRect, (float)animatorStateRunTimeControlSerialized.value, 0f, 1f, EditorGUILayoutEx.ANIMATION_STYLES.timeScrubber); } } /////////////////////////////////////////////////////////////// /////////// AVATAR Preview GUI //////////// if (!Application.isPlaying && motion != null) { //This makes layout to work (Reserving space) Rect avatarRect = GUILayoutUtility.GetRect(Screen.width - 16f, 200); avatarRect.width -= 70f; avatarRect.xMin += 6f; if (avatarPreview == null) { avatarPreview = new AvatarPreviewW(null, motion); } else { avatarPreview.SetPreviewMotion(motion); } EditorGUILayout.BeginHorizontal(); if (eventTimeValues != null && Event.current.type == EventType.Repaint) { //find first selected if exist int eventTimeValueSelectedIndex = Array.IndexOf(eventTimeValuesSelected, true); if (eventTimeValueSelectedIndex > -1) { avatarPreview.SetTimeAt(eventTimeValues [eventTimeValueSelectedIndex]); } else { //!!! changing //avatarPreview.timeControl.startTime // start/stop makes AvatarPreview to play from start to stop // and the rest of animation isn't visible in Timeline so not good for selecting range // but its not offer good usability of resized animation if (avatarPreview.timeControl.playing) { //restrict animation into this range if (avatarPreview.timeControl.normalizedTime < mecanimNode.range.rangeStart || avatarPreview.timeControl.normalizedTime > mecanimNode.range.rangeEnd) { avatarPreview.timeControl.nextCurrentTime = avatarPreview.timeControl.startTime * (1f - mecanimNode.range.rangeStart) + avatarPreview.timeControl.stopTime * mecanimNode.range.rangeStart; } } else { //set AvatarPreview animation time range depending of drag of range control handles if (Math.Abs(mecanimNode.range.rangeStart - timeNormalizedStartPrev) > 0.01f) { timeNormalizedStartPrev = mecanimNode.range.rangeStart; avatarPreview.SetTimeAt(timeNormalizedStartPrev); } else if (Math.Abs(mecanimNode.range.rangeEnd - timeNormalizedEndPrev) > 0.01f) { timeNormalizedEndPrev = mecanimNode.range.rangeEnd; avatarPreview.SetTimeAt(timeNormalizedEndPrev); } } } } avatarPreview.timeControl.playbackSpeed = mecanimNode.speed; avatarPreview.DoAvatarPreview(avatarRect, GUIStyle.none); //Debug.Log(avatarPreview.timeControl.currentTime+" "+); EditorGUILayout.EndHorizontal(); ////////// Events Timeline GUI ////////// if (!eventTimeLineInitalized) { //TODO calculate PopupRect eventTimeLineValuePopUpRect = new Rect((Screen.width - 250) * 0.5f, (Screen.height - 150) * 0.5f, 250, 150); //select the time values from nodes //eventTimeValues = mecanimNode.children.Select ((val) => (float)((SendEventNormalized)val).timeNormalized.Value).ToArray (); eventTimeValues = mecanimNode.children.Select((val) => (float)(((SendEventNormalizedNode)val).timeNormalized.serializedProperty as SerializedProperty).floatValue).ToArray(); eventDisplayNames = mecanimNode.children.Select((val) => ((SendEventNormalizedNode)val).name).ToArray(); eventTimeValuesSelected = new bool[eventTimeValues.Length]; playButtonStyle = "TimeScrubberButton"; if (playButtonStyle != null) { playButtonSize = playButtonStyle.CalcSize(new GUIContent()); } eventTimeLineInitalized = true; } Rect timeLineRect = GUILayoutUtility.GetRect(Screen.width - 16f, 50f); //Rect timeLineRect = GUILayoutUtility.GetLastRect (); Texture eventMarkerTexture = EditorGUILayoutEx.ANIMATION_STYLES.eventMarker.image; timeLineRect.xMin += playButtonSize.x - eventMarkerTexture.width * 0.5f; timeLineRect.xMax -= eventMarkerTexture.width * 0.5f; //timeLineRect.height = EditorGUILayoutEx.eventMarkerTexture.height * 3 * 0.66f + playButtonSize.y; timeLineRect.width -= 66f; EditorGUILayoutEx.CustomTimeLine(ref timeLineRect, new GUIContent(eventMarkerTexture), ref eventTimeValues, ref eventTimeValuesPrev, ref eventDisplayNames, ref eventTimeValuesSelected, avatarPreview.timeControl.normalizedTime, onMecanimEventAdd, onMecanimEventDelete, onMecanimEventClose, onMecanimEventEdit, onMecanimEventDragEnd ); EditorGUILayout.LabelField("Events Timeline"); SendEventNormalizedNode ev; //update time values int eventTimeValuesNumber = mecanimNode.children.Length; for (i = 0; i < eventTimeValuesNumber; i++) { ev = ((SendEventNormalizedNode)mecanimNode.children [i]); //ev.timeNormalized.Value = eventTimeValues [i]; ev.timeNormalized.Value = eventTimeValues [i]; //if changes have been made in pop editor or SendEventNormailized inspector if (ev.name != eventDisplayNames [i]) { eventDisplayNames [i] = ((SendEventNormalizedNode)mecanimNode.children [i]).name; } EditorUtilityEx.ApplySerializedPropertyChangeTo(ev.timeNormalized); //ev.timeNormalized.ApplyModifiedProperties (); } // Restore the indent level //EditorGUI.indentLevel = indentLevel; // Apply modified properties this.serializedNode.ApplyModifiedProperties(); } } }
/// <summary> /// The custom inspector. /// </summary> public override void OnInspectorGUI() { int i = 0; ////// RESTORE SAVED ////// //restore and delete clipboard mecanimNode = target as MecanimNode; if (mecanimNode != null) { Motion motion = null; ////////////////////////////////////////////////////////////// /// PRESEVE RESTORE // if (EditorApplication.isPlaying || EditorApplication.isPaused) { if (GUILayout.Button ("Preserve")) { serializedNode.ApplyModifiedProperties (); UnityVariable.SetDirty (mecanimNode.blendX); UnityVariable.SetDirty (mecanimNode.blendY); UnityVariable.SetDirty (mecanimNode.motionOverride); // if (variablesBindedToCurves != null) { // UnityVariable[] varArray = variablesBindedToCurves; // // int varNumber = varArray.Length; // for (int varCurrent=0; varCurrent<varNumber; varCurrent++) { // varArray [varCurrent].OnBeforeSerialize (); // // } // } EditorUtilityEx.Clipboard.preserve (mecanimNode.instanceID, mecanimNode, mecanimNode.GetType ().GetFields ()); } } else { if (EditorUtilityEx.Clipboard.HasBeenPreseved (mecanimNode.instanceID) && GUILayout.Button ("Apply Playmode Changes")) { EditorUtilityEx.Clipboard.restore (mecanimNode.instanceID, mecanimNode); animatorStateSerialized = null; NodePropertyIterator iterator = serializedNode.GetIterator (); while (iterator.Next (true)) { if (iterator.current.value is UnityVariable) { //Debug.Log("OnBeforeDeserialize:"+((UnityVariable)iterator.current.value).Value); ((UnityVariable)iterator.current.value).OnAfterDeserialize (); //Debug.Log("OnAfterDeserialize:"+((UnityVariable)iterator.current.value).Value); } else if (iterator.current.value is UnityVariable[]) { UnityVariable[] varArray = (UnityVariable[])iterator.current.value; int varNumber = varArray.Length; for (int varCurrent=0; varCurrent<varNumber; varCurrent++) { varArray [varCurrent].OnAfterDeserialize (); } } iterator.current.ValueChanged (); this.serializedNode.Update (); iterator.current.ApplyModifiedValue (); } } } ////////////////////// if (Event.current.type == EventType.Layout) { this.serializedNode.Update (); } DrawDefaultInspector (); // // if (EditorGUILayoutEx.ANIMATION_STYLES == null) // EditorGUILayoutEx.ANIMATION_STYLES = new EditorGUILayoutEx.AnimationStyles (); /////////////////////////////// ANIMATOR STATE ///////////////////////////////// if (animatorStateSerialized == null) { NodePropertyIterator iterator = this.serializedNode.GetIterator (); if (iterator.Find ("animatorStateSelected")) animatorStateSerialized = iterator.current; if (iterator.Find ("motionOverride")) motionOverrideSerialized = iterator.current; } ////////// MOTION OVERRIDE HANDLING ////////// if (animatorStateSerialized.value != null) { UnityVariable motionOverridVariable = (UnityVariable)motionOverrideSerialized.value; //if there are no override use motion of selected AnimationState //Debug.Log(((UnityEngine.Object)mecanimNode.motionOverride.Value).); if (motionOverridVariable == null || motionOverridVariable.Value == null || motionOverridVariable.ValueType != typeof(AnimationClip)) motion = ((ws.winx.unity.AnimatorState)animatorStateSerialized.value).motion; else // motion = (Motion)motionOverridVariable.Value; if (motionOverridVariable != null && motionOverridVariable.Value != null && ((ws.winx.unity.AnimatorState)animatorStateSerialized.value).motion == null) { Debug.LogError ("Can't override state that doesn't contain motion"); } } /////////////////////////////////////////////////// if (GUILayout.Button ("BindEditor") && motion!=null) { MecanimNodeEditorWindow.Show ( mecanimNode.self, motion as AnimationClip, this.serializedNode, null); } ///////////// TIME CONTROL OF ANIMATION (SLIDER) ///////// if (Application.isPlaying) { if (animatorStateRuntimeControlEnabledSerialized == null) { NodePropertyIterator iterator = this.serializedNode.GetIterator (); if (iterator.Find ("animationRunTimeControlEnabled")) { animatorStateRuntimeControlEnabledSerialized = iterator.current; } if (iterator.Find ("animatorStateRunTimeControl")) { animatorStateRunTimeControlSerialized = iterator.current; } } if (animatorStateRuntimeControlEnabledSerialized != null && animatorStateRunTimeControlSerialized != null && (bool)animatorStateRuntimeControlEnabledSerialized.value) { Rect timeControlRect = GUILayoutUtility.GetRect (Screen.width - 16f, 26f); timeControlRect.xMin += 38f; timeControlRect.xMax -= 70f; animatorStateRunTimeControlSerialized.value = EditorGUILayoutEx.CustomHSlider (timeControlRect, (float)animatorStateRunTimeControlSerialized.value, 0f, 1f,EditorGUILayoutEx.ANIMATION_STYLES.timeScrubber); } } /////////////////////////////////////////////////////////////// /////////// AVATAR Preview GUI //////////// if (!Application.isPlaying && motion != null) { //This makes layout to work (Reserving space) Rect avatarRect = GUILayoutUtility.GetRect (Screen.width - 16f, 200); avatarRect.width -= 70f; avatarRect.xMin += 6f; if (avatarPreview == null) avatarPreview = new AvatarPreviewW (null, motion); else avatarPreview.SetPreviewMotion (motion); EditorGUILayout.BeginHorizontal (); if (eventTimeValues != null && Event.current.type == EventType.Repaint) { //find first selected if exist int eventTimeValueSelectedIndex = Array.IndexOf (eventTimeValuesSelected, true); if (eventTimeValueSelectedIndex > -1) { avatarPreview.SetTimeAt (eventTimeValues [eventTimeValueSelectedIndex]); } else { //!!! changing //avatarPreview.timeControl.startTime // start/stop makes AvatarPreview to play from start to stop // and the rest of animation isn't visible in Timeline so not good for selecting range // but its not offer good usability of resized animation if (avatarPreview.timeControl.playing) { //restrict animation into this range if (avatarPreview.timeControl.normalizedTime < mecanimNode.range.rangeStart || avatarPreview.timeControl.normalizedTime > mecanimNode.range.rangeEnd) { avatarPreview.timeControl.nextCurrentTime = avatarPreview.timeControl.startTime * (1f - mecanimNode.range.rangeStart) + avatarPreview.timeControl.stopTime * mecanimNode.range.rangeStart; } } else { //set AvatarPreview animation time range depending of drag of range control handles if (Math.Abs (mecanimNode.range.rangeStart - timeNormalizedStartPrev) > 0.01f) { timeNormalizedStartPrev = mecanimNode.range.rangeStart; avatarPreview.SetTimeAt (timeNormalizedStartPrev); } else if (Math.Abs (mecanimNode.range.rangeEnd - timeNormalizedEndPrev) > 0.01f) { timeNormalizedEndPrev = mecanimNode.range.rangeEnd; avatarPreview.SetTimeAt (timeNormalizedEndPrev); } } } } avatarPreview.timeControl.playbackSpeed = mecanimNode.speed; avatarPreview.DoAvatarPreview (avatarRect, GUIStyle.none); //Debug.Log(avatarPreview.timeControl.currentTime+" "+); EditorGUILayout.EndHorizontal (); ////////// Events Timeline GUI ////////// if (!eventTimeLineInitalized) { //TODO calculate PopupRect eventTimeLineValuePopUpRect = new Rect ((Screen.width - 250) * 0.5f, (Screen.height - 150) * 0.5f, 250, 150); //select the time values from nodes //eventTimeValues = mecanimNode.children.Select ((val) => (float)((SendEventNormalized)val).timeNormalized.Value).ToArray (); eventTimeValues = mecanimNode.children.Select ((val) => (float)((SendEventNormalizedNode)val).timeNormalized.serializedProperty.floatValue).ToArray (); eventDisplayNames = mecanimNode.children.Select ((val) => ((SendEventNormalizedNode)val).name).ToArray (); eventTimeValuesSelected = new bool[eventTimeValues.Length]; playButtonStyle = "TimeScrubberButton"; if (playButtonStyle != null) playButtonSize = playButtonStyle.CalcSize (new GUIContent ()); eventTimeLineInitalized = true; } Rect timeLineRect = GUILayoutUtility.GetRect (Screen.width - 16f, 50f); //Rect timeLineRect = GUILayoutUtility.GetLastRect (); Texture eventMarkerTexture = EditorGUILayoutEx.ANIMATION_STYLES.eventMarker.image; timeLineRect.xMin += playButtonSize.x - eventMarkerTexture.width * 0.5f; timeLineRect.xMax -= eventMarkerTexture.width * 0.5f; //timeLineRect.height = EditorGUILayoutEx.eventMarkerTexture.height * 3 * 0.66f + playButtonSize.y; timeLineRect.width -= 66f; EditorGUILayoutEx.CustomTimeLine (ref timeLineRect,new GUIContent(eventMarkerTexture), ref eventTimeValues, ref eventTimeValuesPrev, ref eventDisplayNames, ref eventTimeValuesSelected, avatarPreview.timeControl.normalizedTime, onMecanimEventAdd, onMecanimEventDelete, onMecanimEventClose, onMecanimEventEdit, onMecanimEventDragEnd ); EditorGUILayout.LabelField ("Events Timeline"); SendEventNormalizedNode ev; //update time values int eventTimeValuesNumber = mecanimNode.children.Length; for (i=0; i<eventTimeValuesNumber; i++) { ev = ((SendEventNormalizedNode)mecanimNode.children [i]); //ev.timeNormalized.Value = eventTimeValues [i]; ev.timeNormalized.Value = eventTimeValues [i]; //if changes have been made in pop editor or SendEventNormailized inspector if (ev.name != eventDisplayNames [i]) eventDisplayNames [i] = ((SendEventNormalizedNode)mecanimNode.children [i]).name; ev.timeNormalized.ApplyModifiedProperties (); } // Restore the indent level //EditorGUI.indentLevel = indentLevel; // Apply modified properties this.serializedNode.ApplyModifiedProperties (); } } }