CustomSkinEditor - Add Bedrock model import

This commit is contained in:
miku-666
2024-04-08 16:55:05 +02:00
parent 416ef2424e
commit a7efbd1c34
3 changed files with 188 additions and 15 deletions

View File

@@ -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<Geometry> Models;
}
internal class Geometry
{
[JsonProperty("description")]
public GeometryDescription Description { get; set; }
[JsonProperty("bones")]
public List<Bone> 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<Cube> 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; }
}
}

View File

@@ -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<BedrockModel>(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<BlockBenchModel>(File.ReadAllText(openFileDialog.FileName));
@@ -262,9 +294,9 @@ namespace PckStudio.Forms.Editor
if (token.Type == JTokenType.Object)
{
Outline outline = token.ToObject<Outline>();
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)

View File

@@ -143,6 +143,7 @@
<Compile Include="Extensions\SkinExtensions.cs" />
<Compile Include="Extensions\System.Numerics.cs" />
<Compile Include="Extensions\TreeNodeExtensions.cs" />
<Compile Include="External\Format\BedrockModel.cs" />
<Compile Include="Internal\Deserializer\ImageDeserializer.cs" />
<Compile Include="Internal\Serializer\AnimationSerializer.cs" />
<Compile Include="Internal\Deserializer\AnimationDeserializer.cs" />