Skip to content

Commit c05c94a

Browse files
committed
M2: Add PCOL read/write chunk support
1 parent 94b616c commit c05c94a

6 files changed

Lines changed: 204 additions & 8 deletions

File tree

Warcraft.NET/Attribute/AutoDocAttributes.cs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,26 @@ internal enum AutoDocChunkVersion
1212
SL = 16,
1313
DF = 32,
1414
TWW = 64,
15+
MD = 128,
1516
}
1617

1718
internal static class AutoDocChunkVersionHelper
1819
{
19-
internal const AutoDocChunkVersion VersionAll = AutoDocChunkVersion.LK | AutoDocChunkVersion.WoD | AutoDocChunkVersion.Legion | AutoDocChunkVersion.BfA | AutoDocChunkVersion.SL | AutoDocChunkVersion.DF | AutoDocChunkVersion.TWW;
20-
internal const AutoDocChunkVersion VersionAfterLK = AutoDocChunkVersion.WoD | AutoDocChunkVersion.Legion | AutoDocChunkVersion.BfA | AutoDocChunkVersion.SL | AutoDocChunkVersion.DF | AutoDocChunkVersion.TWW;
21-
internal const AutoDocChunkVersion VersionAfterWoD = AutoDocChunkVersion.Legion | AutoDocChunkVersion.BfA | AutoDocChunkVersion.SL | AutoDocChunkVersion.DF | AutoDocChunkVersion.TWW;
22-
internal const AutoDocChunkVersion VersionAfterLegion = AutoDocChunkVersion.BfA | AutoDocChunkVersion.SL | AutoDocChunkVersion.DF | AutoDocChunkVersion.TWW;
23-
internal const AutoDocChunkVersion VersionAfterBfA = AutoDocChunkVersion.SL | AutoDocChunkVersion.DF | AutoDocChunkVersion.TWW;
24-
internal const AutoDocChunkVersion VersionAfterSL = AutoDocChunkVersion.DF | AutoDocChunkVersion.TWW;
25-
internal const AutoDocChunkVersion VersionAfterDF = AutoDocChunkVersion.TWW;
20+
internal const AutoDocChunkVersion VersionAll = AutoDocChunkVersion.LK | AutoDocChunkVersion.WoD | AutoDocChunkVersion.Legion | AutoDocChunkVersion.BfA | AutoDocChunkVersion.SL | AutoDocChunkVersion.DF | AutoDocChunkVersion.TWW | AutoDocChunkVersion.MD;
21+
internal const AutoDocChunkVersion VersionAfterLK = AutoDocChunkVersion.WoD | AutoDocChunkVersion.Legion | AutoDocChunkVersion.BfA | AutoDocChunkVersion.SL | AutoDocChunkVersion.DF | AutoDocChunkVersion.TWW | AutoDocChunkVersion.MD;
22+
internal const AutoDocChunkVersion VersionAfterWoD = AutoDocChunkVersion.Legion | AutoDocChunkVersion.BfA | AutoDocChunkVersion.SL | AutoDocChunkVersion.DF | AutoDocChunkVersion.TWW | AutoDocChunkVersion.MD;
23+
internal const AutoDocChunkVersion VersionAfterLegion = AutoDocChunkVersion.BfA | AutoDocChunkVersion.SL | AutoDocChunkVersion.DF | AutoDocChunkVersion.TWW | AutoDocChunkVersion.MD;
24+
internal const AutoDocChunkVersion VersionAfterBfA = AutoDocChunkVersion.SL | AutoDocChunkVersion.DF | AutoDocChunkVersion.TWW | AutoDocChunkVersion.MD;
25+
internal const AutoDocChunkVersion VersionAfterSL = AutoDocChunkVersion.DF | AutoDocChunkVersion.TWW | AutoDocChunkVersion.MD;
26+
internal const AutoDocChunkVersion VersionAfterDF = AutoDocChunkVersion.TWW | AutoDocChunkVersion.MD;
27+
internal const AutoDocChunkVersion VersionAfterTWW = AutoDocChunkVersion.MD;
2628

2729
internal const AutoDocChunkVersion VersionBeforeLegion = AutoDocChunkVersion.LK | AutoDocChunkVersion.WoD;
2830
internal const AutoDocChunkVersion VersionBeforeBfA = AutoDocChunkVersion.LK | AutoDocChunkVersion.WoD | AutoDocChunkVersion.Legion;
2931
internal const AutoDocChunkVersion VersionBeforeSL = AutoDocChunkVersion.LK | AutoDocChunkVersion.WoD | AutoDocChunkVersion.Legion | AutoDocChunkVersion.BfA;
3032
internal const AutoDocChunkVersion VersionBeforeDF = AutoDocChunkVersion.LK | AutoDocChunkVersion.WoD | AutoDocChunkVersion.Legion | AutoDocChunkVersion.BfA | AutoDocChunkVersion.SL;
3133
internal const AutoDocChunkVersion VersionBeforeTWW = AutoDocChunkVersion.LK | AutoDocChunkVersion.WoD | AutoDocChunkVersion.Legion | AutoDocChunkVersion.BfA | AutoDocChunkVersion.SL | AutoDocChunkVersion.DF;
34+
internal const AutoDocChunkVersion VersionBeforeMD = AutoDocChunkVersion.LK | AutoDocChunkVersion.WoD | AutoDocChunkVersion.Legion | AutoDocChunkVersion.BfA | AutoDocChunkVersion.SL | AutoDocChunkVersion.DF | AutoDocChunkVersion.TWW;
3235
}
3336

