mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/PCK-Studio.git
synced 2026-05-25 07:35:48 +00:00
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:
@@ -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");
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,5 @@
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Theme { get; set; }
|
||||
public int Id { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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" />
|
||||
|
||||
Reference in New Issue
Block a user