diff --git a/Warcraft.NET/Files/ADT/Terrain/MCNK/SubChunks/MCRD.cs b/Warcraft.NET/Files/ADT/Terrain/MCNK/SubChunks/MCRF.cs similarity index 100% rename from Warcraft.NET/Files/ADT/Terrain/MCNK/SubChunks/MCRD.cs rename to Warcraft.NET/Files/ADT/Terrain/MCNK/SubChunks/MCRF.cs diff --git a/Warcraft.NET/Files/BLP/BLP.cs b/Warcraft.NET/Files/BLP/BLP.cs index f672c4c..9ebecf6 100644 --- a/Warcraft.NET/Files/BLP/BLP.cs +++ b/Warcraft.NET/Files/BLP/BLP.cs @@ -235,7 +235,8 @@ public BLP(Image image, TextureCompressionType compressionType) /// /// Image. /// Only DXT pixel format! - public BLP(Image image, BLPPixelFormat pixelFormat) + /// If set to true, make mipmaps. + public BLP(Image image, BLPPixelFormat pixelFormat, bool makeMipMaps = true) { if (pixelFormat != BLPPixelFormat.DXT1 && pixelFormat != BLPPixelFormat.DXT3 && pixelFormat != BLPPixelFormat.DXT5) throw new ArgumentException("This constructor only support DXT pixel format!"); @@ -256,7 +257,7 @@ public BLP(Image image, BLPPixelFormat pixelFormat) Header.Resolution = new Resolution((uint)image.Width, (uint)image.Height); // It's now time to compress the image - _rawMipMaps = CompressImage(image); + _rawMipMaps = CompressImage(image, makeMipMaps); // Calculate the offsets and sizes var mipOffset = (uint)(Header.GetSize() + (_palette.Count * 4)); @@ -534,7 +535,8 @@ private Image DecompressMipMap(byte[] inData, uint mipLevel) /// /// The compressed image data. /// The image to be compressed. - private List CompressImage(Image inImage) + /// If set to true, make mipmaps. + private List CompressImage(Image inImage, bool makeMipMaps = true) { var mipMaps = new List(); @@ -548,10 +550,13 @@ private List CompressImage(Image inImage) // Add the original image as the first mipmap mipMaps.Add(CompressImage(inImage, 0)); - // Then, compress the image N amount of times into mipmaps - for (uint i = 1; i < GetNumReasonableMipMapLevels(); ++i) + // Then, if needed, compress the image N amount of times into mipmaps + if (makeMipMaps) { - mipMaps.Add(CompressImage(inImage, i)); + for (uint i = 1; i < GetNumReasonableMipMapLevels(); ++i) + { + mipMaps.Add(CompressImage(inImage, i)); + } } return mipMaps; diff --git a/Warcraft.NET/Files/WDT/Chunks/Legion/MLTA.cs b/Warcraft.NET/Files/WDT/Chunks/Legion/MLTA.cs new file mode 100644 index 0000000..7e3a59e --- /dev/null +++ b/Warcraft.NET/Files/WDT/Chunks/Legion/MLTA.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Warcraft.NET.Files.Interfaces; +using Warcraft.NET.Files.WDT.Entries.Legion; + +namespace Warcraft.NET.Files.WDT.Chunks.Legion +{ + /// + /// MLTA Chunk - Contains light animations + /// + public class MLTA : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MLTA"; + + public List Entries = new(); + + /// + /// Initializes a new instance of the class. + /// + public MLTA() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MLTA(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + var mltaCount = br.BaseStream.Length / MLTAEntry.GetSize(); + + for (var i = 0; i < mltaCount; ++i) + { + Entries.Add(new MLTAEntry(br.ReadBytes(MLTAEntry.GetSize()))); + } + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + foreach (MLTAEntry mltaEntry in Entries) + { + bw.Write(mltaEntry.Serialize()); + } + + return ms.ToArray(); + } + } + } +} diff --git a/Warcraft.NET/Files/WDT/Chunks/Legion/MPL2.cs b/Warcraft.NET/Files/WDT/Chunks/Legion/MPL2.cs index 442a2b2..07b7d74 100644 --- a/Warcraft.NET/Files/WDT/Chunks/Legion/MPL2.cs +++ b/Warcraft.NET/Files/WDT/Chunks/Legion/MPL2.cs @@ -6,7 +6,7 @@ namespace Warcraft.NET.Files.WDT.Chunks.Legion { /// - /// MPLT Chunk - Contains Legion light placement information + /// MPL2 Chunk - Contains Legion point light information /// public class MPL2 : IIFFChunk, IBinarySerializable { @@ -15,7 +15,7 @@ public class MPL2 : IIFFChunk, IBinarySerializable /// public const string Signature = "MPL2"; - public List Entries = new(); + public List Entries = []; /// /// Initializes a new instance of the class. @@ -39,9 +39,9 @@ public void LoadBinaryData(byte[] inData) using (var ms = new MemoryStream(inData)) using (var br = new BinaryReader(ms)) { - var mpltCount = br.BaseStream.Length / MPL2Entry.GetSize(); + var mpl2Count = br.BaseStream.Length / MPL2Entry.GetSize(); - for (var i = 0; i < mpltCount; ++i) + for (var i = 0; i < mpl2Count; ++i) { Entries.Add(new MPL2Entry(br.ReadBytes(MPL2Entry.GetSize()))); } diff --git a/Warcraft.NET/Files/WDT/Chunks/Legion/MTEX.cs b/Warcraft.NET/Files/WDT/Chunks/Legion/MTEX.cs new file mode 100644 index 0000000..beefad2 --- /dev/null +++ b/Warcraft.NET/Files/WDT/Chunks/Legion/MTEX.cs @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using System.IO; +using Warcraft.NET.Files.Interfaces; + +namespace Warcraft.NET.Files.WDT.Chunks.Legion +{ + /// + /// MTEX Chunk - Contains textures used for lights + /// + public class MTEX : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MTEX"; + + public List Entries = []; + + /// + /// Initializes a new instance of the class. + /// + public MTEX() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MTEX(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + var textureCount = br.BaseStream.Length / 4; + + for (var i = 0; i < textureCount; ++i) + { + Entries.Add(br.ReadUInt32()); + } + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + foreach (var texture in Entries) + { + bw.Write(texture); + } + + return ms.ToArray(); + } + } + } +} diff --git a/Warcraft.NET/Files/WDT/Chunks/SL/MPL3.cs b/Warcraft.NET/Files/WDT/Chunks/SL/MPL3.cs new file mode 100644 index 0000000..b5e3f4d --- /dev/null +++ b/Warcraft.NET/Files/WDT/Chunks/SL/MPL3.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.IO; +using Warcraft.NET.Files.Interfaces; +using Warcraft.NET.Files.WDT.Entries.SL; + +namespace Warcraft.NET.Files.WDT.Chunks.SL +{ + /// + /// MPL3 Chunk - Contains Shadowlands point light information + /// + public class MPL3 : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MPL3"; + + public List Entries = new(); + + /// + /// Initializes a new instance of the class. + /// + public MPL3() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MPL3(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + var mpl3Count = br.BaseStream.Length / MPL3Entry.GetSize(); + + for (var i = 0; i < mpl3Count; ++i) + { + Entries.Add(new MPL3Entry(br.ReadBytes(MPL3Entry.GetSize()))); + } + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + foreach (MPL3Entry mpl3Entry in Entries) + { + bw.Write(mpl3Entry.Serialize()); + } + + return ms.ToArray(); + } + } + } +} diff --git a/Warcraft.NET/Files/WDT/Chunks/WoD/MAOI.cs b/Warcraft.NET/Files/WDT/Chunks/WoD/MAOI.cs index 144230e..3a84239 100644 --- a/Warcraft.NET/Files/WDT/Chunks/WoD/MAOI.cs +++ b/Warcraft.NET/Files/WDT/Chunks/WoD/MAOI.cs @@ -5,7 +5,7 @@ namespace Warcraft.NET.Files.WDT.Chunks.WoD { /// - /// MAOH Chunk - Contains occlusion heighmap + /// MAOH Chunk - Contains occlusion heightmap /// public class MAOH : IIFFChunk, IBinarySerializable { diff --git a/Warcraft.NET/Files/WDT/Entries/Entrys/BfA/MAIDEntry.cs b/Warcraft.NET/Files/WDT/Entries/BfA/MAIDEntry.cs similarity index 100% rename from Warcraft.NET/Files/WDT/Entries/Entrys/BfA/MAIDEntry.cs rename to Warcraft.NET/Files/WDT/Entries/BfA/MAIDEntry.cs diff --git a/Warcraft.NET/Files/WDT/Entries/Legion/MLTAEntry.cs b/Warcraft.NET/Files/WDT/Entries/Legion/MLTAEntry.cs new file mode 100644 index 0000000..75b30da --- /dev/null +++ b/Warcraft.NET/Files/WDT/Entries/Legion/MLTAEntry.cs @@ -0,0 +1,71 @@ +using System.IO; + +namespace Warcraft.NET.Files.WDT.Entries.Legion +{ + /// + /// An entry struct containing light animations + /// + public class MLTAEntry + { + /// + /// Flicker intensity + /// + public float FlickerIntensity { get; set; } + + /// + /// Flicker intensity + /// + public float FlickerSpeed { get; set; } + + /// + /// Flicker mode + /// 0 = off, 1 = sine curve, 2 = noise curve, 3 = noise step curve + /// + public int FlickerMode { get; set; } + + public MLTAEntry() { } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MLTAEntry(byte[] data) + { + using (var ms = new MemoryStream(data)) + { + using (var br = new BinaryReader(ms)) + { + FlickerIntensity = br.ReadSingle(); + FlickerSpeed = br.ReadSingle(); + FlickerMode = br.ReadInt32(); + } + } + } + + /// + /// Gets the size of an entry. + /// + /// The size. + public static int GetSize() + { + return 12; + } + + /// + /// Gets the size of the data contained in this chunk. + /// + /// The size. + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + bw.Write(FlickerIntensity); + bw.Write(FlickerSpeed); + bw.Write(FlickerMode); + + return ms.ToArray(); + } + } + } +} diff --git a/Warcraft.NET/Files/WDT/Entries/Entrys/Legion/MPL2Entry.cs b/Warcraft.NET/Files/WDT/Entries/Legion/MPL2Entry.cs similarity index 98% rename from Warcraft.NET/Files/WDT/Entries/Entrys/Legion/MPL2Entry.cs rename to Warcraft.NET/Files/WDT/Entries/Legion/MPL2Entry.cs index 2a81f11..74e6f05 100644 --- a/Warcraft.NET/Files/WDT/Entries/Entrys/Legion/MPL2Entry.cs +++ b/Warcraft.NET/Files/WDT/Entries/Legion/MPL2Entry.cs @@ -6,7 +6,7 @@ namespace Warcraft.NET.Files.WDT.Entries.Legion { /// - /// An entry struct containing light information + /// An entry struct containing point light information /// public class MPL2Entry : MPLTEntry { diff --git a/Warcraft.NET/Files/WDT/Entries/Entrys/MAINEntry.cs b/Warcraft.NET/Files/WDT/Entries/MAINEntry.cs similarity index 90% rename from Warcraft.NET/Files/WDT/Entries/Entrys/MAINEntry.cs rename to Warcraft.NET/Files/WDT/Entries/MAINEntry.cs index 148bca3..7ab2c6d 100644 --- a/Warcraft.NET/Files/WDT/Entries/Entrys/MAINEntry.cs +++ b/Warcraft.NET/Files/WDT/Entries/MAINEntry.cs @@ -18,6 +18,13 @@ public class MAINEntry /// public uint AsyncId { get; set; } = 0; + /// + /// Initializes a new instance of the class. + /// + public MAINEntry() + { + } + /// /// Initializes a new instance of the class. /// diff --git a/Warcraft.NET/Files/WDT/Entries/SL/MPL3Entry.cs b/Warcraft.NET/Files/WDT/Entries/SL/MPL3Entry.cs new file mode 100644 index 0000000..459512c --- /dev/null +++ b/Warcraft.NET/Files/WDT/Entries/SL/MPL3Entry.cs @@ -0,0 +1,145 @@ +using System.IO; +using System.Numerics; +using Warcraft.NET.Extensions; +using Warcraft.NET.Files.Structures; + +namespace Warcraft.NET.Files.WDT.Entries.SL +{ + /// + /// An entry struct containing point light information (v3) + /// + public class MPL3Entry + { + /// + /// Light Id + /// + public uint Id { get; set; } + + /// + /// Color + /// + public uint Color { get; set; } + + /// + /// Position + /// + public Vector3 Position { get; set; } + + /// + /// Attenuation Start + /// + public float AttenuationStart { get; set; } + + /// + /// Attenuation End + /// + public float AttenuationEnd { get; set; } + + /// + /// Intensity + /// + public float Intensity { get; set; } + + /// + /// Unknown/unused vector3, likely rotation from another struct but unused for point lights. + /// + public Vector3 Unused0 { get; set; } + + /// + /// Map Tile X + /// + public ushort TileX { get; set; } + + /// + /// Map Tile X + /// + public ushort TileY { get; set; } + + /// + /// Index to MLTA chunk entry + /// Defaults to -1 if not used + /// + public short MLTAIndex { get; set; } = -1; + + /// + /// Index to MTEX chunk entry (note: not related to old ADT MTEX) + /// Default to -1 if not used + /// + public short MTEXIndex { get; set; } = -1; + + /// + /// Flags + /// + public ushort Flags { get; set; } + + /// + /// Unknown value, wiki mentions it is "a packed value". 14336 appears to be the most common value. + /// + public ushort Unknown1 { get; set; } = 14336; + + public MPL3Entry() { } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MPL3Entry(byte[] data) + { + using (var ms = new MemoryStream(data)) + { + using (var br = new BinaryReader(ms)) + { + Id = br.ReadUInt32(); + Color = br.ReadUInt32(); + Position = br.ReadVector3(AxisConfiguration.Native); + AttenuationStart = br.ReadSingle(); + AttenuationEnd = br.ReadSingle(); + Intensity = br.ReadSingle(); + Unused0 = br.ReadVector3(); + TileX = br.ReadUInt16(); + TileY = br.ReadUInt16(); + MLTAIndex = br.ReadInt16(); + MTEXIndex = br.ReadInt16(); + Flags = br.ReadUInt16(); + Unknown1 = br.ReadUInt16(); + } + } + } + + /// + /// Gets the size of an entry. + /// + /// The size. + public new static int GetSize() + { + return 56; + } + + /// + /// Gets the size of the data contained in this chunk. + /// + /// The size. + public new byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + bw.Write(Id); + bw.Write(Color); + bw.WriteVector3(Position, AxisConfiguration.Native); + bw.Write(AttenuationStart); + bw.Write(AttenuationEnd); + bw.Write(Intensity); + bw.WriteVector3(Unused0); + bw.Write(TileX); + bw.Write(TileY); + bw.Write(MLTAIndex); + bw.Write(MTEXIndex); + bw.Write(Flags); + bw.Write(Unknown1); + + return ms.ToArray(); + } + } + } +} diff --git a/Warcraft.NET/Files/WDT/Entries/Entrys/WoD/MAOIEntry.cs b/Warcraft.NET/Files/WDT/Entries/WoD/MAOIEntry.cs similarity index 100% rename from Warcraft.NET/Files/WDT/Entries/Entrys/WoD/MAOIEntry.cs rename to Warcraft.NET/Files/WDT/Entries/WoD/MAOIEntry.cs diff --git a/Warcraft.NET/Files/WDT/Entries/Entrys/WoD/MPLTEntry.cs b/Warcraft.NET/Files/WDT/Entries/WoD/MPLTEntry.cs similarity index 100% rename from Warcraft.NET/Files/WDT/Entries/Entrys/WoD/MPLTEntry.cs rename to Warcraft.NET/Files/WDT/Entries/WoD/MPLTEntry.cs diff --git a/Warcraft.NET/Files/WDT/Light/Legion/WorldLightTable.cs b/Warcraft.NET/Files/WDT/Light/Legion/WorldLightTable.cs index 9f110e9..d0952a8 100644 --- a/Warcraft.NET/Files/WDT/Light/Legion/WorldLightTable.cs +++ b/Warcraft.NET/Files/WDT/Light/Legion/WorldLightTable.cs @@ -7,10 +7,22 @@ namespace Warcraft.NET.Files.WDT.Light.Legion public class WorldLightTable : WorldLightTableWoD { /// - /// WoD Light Table + /// Legion Point Light Table /// - [ChunkOrder(3), ChunkOptional] - public MPL2 LightTable2 { get; set; } + [ChunkOrder(2), ChunkOptional] + public MPL2 PointLights2 { get; set; } + + /// + /// Texture FileDataIDs + /// + [ChunkOrder(4), ChunkOptional] + public MTEX TextureFileDataIDs { get; set; } + + /// + /// Light animations + /// + [ChunkOrder(5), ChunkOptional] + public MLTA LightAnimations { get; set; } /// /// Initializes a new instance of the class. diff --git a/Warcraft.NET/Files/WDT/Light/SL/WorldLightTable.cs b/Warcraft.NET/Files/WDT/Light/SL/WorldLightTable.cs new file mode 100644 index 0000000..7fe4f26 --- /dev/null +++ b/Warcraft.NET/Files/WDT/Light/SL/WorldLightTable.cs @@ -0,0 +1,23 @@ +using Warcraft.NET.Attribute; +using Warcraft.NET.Files.WDT.Chunks.SL; +using WorldLightTableLegion = Warcraft.NET.Files.WDT.Light.Legion.WorldLightTable; + +namespace Warcraft.NET.Files.WDT.Light.SL +{ + public class WorldLightTable : WorldLightTableLegion + { + /// + /// SL Point Light Table + /// + [ChunkOrder(3), ChunkOptional] + public MPL3 PointLights3 { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The binary data. + public WorldLightTable(byte[] inData = null) : base(inData) + { + } + } +} diff --git a/Warcraft.NET/Files/WDT/Light/WoD/WorldLightTable.cs b/Warcraft.NET/Files/WDT/Light/WoD/WorldLightTable.cs index 3dcbd6a..d976e63 100644 --- a/Warcraft.NET/Files/WDT/Light/WoD/WorldLightTable.cs +++ b/Warcraft.NET/Files/WDT/Light/WoD/WorldLightTable.cs @@ -6,10 +6,10 @@ namespace Warcraft.NET.Files.WDT.Light.WoD public class WorldLightTable : WorldLightTableBase { /// - /// WoD Light Table + /// WoD Point Light Table /// [ChunkOrder(2), ChunkOptional] - public MPLT LightTable { get; set; } + public MPLT PointLights { get; set; } /// /// Initializes a new instance of the class. diff --git a/Warcraft.NET/Files/WDT/Root/BfA/WorldDataTable.cs b/Warcraft.NET/Files/WDT/Root/BfA/WorldDataTable.cs index 0968d00..737db72 100644 --- a/Warcraft.NET/Files/WDT/Root/BfA/WorldDataTable.cs +++ b/Warcraft.NET/Files/WDT/Root/BfA/WorldDataTable.cs @@ -11,6 +11,13 @@ public class WorldDataTable : WorldDataTableBase [ChunkOrder(6), ChunkOptional] public MAID Ids { get; set; } + /// + /// Initializes a new instance of the class. + /// + public WorldDataTable() : base() + { + } + /// /// Initializes a new instance of the class. /// diff --git a/Warcraft.NET/Files/WDT/Root/WorldDataTableBase.cs b/Warcraft.NET/Files/WDT/Root/WorldDataTableBase.cs index 1655bd7..94733af 100644 --- a/Warcraft.NET/Files/WDT/Root/WorldDataTableBase.cs +++ b/Warcraft.NET/Files/WDT/Root/WorldDataTableBase.cs @@ -37,6 +37,13 @@ public abstract class WorldDataTableBase : ChunkedFile [ChunkOrder(5), ChunkOptional] public ADT.Chunks.MODF WorldModelObjectPlacementInfo { get; set; } + /// + /// Initializes a new instance of the class. + /// + public WorldDataTableBase() : base() + { + } + /// /// Initializes a new instance of the class. /// diff --git a/Warcraft.NET/README.md b/Warcraft.NET/README.md index eb6ceb7..f5592fa 100644 --- a/Warcraft.NET/README.md +++ b/Warcraft.NET/README.md @@ -18,5 +18,5 @@ The use of the GPLv3 license and not the LGPLv3 license is a conscious choice by Special thanks to: - [wowdev.wiki](https://wowdev.wiki/) -- [libwarcarft](https://github.com/WowDevTools/libwarcraft) +- [libwarcraft](https://github.com/WowDevTools/libwarcraft)