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/Animation | |
| 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/Animation')
24 files changed, 2746 insertions, 0 deletions
diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationClipActions.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationClipActions.cs new file mode 100644 index 0000000..4c79048 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationClipActions.cs @@ -0,0 +1,96 @@ +using System.ComponentModel; +using System.Linq; +using JetBrains.Annotations; +using UnityEngine; +using UnityEngine.Timeline; +using UnityEngine.Playables; +using ClipAction = UnityEditor.Timeline.ItemAction<UnityEngine.Timeline.TimelineClip>; + +namespace UnityEditor.Timeline +{ + [MenuEntry("Match Offsets To Previous Clip", MenuOrder.CustomClipAction.AnimClipMatchPrevious), UsedImplicitly] + class MatchOffsetsPreviousAction : ClipAction + { + public override bool Execute(WindowState state, TimelineClip[] items) + { + AnimationOffsetMenu.MatchClipsToPrevious(state, items.Where(x => IsValidClip(x, TimelineEditor.inspectedDirector)).ToArray()); + return true; + } + + private static bool IsValidClip(TimelineClip clip, PlayableDirector director) + { + return clip != null && + clip.parentTrack != null && + (clip.asset as AnimationPlayableAsset) != null && + clip.parentTrack.clips.Any(x => x.start < clip.start) && + TimelineUtility.GetSceneGameObject(director, clip.parentTrack) != null; + } + + protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] items) + { + if (!items.All(TimelineAnimationUtilities.IsAnimationClip)) + return MenuActionDisplayState.Hidden; + + var director = TimelineEditor.inspectedDirector; + if (TimelineEditor.inspectedDirector == null) + return MenuActionDisplayState.Hidden; + + if (items.Any(c => IsValidClip(c, director))) + return MenuActionDisplayState.Visible; + + return MenuActionDisplayState.Hidden; + } + } + + [MenuEntry("Match Offsets To Next Clip", MenuOrder.CustomClipAction.AnimClipMatchNext), UsedImplicitly] + class MatchOffsetsNextAction : ClipAction + { + public override bool Execute(WindowState state, TimelineClip[] items) + { + AnimationOffsetMenu.MatchClipsToNext(state, items.Where(x => IsValidClip(x, TimelineEditor.inspectedDirector)).ToArray()); + return true; + } + + private static bool IsValidClip(TimelineClip clip, PlayableDirector director) + { + return clip != null && + clip.parentTrack != null && + (clip.asset as AnimationPlayableAsset) != null && + clip.parentTrack.clips.Any(x => x.start > clip.start) && + TimelineUtility.GetSceneGameObject(director, clip.parentTrack) != null; + } + + protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] items) + { + if (!items.All(TimelineAnimationUtilities.IsAnimationClip)) + return MenuActionDisplayState.Hidden; + + var director = TimelineEditor.inspectedDirector; + if (TimelineEditor.inspectedDirector == null) + return MenuActionDisplayState.Hidden; + + if (items.Any(c => IsValidClip(c, director))) + return MenuActionDisplayState.Visible; + + return MenuActionDisplayState.Hidden; + } + } + + [MenuEntry("Reset Offsets", MenuOrder.CustomClipAction.AnimClipResetOffset), UsedImplicitly] + class ResetOffsets : ClipAction + { + public override bool Execute(WindowState state, TimelineClip[] items) + { + AnimationOffsetMenu.ResetClipOffsets(state, items.Where(TimelineAnimationUtilities.IsAnimationClip).ToArray()); + return true; + } + + protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] items) + { + if (!items.All(TimelineAnimationUtilities.IsAnimationClip)) + return MenuActionDisplayState.Hidden; + + return MenuActionDisplayState.Visible; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationClipActions.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationClipActions.cs.meta new file mode 100644 index 0000000..0632984 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationClipActions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bf22284ca28e7ef4490033b61e9b52cd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationClipCurveCache.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationClipCurveCache.cs new file mode 100644 index 0000000..8570a73 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationClipCurveCache.cs @@ -0,0 +1,436 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEditor; +using UnityEditorInternal; + +namespace UnityEditor.Timeline +{ + struct CurveBindingPair + { + public EditorCurveBinding binding; + public AnimationCurve curve; + public ObjectReferenceKeyframe[] objectCurve; + } + + class CurveBindingGroup + { + public CurveBindingPair[] curveBindingPairs { get; set; } + public Vector2 timeRange { get; set; } + public Vector2 valueRange { get; set; } + + public bool isFloatCurve + { + get + { + return curveBindingPairs != null && curveBindingPairs.Length > 0 && + curveBindingPairs[0].curve != null; + } + } + + public bool isObjectCurve + { + get + { + return curveBindingPairs != null && curveBindingPairs.Length > 0 && + curveBindingPairs[0].objectCurve != null; + } + } + + public int count + { + get + { + if (curveBindingPairs == null) + return 0; + return curveBindingPairs.Length; + } + } + } + + class AnimationClipCurveInfo + { + bool m_CurveDirty = true; + bool m_KeysDirty = true; + + public bool dirty + { + get { return m_CurveDirty; } + set + { + m_CurveDirty = value; + if (m_CurveDirty) + { + m_KeysDirty = true; + if (m_groupings != null) + m_groupings.Clear(); + } + } + } + + public AnimationCurve[] curves; + public EditorCurveBinding[] bindings; + + public EditorCurveBinding[] objectBindings; + public List<ObjectReferenceKeyframe[]> objectCurves; + + Dictionary<string, CurveBindingGroup> m_groupings; + + // to tell whether the cache has changed + public int version { get; private set; } + + float[] m_KeyTimes; + + Dictionary<EditorCurveBinding, float[]> m_individualBindinsKey; + + public float[] keyTimes + { + get + { + if (m_KeysDirty || m_KeyTimes == null) + { + RebuildKeyCache(); + } + return m_KeyTimes; + } + } + + public float[] GetCurveTimes(EditorCurveBinding curve) + { + return GetCurveTimes(new[] { curve }); + } + + public float[] GetCurveTimes(EditorCurveBinding[] curves) + { + if (m_KeysDirty || m_KeyTimes == null) + { + RebuildKeyCache(); + } + + var keyTimes = new List<float>(); + for (int i = 0; i < curves.Length; i++) + { + var c = curves[i]; + if (m_individualBindinsKey.ContainsKey(c)) + { + keyTimes.AddRange(m_individualBindinsKey[c]); + } + } + return keyTimes.ToArray(); + } + + void RebuildKeyCache() + { + m_individualBindinsKey = new Dictionary<EditorCurveBinding, float[]>(); + + List<float> keys = curves.SelectMany(y => y.keys).Select(z => z.time).ToList(); + for (int i = 0; i < objectCurves.Count; i++) + { + var kf = objectCurves[i]; + keys.AddRange(kf.Select(x => x.time)); + } + + for (int b = 0; b < bindings.Count(); b++) + { + m_individualBindinsKey.Add(bindings[b], curves[b].keys.Select(k => k.time).Distinct().ToArray()); + } + + m_KeyTimes = keys.OrderBy(x => x).Distinct().ToArray(); + m_KeysDirty = false; + } + + public void Update(AnimationClip clip) + { + List<EditorCurveBinding> postfilter = new List<EditorCurveBinding>(); + var clipBindings = AnimationUtility.GetCurveBindings(clip); + for (int i = 0; i < clipBindings.Length; i++) + { + var bind = clipBindings[i]; + if (!bind.propertyName.Contains("LocalRotation.w")) + postfilter.Add(RotationCurveInterpolation.RemapAnimationBindingForRotationCurves(bind, clip)); + } + bindings = postfilter.ToArray(); + + curves = new AnimationCurve[bindings.Length]; + for (int i = 0; i < bindings.Length; i++) + { + curves[i] = AnimationUtility.GetEditorCurve(clip, bindings[i]); + } + + objectBindings = AnimationUtility.GetObjectReferenceCurveBindings(clip); + objectCurves = new List<ObjectReferenceKeyframe[]>(objectBindings.Length); + for (int i = 0; i < objectBindings.Length; i++) + { + objectCurves.Add(AnimationUtility.GetObjectReferenceCurve(clip, objectBindings[i])); + } + + m_CurveDirty = false; + m_KeysDirty = true; + + version = version + 1; + } + + public bool GetBindingForCurve(AnimationCurve curve, ref EditorCurveBinding binding) + { + for (int i = 0; i < curves.Length; i++) + { + if (curve == curves[i]) + { + binding = bindings[i]; + return true; + } + } + return false; + } + + public AnimationCurve GetCurveForBinding(EditorCurveBinding binding) + { + for (int i = 0; i < curves.Length; i++) + { + if (binding.Equals(bindings[i])) + { + return curves[i]; + } + } + return null; + } + + public ObjectReferenceKeyframe[] GetObjectCurveForBinding(EditorCurveBinding binding) + { + if (objectCurves == null) + return null; + + for (int i = 0; i < objectCurves.Count; i++) + { + if (binding.Equals(objectBindings[i])) + { + return objectCurves[i]; + } + } + return null; + } + + // given a groupID, get the list of curve bindings + public CurveBindingGroup GetGroupBinding(string groupID) + { + if (m_groupings == null) + m_groupings = new Dictionary<string, CurveBindingGroup>(); + + CurveBindingGroup result = null; + if (!m_groupings.TryGetValue(groupID, out result)) + { + result = new CurveBindingGroup(); + result.timeRange = new Vector2(float.MaxValue, float.MinValue); + result.valueRange = new Vector2(float.MaxValue, float.MinValue); + List<CurveBindingPair> found = new List<CurveBindingPair>(); + for (int i = 0; i < bindings.Length; i++) + { + if (bindings[i].GetGroupID() == groupID) + { + CurveBindingPair pair = new CurveBindingPair(); + pair.binding = bindings[i]; + pair.curve = curves[i]; + found.Add(pair); + + for (int k = 0; k < curves[i].keys.Length; k++) + { + var key = curves[i].keys[k]; + result.timeRange = new Vector2(Mathf.Min(key.time, result.timeRange.x), Mathf.Max(key.time, result.timeRange.y)); + result.valueRange = new Vector2(Mathf.Min(key.value, result.valueRange.x), Mathf.Max(key.value, result.valueRange.y)); + } + } + } + for (int i = 0; i < objectBindings.Length; i++) + { + if (objectBindings[i].GetGroupID() == groupID) + { + CurveBindingPair pair = new CurveBindingPair(); + pair.binding = objectBindings[i]; + pair.objectCurve = objectCurves[i]; + found.Add(pair); + + for (int k = 0; k < objectCurves[i].Length; k++) + { + var key = objectCurves[i][k]; + result.timeRange = new Vector2(Mathf.Min(key.time, result.timeRange.x), Mathf.Max(key.time, result.timeRange.y)); + } + } + } + + result.curveBindingPairs = found.OrderBy(x => AnimationWindowUtility.GetComponentIndex(x.binding.propertyName)).ToArray(); + + m_groupings.Add(groupID, result); + } + return result; + } + } + + // Cache for storing the animation clip data + class AnimationClipCurveCache + { + static AnimationClipCurveCache s_Instance; + Dictionary<AnimationClip, AnimationClipCurveInfo> m_ClipCache = new Dictionary<AnimationClip, AnimationClipCurveInfo>(); + bool m_IsEnabled; + + + public static AnimationClipCurveCache Instance + { + get + { + if (s_Instance == null) + { + s_Instance = new AnimationClipCurveCache(); + } + + return s_Instance; + } + } + + public void OnEnable() + { + if (!m_IsEnabled) + { + AnimationUtility.onCurveWasModified += OnCurveWasModified; + m_IsEnabled = true; + } + } + + public void OnDisable() + { + if (m_IsEnabled) + { + AnimationUtility.onCurveWasModified -= OnCurveWasModified; + m_IsEnabled = false; + } + } + + // callback when a curve is edited. Force the cache to update next time it's accessed + void OnCurveWasModified(AnimationClip clip, EditorCurveBinding binding, AnimationUtility.CurveModifiedType modification) + { + if (modification == AnimationUtility.CurveModifiedType.CurveDeleted) + { + m_ClipCache.Remove(clip); + } + else + { + AnimationClipCurveInfo data; + if (m_ClipCache.TryGetValue(clip, out data)) + { + data.dirty = true; + } + } + } + + public AnimationClipCurveInfo GetCurveInfo(AnimationClip clip) + { + AnimationClipCurveInfo data; + if (clip == null) + return null; + if (!m_ClipCache.TryGetValue(clip, out data)) + { + data = new AnimationClipCurveInfo(); + data.dirty = true; + m_ClipCache[clip] = data; + } + if (data.dirty) + { + data.Update(clip); + } + return data; + } + + public void ClearCachedProxyClips() + { + var toRemove = new List<AnimationClip>(); + foreach (var entry in m_ClipCache) + { + var clip = entry.Key; + if (clip != null && (clip.hideFlags & HideFlags.HideAndDontSave) == HideFlags.HideAndDontSave) + toRemove.Add(clip); + } + + foreach (var clip in toRemove) + { + m_ClipCache.Remove(clip); + Object.DestroyImmediate(clip, true); + } + } + + + public void Clear() + { + ClearCachedProxyClips(); + m_ClipCache.Clear(); + } + + } + + static class EditorCurveBindingExtension + { + // identifier to generate an id thats the same for all curves in the same group + public static string GetGroupID(this EditorCurveBinding binding) + { + return binding.type + AnimationWindowUtility.GetPropertyGroupName(binding.propertyName); + } + } + + + static class CurveBindingGroupExtensions + { + // Extentions to determine curve types + public static bool IsEnableGroup(this CurveBindingGroup curves) + { + return curves.isFloatCurve && curves.count == 1 && curves.curveBindingPairs[0].binding.propertyName == "m_Enabled"; + } + + public static bool IsVectorGroup(this CurveBindingGroup curves) + { + if (!curves.isFloatCurve) + return false; + if (curves.count <= 1 || curves.count > 4) + return false; + char l = curves.curveBindingPairs[0].binding.propertyName.Last(); + return l == 'x' || l == 'y' || l == 'z' || l == 'w'; + } + + public static bool IsColorGroup(this CurveBindingGroup curves) + { + if (!curves.isFloatCurve) + return false; + if (curves.count != 3 && curves.count != 4) + return false; + char l = curves.curveBindingPairs[0].binding.propertyName.Last(); + return l == 'r' || l == 'g' || l == 'b' || l == 'a'; + } + + public static string GetDescription(this CurveBindingGroup group, float t) + { + string result = string.Empty; + if (group.isFloatCurve) + { + if (group.count > 1) + { + result += "(" + group.curveBindingPairs[0].curve.Evaluate(t).ToString("0.##"); + for (int j = 1; j < group.curveBindingPairs.Length; j++) + { + result += "," + group.curveBindingPairs[j].curve.Evaluate(t).ToString("0.##"); + } + result += ")"; + } + else + { + result = group.curveBindingPairs[0].curve.Evaluate(t).ToString("0.##"); + } + } + else if (group.isObjectCurve) + { + Object obj = null; + if (group.curveBindingPairs[0].objectCurve.Length > 0) + obj = CurveEditUtility.Evaluate(group.curveBindingPairs[0].objectCurve, t); + result = (obj == null ? "None" : obj.name); + } + + return result; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationClipCurveCache.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationClipCurveCache.cs.meta new file mode 100644 index 0000000..47fcaa3 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationClipCurveCache.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 07a967d2fca95324f8922df8394a5655 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationOffsetMenu.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationOffsetMenu.cs new file mode 100644 index 0000000..dbfc688 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationOffsetMenu.cs @@ -0,0 +1,82 @@ +using System.Linq; +using UnityEngine; +using UnityEngine.Timeline; + +namespace UnityEditor.Timeline +{ + static class AnimationOffsetMenu + { + public static GUIContent MatchPreviousMenuItem = EditorGUIUtility.TrTextContent("Match Offsets To Previous Clip"); + public static GUIContent MatchNextMenuItem = EditorGUIUtility.TrTextContent("Match Offsets To Next Clip"); + public static string MatchFieldsPrefix = "Match Offsets Fields/"; + public static GUIContent ResetOffsetMenuItem = EditorGUIUtility.TrTextContent("Reset Offsets"); + + static bool EnforcePreviewMode(WindowState state) + { + state.previewMode = true; // try and set the preview mode + if (!state.previewMode) + { + Debug.LogError("Match clips cannot be completed because preview mode cannot be enabed"); + return false; + } + return true; + } + + internal static void MatchClipsToPrevious(WindowState state, TimelineClip[] clips) + { + if (!EnforcePreviewMode(state)) + return; + + clips = clips.OrderBy(x => x.start).ToArray(); + foreach (var clip in clips) + { + var sceneObject = TimelineUtility.GetSceneGameObject(state.editSequence.director, clip.parentTrack); + if (sceneObject != null) + { + TimelineUndo.PushUndo(clip.asset, "Match Clip"); + TimelineAnimationUtilities.MatchPrevious(clip, sceneObject.transform, state.editSequence.director); + } + } + + InspectorWindow.RepaintAllInspectors(); + TimelineEditor.Refresh(RefreshReason.ContentsModified); + } + + internal static void MatchClipsToNext(WindowState state, TimelineClip[] clips) + { + if (!EnforcePreviewMode(state)) + return; + + clips = clips.OrderByDescending(x => x.start).ToArray(); + foreach (var clip in clips) + { + var sceneObject = TimelineUtility.GetSceneGameObject(state.editSequence.director, clip.parentTrack); + if (sceneObject != null) + { + TimelineUndo.PushUndo(clip.asset, "Match Clip"); + TimelineAnimationUtilities.MatchNext(clip, sceneObject.transform, state.editSequence.director); + } + } + + InspectorWindow.RepaintAllInspectors(); + TimelineEditor.Refresh(RefreshReason.ContentsModified); + } + + public static void ResetClipOffsets(WindowState state, TimelineClip[] clips) + { + foreach (var clip in clips) + { + if (clip.asset is AnimationPlayableAsset) + { + TimelineUndo.PushUndo(clip.asset, "Reset Offsets"); + var playableAsset = (AnimationPlayableAsset)clip.asset; + playableAsset.ResetOffsets(); + } + } + state.rebuildGraph = true; + + InspectorWindow.RepaintAllInspectors(); + TimelineEditor.Refresh(RefreshReason.SceneNeedsUpdate); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationOffsetMenu.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationOffsetMenu.cs.meta new file mode 100644 index 0000000..e628663 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationOffsetMenu.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9ace5095cc37ed849b52109d2ee305d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationPlayableAssetEditor.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationPlayableAssetEditor.cs new file mode 100644 index 0000000..e4bebc1 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationPlayableAssetEditor.cs @@ -0,0 +1,65 @@ +using JetBrains.Annotations; +using UnityEngine; +using UnityEngine.Playables; +using UnityEngine.Timeline; + +namespace UnityEditor.Timeline +{ + [CustomTimelineEditor(typeof(AnimationPlayableAsset)), UsedImplicitly] + class AnimationPlayableAssetEditor : ClipEditor + { + public static readonly string k_NoClipAssignedError = LocalizationDatabase.GetLocalizedString("No animation clip assigned"); + public static readonly string k_LegacyClipError = LocalizationDatabase.GetLocalizedString("Legacy animation clips are not supported"); + static readonly string k_MotionCurveError = LocalizationDatabase.GetLocalizedString("You are using motion curves without applyRootMotion enabled on the Animator. The root transform will not be animated"); + static readonly string k_RootCurveError = LocalizationDatabase.GetLocalizedString("You are using root curves without applyRootMotion enabled on the Animator. The root transform will not be animated"); + + /// <inheritdoc/> + public override ClipDrawOptions GetClipOptions(TimelineClip clip) + { + var clipOptions = base.GetClipOptions(clip); + var asset = clip.asset as AnimationPlayableAsset; + + if (asset != null) + clipOptions.errorText = GetErrorText(asset, clip.parentTrack as AnimationTrack, clipOptions.errorText); + + if (clip.recordable) + clipOptions.highlightColor = DirectorStyles.Instance.customSkin.colorAnimationRecorded; + + return clipOptions; + } + + /// <inheritdoc /> + public override void OnCreate(TimelineClip clip, TrackAsset track, TimelineClip clonedFrom) + { + var asset = clip.asset as AnimationPlayableAsset; + if (asset != null && asset.clip != null && asset.clip.legacy) + { + asset.clip = null; + Debug.LogError("Legacy Animation Clips are not supported"); + } + } + + string GetErrorText(AnimationPlayableAsset animationAsset, AnimationTrack track, string defaultError) + { + if (animationAsset.clip == null) + return k_NoClipAssignedError; + if (animationAsset.clip.legacy) + return k_LegacyClipError; + if (animationAsset.clip.hasMotionCurves || animationAsset.clip.hasRootCurves) + { + if (track != null && track.trackOffset == TrackOffset.Auto) + { + var animator = track.GetBinding(TimelineEditor.inspectedDirector); + if (animator != null && !animator.applyRootMotion && !animationAsset.clip.hasGenericRootTransform) + { + if (animationAsset.clip.hasMotionCurves) + return k_MotionCurveError; + return k_RootCurveError; + } + } + } + + return defaultError; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationPlayableAssetEditor.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationPlayableAssetEditor.cs.meta new file mode 100644 index 0000000..0a749e8 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationPlayableAssetEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7fed0d9d0f7a7f41a8525aa79e790b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationTrackActions.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationTrackActions.cs new file mode 100644 index 0000000..0b1a171 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationTrackActions.cs @@ -0,0 +1,151 @@ +using System.ComponentModel; +using System.Linq; +using JetBrains.Annotations; +using UnityEngine; +using UnityEngine.Timeline; + +namespace UnityEditor.Timeline +{ + [MenuEntry("Add Override Track", MenuOrder.CustomTrackAction.AnimAddOverrideTrack), UsedImplicitly] + class AddOverrideTrackAction : TrackAction + { + public override bool Execute(WindowState state, TrackAsset[] tracks) + { + foreach (var animTrack in tracks.OfType<AnimationTrack>()) + { + TimelineHelpers.CreateTrack(typeof(AnimationTrack), animTrack, "Override " + animTrack.GetChildTracks().Count()); + } + + return true; + } + + protected override MenuActionDisplayState GetDisplayState(WindowState state, TrackAsset[] tracks) + { + if (tracks.Any(t => t.isSubTrack || !t.GetType().IsAssignableFrom(typeof(AnimationTrack)))) + return MenuActionDisplayState.Hidden; + + if (tracks.Any(t => t.lockedInHierarchy)) + return MenuActionDisplayState.Disabled; + + return MenuActionDisplayState.Visible; + } + } + + [MenuEntry("Convert To Clip Track", MenuOrder.CustomTrackAction.AnimConvertToClipMode), UsedImplicitly] + class ConvertToClipModeAction : TrackAction + { + public override bool Execute(WindowState state, TrackAsset[] tracks) + { + foreach (var animTrack in tracks.OfType<AnimationTrack>()) + animTrack.ConvertToClipMode(); + + TimelineEditor.Refresh(RefreshReason.ContentsAddedOrRemoved); + + return true; + } + + protected override MenuActionDisplayState GetDisplayState(WindowState state, TrackAsset[] tracks) + { + if (tracks.Any(t => !t.GetType().IsAssignableFrom(typeof(AnimationTrack)))) + return MenuActionDisplayState.Hidden; + + if (tracks.Any(t => t.lockedInHierarchy)) + return MenuActionDisplayState.Disabled; + + if (tracks.OfType<AnimationTrack>().All(a => a.CanConvertToClipMode())) + return MenuActionDisplayState.Visible; + + return MenuActionDisplayState.Hidden; + } + } + + [MenuEntry("Convert To Infinite Clip", MenuOrder.CustomTrackAction.AnimConvertFromClipMode), UsedImplicitly] + class ConvertFromClipTrackAction : TrackAction + { + public override bool Execute(WindowState state, TrackAsset[] tracks) + { + foreach (var animTrack in tracks.OfType<AnimationTrack>()) + animTrack.ConvertFromClipMode(state.editSequence.asset); + + TimelineEditor.Refresh(RefreshReason.ContentsAddedOrRemoved); + + return true; + } + + protected override MenuActionDisplayState GetDisplayState(WindowState state, TrackAsset[] tracks) + { + if (tracks.Any(t => !t.GetType().IsAssignableFrom(typeof(AnimationTrack)))) + return MenuActionDisplayState.Hidden; + + if (tracks.Any(t => t.lockedInHierarchy)) + return MenuActionDisplayState.Disabled; + + if (tracks.OfType<AnimationTrack>().All(a => a.CanConvertFromClipMode())) + return MenuActionDisplayState.Visible; + + return MenuActionDisplayState.Hidden; + } + } + + abstract class TrackOffsetBaseAction : TrackAction + { + public abstract TrackOffset trackOffset { get; } + + protected override MenuActionDisplayState GetDisplayState(WindowState state, TrackAsset[] tracks) + { + if (tracks.Any(t => !t.GetType().IsAssignableFrom(typeof(AnimationTrack)))) + return MenuActionDisplayState.Hidden; + + if (tracks.Any(t => t.lockedInHierarchy)) + return MenuActionDisplayState.Disabled; + + return MenuActionDisplayState.Visible; + } + + protected override bool IsChecked(WindowState state, TrackAsset[] tracks) + { + return tracks.OfType<AnimationTrack>().All(t => t.trackOffset == trackOffset); + } + + public override bool Execute(WindowState state, TrackAsset[] tracks) + { + foreach (var animTrack in tracks.OfType<AnimationTrack>()) + { + state.UnarmForRecord(animTrack); + TimelineUndo.PushUndo(animTrack, "Set Transform Offsets"); + animTrack.trackOffset = trackOffset; + } + + TimelineEditor.Refresh(RefreshReason.ContentsModified); + return true; + } + } + + + [MenuEntry("Track Offsets/Apply Transform Offsets", MenuOrder.CustomTrackAction.AnimApplyTrackOffset), UsedImplicitly] + class ApplyTransformOffsetAction : TrackOffsetBaseAction + { + public override TrackOffset trackOffset + { + get { return TrackOffset.ApplyTransformOffsets; } + } + } + + [MenuEntry("Track Offsets/Apply Scene Offsets", MenuOrder.CustomTrackAction.AnimApplySceneOffset), UsedImplicitly] + class ApplySceneOffsetAction : TrackOffsetBaseAction + { + public override TrackOffset trackOffset + { + get { return TrackOffset.ApplySceneOffsets; } + } + } + + [MenuEntry("Track Offsets/Auto (Deprecated)", MenuOrder.CustomTrackAction.AnimApplyAutoOffset), UsedImplicitly] + class ApplyAutoAction : TrackOffsetBaseAction + { + public override TrackOffset trackOffset + { + get { return TrackOffset.Auto; } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationTrackActions.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationTrackActions.cs.meta new file mode 100644 index 0000000..4ca0e4d --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/AnimationTrackActions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d4553f2006f48b6448553cb525d2876e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingSelector.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingSelector.cs new file mode 100644 index 0000000..7f3cdde --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingSelector.cs @@ -0,0 +1,224 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor.IMGUI.Controls; +using UnityEditor.Timeline; +using UnityEditorInternal; +using UnityEngine; +using UnityEngine.Timeline; + +namespace UnityEditor +{ + class BindingSelector + { + TreeViewController m_TreeView; + public TreeViewController treeViewController + { + get { return m_TreeView; } + } + + TreeViewState m_TrackGlobalTreeViewState; + TreeViewState m_TreeViewState; + BindingTreeViewDataSource m_TreeViewDataSource; + CurveDataSource m_CurveDataSource; + TimelineWindow m_Window; + CurveEditor m_CurveEditor; + ReorderableList m_DopeLines; + string[] m_StringList = {}; + int[] m_Selection; + bool m_PartOfSelection; + public BindingSelector(EditorWindow window, CurveEditor curveEditor, TreeViewState trackGlobalTreeViewState) + { + m_Window = window as TimelineWindow; + m_CurveEditor = curveEditor; + m_TrackGlobalTreeViewState = trackGlobalTreeViewState; + + m_DopeLines = new ReorderableList(m_StringList, typeof(string), false, false, false, false); + m_DopeLines.drawElementBackgroundCallback = null; + m_DopeLines.showDefaultBackground = false; + m_DopeLines.index = 0; + m_DopeLines.headerHeight = 0; + m_DopeLines.elementHeight = 20; + m_DopeLines.draggable = false; + } + + public bool selectable { get { return true; } } + + public object selectableObject + { + get { return this; } + } + + public bool selected + { + get { return m_PartOfSelection; } + set + { + m_PartOfSelection = value; + + if (!m_PartOfSelection) + { + m_DopeLines.index = -1; + } + } + } + + public virtual void Delete(WindowState state) + { + // we dont support deleting the summary + if (m_DopeLines.index < 1) + return; + + if (m_CurveDataSource == null) + return; + + var clip = m_CurveDataSource.animationClip; + if (clip == null) + return; + + int curveIndexToDelete = m_DopeLines.index - 1; + var bindings = AnimationUtility.GetCurveBindings(clip); + + if (curveIndexToDelete >= bindings.Length) + return; + + TimelineUndo.PushUndo(clip, "Delete Curve"); + AnimationUtility.SetEditorCurve(clip, bindings[m_DopeLines.index - 1], null); + state.rebuildGraph = true; + } + + public void OnGUI(Rect targetRect) + { + if (m_TreeView == null) + return; + + m_TreeView.OnEvent(); + m_TreeView.OnGUI(targetRect, GUIUtility.GetControlID(FocusType.Passive)); + } + + public void InitIfNeeded(Rect rect, CurveDataSource dataSource, bool isNewSelection) + { + if (Event.current.type != EventType.Layout) + return; + + m_CurveDataSource = dataSource; + var clip = dataSource.animationClip; + + List<EditorCurveBinding> allBindings = new List<EditorCurveBinding>(); + allBindings.Add(new EditorCurveBinding { propertyName = "Summary" }); + if (clip != null) + allBindings.AddRange(AnimationUtility.GetCurveBindings(clip)); + + m_DopeLines.list = allBindings.ToArray(); + + if (m_TreeViewState != null) + { + if (isNewSelection) + RefreshAll(); + + return; + } + + m_TreeViewState = m_TrackGlobalTreeViewState != null ? m_TrackGlobalTreeViewState : new TreeViewState(); + + m_TreeView = new TreeViewController(m_Window, m_TreeViewState) + { + useExpansionAnimation = false, + deselectOnUnhandledMouseDown = true + }; + + m_TreeView.selectionChangedCallback += OnItemSelectionChanged; + + m_TreeViewDataSource = new BindingTreeViewDataSource(m_TreeView, clip, m_CurveDataSource); + + m_TreeView.Init(rect, m_TreeViewDataSource, new BindingTreeViewGUI(m_TreeView), null); + + m_TreeViewDataSource.UpdateData(); + + RefreshSelection(); + } + + void OnItemSelectionChanged(int[] selection) + { + RefreshSelection(selection); + } + + void RefreshAll() + { + RefreshTree(); + RefreshSelection(); + } + + void RefreshSelection() + { + RefreshSelection(m_TreeViewState.selectedIDs != null ? m_TreeViewState.selectedIDs.ToArray() : null); + } + + void RefreshSelection(int[] selection) + { + if (selection == null || selection.Length == 0) + { + // select all. + if (m_TreeViewDataSource.GetRows().Count > 0) + { + m_Selection = m_TreeViewDataSource.GetRows().Select(r => r.id).ToArray(); + } + } + else + { + m_Selection = selection; + } + + RefreshCurves(); + } + + public void RefreshCurves() + { + if (m_CurveDataSource == null || m_Selection == null) + return; + + var bindings = new List<EditorCurveBinding>(); + foreach (int s in m_Selection) + { + var item = (CurveTreeViewNode)m_TreeView.FindItem(s); + if (item != null && item.bindings != null) + bindings.AddRange(item.bindings); + } + + var wrappers = m_CurveDataSource.GenerateWrappers(bindings); + m_CurveEditor.animationCurves = wrappers.ToArray(); + } + + public void RefreshTree() + { + if (m_TreeViewDataSource == null) + return; + + if (m_Selection == null) + m_Selection = new int[0]; + + // get the names of the previous items + var selected = m_Selection.Select(x => m_TreeViewDataSource.FindItem(x)).Where(t => t != null).Select(c => c.displayName).ToArray(); + + // update the source + m_TreeViewDataSource.UpdateData(); + + // find the same items + var reselected = m_TreeViewDataSource.GetRows().Where(x => selected.Contains(x.displayName)).Select(x => x.id).ToArray(); + if (!reselected.Any()) + { + if (m_TreeViewDataSource.GetRows().Count > 0) + { + reselected = new[] { m_TreeViewDataSource.GetItem(0).id }; + } + } + + // update the selection + OnItemSelectionChanged(reselected); + } + + internal virtual bool IsRenamingNodeAllowed(TreeViewItem node) + { + return false; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingSelector.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingSelector.cs.meta new file mode 100644 index 0000000..b08aa56 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c171b9ca03610ea4faa426e082a1075d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingTreeViewDataSource.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingTreeViewDataSource.cs new file mode 100644 index 0000000..8118285 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingTreeViewDataSource.cs @@ -0,0 +1,139 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEditor.IMGUI.Controls; +using UnityEditor.Timeline; +using UnityEngine; + +namespace UnityEditorInternal +{ + class BindingTreeViewDataSource : TreeViewDataSource + { + public const int RootID = int.MinValue; + public const int GroupID = -1; + + AnimationClip m_Clip; + CurveDataSource m_CurveDataSource; + + public BindingTreeViewDataSource( + TreeViewController treeView, AnimationClip clip, CurveDataSource curveDataSource) + : base(treeView) + { + m_Clip = clip; + showRootItem = false; + m_CurveDataSource = curveDataSource; + } + + void SetupRootNodeSettings() + { + showRootItem = false; + SetExpanded(RootID, true); + SetExpanded(GroupID, true); + } + + static string GroupName(EditorCurveBinding binding) + { + string property = AnimationWindowUtility.NicifyPropertyGroupName(binding.type, binding.propertyName); + if (!string.IsNullOrEmpty(binding.path)) + { + property = binding.path + " : " + property; + } + + int lastArrayIdx = property.LastIndexOf("Array."); + if (lastArrayIdx != -1) + { + property = property.Substring(0, lastArrayIdx - 1); + } + return property; + } + + static string PropertyName(EditorCurveBinding binding, string arrayPrefixToRemove = "") + { + string propertyName = AnimationWindowUtility.GetPropertyDisplayName(binding.propertyName); + if (propertyName.Contains("Array")) + { + propertyName = propertyName.Replace("Array.", ""); + propertyName = propertyName.Replace(arrayPrefixToRemove, ""); + propertyName = propertyName.TrimStart('.'); + } + return propertyName; + } + + public override void FetchData() + { + if (m_Clip == null) + return; + + var bindings = AnimationUtility.GetCurveBindings(m_Clip) + .Union(AnimationUtility.GetObjectReferenceCurveBindings(m_Clip)) + .ToArray(); + + var results = bindings.GroupBy(p => GroupName(p), p => p, (key, g) => new + { + parent = key, + bindings = g.ToList() + }).OrderBy(t => + { + //Force transform order first + if (t.parent == "Position") return -3; + if (t.parent == "Rotation") return -2; + if (t.parent == "Scale") return -1; + return 0; + }).ThenBy(t => t.parent); + + m_RootItem = new CurveTreeViewNode(RootID, null, "root", null) + { + children = new List<TreeViewItem>(1) + }; + + var groupingNode = new CurveTreeViewNode(GroupID, m_RootItem, m_CurveDataSource.groupingName, bindings) + { + children = new List<TreeViewItem>() + }; + + m_RootItem.children.Add(groupingNode); + + foreach (var r in results) + { + var newNode = new CurveTreeViewNode(r.parent.GetHashCode(), groupingNode, r.parent, r.bindings.ToArray()); + groupingNode.children.Add(newNode); + if (r.bindings.Count > 1) + { + for (int b = 0; b < r.bindings.Count; b++) + { + if (newNode.children == null) + newNode.children = new List<TreeViewItem>(); + + var binding = r.bindings[b]; + var bindingNode = new CurveTreeViewNode(binding.GetHashCode(), newNode, PropertyName(binding, newNode.displayName), new[] {binding}); + newNode.children.Add(bindingNode); + } + } + } + + SetupRootNodeSettings(); + m_NeedRefreshRows = true; + } + + public void UpdateData() + { + m_TreeView.ReloadData(); + } + } + + class CurveTreeViewNode : TreeViewItem + { + EditorCurveBinding[] m_Bindings; + + public EditorCurveBinding[] bindings + { + get { return m_Bindings; } + } + + public CurveTreeViewNode(int id, TreeViewItem parent, string displayName, EditorCurveBinding[] bindings) + : base(id, parent != null ? parent.depth + 1 : -1, parent, displayName) + { + m_Bindings = bindings; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingTreeViewDataSource.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingTreeViewDataSource.cs.meta new file mode 100644 index 0000000..b553947 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingTreeViewDataSource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9c2177aaf0fde92439246adc2dc0bfa2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingTreeViewDataSourceGUI.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingTreeViewDataSourceGUI.cs new file mode 100644 index 0000000..443a216 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingTreeViewDataSourceGUI.cs @@ -0,0 +1,80 @@ +using UnityEditor; +using UnityEditor.IMGUI.Controls; +using UnityEngine; + +namespace UnityEditorInternal +{ + class BindingTreeViewGUI : TreeViewGUI + { + static readonly float s_RowRightOffset = 10; + static readonly float s_ColorIndicatorTopMargin = 3; + static readonly Color s_KeyColorForNonCurves = new Color(0.7f, 0.7f, 0.7f, 0.5f); + static readonly Color s_ChildrenCurveLabelColor = new Color(1.0f, 1.0f, 1.0f, 0.7f); + + public BindingTreeViewGUI(TreeViewController treeView) + : base(treeView, true) + { + k_IconWidth = 13.0f; + } + + public override void OnRowGUI(Rect rowRect, TreeViewItem node, int row, bool selected, bool focused) + { + Color originalColor = GUI.color; + GUI.color = node.parent == null || + node.parent.id == BindingTreeViewDataSource.RootID || + node.parent.id == BindingTreeViewDataSource.GroupID ? + Color.white : + s_ChildrenCurveLabelColor; + + base.OnRowGUI(rowRect, node, row, selected, focused); + + GUI.color = originalColor; + DoCurveColorIndicator(rowRect, node as CurveTreeViewNode); + } + + protected override bool IsRenaming(int id) + { + return false; + } + + public override bool BeginRename(TreeViewItem item, float delay) + { + return false; + } + + void DoCurveColorIndicator(Rect rect, CurveTreeViewNode node) + { + if (node == null) + return; + + if (Event.current.type != EventType.Repaint) + return; + + Color originalColor = GUI.color; + + if (node.bindings.Length == 1 && !node.bindings[0].isPPtrCurve) + GUI.color = CurveUtility.GetPropertyColor(node.bindings[0].propertyName); + else + GUI.color = s_KeyColorForNonCurves; + + Texture icon = CurveUtility.GetIconCurve(); + rect = new Rect(rect.xMax - s_RowRightOffset - (icon.width * 0.5f) - 5, rect.yMin + s_ColorIndicatorTopMargin, icon.width, icon.height); + + GUI.DrawTexture(rect, icon, ScaleMode.ScaleToFit, true, 1); + + GUI.color = originalColor; + } + + protected override Texture GetIconForItem(TreeViewItem item) + { + var node = item as CurveTreeViewNode; + if (node == null) + return null; + + if (node.bindings == null || node.bindings.Length == 0) + return null; + + return AssetPreview.GetMiniTypeThumbnail(node.bindings[0].type); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingTreeViewDataSourceGUI.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingTreeViewDataSourceGUI.cs.meta new file mode 100644 index 0000000..2e16c1b --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/BindingTreeViewDataSourceGUI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c09dc5cd0a70cf40856b7d406106ee1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/ClipCurveEditor.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/ClipCurveEditor.cs new file mode 100644 index 0000000..da1d0e6 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/ClipCurveEditor.cs @@ -0,0 +1,332 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.Timeline; +using UnityEngine; +using UnityEngine.Timeline; + +namespace UnityEditor +{ + class ClipCurveEditor + { + internal readonly CurveEditor m_CurveEditor; + static readonly CurveEditorSettings s_CurveEditorSettings = new CurveEditorSettings + { + hSlider = false, + vSlider = false, + hRangeLocked = false, + vRangeLocked = false, + scaleWithWindow = true, + hRangeMin = 0.0f, + showAxisLabels = true, + allowDeleteLastKeyInCurve = true, + rectangleToolFlags = CurveEditorSettings.RectangleToolFlags.MiniRectangleTool + }; + + static readonly float s_GridLabelWidth = 40.0f; + + readonly BindingSelector m_BindingHierarchy; + public BindingSelector bindingHierarchy + { + get { return m_BindingHierarchy; } + } + + public Rect shownAreaInsideMargins + { + get { return m_CurveEditor != null ? m_CurveEditor.shownAreaInsideMargins : new Rect(1, 1, 1, 1); } + } + + Vector2 m_ScrollPosition = Vector2.zero; + + readonly CurveDataSource m_DataSource; + + float m_LastFrameRate = 30.0f; + int m_LastClipVersion = -1; + int m_LastCurveCount = -1; + TrackViewModelData m_ViewModel; + bool m_ShouldRestoreShownArea; + + bool isNewSelection + { + get + { + if (m_ViewModel == null || m_DataSource == null) + return true; + + return m_ViewModel.lastInlineCurveDataID != m_DataSource.id; + } + } + + internal CurveEditor curveEditor + { + get { return m_CurveEditor; } + } + + public ClipCurveEditor(CurveDataSource dataSource, TimelineWindow parentWindow, TrackAsset hostTrack) + { + m_DataSource = dataSource; + + m_CurveEditor = new CurveEditor(new Rect(0, 0, 1000, 100), new CurveWrapper[0], false); + + s_CurveEditorSettings.vTickStyle = new TickStyle + { + tickColor = { color = DirectorStyles.Instance.customSkin.colorInlineCurveVerticalLines }, + distLabel = 20, + stubs = true + }; + + s_CurveEditorSettings.hTickStyle = new TickStyle + { + // hide horizontal lines by giving them a transparent color + tickColor = { color = new Color(0.0f, 0.0f, 0.0f, 0.0f) }, + distLabel = 0 + }; + + m_CurveEditor.settings = s_CurveEditorSettings; + + m_ViewModel = TimelineWindowViewPrefs.GetTrackViewModelData(hostTrack); + + m_ShouldRestoreShownArea = true; + m_CurveEditor.ignoreScrollWheelUntilClicked = true; + m_CurveEditor.curvesUpdated = OnCurvesUpdated; + + m_BindingHierarchy = new BindingSelector(parentWindow, m_CurveEditor, m_ViewModel.inlineCurvesState); + } + + public void SelectAllKeys() + { + m_CurveEditor.SelectAll(); + } + + public void FrameClip() + { + m_CurveEditor.InvalidateBounds(); + m_CurveEditor.FrameClip(false, true); + } + + public CurveDataSource dataSource + { + get { return m_DataSource; } + } + + internal void OnCurvesUpdated() + { + if (m_DataSource == null) + return; + + if (m_CurveEditor == null) + return; + + if (m_CurveEditor.animationCurves.Length == 0) + return; + + List<CurveWrapper> curvesToUpdate = m_CurveEditor.animationCurves.Where(c => c.changed).ToList(); + + // nothing changed, return. + if (curvesToUpdate.Count == 0) + return; + + AnimationClip clip = m_DataSource.animationClip; + + // something changed, manage the undo properly. + Undo.RegisterCompleteObjectUndo(clip, "Edit Clip Curve"); + + foreach (CurveWrapper c in curvesToUpdate) + { + AnimationUtility.SetEditorCurve(clip, c.binding, c.curve); + c.changed = false; + } + + m_DataSource.UpdateCurves(curvesToUpdate); + } + + public void DrawHeader(Rect headerRect) + { + m_BindingHierarchy.InitIfNeeded(headerRect, m_DataSource, isNewSelection); + + try + { + GUILayout.BeginArea(headerRect); + m_ScrollPosition = GUILayout.BeginScrollView(m_ScrollPosition, GUIStyle.none, GUI.skin.verticalScrollbar); + m_BindingHierarchy.OnGUI(new Rect(0, 0, headerRect.width, headerRect.height)); + GUILayout.EndScrollView(); + GUILayout.EndArea(); + } + catch (Exception e) + { + Debug.LogException(e); + } + } + + class FrameFormatCurveEditorState : ICurveEditorState + { + public TimeArea.TimeFormat timeFormat + { + get { return TimeArea.TimeFormat.Frame; } + } + public Vector2 timeRange { get { return new Vector2(0, 1); } } + public bool rippleTime { get { return false; } } + } + + class UnformattedCurveEditorState : ICurveEditorState + { + public TimeArea.TimeFormat timeFormat + { + get { return TimeArea.TimeFormat.None; } + } + public Vector2 timeRange { get { return new Vector2(0, 1); } } + public bool rippleTime { get { return false; } } + } + + void UpdateCurveEditorIfNeeded(WindowState state) + { + if ((Event.current.type != EventType.Layout) || (m_DataSource == null) || (m_BindingHierarchy == null) || (m_DataSource.animationClip == null)) + return; + + AnimationClipCurveInfo curveInfo = AnimationClipCurveCache.Instance.GetCurveInfo(m_DataSource.animationClip); + int version = curveInfo.version; + if (version != m_LastClipVersion) + { + // tree has changed + if (m_LastCurveCount != curveInfo.curves.Length) + { + m_BindingHierarchy.RefreshTree(); + m_LastCurveCount = curveInfo.curves.Length; + } + else + { + // update just the curves + m_BindingHierarchy.RefreshCurves(); + } + m_LastClipVersion = version; + } + + if (state.timeInFrames) + m_CurveEditor.state = new FrameFormatCurveEditorState(); + else + m_CurveEditor.state = new UnformattedCurveEditorState(); + + m_CurveEditor.invSnap = state.referenceSequence.frameRate; + } + + public void DrawCurveEditor(Rect rect, WindowState state, Vector2 clipRange, bool loop, bool selected) + { + var curveEndTime = m_DataSource.start + m_DataSource.animationClip.length / m_DataSource.timeScale; + var curveRange = new Vector2(state.TimeToPixel(m_DataSource.start), state.TimeToPixel(curveEndTime)); + + SetupMarginsAndRect(rect, curveRange, state); + UpdateCurveEditorIfNeeded(state); + + if (m_ShouldRestoreShownArea) + RestoreShownArea(); + m_CurveEditor.SetShownHRangeInsideMargins(0.0f, m_DataSource.animationClip.length); //align the curve with the clip. + + if (m_LastFrameRate != state.referenceSequence.frameRate) + { + m_CurveEditor.hTicks.SetTickModulosForFrameRate(state.referenceSequence.frameRate); + m_LastFrameRate = state.referenceSequence.frameRate; + } + + foreach (var cw in m_CurveEditor.animationCurves) + cw.renderer.SetWrap(WrapMode.Default, loop ? WrapMode.Loop : WrapMode.Default); + + using (new GUIGroupScope(rect)) + { + var localRect = new Rect(0.0f, 0.0f, rect.width, rect.height); + var localClipRange = new Vector2(Mathf.Floor(clipRange.x - rect.xMin), Mathf.Ceil(clipRange.y - rect.xMin)); + var localCurveRange = new Vector2(Mathf.Floor(curveRange.x - rect.xMin), Mathf.Ceil(curveRange.y - rect.xMin)); + + EditorGUI.DrawRect(new Rect(localCurveRange.x, 0.0f, 1.0f, rect.height), new Color(1.0f, 1.0f, 1.0f, 0.5f)); + DrawCurveEditorBackground(localRect, localClipRange); + + if (selected) + { + var selectionRect = new Rect(localClipRange.x, 0.0f, localClipRange.y - localClipRange.x, localRect.height); + DrawOutline(selectionRect); + } + + EditorGUI.BeginChangeCheck(); + { + var evt = Event.current; + if (evt.type == EventType.Layout || evt.type == EventType.Repaint || selected) + m_CurveEditor.CurveGUI(); + } + if (EditorGUI.EndChangeCheck()) + OnCurvesUpdated(); + + DrawOverlay(localRect, localClipRange, DirectorStyles.Instance.customSkin.colorInlineCurveOutOfRangeOverlay); + DrawGrid(localRect, localCurveRange); + } + } + + void SetupMarginsAndRect(Rect rect, Vector2 curveRange, WindowState state) + { + var timelineWidth = state.TimeToPixel(Mathf.Max((float)state.editSequence.duration, state.timeAreaShownRange.y)); + m_CurveEditor.rect = new Rect(-rect.xMin, 0.0f, timelineWidth, rect.height); + m_CurveEditor.leftmargin = curveRange.x; + m_CurveEditor.rightmargin = timelineWidth - curveRange.y; + m_CurveEditor.topmargin = m_CurveEditor.bottommargin = CalculateTopMargin(rect.height); + } + + void RestoreShownArea() + { + if (isNewSelection) + FrameClip(); + else + m_CurveEditor.shownAreaInsideMargins = m_ViewModel.inlineCurvesShownAreaInsideMargins; + m_ShouldRestoreShownArea = false; + } + + static void DrawCurveEditorBackground(Rect rect, Vector2 activeRange) + { + if (EditorGUIUtility.isProSkin) + return; + + var animEditorBackgroundRect = Rect.MinMaxRect(0.0f, rect.yMin, rect.xMax, rect.yMax); + + // Curves are not legible in Personal Skin so we need to darken the background a bit. + EditorGUI.DrawRect(animEditorBackgroundRect, DirectorStyles.Instance.customSkin.colorInlineCurvesBackground); + } + + static float CalculateTopMargin(float height) + { + return Mathf.Clamp(0.15f * height, 10.0f, 40.0f); + } + + static void DrawOutline(Rect rect, float thickness = 2.0f) + { + // Draw top selected lines. + EditorGUI.DrawRect(new Rect(rect.xMin, rect.yMin, rect.width, thickness), Color.white); + + // Draw bottom selected lines. + EditorGUI.DrawRect(new Rect(rect.xMin, rect.yMax - thickness, rect.width, thickness), Color.white); + + // Draw Left Selected Lines + EditorGUI.DrawRect(new Rect(rect.xMin, rect.yMin, thickness, rect.height), Color.white); + + // Draw Right Selected Lines + EditorGUI.DrawRect(new Rect(rect.xMax - thickness, rect.yMin, thickness, rect.height), Color.white); + } + + static void DrawOverlay(Rect rect, Vector2 clipRange, Color color) + { + var leftSide = new Rect(rect.xMin, rect.yMin, clipRange.x - rect.xMin, rect.height); + EditorGUI.DrawRect(leftSide, color); + + var rightSide = new Rect(Mathf.Max(0.0f, clipRange.y), rect.yMin, rect.xMax, rect.height); + EditorGUI.DrawRect(rightSide, color); + } + + void DrawGrid(Rect rect, Vector2 curveRange) + { + var gridXPos = Mathf.Max(curveRange.x - s_GridLabelWidth, rect.xMin); + var gridRect = new Rect(gridXPos, rect.y, s_GridLabelWidth, rect.height); + var originalRect = m_CurveEditor.rect; + + m_CurveEditor.rect = new Rect(0.0f, 0.0f, rect.width, rect.height); + using (new GUIGroupScope(gridRect)) + m_CurveEditor.GridGUI(); + m_CurveEditor.rect = originalRect; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/ClipCurveEditor.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/ClipCurveEditor.cs.meta new file mode 100644 index 0000000..5ae80d2 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/ClipCurveEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d49b2ed20045e034f9cdf6a6d95e6183 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/CurveDataSource.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/CurveDataSource.cs new file mode 100644 index 0000000..b5ad13b --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/CurveDataSource.cs @@ -0,0 +1,272 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Timeline; + +namespace UnityEditor.Timeline +{ + abstract class CurveDataSource + { + public static CurveDataSource Create(IRowGUI trackGUI) + { + if (trackGUI.asset is AnimationTrack) + return new InfiniteClipCurveDataSource(trackGUI); + + return new TrackParametersCurveDataSource(trackGUI); + } + + public static CurveDataSource Create(TimelineClipGUI clipGUI) + { + if (clipGUI.clip.animationClip != null) + return new ClipAnimationCurveDataSource(clipGUI); + + return new ClipParametersCurveDataSource(clipGUI); + } + + int? m_ID = null; + public int id + { + get + { + if (!m_ID.HasValue) + m_ID = CreateHashCode(); + + return m_ID.Value; + } + } + + readonly IRowGUI m_TrackGUI; + protected IRowGUI trackGUI { get { return m_TrackGUI; } } + + protected CurveDataSource(IRowGUI trackGUI) + { + m_TrackGUI = trackGUI; + } + + public abstract AnimationClip animationClip { get; } + public abstract float start { get; } + public abstract float timeScale { get; } + public abstract string groupingName { get; } + public virtual void UpdateCurves(List<CurveWrapper> updatedCurves) {} + public virtual void RebuildCurves() {} // Only necessary when using proxies + + public Rect GetBackgroundRect(WindowState state) + { + var trackRect = m_TrackGUI.boundingRect; + return new Rect( + state.timeAreaTranslation.x + trackRect.xMin, + trackRect.y, + (float)state.editSequence.asset.duration * state.timeAreaScale.x, + trackRect.height + ); + } + + public List<CurveWrapper> GenerateWrappers(List<EditorCurveBinding> bindings) + { + var wrappers = new List<CurveWrapper>(bindings.Count); + int curveWrapperId = 0; + + foreach (EditorCurveBinding b in bindings) + { + // General configuration + var wrapper = new CurveWrapper + { + id = curveWrapperId++, + binding = b, + groupId = -1, + hidden = false, + readOnly = false, + getAxisUiScalarsCallback = () => new Vector2(1, 1) + }; + + // Specific configuration + ConfigureCurveWrapper(wrapper); + + wrappers.Add(wrapper); + } + + return wrappers; + } + + protected virtual void ConfigureCurveWrapper(CurveWrapper wrapper) + { + wrapper.color = CurveUtility.GetPropertyColor(wrapper.binding.propertyName); + wrapper.renderer = new NormalCurveRenderer(AnimationUtility.GetEditorCurve(animationClip, wrapper.binding)); + wrapper.renderer.SetCustomRange(0.0f, animationClip.length); + } + + protected virtual int CreateHashCode() + { + return m_TrackGUI.asset.GetHashCode(); + } + } + + class ClipAnimationCurveDataSource : CurveDataSource + { + static readonly string k_GroupingName = L10n.Tr("Animated Values"); + + readonly TimelineClipGUI m_ClipGUI; + + public ClipAnimationCurveDataSource(TimelineClipGUI clipGUI) : base(clipGUI.parent) + { + m_ClipGUI = clipGUI; + } + + public override AnimationClip animationClip + { + get { return m_ClipGUI.clip.animationClip; } + } + + public override float start + { + get { return (float)m_ClipGUI.clip.FromLocalTimeUnbound(0.0); } + } + + public override float timeScale + { + get { return (float)m_ClipGUI.clip.timeScale; } + } + + public override string groupingName + { + get { return k_GroupingName; } + } + + protected override int CreateHashCode() + { + return base.CreateHashCode().CombineHash(m_ClipGUI.clip.GetHashCode()); + } + } + + class ClipParametersCurveDataSource : CurveDataSource + { + static readonly string k_GroupingName = L10n.Tr("Clip Properties"); + + readonly TimelineClipGUI m_ClipGUI; + readonly CurvesProxy m_CurvesProxy; + + public ClipParametersCurveDataSource(TimelineClipGUI clipGUI) : base(clipGUI.parent) + { + m_ClipGUI = clipGUI; + m_CurvesProxy = new CurvesProxy(clipGUI.clip); + } + + public override AnimationClip animationClip + { + get { return m_CurvesProxy.curves; } + } + + public override float start + { + get { return (float)m_ClipGUI.clip.FromLocalTimeUnbound(0.0); } + } + + public override float timeScale + { + get { return (float)m_ClipGUI.clip.timeScale; } + } + + public override string groupingName + { + get { return k_GroupingName; } + } + + public override void UpdateCurves(List<CurveWrapper> updatedCurves) + { + m_CurvesProxy.UpdateCurves(updatedCurves); + } + + public override void RebuildCurves() + { + m_CurvesProxy.RebuildCurves(); + } + + protected override void ConfigureCurveWrapper(CurveWrapper wrapper) + { + m_CurvesProxy.ConfigureCurveWrapper(wrapper); + } + + protected override int CreateHashCode() + { + return base.CreateHashCode().CombineHash(m_ClipGUI.clip.GetHashCode()); + } + } + + class InfiniteClipCurveDataSource : CurveDataSource + { + static readonly string k_GroupingName = L10n.Tr("Animated Values"); + + readonly AnimationTrack m_AnimationTrack; + + public InfiniteClipCurveDataSource(IRowGUI trackGui) : base(trackGui) + { + m_AnimationTrack = trackGui.asset as AnimationTrack; + } + + public override AnimationClip animationClip + { + get { return m_AnimationTrack.infiniteClip; } + } + + public override float start + { + get { return 0.0f; } + } + + public override float timeScale + { + get { return 1.0f; } + } + + public override string groupingName + { + get { return k_GroupingName; } + } + } + + class TrackParametersCurveDataSource : CurveDataSource + { + static readonly string k_GroupingName = L10n.Tr("Track Properties"); + + readonly CurvesProxy m_CurvesProxy; + + public TrackParametersCurveDataSource(IRowGUI trackGui) : base(trackGui) + { + m_CurvesProxy = new CurvesProxy(trackGui.asset); + } + + public override AnimationClip animationClip + { + get { return m_CurvesProxy.curves; } + } + + public override float start + { + get { return 0.0f; } + } + + public override float timeScale + { + get { return 1.0f; } + } + + public override string groupingName + { + get { return k_GroupingName; } + } + + public override void UpdateCurves(List<CurveWrapper> updatedCurves) + { + m_CurvesProxy.UpdateCurves(updatedCurves); + } + + public override void RebuildCurves() + { + m_CurvesProxy.RebuildCurves(); + } + + protected override void ConfigureCurveWrapper(CurveWrapper wrapper) + { + m_CurvesProxy.ConfigureCurveWrapper(wrapper); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/CurveDataSource.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/CurveDataSource.cs.meta new file mode 100644 index 0000000..6416ecf --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/CurveDataSource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 87a1ae9719ec25d44a4dbec20ec0f892 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/CurvesProxy.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/CurvesProxy.cs new file mode 100644 index 0000000..ce17112 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/CurvesProxy.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; +using UnityEngine; +using UnityEngine.Timeline; +using UnityObject = UnityEngine.Object; + +namespace UnityEditor.Timeline +{ + class CurvesProxy : ICurvesOwner + { + public AnimationClip curves + { + get { return proxyCurves != null ? proxyCurves : m_OriginalOwner.curves; } + } + + public bool hasCurves + { + get { return m_IsAnimatable || m_OriginalOwner.hasCurves; } + } + + public double duration + { + get { return m_OriginalOwner.duration; } + } + + public string defaultCurvesName + { + get { return m_OriginalOwner.defaultCurvesName; } + } + + public UnityObject asset + { + get { return m_OriginalOwner.asset; } + } + + public UnityObject assetOwner + { + get { return m_OriginalOwner.assetOwner; } + } + + public TrackAsset targetTrack + { + get { return m_OriginalOwner.targetTrack; } + } + + readonly ICurvesOwner m_OriginalOwner; + readonly bool m_IsAnimatable; + readonly Dictionary<EditorCurveBinding, SerializedProperty> m_PropertiesMap = new Dictionary<EditorCurveBinding, SerializedProperty>(); + int m_ProxyIsRebuilding = 0; + + AnimationClip m_ProxyCurves; + AnimationClip proxyCurves + { + get + { + if (!m_IsAnimatable) return null; + + if (m_ProxyCurves == null) + RebuildProxyCurves(); + + return m_ProxyCurves; + } + } + + List<SerializedProperty> m_AllAnimatableParameters; + List<SerializedProperty> allAnimatableParameters + { + get + { + var so = AnimatedParameterUtility.GetSerializedPlayableAsset(m_OriginalOwner.asset); + if (so == null) + return null; + + so.UpdateIfRequiredOrScript(); + + if (m_AllAnimatableParameters == null) + m_AllAnimatableParameters = m_OriginalOwner.GetAllAnimatableParameters().ToList(); + + return m_AllAnimatableParameters; + } + } + + public CurvesProxy([NotNull] ICurvesOwner originalOwner) + { + m_OriginalOwner = originalOwner; + m_IsAnimatable = originalOwner.HasAnyAnimatableParameters(); + + RebuildProxyCurves(); + } + + public void CreateCurves(string curvesClipName) + { + m_OriginalOwner.CreateCurves(curvesClipName); + } + + public void ConfigureCurveWrapper(CurveWrapper wrapper) + { + var color = CurveUtility.GetPropertyColor(wrapper.binding.propertyName); + wrapper.color = color; + + float h, s, v; + Color.RGBToHSV(color, out h, out s, out v); + wrapper.wrapColorMultiplier = Color.HSVToRGB(h, s * 0.33f, v * 1.15f); + + var curve = AnimationUtility.GetEditorCurve(proxyCurves, wrapper.binding); + + wrapper.renderer = new NormalCurveRenderer(curve); + + // Use curve length instead of animation clip length + wrapper.renderer.SetCustomRange(0.0f, curve.keys.Last().time); + } + + public void RebuildCurves() + { + RebuildProxyCurves(); + } + + public void UpdateCurves(List<CurveWrapper> updatedCurves) + { + if (m_ProxyIsRebuilding > 0) + return; + + Undo.RegisterCompleteObjectUndo(m_OriginalOwner.asset, "Edit Clip Curve"); + + if (m_OriginalOwner.curves != null) + Undo.RegisterCompleteObjectUndo(m_OriginalOwner.curves, "Edit Clip Curve"); + + foreach (var curve in updatedCurves) + { + UpdateCurve(curve.binding, curve.curve); + } + + AnimatedParameterUtility.UpdateSerializedPlayableAsset(m_OriginalOwner.asset); + } + + void UpdateCurve(EditorCurveBinding binding, AnimationCurve curve) + { + ApplyConstraints(binding, curve); + + if (curve.length == 0) + { + HandleAllKeysDeleted(binding); + } + else if (curve.length == 1) + { + HandleConstantCurveValueChanged(binding, curve); + } + else + { + HandleCurveUpdated(binding, curve); + } + } + + void ApplyConstraints(EditorCurveBinding binding, AnimationCurve curve) + { + if (curve.length == 0) + return; + + var curveUpdated = false; + + var property = m_PropertiesMap[binding]; + if (property.propertyType == SerializedPropertyType.Boolean) + { + TimelineAnimationUtilities.ConstrainCurveToBooleanValues(curve); + curveUpdated = true; + } + else + { + var range = AnimatedParameterUtility.GetAttributeForProperty<RangeAttribute>(property); + if (range != null) + { + TimelineAnimationUtilities.ConstrainCurveToRange(curve, range.min, range.max); + curveUpdated = true; + } + } + + if (!curveUpdated) + return; + + using (new RebuildGuard(this)) + { + AnimationUtility.SetEditorCurve(m_ProxyCurves, binding, curve); + } + } + + void HandleCurveUpdated(EditorCurveBinding binding, AnimationCurve updatedCurve) + { + if (!m_OriginalOwner.hasCurves) + m_OriginalOwner.CreateCurves(null); + + AnimationUtility.SetEditorCurve(m_OriginalOwner.curves, binding, updatedCurve); + } + + void HandleConstantCurveValueChanged(EditorCurveBinding binding, AnimationCurve updatedCurve) + { + var prop = m_PropertiesMap[binding]; + if (prop == null) + return; + + Undo.RegisterCompleteObjectUndo(prop.serializedObject.targetObject, "Edit Clip Curve"); + prop.serializedObject.UpdateIfRequiredOrScript(); + CurveEditUtility.SetFromKeyValue(prop, updatedCurve.keys[0].value); + prop.serializedObject.ApplyModifiedProperties(); + } + + void HandleAllKeysDeleted(EditorCurveBinding binding) + { + if (m_OriginalOwner.hasCurves) + { + // Remove curve from original asset + AnimationUtility.SetEditorCurve(m_OriginalOwner.curves, binding, null); + m_OriginalOwner.SanitizeCurvesData(); + } + + // Ensure proxy still has constant value + RebuildProxyCurves(); + } + + void RebuildProxyCurves() + { + if (!m_IsAnimatable) + return; + + using (new RebuildGuard(this)) + { + if (m_ProxyCurves == null) + { + m_ProxyCurves = new AnimationClip + { + legacy = true, + name = "Constant Curves", + hideFlags = HideFlags.HideAndDontSave, + frameRate = m_OriginalOwner.targetTrack.timelineAsset == null + ? TimelineAsset.EditorSettings.kDefaultFps + : m_OriginalOwner.targetTrack.timelineAsset.editorSettings.fps + }; + } + else + { + m_ProxyCurves.ClearCurves(); + } + + m_OriginalOwner.SanitizeCurvesData(); + AnimatedParameterUtility.UpdateSerializedPlayableAsset(m_OriginalOwner.asset); + + foreach (var param in allAnimatableParameters) + CreateProxyCurve(param, m_ProxyCurves, m_OriginalOwner.asset, param.propertyPath); + + AnimationClipCurveCache.Instance.GetCurveInfo(m_ProxyCurves).dirty = true; + } + } + + void CreateProxyCurve(SerializedProperty prop, AnimationClip clip, UnityObject owner, string propertyName) + { + var binding = AnimatedParameterUtility.GetCurveBinding(owner, propertyName); + + var originalCurve = m_OriginalOwner.hasCurves + ? AnimationUtility.GetEditorCurve(m_OriginalOwner.curves, binding) + : null; + + if (originalCurve != null) + { + AnimationUtility.SetEditorCurve(clip, binding, originalCurve); + } + else + { + var curve = new AnimationCurve(); + + CurveEditUtility.AddKeyFrameToCurve( + curve, 0.0f, clip.frameRate, CurveEditUtility.GetKeyValue(prop), + prop.propertyType == SerializedPropertyType.Boolean); + + AnimationUtility.SetEditorCurve(clip, binding, curve); + } + + m_PropertiesMap[binding] = prop; + } + + struct RebuildGuard : IDisposable + { + CurvesProxy m_Owner; + AnimationUtility.OnCurveWasModified m_Callback; + + public RebuildGuard(CurvesProxy owner) + { + m_Callback = AnimationUtility.onCurveWasModified; + AnimationUtility.onCurveWasModified = null; + m_Owner = owner; + m_Owner.m_ProxyIsRebuilding++; + } + + public void Dispose() + { + AnimationUtility.onCurveWasModified = m_Callback; + m_Owner.m_ProxyIsRebuilding--; + m_Owner = null; + } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/CurvesProxy.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/CurvesProxy.cs.meta new file mode 100644 index 0000000..18e3029 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/CurvesProxy.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d72ccd2c66ea846fc842adf682b11526 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/TimelineAnimationUtilities.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/TimelineAnimationUtilities.cs new file mode 100644 index 0000000..60cf7cc --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/TimelineAnimationUtilities.cs @@ -0,0 +1,435 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEditor; +using UnityEngineInternal; +using UnityEngine.Timeline; +using UnityEngine.Playables; +using Object = UnityEngine.Object; + +namespace UnityEditor.Timeline +{ + class TimelineAnimationUtilities + { + public enum OffsetEditMode + { + None = -1, + Translation = 0, + Rotation = 1 + } + + public static bool ValidateOffsetAvailabitity(PlayableDirector director, Animator animator) + { + if (director == null || animator == null) + return false; + + return true; + } + + public static TimelineClip GetPreviousClip(TimelineClip clip) + { + TimelineClip previousClip = null; + foreach (var c in clip.parentTrack.clips) + { + if (c.start < clip.start && (previousClip == null || c.start >= previousClip.start)) + previousClip = c; + } + return previousClip; + } + + public static TimelineClip GetNextClip(TimelineClip clip) + { + return clip.parentTrack.clips.Where(c => c.start > clip.start).OrderBy(c => c.start).FirstOrDefault(); + } + + public struct RigidTransform + { + public Vector3 position; + public Quaternion rotation; + + public static RigidTransform Compose(Vector3 pos, Quaternion rot) + { + RigidTransform ret; + ret.position = pos; + ret.rotation = rot; + return ret; + } + + public static RigidTransform Mul(RigidTransform a, RigidTransform b) + { + RigidTransform ret; + ret.rotation = a.rotation * b.rotation; + ret.position = a.position + a.rotation * b.position; + return ret; + } + + public static RigidTransform Inverse(RigidTransform a) + { + RigidTransform ret; + ret.rotation = Quaternion.Inverse(a.rotation); + ret.position = ret.rotation * (-a.position); + return ret; + } + + public static RigidTransform identity + { + get { return Compose(Vector3.zero, Quaternion.identity); } + } + } + + + private static Matrix4x4 GetTrackMatrix(Transform transform, AnimationTrack track) + { + Matrix4x4 trackMatrix = Matrix4x4.TRS(track.position, track.rotation, Vector3.one); + + // in scene off mode, the track offsets are set to the preview position which is stored in the track + if (track.trackOffset == TrackOffset.ApplySceneOffsets) + { + trackMatrix = Matrix4x4.TRS(track.sceneOffsetPosition, Quaternion.Euler(track.sceneOffsetRotation), Vector3.one); + } + + // put the parent transform on to the track matrix + if (transform.parent != null) + { + trackMatrix = transform.parent.localToWorldMatrix * trackMatrix; + } + + return trackMatrix; + } + + // Given a world space position and rotation, updates the clip offsets to match that + public static RigidTransform UpdateClipOffsets(AnimationPlayableAsset asset, AnimationTrack track, Transform transform, Vector3 globalPosition, Quaternion globalRotation) + { + Matrix4x4 worldToLocal = transform.worldToLocalMatrix; + Matrix4x4 clipMatrix = Matrix4x4.TRS(asset.position, asset.rotation, Vector3.one); + Matrix4x4 trackMatrix = GetTrackMatrix(transform, track); + + + // Use the transform to find the proper goal matrix with scale taken into account + var oldPos = transform.position; + var oldRot = transform.rotation; + transform.position = globalPosition; + transform.rotation = globalRotation; + Matrix4x4 goal = transform.localToWorldMatrix; + transform.position = oldPos; + transform.rotation = oldRot; + + // compute the new clip matrix. + Matrix4x4 newClip = trackMatrix.inverse * goal * worldToLocal * trackMatrix * clipMatrix; + return RigidTransform.Compose(newClip.GetColumn(3), MathUtils.QuaternionFromMatrix(newClip)); + } + + public static RigidTransform GetTrackOffsets(AnimationTrack track, Transform transform) + { + Vector3 position = track.position; + Quaternion rotation = track.rotation; + if (transform != null && transform.parent != null) + { + position = transform.parent.TransformPoint(position); + rotation = transform.parent.rotation * rotation; + MathUtils.QuaternionNormalize(ref rotation); + } + + return RigidTransform.Compose(position, rotation); + } + + public static void UpdateTrackOffset(AnimationTrack track, Transform transform, RigidTransform offsets) + { + if (transform != null && transform.parent != null) + { + offsets.position = transform.parent.InverseTransformPoint(offsets.position); + offsets.rotation = Quaternion.Inverse(transform.parent.rotation) * offsets.rotation; + MathUtils.QuaternionNormalize(ref offsets.rotation); + } + + track.position = offsets.position; + track.eulerAngles = AnimationUtility.GetClosestEuler(offsets.rotation, track.eulerAngles, RotationOrder.OrderZXY); + track.UpdateClipOffsets(); + } + + static MatchTargetFields GetMatchFields(TimelineClip clip) + { + var track = clip.parentTrack as AnimationTrack; + if (track == null) + return MatchTargetFieldConstants.None; + + var asset = clip.asset as AnimationPlayableAsset; + var fields = track.matchTargetFields; + if (asset != null && !asset.useTrackMatchFields) + fields = asset.matchTargetFields; + return fields; + } + + static void WriteMatchFields(AnimationPlayableAsset asset, RigidTransform result, MatchTargetFields fields) + { + Vector3 position = asset.position; + + position.x = fields.HasAny(MatchTargetFields.PositionX) ? result.position.x : position.x; + position.y = fields.HasAny(MatchTargetFields.PositionY) ? result.position.y : position.y; + position.z = fields.HasAny(MatchTargetFields.PositionZ) ? result.position.z : position.z; + + asset.position = position; + + // check first to avoid unnecessary conversion errors + if (fields.HasAny(MatchTargetFieldConstants.Rotation)) + { + Vector3 eulers = asset.eulerAngles; + Vector3 resultEulers = result.rotation.eulerAngles; + + eulers.x = fields.HasAny(MatchTargetFields.RotationX) ? resultEulers.x : eulers.x; + eulers.y = fields.HasAny(MatchTargetFields.RotationY) ? resultEulers.y : eulers.y; + eulers.z = fields.HasAny(MatchTargetFields.RotationZ) ? resultEulers.z : eulers.z; + + asset.eulerAngles = AnimationUtility.GetClosestEuler(Quaternion.Euler(eulers), asset.eulerAngles, RotationOrder.OrderZXY); + } + } + + public static void MatchPrevious(TimelineClip currentClip, Transform matchPoint, PlayableDirector director) + { + const double timeEpsilon = 0.00001; + MatchTargetFields matchFields = GetMatchFields(currentClip); + if (matchFields == MatchTargetFieldConstants.None || matchPoint == null) + return; + + double cachedTime = director.time; + + // finds previous clip + TimelineClip previousClip = GetPreviousClip(currentClip); + if (previousClip == null || currentClip == previousClip) + return; + + // make sure the transform is properly updated before modifying the graph + director.Evaluate(); + + var parentTrack = currentClip.parentTrack as AnimationTrack; + + var blendIn = currentClip.blendInDuration; + currentClip.blendInDuration = 0; + var blendOut = previousClip.blendOutDuration; + previousClip.blendOutDuration = 0; + + //evaluate previous without current + parentTrack.RemoveClip(currentClip); + director.RebuildGraph(); + double previousEndTime = currentClip.start > previousClip.end ? previousClip.end : currentClip.start; + director.time = previousEndTime - timeEpsilon; + director.Evaluate(); // add port to evaluate only track + + var targetPosition = matchPoint.position; + var targetRotation = matchPoint.rotation; + + // evaluate current without previous + parentTrack.AddClip(currentClip); + parentTrack.RemoveClip(previousClip); + director.RebuildGraph(); + director.time = currentClip.start + timeEpsilon; + director.Evaluate(); + + ////////////////////////////////////////////////////////////////////// + //compute offsets + + var animationPlayable = currentClip.asset as AnimationPlayableAsset; + var match = UpdateClipOffsets(animationPlayable, parentTrack, matchPoint, targetPosition, targetRotation); + WriteMatchFields(animationPlayable, match, matchFields); + + ////////////////////////////////////////////////////////////////////// + + currentClip.blendInDuration = blendIn; + previousClip.blendOutDuration = blendOut; + + parentTrack.AddClip(previousClip); + director.RebuildGraph(); + director.time = cachedTime; + director.Evaluate(); + } + + public static void MatchNext(TimelineClip currentClip, Transform matchPoint, PlayableDirector director) + { + const double timeEpsilon = 0.00001; + MatchTargetFields matchFields = GetMatchFields(currentClip); + if (matchFields == MatchTargetFieldConstants.None || matchPoint == null) + return; + + double cachedTime = director.time; + + // finds next clip + TimelineClip nextClip = GetNextClip(currentClip); + if (nextClip == null || currentClip == nextClip) + return; + + // make sure the transform is properly updated before modifying the graph + director.Evaluate(); + + var parentTrack = currentClip.parentTrack as AnimationTrack; + + var blendOut = currentClip.blendOutDuration; + var blendIn = nextClip.blendInDuration; + currentClip.blendOutDuration = 0; + nextClip.blendInDuration = 0; + + //evaluate previous without current + parentTrack.RemoveClip(currentClip); + director.RebuildGraph(); + director.time = nextClip.start + timeEpsilon; + director.Evaluate(); // add port to evaluate only track + + var targetPosition = matchPoint.position; + var targetRotation = matchPoint.rotation; + + // evaluate current without next + parentTrack.AddClip(currentClip); + parentTrack.RemoveClip(nextClip); + director.RebuildGraph(); + director.time = Math.Min(nextClip.start, currentClip.end - timeEpsilon); + director.Evaluate(); + + ////////////////////////////////////////////////////////////////////// + //compute offsets + + var animationPlayable = currentClip.asset as AnimationPlayableAsset; + var match = UpdateClipOffsets(animationPlayable, parentTrack, matchPoint, targetPosition, targetRotation); + WriteMatchFields(animationPlayable, match, matchFields); + + ////////////////////////////////////////////////////////////////////// + + currentClip.blendOutDuration = blendOut; + nextClip.blendInDuration = blendIn; + + parentTrack.AddClip(nextClip); + director.RebuildGraph(); + director.time = cachedTime; + director.Evaluate(); + } + + public static TimelineWindowTimeControl CreateTimeController(WindowState state, TimelineClip clip) + { + var animationWindow = EditorWindow.GetWindow<AnimationWindow>(); + var timeController = ScriptableObject.CreateInstance<TimelineWindowTimeControl>(); + timeController.Init(animationWindow.state, clip); + return timeController; + } + + public static TimelineWindowTimeControl CreateTimeController(WindowState state, TimelineWindowTimeControl.ClipData clipData) + { + var animationWindow = EditorWindow.GetWindow<AnimationWindow>(); + var timeController = ScriptableObject.CreateInstance<TimelineWindowTimeControl>(); + timeController.Init(animationWindow.state, clipData); + return timeController; + } + + public static void EditAnimationClipWithTimeController(AnimationClip animationClip, TimelineWindowTimeControl timeController, Object sourceObject) + { + var animationWindow = EditorWindow.GetWindow<AnimationWindow>(); + animationWindow.EditSequencerClip(animationClip, sourceObject, timeController); + } + + public static void UnlinkAnimationWindowFromTracks(IEnumerable<TrackAsset> tracks) + { + var clips = new List<AnimationClip>(); + foreach (var track in tracks) + { + var animationTrack = track as AnimationTrack; + if (animationTrack != null && animationTrack.infiniteClip != null) + clips.Add(animationTrack.infiniteClip); + + GetAnimationClips(track.GetClips(), clips); + } + UnlinkAnimationWindowFromAnimationClips(clips); + } + + public static void UnlinkAnimationWindowFromClips(IEnumerable<TimelineClip> timelineClips) + { + var clips = new List<AnimationClip>(); + GetAnimationClips(timelineClips, clips); + UnlinkAnimationWindowFromAnimationClips(clips); + } + + public static void UnlinkAnimationWindowFromAnimationClips(ICollection<AnimationClip> clips) + { + if (clips.Count == 0) + return; + + UnityEngine.Object[] windows = Resources.FindObjectsOfTypeAll(typeof(AnimationWindow)); + foreach (var animWindow in windows.OfType<AnimationWindow>()) + { + if (animWindow != null && animWindow.state != null && animWindow.state.linkedWithSequencer && clips.Contains(animWindow.state.activeAnimationClip)) + animWindow.UnlinkSequencer(); + } + } + + public static void UnlinkAnimationWindow() + { + UnityEngine.Object[] windows = Resources.FindObjectsOfTypeAll(typeof(AnimationWindow)); + foreach (var animWindow in windows.OfType<AnimationWindow>()) + { + if (animWindow != null && animWindow.state != null && animWindow.state.linkedWithSequencer) + animWindow.UnlinkSequencer(); + } + } + + private static void GetAnimationClips(IEnumerable<TimelineClip> timelineClips, List<AnimationClip> clips) + { + foreach (var timelineClip in timelineClips) + { + if (timelineClip.curves != null) + clips.Add(timelineClip.curves); + AnimationPlayableAsset apa = timelineClip.asset as AnimationPlayableAsset; + if (apa != null && apa.clip != null) + clips.Add(apa.clip); + } + } + + public static int GetAnimationWindowCurrentFrame() + { + var animationWindow = EditorWindow.GetWindow<AnimationWindow>(); + if (animationWindow) + return animationWindow.state.currentFrame; + return -1; + } + + public static void SetAnimationWindowCurrentFrame(int frame) + { + var animationWindow = EditorWindow.GetWindow<AnimationWindow>(); + if (animationWindow) + animationWindow.state.currentFrame = frame; + } + + public static void ConstrainCurveToBooleanValues(AnimationCurve curve) + { + // Clamp the values first + var keys = curve.keys; + for (var i = 0; i < keys.Length; i++) + { + var key = keys[i]; + key.value = key.value < 0.5f ? 0.0f : 1.0f; + keys[i] = key; + } + curve.keys = keys; + + // Update the tangents once all the values are clamped + for (var i = 0; i < curve.length; i++) + { + AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Constant); + AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Constant); + } + } + + public static void ConstrainCurveToRange(AnimationCurve curve, float minValue, float maxValue) + { + var keys = curve.keys; + for (var i = 0; i < keys.Length; i++) + { + var key = keys[i]; + key.value = Mathf.Clamp(key.value, minValue, maxValue); + keys[i] = key; + } + curve.keys = keys; + } + + public static bool IsAnimationClip(TimelineClip clip) + { + return clip != null && (clip.asset as AnimationPlayableAsset) != null; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/TimelineAnimationUtilities.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/TimelineAnimationUtilities.cs.meta new file mode 100644 index 0000000..78ae589 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Animation/TimelineAnimationUtilities.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9685354eb873b8d4699078b307b0f260 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: |
