Switch-Toolbox/Switch_Toolbox_Library/Forms/Animation/AnimationPanel.cs
2019-11-23 16:06:33 -05:00

523 lines
16 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using Toolbox.Library.Forms;
using Toolbox.Library.Animations;
namespace Toolbox.Library
{
//Thanks to forge! Based on
// https://github.com/jam1garner/Smash-Forge/blob/52844da94c7bed830d841e0d7e5d49c3f2c69471/Smash%20Forge/GUI/ModelViewport.cs
public partial class AnimationPanel : STUserControl
{
public PlayerState AnimationPlayerState = PlayerState.Stop;
public enum PlayerState
{
Playing,
Pause,
Stop,
}
public bool IsLooping
{
get { return loopChkBox.Checked; }
set { loopChkBox.Checked = value; }
}
public bool IsPlaying
{
get
{
return AnimationPlayerState == PlayerState.Playing;
}
}
private static AnimationPanel _instance;
public static AnimationPanel Instance { get { return _instance == null ? _instance = new AnimationPanel() : _instance; } }
//Animation Functions
public int AnimationSpeed = 60;
public float Frame = 0;
// Frame rate control
private Thread renderThread;
private bool renderThreadIsUpdating = false;
public bool isOpen = true;
private STAnimation stCurrentAnimation;
public STAnimation CurrentSTAnimation
{
get
{
return stCurrentAnimation;
}
set
{
if (value == null)
return;
int frameCount = 1;
if (value.FrameCount != 0)
frameCount = (int)value.FrameCount;
ResetModels();
stCurrentAnimation = value;
totalFrame.Maximum = frameCount;
totalFrame.Value = frameCount;
currentFrameUpDown.Maximum = frameCount;
animationTrackBar.FrameCount = frameCount;
currentFrameUpDown.Value = 0;
SetAnimationsToFrame(0);
UpdateViewport();
}
}
private Animation currentAnimation;
public Animation CurrentAnimation
{
get
{
return currentAnimation;
}
set
{
if (value == null)
return;
int frameCount = 1;
if (value.FrameCount != 0)
frameCount = value.FrameCount;
ResetModels();
currentAnimation = value;
totalFrame.Maximum = frameCount;
totalFrame.Value = frameCount;
currentFrameUpDown.Maximum = frameCount;
animationTrackBar.FrameCount = frameCount;
currentFrameUpDown.Value = 0;
SetAnimationsToFrame(0);
UpdateViewport();
}
}
public void ResetModels()
{
var viewport = LibraryGUI.GetActiveViewport();
if (viewport == null)
return;
if (viewport.scene == null)
return;
foreach (var drawable in viewport.scene.objects)
{
if (drawable is STSkeleton)
{
((STSkeleton)drawable).reset();
}
}
}
public AnimationPanel()
{
InitializeComponent();
BackColor = FormThemes.BaseTheme.FormBackColor;
ForeColor = FormThemes.BaseTheme.FormForeColor;
animationTrackBar.BackColor = FormThemes.BaseTheme.FormBackColor;
animationTrackBar.ForeColor = FormThemes.BaseTheme.FormForeColor;
animationTrackBar.FrameChanged += new EventHandler(animationTrackBar_ValueChanged);
/* animationTrackBar.ThumbInnerColor = FormThemes.BaseTheme.TimelineThumbColor;
animationTrackBar.ThumbOuterColor = FormThemes.BaseTheme.TimelineThumbColor;
this.animationTrackBar.BarInnerColor = FormThemes.BaseTheme.FormBackColor;
this.animationTrackBar.BarPenColorBottom = FormThemes.BaseTheme.FormBackColor;
this.animationTrackBar.BarPenColorTop = FormThemes.BaseTheme.FormBackColor;
this.animationTrackBar.ElapsedInnerColor = FormThemes.BaseTheme.FormBackColor;
this.animationTrackBar.ElapsedPenColorBottom = FormThemes.BaseTheme.FormBackColor;
this.animationTrackBar.ElapsedPenColorTop = FormThemes.BaseTheme.FormBackColor;
*/
panel1.BackColor = FormThemes.BaseTheme.FormBackColor;
animationPlayBtn.BackColor = FormThemes.BaseTheme.FormBackColor;
button2.BackColor = FormThemes.BaseTheme.FormBackColor;
animationPlayBtn.ForeColor = FormThemes.BaseTheme.FormForeColor;
button2.ForeColor = FormThemes.BaseTheme.FormForeColor;
totalFrame.ForeColor = FormThemes.BaseTheme.FormForeColor;
totalFrame.BackColor = FormThemes.BaseTheme.FormBackColor;
currentFrameUpDown.ForeColor = FormThemes.BaseTheme.FormForeColor;
currentFrameUpDown.BackColor = FormThemes.BaseTheme.FormBackColor;
this.LostFocus += new System.EventHandler(AnimationPanel_LostFocus);
}
private void Play()
{
AnimationPlayerState = PlayerState.Playing;
UpdateAnimationUI();
animationTrackBar.Play();
}
private void Pause()
{
AnimationPlayerState = PlayerState.Stop;
UpdateAnimationUI();
animationTrackBar.Stop();
}
private void Stop()
{
currentFrameUpDown.Value = 0;
AnimationPlayerState = PlayerState.Stop;
UpdateAnimationUI();
}
private void UpdateAnimationUI()
{
animationPlayBtn.BackgroundImage = IsPlaying ? Properties.Resources.stop
: Properties.Resources.arrowR;
}
private void UpdateAnimationFrame()
{
if (IsPlaying)
{
if (currentFrameUpDown.InvokeRequired)
{
currentFrameUpDown.BeginInvoke((Action)(() =>
{
AdvanceNextFrame();
}));
}
else
{
AdvanceNextFrame();
}
}
}
private void AdvanceNextFrame()
{
if (animationTrackBar.CurrentFrame == animationTrackBar.FrameCount - 1)
{
if (IsLooping)
currentFrameUpDown.Value = 0;
else
Stop();
}
else if (!animationTrackBar.Locked)
{
if (currentFrameUpDown.Value < totalFrame.Value)
currentFrameUpDown.Value++;
}
currentFrameUpDown.Refresh();
totalFrame.Refresh();
}
private void animationPlayBtn_Click(object sender, EventArgs e)
{
if (currentAnimation?.FrameCount <= 0 &&
stCurrentAnimation?.FrameCount <= 0)
return;
if (AnimationPlayerState == PlayerState.Playing)
Pause();
else
Play();
}
private void totalFrame_ValueChanged(object sender, EventArgs e)
{
if (currentAnimation == null && stCurrentAnimation == null) return;
if (totalFrame.Value < 1)
{
totalFrame.Value = 1;
}
else
{
if (stCurrentAnimation != null)
{
stCurrentAnimation.FrameCount = (int)totalFrame.Value;
animationTrackBar.CurrentFrame = 0;
animationTrackBar.FrameCount = stCurrentAnimation.FrameCount;
}
else
{
if (currentAnimation.Tag is Animation)
((Animation)currentAnimation.Tag).FrameCount = (int)totalFrame.Value;
currentAnimation.FrameCount = (int)totalFrame.Value;
animationTrackBar.CurrentFrame = 0;
animationTrackBar.FrameCount = currentAnimation.FrameCount;
}
}
}
private void UpdateViewport()
{
if (IsDisposed)
return;
Viewport viewport = LibraryGUI.GetActiveViewport();
if (viewport == null)
return;
if (viewport.GL_Control == null || viewport.GL_Control.IsDisposed || viewport.GL_Control.Disposing)
return;
if (viewport.GL_Control.InvokeRequired)
{
viewport.GL_Control.Invoke((MethodInvoker)delegate {
// Running on the UI thread
viewport.GL_Control.Invalidate();
});
}
else
{
viewport.GL_Control.Invalidate();
}
}
private void nextButton_Click(object sender, EventArgs e) {
if (animationTrackBar.CurrentFrame < animationTrackBar.FrameCount)
animationTrackBar.CurrentFrame++;
}
private void prevButton_Click(object sender, EventArgs e) {
if (animationTrackBar.CurrentFrame > 0)
animationTrackBar.CurrentFrame--;
}
private void animationTrackBar_Scroll(object sender, EventArgs e)
{
}
private void animationTrackBar_ValueChanged(object sender, EventArgs e) {
if (currentAnimation == null && stCurrentAnimation == null || totalFrame.Value <= 0)
return;
currentFrameUpDown.Value = (decimal)animationTrackBar.CurrentFrame;
}
private void OnFrameAdvanced()
{
UpdateViewport();
SetAnimationsToFrame(animationTrackBar.CurrentFrame);
if (!renderThreadIsUpdating || !IsPlaying)
UpdateViewport();
}
private void SetAnimationsToFrame(float frameNum)
{
if (currentAnimation == null && stCurrentAnimation == null)
return;
var viewport = LibraryGUI.GetActiveViewport();
if (viewport == null || viewport.scene == null)
return;
if (stCurrentAnimation != null)
{
Console.WriteLine("SetAnimationsToFrame");
if (frameNum > stCurrentAnimation.FrameCount)
return;
float animFrameNum = frameNum;
stCurrentAnimation.SetFrame(animFrameNum);
stCurrentAnimation.NextFrame();
//Add frames to the playing animation
stCurrentAnimation.Frame += frameNum;
//Reset it when it reaches the total frame count
if (stCurrentAnimation.Frame >= stCurrentAnimation.FrameCount && stCurrentAnimation.Loop)
{
stCurrentAnimation.Frame = 0;
}
}
else
{
var anim = currentAnimation.Tag;
float animFrameNum = frameNum;
if (anim is MaterialAnimation)
{
((MaterialAnimation)anim).SetFrame(animFrameNum);
((MaterialAnimation)anim).NextFrame(viewport);
}
else if (anim is VisibilityAnimation)
{
((VisibilityAnimation)anim).SetFrame(animFrameNum);
((VisibilityAnimation)anim).NextFrame(viewport);
}
else if (anim is CameraAnimation)
{
((CameraAnimation)anim).SetFrame(animFrameNum);
((CameraAnimation)anim).NextFrame(viewport);
}
else if (anim is LightAnimation)
{
((LightAnimation)anim).SetFrame(animFrameNum);
((LightAnimation)anim).NextFrame(viewport);
}
else if (anim is FogAnimation)
{
((FogAnimation)anim).SetFrame(animFrameNum);
((FogAnimation)anim).NextFrame(viewport);
}
else //Play a skeletal animation if it's not the other types
{
foreach (var drawable in viewport.scene.objects)
{
if (drawable is STSkeleton)
{
currentAnimation.SetFrame(animFrameNum);
currentAnimation.NextFrame((STSkeleton)drawable);
}
}
}
//Add frames to the playing animation
currentAnimation.Frame += frameNum;
//Reset it when it reaches the total frame count
if (currentAnimation.Frame >= currentAnimation.FrameCount)
{
currentAnimation.Frame = 0;
}
}
}
private void currentFrameUpDown_ValueChanged(object sender, EventArgs e)
{
if (currentFrameUpDown.Value > totalFrame.Value)
currentFrameUpDown.Value = totalFrame.Value;
//Check locked state current frame will change during playing
if (!animationTrackBar.Locked)
{
animationTrackBar.CurrentFrame = (int)currentFrameUpDown.Value;
}
OnFrameAdvanced();
}
public void AnimationPanel_FormClosed()
{
isOpen = false;
Dispose();
}
private void AnimationPanel_Load(object sender, EventArgs e)
{
Viewport viewport = LibraryGUI.GetActiveViewport();
if (viewport != null)
{
if (viewport.GL_Control != null)
viewport.GL_Control.VSync = Runtime.enableVSync;
}
renderThread = new Thread(new ThreadStart(RenderAndAnimationLoop));
renderThread.Start();
}
private void RenderAndAnimationLoop()
{
if (IsDisposed)
return;
// TODO: We don't really need two timers.
Stopwatch animationStopwatch = Stopwatch.StartNew();
// Wait for UI to load before triggering paint events.
// int waitTimeMs = 500;
// Thread.Sleep(waitTimeMs);
// UpdateViewport();
int frameUpdateInterval = 5;
int animationUpdateInterval = 16;
while (isOpen)
{
// Always refresh the viewport when animations are playing.
if (renderThreadIsUpdating || IsPlaying)
{
if (animationStopwatch.ElapsedMilliseconds > animationUpdateInterval)
{
UpdateAnimationFrame();
animationStopwatch.Restart();
}
}
else
{
// Avoid wasting the CPU if we don't need to render anything.
Thread.Sleep(1);
}
}
}
private void AnimationPanel_Enter(object sender, EventArgs e)
{
}
private void AnimationPanel_LostFocus(object sender, EventArgs e)
{
renderThreadIsUpdating = false;
}
private void AnimationPanel_Click(object sender, EventArgs e)
{
renderThreadIsUpdating = true;
}
private void AnimationPanel_Leave(object sender, EventArgs e)
{
renderThreadIsUpdating = false;
}
public void ClosePanel()
{
ResetModels();
renderThread.Abort();
renderThreadIsUpdating = false;
stCurrentAnimation = null;
currentAnimation = null;
isOpen = false;
Dispose();
Console.WriteLine("Disposeing ANIM PANEL!!");
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
}
private void colorSlider1_Scroll(object sender, ScrollEventArgs e)
{
}
}
}