mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/PCK-Studio.git
synced 2026-05-23 13:07:25 +00:00
CustomSkinEditor - Add Bedrock model import
This commit is contained in:
126
PCK-Studio/External/Format/BedrockModel.cs
vendored
Normal file
126
PCK-Studio/External/Format/BedrockModel.cs
vendored
Normal 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; }
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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" />
|
||||
|
||||
Reference in New Issue
Block a user