mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/PCK-Studio.git
synced 2026-07-07 12:38:25 +00:00
Move Common functionality to Core project & rendering and Model support as well
This commit is contained in:
115
PckStudio.Core/Deserializer/AnimationDeserializer.cs
Normal file
115
PckStudio.Core/Deserializer/AnimationDeserializer.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OMI.Formats.Pck;
|
||||
using PckStudio.Core;
|
||||
using PckStudio.Core.Extensions;
|
||||
using PckStudio.Interfaces;
|
||||
|
||||
namespace PckStudio.Core.Deserializer
|
||||
{
|
||||
public sealed class AnimationDeserializer : IPckAssetDeserializer<Animation>
|
||||
{
|
||||
public static readonly AnimationDeserializer DefaultDeserializer = new AnimationDeserializer();
|
||||
|
||||
public Animation Deserialize(PckAsset asset)
|
||||
{
|
||||
_ = asset ?? throw new ArgumentNullException(nameof(asset));
|
||||
if (asset.Size > 0)
|
||||
{
|
||||
Image texture = asset.GetTexture();
|
||||
IEnumerable<Image> frameTextures = texture.Split(ImageLayoutDirection.Vertical);
|
||||
string animString = asset.GetProperty("ANIM");
|
||||
bool animStringIsEmpty = string.IsNullOrEmpty(animString);
|
||||
Animation animation = new Animation(frameTextures, animStringIsEmpty);
|
||||
if (!animStringIsEmpty)
|
||||
DeserializeAnimationAnim(ref animation, animString);
|
||||
return animation;
|
||||
}
|
||||
return Animation.CreateEmpty();
|
||||
}
|
||||
|
||||
private static bool DeserializeAnimationAnim(ref Animation animation, string animString)
|
||||
{
|
||||
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);
|
||||
Animation result = new Animation(textures);
|
||||
if (jsonObject["animation"] is not JToken animation)
|
||||
return result;
|
||||
|
||||
int frameTime = Animation.MinimumFrameTime;
|
||||
|
||||
if (animation["frametime"] is JToken frametime_token && frametime_token.Type == JTokenType.Integer)
|
||||
frameTime = (int)frametime_token;
|
||||
|
||||
if (animation["interpolate"] is JToken interpolate_token && interpolate_token.Type == JTokenType.Boolean)
|
||||
result.Interpolate = (bool)interpolate_token;
|
||||
|
||||
if (animation["frames"] is JToken frames_token && frames_token.Type == JTokenType.Array)
|
||||
{
|
||||
foreach (JToken frame in frames_token.Children())
|
||||
{
|
||||
if (frame.Type == JTokenType.Object &&
|
||||
frame["index"] is JToken frame_index &&
|
||||
frame_index.Type == JTokenType.Integer &&
|
||||
frame["time"] is JToken frame_time &&
|
||||
frame_time.Type == JTokenType.Integer)
|
||||
{
|
||||
Debug.WriteLine("Index: {0}, Time: {1}", frame_index, frame_time);
|
||||
result.AddFrame((int)frame_index, (int)frame_time);
|
||||
}
|
||||
else if (frame.Type == JTokenType.Integer)
|
||||
{
|
||||
Debug.WriteLine("Index: {0}, Time: {1}", frame, frameTime);
|
||||
result.AddFrame((int)frame, frameTime);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
for (int i = 0; i < result.TextureCount; i++)
|
||||
{
|
||||
result.AddFrame(i, frameTime);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
PckStudio.Core/Deserializer/ImageDeserializer.cs
Normal file
31
PckStudio.Core/Deserializer/ImageDeserializer.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using OMI.Formats.Pck;
|
||||
using PckStudio.Interfaces;
|
||||
using PckStudio.Core.IO.TGA;
|
||||
|
||||
namespace PckStudio.Core.Deserializer
|
||||
{
|
||||
internal sealed class ImageDeserializer : IPckAssetDeserializer<Image>
|
||||
{
|
||||
public static readonly ImageDeserializer DefaultDeserializer = new ImageDeserializer();
|
||||
// TODO: replace empty image with image displaying something went wrong
|
||||
private static Image EmptyImage = new Bitmap(1, 1, PixelFormat.Format32bppArgb);
|
||||
|
||||
public Image Deserialize(PckAsset asset)
|
||||
{
|
||||
_ = asset ?? throw new ArgumentNullException(nameof(asset));
|
||||
if (asset.Size == 0)
|
||||
return EmptyImage;
|
||||
|
||||
using var stream = new MemoryStream(asset.Data);
|
||||
|
||||
Image img = Path.GetExtension(asset.Filename) == ".tga"
|
||||
? TGADeserializer.DeserializeFromStream(stream)
|
||||
: Image.FromStream(stream);
|
||||
return img.RawFormat != ImageFormat.Jpeg || img.RawFormat != ImageFormat.Png ? new Bitmap(img) : img;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user