You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					658 lines
				
				26 KiB
			
		
		
			
		
	
	
					658 lines
				
				26 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								using System;
							 | 
						||
| 
								 | 
							
								using System.Collections.Generic;
							 | 
						||
| 
								 | 
							
								using System.Linq;
							 | 
						||
| 
								 | 
							
								using UnityEditorInternal;
							 | 
						||
| 
								 | 
							
								using UnityEngine;
							 | 
						||
| 
								 | 
							
								using Object = UnityEngine.Object;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace UnityEditor.Timeline
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Utility class for editing animation clips from serialized properties
							 | 
						||
| 
								 | 
							
								    static class CurveEditUtility
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        static bool IsRotationKey(EditorCurveBinding binding)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return binding.propertyName.Contains("localEulerAnglesRaw");
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public static void AddKey(AnimationClip clip, EditorCurveBinding sourceBinding, SerializedProperty prop, double time)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (sourceBinding.isPPtrCurve)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                AddObjectKey(clip, sourceBinding, prop, time);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if (IsRotationKey(sourceBinding))
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                AddRotationKey(clip, sourceBinding, prop, time);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                AddFloatKey(clip, sourceBinding, prop, time);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        static void AddObjectKey(AnimationClip clip, EditorCurveBinding sourceBinding, SerializedProperty prop, double time)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (prop.propertyType != SerializedPropertyType.ObjectReference)
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            ObjectReferenceKeyframe[] curve = null;
							 | 
						||
| 
								 | 
							
								            var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
							 | 
						||
| 
								 | 
							
								            var curveIndex = Array.IndexOf(info.objectBindings, sourceBinding);
							 | 
						||
| 
								 | 
							
								            if (curveIndex >= 0)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                curve = info.objectCurves[curveIndex];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // where in the array does the evaluation land?
							 | 
						||
| 
								 | 
							
								                var evalIndex = EvaluateIndex(curve, (float)time);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (KeyCompare(curve[evalIndex].time, (float)time, clip.frameRate) == 0)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    curve[evalIndex].value = prop.objectReferenceValue;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                // check the next key (always return the minimum value)
							 | 
						||
| 
								 | 
							
								                else if (evalIndex < curve.Length - 1 && KeyCompare(curve[evalIndex + 1].time, (float)time, clip.frameRate) == 0)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    curve[evalIndex + 1].value = prop.objectReferenceValue;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                // resize the array
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    if (time > curve[0].time)
							 | 
						||
| 
								 | 
							
								                        evalIndex++;
							 | 
						||
| 
								 | 
							
								                    var key = new ObjectReferenceKeyframe();
							 | 
						||
| 
								 | 
							
								                    key.time = (float)time;
							 | 
						||
| 
								 | 
							
								                    key.value = prop.objectReferenceValue;
							 | 
						||
| 
								 | 
							
								                    ArrayUtility.Insert(ref curve, evalIndex, key);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else // curve doesn't exist, add it
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                curve = new ObjectReferenceKeyframe[1];
							 | 
						||
| 
								 | 
							
								                curve[0].time = (float)time;
							 | 
						||
| 
								 | 
							
								                curve[0].value = prop.objectReferenceValue;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            AnimationUtility.SetObjectReferenceCurve(clip, sourceBinding, curve);
							 | 
						||
| 
								 | 
							
								            EditorUtility.SetDirty(clip);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        static void AddRotationKey(AnimationClip clip, EditorCurveBinding sourceBind, SerializedProperty prop, double time)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (prop.propertyType != SerializedPropertyType.Quaternion)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var updateCurves = new List<AnimationCurve>();
							 | 
						||
| 
								 | 
							
								            var updateBindings = new List<EditorCurveBinding>();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
							 | 
						||
