mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/PCK-Studio.git
synced 2026-09-22 02:23:13 +00:00
Created PSM Version 2
This commit is contained in:
@@ -185,7 +185,7 @@ namespace PckStudio.Forms.Editor
|
||||
}
|
||||
}
|
||||
|
||||
private void buttonDone_Click(object sender, EventArgs e)
|
||||
private void prepareSkinForExport()
|
||||
{
|
||||
EditorValue.Model.AdditionalBoxes.Clear();
|
||||
EditorValue.Model.AdditionalBoxes.AddRange(renderer3D1.ModelData);
|
||||
@@ -194,6 +194,11 @@ namespace PckStudio.Forms.Editor
|
||||
// just in case they're not the same instance
|
||||
EditorValue.Anim = renderer3D1.ANIM;
|
||||
EditorValue.GameFlags = _gameFlags;
|
||||
}
|
||||
|
||||
private void buttonDone_Click(object sender, EventArgs e)
|
||||
{
|
||||
prepareSkinForExport();
|
||||
DialogResult = DialogResult.OK;
|
||||
Save();
|
||||
}
|
||||
@@ -205,8 +210,11 @@ namespace PckStudio.Forms.Editor
|
||||
saveFileDialog.Filter = SkinModelImporter.Default.SupportedModelFileFormatsFilter;
|
||||
saveFileDialog.FileName = EditorValue.MetaData.Name.TrimEnd(new char[] { '\n', '\r' }).Replace(' ', '_');
|
||||
if (saveFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
prepareSkinForExport();
|
||||
SkinModelImporter.Default.Export(saveFileDialog.FileName, EditorValue.GetModelInfo());
|
||||
}
|
||||
}
|
||||
|
||||
private void importSkinButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
@@ -434,6 +442,7 @@ namespace PckStudio.Forms.Editor
|
||||
{
|
||||
Image templateTexture = Resources.classic_template;
|
||||
SkinAnimMask templateAnimMask = SkinAnimMask.MODERN_WIDE_MODEL;
|
||||
SkinGameFlagsMask templateSkinFlagsMask = SkinGameFlagsMask.HUMAN_SKIN;
|
||||
|
||||
SaveFileDialog saveFileDialog = new SaveFileDialog();
|
||||
saveFileDialog.Title = "Save Template Model";
|
||||
@@ -441,7 +450,7 @@ namespace PckStudio.Forms.Editor
|
||||
saveFileDialog.FileName = SanitizeModelFilename(EditorValue.MetaData.Name);
|
||||
if (saveFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
SkinModelInfo modelInfo = new SkinModelInfo(templateTexture, templateAnimMask, new SkinModel());
|
||||
SkinModelInfo modelInfo = new SkinModelInfo(templateTexture, templateAnimMask, templateSkinFlagsMask, new SkinModel());
|
||||
SkinModelImporter.Default.Export(saveFileDialog.FileName, modelInfo);
|
||||
}
|
||||
}
|
||||
@@ -462,6 +471,7 @@ namespace PckStudio.Forms.Editor
|
||||
{
|
||||
renderer3D1.ANIM = skinAdjustmentsEditorControl1.GetAnim();
|
||||
_gameFlags = skinAdjustmentsEditorControl1.GetGameFlags();
|
||||
EditorValue.GameFlags = _gameFlags;
|
||||
}
|
||||
|
||||
private void armorButtonControl_Click(object sender, EventArgs e)
|
||||
|
||||
@@ -11,12 +11,13 @@ namespace PckStudio.ModelSupport.Extension
|
||||
{
|
||||
public static class SkinExtension
|
||||
{
|
||||
public static SkinModelInfo GetModelInfo(this Skin skin) => new SkinModelInfo(skin.Texture, skin.Anim, skin.Model);
|
||||
public static SkinModelInfo GetModelInfo(this Skin skin) => new SkinModelInfo(skin.Texture, skin.Anim, skin.GameFlags, skin.Model);
|
||||
|
||||
public static void SetModelInfo(this Skin skin, SkinModelInfo modelInfo)
|
||||
{
|
||||
skin.Texture = modelInfo.Texture;
|
||||
skin.Anim = modelInfo.Anim;
|
||||
skin.GameFlags = modelInfo.SkinFlags;
|
||||
skin.Model = modelInfo.Model;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ using PckStudio.Core.Skin;
|
||||
|
||||
namespace PckStudio.ModelSupport.Internal.Format
|
||||
{
|
||||
/*
|
||||
/*
|
||||
* VERSION 1
|
||||
Magic - 3 bytes("psm")
|
||||
Version - 1 byte [u8]
|
||||
Anim - 4 bytes[int32]
|
||||
@@ -19,18 +20,42 @@ namespace PckStudio.ModelSupport.Internal.Format
|
||||
Size-Z - 4 bytes (float32)
|
||||
MirrorAndUvX - 1 bit flag 7 bits uv.x value(0-64) (s8)
|
||||
HideWithArmorAndUvY - 1 bit flag 7 bits uv.y value(0-64) (s8)
|
||||
inflation/scale value - 4 bytes (float32)
|
||||
Inflation - 4 bytes (float32)
|
||||
}
|
||||
NumberOfOffsets - 4 bytes[int32]
|
||||
{
|
||||
offset part - 1 byte
|
||||
vertical offset - 4 bytes[float]
|
||||
}
|
||||
*/
|
||||
|
||||
* VERSION 2
|
||||
Magic - 3 bytes("psm")
|
||||
Version - 1 byte [u8]
|
||||
Anim - 4 bytes [int32]
|
||||
Game Flags - 1 byte [u8]
|
||||
NumberOfParts - 4 bytes[int32]
|
||||
{
|
||||
ArmorMaskAndParParent - 3 bits Armor Mask 5 bits (Box Parent Type)
|
||||
Position-X - 4 bytes (float32)
|
||||
Position-Y - 4 bytes (float32)
|
||||
Position-Z - 4 bytes (float32)
|
||||
Size-X - 4 bytes (float32)
|
||||
Size-Y - 4 bytes (float32)
|
||||
Size-Z - 4 bytes (float32)
|
||||
MirrorAndUvX - 1 bit flag 7 bits uv.x value(0-64) (s8)
|
||||
ArmorMaskingAndUvY - 1 bit Helmet Mask 7 bits uv.y value(0-64) (s8)
|
||||
Inflation - 4 bytes (float32)
|
||||
}
|
||||
NumberOfOffsets - 4 bytes[int32]
|
||||
{
|
||||
offset part - 1 byte
|
||||
vertical offset - 4 bytes[float]
|
||||
}
|
||||
*/
|
||||
public sealed class PSMFile
|
||||
{
|
||||
internal static readonly string HEADER_MAGIC = "psm";
|
||||
internal const byte CurrentVersion = 1;
|
||||
internal const byte CurrentVersion = 2;
|
||||
|
||||
public readonly byte Version;
|
||||
|
||||
@@ -39,13 +64,15 @@ namespace PckStudio.ModelSupport.Internal.Format
|
||||
Version = version;
|
||||
}
|
||||
|
||||
internal PSMFile(byte version, SkinANIM skinANIM)
|
||||
internal PSMFile(byte version, SkinANIM skinANIM, SkinGameFlags skinFlags)
|
||||
: this(version)
|
||||
{
|
||||
SkinANIM = skinANIM;
|
||||
SkinFlags = skinFlags;
|
||||
}
|
||||
|
||||
public SkinANIM SkinANIM { get; private set; }
|
||||
public SkinGameFlags SkinFlags { get; private set; }
|
||||
|
||||
public readonly List<SkinBOX> Parts = new List<SkinBOX>();
|
||||
public readonly List<SkinPartOffset> Offsets = new List<SkinPartOffset>();
|
||||
@@ -82,5 +109,22 @@ namespace PckStudio.ModelSupport.Internal.Format
|
||||
ARM1 = 3,
|
||||
LEG0 = 4,
|
||||
LEG1 = 5,
|
||||
HEADWEAR = 6,
|
||||
JACKET = 7,
|
||||
SLEEVE0 = 8,
|
||||
SLEEVE1 = 9,
|
||||
PANTS0 = 10,
|
||||
PANTS1 = 11,
|
||||
WAIST = 12,
|
||||
LEGGING0 = 13,
|
||||
LEGGING1 = 14,
|
||||
SOCK0 = 15,
|
||||
SOCK1 = 16,
|
||||
BOOT0 = 17,
|
||||
BOOT1 = 18,
|
||||
ARMAMOR0 = 19,
|
||||
ARMAMOR1 = 20,
|
||||
BODYARMOR = 21,
|
||||
BELT = 22,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ using OMI.Workers;
|
||||
using PckStudio.Core.FileFormats;
|
||||
using PckStudio.Core;
|
||||
using PckStudio.Core.Skin;
|
||||
using System;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
|
||||
namespace PckStudio.ModelSupport.Internal.Format
|
||||
{
|
||||
@@ -35,33 +37,49 @@ namespace PckStudio.ModelSupport.Internal.Format
|
||||
}
|
||||
|
||||
byte version = reader.ReadByte();
|
||||
if (version < 1 || version > 1)
|
||||
if (version < 1 || version > PSMFile.CurrentVersion)
|
||||
{
|
||||
Trace.TraceError("PSMFileReader.FromStream - Failed to load csmb.\n\tReason: Unsupported version.");
|
||||
return new PSMFile(byte.MaxValue);
|
||||
}
|
||||
|
||||
var skinANIM = SkinANIM.FromValue(reader.ReadInt32());
|
||||
PSMFile csmbFile = new PSMFile(version, skinANIM);
|
||||
var skinFlags = SkinGameFlags.Empty;
|
||||
|
||||
if(version > 1)
|
||||
skinFlags = SkinGameFlags.FromValue(reader.ReadByte());
|
||||
|
||||
PSMFile psmFile = new PSMFile(version, skinANIM, skinFlags);
|
||||
int numOfParts = reader.ReadInt32();
|
||||
for (int i = 0; i < numOfParts; i++)
|
||||
{
|
||||
SkinBOX part = ReadPart(reader);
|
||||
csmbFile.Parts.Add(part);
|
||||
SkinBOX part = ReadPart(reader, version);
|
||||
psmFile.Parts.Add(part);
|
||||
}
|
||||
int numOfOffsets = reader.ReadInt32();
|
||||
for (int i = 0; i < numOfOffsets; i++)
|
||||
{
|
||||
SkinPartOffset offset = ReadOffset(reader);
|
||||
csmbFile.Offsets.Add(offset);
|
||||
psmFile.Offsets.Add(offset);
|
||||
}
|
||||
|
||||
return csmbFile;
|
||||
return psmFile;
|
||||
}
|
||||
|
||||
private SkinBOX ReadPart(EndiannessAwareBinaryReader reader)
|
||||
private SkinBOX ReadPart(EndiannessAwareBinaryReader reader, int version)
|
||||
{
|
||||
string type = GetParentType((PSMParentType)reader.ReadByte());
|
||||
int armorMask = 0;
|
||||
string type = "";
|
||||
if(version == 1)
|
||||
type = GetParentType((PSMParentType)reader.ReadByte());
|
||||
else
|
||||
{
|
||||
byte armorMaskAndParentType = reader.ReadByte();
|
||||
|
||||
type = GetParentType((PSMParentType)(armorMaskAndParentType & 0x1F)); // get first 5 bits
|
||||
armorMask = (armorMaskAndParentType & 0xE0) >> 5; // get last 3 bits
|
||||
}
|
||||
|
||||
float posX = reader.ReadSingle();
|
||||
float posY = reader.ReadSingle();
|
||||
float posZ = reader.ReadSingle();
|
||||
@@ -73,9 +91,9 @@ namespace PckStudio.ModelSupport.Internal.Format
|
||||
int uvX = mirrorAndUvX & 0x7f;
|
||||
int uvY = hideWithArmorAndUvY & 0x7f;
|
||||
bool mirror = (mirrorAndUvX & 0x80) != 0;
|
||||
int hideWithArmor = (hideWithArmorAndUvY & 0x80);
|
||||
armorMask = (armorMask << 1) | ((hideWithArmorAndUvY >> 7) & 1);
|
||||
float scale = reader.ReadSingle();
|
||||
return new SkinBOX(type, new System.Numerics.Vector3(posX, posY, posZ), new System.Numerics.Vector3(sizeX, sizeY, sizeZ), new System.Numerics.Vector2(uvX, uvY), hideWithArmor, mirror, scale);
|
||||
return new SkinBOX(type, new System.Numerics.Vector3(posX, posY, posZ), new System.Numerics.Vector3(sizeX, sizeY, sizeZ), new System.Numerics.Vector2(uvX, uvY), armorMask, mirror, scale);
|
||||
}
|
||||
|
||||
private SkinPartOffset ReadOffset(EndiannessAwareBinaryReader reader)
|
||||
@@ -101,6 +119,40 @@ namespace PckStudio.ModelSupport.Internal.Format
|
||||
return "LEG0";
|
||||
case PSMParentType.LEG1:
|
||||
return "LEG1";
|
||||
case PSMParentType.HEADWEAR:
|
||||
return "HEADWEAR";
|
||||
case PSMParentType.JACKET:
|
||||
return "JACKET";
|
||||
case PSMParentType.SLEEVE0:
|
||||
return "SLEEVE0";
|
||||
case PSMParentType.SLEEVE1:
|
||||
return "SLEEVE1";
|
||||
case PSMParentType.PANTS0:
|
||||
return "PANTS0";
|
||||
case PSMParentType.PANTS1:
|
||||
return "PANTS1";
|
||||
case PSMParentType.WAIST:
|
||||
return "WAIST";
|
||||
case PSMParentType.LEGGING0:
|
||||
return "LEGGING0";
|
||||
case PSMParentType.LEGGING1:
|
||||
return "LEGGING1";
|
||||
case PSMParentType.SOCK0:
|
||||
return "SOCK0";
|
||||
case PSMParentType.SOCK1:
|
||||
return "SOCK1";
|
||||
case PSMParentType.BOOT0:
|
||||
return "BOOT0";
|
||||
case PSMParentType.BOOT1:
|
||||
return "BOOT1";
|
||||
case PSMParentType.ARMAMOR0:
|
||||
return "ARMARMOR0";
|
||||
case PSMParentType.ARMAMOR1:
|
||||
return "ARMARMOR1";
|
||||
case PSMParentType.BODYARMOR:
|
||||
return "BODYARMOR";
|
||||
case PSMParentType.BELT:
|
||||
return "BELT";
|
||||
default:
|
||||
throw new InvalidDataException(type.ToString());
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using OMI;
|
||||
using System;
|
||||
using OpenTK;
|
||||
using PckStudio.Core.Skin;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace PckStudio.ModelSupport.Internal.Format
|
||||
{
|
||||
@@ -33,6 +34,7 @@ namespace PckStudio.ModelSupport.Internal.Format
|
||||
writer.WriteString(PSMFile.HEADER_MAGIC);
|
||||
writer.Write(_PSM.Version);
|
||||
writer.Write(_PSM.SkinANIM.ToValue());
|
||||
writer.Write((byte)_PSM.SkinFlags.ToValue());
|
||||
writer.Write(_PSM.Parts.Count);
|
||||
foreach (SkinBOX part in _PSM.Parts)
|
||||
{
|
||||
@@ -49,7 +51,11 @@ namespace PckStudio.ModelSupport.Internal.Format
|
||||
|
||||
private void WritePart(EndiannessAwareBinaryWriter writer, SkinBOX part)
|
||||
{
|
||||
writer.Write((byte)GetParentPart(part.Type));
|
||||
byte armorMask = (byte)((part.ArmorMaskFlags.ToValue() >> 1) & 0x07);
|
||||
byte parentType = (byte)((int)GetParentPart(part.Type) & 0x1F);
|
||||
|
||||
byte armorMaskAndParentType = (byte)((armorMask << 5) | parentType);
|
||||
writer.Write(armorMaskAndParentType);
|
||||
writer.Write(part.Pos.X);
|
||||
writer.Write(part.Pos.Y);
|
||||
writer.Write(part.Pos.Z);
|
||||
@@ -60,9 +66,9 @@ namespace PckStudio.ModelSupport.Internal.Format
|
||||
byte uvX = (byte)MathHelper.Clamp((int)part.UV.X, 0, 64);
|
||||
byte uvY = (byte)MathHelper.Clamp((int)part.UV.Y, 0, 64);
|
||||
byte mirrorAndUvX = (byte)(Convert.ToByte(part.Mirror) << 7 | uvX);
|
||||
byte hideWithArmorAndUvY = (byte)(Convert.ToByte(part.ArmorMaskFlags.ToValue()) << 7 | uvY);
|
||||
byte helmetMaskAndUvY = (byte)(Convert.ToByte(part.ArmorMaskFlags.ToValue()) << 7 | uvY);
|
||||
writer.Write(mirrorAndUvX);
|
||||
writer.Write(hideWithArmorAndUvY);
|
||||
writer.Write(helmetMaskAndUvY);
|
||||
writer.Write(part.Scale);
|
||||
}
|
||||
|
||||
@@ -82,6 +88,40 @@ namespace PckStudio.ModelSupport.Internal.Format
|
||||
return PSMParentType.LEG0;
|
||||
case "LEG1":
|
||||
return PSMParentType.LEG1;
|
||||
case "HEADWEAR":
|
||||
return PSMParentType.HEADWEAR;
|
||||
case "JACKET":
|
||||
return PSMParentType.JACKET;
|
||||
case "SLEEVE0":
|
||||
return PSMParentType.SLEEVE0;
|
||||
case "SLEEVE1":
|
||||
return PSMParentType.SLEEVE1;
|
||||
case "PANTS0":
|
||||
return PSMParentType.PANTS0;
|
||||
case "PANTS1":
|
||||
return PSMParentType.PANTS1;
|
||||
case "WAIST":
|
||||
return PSMParentType.WAIST;
|
||||
case "LEGGING0":
|
||||
return PSMParentType.LEGGING0;
|
||||
case "LEGGING1":
|
||||
return PSMParentType.LEGGING1;
|
||||
case "SOCK0":
|
||||
return PSMParentType.SOCK0;
|
||||
case "SOCK1":
|
||||
return PSMParentType.SOCK1;
|
||||
case "BOOT0":
|
||||
return PSMParentType.BOOT0;
|
||||
case "BOOT1":
|
||||
return PSMParentType.BOOT1;
|
||||
case "ARMARMOR0":
|
||||
return PSMParentType.ARMAMOR0;
|
||||
case "ARMARMOR1":
|
||||
return PSMParentType.ARMAMOR1;
|
||||
case "BODYARMOR":
|
||||
return PSMParentType.BODYARMOR;
|
||||
case "BELT":
|
||||
return PSMParentType.BELT;
|
||||
default:
|
||||
throw new InvalidDataException(type);
|
||||
}
|
||||
|
||||
@@ -51,13 +51,13 @@ namespace PckStudio.ModelSupport
|
||||
internal static SkinModelInfo ImportPsm(string filepath)
|
||||
{
|
||||
var reader = new PSMFileReader();
|
||||
PSMFile csmbFile = reader.FromFile(filepath);
|
||||
return new SkinModelInfo(null, csmbFile.SkinANIM, new(csmbFile.Parts, csmbFile.Offsets));
|
||||
PSMFile psmFile = reader.FromFile(filepath);
|
||||
return new SkinModelInfo(null, psmFile.SkinANIM, psmFile.SkinFlags, new(psmFile.Parts, psmFile.Offsets));
|
||||
}
|
||||
|
||||
internal static void ExportPsm(string filepath, SkinModelInfo modelInfo)
|
||||
{
|
||||
PSMFile psmFile = new PSMFile(PSMFile.CurrentVersion, modelInfo.Anim);
|
||||
PSMFile psmFile = new PSMFile(PSMFile.CurrentVersion, modelInfo.Anim, modelInfo.SkinFlags);
|
||||
psmFile.Parts.AddRange(modelInfo.Model.AdditionalBoxes);
|
||||
psmFile.Offsets.AddRange(modelInfo.Model.PartOffsets);
|
||||
var writer = new PSMFileWriter(psmFile);
|
||||
@@ -143,7 +143,7 @@ namespace PckStudio.ModelSupport
|
||||
if (mask != SkinAnimMask.NONE)
|
||||
skinANIM &= ~mask;
|
||||
|
||||
return new SkinModelInfo(texture, skinANIM, skinModel);
|
||||
return new SkinModelInfo(texture, skinANIM, SkinGameFlagsMask.HUMAN_SKIN, skinModel);
|
||||
}
|
||||
|
||||
private static IEnumerable<SkinBOX> ReadOutliner(string parentName, JArray oulineChildren, IReadOnlyCollection<Element> elements)
|
||||
|
||||
@@ -12,12 +12,14 @@ namespace PckStudio.ModelSupport
|
||||
{
|
||||
public SkinModel Model { get; }
|
||||
public SkinANIM Anim { get; }
|
||||
public SkinGameFlags SkinFlags { get; }
|
||||
public Image Texture { get; }
|
||||
|
||||
public SkinModelInfo(Image texture, SkinANIM anim, SkinModel model)
|
||||
public SkinModelInfo(Image texture, SkinANIM anim, SkinGameFlags skinFlags, SkinModel model)
|
||||
{
|
||||
Texture = texture;
|
||||
Anim = anim;
|
||||
SkinFlags = skinFlags;
|
||||
Model = model;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user