diff --git a/PCK-Studio/Extensions/AnimationExtensions.cs b/PCK-Studio/Extensions/AnimationExtensions.cs index 4c7aeb3f..557e8e45 100644 --- a/PCK-Studio/Extensions/AnimationExtensions.cs +++ b/PCK-Studio/Extensions/AnimationExtensions.cs @@ -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) { diff --git a/PCK-Studio/Forms/Editor/AnimationEditor.cs b/PCK-Studio/Forms/Editor/AnimationEditor.cs index 6df69bf8..f96da2bd 100644 --- a/PCK-Studio/Forms/Editor/AnimationEditor.cs +++ b/PCK-Studio/Forms/Editor/AnimationEditor.cs @@ -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"; } } diff --git a/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs b/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs index ec5b8f2c..f52f8cb7 100644 --- a/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs +++ b/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs @@ -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(); } } diff --git a/PCK-Studio/ToolboxItems/AnimationPictureBox.cs b/PCK-Studio/ToolboxItems/AnimationPictureBox.cs index 666650f6..580cd49f 100644 --- a/PCK-Studio/ToolboxItems/AnimationPictureBox.cs +++ b/PCK-Studio/ToolboxItems/AnimationPictureBox.cs @@ -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); - } + } } }