Initial commit

This commit is contained in:
AbstractConcept 2022-09-13 00:36:34 -05:00
commit 3c7cc0c973
8391 changed files with 704313 additions and 0 deletions

View file

@ -0,0 +1,106 @@
using System;
using UnityEngine.Playables;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
interface ISequenceState : IDisposable
{
TimelineAsset asset { get; }
PlayableDirector director { get; }
TimelineClip hostClip { get; }
double start { get; }
double timeScale { get; }
double duration { get; }
bool isReadOnly { get; }
TimelineAssetViewModel viewModel { get; }
double time { get; set; }
int frame { get; set; }
float frameRate { get; set; }
Range GetEvaluableRange();
string TimeAsString(double timeValue, string format = "F2");
double ToGlobalTime(double t);
double ToLocalTime(double t);
void ResetIsReadOnly();
}
/**
* This class is used to hold default values for an implementation of ISequenceState.
* It could be removed in a phase 2, but it is currently used to limit the scope of
* this refactoring: it allows client code to access sequence info without having to
* worry about `currentSequence` being null.
* In the future this should be removed and we should pass around the correct data
* structure (i.e. SequenceState OR WindowState) based on the situation.
*/
class NullSequenceState : ISequenceState
{
public TimelineAsset asset { get { return null; } }
public PlayableDirector director { get { return null; } }
public TimelineClip hostClip { get { return null; } }
public double start { get { return 0.0; } }
public double timeScale { get { return 1.0; } }
public double duration { get { return 0.0; } }
public bool isReadOnly { get { return false; } }
TimelineAssetViewModel m_ViewModel;
public TimelineAssetViewModel viewModel
{
get
{
if (m_ViewModel == null)
m_ViewModel = TimelineWindowViewPrefs.CreateUnassociatedViewModel();
return m_ViewModel;
}
}
public double time
{
get { return 0.0; }
set { /* NO-OP*/ }
}
public int frame
{
get { return 0; }
set { /* NO-OP*/ }
}
public float frameRate
{
get { return TimelineAsset.EditorSettings.kDefaultFps; }
set { /* NO-OP*/ }
}
public Range GetEvaluableRange()
{
return new Range();
}
public string TimeAsString(double timeValue, string format = "F2")
{
return TimeUtility.TimeAsTimeCode(timeValue, frameRate, format);
}
public double ToGlobalTime(double t)
{
return t;
}
public double ToLocalTime(double t)
{
return t;
}
public void ResetIsReadOnly()
{
// NO-OP
}
public void Dispose()
{
// NO-OP
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 167329c8289a3a14a9e342df49fc4104
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,298 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
class SequenceHierarchy : ScriptableObject
{
readonly List<ISequenceState> m_Sequences = new List<ISequenceState>();
WindowState m_WindowState;
[SerializeField]
SequencePath m_SerializedPath;
public ISequenceState masterSequence
{
get { return m_Sequences.FirstOrDefault(); }
}
public ISequenceState editSequence
{
get { return m_Sequences.LastOrDefault(); }
}
public int count
{
get { return m_Sequences.Count; }
}
public IEnumerable<ISequenceState> allSequences
{
get { return m_Sequences; }
}
public static SequenceHierarchy CreateInstance()
{
var hierarchy = ScriptableObject.CreateInstance<SequenceHierarchy>();
hierarchy.hideFlags = HideFlags.HideAndDontSave;
return hierarchy;
}
public void Init(WindowState owner)
{
m_WindowState = owner;
}
// This is called when performing Undo operations.
// It needs to be called here since some operations are not
// allowed (EditorUtility.InstanceIDToObject, for example)
// during the ISerializationCallbackReceiver methods.
void OnValidate()
{
if (m_SerializedPath == null || m_WindowState == null || m_WindowState.GetWindow() == null)
return;
m_WindowState.SetCurrentSequencePath(m_SerializedPath, true);
}
public void Add(TimelineAsset asset, PlayableDirector director, TimelineClip hostClip)
{
if (hostClip == null)
AddToCurrentUndoGroup(this); // Merge with selection undo
else
TimelineUndo.PushUndo(this, "Edit Sub-Timeline");
Add_Internal(asset, director, hostClip);
UpdateSerializedPath();
}
public void Remove()
{
if (m_Sequences.Count == 0) return;
TimelineUndo.PushUndo(this, "Go to Sub-Timeline");
Remove_Internal();
UpdateSerializedPath();
}
public ISequenceState GetStateAtIndex(int index)
{
return m_Sequences[index];
}
public void RemoveUntilCount(int expectedCount)
{
if (expectedCount < 0 || m_Sequences.Count <= expectedCount) return;
TimelineUndo.PushUndo(this, "Go to Sub-Timeline");
RemoveUntilCount_Internal(expectedCount);
UpdateSerializedPath();
}
public void Clear()
{
if (m_Sequences.Count == 0) return;
AddToCurrentUndoGroup(this);
Clear_Internal();
UpdateSerializedPath();
}
public SequencePath ToSequencePath()
{
var path = new SequencePath();
if (m_Sequences.Count == 0)
return path;
var rootSequence = m_Sequences[0];
var root = 0;
if (rootSequence.director != null && rootSequence.director.gameObject != null)
root = rootSequence.director.gameObject.GetInstanceID();
else if (rootSequence.asset != null)
root = rootSequence.asset.GetInstanceID();
path.SetSelectionRoot(root);
var resolver = rootSequence.director;
if (m_Sequences.Count > 1)
{
for (int i = 1, n = m_Sequences.Count; i < n; ++i)
{
path.AddSubSequence(m_Sequences[i], resolver);
resolver = m_Sequences[i].director;
}
}
return path;
}
public bool NeedsUpdate(SequencePath path, bool forceRebuild)
{
return forceRebuild || !SequencePath.AreEqual(m_SerializedPath, path);
}
public void FromSequencePath(SequencePath path, bool forceRebuild)
{
if (!NeedsUpdate(path, forceRebuild))
return;
Clear_Internal();
var rootObject = EditorUtility.InstanceIDToObject(path.selectionRoot);
if (rootObject == null)
{
UpdateSerializedPath();
return;
}
var candidateAsset = rootObject as TimelineAsset;
if (candidateAsset != null)
{
Add_Internal(candidateAsset, null, null);
UpdateSerializedPath();
return;
}
var candidateGameObject = rootObject as GameObject;
if (candidateGameObject == null)
{
UpdateSerializedPath();
return;
}
var director = TimelineUtility.GetDirectorComponentForGameObject(candidateGameObject);
var asset = TimelineUtility.GetTimelineAssetForDirectorComponent(director);
Add_Internal(asset, director, null);
if (!path.subElements.Any())
{
UpdateSerializedPath();
return;
}
List<SequenceBuildingBlock> buildingBlocks;
if (ValidateSubElements(path.subElements, director, out buildingBlocks))
{
foreach (var buildingBlock in buildingBlocks)
Add_Internal(buildingBlock.asset, buildingBlock.director, buildingBlock.hostClip);
}
UpdateSerializedPath();
}
void Add_Internal(TimelineAsset asset, PlayableDirector director, TimelineClip hostClip)
{
if (hostClip == null)
Clear_Internal();
var parent = m_Sequences.Count > 0 ? editSequence : null;
m_Sequences.Add(new SequenceState(m_WindowState, asset, director, hostClip, (SequenceState)parent));
}
void Remove_Internal()
{
m_Sequences.Last().Dispose();
m_Sequences.RemoveAt(m_Sequences.Count - 1);
}
void RemoveUntilCount_Internal(int expectedCount)
{
while (m_Sequences.Count > expectedCount)
{
Remove_Internal();
}
}
void Clear_Internal()
{
RemoveUntilCount_Internal(0);
}
void UpdateSerializedPath()
{
m_SerializedPath = ToSequencePath();
}
static bool ValidateSubElements(List<SequencePathSubElement> subElements, PlayableDirector director, out List<SequenceBuildingBlock> buildingBlocks)
{
buildingBlocks = new List<SequenceBuildingBlock>(subElements.Count);
var currentDirector = director;
foreach (var element in subElements)
{
var timeline = currentDirector.playableAsset as TimelineAsset;
if (timeline == null)
return false;
if (timeline.trackObjects == null)
return false;
var track = timeline.GetOutputTracks().FirstOrDefault(t => t.GetInstanceID() == element.trackInstanceID);
if (track == null)
return false;
if (track.Hash() != element.trackHash)
return false;
if (track.clips == null)
return false;
if (track.clips.Length <= element.clipIndex)
return false;
var clip = track.clips[element.clipIndex];
if (clip == null)
return false;
if (clip.Hash() != element.clipHash)
return false;
var candidateDirectors = TimelineUtility.GetSubTimelines(clip, director);
if (element.subDirectorIndex < 0 || element.subDirectorIndex >= candidateDirectors.Count)
return false;
var candidateDirector = candidateDirectors[element.subDirectorIndex];
if (candidateDirector == null || !(candidateDirector.playableAsset is TimelineAsset))
return false;
currentDirector = candidateDirector;
buildingBlocks.Add(
new SequenceBuildingBlock
{
asset = currentDirector.playableAsset as TimelineAsset,
director = currentDirector,
hostClip = clip
});
}
return true;
}
struct SequenceBuildingBlock
{
public TimelineAsset asset;
public PlayableDirector director;
public TimelineClip hostClip;
}
static void AddToCurrentUndoGroup(Object target)
{
if (target == null) return;
var group = Undo.GetCurrentGroup();
var groupName = Undo.GetCurrentGroupName();
EditorUtility.SetDirty(target);
Undo.RegisterCompleteObjectUndo(target, groupName);
Undo.CollapseUndoOperations(group);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6901fab4d5157ac48b9f263730387c03
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
[Serializable]
class SequencePath
{
[SerializeField] int m_SelectionRoot;
public int selectionRoot
{
get { return m_SelectionRoot; }
}
[SerializeField] List<SequencePathSubElement> m_SubElements;
public List<SequencePathSubElement> subElements
{
get { return m_SubElements ?? (m_SubElements = new List<SequencePathSubElement>()); }
}
public void SetSelectionRoot(int instanceID)
{
m_SelectionRoot = instanceID;
subElements.Clear();
}
public void AddSubSequence(ISequenceState state, IExposedPropertyTable resolver)
{
subElements.Add(SequencePathSubElement.Create(state, resolver));
}
public void Clear()
{
m_SelectionRoot = 0;
subElements.Clear();
}
public static bool AreEqual(SequencePath lhs, SequencePath rhs)
{
if (ReferenceEquals(lhs, null) && ReferenceEquals(rhs, null)) return true;
if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null)) return false;
if (ReferenceEquals(lhs, rhs)) return true;
var result = lhs.selectionRoot == rhs.selectionRoot &&
lhs.subElements.Count == rhs.subElements.Count;
if (!result)
return false;
for (int i = 0, n = lhs.subElements.Count; i < n; ++i)
result = result && SequencePathSubElement.AreEqual(lhs.subElements[i], rhs.subElements[i]);
return result;
}
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendFormat("[{0}]", m_SelectionRoot.ToString());
if (m_SubElements != null && m_SubElements.Count > 0)
{
foreach (var element in m_SubElements)
{
sb.Append(" > ");
sb.Append(element.ToString());
}
}
return sb.ToString();
}
}
[Serializable]
class SequencePathSubElement
{
public int trackInstanceID;
public int trackHash;
public int clipIndex;
public int clipHash;
public int subDirectorIndex;
public static SequencePathSubElement Create(ISequenceState state, IExposedPropertyTable resolver)
{
var clip = state.hostClip;
Debug.Assert(clip != null);
var track = clip.parentTrack;
Debug.Assert(track != null);
var asset = track.timelineAsset;
Debug.Assert(asset != null);
var directors = TimelineUtility.GetSubTimelines(clip, resolver as PlayableDirector);
return new SequencePathSubElement
{
trackInstanceID = track.GetInstanceID(),
trackHash = track.Hash(),
clipIndex = Array.IndexOf(track.clips, clip),
clipHash = clip.Hash(),
subDirectorIndex = directors.IndexOf(state.director)
};
}
public static bool AreEqual(SequencePathSubElement lhs, SequencePathSubElement rhs)
{
if (ReferenceEquals(lhs, null) && ReferenceEquals(rhs, null)) return true;
if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null)) return false;
if (ReferenceEquals(lhs, rhs)) return true;
return lhs.trackInstanceID == rhs.trackInstanceID &&
lhs.trackHash == rhs.trackHash &&
lhs.clipIndex == rhs.clipIndex &&
lhs.clipHash == rhs.clipHash &&
lhs.subDirectorIndex == rhs.subDirectorIndex;
}
public override string ToString()
{
return string.Format(
"[track[{0}] ({1}) > clip[{2}] ({3})]",
trackInstanceID.ToString(), trackHash.ToString(),
clipIndex.ToString(), clipHash.ToString());
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d1207768d96c479488b6b81f3483e0c1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,212 @@
using System;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
class SequenceState : ISequenceState
{
readonly WindowState m_WindowState;
readonly SequenceState m_ParentSequence;
double m_Time;
Range? m_CachedEvaluableRange;
public TimelineAsset asset { get; }
public PlayableDirector director { get; }
public TimelineClip hostClip { get; }
public double start { get; }
public double timeScale { get; }
public double duration
{
get
{
if (asset == null)
return 0.0;
var assetDuration = asset.durationMode == TimelineAsset.DurationMode.FixedLength ? asset.fixedDuration : asset.duration;
return hostClip == null ? assetDuration : Math.Min(hostClip.duration, assetDuration);
}
}
bool? m_IsReadOnly;
public bool isReadOnly
{
get
{
if (!m_IsReadOnly.HasValue)
m_IsReadOnly = FileUtil.IsReadOnly(asset);
return m_IsReadOnly.Value;
}
}
public void ResetIsReadOnly()
{
m_IsReadOnly = null;
}
public TimelineAssetViewModel viewModel
{
get
{
return TimelineWindowViewPrefs.GetOrCreateViewModel(asset);
}
}
public double time
{
get
{
if (m_ParentSequence != null)
return hostClip.ToLocalTimeUnbound(m_ParentSequence.time);
return GetLocalTime();
}
set
{
var correctedValue = Math.Min(value, TimeUtility.k_MaxTimelineDurationInSeconds);
viewModel.windowTime = correctedValue;
if (m_ParentSequence != null)
m_ParentSequence.time = hostClip.FromLocalTimeUnbound(correctedValue);
else
SetLocalTime(correctedValue);
}
}
public int frame
{
get { return TimeUtility.ToFrames(time, frameRate); }
set { time = TimeUtility.FromFrames(Mathf.Max(0, value), frameRate); }
}
public float frameRate
{
get
{
if (asset != null)
return asset.editorSettings.fps;
return TimelineAsset.EditorSettings.kDefaultFps;
}
set
{
TimelineAsset.EditorSettings settings = asset.editorSettings;
if (Math.Abs(settings.fps - value) > TimeUtility.kFrameRateEpsilon)
{
settings.fps = Mathf.Max(value, (float)TimeUtility.kFrameRateEpsilon);
EditorUtility.SetDirty(asset);
}
}
}
public SequenceState(WindowState windowState, TimelineAsset asset, PlayableDirector director, TimelineClip hostClip, SequenceState parentSequence)
{
m_WindowState = windowState;
m_ParentSequence = parentSequence;
this.asset = asset;
this.director = director;
this.hostClip = hostClip;
start = hostClip == null ? 0.0 : hostClip.start;
timeScale = hostClip == null ? 1.0 : hostClip.timeScale * parentSequence.timeScale;
}
public Range GetEvaluableRange()
{
if (hostClip == null)
return new Range
{
start = 0.0,
end = duration
};
if (!m_CachedEvaluableRange.HasValue)
{
var globalRange = GetGlobalEvaluableRange();
m_CachedEvaluableRange = new Range
{
start = ToLocalTime(globalRange.start),
end = ToLocalTime(globalRange.end)
};
}
return m_CachedEvaluableRange.Value;
}
public string TimeAsString(double timeValue, string format = "F2")
{
if (viewModel.timeInFrames)
return TimeUtility.TimeAsFrames(timeValue, frameRate, format);
return TimeUtility.TimeAsTimeCode(timeValue, frameRate, format);
}
public double ToGlobalTime(double t)
{
if (hostClip == null)
return t;
return m_ParentSequence.ToGlobalTime(hostClip.FromLocalTimeUnbound(t));
}
public double ToLocalTime(double t)
{
if (hostClip == null)
return t;
return hostClip.ToLocalTimeUnbound(m_ParentSequence.ToLocalTime(t));
}
double GetLocalTime()
{
if (!m_WindowState.previewMode && !Application.isPlaying)
return viewModel.windowTime;
// the time needs to always be synchronized with the director
if (director != null)
m_Time = director.time;
return m_Time;
}
void SetLocalTime(double newTime)
{
// do this prior to the calback, because the callback pulls from the get
if (director != null)
director.time = newTime;
if (Math.Abs(m_Time - newTime) > TimeUtility.kTimeEpsilon)
{
m_Time = newTime;
m_WindowState.InvokeTimeChangeCallback();
}
}
Range GetGlobalEvaluableRange()
{
if (hostClip == null)
return new Range
{
start = 0.0,
end = duration
};
var currentRange = new Range
{
start = hostClip.ToLocalTimeUnbound(ToGlobalTime(hostClip.start)),
end = hostClip.ToLocalTimeUnbound(ToGlobalTime(hostClip.end))
};
return Range.Intersection(currentRange, m_ParentSequence.GetGlobalEvaluableRange());
}
public void Dispose()
{
TimelineWindowViewPrefs.SaveViewModel(asset);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 09f4db536a377bc40a9ac110af702bfa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: df8df80bb65e9ec4280229a9921c4f3c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: