AnimationPictureBox - Update animation system as a whole

This commit is contained in:
miku-666
2024-04-29 20:46:58 +02:00
parent 792399ca50
commit 8f475070e3
4 changed files with 60 additions and 122 deletions

View File

@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using AnimatedGif;
using Newtonsoft.Json.Linq;
using PckStudio.Internal;
@@ -11,6 +13,17 @@ namespace PckStudio.Extensions
{
internal static class AnimationExtensions
{
internal static Image CreateAnimationImage(this Animation animation)
{
var ms = new System.IO.MemoryStream();
var generateor = new AnimatedGifCreator(ms, Animation.GameTickInMilliseconds, 0);
foreach (var frame in animation.GetInterpolatedFrames())
{
generateor.AddFrame(frame.Texture, frame.Ticks * Animation.GameTickInMilliseconds, GifQuality.Bit8);
}
ms.Position = 0;
return Image.FromStream(ms);
}
internal static JObject ConvertToJavaAnimation(this Animation animation)
{

View File

@@ -43,6 +43,7 @@ namespace PckStudio.Forms.Editor
private Animation _animation;
private bool _isSpecialTile;
private AnimationEditor()
{
InitializeComponent();
@@ -56,6 +57,7 @@ namespace PckStudio.Forms.Editor
_animation = animation;
tileLabel.Text = displayName;
_isSpecialTile = isSpecialTile;
animationPictureBox.Image = animation.CreateAnimationImage();
}
internal AnimationEditor(Animation animation, string displayName, Color blendColor)
@@ -63,7 +65,7 @@ namespace PckStudio.Forms.Editor
{
animationPictureBox.UseBlendColor = true;
animationPictureBox.BlendColor = blendColor;
}
}
private void ValidateToolStrip()
{
@@ -90,12 +92,11 @@ namespace PckStudio.Forms.Editor
InterpolationCheckbox.Checked = _animation.Interpolate;
TextureIcons.Images.Clear();
TextureIcons.Images.AddRange(_animation.GetTextures().ToArray());
UpdateTreeView();
if (_animation.FrameCount > 0)
{
animationPictureBox.SelectFrame(_animation, 0);
animationPictureBox.Image.SelectActiveFrame(FrameDimension.Page, 0);
}
}
@@ -111,13 +112,15 @@ namespace PckStudio.Forms.Editor
})
.ToArray()
);
}
}
private void frameTreeView_AfterSelect(object sender, TreeViewEventArgs e)
{
if (animationPictureBox.IsPlaying)
AnimationStartStopBtn.Text = "Play Animation";
animationPictureBox.SelectFrame(_animation, frameTreeView.SelectedNode.Index);
{
StopAnimation();
}
animationPictureBox.Image = _animation.GetFrame(frameTreeView.SelectedNode.Index).Texture;
}
private void StopAnimation()
@@ -133,9 +136,11 @@ namespace PckStudio.Forms.Editor
StopAnimation();
return;
}
if (_animation.FrameCount > 1)
{
animationPictureBox.Start(_animation);
animationPictureBox.Image = _animation.CreateAnimationImage();
animationPictureBox.Start();
AnimationStartStopBtn.Text = "Stop Animation";
}
}

View File

@@ -255,7 +255,8 @@ namespace PckStudio.Forms.Editor
animationFile.Size > 0)
{
var animation = animationFile.GetDeserializedData(AnimationDeserializer.DefaultDeserializer);
selectTilePictureBox.Start(animation);
selectTilePictureBox.Image = animation.CreateAnimationImage();
selectTilePictureBox.Start();
}
}

View File

