Refactor Skin.cs

- Move texture from 'SkinModel' to Skin.cs
- Move 'Id' from SkinMetaData into it's own class(SkinIdentifier.cs)
- Create SkinModelInfo class for keeping skin conversion simple
This commit is contained in:
miku-666
2025-01-12 15:38:19 +01:00
parent 45785b2841
commit c5aa1eb437
10 changed files with 116 additions and 129 deletions

View File

@@ -94,9 +94,9 @@ namespace PckStudio.Extensions
if (asset.Type != PckAssetType.SkinFile)
throw new InvalidOperationException("Asset is not a skin file");
asset.SetTexture(skin.Model.Texture);
asset.SetTexture(skin.Texture);
string skinId = skin.MetaData.Id.ToString("d08");
string skinId = skin.Identifier.ToString("d08");
// TODO: keep filepath
asset.Filename = $"dlcskin{skinId}.png";
@@ -118,7 +118,7 @@ namespace PckStudio.Extensions
asset.SetProperty("CAPEPATH", $"dlccape{skinId}.png");
}
asset.SetProperty("ANIM", skin.Model.ANIM.ToString());
asset.SetProperty("ANIM", skin.ANIM.ToString());
asset.SetProperty("GAME_FLAGS", "0x18");
asset.SetProperty("FREE", "1");

View File

