CustomSkinEditor - Add block bench model import

This commit is contained in:
miku-666
2024-04-06 21:33:17 +02:00
parent bfffad35eb
commit 937daca168
6 changed files with 339 additions and 25 deletions

View File

@@ -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);
}
}
}

View 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;
}
}

View File

@@ -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;
}

View File

@@ -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" />

View File

@@ -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()

View File

@@ -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;