diff options
| author | Andrew Lee <alee14498@protonmail.com> | 2020-04-19 17:19:32 -0400 |
|---|---|---|
| committer | Andrew Lee <alee14498@protonmail.com> | 2020-04-19 17:19:32 -0400 |
| commit | c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78 (patch) | |
| tree | ee4d51c7c1d633e11f46453ef1edd3c77c4ef9f7 /Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/AnimatedParameterUtility.cs | |
| download | Project-Sandbox-c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78.tar.gz Project-Sandbox-c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78.tar.bz2 Project-Sandbox-c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78.zip | |
Inital commit
Diffstat (limited to 'Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/AnimatedParameterUtility.cs')
| -rw-r--r-- | Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/AnimatedParameterUtility.cs | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/AnimatedParameterUtility.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/AnimatedParameterUtility.cs new file mode 100644 index 0000000..53542e3 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/AnimatedParameterUtility.cs @@ -0,0 +1,358 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEngine; +using UnityEngine.Playables; +using UnityEngine.Timeline; +using UnityObject = UnityEngine.Object; + +namespace UnityEditor.Timeline +{ + static class AnimatedParameterUtility + { + static readonly Type k_DefaultAnimationType = typeof(TimelineAsset); + static SerializedObject s_CachedObject; + + public static ICurvesOwner ToCurvesOwner(IPlayableAsset playableAsset, TimelineAsset timeline) + { + if (playableAsset == null) + return null; + + var curvesOwner = playableAsset as ICurvesOwner; + if (curvesOwner == null) + { + // If the asset is not directly an ICurvesOwner, it might be the asset for a TimelineClip + curvesOwner = TimelineRecording.FindClipWithAsset(timeline, playableAsset); + } + + return curvesOwner; + } + + public static bool TryGetSerializedPlayableAsset(UnityObject asset, out SerializedObject serializedObject) + { + serializedObject = null; + if (asset == null || Attribute.IsDefined(asset.GetType(), typeof(NotKeyableAttribute)) || !HasScriptPlayable(asset)) + return false; + + serializedObject = GetSerializedPlayableAsset(asset); + return serializedObject != null; + } + + public static SerializedObject GetSerializedPlayableAsset(UnityObject asset) + { + if (!(asset is IPlayableAsset)) + return null; + + var scriptObject = asset as ScriptableObject; + if (scriptObject == null) + return null; + + if (s_CachedObject == null || s_CachedObject.targetObject != asset) + { + s_CachedObject = new SerializedObject(scriptObject); + } + + return s_CachedObject; + } + + public static void UpdateSerializedPlayableAsset(UnityObject asset) + { + var so = GetSerializedPlayableAsset(asset); + if (so != null) + so.UpdateIfRequiredOrScript(); + } + + public static bool HasScriptPlayable(UnityObject asset) + { + if (asset == null) + return false; + + var scriptPlayable = asset as IPlayableBehaviour; + return scriptPlayable != null || GetScriptPlayableFields(asset as IPlayableAsset).Any(); + } + + public static FieldInfo[] GetScriptPlayableFields(IPlayableAsset asset) + { + if (asset == null) + return new FieldInfo[0]; + + FieldInfo[] scriptPlayableFields; + if (!AnimatedParameterCache.TryGetScriptPlayableFields(asset.GetType(), out scriptPlayableFields)) + { + scriptPlayableFields = GetScriptPlayableFields_Internal(asset); + AnimatedParameterCache.SetScriptPlayableFields(asset.GetType(), scriptPlayableFields); + } + + return scriptPlayableFields; + } + + static FieldInfo[] GetScriptPlayableFields_Internal(IPlayableAsset asset) + { + return asset.GetType() + .GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + .Where( + f => typeof(IPlayableBehaviour).IsAssignableFrom(f.FieldType) && // The field is an IPlayableBehaviour + (f.IsPublic || f.GetCustomAttributes(typeof(SerializeField), false).Any()) && // The field is either public or marked with [SerializeField] + !f.GetCustomAttributes(typeof(NotKeyableAttribute), false).Any() && // The field is not marked with [NotKeyable] + !f.GetCustomAttributes(typeof(HideInInspector), false).Any() && // The field is not marked with [HideInInspector] + !f.FieldType.GetCustomAttributes(typeof(NotKeyableAttribute), false).Any()) // The field is not of a type marked with [NotKeyable] + .ToArray(); + } + + public static bool HasAnyAnimatableParameters(UnityObject asset) + { + return GetAllAnimatableParameters(asset).Any(); + } + + public static IEnumerable<SerializedProperty> GetAllAnimatableParameters(UnityObject asset) + { + SerializedObject serializedObject; + if (!TryGetSerializedPlayableAsset(asset, out serializedObject)) + yield break; + + var prop = serializedObject.GetIterator(); + + // We need to keep this variable because prop starts invalid + var outOfBounds = false; + while (!outOfBounds && prop.NextVisible(true)) + { + foreach (var property in SelectAnimatableProperty(prop)) + yield return property; + + // We can become out of bounds by calling SelectAnimatableProperty, if the last iterated property is a color. + outOfBounds = !prop.isValid; + } + } + + static IEnumerable<SerializedProperty> SelectAnimatableProperty(SerializedProperty prop) + { + // We're only interested by animatable leaf parameters + if (!prop.hasChildren && IsParameterAnimatable(prop)) + yield return prop.Copy(); + + // Color type is not considered "visible" when iterating + if (prop.propertyType == SerializedPropertyType.Color) + { + var end = prop.GetEndProperty(); + + // For some reasons, if the last 2+ serialized properties are of type Color, prop becomes invalid and + // Next() throws an exception. This is not the case when only the last serialized property is a Color. + while (!SerializedProperty.EqualContents(prop, end) && prop.isValid && prop.Next(true)) + { + foreach (var property in SelectAnimatableProperty(prop)) + yield return property; + } + } + } + + public static bool IsParameterAnimatable(UnityObject asset, string parameterName) + { + SerializedObject serializedObject; + if (!TryGetSerializedPlayableAsset(asset, out serializedObject)) + return false; + + var prop = serializedObject.FindProperty(parameterName); + return IsParameterAnimatable(prop); + } + + public static bool IsParameterAnimatable(SerializedProperty property) + { + if (property == null) + return false; + + bool isAnimatable; + if (!AnimatedParameterCache.TryGetIsPropertyAnimatable(property, out isAnimatable)) + { + isAnimatable = IsParameterAnimatable_Internal(property); + AnimatedParameterCache.SetIsPropertyAnimatable(property, isAnimatable); + } + + return isAnimatable; + } + + static bool IsParameterAnimatable_Internal(SerializedProperty property) + { + if (property == null) + return false; + + var asset = property.serializedObject.targetObject; + + // Currently not supported + if (asset is AnimationTrack) + return false; + + if (IsParameterKeyable(property)) + return asset is IPlayableBehaviour || IsParameterAtPathAnimatable(asset, property.propertyPath); + + return false; + } + + static bool IsParameterKeyable(SerializedProperty property) + { + return IsTypeAnimatable(property.propertyType) && IsKeyableInHierarchy(property); + } + + static bool IsKeyableInHierarchy(SerializedProperty property) + { + const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + var pathSegments = property.propertyPath.Split('.'); + var type = property.serializedObject.targetObject.GetType(); + foreach (var segment in pathSegments) + { + if (type.GetCustomAttributes(typeof(NotKeyableAttribute), false).Any()) + { + return false; + } + + if (type.IsArray) + { + if (segment != "Array") + type = type.GetElementType(); + continue; + } + + var fieldInfo = type.GetField(segment, bindingFlags); + + if (fieldInfo == null || + fieldInfo.GetCustomAttributes(typeof(NotKeyableAttribute), false).Any() || + fieldInfo.GetCustomAttributes(typeof(HideInInspector), false).Any()) + { + return false; + } + + type = fieldInfo.FieldType; + } + + return true; + } + + static bool IsParameterAtPathAnimatable(UnityObject asset, string path) + { + if (asset == null) + return false; + + return GetScriptPlayableFields(asset as IPlayableAsset) + .Any( + f => path.StartsWith(f.Name, StringComparison.Ordinal) && + path.Length > f.Name.Length && + path[f.Name.Length] == '.'); + } + + public static bool IsTypeAnimatable(SerializedPropertyType type) + { + // Note: Integer is not currently supported by the animated property system + switch (type) + { + case SerializedPropertyType.Boolean: + case SerializedPropertyType.Float: + case SerializedPropertyType.Vector2: + case SerializedPropertyType.Vector3: + case SerializedPropertyType.Color: + case SerializedPropertyType.Quaternion: + case SerializedPropertyType.Vector4: + return true; + default: + return false; + } + } + + public static bool IsParameterAnimated(UnityObject asset, AnimationClip animationData, string parameterName) + { + if (asset == null || animationData == null) + return false; + + var binding = GetCurveBinding(asset, parameterName); + var bindings = AnimationClipCurveCache.Instance.GetCurveInfo(animationData).bindings; + return bindings.Any(x => BindingMatchesParameterName(x, binding.propertyName)); + } + + // Retrieve an animated parameter curve. parameter name is required to include the appropriate field for vectors + // e.g.: position + public static AnimationCurve GetAnimatedParameter(UnityObject asset, AnimationClip animationData, string parameterName) + { + if (!(asset is ScriptableObject) || animationData == null) + return null; + + var binding = GetCurveBinding(asset, parameterName); + return AnimationUtility.GetEditorCurve(animationData, binding); + } + + // get an animatable curve binding for this parameter + public static EditorCurveBinding GetCurveBinding(UnityObject asset, string parameterName) + { + var animationName = GetAnimatedParameterBindingName(asset, parameterName); + return EditorCurveBinding.FloatCurve(string.Empty, GetValidAnimationType(asset), animationName); + } + + public static string GetAnimatedParameterBindingName(UnityObject asset, string parameterName) + { + if (asset == null) + return parameterName; + + string bindingName; + if (!AnimatedParameterCache.TryGetBindingName(asset.GetType(), parameterName, out bindingName)) + { + bindingName = GetAnimatedParameterBindingName_Internal(asset, parameterName); + AnimatedParameterCache.SetBindingName(asset.GetType(), parameterName, bindingName); + } + + return bindingName; + } + + static string GetAnimatedParameterBindingName_Internal(UnityObject asset, string parameterName) + { + if (asset is IPlayableBehaviour) + return parameterName; + + // strip the IScript playable field name + var fields = GetScriptPlayableFields(asset as IPlayableAsset); + foreach (var f in fields) + { + if (parameterName.StartsWith(f.Name, StringComparison.Ordinal)) + { + if (parameterName.Length > f.Name.Length && parameterName[f.Name.Length] == '.') + return parameterName.Substring(f.Name.Length + 1); + } + } + + return parameterName; + } + + public static bool BindingMatchesParameterName(EditorCurveBinding binding, string parameterName) + { + if (binding.propertyName == parameterName) + return true; + + var indexOfDot = binding.propertyName.IndexOf('.'); + return indexOfDot > 0 && parameterName.Length == indexOfDot && + binding.propertyName.StartsWith(parameterName, StringComparison.Ordinal); + } + + // the animated type must be a non-abstract instantiable object. + public static Type GetValidAnimationType(UnityObject asset) + { + return asset != null ? asset.GetType() : k_DefaultAnimationType; + } + + public static FieldInfo GetFieldInfoForProperty(SerializedProperty property) + { + FieldInfo fieldInfo; + + if (!AnimatedParameterCache.TryGetFieldInfoForProperty(property, out fieldInfo)) + { + Type _; + fieldInfo = ScriptAttributeUtility.GetFieldInfoFromProperty(property, out _); + AnimatedParameterCache.SetFieldInfoForProperty(property, fieldInfo); + } + + return fieldInfo; + } + + public static T GetAttributeForProperty<T>(SerializedProperty property) where T : Attribute + { + var fieldInfo = GetFieldInfoForProperty(property); + return fieldInfo.GetCustomAttributes(typeof(T), false).FirstOrDefault() as T; + } + } +} |