| 
								 | 
							
								            for (var i = 0; i < info.bindings.Length; i++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                if (sourceBind.type != info.bindings[i].type)
							 | 
						||
| 
								 | 
							
								                    continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (info.bindings[i].propertyName.Contains("localEuler"))
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    updateBindings.Add(info.bindings[i]);
							 | 
						||
| 
								 | 
							
								                    updateCurves.Add(info.curves[i]);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // use this instead of serialized properties because the editor will attempt to maintain
							 | 
						||
| 
								 | 
							
								            // correct localeulers
							 | 
						||
| 
								 | 
							
								            var eulers = ((Transform)prop.serializedObject.targetObject).localEulerAngles;
							 | 
						||
| 
								 | 
							
								            if (updateBindings.Count == 0)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var propName = AnimationWindowUtility.GetPropertyGroupName(sourceBind.propertyName);
							 | 
						||
| 
								 | 
							
								                updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, propName + ".x"));
							 | 
						||
| 
								 | 
							
								                updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, propName + ".y"));
							 | 
						||
| 
								 | 
							
								                updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, propName + ".z"));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                var curveX = new AnimationCurve();
							 | 
						||
| 
								 | 
							
								                var curveY = new AnimationCurve();
							 | 
						||
| 
								 | 
							
								                var curveZ = new AnimationCurve();
							 | 
						||
| 
								 | 
							
								                AddKeyFrameToCurve(curveX, (float)time, clip.frameRate, eulers.x, false);
							 | 
						||
| 
								 | 
							
								                AddKeyFrameToCurve(curveY, (float)time, clip.frameRate, eulers.y, false);
							 | 
						||
| 
								 | 
							
								                AddKeyFrameToCurve(curveZ, (float)time, clip.frameRate, eulers.z, false);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                updateCurves.Add(curveX);
							 | 
						||
| 
								 | 
							
								                updateCurves.Add(curveY);
							 | 
						||
| 
								 | 
							
								                updateCurves.Add(curveZ);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for (var i = 0; i < updateBindings.Count; i++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var c = updateBindings[i].propertyName.Last();
							 | 
						||
| 
								 | 
							
								                var value = eulers.x;
							 | 
						||
| 
								 | 
							
								                if (c == 'y') value = eulers.y;
							 | 
						||
| 
								 | 
							
								                else if (c == 'z') value = eulers.z;
							 | 
						||
| 
								 | 
							
								                AddKeyFrameToCurve(updateCurves[i], (float)time, clip.frameRate, value, false);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            UpdateEditorCurves(clip, updateBindings, updateCurves);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Add a floating point curve key
							 | 
						||
| 
								 | 
							
								        static void AddFloatKey(AnimationClip clip, EditorCurveBinding sourceBind, SerializedProperty prop, double time)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var updateCurves = new List<AnimationCurve>();
							 | 
						||
| 
								 | 
							
								            var updateBindings = new List<EditorCurveBinding>();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var updated = false;
							 | 
						||
| 
								 | 
							
								            var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
							 | 
						||
| 
								 | 
							
								            for (var i = 0; i < info.bindings.Length; i++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var binding = info.bindings[i];
							 | 
						||
| 
								 | 
							
								                if (binding.type != sourceBind.type)
							 | 
						||
| 
								 | 
							
								                    continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                SerializedProperty valProp = null;
							 | 
						||
| 
								 | 
							
								                var curve = info.curves[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // perfect match on property path, editting a float
							 | 
						||
| 
								 | 
							
								                if (prop.propertyPath.Equals(binding.propertyName))
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    valProp = prop;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                // this is a child object
							 | 
						||
| 
								 | 
							
								                else if (binding.propertyName.Contains(prop.propertyPath))
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    valProp = prop.serializedObject.FindProperty(binding.propertyName);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (valProp != null)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    var value = GetKeyValue(valProp);
							 | 
						||
| 
								 | 
							
								                    if (!float.IsNaN(value)) // Nan indicates an error retrieving the property value
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        updated = true;
							 | 
						||
| 
								 | 
							
								                        AddKeyFrameToCurve(curve, (float)time, clip.frameRate, value, valProp.propertyType == SerializedPropertyType.Boolean);
							 | 
						||
| 
								 | 
							
								                        updateCurves.Add(curve);
							 | 
						||
| 
								 | 
							
								                        updateBindings.Add(binding);
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Curves don't exist, add them
							 | 
						||
| 
								 | 
							
								            if (!updated)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var propName = AnimationWindowUtility.GetPropertyGroupName(sourceBind.propertyName);
							 | 
						||
| 
								 | 
							
								                if (!prop.hasChildren)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    var value = GetKeyValue(prop);
							 | 
						||
| 
								 | 
							
								                    if (!float.IsNaN(value))
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, sourceBind.propertyName));
							 | 
						||
| 
								 | 
							
								                        var curve = new AnimationCurve();
							 | 
						||
| 
								 | 
							
								                        AddKeyFrameToCurve(curve, (float)time, clip.frameRate, value, prop.propertyType == SerializedPropertyType.Boolean);
							 | 
						||
| 
								 | 
							
								                        updateCurves.Add(curve);
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    // special case because subproperties on color aren't 'visible' so you can't iterate over them
							 | 
						||
| 
								 | 
							
								                    if (prop.propertyType == SerializedPropertyType.Color)
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, propName + ".r"));
							 | 
						||