@@ -15,7 +15,7 @@ namespace PckStudio.Extensions
{
public static PckAsset CreateFile(this Skin skin, LOCFile localizationFile)
{
string skinId = skin.MetaData.Id.ToString("d08");
string skinId = skin.Identifier.ToString("d08");
PckAsset skinFile = new PckAsset($"dlcskin{skinId}.png", PckAssetType.SkinFile);
skinFile.AddProperty("DISPLAYNAME", skin.MetaData.Name);
@@ -41,7 +41,7 @@ namespace PckStudio.Extensions
skinFile.AddProperty("CAPEPATH", $"dlccape{skinId}.png");
}
skinFile.AddProperty("ANIM", skin.Model.ANIM);
skinFile.AddProperty("ANIM", skin.ANIM);
skinFile.AddProperty("GAME_FLAGS", "0x18");
skinFile.AddProperty("FREE", "1");
@@ -54,7 +54,7 @@ namespace PckStudio.Extensions
skinFile.AddProperty(offset.ToProperty());
}
skinFile.SetTexture(skin.Model.Texture);
skinFile.SetTexture(skin.Texture);
return skinFile;
}
@@ -63,7 +63,7 @@ namespace PckStudio.Extensions
{
if (!skin.HasCape)
throw new InvalidOperationException("Skin does not contain a cape.");
string skinId = skin.MetaData.Id.ToString("d08");
string skinId = skin.Identifier.ToString("d08");
PckAsset capeFile = new PckAsset($"dlccape{skinId}.png", PckAssetType.CapeFile);
capeFile.SetTexture(skin.CapeTexture);
return capeFile;

View File

@@ -33,18 +33,16 @@ namespace PckStudio.Forms.Additional_Popups
private void SetNewTexture(Image img)
{
if (img is null)
{
Debug.Assert(false, "Image is null.");
}
Debug.Assert(img is not null, "Image is null.");
if (img.Width != img.Height && img.Height != img.Width / 2)
{
MessageBox.Show("The selected image does not suit a skin texture.", "Invalid image dimensions.", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
newSkin.Model.ANIM.SetFlag(SkinAnimFlag.RESOLUTION_64x64, img.Width == img.Height);
newSkin.ANIM.SetFlag(SkinAnimFlag.RESOLUTION_64x64, img.Width == img.Height);
skinPictureBox.Image = newSkin.Model.Texture = img;
skinPictureBox.Image = newSkin.Texture = img;
labelSelectTexture.Visible = false;
capePictureBox.Visible = true;
buttonCape.Visible = true;
@@ -55,43 +53,43 @@ namespace PckStudio.Forms.Additional_Popups
private void DrawModel()
{
bool isSlim = newSkin.Model.ANIM.GetFlag(SkinAnimFlag.SLIM_MODEL);
bool isSlim = newSkin.ANIM.GetFlag(SkinAnimFlag.SLIM_MODEL);
Pen outlineColor = Pens.LightGray;
Brush fillColor = Brushes.Gray;
Image previewTexture = new Bitmap(displayBox.Width, displayBox.Height);
using (Graphics g = Graphics.FromImage(previewTexture))
{
if(!newSkin.Model.ANIM.GetFlag(SkinAnimFlag.HEAD_DISABLED))
if(!newSkin.ANIM.GetFlag(SkinAnimFlag.HEAD_DISABLED))
{
//Head
g.DrawRectangle(outlineColor, 70, 15, 40, 40);
g.FillRectangle(fillColor, 71, 16, 39, 39);
}
if (!newSkin.Model.ANIM.GetFlag(SkinAnimFlag.BODY_DISABLED))
if (!newSkin.ANIM.GetFlag(SkinAnimFlag.BODY_DISABLED))
{
//Body
g.DrawRectangle(outlineColor, 70, 55, 40, 60);
g.FillRectangle(fillColor, 71, 56, 39, 59);
}
if (!newSkin.Model.ANIM.GetFlag(SkinAnimFlag.RIGHT_ARM_DISABLED))
if (!newSkin.ANIM.GetFlag(SkinAnimFlag.RIGHT_ARM_DISABLED))
{
//Arm0
g.DrawRectangle(outlineColor, isSlim ? 55 : 50, 55, isSlim ? 15 : 20, 60);
g.FillRectangle(fillColor , isSlim ? 56 : 51, 56, isSlim ? 14 : 19, 59);
}
if (!newSkin.Model.ANIM.GetFlag(SkinAnimFlag.LEFT_ARM_DISABLED))
if (!newSkin.ANIM.GetFlag(SkinAnimFlag.LEFT_ARM_DISABLED))
{
//Arm1
g.DrawRectangle(outlineColor, 110, 55, isSlim ? 15 : 20, 60);
g.FillRectangle(fillColor, 111, 56, isSlim ? 14 : 19, 59);
}
if (!newSkin.Model.ANIM.GetFlag(SkinAnimFlag.RIGHT_LEG_DISABLED))
if (!newSkin.ANIM.GetFlag(SkinAnimFlag.RIGHT_LEG_DISABLED))
{
//Leg0
g.DrawRectangle(outlineColor, 70, 115, 20, 60);
g.FillRectangle(fillColor, 71, 116, 19, 59);
}
if (!newSkin.Model.ANIM.GetFlag(SkinAnimFlag.LEFT_LEG_DISABLED))
if (!newSkin.ANIM.GetFlag(SkinAnimFlag.LEFT_LEG_DISABLED))
{
//Leg1
g.DrawRectangle(outlineColor, 90, 115, 20, 60);
@@ -157,7 +155,7 @@ namespace PckStudio.Forms.Additional_Popups
return;
}
var img = Image.FromFile(ofd.FileName).ReleaseFromFile();
Image img = Image.FromFile(ofd.FileName).ReleaseFromFile();
SetNewTexture(img);
}
}
@@ -184,7 +182,7 @@ namespace PckStudio.Forms.Additional_Popups
ofd.Title = "Select a PNG File";
if (ofd.ShowDialog() == DialogResult.OK)
{
var img = Image.FromFile(ofd.FileName).ReleaseFromFile();
Image img = Image.FromFile(ofd.FileName).ReleaseFromFile();
if (img.RawFormat != ImageFormat.Png && img.Width != img.Height * 2)
{
MessageBox.Show(this, "Not a Valid Cape File");
@@ -207,7 +205,7 @@ namespace PckStudio.Forms.Additional_Popups
MessageBox.Show("The Skin Id must be a unique 8 digit number that is not already in use", "Invalid Skin Id", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
newSkin.MetaData.Id = _skinId;
newSkin.Identifier = new SkinIdentifier(_skinId);
}
newSkin.MetaData.Name = textSkinName.Text;
newSkin.MetaData.Theme = textThemeName.Text;
@@ -232,7 +230,7 @@ namespace PckStudio.Forms.Additional_Popups
if (customSkinEditor.ShowDialog() == DialogResult.OK)
{
skinPictureBox.Image = customSkinEditor.ResultSkin.Model.Texture;
skinPictureBox.Image = customSkinEditor.ResultSkin.Texture;
newSkin = customSkinEditor.ResultSkin;
buttonDone.Enabled = true;
labelSelectTexture.Visible = false;
@@ -244,8 +242,8 @@ namespace PckStudio.Forms.Additional_Popups
{
if (radioButtonAuto.Checked)
{
newSkin.MetaData.Id = rng.Next(100000, 99999999);
textSkinID.Text = newSkin.MetaData.Id.ToString();
newSkin.Identifier = new(rng.Next(100000, 99999999));
textSkinID.Text = newSkin.Identifier.ToString();
textSkinID.Enabled = false;
}
}
@@ -257,10 +255,10 @@ namespace PckStudio.Forms.Additional_Popups
private void buttonAnimGen_Click(object sender, EventArgs e)
{
using ANIMEditor diag = new ANIMEditor(newSkin.Model.ANIM);
using ANIMEditor diag = new ANIMEditor(newSkin.ANIM);
if (diag.ShowDialog(this) == DialogResult.OK)
{
newSkin.Model.ANIM = diag.ResultAnim;
newSkin.ANIM = diag.ResultAnim;
DrawModel();
}
}

View File

@@ -74,10 +74,10 @@ namespace PckStudio.Forms.Editor
{
if (keyData == Keys.A)
{
using var animeditor = new ANIMEditor(_skin.Model.ANIM);
using var animeditor = new ANIMEditor(_skin.ANIM);
if (animeditor.ShowDialog() == DialogResult.OK)
{
renderer3D1.ANIM = _skin.Model.ANIM = animeditor.ResultAnim;
renderer3D1.ANIM = _skin.ANIM = animeditor.ResultAnim;
skinPartListBox_SelectedIndexChanged(this, EventArgs.Empty);
}
return true;
@@ -87,12 +87,12 @@ namespace PckStudio.Forms.Editor
private void LoadModelData()
{
SkinModelInfo modelInfo = _skin.Model;
SkinModel modelInfo = _skin.Model;
List<SkinBOX> boxProperties = modelInfo.AdditionalBoxes;
List<SkinPartOffset> offsetProperties = modelInfo.PartOffsets;
renderer3D1.ANIM = modelInfo.ANIM;
renderer3D1.ANIM = _skin.ANIM;
renderer3D1.ModelData.Clear();
foreach (SkinBOX box in boxProperties)
@@ -105,14 +105,14 @@ namespace PckStudio.Forms.Editor
renderer3D1.SetPartOffset(offset);
}
if (modelInfo.Texture is not null)
if (_skin.Texture is not null)
{
renderer3D1.Texture = modelInfo.Texture;
renderer3D1.Texture = _skin.Texture;
}
if (modelInfo.Texture is null && renderer3D1.Texture is not null)
if (_skin.Texture is null && renderer3D1.Texture is not null)
{
modelInfo.Texture = renderer3D1.Texture;
_skin.Texture = renderer3D1.Texture;
}
skinOffsetListBindingSource = new BindingSource(renderer3D1.GetOffsets().ToArray(), null);
@@ -126,12 +126,12 @@ namespace PckStudio.Forms.Editor
private void GenerateUVTextureMap(SkinBOX skinBox)
{
if (_skin?.Model?.Texture is null)
if (_skin?.Texture is null)
{
Trace.TraceWarning($"[{nameof(CustomSkinEditor)}@{nameof(GenerateUVTextureMap)}] Failed to generate uv for {skinBox}. Reason: Model.Texture was null");
return;
}
using (Graphics graphics = Graphics.FromImage(_skin.Model.Texture))
using (Graphics graphics = Graphics.FromImage(_skin.Texture))
{
graphics.ApplyConfig(_graphicsConfig);
int argb = rng.Next(unchecked((int)0xFF000000), -1);
@@ -139,7 +139,7 @@ namespace PckStudio.Forms.Editor
Brush brush = new SolidBrush(color);
graphics.FillPath(brush, skinBox.GetUVGraphicsPath());
}
renderer3D1.Texture = _skin.Model.Texture;
renderer3D1.Texture = _skin.Texture;
}
private void createToolStripMenuItem_Click(object sender, EventArgs e)
@@ -158,7 +158,7 @@ namespace PckStudio.Forms.Editor
private void exportTextureButton_Click(object sender, EventArgs e)
{
if (_skin?.Model?.Texture is null)
if (_skin?.Texture is null)
{
Trace.TraceWarning($"[{nameof(CustomSkinEditor)}@{nameof(exportTextureButton_Click)}] Failed to export texture. Reason: skin.Model.Texture was null");
return;
@@ -167,7 +167,7 @@ namespace PckStudio.Forms.Editor
saveFileDialog.Filter = "PNG Image Files | *.png";
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
_skin.Model.Texture.Save(saveFileDialog.FileName, ImageFormat.Png);
_skin.Texture.Save(saveFileDialog.FileName, ImageFormat.Png);
}
}
@@ -191,7 +191,7 @@ namespace PckStudio.Forms.Editor
_skin.Model.PartOffsets.Clear();
_skin.Model.PartOffsets.AddRange(renderer3D1.GetOffsets());
// just in case they're not the same instance
_skin.Model.ANIM = renderer3D1.ANIM;
_skin.ANIM = renderer3D1.ANIM;
DialogResult = DialogResult.OK;
}
@@ -202,7 +202,7 @@ namespace PckStudio.Forms.Editor
saveFileDialog.Filter = SkinModelImporter.Default.SupportedModelFileFormatsFilter;
saveFileDialog.FileName = _skin.MetaData.Name.TrimEnd(new char[] { '\n', '\r' }).Replace(' ', '_');
if (saveFileDialog.ShowDialog() == DialogResult.OK)
SkinModelImporter.Default.Export(saveFileDialog.FileName, _skin.Model);
SkinModelImporter.Default.Export(saveFileDialog.FileName, _skin.GetModelInfo());
}
private void importSkinButton_Click(object sender, EventArgs e)
@@ -215,7 +215,7 @@ namespace PckStudio.Forms.Editor
SkinModelInfo modelInfo = SkinModelImporter.Default.Import(openFileDialog.FileName);
if (modelInfo is not null)
{
_skin.Model = modelInfo;
_skin.SetModelInfo(modelInfo);
LoadModelData();
}
}
@@ -268,7 +268,7 @@ namespace PckStudio.Forms.Editor
MessageBox.Show("The selected image does not suit a skin texture.", "Invalid image dimensions.", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
uvPictureBox.Image = _skin.Model.Texture = texture;
uvPictureBox.Image = _skin.Texture = texture;
textureSizeLabel.Text = $"{texture.Width}x{texture.Height}";
}
@@ -296,7 +296,7 @@ namespace PckStudio.Forms.Editor
sizeLabel.Text = $"Size: {box.Size}";
positionLabel.Text = $"Position: {box.Pos}";
Image uvArea = _skin.Model.Texture.GetArea(Rectangle.Truncate(new RectangleF(box.UV.X, box.UV.Y, box.Size.X * 2 + box.Size.Z * 2, box.Size.Z + box.Size.Y)));
Image uvArea = _skin.Texture.GetArea(Rectangle.Truncate(new RectangleF(box.UV.X, box.UV.Y, box.Size.X * 2 + box.Size.Z * 2, box.Size.Z + box.Size.Y)));
Bitmap refImg = new Bitmap(1, 1);
@@ -309,14 +309,14 @@ namespace PckStudio.Forms.Editor
Color avgColor = refImg.GetPixel(0, 0);
renderer3D1.HighlightlingColor = avgColor.Inversed();
Size scaleSize = new Size(_skin.Model.Texture.Width * scale, _skin.Model.Texture.Height * scale);
Size scaleSize = new Size(_skin.Texture.Width * scale, _skin.Texture.Height * scale);
uvPictureBox.Image = new Bitmap(scaleSize.Width, scaleSize.Height);
using (Graphics g = Graphics.FromImage(uvPictureBox.Image))
{
GraphicsPath graphicsPath = box.GetUVGraphicsPath(new System.Numerics.Vector2(scaleSize.Width * renderer3D1.TillingFactor.X, scaleSize.Height * renderer3D1.TillingFactor.Y));
var brush = new SolidBrush(Color.FromArgb(127, avgColor.GreyScaled()));
g.ApplyConfig(_graphicsConfig);
g.DrawImage(_skin.Model.Texture, new Rectangle(Point.Empty, scaleSize), new Rectangle(Point.Empty, _skin.Model.Texture.Size), GraphicsUnit.Pixel);
g.DrawImage(_skin.Texture, new Rectangle(Point.Empty, scaleSize), new Rectangle(Point.Empty, _skin.Texture.Size), GraphicsUnit.Pixel);
g.FillPath(brush, graphicsPath);
}
uvPictureBox.Invalidate();
@@ -410,7 +410,7 @@ namespace PckStudio.Forms.Editor
private void ClearSelection()
{
skinPartListBox.ClearSelected();
uvPictureBox.Image = _skin.Model.Texture;
uvPictureBox.Image = _skin.Texture;
}
@@ -451,7 +451,7 @@ namespace PckStudio.Forms.Editor
saveFileDialog.FileName = templateFilename.TrimEnd(new char[] { '\n', '\r' }).Replace(' ', '_');
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
SkinModelInfo modelInfo = new SkinModelInfo(templateTexture, new SkinANIM(templateAnimMask));
SkinModelInfo modelInfo = new SkinModelInfo(templateTexture, templateAnimMask, new SkinModel());
SkinModelImporter.Default.Export(saveFileDialog.FileName, modelInfo);
}
}

View File

@@ -49,15 +49,6 @@ namespace PckStudio.Internal.FileFormats
public readonly List<SkinBOX> Parts = new List<SkinBOX>();
public readonly List<SkinPartOffset> Offsets = new List<SkinPartOffset>();
public static PSMFile FromSkin(SkinModelInfo skin)
{
var csmb = new PSMFile(1);
csmb.SkinANIM = skin.ANIM;
csmb.Parts.AddRange(skin.AdditionalBoxes);
csmb.Offsets.AddRange(skin.PartOffsets);
return csmb;
}
}
public enum PSMOffsetType : byte

View File

@@ -10,8 +10,17 @@ namespace PckStudio.Internal.Skin
public sealed class Skin
{
public SkinMetaData MetaData { get; set; }
public SkinModelInfo Model { get; set; }
public SkinIdentifier Identifier { get; set; }
public SkinANIM ANIM { get; set; }
public SkinModel Model { get; set; }
public Image Texture { get; set; }
public Image CapeTexture { get; set; }
public bool HasCape => CapeTexture is not null;
public Skin(string name, Image texture)
@@ -19,9 +28,9 @@ namespace PckStudio.Internal.Skin
MetaData = new SkinMetaData()
{
Name = name,
Id = 0,
};
Model = new SkinModelInfo(texture);
Texture = texture;
Model = new SkinModel();
}
public Skin(string name, Image texture, Image capeTexture)
@@ -35,14 +44,22 @@ namespace PckStudio.Internal.Skin
{
Model.AdditionalBoxes.AddRange(additionalBoxes);
Model.PartOffsets.AddRange(partOffsets);
Model.ANIM = anim;
ANIM = anim;
}
internal Skin(string name, int id, Image texture, SkinANIM anim, IEnumerable<SkinBOX> additionalBoxes, IEnumerable<SkinPartOffset> partOffsets)
: this(name, anim, texture, additionalBoxes, partOffsets)
{
MetaData.Id = id;
Identifier = new(id);
}
internal SkinModelInfo GetModelInfo() => new SkinModelInfo(Texture, ANIM, Model);
internal void SetModelInfo(SkinModelInfo modelInfo)
{
Texture = modelInfo.Texture;
ANIM = modelInfo.Anim;
Model = modelInfo.Model;
}
}
}

View File

@@ -4,6 +4,5 @@
{
public string Name { get; set; }
public string Theme { get; set; }
public int Id { get; set; }
}
}

