UniversalViewer/Assets/Scripts/ModelViewerBase/UI/TimelineController.cs

323 lines
9.0 KiB
C#
Raw Permalink Normal View History

2024-04-21 22:38:26 +08:00
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using Object = UnityEngine.Object;
public class TimelineController : MonoBehaviour
{
[System.Serializable]
public class CopyBufferData
{
public ObjectContainer TrackedObject;
public FrameContent Content;
}
public static TimelineController Instance;
public TMPro.TMP_InputField FrameCountInput;
public TMPro.TMP_Text SelectedObjectLabel;
public TMPro.TMP_InputField
InputFrameRate,
InputFrameDelay;
public int FrameCount;
public int CurrentFrame;
public ScrollRect Timeline;
public ScrollRect ObjectsList;
public Slider TimelineSlider;
public CopyBufferData CopyBuffer = null;
public List<TimelineFrameContainer> Frames;
public bool Play;
public float FrameDelayMS = 33;
public float FrameRate = 30;
private void Awake()
{
Instance = this;
}
IEnumerator Start()
{
while(ModelViewerMain.GetInstance() == null)
{
yield return 0;
}
SetFrameRate("30");
FrameCount = (int)float.Parse(FrameCountInput.text, CultureInfo.InvariantCulture);
FillTimeline(FrameCount);
UpdateTimeline();
StartCoroutine(UpdateLoop());
}
IEnumerator UpdateLoop()
{
while (true)
{
if (Play)
{
ChangeCurrentFrame(1, false);
}
yield return new WaitForSeconds(FrameDelayMS/1000);
}
}
public void TogglePlay()
{
Play = !Play;
}
public void ChangeCurrentFrame(int frameChange)
{
TimelineController.ChangeCurrentFrame(frameChange, true);
}
public static void ChangeCurrentFrame(int frameChange, bool stopPlayback)
{
int frame = Instance.CurrentFrame + frameChange;
if (frame < 0)
frame = Instance.FrameCount - 1;
if (frame >= Instance.FrameCount)
frame = 0;
if (stopPlayback)
Instance.Play = false;
SetCurrentFrame(frame);
}
public static void SetCurrentFrame(int frameIndex)
{
var main = ModelViewerMain.GetInstance();
Instance.CurrentFrame = frameIndex;
Debug.Log("Setting frame to: " + frameIndex);
2024-04-21 22:38:26 +08:00
foreach (var container in main.CurrentScene.AllObjects)
{
container.GetClosestFrames(frameIndex, out var previousFrame, out var nextFrame);
var blendAmount = previousFrame == nextFrame? 0 : 1 - (float)(nextFrame.FrameNum - frameIndex) / (nextFrame.FrameNum - previousFrame.FrameNum);
Debug.Log($"Setting {container.name} to frame {previousFrame.FrameNum}({nextFrame.FrameNum})");
2024-04-21 22:38:26 +08:00
container.Lerp(previousFrame.ObjectData, nextFrame.ObjectData, blendAmount);
}
UpdateTimeline();
}
public static void SetCurrentFrame(ObjectContainer container)
{
int frameIndex = Instance.CurrentFrame;
container.GetClosestFrames(frameIndex, out var previousFrame, out var nextFrame);
var blendAmount = previousFrame == nextFrame ? 0 : 1 - (float)(nextFrame.FrameNum - frameIndex) / (nextFrame.FrameNum - previousFrame.FrameNum);
container.Lerp(previousFrame.ObjectData, nextFrame.ObjectData, blendAmount);
}
public void FillTimeline(int frames)
{
if (frames > Frames.Count)
{
int diff = frames - Frames.Count;
for (int i = 0; i < diff; i++)
{
var frame = Instantiate(SharedResources.Instance.TimelineFrame, Timeline.content).SetNum(Frames.Count);
frame.name = Frames.Count.ToString();
Frames.Add(frame);
}
}
foreach (var frame in Frames)
{
frame.gameObject.SetActive(frame.FrameIndex < frames);
}
}
public void OnSliderScroll()
{
var sliderPos = TimelineSlider.handleRect.position;
var newFrame = Frames.Where(f => f.gameObject.activeInHierarchy).OrderBy(frame => Vector3.Distance(sliderPos, frame.GetComponent<RectTransform>().position)).First();
if (CurrentFrame != newFrame.FrameIndex)
{
SetCurrentFrame(newFrame.FrameIndex);
}
}
public void SetFrameCount(string text)
{
FrameCount = int.Parse(text);
FillTimeline(FrameCount);
UpdateTimeline();
}
public void SetFrameDelay(string text)
{
FrameDelayMS = (int)float.Parse(text, CultureInfo.InvariantCulture);
if (FrameDelayMS == 0)
{
FrameDelayMS = 1;
}
FrameRate = 1 / (FrameDelayMS / 1000);
InputFrameRate.SetTextWithoutNotify(Mathf.Round(FrameRate).ToString());
InputFrameDelay.SetTextWithoutNotify(Mathf.Round(FrameDelayMS).ToString());
}
public void SetFrameRate(string text)
{
FrameRate = (int)float.Parse(text, CultureInfo.InvariantCulture);
if(FrameRate == 0)
{
FrameRate = 1;
}
FrameDelayMS = (1 / FrameRate) * 1000;
InputFrameRate.SetTextWithoutNotify(Mathf.Round(FrameRate).ToString());
InputFrameDelay.SetTextWithoutNotify(Mathf.Round(FrameDelayMS).ToString());
}
public static void SwapFrames(int frameNum1, int frameNum2)
{
if (frameNum1 < 0 || frameNum1 >= Instance.FrameCount) return;
if (frameNum2 < 0 || frameNum2 >= Instance.FrameCount) return;
var selectedObject = GetCurrentObject();
var frames = selectedObject.Frames;
var frame1 = selectedObject.TryGetFrame(frameNum1);
var frame2 = selectedObject.TryGetFrame(frameNum2);
if (frame1 != null)
{
frame1.FrameNum = frameNum2;
}
if (frame2 != null)
{
frame2.FrameNum = frameNum1;
}
selectedObject.Frames = selectedObject.Frames.OrderBy(f => f.FrameNum).ToList();
SetCurrentFrame(Instance.CurrentFrame);
}
public static void UpdateTimeline()
{
var container = GetCurrentObject();
Instance.SelectedObjectLabel.text = container.name;
var frames = Instance.Frames.ToList();
for (int i = 0; i < container.Frames.Count; i++)
{
var frameNum = container.Frames[i].FrameNum;
if (frameNum >= frames.Count) return;
var frame = frames[frameNum];
frame.UpdateContent(container, container.Frames[i]);
frames[frameNum] = null;
}
foreach(var frame in frames)
{
if (frame == null) continue;
frame.UpdateContent(container, null);
}
}
public static ObjectContainer GetCurrentObject()
{
ObjectContainer container = ModelViewerMain.GetInstance().SelectedObject;
if (container == null)
{
container = ModelViewerMain.GetInstance().MainCameraOrbit;
}
return container;
}
public void OnButtonSet()
{
GetCurrentObject().SetKeyframe(CurrentFrame);
}
public void OnButtonDelete()
{
Frames[CurrentFrame].DeleteFrame();
}
public void OnButtonCopy()
{
Frames[CurrentFrame].CopyFrame();
}
public void OnButtonPaste()
{
var data = CopyBuffer;
if (data == null) return;
if (GetCurrentObject() == data.TrackedObject)
{
if (Input.GetKey(KeyCode.LeftShift)) PasteStep0(data);
else PasteStep1(data, new PoseLoadOptions(true));
return;
}
UIPopupMessage.Create("You're pasting from a different object. Continue?",
() =>
{
if (Input.GetKey(KeyCode.LeftShift)) PasteStep0(data);
else PasteStep1(data, new PoseLoadOptions(true));
},
() => { }
);
}
private void PasteStep0(CopyBufferData data)
{
UIPopupPastePanel.Create(
(pasteOptions) => { PasteStep1(data, pasteOptions); Debug.Log(pasteOptions.Root); },
() => { });
}
private void PasteStep1(CopyBufferData data, PoseLoadOptions options)
{
int frameNum = CurrentFrame;
var trackedObject = data.TrackedObject;
if (trackedObject == null)
{
Error.Log(Color.red, "Object has been deleted?");
return;
}
if (!trackedObject.GetCurrentFrame(frameNum, out var currentFrame))
{
trackedObject.PastePose(data.Content.ObjectData, options);
currentFrame.SetObjectData(trackedObject.SerializeFrame());
SetCurrentFrame(trackedObject);
return;
}
UIPopupMessage.Create($"Replace existing data for {trackedObject.name}?",
() => {
trackedObject.PastePose(data.Content.ObjectData, options);
currentFrame.SetObjectData(trackedObject.SerializeFrame());
SetCurrentFrame(trackedObject);
},
() =>{}
);
}
}