| 
								 | 
							
								                        updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, propName + ".g"));
							 | 
						||
| 
								 | 
							
								                        updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, propName + ".b"));
							 | 
						||
| 
								 | 
							
								                        updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, propName + ".a"));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        var c = prop.colorValue;
							 | 
						||
| 
								 | 
							
								                        for (var i = 0; i < 4; i++)
							 | 
						||
| 
								 | 
							
								                        {
							 | 
						||
| 
								 | 
							
								                            var curve = new AnimationCurve();
							 | 
						||
| 
								 | 
							
								                            AddKeyFrameToCurve(curve, (float)time, clip.frameRate, c[i], prop.propertyType == SerializedPropertyType.Boolean);
							 | 
						||
| 
								 | 
							
								                            updateCurves.Add(curve);
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    else
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        prop = prop.Copy();
							 | 
						||
| 
								 | 
							
								                        foreach (SerializedProperty cp in prop)
							 | 
						||
| 
								 | 
							
								                        {
							 | 
						||
| 
								 | 
							
								                            updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, cp.propertyPath));
							 | 
						||
| 
								 | 
							
								                            var curve = new AnimationCurve();
							 | 
						||
| 
								 | 
							
								                            AddKeyFrameToCurve(curve, (float)time, clip.frameRate, GetKeyValue(cp), cp.propertyType == SerializedPropertyType.Boolean);
							 | 
						||
| 
								 | 
							
								                            updateCurves.Add(curve);
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            UpdateEditorCurves(clip, updateBindings, updateCurves);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public static void RemoveKey(AnimationClip clip, EditorCurveBinding sourceBinding, SerializedProperty prop, double time)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (sourceBinding.isPPtrCurve)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                RemoveObjectKey(clip, sourceBinding, time);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if (IsRotationKey(sourceBinding))
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                RemoveRotationKey(clip, sourceBinding, prop, time);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                RemoveFloatKey(clip, sourceBinding, prop, time);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public static void RemoveObjectKey(AnimationClip clip, EditorCurveBinding sourceBinding, double time)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
							 | 
						||
| 
								 | 
							
								            var curveIndex = Array.IndexOf(info.objectBindings, sourceBinding);
							 | 
						||
| 
								 | 
							
								            if (curveIndex >= 0)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var curve = info.objectCurves[curveIndex];
							 | 
						||
| 
								 | 
							
								                var evalIndex = GetKeyframeAtTime(curve, (float)time, clip.frameRate);
							 | 
						||
| 
								 | 
							
								                if (evalIndex >= 0)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    ArrayUtility.RemoveAt(ref curve, evalIndex);
							 | 
						||
| 
								 | 
							
								                    AnimationUtility.SetObjectReferenceCurve(clip, sourceBinding, curve.Length == 0 ? null : curve);
							 | 
						||
| 
								 | 
							
								                    EditorUtility.SetDirty(clip);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public static int GetObjectKeyCount(AnimationClip clip, EditorCurveBinding sourceBinding)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
							 | 
						||