3437
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]

Warcraft.NET/Extensions/ExtendedIO.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,25 @@ public static T ReadStruct<T>(this BinaryReader reader) where T : struct
396396

397397
return Unsafe.ReadUnaligned<T>(ref result[0]);
398398
}
399+
400+
401+
/// <summary>
402+
/// Read a list of structs
403+
/// </summary>
404+
/// <param name="count">Count of structs to read</param>
405+
/// <param name="offset">Offset to read from</param>
406+
/// <param name="br">The reader.</param>
407+
/// <typeparam name="T">Type of struct to read</typeparam>
408+
public static List<T> ReadStructList<T>(this BinaryReader br, uint count, uint offset) where T : struct
409+
{
410+
br.BaseStream.Position = offset;
411+
List<T> list = new List<T>();
412+
413+
for (var i = 0; i < count; i++)
414+
list.Add(br.ReadStruct<T>());
415+
416+
return list;
417+
}
399418
#endregion
400419

401420
#region Write
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using Warcraft.NET.Files.Interfaces;
2+
3+
namespace Warcraft.NET.Files.M2.Chunks.TWW
4+
{
5+
public class DPIV : IIFFChunk, IBinarySerializable
6+
{
7+
/// <summary>
8+
/// Holds the binary chunk signature.
9+
/// </summary>
10+
public const string Signature = "DPIV";
11+
12+
/// <summary>
13+
/// Gets or sets the DPIV data
14+
/// </summary>
15+
public byte[] Data = new byte[32];
16+
17+
/// <summary>
18+
/// Initializes a new instance of <see cref="DPIV"/>
19+
/// </summary>
20+
public DPIV() { }
21+
22+
/// <summary>
23+
/// Initializes a new instance of <see cref="DPIV"/>
24+
/// </summary>
25+
/// <param name="inData">ExtendedData.</param>
26+
public DPIV(byte[] inData) => LoadBinaryData(inData);
27+
28+
/// <inheritdoc />
29+
public string GetSignature() { return Signature; }
30+
31+
/// <inheritdoc />
32+
public uint GetSize() { return (uint)Serialize().Length; }
33+
34+
/// <inheritdoc />
35+
public void LoadBinaryData(byte[] inData)
36+
{
37+
Data = inData;
38+
}
39+
40+
/// <inheritdoc />
41+
public byte[] Serialize(long offset = 0)
42+
{
43+
return Data;
44+
}
45+
}
46+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using Warcraft.NET.Attribute;
4+
using Warcraft.NET.Extensions;
5+
using Warcraft.NET.Files.Interfaces;
6+
using Warcraft.NET.Files.Structures;
7+
8+
namespace Warcraft.NET.Files.M2.Chunks.TWW
9+
{
10+
[AutoDocChunk(AutoDocChunkVersionHelper.VersionAfterTWW, AutoDocChunkVersionHelper.VersionBeforeMD)]
11+
public class PCOL : IIFFChunk, IBinarySerializable
12+
{
13+
/// <summary>
14+
/// Holds the binary chunk signature.
15+
/// </summary>
16+
public const string Signature = "PCOL";
17+
18+
/// <summary>
19+
/// Gets or sets the vertex positions
20+
/// </summary>
21+
public List<C3Vector> VertexPositions { get; set; }
22+
23+
/// <summary>
24+
/// Gets or sets the face normals
25+
/// </summary>
26+
public List<C3Vector> FaceNormals { get; set; }
27+
28+
/// <summary>
29+
/// Gets or sets the indices
30+
/// </summary>
31+
public List<ushort> Indices { get; set; }
32+
33+
/// <summary>
34+
/// Gets or sets the flags (unknown meaning)
35+
/// </summary>
36+
public List<ushort> Flags { get; set; }
37+
38+
/// <summary>
39+
/// Initializes a new instance of <see cref="PCOL"/>
40+
/// </summary>
41+
public PCOL() { }
42+
43+
/// <summary>
44+
/// Initializes a new instance of <see cref="PCOL"/>
45+
/// </summary>
46+
/// <param name="inData">ExtendedData.</param>
47+
public PCOL(byte[] inData) => LoadBinaryData(inData);
48+
49+
/// <inheritdoc />
50+
public string GetSignature() { return Signature; }
51+
52+
/// <inheritdoc />
53+
public uint GetSize() { return (uint)Serialize().Length; }
54+
55+
/// <inheritdoc />
56+
public void LoadBinaryData(byte[] inData)
57+
{
58+
using (var ms = new MemoryStream(inData))
59+
using (var br = new BinaryReader(ms))
60+
{
61+
var vertexPositionCount = br.ReadUInt32();
62+
var vertexPositionOffset = br.ReadUInt32();
63+
var faceNormalCount = br.ReadUInt32();
64+
var faceNormalOffset = br.ReadUInt32();
65+
var indexCount = br.ReadUInt32();
66+
var indexOffset = br.ReadUInt32();
67+
var flagCount = br.ReadUInt32();
68+
var flagOffset = br.ReadUInt32();
69+
70+
VertexPositions = br.ReadStructList<C3Vector>(vertexPositionCount, vertexPositionOffset);
71+
FaceNormals = br.ReadStructList<C3Vector>(faceNormalCount, faceNormalOffset);
72+
Indices = br.ReadStructList<ushort>(indexCount, indexOffset);
73+
Flags = br.ReadStructList<ushort>(flagCount, flagOffset);
74+
}
75+
}
76+
77+
/// <inheritdoc />
78+
public byte[] Serialize(long offset = 0)
79+
{
80+
using var ms = new MemoryStream();
81+
using (var bw = new BinaryWriter(ms))
82+
{
83+
bw.Write((uint)VertexPositions.Count);
84+
bw.Write((uint)(32)); // vertex positions offset
85+
86+
bw.Write((uint)FaceNormals.Count);
87+
bw.Write((uint)(32 + VertexPositions.Count * sizeof(float) * 3)); // face normals offset
88+
89+
bw.Write((uint)Indices.Count);
90+
bw.Write((uint)(32 + VertexPositions.Count * sizeof(float) * 3 + FaceNormals.Count * sizeof(float) * 3)); // indices offset
91+
92+
bw.Write((uint)Flags.Count);
93+
bw.Write((uint)(32 + VertexPositions.Count * sizeof(float) * 3 + FaceNormals.Count * sizeof(float) * 3 + Indices.Count * sizeof(ushort))); // flags offset
94+
95+
foreach (var vertex in VertexPositions)
96+
bw.WriteStruct(vertex);
97+
98+
foreach (var normal in FaceNormals)
99+
bw.WriteStruct(normal);
100+
101+
foreach (var index in Indices)
102+
bw.Write(index);
103+
104+
foreach (var flag in Flags)
105+
bw.Write(flag);
106+
107+
return ms.ToArray();
108+
}
109+
}
110+
}
111+
}

Warcraft.NET/Files/M2/Flags/MD21Flags.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,11 @@ public enum MD21Flags : uint
116116
/// <summary>
117117
/// Unknown Flag: apparently use 24500 upgraded model format: chunked .anim files, change in the exporter reordering sequence+bone blocks before name
118118
/// </summary>
119-
Unknown200000 = 0x200000
119+
Unknown200000 = 0x200000,
120120

121+
/// <summary>
122+
/// Is a housing furniture model: Seen on 11.1.7+ player housing furniture models
123+
/// </summary>
124+
HousingFurnitrue = 0x40000000
121125
}
122126
}

Warcraft.NET/Files/M2/Model.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Warcraft.NET.Files.M2.Chunks.DF;
55
using Warcraft.NET.Files.M2.Chunks.Legion;
66
using Warcraft.NET.Files.M2.Chunks.SL;
7+
using Warcraft.NET.Files.M2.Chunks.TWW;
78

89
namespace Warcraft.NET.Files.M2
910
{
@@ -172,6 +173,18 @@ public class Model : ChunkedFile
172173
[ChunkOrder(27),ChunkOptional]
173174
public AFRA AFRA { get; set; }
174175

176+
/// <summary>
177+
/// Gets or sets the PCOL
178+
/// </summary>
179+
[ChunkOrder(28), ChunkOptional]
180+
public PCOL PCOL { get; set; }
181+
182+
/// <summary>
183+
/// Gets or sets the DPIV
184+
/// </summary>
185+
[ChunkOrder(29), ChunkOptional]
186+
public DPIV DPIV { get; set; }
187+
175188
/// <summary>
176189
/// Initializes a new instance of the <see cref="Model"/> class.
177190
/// </summary>

0 commit comments

Comments
 (0)