/// <summary> /// Show the specified space, clip, node and position. /// </summary> /// <param name="space">Space.</param> /// <param name="clip">Clip.</param> /// <param name="node">Node.</param> /// <param name="position">Position.</param> public static void Show(GameObject space, AnimationClip clip, SerializedNode node, Rect?position) { MecanimNodeEditorWindow.__spaceGameObject = space; //in this case is character MecanimNodeEditorWindow.__spaceGameObjectAnimationClip = clip; MecanimNodeEditorWindow.__serializedNode = node; /////// ACCESS SERIALIZED DATA ///////// NodePropertyIterator iterator = node.GetIterator(); __isPlaying = false; __isRecording = false; __variableSelected = null; __timeNormalized = 0f; __timeNormalizedUpdate = false; __timeCurrent = 0f; AnimationMode.StopAnimationMode(); Undo.postprocessModifications -= PostprocessAnimationRecordingModifications; SceneView.onSceneGUIDelegate += OnSceneGUI; if (iterator.Find("clipBindings")) { clipBindingsSerialized = iterator.current; } if (__mecanimNodeClipBinding == null) { __mecanimNodeClipBinding = ScriptableObject.CreateInstance <EditorClipBinding> (); } __mecanimNodeClipBinding.gameObject = __spaceGameObject; __mecanimNodeClipBinding.clip = __spaceGameObjectAnimationClip; /////// INIT SERIALIZED NODE PROPERTIES - CURVES, COLORS, VARIABLES ////// if (iterator.Find("curves")) { curvesSerialized = iterator.current; } else { Debug.LogError("MecananimNode should have public field 'curves'"); } if (iterator.Find("curvesColors")) { curvesColorsSerialized = iterator.current; } else { Debug.LogError("MecananimNode should have public field 'curvesColors'"); } if (iterator.Find("variablesBindedToCurves")) { variablesBindedToCurvesSerialized = iterator.current; } else { Debug.LogError("MecananimNode should have public field 'variablesBindedToCurves'"); } curves = (AnimationCurve[])curvesSerialized.value; curveColors = (Color[])curvesColorsSerialized.value; variablesBindedToCurves = (UnityVariable[])variablesBindedToCurvesSerialized.value; AnimationModeUtility.ResetBindingsTransformPropertyModification(clipBindingsSerialized.value as EditorClipBinding[]); AnimationModeUtility.ResetBindingTransformPropertyModification(__mecanimNodeClipBinding); keyframeTimeValues = new float[0]; eventTimeValuesPrev = new float[0]; keyframeTimeValuesSelected = new bool[0]; keyframesDisplayNames = new string[0]; ///////////// create Reordable list of gameObject-animationClip ////////////////// __gameObjectClipList = new ReorderableList(clipBindingsSerialized.value as IList, typeof(EditorClipBinding), true, true, true, true); __gameObjectClipList.drawElementCallback = onDrawElement; __gameObjectClipList.drawHeaderCallback = onDrawHeaderElement; __gameObjectClipList.onRemoveCallback = onRemoveCallback; __gameObjectClipList.onAddCallback = onAddCallback; __gameObjectClipList.onSelectCallback = onSelectCallback; //__gameObjectClipList.elementHeight = 32f; if (MecanimNodeEditorWindow.__window != null) //restore last { position = __window.position; } MecanimNodeEditorWindow.__window = (MecanimNodeEditorWindow)EditorWindow.GetWindow(typeof(MecanimNodeEditorWindow)); if (position.HasValue) { MecanimNodeEditorWindow.__window.position = position.Value; } MecanimNodeEditorWindow.__window.Show(); }
/// <summary> /// Handles the GUI event. /// </summary> void OnGUI() { if (_keyframeMarker == null) { _keyframeMarker = new GUIContent(EditorGUILayoutEx.ANIMATION_STYLES.pointIcon); } if (!Application.isPlaying && __gameObjectClipList != null) { _curvesEditorShow = EditorGUILayout.Foldout(_curvesEditorShow, "Curves"); //int indentLevel = 0; Rect curveEditorRect = new Rect(0, 0, 0, 0); int i = 0; if (_curvesEditorShow) { //This makes layout to work (Reserving space) curveEditorRect = GUILayoutUtility.GetRect(Screen.width - 16f, 200); /////// CURVE EDITOR //////// curveEditorRect.width = curveEditorRect.width - 32f; curveEditorRect.x = 16f; if (curveEditor == null) { CurveWrapperW[] curveWrappers; int numCurves = curves.Length; curveWrappers = new CurveWrapperW[numCurves]; CurveWrapperW curveWrapperNew; for (i = 0; i < numCurves; i++) { curveWrapperNew = new CurveWrapperW(); curveWrapperNew.curve = curves [i]; curveWrapperNew.color = curveColors [i]; curveWrappers [i] = curveWrapperNew; } curveEditor = new CurveEditorW(curveEditorRect, curveWrappers, false); curveEditor.FrameSelected(true, true); curveEditor.scaleWithWindow = true; curveEditor.hSlider = false; curveEditor.hRangeMin = 0f; curveEditor.hRangeMax = 1f; curveEditor.hRangeLocked = true; curveEditor.onSelect += onCurveSelect; } else { curveEditor.rect = curveEditorRect; curveEditor.FrameSelected(false, false); } curveEditor.DoEditor(); /////////////////////////////////////////////////////////////////////////////// ///////////// ADD/REMOVE CURVE BINDED TO OBJECT PROP OR GLOBAL VARIABLE ///////////// /// // EditorGUILayout.BeginHorizontal(); //if curve is selected display curve properties if (_curveIndexSelected > -1 && _curveIndexSelected < variablesBindedToCurves.Length) { UnityVariable variableSelected = variablesBindedToCurves [_curveIndexSelected]; try { bindingCurvesGUIContent.text = variableSelected.instanceBinded.name + "." + variableSelected.memberPath; EditorGUILayout.LabelField(bindingCurvesGUIContent, new GUILayoutOption[] {}); EditorGUI.BeginChangeCheck(); Color colorNew = EditorGUILayout.ColorField(curveColors [_curveIndexSelected]); if (EditorGUI.EndChangeCheck()) { curveEditor.animationCurves [_curveIndexSelected].color = colorNew; curveColors [_curveIndexSelected] = colorNew; curvesColorsSerialized.ValueChanged(); curvesColorsSerialized.ApplyModifiedValue(); } } catch (MissingReferenceException ex) { bindingCurvesGUIContent.text = "Invalid UVariable " + ex.Message; } } else { bindingCurvesGUIContent.text = "Curve binding:"; List <UnityVariable> blackboardLocalList = (MecanimNodeEditorWindow.__serializedNode.target.blackboard as BlackboardCustom).GetVariableBy(typeof(float)); List <GUIContent> displayOptionsList = blackboardLocalList.Select((item) => new GUIContent("Local/" + item.name)).ToList(); __variableSelected = EditorGUILayoutEx.UnityVariablePopup(bindingCurvesGUIContent, __variableSelected, typeof(float), displayOptionsList, blackboardLocalList); _colorSelected = EditorGUILayout.ColorField(_colorSelected); } /////////////// ADD CURVE(+) ///////// if (GUILayout.Button("Add") && __variableSelected != null) { List <UnityVariable> vList = variablesBindedToCurves.ToList(); vList.Add(__variableSelected); variablesBindedToCurvesSerialized.value = variablesBindedToCurves = vList.ToArray(); variablesBindedToCurvesSerialized.ValueChanged(); //variablesBindedToCurvesSerialized.ApplyModifiedValue (); List <Color> cList = curveColors.ToList(); _colorSelected.a = 1; cList.Add(_colorSelected); curvesColorsSerialized.value = curveColors = cList.ToArray(); curvesColorsSerialized.ValueChanged(); //curvesColorsSerialized.ApplyModifiedValue (); AnimationCurve curveAnimationNew; List <AnimationCurve> crList = curves.ToList(); curveAnimationNew = new AnimationCurve(new Keyframe[] { new Keyframe(0f, (float)__variableSelected.Value), new Keyframe(1f, 1f) }); //TODO add from preset crList.Add(curveAnimationNew); curvesSerialized.value = curves = crList.ToArray(); curvesSerialized.ValueChanged(); //curvesColorsSerialized.ApplyModifiedValue (); ///add curve wrapped to CurveEditor CurveWrapperW curveWrapperW = new CurveWrapperW(); curveWrapperW.color = _colorSelected; curveWrapperW.curve = curveAnimationNew; curveEditor.AddCurve(curveWrapperW); curveEditor.FrameSelected(true, true); __serializedNode.Update(); __serializedNode.ApplyModifiedProperties(); __variableSelected = null; } ///////////// DELETE CURVE //////////// if (GUILayout.Button("Del") || Event.current.keyCode == KeyCode.Delete) { curveEditor.RemoveCurveAt(_curveIndexSelected); List <UnityVariable> vList = variablesBindedToCurves.ToList(); vList.RemoveAt(_curveIndexSelected); variablesBindedToCurvesSerialized.value = variablesBindedToCurves = vList.ToArray(); variablesBindedToCurvesSerialized.ValueChanged(); List <Color> cList = curveColors.ToList(); cList.RemoveAt(_curveIndexSelected); curvesColorsSerialized.value = curveColors = cList.ToArray(); curvesColorsSerialized.ValueChanged(); List <AnimationCurve> crList = curves.ToList(); crList.RemoveAt(_curveIndexSelected); curvesSerialized.value = curves = crList.ToArray(); curvesSerialized.ValueChanged(); _curveIndexSelected = -1; __variableSelected = null; __serializedNode.ApplyModifiedProperties(); } EditorGUILayout.EndHorizontal(); } else //NOT CURVE EDITOR ///////////// GAMEOBJECT - CLIP BINDINGS ////////// { __gameObjectClipList.DoLayoutList(); ////////////////////////////////////////////// } EditorGUILayout.Space(); __mecanimNodeClipBinding.clip = __spaceGameObjectAnimationClip; ///////////// TIME CONTROL OF ANIMATION (SLIDER) ///////// Rect timeControlRect = GUILayoutUtility.GetRect(Screen.width, 26f); timeControlRect.xMax = 32f; ///////////// PLAY ANIMATION TOGGLE ///////// __isPlaying = GUI.Toggle(timeControlRect, __isPlaying, !__isPlaying ? EditorGUILayoutEx.ANIMATION_STYLES.playIcon : EditorGUILayoutEx.ANIMATION_STYLES.pauseIcon, EditorGUILayoutEx.ANIMATION_STYLES.playButton); if (__isPlaying) { } else { } timeControlRect.xMin = timeControlRect.xMax + 1f; timeControlRect.xMax = timeControlRect.xMin + 21f; timeControlRect.yMin += 2f; EditorGUI.BeginChangeCheck(); Color color = GUI.color; //save color if (AnimationMode.InAnimationMode()) { GUI.color = AnimationMode.animatedPropertyColor; //change color of record button to red } ///////////// RECORD ANIMATION TOGGLE ///////// __isRecording = GUI.Toggle(timeControlRect, __isRecording, EditorGUILayoutEx.ANIMATION_STYLES.recordIcon, EditorStyles.toolbarButton); GUI.color = color; //restore color if (EditorGUI.EndChangeCheck()) { if (__isRecording) { if (!AnimationMode.InAnimationMode()) { List <EditorClipBinding> list = (clipBindingsSerialized.value as EditorClipBinding[]).ToList(); list.Add(__mecanimNodeClipBinding); __clipBindingsToBeAnimated = list.ToArray(); AnimationMode.StartAnimationMode(); Undo.postprocessModifications += PostprocessAnimationRecordingModifications; //calculate offset of boonRoot position before animation from boonRoot position at time=0s. AnimationModeUtility.SaveBindingsOffset(clipBindingsSerialized.value as EditorClipBinding[]); AnimationModeUtility.SaveBindingOffset(__mecanimNodeClipBinding); //calculate time in seconds from the current postion of time scrubber __timeCurrent = __timeNormalized * __spaceGameObjectAnimationClip.length; //apply clip animaiton at __timeCurrent AnimationModeUtility.SampleClipBindingAt(__clipBindingsToBeAnimated , __timeCurrent); LockRootGameObject(true); SceneView.RepaintAll(); } } else { //Remove Undo property modificaiton handlers Undo.postprocessModifications -= PostprocessAnimationRecordingModifications; AnimationMode.StopAnimationMode(); //reset gameobject with bones to state before animation AnimationModeUtility.ResetBindingsTransformPropertyModification(clipBindingsSerialized.value as EditorClipBinding[]); //reset Node.self gameObject AnimationModeUtility.ResetBindingTransformPropertyModification(__mecanimNodeClipBinding); LockRootGameObject(false); } } timeControlRect.xMin = 40f + 16f; timeControlRect.xMax = Screen.width - 68f; timeControlRect.yMin -= 2f; EditorGUI.BeginChangeCheck(); /// TIMELINE SLIDER /// __timeNormalized = EditorGUILayoutEx.CustomHSlider(timeControlRect, __timeNormalized, 0f, 1f, EditorGUILayoutEx.ANIMATION_STYLES.timeScrubber); if (EditorGUI.EndChangeCheck() || __timeNormalizedUpdate) { __timeCurrent = __timeNormalized * __spaceGameObjectAnimationClip.length; __timeNormalizedUpdate = false; if (!AnimationMode.InAnimationMode()) { AnimationMode.StartAnimationMode(); //calculate offset of boonRoot position before animation from boonRoot position at time=0s. AnimationModeUtility.SaveBindingsOffset(clipBindingsSerialized.value as EditorClipBinding[]); AnimationModeUtility.SaveBindingOffset(__mecanimNodeClipBinding); LockRootGameObject(true); } if (!__isRecording) { __isRecording = true; //add recording Undo events handlers Undo.postprocessModifications += PostprocessAnimationRecordingModifications; List <EditorClipBinding> list = (clipBindingsSerialized.value as EditorClipBinding[]).ToList(); list.Add(__mecanimNodeClipBinding); __clipBindingsToBeAnimated = list.ToArray(); } //moves clip to time: __timeCurrent AnimationModeUtility.SampleClipBindingAt(__clipBindingsToBeAnimated, __timeCurrent); } ///////////// ROTATION/SCALE KEYFRAMES ///////////////////////// Rect keyframesRect = GUILayoutUtility.GetRect(Screen.width - 16f, 16f); keyframesRect.xMax = timeControlRect.xMax + _keyframeMarker.image.width * 0.5f; keyframesRect.xMin = timeControlRect.xMin - _keyframeMarker.image.width * 0.5f; //Show rotation or scale keyframes if Rotation or Scale tools are selected if (Selection.activeGameObject != null) { if (Tools.current == Tool.Rotate) { EditorClipBinding clipBindingCurrent = (clipBindingsSerialized.value as EditorClipBinding[]).FirstOrDefault((itm) => itm.gameObject != null && itm.gameObject.transform.childCount > 0 && itm.gameObject.transform.GetChild(0).gameObject == Selection.activeGameObject); if (clipBindingCurrent != null && clipBindingCurrent.visible && clipBindingCurrent.clip != null) { EditorCurveBinding curveBinding = AnimationUtilityEx.EditorCurveBinding_RotX; curveBinding.path = AnimationUtility.CalculateTransformPath(clipBindingCurrent.gameObject.transform.GetChild(0), clipBindingCurrent.gameObject.transform.root); keyframeTimeValues = AnimationUtilityEx.GetTimesNormalized(clipBindingCurrent.clip, curveBinding, __spaceGameObjectAnimationClip.length); } else { keyframeTimeValues = new float[0]; } } else if (Tools.current == Tool.Scale) { EditorClipBinding clipBindingCurrent = (clipBindingsSerialized.value as EditorClipBinding[]).FirstOrDefault((itm) => itm.gameObject != null && itm.gameObject.transform.childCount > 0 && itm.gameObject.transform.GetChild(0).gameObject == Selection.activeGameObject); if (clipBindingCurrent != null && clipBindingCurrent.visible && clipBindingCurrent.clip != null) { EditorCurveBinding curveBinding = AnimationUtilityEx.EditorCurveBinding_SclX; curveBinding.path = AnimationUtility.CalculateTransformPath(clipBindingCurrent.gameObject.transform.GetChild(0), clipBindingCurrent.gameObject.transform.root); keyframeTimeValues = AnimationUtilityEx.GetTimesNormalized(clipBindingCurrent.clip, curveBinding, __spaceGameObjectAnimationClip.length); } else { keyframeTimeValues = new float[0]; } } else { keyframeTimeValues = new float[0]; } } else { keyframeTimeValues = new float[0]; } keyframesDisplayNames = keyframeTimeValues.Select((itm) => { return(Decimal.Round(Convert.ToDecimal(itm * __spaceGameObjectAnimationClip.length), 2).ToString() + ".s"); }).ToArray(); keyframeTimeValuesSelected = new bool[keyframeTimeValues.Length]; //used for multiselection option not used here //create custom timeline showing rotation or scale keyframes EditorGUILayoutEx.CustomTimeLine(ref keyframesRect, _keyframeMarker, ref keyframeTimeValues, ref eventTimeValuesPrev, ref keyframesDisplayNames, ref keyframeTimeValuesSelected, -1f, null, onKeyframeDelete, null, onKeyframeEdit, null ); // DISPLAY TIME in [s] and in [%] EditorGUILayout.LabelField("Time: " + Decimal.Round(Convert.ToDecimal(__timeCurrent), 2).ToString() + "s (" + Mathf.FloorToInt(__timeNormalized * 100) + "%) Frame:" + Mathf.FloorToInt(__timeCurrent * __spaceGameObjectAnimationClip.frameRate).ToString()); /////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// /// /// Draw red time scrubber line on top of Curve Editor /// ////////////////////////////////////////////////////////////// if (_curvesEditorShow) { Handles.color = Color.red; float leftrightMargin = 39f; // 40f; float effectiveWidth = curveEditorRect.width - 2 * leftrightMargin - curveEditorRect.xMin; float timeLineX = curveEditorRect.xMin + leftrightMargin + effectiveWidth * __timeNormalized; Handles.DrawLine(new Vector2(timeLineX, curveEditorRect.y), new Vector2(timeLineX, curveEditorRect.y + curveEditorRect.height)); } ////////// EVALUATE CURVES ////////// int variablesNum = variablesBindedToCurves.Length; for (int varriableCurrentinx = 0; varriableCurrentinx < variablesNum; varriableCurrentinx++) { try { variablesBindedToCurves [varriableCurrentinx].Value = curves [varriableCurrentinx].Evaluate(__timeNormalized); } catch (Exception ex) { variablesBindedToCurves [varriableCurrentinx].name = "Invalid UVariable" + ex.Message; } } } }