Created
January 21, 2022 16:46
-
-
Save alankent/738a1b7fb7f1fafa85c9b2c21fed1ea3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEditor.Timeline; | |
using UnityEngine.Sequences.Timeline; | |
using UnityEngine.Timeline; | |
namespace UnityEditor.Sequences.Timeline | |
{ | |
[CustomTimelineEditor(typeof(ProgressClip))] | |
public class ProgressClipEditor : ClipEditor | |
{ | |
/// <inheritdoc cref="ClipEditor.GetClipOptions"/> | |
public override ClipDrawOptions GetClipOptions(TimelineClip clip) | |
{ | |
var options = base.GetClipOptions(clip); | |
// Brighten clip color when playhead over clip. | |
var director = TimelineEditor.inspectedDirector; | |
if (director != null && director.time >= clip.start && director.time <= clip.end) | |
{ | |
options.highlightColor = options.highlightColor * 1.5f; | |
} | |
return options; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEditor.Timeline; | |
using UnityEngine; | |
using UnityEngine.Timeline; | |
namespace UnityEditor.Sequences.Timeline | |
{ | |
[CustomTimelineEditor(typeof(ProgressTrackAsset))] | |
public class ProgressTrackEditor : TrackEditor | |
{ | |
public override TrackDrawOptions GetTrackOptions(TrackAsset track, Object binding) | |
{ | |
var options = base.GetTrackOptions(track, binding); | |
//options.icon = (Texture2D)AssetDatabase.LoadAssetAtPath("Assets/_SHARED/Scripts/Progress Track/Editor/ProgressTrackIcon.png", typeof(Texture2D)); | |
return options; | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using System.IO; | |
using UnityEditor.Recorder.Timeline; | |
using UnityEngine; | |
using UnityEngine.Playables; | |
using UnityEngine.Timeline; | |
using UnityEngine.UI; | |
// GREAT VIDEO! https://www.youtube.com/watch?v=UEuM-Fckx5w | |
public class ProgressBehaviour : PlayableBehaviour | |
{ | |
public float Alpha; | |
public Vector2 BarScale = Vector2.one; | |
public Vector2 BarPosition; | |
public bool ShowVideoFilename = false; | |
public string VideoFilename; | |
public PlayableDirector PlayableDirector; | |
private Canvas m_Canvas; | |
private Transform m_leftBar; | |
private Transform m_rightBar; | |
private Text m_filenameText; | |
public override void ProcessFrame(Playable playable, FrameData info, object playerData) | |
{ | |
// Time in seconds since start of clip and the duration of the clip. | |
// Because we want to reach 100% on the last frame inside the clip, we subtract one frame duration (plus a bit more for rounding errors) | |
// Note that this does not work when scrubbing the timeline in Editor mode as deltaTime is zero then, but when recording its fine. | |
float time = (float)playable.GetTime(); | |
float clipDuration = ((float)playable.GetDuration()) - (1.5f * info.deltaTime); | |
float progress = time / clipDuration; | |
if (progress < 0f) progress = 0f; | |
if (progress > 1f) progress = 1f; | |
ScriptPlayable<ProgressMixerBehaviour> outputPlayable = | |
(ScriptPlayable<ProgressMixerBehaviour>)playable.GetOutput(0); | |
var outputPlayableBehaviour = outputPlayable.GetBehaviour(); | |
m_Canvas = outputPlayableBehaviour.canvas; | |
// Fade in/out the alpha. Time in seconds since start of clip and the duration of the clip. | |
if (m_Canvas == null) return; | |
if (m_Canvas.transform.childCount == 0) | |
{ | |
// if the board isn't loaded, load it | |
var leftGo = new GameObject("Left Bar"); | |
leftGo.hideFlags = HideFlags.HideAndDontSave; | |
leftGo.transform.parent = m_Canvas.transform; | |
var leftImage = leftGo.AddComponent<Image>(); | |
leftImage.color = new Color(1f, 1f, 1f, Alpha); | |
m_leftBar = leftGo.transform; | |
var rightGo = new GameObject("Right Bar"); | |
rightGo.hideFlags = HideFlags.HideAndDontSave; | |
rightGo.transform.parent = m_Canvas.transform; | |
var rightImage = rightGo.AddComponent<Image>(); | |
rightImage.color = new Color(1f, 1f, 1f, Alpha / 2f); | |
m_rightBar = rightGo.transform; | |
var filenameGo = new GameObject("Filename"); | |
filenameGo.hideFlags = HideFlags.HideAndDontSave; | |
filenameGo.transform.parent = m_Canvas.transform; | |
m_filenameText = filenameGo.AddComponent<Text>(); | |
// Set Text component properties. | |
m_filenameText.color = new Color(1f, 1f, 1f, 0.75f); | |
m_filenameText.font = Resources.GetBuiltinResource<Font>("Arial.ttf"); | |
m_filenameText.fontSize = 32; | |
m_filenameText.lineSpacing = 1; | |
m_filenameText.alignment = TextAnchor.MiddleCenter; | |
m_filenameText.horizontalOverflow = HorizontalWrapMode.Overflow; | |
m_filenameText.verticalOverflow = VerticalWrapMode.Overflow; | |
//m_filenameText.transform.localPosition = new Vector3(-Screen.width / 2f, -Screen.height / 2f, 0f); | |
//m_filenameText.transform.localPosition = new Vector3(Screen.width * -0.4f, Screen.height -0.4f, 0f); | |
m_filenameText.transform.localPosition = new Vector3(0f, 0f, 0f); | |
m_filenameText.transform.localScale = Vector2.one; | |
m_filenameText.transform.rotation = Quaternion.Euler(Vector3.zero); | |
} | |
else | |
{ | |
for (int i = 0; i < m_Canvas.transform.childCount; i++) | |
{ | |
var child = m_Canvas.transform.GetChild(i); | |
//child.transform.localPosition = BarPosition; | |
//child.localScale = BarScale; | |
} | |
} | |
var barX = (progress - 0.5f) * Screen.width; | |
var leftX = -Screen.width / 2f; | |
var rightX = Screen.width / 2f; | |
var barY = -Screen.height / 2f; | |
m_leftBar.localPosition = new Vector3((leftX + barX) / 2f, barY, 0f) * BarScale; | |
m_rightBar.localPosition = new Vector3((barX + rightX) / 2f, barY, 0f) * BarScale; | |
m_leftBar.localScale = new Vector3((barX - leftX) * 0.01f, 0.2f, 1f) * BarScale; | |
m_rightBar.localScale = new Vector3((rightX - barX) * 0.01f, 0.2f, 1f) * BarScale; | |
if (ShowVideoFilename) | |
m_filenameText.text = VideoFilename; // TODO: Could try to update based on current frame number to make it dynamic. | |
else | |
m_filenameText.text = null; | |
//Debug.Log("Prog=" + (progress - 0.5f)+ " lx=" + leftX + " rx=" + rightX + " barX=" + barX); | |
} | |
public override void OnBehaviourPause(Playable playable, FrameData info) | |
{ | |
if (m_Canvas == null) return; | |
while (m_Canvas.transform.childCount > 0) | |
{ | |
var child = m_Canvas.transform.GetChild(0); | |
child.SetParent(null); | |
#if UNITY_EDITOR | |
Object.DestroyImmediate(child.gameObject); | |
#else | |
Object.Destroy(child.gameObject); | |
#endif | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using System.IO; | |
using UnityEditor.Recorder.Timeline; | |
using UnityEngine; | |
using UnityEngine.Playables; | |
using UnityEngine.Timeline; | |
// Contains clip data which is passed to the behavior at run time. | |
public class ProgressClip : PlayableAsset, ITimelineClipAsset | |
{ | |
[Range(0f, 1f)] public float Alpha = 0.5f; | |
public Vector2 BarScale = new Vector2(0.875f * 0.95f, 0.875f * 0.95f); | |
public bool ShowVideoFilename = false; | |
public string VideoFilename; | |
// We dont support blending or anything fancy. | |
public ClipCaps clipCaps => ClipCaps.None; | |
private PlayableDirector m_playableDirector; | |
public override Playable CreatePlayable(PlayableGraph graph, GameObject owner) | |
{ | |
// 'owner' you can call GetComponent<PlayableDirector>(); on | |
var playable = ScriptPlayable<ProgressBehaviour>.Create(graph); | |
if (playable.GetBehaviour() != null) | |
SetAttributes(playable.GetBehaviour()); | |
// Look for a recorder track that starts at the same time we do and steal its filename. | |
m_playableDirector = owner.GetComponent<PlayableDirector>(); | |
return playable; | |
} | |
void SetAttributes(ProgressBehaviour progressBehavior) | |
{ | |
FindVideoFilename(); | |
progressBehavior.Alpha = Alpha; | |
progressBehavior.BarScale = BarScale; | |
progressBehavior.ShowVideoFilename = ShowVideoFilename; | |
progressBehavior.VideoFilename = VideoFilename; | |
} | |
private void FindVideoFilename() | |
{ | |
VideoFilename = null; | |
if (m_playableDirector == null) return; | |
var timelineAsset = m_playableDirector.playableAsset as TimelineAsset; | |
foreach (var track in timelineAsset.GetOutputTracks()) | |
{ | |
var recorderTrack = track as RecorderTrack; | |
if (recorderTrack != null) | |
{ | |
foreach (var clip in recorderTrack.GetClips()) | |
{ | |
//TODO: if (clip.start == myStart)? This finds the first recorder clip, but it might be a Timeline has multiple recorder clips... | |
var asset = clip.asset as RecorderClip; | |
if (asset) | |
{ | |
VideoFilename = Path.GetFileName(asset.settings.OutputFile); | |
} | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEngine.Playables; | |
public class ProgressMixerBehaviour : PlayableBehaviour | |
{ | |
Canvas m_Canvas; | |
public Canvas canvas => m_Canvas; | |
/// <inheritdoc cref="PlayableBehaviour.OnPlayableCreate"/> | |
public override void OnPlayableCreate(Playable playable) | |
{ | |
var canvasGo = new GameObject("Video Progress Bar"); | |
canvasGo.hideFlags = HideFlags.HideAndDontSave; | |
m_Canvas = canvasGo.AddComponent<Canvas>(); | |
m_Canvas.renderMode = RenderMode.ScreenSpaceOverlay; | |
} | |
/// <inheritdoc cref="PlayableBehaviour.OnPlayableDestroy"/> | |
public override void OnPlayableDestroy(Playable playable) | |
{ | |
#if UNITY_EDITOR | |
Object.DestroyImmediate(m_Canvas.gameObject); | |
#else | |
Object.Destroy(m_Canvas.gameObject); | |
#endif | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using UnityEngine; | |
using UnityEngine.Playables; | |
using UnityEngine.Timeline; | |
// Progress bar track - holds progress bar clips. | |
[Serializable] | |
[DisplayName("Progress Bar Track")] | |
[TrackColor(111 / 255f, 43 / 255f, 111 / 255f)] // To ask UX | |
[TrackClipType(typeof(ProgressClip))] | |
public class ProgressTrackAsset : TrackAsset | |
{ | |
public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount) | |
{ | |
var mixer = ScriptPlayable<ProgressMixerBehaviour>.Create(graph, inputCount); | |
//mixer.GetBehaviour().canvas.sortingOrder = 1; | |
return mixer; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment