AnimationExtensions - Move common serialization functions to animation serializer

This commit is contained in:
miku-666
2024-07-20 17:47:53 +02:00
parent bb6209105c
commit f9826d8fc6
4 changed files with 88 additions and 82 deletions

View File

@@ -29,81 +29,5 @@ namespace PckStudio.Extensions
ms.Position = 0;
return Image.FromStream(ms);
}
internal static JObject ConvertToJavaAnimation(this Animation animation)
{
JObject janimation = new JObject();
JObject mcmeta = new JObject();
mcmeta["comment"] = $"Animation converted with {Application.ProductName}";
mcmeta["animation"] = janimation;
JArray jframes = new JArray();
foreach (Animation.Frame frame in animation.GetFrames())
{
JObject jframe = new JObject();
jframe["index"] = animation.GetTextureIndex(frame.Texture);
jframe["time"] = frame.Ticks;
jframes.Add(jframe);
}
janimation["interpolation"] = animation.Interpolate;
janimation["frames"] = jframes;
return mcmeta;
}
internal static bool ApplyAnim(this Animation animation, string animString)
{
if (string.IsNullOrEmpty(animString))
{
Trace.TraceError($"[{nameof(AnimationExtensions)}:{nameof(ApplyAnim)}] Failed to parse anim. anim was null or empty.");
return false;
}
animString = animString.Trim();
animation.Interpolate = animString.StartsWith("#");
animString = animation.Interpolate ? animString.Substring(1) : animString;
string[] animData = animString.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (animData.Length <= 0)
{
Trace.TraceError($"[{nameof(AnimationExtensions)}:{nameof(ApplyAnim)}] Failed to parse anim. animData was empty.");
return false;
}
int lastFrameTime = Animation.MinimumFrameTime;
foreach (string frameInfo in animData)
{
string[] frameData = frameInfo.Split('*');
int currentFrameIndex = 0;
int.TryParse(frameData[0], out currentFrameIndex);
// Some textures like the Halloween 2015's Lava texture don't have a
// frame time parameter for certain frames.
// This will detect that and place the last frame time in its place.
// This is accurate to console edition behavior.
// - MattNL
int currentFrameTime = frameData.Length < 2 || string.IsNullOrEmpty(frameData[1]) ? lastFrameTime : int.Parse(frameData[1]);
animation.AddFrame(currentFrameIndex, currentFrameTime);
lastFrameTime = currentFrameTime;
}
return true;
}
internal static string BuildAnim(this Animation animation)
{
StringBuilder stringBuilder = new StringBuilder(animation.Interpolate ? "#" : string.Empty);
foreach (Animation.Frame frame in animation.GetFrames())
stringBuilder.Append($"{animation.GetTextureIndex(frame.Texture)}*{frame.Ticks},");
return stringBuilder.ToString(0, stringBuilder.Length - 1);
}
internal static Image BuildTexture(this Animation animation)
{
IReadOnlyCollection<Image> textures = animation.GetTextures();
Size size = textures.First().Size;
if (size.Width != size.Height)
throw new Exception("Invalid size");
return textures.Combine(ImageLayoutDirection.Vertical);
}
}
}

View File

@@ -33,6 +33,7 @@ using PckStudio.Extensions;
using PckStudio.Properties;
using PckStudio.Internal;
using PckStudio.Internal.Deserializer;
using PckStudio.Internal.Serializer;
namespace PckStudio.Forms.Editor
{
@@ -353,11 +354,11 @@ namespace PckStudio.Forms.Editor
fileDialog.Filter = "Animation Scripts (*.mcmeta)|*.png.mcmeta";
if (fileDialog.ShowDialog(this) == DialogResult.OK)
{
JObject mcmeta = _animation.ConvertToJavaAnimation();
JObject mcmeta = AnimationSerializer.SerializeJavaAnimation(_animation);
string jsondata = JsonConvert.SerializeObject(mcmeta, Formatting.Indented);
string filename = fileDialog.FileName;
File.WriteAllText(filename, jsondata);
Image finalTexture = _animation.BuildTexture();
Image finalTexture = AnimationSerializer.SerializeTexture(_animation);
// removes ".mcmeta" from filename
string texturePath = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename));
finalTexture.Save(texturePath);
@@ -421,7 +422,7 @@ namespace PckStudio.Forms.Editor
return;
}
var oldResolution = _animation.BuildTexture().Width;
var oldResolution = _animation.GetFrame(0).Texture.Width;
FrameDimension dimension = new FrameDimension(gif.FrameDimensionsList[0]);
int frameCount = gif.GetFrameCount(dimension);

View File

@@ -24,12 +24,50 @@ namespace PckStudio.Internal.Deserializer
Image texture = asset.GetTexture();
IEnumerable<Image> frameTextures = texture.Split(ImageLayoutDirection.Vertical);
Animation animation = new Animation(frameTextures);
animation.ApplyAnim(asset.GetProperty("ANIM"));
DeserializeAnimationAnim(ref animation, asset.GetProperty("ANIM"));
return animation;
}
return Animation.CreateEmpty();
}
private static bool DeserializeAnimationAnim(ref Animation animation, string animString)
{
if (string.IsNullOrEmpty(animString))
{
Trace.TraceError($"[{nameof(AnimationExtensions)}:{nameof(DeserializeAnimationAnim)}] Failed to parse anim. anim was null or empty.");
return false;
}
animString = animString.Trim();
animation.Interpolate = animString.StartsWith("#");
animString = animation.Interpolate ? animString.Substring(1) : animString;
string[] animData = animString.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (animData.Length <= 0)
{
Trace.TraceError($"[{nameof(AnimationExtensions)}:{nameof(DeserializeAnimationAnim)}] Failed to parse anim. animData was empty.");
return false;
}
int lastFrameTime = Animation.MinimumFrameTime;
foreach (string frameInfo in animData)
{
string[] frameData = frameInfo.Split('*');
int currentFrameIndex = 0;
int.TryParse(frameData[0], out currentFrameIndex);
// Some textures like the Halloween 2015's Lava texture don't have a
// frame time parameter for certain frames.
// This will detect that and place the last frame time in its place.
// This is accurate to console edition behavior.
// - MattNL
int currentFrameTime = frameData.Length < 2 || string.IsNullOrEmpty(frameData[1]) ? lastFrameTime : int.Parse(frameData[1]);
animation.AddFrame(currentFrameIndex, currentFrameTime);
lastFrameTime = currentFrameTime;
}
return true;
}
public Animation DeserializeJavaAnimation(JObject jsonObject, Image texture)
{
IEnumerable<Image> textures = texture.Split(ImageLayoutDirection.Vertical);

View File

@@ -15,10 +15,16 @@
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
using System.Collections.Generic;
using System;
using System.Drawing;
using System.Text;
using OMI.Formats.Pck;
using PckStudio.Extensions;
using PckStudio.Interfaces;
using System.Linq;
using Newtonsoft.Json.Linq;
using System.Windows.Forms;
namespace PckStudio.Internal.Serializer
{
@@ -28,10 +34,47 @@ namespace PckStudio.Internal.Serializer
public void Serialize(Animation animation, ref PckAsset asset)
{
string anim = animation.BuildAnim();
string anim = SerializeAnim(animation);
asset.SetProperty("ANIM", anim);
Image texture = animation.BuildTexture();
Image texture = SerializeTexture(animation);
asset.SetTexture(texture);
}
private static string SerializeAnim(Animation animation)
{
StringBuilder stringBuilder = new StringBuilder(animation.Interpolate ? "#" : string.Empty);
foreach (Animation.Frame frame in animation.GetFrames())
stringBuilder.Append($"{animation.GetTextureIndex(frame.Texture)}*{frame.Ticks},");
return stringBuilder.ToString(0, stringBuilder.Length - 1);
}
internal static Image SerializeTexture(Animation animation)
{
IReadOnlyCollection<Image> textures = animation.GetTextures();
Size size = textures.First().Size;
if (size.Width != size.Height)
throw new Exception("Invalid size");
return textures.Combine(ImageLayoutDirection.Vertical);
}
internal static JObject SerializeJavaAnimation(Animation animation)
{
JObject janimation = new JObject();
JObject mcmeta = new JObject();
mcmeta["comment"] = $"Animation converted with {Application.ProductName}";
mcmeta["animation"] = janimation;
JArray jframes = new JArray();
foreach (Animation.Frame frame in animation.GetFrames())
{
JObject jframe = new JObject();
jframe["index"] = animation.GetTextureIndex(frame.Texture);
jframe["time"] = frame.Ticks;
jframes.Add(jframe);
}
janimation["interpolation"] = animation.Interpolate;
janimation["frames"] = jframes;
return mcmeta;
}
}
}