mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/PCK-Studio.git
synced 2026-07-11 18:39:00 +00:00
CustomSkinEditor - Add block bench model import
This commit is contained in:
@@ -11,5 +11,15 @@
|
||||
{
|
||||
return new OpenTK.Vector2(vector2.X, vector2.Y);
|
||||
}
|
||||
|
||||
internal static System.Numerics.Vector3 ToNumericsVector(this OpenTK.Vector3 vector3)
|
||||
{
|
||||
return new System.Numerics.Vector3(vector3.X, vector3.Y, vector3.Z);
|
||||
}
|
||||
|
||||
internal static System.Numerics.Vector2 ToNumericsVector(this OpenTK.Vector2 vector2)
|
||||
{
|
||||
return new System.Numerics.Vector2(vector2.X, vector2.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
155
PCK-Studio/External/Format/BlockBenchModel.cs
vendored
Normal file
155
PCK-Studio/External/Format/BlockBenchModel.cs
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
using System;
|
||||
using System.Buffers.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PckStudio.External.Format
|
||||
{
|
||||
internal class Meta
|
||||
{
|
||||
[JsonProperty("format_version")]
|
||||
internal string FormatVersion;
|
||||
|
||||
[JsonProperty("model_format")]
|
||||
internal string ModelFormat;
|
||||
|
||||
[JsonProperty("box_uv")]
|
||||
internal bool UseBoxUv;
|
||||
}
|
||||
|
||||
internal class Element
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
internal string Name;
|
||||
|
||||
[JsonProperty("box_uv")]
|
||||
internal bool UseBoxUv;
|
||||
|
||||
[JsonProperty("visibility")]
|
||||
internal bool Visibility { get; set; } = true;
|
||||
|
||||
[JsonProperty("rescale")]
|
||||
internal bool Rescale;
|
||||
|
||||
[JsonProperty("locked")]
|
||||
internal bool Locked;
|
||||
|
||||
[JsonProperty("inflate")]
|
||||
internal float Inflate;
|
||||
|
||||
[JsonProperty("origin")]
|
||||
private float[] origin;
|
||||
|
||||
[JsonProperty("from")]
|
||||
private float[] from;
|
||||
|
||||
[JsonProperty("to")]
|
||||
private float[] to;
|
||||
|
||||
[JsonProperty("uv_offset")]
|
||||
private int[] uv_offset;
|
||||
|
||||
[JsonIgnore()]
|
||||
internal Vector3 Origin => new Vector3(origin?[0] ?? 0, origin?[1] ?? 0, origin?[2] ?? 0);
|
||||
|
||||
[JsonIgnore()]
|
||||
internal Vector3 From => new Vector3(from?[0] ?? 0, from?[1] ?? 0, from?[2] ?? 0);
|
||||
|
||||
[JsonIgnore()]
|
||||
internal Vector3 To => new Vector3(to?[0] ?? 0, to?[1] ?? 0, to?[2] ?? 0);
|
||||
|
||||
[JsonIgnore()]
|
||||
internal Vector2 UvOffset => new Vector2(uv_offset?[0] ?? 0, uv_offset?[1] ?? 0);
|
||||
|
||||
[JsonProperty("type")]
|
||||
internal string Type;
|
||||
|
||||
[JsonProperty("uuid")]
|
||||
internal Guid Uuid;
|
||||
}
|
||||
|
||||
internal class Texture
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
internal string Name;
|
||||
|
||||
[JsonProperty("source")]
|
||||
internal Uri TextureSource;
|
||||
|
||||
internal Image GetTexture()
|
||||
{
|
||||
string data = TextureSource.AbsolutePath;
|
||||
const string dataHead = "image/png;base64,";
|
||||
if (data.StartsWith(dataHead))
|
||||
{
|
||||
byte[] encodedData = Convert.FromBase64String(data.Substring(dataHead.Length));
|
||||
using (var ms = new MemoryStream(encodedData))
|
||||
{
|
||||
return Image.FromStream(ms);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Outline
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
internal string Name;
|
||||
|
||||
[JsonProperty("origin")]
|
||||
internal float[] Origin;
|
||||
|
||||
[JsonProperty("uuid")]
|
||||
internal Guid Uuid;
|
||||
|
||||
[JsonProperty("children")]
|
||||
internal Guid[] Children;
|
||||
}
|
||||
|
||||
internal class TextureRes
|
||||
{
|
||||
[JsonProperty("width")]
|
||||
internal int Width;
|
||||
|
||||
[JsonProperty("height")]
|
||||
internal int Height;
|
||||
|
||||
public static implicit operator Size(TextureRes res) => new Size(res.Width, res.Height);
|
||||
}
|
||||
|
||||
internal class BlockBenchModel
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
internal string Name;
|
||||
|
||||
[JsonProperty("meta")]
|
||||
internal Meta Metadata;
|
||||
|
||||
[JsonProperty("model_identifier")]
|
||||
internal string ModelIdentifier;
|
||||
|
||||
[JsonProperty("visible_box")]
|
||||
internal int[] VisibleBox;
|
||||
|
||||
[JsonProperty("resolution")]
|
||||
internal TextureRes TextureResolution;
|
||||
|
||||
[JsonProperty("elements")]
|
||||
internal Element[] Elements;
|
||||
|
||||
[JsonProperty("outliner")]
|
||||
internal Outline[] Outliner;
|
||||
|
||||
[JsonProperty("textures")]
|
||||
internal Texture[] Textures;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,11 @@ using PckStudio.IO.PSM;
|
||||
using PckStudio.Internal.FileFormats;
|
||||
using System.Linq;
|
||||
using PckStudio.Forms.Additional_Popups;
|
||||
using PckStudio.External.Format;
|
||||
using Newtonsoft.Json;
|
||||
using System.Numerics;
|
||||
using PckStudio.Rendering;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace PckStudio.Forms.Editor
|
||||
{
|
||||
@@ -48,7 +53,8 @@ namespace PckStudio.Forms.Editor
|
||||
|
||||
private readonly FileDialogOption[] fileFilters =
|
||||
[
|
||||
new ("Pck skin model(*.psm)", "*.psm")
|
||||
new ("Pck skin model(*.psm)", "*.psm"),
|
||||
new ("Block bench model(*.bbmodel)", "*.bbmodel")
|
||||
];
|
||||
|
||||
private string skinModelFileFilters => string.Join("|", fileFilters);
|
||||
@@ -220,6 +226,66 @@ namespace PckStudio.Forms.Editor
|
||||
_skin.PartOffsets.AddRange(csmbFile.Offsets);
|
||||
LoadModelData(_skin);
|
||||
break;
|
||||
case ".bbmodel":
|
||||
BlockBenchModel blockBenchModel = JsonConvert.DeserializeObject<BlockBenchModel>(File.ReadAllText(openFileDialog.FileName));
|
||||
_skin.AdditionalBoxes.Clear();
|
||||
_skin.PartOffsets.Clear();
|
||||
// TODO: clean this up -miku
|
||||
_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);
|
||||
|
||||
|
||||
// IMPROVMENT: detect default body parts and toggle anim flag instead of adding box data -miku
|
||||
foreach (Outline outline in blockBenchModel.Outliner)
|
||||
{
|
||||
foreach (Element element in blockBenchModel.Elements.Where(e => outline.Children.Contains(e.Uuid)))
|
||||
{
|
||||
if (!element.UseBoxUv || !element.Visibility)
|
||||
continue;
|
||||
|
||||
BoundingBox boundingBox = new BoundingBox(element.From.ToOpenTKVector(), element.To.ToOpenTKVector());
|
||||
Vector3 pos = boundingBox.Start.ToNumericsVector();
|
||||
Vector3 size = boundingBox.Volume.ToNumericsVector();
|
||||
|
||||
//Debug.WriteLine($"{outline.Name} {element.Name}({element.Uuid})");
|
||||
//Debug.WriteLine($"boundingBox.Start({boundingBox.Start})");
|
||||
//Debug.WriteLine($"boundingBox.End({boundingBox.End})");
|
||||
//Debug.WriteLine($"size({size})");
|
||||
|
||||
Vector3 transformUnit = new Vector3(-1, -1, 1);
|
||||
Vector3 coordinateUnit = new Vector3(1, 1, 0);
|
||||
|
||||
pos *= transformUnit;
|
||||
pos -= size * coordinateUnit;
|
||||
pos.Y += 24f;
|
||||
|
||||
Vector3 translation = renderer3D1.GetTranslation(outline.Name).ToNumericsVector();
|
||||
Vector3 pivot = renderer3D1.GetPivot(outline.Name).ToNumericsVector();
|
||||
|
||||
pos += translation * -Vector3.UnitX - pivot * Vector3.UnitY;
|
||||
//Debug.WriteLine(translation);
|
||||
//Debug.WriteLine(pivot);
|
||||
//Debug.WriteLine(pos);
|
||||
|
||||
_skin.AdditionalBoxes.Add(new SkinBOX(outline.Name, pos, size, element.UvOffset));
|
||||
}
|
||||
}
|
||||
|
||||
_skin.Texture = blockBenchModel.Textures[0].GetTexture();
|
||||
LoadModelData(_skin);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -151,6 +151,7 @@
|
||||
<Compile Include="Internal\Json\Entities.cs" />
|
||||
<Compile Include="Internal\Json\EntityInfo.cs" />
|
||||
<Compile Include="Internal\ResourceCategory.cs" />
|
||||
<Compile Include="External\Format\BlockBenchModel.cs" />
|
||||
<Compile Include="Internal\Skin.cs" />
|
||||
<Compile Include="Internal\SkinPartOffset.cs" />
|
||||
<Compile Include="Internal\CommitInfo.cs" />
|
||||
|
||||
@@ -11,11 +11,14 @@ namespace PckStudio.Rendering
|
||||
{
|
||||
public readonly Vector3 Start;
|
||||
public readonly Vector3 End;
|
||||
public readonly Vector3 Volume;
|
||||
|
||||
public BoundingBox(Vector3 start, Vector3 end)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
Vector3 size = End - Start;
|
||||
Volume = new Vector3(Math.Abs(size.X), Math.Abs(size.Y), Math.Abs(size.Z));
|
||||
}
|
||||
|
||||
public ColorVertex[] GetVertices()
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace PckStudio.Rendering
|
||||
}
|
||||
}
|
||||
|
||||
[Description("Event that gets fired when the Texture is changing")]
|
||||
[Description("Event that gets fired when the skin texture is changing")]
|
||||
[Category("Property Chnaged")]
|
||||
[Browsable(true)]
|
||||
public event EventHandler<TextureChangingEventArgs> TextureChanging
|
||||
@@ -110,7 +110,7 @@ namespace PckStudio.Rendering
|
||||
remove => Events.RemoveHandler(nameof(TextureChanging), value);
|
||||
}
|
||||
|
||||
[Description("Event that gets fired when the Texture is changing")]
|
||||
[Description("Event that gets fired when the cape texture is changing")]
|
||||
[Category("Property Chnaged")]
|
||||
[Browsable(true)]
|
||||
public event EventHandler<TextureChangingEventArgs> CapeTextureChanging
|
||||
@@ -345,13 +345,13 @@ namespace PckStudio.Rendering
|
||||
leftArm.AddCube(new(-1, -2, -2), new(4, 12, 4), new(48, 48), inflate: OverlayScale);
|
||||
|
||||
rightLeg ??= new CubeGroupMesh("Right Leg");
|
||||
rightLeg.Pivot = new Vector3(0f, 12f, 0f);
|
||||
rightLeg.Pivot = new Vector3(-2f, 12f, 0f);
|
||||
rightLeg.Translation = new Vector3(-2f, -12f, 0f);
|
||||
rightLeg.AddCube(new(-2, 0, -2), new(4, 12, 4), new(0, 16));
|
||||
rightLeg.AddCube(new(-2, 0, -2), new(4, 12, 4), new(0, 32), OverlayScale);
|
||||
|
||||
leftLeg ??= new CubeGroupMesh("Left Leg");
|
||||
leftLeg.Pivot = new Vector3(0f, 12f, 0f);
|
||||
leftLeg.Pivot = new Vector3(2f, 12f, 0f);
|
||||
leftLeg.Translation = new Vector3(2f, -12f, 0f);
|
||||
leftLeg.AddCube(new(-2, 0, -2), new(4, 12, 4), new(16, 48));
|
||||
leftLeg.AddCube(new(-2, 0, -2), new(4, 12, 4), new(0, 48), OverlayScale);
|
||||
@@ -642,22 +642,7 @@ namespace PckStudio.Rendering
|
||||
GLErrorCheck();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
// Debug render
|
||||
{
|
||||
ColorVertex[] vertices = [
|
||||
new ColorVertex(Vector3.Zero, Color.White)
|
||||
];
|
||||
VertexArray vao = new VertexArray();
|
||||
var debugVBO = new VertexBuffer();
|
||||
debugVBO.SetData(vertices);
|
||||
VertexBufferLayout layout = new VertexBufferLayout();
|
||||
layout.Add(ShaderDataType.Float3);
|
||||
layout.Add(ShaderDataType.Float4);
|
||||
vao.AddBuffer(debugVBO, layout);
|
||||
d_debugDrawContext = new DrawContext(vao, debugVBO.GenIndexBuffer(), PrimitiveType.Points);
|
||||
}
|
||||
#endif
|
||||
InitializeDebugShaders();
|
||||
}
|
||||
|
||||
private DrawContext GetGuidelineDrawContext()
|
||||
@@ -741,6 +726,16 @@ namespace PckStudio.Rendering
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 GetTranslation(string name)
|
||||
{
|
||||
return meshStorage.ContainsKey(name) ? meshStorage[name].Translation : Vector3.Zero;
|
||||
}
|
||||
|
||||
public Vector3 GetPivot(string name)
|
||||
{
|
||||
return meshStorage.ContainsKey(name) ? meshStorage[name].Pivot : Vector3.Zero;
|
||||
}
|
||||
|
||||
public void SetPartOffset(SkinPartOffset offset)
|
||||
{
|
||||
SetPartOffset(offset.Type, offset.Value);
|
||||
@@ -988,9 +983,9 @@ namespace PckStudio.Rendering
|
||||
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
||||
|
||||
GL.Enable(EnableCap.AlphaTest); // Enable transparent
|
||||
GL.AlphaFunc(AlphaFunction.Greater, 0.4f);
|
||||
GL.AlphaFunc(AlphaFunction.Greater, 0.0f);
|
||||
GL.DepthFunc(DepthFunction.Lequal);
|
||||
|
||||
|
||||
if (showWireFrame)
|
||||
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
|
||||
|
||||
@@ -1305,6 +1300,42 @@ namespace PckStudio.Rendering
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void InitializeDebugShaders()
|
||||
{
|
||||
#if DEBUG
|
||||
// Debug point render
|
||||
{
|
||||
ColorVertex[] vertices = [
|
||||
new ColorVertex(Vector3.Zero, Color.White)
|
||||
];
|
||||
VertexArray vao = new VertexArray();
|
||||
var debugVBO = new VertexBuffer();
|
||||
debugVBO.SetData(vertices);
|
||||
VertexBufferLayout layout = new VertexBufferLayout();
|
||||
layout.Add(ShaderDataType.Float3);
|
||||
layout.Add(ShaderDataType.Float4);
|
||||
vao.AddBuffer(debugVBO, layout);
|
||||
d_debugPointDrawContext = new DrawContext(vao, debugVBO.GenIndexBuffer(), PrimitiveType.Points);
|
||||
}
|
||||
// Debug point render
|
||||
{
|
||||
ColorVertex[] vertices = [
|
||||
new ColorVertex(Vector3.Zero),
|
||||
new ColorVertex(Vector3.One)
|
||||
];
|
||||
VertexArray vao = new VertexArray();
|
||||
var debugVBO = new VertexBuffer();
|
||||
debugVBO.SetData(vertices);
|
||||
VertexBufferLayout layout = new VertexBufferLayout();
|
||||
layout.Add(ShaderDataType.Float3);
|
||||
layout.Add(ShaderDataType.Float4);
|
||||
vao.AddBuffer(debugVBO, layout);
|
||||
d_debugLineDrawContext = new DrawContext(vao, debugVBO.GenIndexBuffer(), PrimitiveType.Lines);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void RenderDebug()
|
||||
{
|
||||
@@ -1324,12 +1355,53 @@ namespace PckStudio.Rendering
|
||||
colorShader.SetUniform1("intensity", 0.75f);
|
||||
colorShader.SetUniform4("baseColor", Color.DeepPink);
|
||||
GL.PointSize(5f);
|
||||
Renderer.Draw(colorShader, d_debugDrawContext);
|
||||
Renderer.Draw(colorShader, d_debugPointDrawContext);
|
||||
GL.PointSize(1f);
|
||||
GL.DepthMask(true);
|
||||
GL.DepthFunc(DepthFunction.Less);
|
||||
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
||||
}
|
||||
if (d_showDirectionArrows)
|
||||
{
|
||||
GL.BlendFunc(BlendingFactor.DstAlpha, BlendingFactor.OneMinusSrcAlpha);
|
||||
GL.DepthFunc(DepthFunction.Always);
|
||||
GL.DepthMask(false);
|
||||
GL.Enable(EnableCap.LineSmooth);
|
||||
colorShader.Bind();
|
||||
|
||||
var viewProjection = Camera.GetViewProjection();
|
||||
var transform = Matrix4.Identity;
|
||||
transform *= Matrix4.CreateTranslation(Vector3.Zero);
|
||||
transform *= Matrix4.CreateScale(Camera.Distance / 4f).Inverted();
|
||||
transform.Invert();
|
||||
colorShader.SetUniformMat4("Transform", ref transform);
|
||||
colorShader.SetUniformMat4("ViewProjection", ref viewProjection);
|
||||
colorShader.SetUniform1("intensity", 0.75f);
|
||||
|
||||
|
||||
Renderer.SetLineWidth(2f);
|
||||
|
||||
colorShader.SetUniform4("baseColor", Color.Red);
|
||||
ColorVertex[] line = [new ColorVertex(Vector3.Zero), new ColorVertex(Vector3.UnitX)];
|
||||
d_debugLineDrawContext.VertexArray.GetBuffer(0).SetData(line);
|
||||
Renderer.Draw(colorShader, d_debugLineDrawContext);
|
||||
|
||||
colorShader.SetUniform4("baseColor", Color.Green);
|
||||
line = [new ColorVertex(Vector3.Zero), new ColorVertex(Vector3.UnitY)];
|
||||
d_debugLineDrawContext.VertexArray.GetBuffer(0).SetData(line);
|
||||
Renderer.Draw(colorShader, d_debugLineDrawContext);
|
||||
|
||||
colorShader.SetUniform4("baseColor", Color.Blue);
|
||||
line = [new ColorVertex(Vector3.Zero), new ColorVertex(Vector3.UnitZ)];
|
||||
d_debugLineDrawContext.VertexArray.GetBuffer(0).SetData(line);
|
||||
Renderer.Draw(colorShader, d_debugLineDrawContext);
|
||||
|
||||
Renderer.SetLineWidth(1f);
|
||||
|
||||
GL.DepthMask(true);
|
||||
GL.DepthFunc(DepthFunction.Less);
|
||||
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
||||
}
|
||||
d_debugLabel.Text = Camera.ToString();
|
||||
#endif
|
||||
}
|
||||
@@ -1388,6 +1460,11 @@ namespace PckStudio.Rendering
|
||||
debugShowFocalPointToolStripMenuItem.Click += (s, e) => d_showFocalPoint = debugShowFocalPointToolStripMenuItem.Checked;
|
||||
contextMenuStrip1.Items.Add(debugShowFocalPointToolStripMenuItem);
|
||||
|
||||
var debugShowDirectionArrows = new ToolStripMenuItem("Show Direction Arrows");
|
||||
debugShowDirectionArrows.CheckOnClick = true;
|
||||
debugShowDirectionArrows.Click += (s, e) => d_showDirectionArrows = debugShowDirectionArrows.Checked;
|
||||
contextMenuStrip1.Items.Add(debugShowDirectionArrows);
|
||||
|
||||
Controls.Add(d_debugLabel);
|
||||
|
||||
this.contextMenuStrip1.ResumeLayout(false);
|
||||
@@ -1396,7 +1473,9 @@ namespace PckStudio.Rendering
|
||||
|
||||
#if DEBUG
|
||||
private bool d_showFocalPoint;
|
||||
private DrawContext d_debugDrawContext;
|
||||
private bool d_showDirectionArrows;
|
||||
private DrawContext d_debugPointDrawContext;
|
||||
private DrawContext d_debugLineDrawContext;
|
||||
private Label d_debugLabel;
|
||||
private ToolStripMenuItem reToolStripMenuItem;
|
||||
private ContextMenuStrip contextMenuStrip1;
|
||||
|
||||
Reference in New Issue
Block a user