diff --git a/LibBSP/LibBSP.csproj b/LibBSP/LibBSP.csproj index 84eebd6..eb7e73c 100644 --- a/LibBSP/LibBSP.csproj +++ b/LibBSP/LibBSP.csproj @@ -68,6 +68,7 @@ + diff --git a/LibBSP/Source/Extensions/UIVertexExtensions.cs b/LibBSP/Source/Extensions/UIVertexExtensions.cs index ccead1d..c449317 100644 --- a/LibBSP/Source/Extensions/UIVertexExtensions.cs +++ b/LibBSP/Source/Extensions/UIVertexExtensions.cs @@ -107,9 +107,17 @@ namespace LibBSP { } UIVertex result = new UIVertex(); switch (type) { + case MapType.CoD: { + if (version == 0) { + goto case MapType.Quake3; + } else if (version == 1) { + result.color = Color32Extensions.FromArgb(255, 255, 255, 255); + goto case MapType.DMoMaM; + } + break; + } case MapType.MOHAA: case MapType.Quake3: - case MapType.CoD: case MapType.CoD2: case MapType.CoD4: case MapType.FAKK: { @@ -194,9 +202,16 @@ namespace LibBSP { structLength = 12; break; } + case MapType.CoD: { + if (version == 0) { + goto case MapType.Quake3; + } else if (version == 1) { + goto case MapType.DMoMaM; + } + break; + } case MapType.MOHAA: case MapType.Quake3: - case MapType.CoD: case MapType.FAKK: { structLength = 44; break; @@ -224,7 +239,7 @@ namespace LibBSP { } /// - /// Gets the index for this lump in the BSP file for a specific map format. + /// Gets the index for the vertices lump in the BSP file for a specific map format. /// /// The map type. /// Index for this lump, or -1 if the format doesn't have this lump. @@ -260,6 +275,9 @@ namespace LibBSP { case MapType.STEF2Demo: { return 6; } + case MapType.CoD: { + return 7; + } case MapType.Raven: case MapType.Quake3: { return 10; @@ -270,5 +288,21 @@ namespace LibBSP { } } + /// + /// Gets the index for the patch vertices lump in the BSP file for a specific map format. + /// + /// The map type. + /// Index for this lump, or -1 if the format doesn't have this lump. + public static int GetIndexForPatchVertsLump(MapType type) { + switch (type) { + case MapType.CoD: { + return 25; + } + default: { + return -1; + } + } + } + } } diff --git a/LibBSP/Source/Structs/BSP/BSP.cs b/LibBSP/Source/Structs/BSP/BSP.cs index 54c78ae..d5645a4 100644 --- a/LibBSP/Source/Structs/BSP/BSP.cs +++ b/LibBSP/Source/Structs/BSP/BSP.cs @@ -93,6 +93,10 @@ namespace LibBSP { // MoHAA private List _lodTerrains; private List _staticModels; + // CoD + private List _patches; + private List _patchVerts; + private NumList _patchIndices; // Nightfire private Textures _materials; private NumList _indices; @@ -481,6 +485,52 @@ namespace LibBSP { } } + /// + /// A List of objects in the BSP file, if available. + /// + public List patches { + get { + if (_patches == null) { + int index = Patch.GetIndexForLump(version); + if (index >= 0) { + _patches = Patch.LumpFactory(reader.ReadLump(this[index]), version, this[index].version); + } + } + return _patches; + } + } + + /// + /// A List of objects in the BSP file representing the patch vertices of the BSP, if available. + /// + public List patchVerts { + get { + if (_patchVerts == null) { + int index = UIVertexExtensions.GetIndexForPatchVertsLump(version); + if (index >= 0) { + _patchVerts = UIVertexExtensions.LumpFactory(reader.ReadLump(this[index]), version, 1); + } + } + return _patchVerts; + } + } + + /// + /// A object containing the Patch Vertex Indices lump, if available. + /// + public NumList patchIndices { + get { + if (_patchIndices == null) { + NumList.DataType type; + int index = NumList.GetIndexForPatchIndicesLump(version, out type); + if (index >= 0) { + _patchIndices = NumList.LumpFactory(reader.ReadLump(this[index]), type); + } + } + return _patchIndices; + } + } + /// /// A object containing the Face Vertex Indices lump, if available. /// @@ -772,8 +822,8 @@ namespace LibBSP { } // Get the index and length from the object - int index = (int)indexProperty.GetGetMethod().Invoke(o, null); - int count = (int)countProperty.GetGetMethod().Invoke(o, null); + int index = (int)(indexProperty.GetGetMethod().Invoke(o, null)); + int count = (int)(countProperty.GetGetMethod().Invoke(o, null)); // Get the lump from this class List theLump = targetLump.GetGetMethod().Invoke(this, null) as List; diff --git a/LibBSP/Source/Structs/BSP/Face.cs b/LibBSP/Source/Structs/BSP/Face.cs index 723fa44..a214c65 100644 --- a/LibBSP/Source/Structs/BSP/Face.cs +++ b/LibBSP/Source/Structs/BSP/Face.cs @@ -74,6 +74,14 @@ namespace LibBSP { lightMaps = -1; patchSize = new Vector2(Single.NaN, Single.NaN); switch (type) { + case MapType.CoD: { + texture = BitConverter.ToInt16(data, 0); + firstVertex = BitConverter.ToInt32(data, 4); + numVertices = BitConverter.ToInt16(data, 8); + numIndices = BitConverter.ToInt16(data, 10); + firstIndex = BitConverter.ToInt32(data, 12); + break; + } case MapType.Quake: case MapType.Quake2: case MapType.Daikatana: @@ -180,6 +188,10 @@ namespace LibBSP { } int structLength = 0; switch (type) { + case MapType.CoD: { + structLength = 16; + break; + } case MapType.Quake: case MapType.Quake2: case MapType.Daikatana: { @@ -272,7 +284,8 @@ namespace LibBSP { case MapType.Quake2: case MapType.SiN: case MapType.Daikatana: - case MapType.SoF: { + case MapType.SoF: + case MapType.CoD: { return 6; } case MapType.Vindictus: diff --git a/LibBSP/Source/Structs/BSP/LODTerrain.cs b/LibBSP/Source/Structs/BSP/LODTerrain.cs index 3c87384..8c5438f 100644 --- a/LibBSP/Source/Structs/BSP/LODTerrain.cs +++ b/LibBSP/Source/Structs/BSP/LODTerrain.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; namespace LibBSP { /// - /// Holds the data used by the brush structures of all formats of BSP. + /// Holds the data for a terrain object in MoHAA. /// public struct LODTerrain { diff --git a/LibBSP/Source/Structs/BSP/Leaf.cs b/LibBSP/Source/Structs/BSP/Leaf.cs index 5e29740..f66c141 100644 --- a/LibBSP/Source/Structs/BSP/Leaf.cs +++ b/LibBSP/Source/Structs/BSP/Leaf.cs @@ -90,6 +90,13 @@ namespace LibBSP { numMarkBrushes = BitConverter.ToInt32(data, 44); break; } + case MapType.CoD: { + firstMarkFace = BitConverter.ToInt32(data, 8); + numMarkFaces = BitConverter.ToInt32(data, 12); + firstMarkBrush = BitConverter.ToInt32(data, 16); + numMarkBrushes = BitConverter.ToInt32(data, 20); + break; + } default: { throw new ArgumentException("Map type " + type + " isn't supported by the Leaf class."); } @@ -209,6 +216,9 @@ namespace LibBSP { case MapType.Nightfire: { return 11; } + case MapType.CoD: { + return 21; + } default: { return -1; } diff --git a/LibBSP/Source/Structs/BSP/Model.cs b/LibBSP/Source/Structs/BSP/Model.cs index 002860d..40ff8ba 100644 --- a/LibBSP/Source/Structs/BSP/Model.cs +++ b/LibBSP/Source/Structs/BSP/Model.cs @@ -22,6 +22,8 @@ namespace LibBSP { [Count("brushes")] public int numBrushes { get; private set; } [Index("faces")] public int firstFace { get; private set; } // Quake/GoldSrc [Count("faces")] public int numFaces { get; private set; } + [Index("markSurfaces")] public int firstLeafPatch { get; private set; } // CoD + [Count("markSurfaces")] public int numLeafPatches { get; private set; } /// /// Creates a new object from a byte array. @@ -42,6 +44,8 @@ namespace LibBSP { numBrushes = -1; firstFace = -1; numFaces = -1; + firstLeafPatch = -1; + numLeafPatches = -1; switch (type) { case MapType.Quake: { headNode = BitConverter.ToInt32(data, 36); @@ -94,7 +98,13 @@ namespace LibBSP { numBrushes = BitConverter.ToInt32(data, 36); break; } - case MapType.CoD: + case MapType.CoD: { + firstFace = BitConverter.ToInt32(data, 24); + numFaces = BitConverter.ToInt32(data, 28); + firstLeafPatch = BitConverter.ToInt32(data, 32); + numLeafPatches = BitConverter.ToInt32(data, 36); + goto case MapType.CoD2; + } case MapType.CoD2: case MapType.CoD4: { firstBrush = BitConverter.ToInt32(data, 40); diff --git a/LibBSP/Source/Structs/BSP/Node.cs b/LibBSP/Source/Structs/BSP/Node.cs index 506ab07..2f6561e 100644 --- a/LibBSP/Source/Structs/BSP/Node.cs +++ b/LibBSP/Source/Structs/BSP/Node.cs @@ -27,8 +27,8 @@ namespace LibBSP { plane = BitConverter.ToInt32(data, 0); // All formats I've seen use the first 4 bytes as an int, plane index switch (type) { case MapType.Quake: { - this.child1 = BitConverter.ToInt16(data, 4); - this.child2 = BitConverter.ToInt16(data, 6); + child1 = BitConverter.ToInt16(data, 4); + child2 = BitConverter.ToInt16(data, 6); break; } // These all use the first three ints for planenum and children @@ -56,8 +56,8 @@ namespace LibBSP { case MapType.Quake3: case MapType.FAKK: case MapType.CoD: { - this.child1 = BitConverter.ToInt32(data, 4); - this.child2 = BitConverter.ToInt32(data, 8); + child1 = BitConverter.ToInt32(data, 4); + child2 = BitConverter.ToInt32(data, 8); break; } default: { @@ -179,6 +179,9 @@ namespace LibBSP { case MapType.STEF2Demo: { return 11; } + case MapType.CoD: { + return 20; + } default: { return -1; } diff --git a/LibBSP/Source/Structs/BSP/Patch.cs b/LibBSP/Source/Structs/BSP/Patch.cs new file mode 100644 index 0000000..980e961 --- /dev/null +++ b/LibBSP/Source/Structs/BSP/Patch.cs @@ -0,0 +1,116 @@ +#if UNITY_2_6 || UNITY_2_6_1 || UNITY_3_0 || UNITY_3_0_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_5_3_OR_NEWER +#define UNITY +#endif + +using System; +using System.Collections.Generic; +#if UNITY +using UnityEngine; +#endif + +namespace LibBSP { +#if !UNITY + using Vector2 = Vector2d; +#endif + + /// + /// Holds the data for a patch in a CoD BSP. + /// + public struct Patch { + + public short shader { get; private set; } + public short type { get; private set; } + public Vector2 dimensions { get; private set; } + public int flags { get; private set; } + [Index("patchVerts")] public int firstVertex { get; private set; } + [Count("patchVerts")] public int numVertices { get; private set; } + [Count("patchIndices")] public int numIndices { get; private set; } + [Index("patchIndices")] public int firstIndex { get; private set; } + + /// + /// Creates a new object from a byte array. + /// + /// byte array to parse. + /// The map type. + /// The version of this lump. + /// was null. + /// This structure is not implemented for the given maptype. + public Patch(byte[] data, MapType type, int version = 0) : this() { + if (data == null) { + throw new ArgumentNullException(); + } + switch (type) { + case MapType.CoD: { + shader = BitConverter.ToInt16(data, 0); + this.type = BitConverter.ToInt16(data, 2); + if (this.type == 0) { // Patch + short x = BitConverter.ToInt16(data, 4); + short y = BitConverter.ToInt16(data, 6); + dimensions = new Vector2(x, y); + flags = BitConverter.ToInt32(data, 8); + firstVertex = BitConverter.ToInt32(data, 12); + numVertices = x * y; + } else if (this.type == 1) { // Terrain + numVertices = BitConverter.ToInt16(data, 4); + numIndices = BitConverter.ToInt16(data, 6); + firstVertex = BitConverter.ToInt32(data, 8); + firstIndex = BitConverter.ToInt32(data, 12); + } + break; + } + default: { + throw new ArgumentException("Map type " + type + " isn't supported by the Patch class."); + } + } + } + + /// + /// Factory method to parse a byte array into a List of objects. + /// + /// The data to parse. + /// The map type. + /// The version of this lump. + /// A List of objects. + /// was null. + /// This structure is not implemented for the given maptype. + public static List LumpFactory(byte[] data, MapType type, int version = 0) { + if (data == null) { + throw new ArgumentNullException(); + } + int structLength = 0; + switch (type) { + case MapType.CoD: { + structLength = 16; + break; + } + default: { + throw new ArgumentException("Map type " + type + " isn't supported by the Patch lump factory."); + } + } + List lump = new List(data.Length / structLength); + byte[] bytes = new byte[structLength]; + for (int i = 0; i < data.Length / structLength; ++i) { + Array.Copy(data, (i * structLength), bytes, 0, structLength); + lump.Add(new Patch(bytes, type, version)); + } + return lump; + } + + /// + /// Gets the index for this lump in the BSP file for a specific map format. + /// + /// The map type. + /// Index for this lump, or -1 if the format doesn't have this lump or it's not implemented. + public static int GetIndexForLump(MapType type) { + switch (type) { + case MapType.CoD: { + return 24; + } + default: { + return -1; + } + } + } + + } +} diff --git a/LibBSP/Source/Structs/Common/Lumps/NumList.cs b/LibBSP/Source/Structs/Common/Lumps/NumList.cs index c658d05..2f9a0c5 100644 --- a/LibBSP/Source/Structs/Common/Lumps/NumList.cs +++ b/LibBSP/Source/Structs/Common/Lumps/NumList.cs @@ -150,6 +150,10 @@ namespace LibBSP { dataType = DataType.UInt16; return 16; } + case MapType.CoD: { + dataType = DataType.UInt32; + return 23; + } } dataType = DataType.Invalid; return -1; @@ -239,6 +243,10 @@ namespace LibBSP { dataType = DataType.UInt16; return 17; } + case MapType.CoD: { + dataType = DataType.UInt32; + return 22; + } } dataType = DataType.Invalid; return -1; @@ -266,6 +274,10 @@ namespace LibBSP { dataType = DataType.UInt32; return 7; } + case MapType.CoD: { + dataType = DataType.UInt16; + return 8; + } case MapType.Raven: case MapType.Quake3: { dataType = DataType.UInt32; @@ -276,6 +288,23 @@ namespace LibBSP { return -1; } + /// + /// Gets the index for the patch indices lump in the BSP file for a specific map format, and the type of data the format uses. + /// + /// The map type. + /// out parameter that will contain the data type this version uses. + /// Index for this lump, or -1 if the format doesn't have this lump or it's not implemented. + public static int GetIndexForPatchIndicesLump(MapType version, out DataType dataType) { + switch (version) { + case MapType.CoD: { + dataType = DataType.UInt16; + return 26; + } + } + dataType = DataType.Invalid; + return -1; + } + /// /// Gets the index for the texture table lump in the BSP file for a specific map format, and the type of data the format uses. ///