204 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Linq;
 | |
| using UnityEngine;
 | |
| using UnityEngine.Timeline;
 | |
| 
 | |
| namespace UnityEditor.Timeline.Utilities
 | |
| {
 | |
|     class KeyTraverser
 | |
|     {
 | |
|         float[] m_KeyCache;
 | |
|         int m_DirtyStamp = -1;
 | |
|         int m_LastHash = -1;
 | |
|         readonly TimelineAsset m_Asset;
 | |
|         readonly float m_Epsilon;
 | |
|         int m_LastIndex = -1;
 | |
| 
 | |
|         public int lastIndex
 | |
|         {
 | |
|             get { return m_LastIndex; }
 | |
|         }
 | |
| 
 | |
|         public static IEnumerable<float> GetClipKeyTimes(TimelineClip clip)
 | |
|         {
 | |
|             if (clip == null || clip.animationClip == null || clip.animationClip.empty)
 | |
|                 return new float[0];
 | |
| 
 | |
|             return AnimationClipCurveCache.Instance.GetCurveInfo(clip.animationClip).keyTimes.
 | |
|                 Select(k => (float)clip.FromLocalTimeUnbound(k)).    // convert to sequence time
 | |
|                 Where(k => k >= clip.start && k <= clip.end);    // remove non visible keys
 | |
|         }
 | |
| 
 | |
|         public static IEnumerable<float> GetTrackKeyTimes(AnimationTrack track)
 | |
|         {
 | |
|             if (track != null)
 | |
|             {
 | |
|                 if (track.inClipMode)
 | |
|                     return track.clips.Where(c => c.recordable).
 | |
|                         SelectMany(x => GetClipKeyTimes(x));
 | |
|                 if (track.infiniteClip != null && !track.infiniteClip.empty)
 | |
|                     return AnimationClipCurveCache.Instance.GetCurveInfo(track.infiniteClip).keyTimes;
 | |
|             }
 | |
|             return new float[0];
 | |
|         }
 | |
| 
 | |
|         static int CalcAnimClipHash(TrackAsset asset)
 | |
|         {
 | |
|             int hash = 0;
 | |
|             if (asset != null)
 | |
|             {
 | |
|                 AnimationTrack animTrack = asset as AnimationTrack;
 | |
|                 if (animTrack != null)
 | |
|                 {
 | |
|                     for (var i = 0; i != animTrack.clips.Length; ++i)
 | |
|                     {
 | |
|                         hash ^= (animTrack.clips[i]).Hash();
 | |
|                     }
 | |
|                 }
 | |
|                 foreach (var subTrack in asset.GetChildTracks())
 | |
|                 {
 | |
|                     if (subTrack != null)
 | |
|                         hash ^= CalcAnimClipHash(subTrack);
 | |
|                 }
 | |
|             }
 | |
|             return hash;
 | |
|         }
 | |
| 
 | |
|         internal static int CalcAnimClipHash(TimelineAsset asset)
 | |
|         {
 | |
|             int hash = 0;
 | |
|             foreach (var t in asset.GetRootTracks())
 | |
|             {
 | |
|                 if (t != null)
 | |
|                     hash ^= CalcAnimClipHash(t);
 | |
|             }
 | |
|             return hash;
 | |
|         }
 | |
| 
 | |
|         void RebuildKeyCache()
 | |
|         {
 | |
|             m_KeyCache = m_Asset.flattenedTracks.Where(x => (x as AnimationTrack) != null)
 | |
|                 .Cast<AnimationTrack>()
 | |
|                 .SelectMany(t => GetTrackKeyTimes(t)).
 | |
|                 OrderBy(x => x).ToArray();
 | |
| 
 | |
|             if (m_KeyCache.Length > 0)
 | |
|             {
 | |
|                 float[] unique = new float[m_KeyCache.Length];
 | |
|                 unique[0] = m_KeyCache[0];
 | |
|                 int index = 0;
 | |
|                 for (int i = 1; i < m_KeyCache.Length; i++)
 | |
|                 {
 | |
|                     if (m_KeyCache[i] - unique[index] > m_Epsilon)
 | |
|                     {
 | |
|                         index++;
 | |
|                         unique[index] = m_KeyCache[i];
 | |
|                     }
 | |
|                 }
 | |
|                 m_KeyCache = unique;
 | |
|                 Array.Resize(ref m_KeyCache, index + 1);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public KeyTraverser(TimelineAsset timeline, float epsilon)
 | |
|         {
 | |
|             m_Asset = timeline;
 | |
|             m_Epsilon = epsilon;
 | |
|         }
 | |
| 
 | |
|         void CheckCache(int dirtyStamp)
 | |
|         {
 | |
|             int hash = CalcAnimClipHash(m_Asset);
 | |
|             if (dirtyStamp != m_DirtyStamp || hash != m_LastHash)
 | |
|             {
 | |
|                 RebuildKeyCache();
 | |
|                 m_DirtyStamp = dirtyStamp;
 | |
|                 m_LastHash = hash;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public float GetNextKey(float key, int dirtyStamp)
 | |
|         {
 | |
|             CheckCache(dirtyStamp);
 | |
|             if (m_KeyCache.Length > 0)
 | |
|             {
 | |
|                 if (key < m_KeyCache.Last() - m_Epsilon)
 | |
|                 {
 | |
|                     if (key > m_KeyCache[0] - m_Epsilon)
 | |
|                     {
 | |
|                         float t = key + m_Epsilon;
 | |
|                         // binary search
 | |
|                         int max = m_KeyCache.Length - 1;
 | |
|                         int min = 0;
 | |
|                         while (max - min > 1)
 | |
|                         {
 | |
|                             int imid = (min + max) / 2;
 | |
|                             if (t > m_KeyCache[imid])
 | |
|                                 min = imid;
 | |
|                             else
 | |
|                                 max = imid;
 | |
|                         }
 | |
|                         m_LastIndex = max;
 | |
|                         return m_KeyCache[max];
 | |
|                     }
 | |
| 
 | |
|                     m_LastIndex = 0;
 | |
|                     return m_KeyCache[0];
 | |
|                 }
 | |
|                 if (key < m_KeyCache.Last() + m_Epsilon)
 | |
|                 {
 | |
|                     m_LastIndex = m_KeyCache.Length - 1;
 | |
|                     return Mathf.Max(key, m_KeyCache.Last());
 | |
|                 }
 | |
|             }
 | |
|             m_LastIndex = -1;
 | |
|             return key;
 | |
|         }
 | |
| 
 | |
|         public float GetPrevKey(float key, int dirtyStamp)
 | |
|         {
 | |
|             CheckCache(dirtyStamp);
 | |
|             if (m_KeyCache.Length > 0)
 | |
|             {
 | |
|                 if (key > m_KeyCache[0] + m_Epsilon)
 | |
|                 {
 | |
|                     if (key < m_KeyCache.Last() + m_Epsilon)
 | |
|                     {
 | |
|                         float t = key - m_Epsilon;
 | |
| 
 | |
|                         // binary search
 | |
|                         int max = m_KeyCache.Length - 1;
 | |
|                         int min = 0;
 | |
|                         while (max - min > 1)
 | |
|                         {
 | |
|                             int imid = (min + max) / 2;
 | |
|                             if (t < m_KeyCache[imid])
 | |
|                                 max = imid;
 | |
|                             else
 | |
|                                 min = imid;
 | |
|                         }
 | |
|                         m_LastIndex = min;
 | |
|                         return m_KeyCache[min];
 | |
|                     }
 | |
|                     m_LastIndex = m_KeyCache.Length - 1;
 | |
|                     return m_KeyCache.Last();
 | |
|                 }
 | |
|                 if (key >= m_KeyCache[0] - m_Epsilon)
 | |
|                 {
 | |
|                     m_LastIndex = 0;
 | |
|                     return Mathf.Min(key, m_KeyCache[0]);
 | |
|                 }
 | |
|             }
 | |
|             m_LastIndex = -1;
 | |
|             return key;
 | |
|         }
 | |
| 
 | |
|         public int GetKeyCount(int dirtyStamp)
 | |
|         {
 | |
|             CheckCache(dirtyStamp);
 | |
|             return m_KeyCache.Length;
 | |
|         }
 | |
|     }
 | |
| }
 |