| 
								 | 
							
								            var curveIndex = Array.IndexOf(info.objectBindings, sourceBinding);
							 | 
						||
| 
								 | 
							
								            if (curveIndex >= 0)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var curve = info.objectCurves[curveIndex];
							 | 
						||
| 
								 | 
							
								                return curve.Length;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return 0;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        static void RemoveRotationKey(AnimationClip clip, EditorCurveBinding sourceBind, SerializedProperty prop, double time)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (prop.propertyType != SerializedPropertyType.Quaternion)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var updateCurves = new List<AnimationCurve>();
							 | 
						||
| 
								 | 
							
								            var updateBindings = new List<EditorCurveBinding>();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
							 | 
						||
| 
								 | 
							
								            for (var i = 0; i < info.bindings.Length; i++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                if (sourceBind.type != info.bindings[i].type)
							 | 
						||
| 
								 | 
							
								                    continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (info.bindings[i].propertyName.Contains("localEuler"))
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    updateBindings.Add(info.bindings[i]);
							 | 
						||
| 
								 | 
							
								                    updateCurves.Add(info.curves[i]);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            foreach (var c in updateCurves)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                RemoveKeyFrameFromCurve(c, (float)time, clip.frameRate);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            UpdateEditorCurves(clip, updateBindings, updateCurves);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Removes the float keys from curves
							 | 
						||
| 
								 | 
							
								        static void RemoveFloatKey(AnimationClip clip, EditorCurveBinding sourceBind, SerializedProperty prop, double time)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var updateCurves = new List<AnimationCurve>();
							 | 
						||
| 
								 | 
							
								            var updateBindings = new List<EditorCurveBinding>();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
							 | 
						||
| 
								 | 
							
								            for (var i = 0; i < info.bindings.Length; i++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var binding = info.bindings[i];
							 | 
						||
| 
								 | 
							
								                if (binding.type != sourceBind.type)
							 | 
						||
| 
								 | 
							
								                    continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                SerializedProperty valProp = null;
							 | 
						||
| 
								 | 
							
								                var curve = info.curves[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // perfect match on property path, editting a float
							 | 
						||
| 
								 | 
							
								                if (prop.propertyPath.Equals(binding.propertyName))
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    valProp = prop;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                // this is a child object
							 | 
						||
| 
								 | 
							
								                else if (binding.propertyName.Contains(prop.propertyPath))
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    valProp = prop.serializedObject.FindProperty(binding.propertyName);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                if (valProp != null)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    RemoveKeyFrameFromCurve(curve, (float)time, clip.frameRate);
							 | 
						||
| 
								 | 
							
								                    updateCurves.Add(curve);
							 | 
						||
| 
								 | 
							
								                    updateBindings.Add(binding);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // update the curve. Do this last to not mess with the curve caches we are iterating over
							 | 
						||
| 
								 | 
							
								            UpdateEditorCurves(clip, updateBindings, updateCurves);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        static void UpdateEditorCurve(AnimationClip clip, EditorCurveBinding binding, AnimationCurve curve)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (curve.keys.Length == 0)
							 | 
						||
| 
								 | 
							
								                AnimationUtility.SetEditorCurve(clip, binding, null);
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								                AnimationUtility.SetEditorCurve(clip, binding, curve);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        static void UpdateEditorCurves(AnimationClip clip, List<EditorCurveBinding> bindings, List<AnimationCurve> curves)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (curves.Count == 0)
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for (var i = 0; i < curves.Count; i++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                UpdateEditorCurve(clip, bindings[i], curves[i]);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            EditorUtility.SetDirty(clip);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public static void RemoveCurves(AnimationClip clip, SerializedProperty prop)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (clip == null || prop == null)
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var toRemove = new List<EditorCurveBinding>();
							 | 
						||
| 
								 | 
							
								            var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
							 | 
						||
| 
								 | 
							
								            for (var i = 0; i < info.bindings.Length; i++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var binding = info.bindings[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // check if we match directly, or with a child object
							 | 
						||
| 
								 | 
							
								                if (prop.propertyPath.Equals(binding.propertyName) || binding.propertyName.Contains(prop.propertyPath))
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    toRemove.Add(binding);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            for (int i = 0; i < toRemove.Count; i++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                AnimationUtility.SetEditorCurve(clip, toRemove[i], null);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // adds a stepped key frame to the given curve
							 | 
						||
| 
								 | 
							
								        public static void AddKeyFrameToCurve(AnimationCurve curve, float time, float framerate, float value, bool stepped)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var key = new Keyframe();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            bool add = true;
							 | 
						||
| 
								 | 
							
								            var keyIndex = GetKeyframeAtTime(curve, time, framerate);
							 | 
						||
| 
								 | 
							
								            if (keyIndex != -1)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                add = false;
							 | 
						||
| 
								 | 
							
								                key = curve[keyIndex]; // retain the tangents and mode
							 | 
						||
| 
								 | 
							
								                curve.RemoveKey(keyIndex);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            key.value = value;
							 | 
						||
| 
								 | 
							
								            key.time = GetKeyTime(time, framerate);
							 | 
						||
| 
								 | 
							
								            keyIndex = curve.AddKey(key);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (stepped)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                AnimationUtility.SetKeyBroken(curve, keyIndex, stepped);
							 | 
						||
| 
								 | 
							
								                AnimationUtility.SetKeyLeftTangentMode(curve, keyIndex, AnimationUtility.TangentMode.Constant);
							 | 
						||
| 
								 | 
							
								                AnimationUtility.SetKeyRightTangentMode(curve, keyIndex, AnimationUtility.TangentMode.Constant);
							 | 
						||
| 
								 | 
							
								                key.outTangent = Mathf.Infinity;
							 | 
						||
| 
								 | 
							
								                key.inTangent = Mathf.Infinity;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if (add)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                AnimationUtility.SetKeyLeftTangentMode(curve, keyIndex, AnimationUtility.TangentMode.ClampedAuto);
							 | 
						||
| 
								 | 
							
								                AnimationUtility.SetKeyRightTangentMode(curve, keyIndex, AnimationUtility.TangentMode.ClampedAuto);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (keyIndex != -1 && !stepped)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                AnimationUtility.UpdateTangentsFromModeSurrounding(curve, keyIndex);
							 | 
						||
| 
								 | 
							
								                AnimationUtility.SetKeyBroken(curve, keyIndex, false);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Removes a keyframe at the given time from the animation curve
							 | 
						||
| 
								 | 
							
								        public static bool RemoveKeyFrameFromCurve(AnimationCurve curve, float time, float framerate)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var keyIndex = GetKeyframeAtTime(curve, time, framerate);
							 | 
						||
| 
								 | 
							
								            if (keyIndex == -1)
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            curve.RemoveKey(keyIndex);
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // gets the value of the key
							 | 
						||
| 
								 | 
							
								        public static float GetKeyValue(SerializedProperty prop)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            switch (prop.propertyType)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                case SerializedPropertyType.Integer:
							 | 
						||
| 
								 | 
							
								                    return prop.intValue;
							 | 
						||
| 
								 | 
							
								                case SerializedPropertyType.Boolean:
							 | 
						||
| 
								 | 
							
								                    return prop.boolValue ? 1.0f : 0.0f;
							 | 
						||
| 
								 | 
							
								                case SerializedPropertyType.Float:
							 | 
						||
| 
								 | 
							
								                    return prop.floatValue;
							 | 
						||
| 
								 | 
							
								                default:
							 | 
						||
| 
								 | 
							
								                    Debug.LogError("Could not convert property type " + prop.propertyType.ToString() + " to float");
							 | 
						||
| 
								 | 
							
								                    break;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return float.NaN;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public static void SetFromKeyValue(SerializedProperty prop, float keyValue)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            switch (prop.propertyType)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                case SerializedPropertyType.Float:
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    prop.floatValue = keyValue;
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                case SerializedPropertyType.Integer:
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    prop.intValue = (int)keyValue;
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                case SerializedPropertyType.Boolean:
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    prop.boolValue = Math.Abs(keyValue) > 0.001f;
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            Debug.LogError("Could not convert float to property type " + prop.propertyType.ToString());
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // gets the index of the key, -1 if not found
							 | 
						||
| 
								 | 
							
								        public static int GetKeyframeAtTime(AnimationCurve curve, float time, float frameRate)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var range = 0.5f / frameRate;
							 | 
						||
| 
								 | 
							
								            var keys = curve.keys;
							 | 
						||
| 
								 | 
							
								            for (var i = 0; i < keys.Length; i++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var k = keys[i];
							 | 
						||
| 
								 | 
							
								                if (k.time >= time - range && k.time < time + range)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    return i;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return -1;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public static int GetKeyframeAtTime(ObjectReferenceKeyframe[] curve, float time, float frameRate)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (curve == null || curve.Length == 0)
							 | 
						||
| 
								 | 
							
								                return -1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var range = 0.5f / frameRate;
							 | 
						||
| 
								 | 
							
								            for (var i = 0; i < curve.Length; i++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var t = curve[i].time;
							 | 
						||
| 
								 | 
							
								                if (t >= time - range && t < time + range)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    return i;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return -1;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public static float GetKeyTime(float time, float frameRate)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return Mathf.Round(time * frameRate) / frameRate;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public static int KeyCompare(float timeA, float timeB, float frameRate)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (Mathf.Abs(timeA - timeB) <= 0.5f / frameRate)
							 | 
						||
| 
								 | 
							
								                return 0;
							 | 
						||
| 
								 | 
							
								            return timeA < timeB ? -1 : 1;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Evaluates an object (bool curve)
							 | 
						||
| 
								 | 
							
								        public static Object Evaluate(ObjectReferenceKeyframe[] curve, float time)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return curve[EvaluateIndex(curve, time)].value;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // returns the index from evaluation
							 | 
						||
| 
								 | 
							
								        public static int EvaluateIndex(ObjectReferenceKeyframe[] curve, float time)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (curve == null || curve.Length == 0)
							 | 
						||
| 
								 | 
							
								                throw new InvalidOperationException("Can not evaluate a PPtr curve with no entries");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // clamp conditions
							 | 
						||
| 
								 | 
							
								            if (time <= curve[0].time)
							 | 
						||
| 
								 | 
							
								                return 0;
							 | 
						||
| 
								 | 
							
								            if (time >= curve.Last().time)
							 | 
						||
| 
								 | 
							
								                return curve.Length - 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // binary search
							 | 
						||
| 
								 | 
							
								            var max = curve.Length - 1;
							 | 
						||
| 
								 | 
							
								            var min = 0;
							 | 
						||
| 
								 | 
							
								            while (max - min > 1)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var imid = (min + max) / 2;
							 | 
						||
| 
								 | 
							
								                if (Mathf.Approximately(curve[imid].time, time))
							 | 
						||
| 
								 | 
							
								                    return imid;
							 | 
						||
| 
								 | 
							
								                if (curve[imid].time < time)
							 | 
						||
| 
								 | 
							
								                    min = imid;
							 | 
						||
| 
								 | 
							
								                else if (curve[imid].time > time)
							 | 
						||
| 
								 | 
							
								                    max = imid;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return min;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Shifts the animation clip so the time start at 0
							 | 
						||
| 
								 | 
							
								        public static void ShiftBySeconds(this AnimationClip clip, float time)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var floatBindings = AnimationUtility.GetCurveBindings(clip);
							 | 
						||
| 
								 | 
							
								            var objectBindings = AnimationUtility.GetObjectReferenceCurveBindings(clip);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // update the float curves
							 | 
						||
| 
								 | 
							
								            foreach (var bind in floatBindings)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var curve = AnimationUtility.GetEditorCurve(clip, bind);
							 | 
						||
| 
								 | 
							
								                var keys = curve.keys;
							 | 
						||
| 
								 | 
							
								                for (var i = 0; i < keys.Length; i++)
							 | 
						||
| 
								 | 
							
								                    keys[i].time += time;
							 | 
						||
| 
								 | 
							
								                curve.keys = keys;
							 | 
						||
| 
								 | 
							
								                AnimationUtility.SetEditorCurve(clip, bind, curve);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // update the PPtr curves
							 | 
						||
| 
								 | 
							
								            foreach (var bind in objectBindings)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var curve = AnimationUtility.GetObjectReferenceCurve(clip, bind);
							 | 
						||
| 
								 | 
							
								                for (var i = 0; i < curve.Length; i++)
							 | 
						||
| 
								 | 
							
								                    curve[i].time += time;
							 | 
						||
| 
								 | 
							
								                AnimationUtility.SetObjectReferenceCurve(clip, bind, curve);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            EditorUtility.SetDirty(clip);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public static void ScaleTime(this AnimationClip clip, float scale)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var floatBindings = AnimationUtility.GetCurveBindings(clip);
							 | 
						||
| 
								 | 
							
								            var objectBindings = AnimationUtility.GetObjectReferenceCurveBindings(clip);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // update the float curves
							 | 
						||
| 
								 | 
							
								            foreach (var bind in floatBindings)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var curve = AnimationUtility.GetEditorCurve(clip, bind);
							 | 
						||
| 
								 | 
							
								                var keys = curve.keys;
							 | 
						||
| 
								 | 
							
								                for (var i = 0; i < keys.Length; i++)
							 | 
						||
| 
								 | 
							
								                    keys[i].time *= scale;
							 | 
						||
| 
								 | 
							
								                curve.keys = keys.OrderBy(x => x.time).ToArray();
							 | 
						||
| 
								 | 
							
								                AnimationUtility.SetEditorCurve(clip, bind, curve);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // update the PPtr curves
							 | 
						||
| 
								 | 
							
								            foreach (var bind in objectBindings)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var curve = AnimationUtility.GetObjectReferenceCurve(clip, bind);
							 | 
						||
| 
								 | 
							
								                for (var i = 0; i < curve.Length; i++)
							 | 
						||
| 
								 | 
							
								                    curve[i].time *= scale;
							 | 
						||
| 
								 | 
							
								                curve = curve.OrderBy(x => x.time).ToArray();
							 | 
						||
| 
								 | 
							
								                AnimationUtility.SetObjectReferenceCurve(clip, bind, curve);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            EditorUtility.SetDirty(clip);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Creates an opposing blend curve that matches the given curve to make sure the result is normalized
							 | 
						||
| 
								 | 
							
								        public static AnimationCurve CreateMatchingCurve(AnimationCurve curve)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            Keyframe[] keys = curve.keys;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for (var i = 0; i != keys.Length; i++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                if (!Single.IsPositiveInfinity(keys[i].inTangent))
							 | 
						||
| 
								 | 
							
								                    keys[i].inTangent = -keys[i].inTangent;
							 | 
						||
| 
								 | 
							
								                if (!Single.IsPositiveInfinity(keys[i].outTangent))
							 | 
						||
| 
								 | 
							
								                    keys[i].outTangent = -keys[i].outTangent;
							 | 
						||
| 
								 | 
							
								                keys[i].value = 1.0f - keys[i].value;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return new AnimationCurve(keys);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Sanitizes the keys on an animation to force the property to be normalized
							 | 
						||
| 
								 | 
							
								        public static Keyframe[] SanitizeCurveKeys(Keyframe[] keys, bool easeIn)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (keys.Length < 2)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                if (easeIn)
							 | 
						||
| 
								 | 
							
								                    keys = new[] { new Keyframe(0, 0), new Keyframe(1, 1) };
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                    keys = new[] { new Keyframe(0, 1), new Keyframe(1, 0) };
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if (easeIn)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                keys[0].time = 0;
							 | 
						||
| 
								 | 
							
								                keys[keys.Length - 1].time = 1;
							 | 
						||
| 
								 | 
							
								                keys[keys.Length - 1].value = 1;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                keys[0].time = 0;
							 | 
						||
| 
								 | 
							
								                keys[0].value = 1;
							 | 
						||
| 
								 | 
							
								                keys[keys.Length - 1].time = 1;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return keys;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 |