From a7efbd1c3467e4fdb03e67f3e255f3293d0cfafb Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:55:05 +0200 Subject: [PATCH] CustomSkinEditor - Add Bedrock model import --- PCK-Studio/External/Format/BedrockModel.cs | 126 ++++++++++++++++++++ PCK-Studio/Forms/Editor/CustomSkinEditor.cs | 76 +++++++++--- PCK-Studio/PckStudio.csproj | 1 + 3 files changed, 188 insertions(+), 15 deletions(-) create mode 100644 PCK-Studio/External/Format/BedrockModel.cs diff --git a/PCK-Studio/External/Format/BedrockModel.cs b/PCK-Studio/External/Format/BedrockModel.cs new file mode 100644 index 00000000..f7dd7c8c --- /dev/null +++ b/PCK-Studio/External/Format/BedrockModel.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace PckStudio.External.Format +{ + internal class BedrockModel + { + [JsonProperty("format_version")] + public string FormatVersion { get; set; } + + [JsonProperty("minecraft:geometry")] + public List Models; + } + + internal class Geometry + { + [JsonProperty("description")] + public GeometryDescription Description { get; set; } + + [JsonProperty("bones")] + public List Bones; + } + + internal class GeometryDescription + { + [JsonProperty("identifier")] + public string Identifier { get; set; } + + [JsonProperty("texture_width")] + private int TextureWidth; + + [JsonProperty("texture_height")] + private int TextureHeight; + + [JsonIgnore] + public Size TextureSize + { + get => new Size(TextureWidth, TextureHeight); + set + { + TextureWidth = value.Width; + TextureHeight = value.Height; + } + } + } + + internal class Bone + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("binding")] + public string Binding { get; set; } + + [JsonIgnore] + public Vector3 Pivot + { + get => pivot.Length < 3 ? Vector3.Zero : new Vector3(pivot[0], pivot[1], pivot[2]); + set + { + pivot[0] = value.X; + pivot[1] = value.Y; + pivot[2] = value.Z; + } + } + + [JsonProperty("cubes")] + public List Cubes; + + [JsonProperty("pivot")] + private float[] pivot { get; set; } + } + + internal class Cube + { + [JsonProperty("origin")] + private float[] origin { get; set; } = new float[3]; + [JsonIgnore] + public Vector3 Origin + { + get => origin.Length < 3 ? Vector3.Zero : new Vector3(origin[0], origin[1], origin[2]); + set + { + origin[0] = value.X; + origin[1] = value.Y; + origin[2] = value.Z; + } + } + + [JsonProperty("size")] + private float[] size { get; set; } = new float[3]; + [JsonIgnore] + public Vector3 Size + { + get => size.Length < 3 ? Vector3.Zero : new Vector3(size[0], size[1], size[2]); + set + { + size[0] = value.X; + size[1] = value.Y; + size[2] = value.Z; + } + } + + [JsonProperty("uv")] + private float[] uv { get; set; } = new float[2]; + [JsonIgnore] + public Vector2 Uv + { + get => uv.Length < 2 ? Vector2.Zero : new Vector2(uv[0], uv[1]); + set + { + uv[0] = value.X; + uv[1] = value.Y; + } + } + + [JsonProperty("inflate")] + public float Inflate { get; set; } + } +} diff --git a/PCK-Studio/Forms/Editor/CustomSkinEditor.cs b/PCK-Studio/Forms/Editor/CustomSkinEditor.cs index 57d65b44..dee59843 100644 --- a/PCK-Studio/Forms/Editor/CustomSkinEditor.cs +++ b/PCK-Studio/Forms/Editor/CustomSkinEditor.cs @@ -18,6 +18,7 @@ using Newtonsoft.Json; using System.Numerics; using PckStudio.Rendering; using System.Diagnostics; +using Newtonsoft.Json.Linq; namespace PckStudio.Forms.Editor { @@ -53,7 +54,8 @@ namespace PckStudio.Forms.Editor private readonly FileDialogFilter[] fileFilters = [ new ("Pck skin model(*.psm)", "*.psm"), - new ("Block bench model(*.bbmodel)", "*.bbmodel") + new ("Block bench model(*.bbmodel)", "*.bbmodel"), + new ("Bedrock Model(*.geo.json)", "*.geo.json"), ]; private string skinModelFileFilters => string.Join("|", fileFilters); @@ -224,6 +226,36 @@ namespace PckStudio.Forms.Editor _skin.AdditionalBoxes.AddRange(csmbFile.Parts); _skin.PartOffsets.AddRange(csmbFile.Offsets); LoadModelData(_skin); + break; + case ".json": + _skin.AdditionalBoxes.Clear(); + _skin.PartOffsets.Clear(); + + _skin.ANIM.SetFlag(SkinAnimFlag.RESOLUTION_64x64, true); + _skin.ANIM.SetFlag(SkinAnimFlag.SLIM_MODEL, false); + _skin.ANIM.SetFlag(SkinAnimFlag.HEAD_DISABLED, true); + _skin.ANIM.SetFlag(SkinAnimFlag.HEAD_OVERLAY_DISABLED, true); + _skin.ANIM.SetFlag(SkinAnimFlag.BODY_DISABLED, true); + _skin.ANIM.SetFlag(SkinAnimFlag.BODY_OVERLAY_DISABLED, true); + _skin.ANIM.SetFlag(SkinAnimFlag.RIGHT_ARM_DISABLED, true); + _skin.ANIM.SetFlag(SkinAnimFlag.RIGHT_ARM_OVERLAY_DISABLED, true); + _skin.ANIM.SetFlag(SkinAnimFlag.LEFT_ARM_DISABLED, true); + _skin.ANIM.SetFlag(SkinAnimFlag.LEFT_ARM_OVERLAY_DISABLED, true); + _skin.ANIM.SetFlag(SkinAnimFlag.RIGHT_LEG_DISABLED, true); + _skin.ANIM.SetFlag(SkinAnimFlag.RIGHT_LEG_OVERLAY_DISABLED, true); + _skin.ANIM.SetFlag(SkinAnimFlag.LEFT_LEG_DISABLED, true); + _skin.ANIM.SetFlag(SkinAnimFlag.LEFT_LEG_OVERLAY_DISABLED, true); + + BedrockModel bedrockModel = JsonConvert.DeserializeObject(File.ReadAllText(openFileDialog.FileName)); + ItemSelectionPopUp itemSelectionPopUp = new ItemSelectionPopUp(bedrockModel.Models.Select(m => m.Description.Identifier).ToArray()); + if (itemSelectionPopUp.ShowDialog() == DialogResult.OK && bedrockModel.Models.IndexInRange(itemSelectionPopUp.SelectedIndex)) + { + Geometry selectedGeometry = bedrockModel.Models[itemSelectionPopUp.SelectedIndex]; + LoadGeometry(selectedGeometry); + LoadModelData(_skin); + } + itemSelectionPopUp.Dispose(); + break; case ".bbmodel": BlockBenchModel blockBenchModel = JsonConvert.DeserializeObject(File.ReadAllText(openFileDialog.FileName)); @@ -262,9 +294,9 @@ namespace PckStudio.Forms.Editor if (token.Type == JTokenType.Object) { Outline outline = token.ToObject(); - string type = outline.Name; - if (!SkinBOX.IsValidType(type)) - continue; + string type = outline.Name; + if (!SkinBOX.IsValidType(type)) + continue; ReadOutliner(token, type, blockBenchModel.Elements); } } @@ -304,15 +336,15 @@ namespace PckStudio.Forms.Editor } private bool LoadElement(string boxType, Element element) - { + { if (!element.UseBoxUv || !element.IsVisibile) return false; - //Debug.WriteLine($"{type} {element.Name}({element.Uuid})"); - BoundingBox boundingBox = new BoundingBox(element.From.ToOpenTKVector(), element.To.ToOpenTKVector()); - Vector3 pos = boundingBox.Start.ToNumericsVector(); - Vector3 size = boundingBox.Volume.ToNumericsVector(); - Vector2 uv = element.UvOffset; + //Debug.WriteLine($"{type} {element.Name}({element.Uuid})"); + BoundingBox boundingBox = new BoundingBox(element.From.ToOpenTKVector(), element.To.ToOpenTKVector()); + Vector3 pos = boundingBox.Start.ToNumericsVector(); + Vector3 size = boundingBox.Volume.ToNumericsVector(); + Vector2 uv = element.UvOffset; pos = TranslatePosition(boxType, pos, size, new Vector3(1, 1, 0)); //Debug.WriteLine(pos); @@ -347,19 +379,19 @@ namespace PckStudio.Forms.Editor Vector3 pos = origin; // The next line essentialy does uses the fomular below just on all axis. // x = -(pos.x + size.x) - pos *= transformUnit; + pos *= transformUnit; pos -= size * translationUnit; // Skin Renderer (and Game) specific offset value. - pos.Y += 24f; + pos.Y += 24f; Vector3 translation = renderer3D1.GetTranslation(boxType).ToNumericsVector(); Vector3 pivot = renderer3D1.GetPivot(boxType).ToNumericsVector(); - + // This will cancel out the part specific translation and pivot. - pos += translation * -Vector3.UnitX - pivot * Vector3.UnitY; + pos += translation * -Vector3.UnitX - pivot * Vector3.UnitY; return pos; - } + } private void cloneToolStripMenuItem_Click(object sender, EventArgs e) { @@ -370,6 +402,20 @@ namespace PckStudio.Forms.Editor } } + private void LoadGeometry(Geometry geometry) + { + foreach (Bone bone in geometry.Bones) + { + if (!SkinBOX.IsValidType(bone.Name)) + continue; + foreach (External.Format.Cube cube in bone.Cubes) + { + Vector3 pos = TranslatePosition(bone.Name, cube.Origin, cube.Size, Vector3.UnitY); + _skin.AdditionalBoxes.Add(new SkinBOX(bone.Name, pos, cube.Size, cube.Uv)); + } + } + } + private void deleteToolStripMenuItem_Click(object sender, EventArgs e) { if (skinPartListBox.SelectedItem is SkinBOX box) diff --git a/PCK-Studio/PckStudio.csproj b/PCK-Studio/PckStudio.csproj index 8baea77e..bd54dcfc 100644 --- a/PCK-Studio/PckStudio.csproj +++ b/PCK-Studio/PckStudio.csproj @@ -143,6 +143,7 @@ +