View File

@@ -3,41 +3,21 @@ using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using OMI.Formats.Pck;
using System.Threading.Tasks;
namespace PckStudio.Internal.Skin
{
public sealed class SkinModelInfo
internal sealed class SkinModelInfo
{
public Image Texture { get; set; }
public SkinANIM ANIM { get; set; }
public readonly List<SkinBOX> AdditionalBoxes;
public readonly List<SkinPartOffset> PartOffsets;
public SkinModelInfo() : this(null)
{
}
public SkinModel Model { get; }
public SkinANIM Anim { get; }
public Image Texture { get; }
public SkinModelInfo(Image texture)
: this(texture, SkinANIM.Empty)
public SkinModelInfo(Image texture, SkinANIM anim, SkinModel model)
{
Texture = texture;
}
public SkinModelInfo(Image texture, SkinANIM anim)
{
Texture = texture;
ANIM = anim;
AdditionalBoxes = new List<SkinBOX>();
PartOffsets = new List<SkinPartOffset>(5);
}
public SkinModelInfo(Image texture, SkinANIM anim, IEnumerable<SkinBOX> additionalBoxes, IEnumerable<SkinPartOffset> partOffsets)
{
Texture = texture;
ANIM = anim;
AdditionalBoxes = new List<SkinBOX>(additionalBoxes);
PartOffsets = new List<SkinPartOffset>(partOffsets);
Anim = anim;
Model = model;
}
}
}

