diff --git a/CM3D2.Serialization/Files/PMat.cs b/CM3D2.Serialization/Files/PMat.cs new file mode 100644 index 0000000..6e15a63 --- /dev/null +++ b/CM3D2.Serialization/Files/PMat.cs @@ -0,0 +1,52 @@ +using System; + +namespace CM3D2.Serialization.Files; + +public class PMat : ICM3D2Serializable, ISummarizable +{ + public readonly string signature = "CM3D2_PMATERIAL"; + //Unsure, unused + public int version; + + /// + /// This is the hash of the corresponding mate file name . + /// + /// Shouldn't be confused with , which is a copy of the mate file name, not the actual usage. + public int hash; + /// + /// The name of the corresponding . + /// + public string materialName; + public float renderQueue; + //Unused + public string shader; + + public void WriteWith(ICM3D2Writer writer) + { + writer.Write(signature); + + writer.Write(version); + writer.Write(hash); + writer.Write(materialName); + writer.Write(renderQueue); + writer.Write(shader); + } + + public void ReadWith(ICM3D2Reader reader) + { + reader.Read(out string temp_signature); + if (temp_signature != signature) + throw new FormatException($"Expected {nameof(signature)} \"{signature}\" but instead found \"{temp_signature}\""); + + reader.Read(out version); + reader.Read(out hash); + reader.Read(out materialName); + reader.Read(out renderQueue); + reader.Read(out shader); + } + + public string Summarize() + { + return $"{{ {signature} v{version} \"{hash}\" {materialName} {renderQueue} {shader}}}"; + } +} \ No newline at end of file diff --git a/CM3D2.Serialization/Files/Tex.cs b/CM3D2.Serialization/Files/Tex.cs new file mode 100644 index 0000000..bd13379 --- /dev/null +++ b/CM3D2.Serialization/Files/Tex.cs @@ -0,0 +1,137 @@ +using CM3D2.Serialization.Collections; +using CM3D2.Serialization.Types; +using System; +using System.CodeDom; + +namespace CM3D2.Serialization.Files; + +public class Tex : ICM3D2Serializable +{ + public readonly string signature = "CM3D2_TEX"; + + public int version; + + public string unknown = string.Empty; + + [FileVersionConstraint(1011)] + public int uvRectCount; + + [FileVersionConstraint(1011)] + [LengthDefinedBy(nameof(uvRectCount))] + public LengthDefinedArray uvRects = new(); + + [FileVersionConstraint(1010)] + public int width = -1; + + [FileVersionConstraint(1010)] + public int height = -1; + + [FileVersionConstraint(1010)] + public int format = -1; + + public int imageDataSize; + + [LengthDefinedBy(nameof(imageDataSize))] + //Typically you'll want to pass the results of EncodeToPNG here and set format to ARGB32. + public LengthDefinedArray imageData = new(); + + public void WriteWith(ICM3D2Writer writer) + { + if (width >= 0 || height >= 0 || format >= 0) + { + version = uvRectCount >= 0 ? 1011 : 1010; + + if (width <= -1) + { + throw new InvalidOperationException("Format or Height is set but width is not"); + } + if (height <= -1) + { + throw new InvalidOperationException("Format or Width is set but height is not"); + } + if (format <= -1) + { + throw new InvalidOperationException("Width or Height is set but format is not"); + } + } + else + { + version = 1000; + + if (uvRectCount >= 0) + { + throw new InvalidOperationException("uvRectCount is set but width, height, and format are not defined."); + } + if (imageDataSize < 24) + { + throw new InvalidOperationException("imageDataSize is less than 24 bytes, which is not valid for version 1000."); + } + } + + writer.Write(signature); + writer.Write(version); + writer.Write(unknown); + + if (version >= 1011) + { + writer.Write(uvRectCount); + uvRects.ValidateLength(uvRectCount, "uvRects", "uvRectCount"); + writer.Write(uvRects); + } + + if (version >= 1010) + { + writer.Write(width); + writer.Write(height); + writer.Write(format); + } + + writer.Write(imageDataSize); + imageData.ValidateLength(imageDataSize, "imageData", "imageDataSize"); + writer.Write(imageData); + } + + public void ReadWith(ICM3D2Reader reader) + { + reader.Read(out var text); + if (text != signature) + { + throw new FormatException(string.Concat("Expected signature \"", signature, "\" but instead found \"", text, "\"")); + } + + reader.Read(out version); + reader.Read(out unknown); + + if (version >= 1011) + { + reader.Read(out uvRectCount); + uvRects.SetLength(uvRectCount); + reader.Read(ref uvRects); + } + + if (version >= 1010) + { + reader.Read(out width); + reader.Read(out height); + reader.Read(out format); + } + + reader.Read(out imageDataSize); + imageData.SetLength(imageDataSize); + reader.Read(ref imageData); + + if (version == 1000) + { + if (imageData.Length >= 24) + { + width = (imageData[16] << 24) | (imageData[17] << 16) | (imageData[18] << 8) | imageData[19]; + height = (imageData[20] << 24) | (imageData[21] << 16) | (imageData[22] << 8) | imageData[23]; + format = 5; + } + else + { + throw new FormatException("imageData does not contain enough data to extract width and height for version 1000."); + } + } + } +} \ No newline at end of file diff --git a/CM3D2.Serialization/Types/Material.cs b/CM3D2.Serialization/Types/Material.cs index 3d82c8a..8c63b27 100644 --- a/CM3D2.Serialization/Types/Material.cs +++ b/CM3D2.Serialization/Types/Material.cs @@ -1,4 +1,5 @@ -using System; +using CM3D2.Serialization.Collections; +using System; using System.Collections.Generic; using System.Text; @@ -154,6 +155,49 @@ protected override void WriteWith(ICM3D2Writer writer) } } + public class KeywordsProperty : Property + { + public static readonly string Type = "keyword"; + public override string type => Type; + + public int keywordCount; + + [LengthDefinedBy(nameof(keywordCount))] + public LengthDefinedList keywords; + + protected override void ReadWith(ICM3D2Reader reader) + { + reader.Read(out keywordCount); + keywords.SetLength(keywordCount); + reader.Read(ref keywords); + } + + protected override void WriteWith(ICM3D2Writer writer) + { + keywordCount = keywords.Count; + writer.Write(keywordCount); + keywords.ValidateLength(keywordCount, nameof(keywords), nameof(keywordCount)); + writer.Write(keywords); + } + + public struct KeywordProperty : ICM3D2Serializable + { + public string keyword; + public bool active; + public void WriteWith(ICM3D2Writer writer) + { + writer.Write(keyword); + writer.Write(active); + } + + public void ReadWith(ICM3D2Reader reader) + { + reader.Read(out keyword); + reader.Read(out active); + } + } + } + public readonly string endTag = "end"; void ICM3D2Serializable.ReadWith(ICM3D2Reader reader) @@ -187,6 +231,11 @@ void ICM3D2Serializable.ReadWith(ICM3D2Reader reader) reader.Read(out FProperty newProp); prop = newProp; } + else if (propType == KeywordsProperty.Type) + { + reader.Read(out KeywordsProperty newProp); + prop = newProp; + } #pragma warning restore CM3D2Serialization031 // Field Read / Write out of Order else if (propType == "end") {