@@ -16,142 +16,61 @@
* 3. This notice may not be removed or altered from any source distribution.
**/
using System;
using System.Threading;
using System.Diagnostics;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.Drawing.Drawing2D;
using System.Runtime.CompilerServices;
using PckStudio.Extensions;
using PckStudio.Internal;
using System.Drawing;
using AnimatedGif;
using System.Drawing.Imaging;
namespace PckStudio.ToolboxItems
{
internal class AnimationPictureBox : BlendPictureBox
{
public bool IsPlaying
{
get
{
lock(l_playing)
{
return _isPlaying;
}
}
private set
{
lock (l_playing)
{
_isPlaying = value;
}
}
}
public bool IsPlaying => _isPlaying;
private bool _isPlaying;
private bool _isPlaying = false;
private int currentAnimationFrameIndex = 0;
private Animation.Frame currentFrame;
private Animation _animation;
private CancellationTokenSource cts = new CancellationTokenSource();
private object l_dispose = new object();
private object l_playing = new object();
public void Start(Animation animation)
{
_animation = animation;
cts = new CancellationTokenSource();
IsPlaying = true;
Task.Run(DoAnimate, cts.Token);
}
public void Stop([CallerMemberName] string callerName = default!)
{
Debug.WriteLine($"{nameof(AnimationPictureBox.Stop)} called from {callerName}!");
IsPlaying = false;
cts.Cancel();
cts.Token.WaitHandle.WaitOne(500);
}
public void SelectFrame(Animation animation, int index)
{
if (IsPlaying)
Stop();
_animation = animation;
currentAnimationFrameIndex = index;
currentFrame = SetAnimationFrame(index);
}
private void DoAnimate()
{
_ = _animation ?? throw new ArgumentNullException(nameof(_animation));
Animation.Frame nextFrame;
while (!cts.IsCancellationRequested && IsPlaying)
{
if (currentAnimationFrameIndex >= _animation.FrameCount)
{
currentAnimationFrameIndex = 0;
}
if (currentAnimationFrameIndex + 1 >= _animation.FrameCount)
{
nextFrame = _animation.GetFrame(0);
}
else
{
nextFrame = _animation.GetFrame(currentAnimationFrameIndex + 1);
}
currentFrame = _animation.GetFrame(currentAnimationFrameIndex++);
if (_animation.Interpolate)
{
InterpolateFrame(currentFrame, nextFrame);
continue;
}
SetAnimationFrame(currentFrame);
if (cts.Token.WaitHandle.WaitOne(Animation.GameTickInMilliseconds * currentFrame.Ticks))
{
IsPlaying = false;
break;
}
}
}
private void InterpolateFrame(Animation.Frame currentFrame, Animation.Frame nextFrame)
private void PictureBox_Internal_Animate(PictureBox pictureBox, bool animate)
{
for (int tick = 0; tick < currentFrame.Ticks && !cts.IsCancellationRequested; tick++)
var animateMethod = typeof(PictureBox).GetMethod("Animate",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance,
null, new Type[] { typeof(bool) }, null);
animateMethod.Invoke(pictureBox, new object[] { animate });
}
public new Image Image
{
get => base.Image;
set
{
double delta = 1.0f - tick / (double)currentFrame.Ticks;
SetTexture(currentFrame.Texture.Interpolate(nextFrame.Texture, delta));
if (cts.Token.WaitHandle.WaitOne(Animation.GameTickInMilliseconds))
break;
base.Image = value;
PictureBox_Internal_Animate(this, false);
if (value is null)
return;
value.SelectActiveFrame(new FrameDimension(value.FrameDimensionsList[0]), 0);
}
}
private Animation.Frame SetAnimationFrame(int frameIndex)
public void Start()
{
var frame = _animation.GetFrame(frameIndex);
SetAnimationFrame(frame);
return frame;
}
private void SetTexture(Image texture)
{
if (!IsHandleCreated || Disposing)
return;
Invoke(() => Image = texture);
}
private void SetAnimationFrame(Animation.Frame frame)
{
SetTexture(frame.Texture);
_isPlaying = true;
PictureBox_Internal_Animate(this, _isPlaying);
}
protected override void Dispose(bool disposing)
{
public void Stop()
{
_isPlaying = false;
PictureBox_Internal_Animate(this, _isPlaying);
}
protected override void Dispose(bool disposing)
{
Stop();
cts.Token.WaitHandle.WaitOne(500);
base.Dispose(disposing);
}
}
}
}