View File

@@ -51,14 +51,14 @@ namespace PckStudio.Internal
{
var reader = new PSMFileReader();
PSMFile csmbFile = reader.FromFile(filepath);
return new SkinModelInfo(null, csmbFile.SkinANIM, csmbFile.Parts, csmbFile.Offsets);
return new SkinModelInfo(null, csmbFile.SkinANIM, new(csmbFile.Parts, csmbFile.Offsets));
}
internal static void ExportPsm(string filepath, SkinModelInfo modelInfo)
{
PSMFile psmFile = new PSMFile(PSMFile.CurrentVersion, modelInfo.ANIM);
psmFile.Parts.AddRange(modelInfo.AdditionalBoxes);
psmFile.Offsets.AddRange(modelInfo.PartOffsets);
PSMFile psmFile = new PSMFile(PSMFile.CurrentVersion, modelInfo.Anim);
psmFile.Parts.AddRange(modelInfo.Model.AdditionalBoxes);
psmFile.Offsets.AddRange(modelInfo.Model.PartOffsets);
var writer = new PSMFileWriter(psmFile);
writer.WriteToFile(filepath);
}
@@ -80,22 +80,19 @@ namespace PckStudio.Internal
IEnumerable<SkinBOX> boxes = ReadOutliner(null, blockBenchModel.Outliner, blockBenchModel.Elements);
SkinModelInfo modelInfo = CreateSkinModelInfo(boxes, partOffsets);
Image texture = null;
if (blockBenchModel.Textures.IndexInRange(0))
{
modelInfo.Texture = blockBenchModel.Textures[0];
modelInfo.Texture = SwapBoxBottomTexture(modelInfo);
modelInfo.ANIM = modelInfo.ANIM.SetFlag(SkinAnimFlag.RESOLUTION_64x64, modelInfo.Texture.Size.Width == modelInfo.Texture.Size.Height);
texture = blockBenchModel.Textures[0];
texture = SwapBoxBottomTexture(texture, boxes);
}
return modelInfo;
return CreateSkinModelInfo(texture, boxes, partOffsets);
}
private static SkinModelInfo CreateSkinModelInfo(IEnumerable<SkinBOX> boxes, IEnumerable<SkinPartOffset> partOffsets)
private static SkinModelInfo CreateSkinModelInfo(Image texture, IEnumerable<SkinBOX> boxes, IEnumerable<SkinPartOffset> partOffsets)
{
SkinModelInfo modelInfo = new SkinModelInfo();
modelInfo.ANIM = (
SkinANIM skinANIM = (
SkinAnimMask.HEAD_DISABLED |
SkinAnimMask.HEAD_OVERLAY_DISABLED |
SkinAnimMask.BODY_DISABLED |
@@ -109,11 +106,15 @@ namespace PckStudio.Internal
SkinAnimMask.LEFT_LEG_DISABLED |
SkinAnimMask.LEFT_LEG_OVERLAY_DISABLED);
modelInfo.PartOffsets.AddRange(partOffsets);
skinANIM = skinANIM.SetFlag(SkinAnimFlag.RESOLUTION_64x64, texture.Size.Width == texture.Size.Height);
SkinModel skinModel = new SkinModel();
skinModel.PartOffsets.AddRange(partOffsets);
SkinBOX ApplyOffset(SkinBOX box)
{
SkinPartOffset offset = modelInfo.PartOffsets.FirstOrDefault(offset => offset.Type == (box.IsOverlayPart() ? box.GetBaseType() : box.Type));
SkinPartOffset offset = skinModel.PartOffsets.FirstOrDefault(offset => offset.Type == (box.IsOverlayPart() ? box.GetBaseType() : box.Type));
return string.IsNullOrEmpty(offset.Type) ? box : new SkinBOX(box.Type, box.Pos - (Vector3.UnitY * offset.Value), box.Size, box.UV, box.HideWithArmor, box.Mirror, box.Scale);
}
@@ -121,7 +122,7 @@ namespace PckStudio.Internal
IEnumerable<SkinBOX> customBoxes = convertedBoxes.Where(box => !SkinBOX.KnownHashes.ContainsKey(box.GetHashCode()));
modelInfo.AdditionalBoxes.AddRange(customBoxes);
skinModel.AdditionalBoxes.AddRange(customBoxes);
// check for know boxes and filter them out
SkinAnimMask mask = (SkinAnimMask)convertedBoxes
@@ -132,9 +133,9 @@ namespace PckStudio.Internal
.Aggregate((a, b) => a | b);
if (mask != SkinAnimMask.NONE)
modelInfo.ANIM &= ~mask;
skinANIM &= ~mask;
return modelInfo;
return new SkinModelInfo(texture, skinANIM, skinModel);
}
private static IEnumerable<SkinBOX> ReadOutliner(string parentName, JArray oulineChildren, IReadOnlyCollection<Element> elements)
@@ -177,7 +178,7 @@ namespace PckStudio.Internal
BlockBenchModel blockBenchModel = BlockBenchModel.Create(BlockBenchFormatInfos.BedrockEntity, Path.GetFileNameWithoutExtension(filepath), new Size(64, exportTexture.Width == exportTexture.Height ? 64 : 32), [exportTexture]);
Dictionary<string, Outline> outliners = new Dictionary<string, Outline>(5);
List<Element> elements = new List<Element>(modelInfo.AdditionalBoxes.Count);
List<Element> elements = new List<Element>(modelInfo.Model.AdditionalBoxes.Count);
Dictionary<string, SkinPartOffset> offsetLookUp = new Dictionary<string, SkinPartOffset>(5);
@@ -185,7 +186,7 @@ namespace PckStudio.Internal
{
string offsetType = box.IsOverlayPart() ? box.GetBaseType() : box.Type;
Vector3 offset = GetOffsetForPart(offsetType, ref offsetLookUp, modelInfo.PartOffsets);
Vector3 offset = GetOffsetForPart(offsetType, ref offsetLookUp, modelInfo.Model.PartOffsets);
if (!outliners.ContainsKey(offsetType))
{
outliners.Add(offsetType, new Outline(offsetType)
@@ -203,9 +204,9 @@ namespace PckStudio.Internal
outliners[offsetType].Children.Add(element.Uuid);
}
ANIM2BOX(modelInfo.ANIM, AddElement);
ANIM2BOX(modelInfo.Anim, AddElement);
foreach (SkinBOX box in modelInfo.AdditionalBoxes)
foreach (SkinBOX box in modelInfo.Model.AdditionalBoxes)
{
AddElement(box);
}
@@ -272,19 +273,15 @@ namespace PckStudio.Internal
(IEnumerable<SkinBOX> boxes, IEnumerable<SkinPartOffset> partOffsets) = LoadGeometry(geometry);
SkinModelInfo modelInfo = CreateSkinModelInfo(boxes, partOffsets);
Image texture = null;
string texturePath = Path.Combine(Path.GetDirectoryName(filepath), Path.GetFileNameWithoutExtension(filepath)) + ".png";
if (File.Exists(texturePath))
{
modelInfo.Texture = Image.FromFile(texturePath).ReleaseFromFile();
modelInfo.Texture = SwapBoxBottomTexture(modelInfo);
texture = Image.FromFile(texturePath).ReleaseFromFile();
texture = SwapBoxBottomTexture(texture, boxes);
}
if (geometry.Description?.TextureSize.Width == geometry.Description?.TextureSize.Height)
modelInfo.ANIM = modelInfo.ANIM.SetFlag(SkinAnimFlag.RESOLUTION_64x64, true);
return modelInfo;
return CreateSkinModelInfo(texture, boxes, partOffsets);
}
private static (IEnumerable<SkinBOX> boxes, IEnumerable<SkinPartOffset> partOffsets) LoadGeometry(Geometry geometry)
@@ -327,7 +324,7 @@ namespace PckStudio.Internal
{
string offsetType = box.IsOverlayPart() ? box.GetBaseType() : box.Type;
Vector3 offset = GetOffsetForPart(offsetType, ref offsetLookUp, modelInfo.PartOffsets);
Vector3 offset = GetOffsetForPart(offsetType, ref offsetLookUp, modelInfo.Model.PartOffsets);
if (!bones.ContainsKey(offsetType))
{
@@ -351,9 +348,9 @@ namespace PckStudio.Internal
});
}
ANIM2BOX(modelInfo.ANIM, AddBone);
ANIM2BOX(modelInfo.Anim, AddBone);
foreach (SkinBOX box in modelInfo.AdditionalBoxes)
foreach (SkinBOX box in modelInfo.Model.AdditionalBoxes)
{
AddBone(box);
}
@@ -497,7 +494,12 @@ namespace PckStudio.Internal
private static Image SwapBoxBottomTexture(SkinModelInfo modelInfo)
{
return SwapTextureAreas(modelInfo.Texture, modelInfo.AdditionalBoxes.Where(box => !(box.Size == Vector3.One || box.Size == Vector3.Zero)).Select(box =>
return SwapBoxBottomTexture(modelInfo.Texture, modelInfo.Model.AdditionalBoxes);
}
private static Image SwapBoxBottomTexture(Image texture, IEnumerable<SkinBOX> boxes)
{
return SwapTextureAreas(texture, boxes.Where(box => !(box.Size == Vector3.One || box.Size == Vector3.Zero)).Select(box =>
{
var imgPos = Point.Truncate(new PointF(box.UV.X + box.Size.X + box.Size.Z, box.UV.Y));
var area = new RectangleF(imgPos, Size.Truncate(new SizeF(box.Size.X, box.Size.Z)));

View File

@@ -659,7 +659,7 @@
<None Include="Resources\atlases\moonPhaseData.json" />
<None Include="Resources\atlases\paintingData.json" />
<None Include="Resources\atlases\particleData.json" />
<None Include="Resources\model\defaultModels.json" />
<None Include="Resources\model\defaultModels.json" />
<None Include="Resources\model\modelMetaData.json" />
<None Include="Resources\shader\framebufferFragmentShader.glsl" />
<None Include="Resources\shader\framebufferVertexShader.glsl" />