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")
{