diff --git a/SabreTools.Models/BSP/Clipnode.cs b/SabreTools.Models/BSP/Clipnode.cs
new file mode 100644
index 0000000..687ebe4
--- /dev/null
+++ b/SabreTools.Models/BSP/Clipnode.cs
@@ -0,0 +1,28 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// This lump contains the so-called clipnodes, which build a second
+ /// BSP tree used only for collision detection.
+ ///
+ /// This structure is a reduced form of the BSPNODE struct from the
+ /// nodes lump. Also the BSP tree built by the clipnodes is simpler
+ /// than the one described by the BSPNODEs to accelerate collision calculations.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class Clipnode
+ {
+ ///
+ /// Index into planes
+ ///
+ public int PlaneIndex;
+
+ ///
+ /// Negative numbers are contents
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+ public short[]? ChildrenIndices = new short[2];
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/ClipnodesLump.cs b/SabreTools.Models/BSP/ClipnodesLump.cs
new file mode 100644
index 0000000..13d8dde
--- /dev/null
+++ b/SabreTools.Models/BSP/ClipnodesLump.cs
@@ -0,0 +1,19 @@
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// This lump contains the so-called clipnodes, which build a second
+ /// BSP tree used only for collision detection.
+ ///
+ /// This structure is a reduced form of the BSPNODE struct from the
+ /// nodes lump. Also the BSP tree built by the clipnodes is simpler
+ /// than the one described by the BSPNODEs to accelerate collision calculations.
+ ///
+ ///
+ public sealed class ClipnodesLump : Lump
+ {
+ ///
+ /// Clipnodes
+ ///
+ public Clipnode[]? Clipnodes { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/Constants.cs b/SabreTools.Models/BSP/Constants.cs
index b0a4159..a7de4cf 100644
--- a/SabreTools.Models/BSP/Constants.cs
+++ b/SabreTools.Models/BSP/Constants.cs
@@ -1,25 +1,59 @@
namespace SabreTools.Models.BSP
{
+ ///
public static class Constants
{
+ #region Header
+
///
/// Number of lumps in a BSP
///
- public const int HL_BSP_LUMP_COUNT = 15;
+ public const int HEADER_LUMPS = 15;
- ///
- /// Index for the entities lump
- ///
- public const int HL_BSP_LUMP_ENTITIES = 0;
+ #endregion
- ///
- /// Index for the texture data lump
- ///
- public const int HL_BSP_LUMP_TEXTUREDATA = 2;
+ #region Lump
- ///
- /// Number of valid mipmap levels
- ///
- public const int HL_BSP_MIPMAP_COUNT = 4;
+ public const int MAX_MAP_HULLS = 4;
+
+ public const int MAX_MAP_MODELS = 400;
+ public const int MAX_MAP_BRUSHES = 4096;
+ public const int MAX_MAP_ENTITIES = 1024;
+ public const int MAX_MAP_ENTSTRING = (128 * 1024);
+
+ public const int MAX_MAP_PLANES = 32767;
+ public const int MAX_MAP_NODES = 32767;
+ public const int MAX_MAP_CLIPNODES = 32767;
+ public const int MAX_MAP_LEAFS = 8192;
+ public const int MAX_MAP_VERTS = 65535;
+ public const int MAX_MAP_FACES = 65535;
+ public const int MAX_MAP_MARKSURFACES = 65535;
+ public const int MAX_MAP_TEXINFO = 8192;
+ public const int MAX_MAP_EDGES = 256000;
+ public const int MAX_MAP_SURFEDGES = 512000;
+ public const int MAX_MAP_TEXTURES = 512;
+ public const int MAX_MAP_MIPTEX = 0x200000;
+ public const int MAX_MAP_LIGHTING = 0x200000;
+ public const int MAX_MAP_VISIBILITY = 0x200000;
+
+ public const int MAX_MAP_PORTALS = 65536;
+
+ #endregion
+
+ #region Entities
+
+ public const int MAX_KEY = 32;
+
+ public const int MAX_VALUE = 1024;
+
+ #endregion
+
+ #region Textures
+
+ public const int MAXTEXTURENAME = 16;
+
+ public const int MIPLEVELS = 4;
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/Edge.cs b/SabreTools.Models/BSP/Edge.cs
new file mode 100644
index 0000000..c449d52
--- /dev/null
+++ b/SabreTools.Models/BSP/Edge.cs
@@ -0,0 +1,19 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// The edges delimit the face and further refer to the vertices of the
+ /// face. Each edge is pointing to the start and end vertex of the edge.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class Edge
+ {
+ ///
+ /// Indices into vertex array
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+ public ushort[]? VertexIndices = new ushort[2];
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/EdgesLump.cs b/SabreTools.Models/BSP/EdgesLump.cs
new file mode 100644
index 0000000..8b35925
--- /dev/null
+++ b/SabreTools.Models/BSP/EdgesLump.cs
@@ -0,0 +1,15 @@
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// The edges delimit the face and further refer to the vertices of the
+ /// face. Each edge is pointing to the start and end vertex of the edge.
+ ///
+ ///
+ public sealed class EdgesLump : Lump
+ {
+ ///
+ /// Edge
+ ///
+ public Edge[]? Edges { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/Entity.cs b/SabreTools.Models/BSP/Entity.cs
new file mode 100644
index 0000000..fe3631a
--- /dev/null
+++ b/SabreTools.Models/BSP/Entity.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// The entity lump is basically a pure ASCII text section.
+ /// It consists of the string representations of all entities,
+ /// which are copied directly from the input file to the output
+ /// BSP file by the compiler.
+ ///
+ /// Every entity begins and ends with curly brackets. In between
+ /// there are the attributes of the entity, one in each line,
+ /// which are pairs of strings enclosed by quotes. The first
+ /// string is the name of the attribute (the key), the second one
+ /// its value. The attribute "classname" is mandatory for every
+ /// entity specifiying its type and therefore, how it is
+ /// interpreted by the engine.
+ ///
+ ///
+ public sealed class Entity
+ {
+ ///
+ /// Entity attributes
+ ///
+ public List>? Attributes { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/EntityLump.cs b/SabreTools.Models/BSP/EntityLump.cs
new file mode 100644
index 0000000..8bba1b5
--- /dev/null
+++ b/SabreTools.Models/BSP/EntityLump.cs
@@ -0,0 +1,25 @@
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// The entity lump is basically a pure ASCII text section.
+ /// It consists of the string representations of all entities,
+ /// which are copied directly from the input file to the output
+ /// BSP file by the compiler.
+ ///
+ /// Every entity begins and ends with curly brackets. In between
+ /// there are the attributes of the entity, one in each line,
+ /// which are pairs of strings enclosed by quotes. The first
+ /// string is the name of the attribute (the key), the second one
+ /// its value. The attribute "classname" is mandatory for every
+ /// entity specifiying its type and therefore, how it is
+ /// interpreted by the engine.
+ ///
+ ///
+ public sealed class EntityLump : Lump
+ {
+ ///
+ /// Entities
+ ///
+ public Entity[]? Entities { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/Enums.cs b/SabreTools.Models/BSP/Enums.cs
new file mode 100644
index 0000000..d853e44
--- /dev/null
+++ b/SabreTools.Models/BSP/Enums.cs
@@ -0,0 +1,160 @@
+using System;
+
+namespace SabreTools.Models.BSP
+{
+ ///
+ public enum Contents : int
+ {
+ CONTENTS_EMPTY = -1,
+ CONTENTS_SOLID = -2,
+ CONTENTS_WATER = -3,
+ CONTENTS_SLIME = -4,
+ CONTENTS_LAVA = -5,
+ CONTENTS_SKY = -6,
+ CONTENTS_ORIGIN = -7,
+ CONTENTS_CLIP = -8,
+ CONTENTS_CURRENT_0 = -9,
+ CONTENTS_CURRENT_90 = -10,
+ CONTENTS_CURRENT_180 = -11,
+ CONTENTS_CURRENT_270 = -12,
+ CONTENTS_CURRENT_UP = -13,
+ CONTENTS_CURRENT_DOWN = -14,
+ CONTENTS_TRANSLUCENT = -15,
+ }
+
+ ///
+ public enum LumpType : int
+ {
+ ///
+ /// The entity lump is basically a pure ASCII text section.
+ /// It consists of the string representations of all entities,
+ /// which are copied directly from the input file to the output
+ /// BSP file by the compiler.
+ ///
+ LUMP_ENTITIES = 0,
+
+ ///
+ /// This lump is a simple array of binary data structures.
+ /// Each of this structures defines a plane in 3-dimensional
+ /// space by using the Hesse normal form
+ ///
+ LUMP_PLANES = 1,
+
+ ///
+ /// The texture lump is somehow a bit more complex then the
+ /// other lumps, because it is possible to save textures
+ /// directly within the BSP file instead of storing them in
+ /// external WAD files.
+ ///
+ LUMP_TEXTURES = 2,
+
+ ///
+ /// This lump simply consists of all vertices of the BSP tree.
+ /// They are stored as a primitve array of triples of floats.
+ ///
+ LUMP_VERTICES = 3,
+
+ ///
+ /// The VIS lump contains data, which is irrelevant to the actual
+ /// BSP tree, but offers a way to boost up the speed of the
+ /// renderer significantly. Especially complex maps profit from
+ /// the use if this data. This lump contains the so-called
+ /// Potentially Visible Sets (PVS) (also called VIS lists) in the
+ /// same amout of leaves of the tree, the user can enter (often
+ /// referred to as VisLeaves). The visiblilty lists are stored as
+ /// sequences of bitfields, which are run-length encoded.
+ ///
+ LUMP_VISIBILITY = 4,
+
+ ///
+ /// This lump is simple again and contains an array of binary
+ /// structures, the nodes, which are a major part of the BSP tree.
+ ///
+ LUMP_NODES = 5,
+
+ ///
+ /// The texinfo lump contains informations about how textures are
+ /// applied to surfaces. The lump itself is an array of binary data
+ /// structures.
+ ///
+ LUMP_TEXINFO = 6,
+
+ ///
+ /// The face lump contains the surfaces of the scene.
+ ///
+ LUMP_FACES = 7,
+
+ ///
+ /// This is one of the largest lumps in the BSP file. The lightmap
+ /// lump stores all lightmaps used in the entire map. The lightmaps
+ /// are arrays of triples of bytes (3 channel color, RGB) and stored
+ /// continuously.
+ ///
+ LUMP_LIGHTING = 8,
+
+ ///
+ /// This lump contains the so-called clipnodes, which build a second
+ /// BSP tree used only for collision detection.
+ ///
+ LUMP_CLIPNODES = 9,
+
+ ///
+ /// The leaves lump contains the leaves of the BSP tree.
+ ///
+ LUMP_LEAVES = 10,
+
+ ///
+ /// The marksurfaces lump is a simple array of short integers.
+ ///
+ LUMP_MARKSURFACES = 11,
+
+ ///
+ /// The edges delimit the face and further refer to the vertices of the
+ /// face. Each edge is pointing to the start and end vertex of the edge.
+ ///
+ LUMP_EDGES = 12,
+
+ ///
+ /// This lump represents pretty much the same mechanism as the marksurfaces.
+ /// A face can insert its surfedge indexes into this array to get the
+ /// corresponding edges delimitting the face and further pointing to the
+ /// vertexes, which are required for rendering. The index can be positive
+ /// or negative. If the value of the surfedge is positive, the first vertex
+ /// of the edge is used as vertex for rendering the face, otherwise, the
+ /// value is multiplied by -1 and the second vertex of the indexed edge is
+ /// used.
+ ///
+ LUMP_SURFEDGES = 13,
+
+ ///
+ /// A model is kind of a mini BSP tree. Its size is determinded by the
+ /// bounding box spaned by the first to members of this struct.
+ ///
+ LUMP_MODELS = 14,
+ }
+
+ ///
+ public enum PlaneType : int
+ {
+ // Plane is perpendicular to given axis
+ PLANE_X = 0,
+ PLANE_Y = 1,
+ PLANE_Z = 2,
+
+ // Non-axial plane is snapped to the nearest
+ PLANE_ANYX = 3,
+ PLANE_ANYY = 4,
+ PLANE_ANYZ = 5,
+ }
+
+ ///
+ [Flags]
+ public enum TextureFlag : uint
+ {
+ ///
+ /// Disable lightmaps and subdivision for the surface
+ ///
+ /// Used by sky and liquids
+ DisableLightmaps = 0x01,
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/Face.cs b/SabreTools.Models/BSP/Face.cs
new file mode 100644
index 0000000..6f77968
--- /dev/null
+++ b/SabreTools.Models/BSP/Face.cs
@@ -0,0 +1,66 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// The face lump contains the surfaces of the scene.
+ ///
+ /// The first number of this data structure is an index into
+ /// the planes lump giving a plane which is parallel to this
+ /// face (meaning they share the same normal). The second
+ /// value may be seen as a boolean. If nPlaneSide equals 0,
+ /// then the normal vector of this face equals the one of the
+ /// parallel plane exactly. Otherwise, the normal of the plane
+ /// has to be multiplied by -1 to point into the right direction.
+ /// Afterwards we have an index into the surfedges lump, as
+ /// well as the count of consecutive surfedges from that position.
+ /// Furthermore there is an index into the texture info lump,
+ /// which is used to find the BSPTEXINFO structure needed to
+ /// calculate the texture coordinates for this face. Afterwards,
+ /// there are four bytes giving some lighting information (partly
+ /// used by the renderer to hide sky surfaces). Finally we have
+ /// an offset in byes giving the beginning of the binary lightmap
+ /// data of this face in the lighting lump.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class Face
+ {
+ ///
+ /// Plane the face is parallel to
+ ///
+ public ushort PlaneIndex;
+
+ ///
+ /// Set if different normals orientation
+ ///
+ public ushort PlaneSideCount;
+
+ ///
+ /// Index of the first surfedge
+ ///
+ public uint FirstEdgeIndex;
+
+ ///
+ /// Number of consecutive surfedges
+ ///
+ public ushort NumberOfEdges;
+
+ ///
+ /// Index of the texture info structure
+ ///
+ public ushort TextureInfoIndex;
+
+ ///
+ /// Specify lighting styles
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
+ public byte[]? LightingStyles = new byte[4];
+
+ ///
+ /// Offsets into the raw lightmap data; if less than zero,
+ /// then a lightmap was not baked for the given face.
+ ///
+ public int LightmapOffsetCount;
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/FacesLump.cs b/SabreTools.Models/BSP/FacesLump.cs
new file mode 100644
index 0000000..2c5a00c
--- /dev/null
+++ b/SabreTools.Models/BSP/FacesLump.cs
@@ -0,0 +1,31 @@
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// The face lump contains the surfaces of the scene.
+ ///
+ /// The first number of this data structure is an index into
+ /// the planes lump giving a plane which is parallel to this
+ /// face (meaning they share the same normal). The second
+ /// value may be seen as a boolean. If nPlaneSide equals 0,
+ /// then the normal vector of this face equals the one of the
+ /// parallel plane exactly. Otherwise, the normal of the plane
+ /// has to be multiplied by -1 to point into the right direction.
+ /// Afterwards we have an index into the surfedges lump, as
+ /// well as the count of consecutive surfedges from that position.
+ /// Furthermore there is an index into the texture info lump,
+ /// which is used to find the BSPTEXINFO structure needed to
+ /// calculate the texture coordinates for this face. Afterwards,
+ /// there are four bytes giving some lighting information (partly
+ /// used by the renderer to hide sky surfaces). Finally we have
+ /// an offset in byes giving the beginning of the binary lightmap
+ /// data of this face in the lighting lump.
+ ///
+ ///
+ public sealed class FacesLump : Lump
+ {
+ ///
+ /// Faces
+ ///
+ public Face[]? Faces { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/File.cs b/SabreTools.Models/BSP/File.cs
index d448759..2cc23bf 100644
--- a/SabreTools.Models/BSP/File.cs
+++ b/SabreTools.Models/BSP/File.cs
@@ -4,6 +4,7 @@ namespace SabreTools.Models.BSP
/// Half-Life Level
///
///
+ ///
public sealed class File
{
///
@@ -12,18 +13,9 @@ namespace SabreTools.Models.BSP
public Header? Header { get; set; }
///
- /// Lumps
+ /// Lump data
///
- public Lump?[]? Lumps { get; set; }
-
- ///
- /// Texture header data
- ///
- public TextureHeader? TextureHeader { get; set; }
-
- ///
- /// Textures
- ///
- public Texture?[]? Textures { get; set; }
+ /// 15 entries
+ public Lump[]? Lumps { get; set; } = new Lump[Constants.HEADER_LUMPS];
}
}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/Header.cs b/SabreTools.Models/BSP/Header.cs
index ddab40b..a776593 100644
--- a/SabreTools.Models/BSP/Header.cs
+++ b/SabreTools.Models/BSP/Header.cs
@@ -3,12 +3,20 @@ using System.Runtime.InteropServices;
namespace SabreTools.Models.BSP
{
///
+ ///
[StructLayout(LayoutKind.Sequential)]
public sealed class Header
{
///
/// Version
///
- public uint Version;
+ /// Must be 30 for a valid HL BSP file
+ public int Version;
+
+ ///
+ /// Lumps
+ ///
+ /// 15 entries
+ public LumpTableEntry[]? Lumps { get; set; }
}
}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/Leaf.cs b/SabreTools.Models/BSP/Leaf.cs
new file mode 100644
index 0000000..64f9219
--- /dev/null
+++ b/SabreTools.Models/BSP/Leaf.cs
@@ -0,0 +1,67 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// The leaves lump contains the leaves of the BSP tree.
+ ///
+ /// The first entry of this struct is the type of the content
+ /// of this leaf. It can be one of the predefined values, found
+ /// in the compiler source codes, and is litte relevant for the
+ /// actual rendering process. All the more important is the
+ /// next integer containing the offset into the vis lump. It
+ /// defines the start of the raw PVS data for this leaf. If this
+ /// value equals -1, no VIS lists are available for this leaf,
+ /// usually if the map has been built without the VIS compiler.
+ /// The next two 16bit integer triples span the bounding box of
+ /// this leaf. Furthermore, the struct contains an index pointing
+ /// into the array of marksurfaces loaded from the marksufaces
+ /// lump as well as the number of consecutive marksurfaces belonging
+ /// to this leaf. The marksurfaces are looped through during the
+ /// rendering process and point to the actual faces. The final 4 bytes
+ /// specify the volume of ambient sounds in Quake, but are unused in
+ /// GoldSrc.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class Leaf
+ {
+ ///
+ /// Contents enumeration
+ ///
+ public Contents Contents;
+
+ ///
+ /// Offset into the visibility lump
+ ///
+ public int VisOffset;
+
+ ///
+ /// Defines bounding box
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public short[] Mins = new short[3];
+
+ ///
+ /// Defines bounding box
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public short[] Maxs = new short[3];
+
+ ///
+ /// Index into marksurfaces array
+ ///
+ public ushort FirstMarkSurfaceIndex;
+
+ ///
+ /// Count of marksurfaces array
+ ///
+ public ushort MarkSurfacesCount;
+
+ ///
+ /// Ambient sound levels
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
+ public byte[]? AmbientLevels = new byte[4];
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/LeavesLump.cs b/SabreTools.Models/BSP/LeavesLump.cs
new file mode 100644
index 0000000..65eabf3
--- /dev/null
+++ b/SabreTools.Models/BSP/LeavesLump.cs
@@ -0,0 +1,31 @@
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// The leaves lump contains the leaves of the BSP tree.
+ ///
+ /// The first entry of this struct is the type of the content
+ /// of this leaf. It can be one of the predefined values, found
+ /// in the compiler source codes, and is litte relevant for the
+ /// actual rendering process. All the more important is the
+ /// next integer containing the offset into the vis lump. It
+ /// defines the start of the raw PVS data for this leaf. If this
+ /// value equals -1, no VIS lists are available for this leaf,
+ /// usually if the map has been built without the VIS compiler.
+ /// The next two 16bit integer triples span the bounding box of
+ /// this leaf. Furthermore, the struct contains an index pointing
+ /// into the array of marksurfaces loaded from the marksufaces
+ /// lump as well as the number of consecutive marksurfaces belonging
+ /// to this leaf. The marksurfaces are looped through during the
+ /// rendering process and point to the actual faces. The final 4 bytes
+ /// specify the volume of ambient sounds in Quake, but are unused in
+ /// GoldSrc.
+ ///
+ ///
+ public sealed class LeavesLump : Lump
+ {
+ ///
+ /// Leaves
+ ///
+ public Leaf[]? Leaves { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/LightmapLump.cs b/SabreTools.Models/BSP/LightmapLump.cs
new file mode 100644
index 0000000..12cf9d7
--- /dev/null
+++ b/SabreTools.Models/BSP/LightmapLump.cs
@@ -0,0 +1,18 @@
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// This is one of the largest lumps in the BSP file. The lightmap
+ /// lump stores all lightmaps used in the entire map. The lightmaps
+ /// are arrays of triples of bytes (3 channel color, RGB) and stored
+ /// continuously.
+ ///
+ ///
+ public sealed class LightmapLump : Lump
+ {
+ ///
+ /// Lightmap RGB values
+ ///
+ /// Array of 3-byte values
+ public byte[,]? Lightmap { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/Lump.cs b/SabreTools.Models/BSP/Lump.cs
index 253e253..6dd4e8f 100644
--- a/SabreTools.Models/BSP/Lump.cs
+++ b/SabreTools.Models/BSP/Lump.cs
@@ -1,19 +1,11 @@
-using System.Runtime.InteropServices;
-
namespace SabreTools.Models.BSP
{
- ///
- [StructLayout(LayoutKind.Sequential)]
- public sealed class Lump
+ ///
+ /// Represents a common Lump type
+ ///
+ ///
+ public abstract class Lump
{
- ///
- /// Offset
- ///
- public uint Offset;
-
- ///
- /// Length
- ///
- public uint Length;
+ // No shared fields between types
}
}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/LumpTableEntry.cs b/SabreTools.Models/BSP/LumpTableEntry.cs
new file mode 100644
index 0000000..875837e
--- /dev/null
+++ b/SabreTools.Models/BSP/LumpTableEntry.cs
@@ -0,0 +1,20 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Models.BSP
+{
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class LumpTableEntry
+ {
+ ///
+ /// File offset to data
+ ///
+ public int Offset;
+
+ ///
+ /// Length of data
+ ///
+ public int Length;
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/MarksurfacesLump.cs b/SabreTools.Models/BSP/MarksurfacesLump.cs
new file mode 100644
index 0000000..1fa00d6
--- /dev/null
+++ b/SabreTools.Models/BSP/MarksurfacesLump.cs
@@ -0,0 +1,19 @@
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// The marksurfaces lump is a simple array of short integers.
+ ///
+ /// This lump is a simple table for redirecting the marksurfaces
+ /// indexes in the leafs to the actial face indexes. A leaf inserts
+ /// it's marksurface indexes into this array and gets the associated
+ /// faces contained within this leaf.
+ ///
+ ///
+ public sealed class MarksurfacesLump : Lump
+ {
+ ///
+ /// Marksurfaces
+ ///
+ public ushort[]? Marksurfaces { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/MipTexture.cs b/SabreTools.Models/BSP/MipTexture.cs
new file mode 100644
index 0000000..7c53b1d
--- /dev/null
+++ b/SabreTools.Models/BSP/MipTexture.cs
@@ -0,0 +1,44 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// Each of this structs describes a texture. The name of the
+ /// texture is a string and may be 16 characters long (including
+ /// the null-character at the end, char equals a 8bit signed
+ /// integer). The name of the texture is needed, if the texture
+ /// has to be found and loaded from an external WAD file.
+ /// Furthermore, the struct contains the width and height of
+ /// the texture. The 4 offsets at the end can either be zero,
+ /// if the texture is stored in an external WAD file, or point
+ /// to the beginnings of the binary texture data within the
+ /// texture lump relative to the beginning of it's BSPMIPTEX struct.
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class MipTexture
+ {
+ ///
+ /// Name of texture
+ ///
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.MAXTEXTURENAME)]
+ public string? Name;
+
+ ///
+ /// Extends of the texture
+ ///
+ public uint Width;
+
+ ///
+ /// Extends of the texture
+ ///
+ public uint Height;
+
+ ///
+ /// Offsets to texture mipmaps BSPMIPTEX
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.MIPLEVELS)]
+ public uint[]? Offsets;
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/Model.cs b/SabreTools.Models/BSP/Model.cs
new file mode 100644
index 0000000..1cd65f8
--- /dev/null
+++ b/SabreTools.Models/BSP/Model.cs
@@ -0,0 +1,65 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// A model is kind of a mini BSP tree. Its size is determinded
+ /// by the bounding box spaned by the first to members of this
+ /// struct. The major difference between a model and the BSP
+ /// tree holding the scene is that the models use a local
+ /// coordinate system for their vertexes and just state its
+ /// origin in world coordinates. During rendering the coordinate
+ /// system is translated to the origin of the model (glTranslate())
+ /// and moved back after the models BSP tree has been traversed.
+ /// Furthermore their are 4 indexes into node arrays. The first
+ /// one has proofed to index the root node of the mini BSP tree
+ /// used for rendering. The other three indexes could probably be
+ /// used for collision detection, meaning they point into the
+ /// clipnodes, but I am not sure about this. The meaning of the
+ /// next value is also somehow unclear to me. Finally their are
+ /// direct indexes into the faces array, not taking the redirecting
+ /// by the marksurfaces.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class Model
+ {
+ ///
+ /// Defines bounding box
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public float[]? Mins = new float[3];
+
+ ///
+ /// Defines bounding box
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public float[]? Maxs = new float[3];
+
+ ///
+ /// Coordinates to move the coordinate system
+ ///
+ public Vector3D OriginVector;
+
+ ///
+ /// Index into nodes array
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.MAX_MAP_HULLS)]
+ public int[]? HeadnodesIndex = new int[Constants.MAX_MAP_HULLS];
+
+ ///
+ /// ???
+ ///
+ public int VisLeafsCount;
+
+ ///
+ /// Index into faces
+ ///
+ public int FirstFaceIndex;
+
+ ///
+ /// Count of faces
+ ///
+ public int FacesCount;
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/ModelsLump.cs b/SabreTools.Models/BSP/ModelsLump.cs
new file mode 100644
index 0000000..ac4874f
--- /dev/null
+++ b/SabreTools.Models/BSP/ModelsLump.cs
@@ -0,0 +1,29 @@
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// A model is kind of a mini BSP tree. Its size is determinded
+ /// by the bounding box spaned by the first to members of this
+ /// struct. The major difference between a model and the BSP
+ /// tree holding the scene is that the models use a local
+ /// coordinate system for their vertexes and just state its
+ /// origin in world coordinates. During rendering the coordinate
+ /// system is translated to the origin of the model (glTranslate())
+ /// and moved back after the models BSP tree has been traversed.
+ /// Furthermore their are 4 indexes into node arrays. The first
+ /// one has proofed to index the root node of the mini BSP tree
+ /// used for rendering. The other three indexes could probably be
+ /// used for collision detection, meaning they point into the
+ /// clipnodes, but I am not sure about this. The meaning of the
+ /// next value is also somehow unclear to me. Finally their are
+ /// direct indexes into the faces array, not taking the redirecting
+ /// by the marksurfaces.
+ ///
+ ///
+ public sealed class ModelsLump : Lump
+ {
+ ///
+ /// Model
+ ///
+ public Model[]? Models { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/Node.cs b/SabreTools.Models/BSP/Node.cs
new file mode 100644
index 0000000..9968b1c
--- /dev/null
+++ b/SabreTools.Models/BSP/Node.cs
@@ -0,0 +1,61 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// This lump is simple again and contains an array of binary
+ /// structures, the nodes, which are a major part of the BSP tree.
+ ///
+ /// Every BSPNODE structure represents a node in the BSP tree and
+ /// every node equals more or less a division step of the BSP algorithm.
+ /// Therefore, each node has an index (iPlane) referring to a plane
+ /// in the plane lump which devides the node into its two child nodes.
+ /// The childnodes are also stored as indexes. Contrary to the plane
+ /// index, the node index for the child is signed. If the index is
+ /// larger than 0, the index indicates a child node. If it is equal
+ /// to or smaller than zero (no valid array index), the bitwise
+ /// inversed value of the index gives an index into the leaves lump.
+ /// Additionally two points (nMins, nMaxs) span the bounding box
+ /// (AABB, axis aligned bounding box) delimitting the space of the node.
+ /// Finally firstFace indexes into the face lump and spezifies the
+ /// first of nFaces surfaces contained in this node.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class Node
+ {
+ ///
+ /// Index into Planes lump
+ ///
+ public uint PlaneIndex;
+
+ ///
+ /// If > 0, then indices into Nodes.
+ /// Otherwise bitwise inverse indices into Leafs
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+ public ushort[] Children = new ushort[2];
+
+ ///
+ /// Defines bounding box
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public ushort[] Mins = new ushort[3];
+
+ ///
+ /// Defines bounding box
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public ushort[] Maxs = new ushort[3];
+
+ ///
+ /// Index into Faces
+ ///
+ public ushort FirstFace;
+
+ ///
+ /// Count of Faces
+ ///
+ public ushort FaceCount;
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/NodesLump.cs b/SabreTools.Models/BSP/NodesLump.cs
new file mode 100644
index 0000000..8e3b1b2
--- /dev/null
+++ b/SabreTools.Models/BSP/NodesLump.cs
@@ -0,0 +1,29 @@
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// This lump is simple again and contains an array of binary
+ /// structures, the nodes, which are a major part of the BSP tree.
+ ///
+ /// Every BSPNODE structure represents a node in the BSP tree and
+ /// every node equals more or less a division step of the BSP algorithm.
+ /// Therefore, each node has an index (iPlane) referring to a plane
+ /// in the plane lump which devides the node into its two child nodes.
+ /// The childnodes are also stored as indexes. Contrary to the plane
+ /// index, the node index for the child is signed. If the index is
+ /// larger than 0, the index indicates a child node. If it is equal
+ /// to or smaller than zero (no valid array index), the bitwise
+ /// inversed value of the index gives an index into the leaves lump.
+ /// Additionally two points (nMins, nMaxs) span the bounding box
+ /// (AABB, axis aligned bounding box) delimitting the space of the node.
+ /// Finally firstFace indexes into the face lump and spezifies the
+ /// first of nFaces surfaces contained in this node.
+ ///
+ ///
+ public sealed class NodesLump : Lump
+ {
+ ///
+ /// Nodes
+ ///
+ public Node[]? Nodes { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/Plane.cs b/SabreTools.Models/BSP/Plane.cs
new file mode 100644
index 0000000..4aa5ac4
--- /dev/null
+++ b/SabreTools.Models/BSP/Plane.cs
@@ -0,0 +1,39 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// Each of this structures defines a plane in 3-dimensional
+ /// space by using the Hesse normal form: normal * point - distance = 0
+ ///
+ /// Where vNormal is the normalized normal vector of the plane
+ /// and fDist is the distance of the plane to the origin of
+ /// the coord system. Additionally, the structure also saves an
+ /// integer describing the orientation of the plane in space.
+ /// If nType equals PLANE_X, then the normal of the plane will
+ /// be parallel to the x axis, meaning the plane is perpendicular
+ /// to the x axis. If nType equals PLANE_ANYX, then the plane's
+ /// normal is nearer to the x axis then to any other axis.
+ /// This information is used by the renderer to speed up some
+ /// computations.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class Plane
+ {
+ ///
+ /// The planes normal vector
+ ///
+ public Vector3D NormalVector;
+
+ ///
+ /// Plane equation is: vNormal * X = fDist
+ ///
+ public float Distance;
+
+ ///
+ /// Plane type
+ ///
+ public PlaneType PlaneType;
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/PlaneLump.cs b/SabreTools.Models/BSP/PlaneLump.cs
new file mode 100644
index 0000000..d4c44bb
--- /dev/null
+++ b/SabreTools.Models/BSP/PlaneLump.cs
@@ -0,0 +1,15 @@
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// Each of this structures defines a plane in 3-dimensional
+ /// space by using the Hesse normal form: normal * point - distance = 0
+ ///
+ ///
+ public sealed class PlaneLump
+ {
+ ///
+ /// Planes
+ ///
+ public Plane[]? Planes { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/SurfedgesLump.cs b/SabreTools.Models/BSP/SurfedgesLump.cs
new file mode 100644
index 0000000..3cd1888
--- /dev/null
+++ b/SabreTools.Models/BSP/SurfedgesLump.cs
@@ -0,0 +1,21 @@
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// This lump represents pretty much the same mechanism as the marksurfaces.
+ /// A face can insert its surfedge indexes into this array to get the
+ /// corresponding edges delimitting the face and further pointing to the
+ /// vertexes, which are required for rendering. The index can be positive
+ /// or negative. If the value of the surfedge is positive, the first vertex
+ /// of the edge is used as vertex for rendering the face, otherwise, the
+ /// value is multiplied by -1 and the second vertex of the indexed edge is
+ /// used.
+ ///
+ ///
+ public sealed class SurfedgesLump : Lump
+ {
+ ///
+ /// Surfedges
+ ///
+ public int[]? Surfedges { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/Texinfo.cs b/SabreTools.Models/BSP/Texinfo.cs
new file mode 100644
index 0000000..1860400
--- /dev/null
+++ b/SabreTools.Models/BSP/Texinfo.cs
@@ -0,0 +1,52 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// The texinfo lump contains informations about how textures are
+ /// applied to surfaces. The lump itself is an array of binary data
+ /// structures.
+ ///
+ /// This struct is mainly responsible for the calculation of the texture
+ /// coordinates (vS, fSShift, vT, fTShift). This values determine the
+ /// position of the texture on the surface. The iMiptex integer refers
+ /// to the textures in the texture lump and would be the index in an
+ /// array of BSPMITEX structs. Finally, there are 4 Bytes used for flags.
+ /// Only one flag is used by the vanilla engine, being 0x1 for disabling
+ /// lightmaps and subdivision for the surface (used by sky and liquids).
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class Texinfo
+ {
+ ///
+ /// S-vector
+ ///
+ public Vector3D SVector;
+
+ ///
+ /// Texture shift in the S direction
+ ///
+ public float TextureSShift;
+
+ ///
+ /// T-vector
+ ///
+ public Vector3D TVector;
+
+ ///
+ /// Texture shift in the T direction
+ ///
+ public float TextureTShift;
+
+ ///
+ /// Index into textures array
+ ///
+ public uint MiptexIndex;
+
+ ///
+ /// Texture flags
+ ///
+ public TextureFlag Flags;
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/TexinfoLump.cs b/SabreTools.Models/BSP/TexinfoLump.cs
new file mode 100644
index 0000000..0583a33
--- /dev/null
+++ b/SabreTools.Models/BSP/TexinfoLump.cs
@@ -0,0 +1,24 @@
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// The texinfo lump contains informations about how textures are
+ /// applied to surfaces. The lump itself is an array of binary data
+ /// structures.
+ ///
+ /// This struct is mainly responsible for the calculation of the texture
+ /// coordinates (vS, fSShift, vT, fTShift). This values determine the
+ /// position of the texture on the surface. The iMiptex integer refers
+ /// to the textures in the texture lump and would be the index in an
+ /// array of BSPMITEX structs. Finally, there are 4 Bytes used for flags.
+ /// Only one flag is used by the vanilla engine, being 0x1 for disabling
+ /// lightmaps and subdivision for the surface (used by sky and liquids).
+ ///
+ ///
+ public sealed class TexinfoLump : Lump
+ {
+ ///
+ /// Texinfos
+ ///
+ public Texinfo[]? Texinfos { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/Texture.cs b/SabreTools.Models/BSP/Texture.cs
deleted file mode 100644
index abb2c89..0000000
--- a/SabreTools.Models/BSP/Texture.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-namespace SabreTools.Models.BSP
-{
- ///
- public sealed class Texture
- {
- ///
- /// Name
- ///
- public string? Name { get; set; }
-
- ///
- /// Width
- ///
- public uint Width { get; set; }
-
- ///
- /// Height
- ///
- public uint Height { get; set; }
-
- ///
- /// Offsets
- ///
- public uint[]? Offsets { get; set; }
-
- ///
- /// Texture data
- ///
- public byte[]? TextureData { get; set; }
-
- ///
- /// Palette size
- ///
- public uint PaletteSize { get; set; }
-
- ///
- /// Palette data
- ///
- public byte[]? PaletteData { get; set; }
- }
-}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/TextureHeader.cs b/SabreTools.Models/BSP/TextureHeader.cs
index b9ec245..4d82b16 100644
--- a/SabreTools.Models/BSP/TextureHeader.cs
+++ b/SabreTools.Models/BSP/TextureHeader.cs
@@ -1,17 +1,18 @@
namespace SabreTools.Models.BSP
{
///
+ ///
public sealed class TextureHeader
{
///
- /// Texture count
+ /// Number of BSPMIPTEX structures
///
- public uint TextureCount { get; set; }
+ public uint MipTextureCount { get; set; }
///
/// Offsets
///
- /// TextureCount entries
- public uint[]? Offsets { get; set; }
+ /// entries
+ public int[]? Offsets { get; set; }
}
}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/TextureLump.cs b/SabreTools.Models/BSP/TextureLump.cs
new file mode 100644
index 0000000..1d77061
--- /dev/null
+++ b/SabreTools.Models/BSP/TextureLump.cs
@@ -0,0 +1,16 @@
+namespace SabreTools.Models.BSP
+{
+ ///
+ public sealed class TextureLump : Lump
+ {
+ ///
+ /// Texture header data
+ ///
+ public TextureHeader? Header { get; set; }
+
+ ///
+ /// Textures
+ ///
+ public MipTexture[]? Textures { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/Vector3D.cs b/SabreTools.Models/BSP/Vector3D.cs
new file mode 100644
index 0000000..49cac66
--- /dev/null
+++ b/SabreTools.Models/BSP/Vector3D.cs
@@ -0,0 +1,17 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// There is a common struct used to represent a point in
+ /// 3-dimensional space which is used throughout the file
+ /// spec and the code of the hlbsp project.
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Vector3D
+ {
+ public float X { get; set; }
+ public float Y { get; set; }
+ public float Z { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/VerticesLump.cs b/SabreTools.Models/BSP/VerticesLump.cs
new file mode 100644
index 0000000..c89b6c9
--- /dev/null
+++ b/SabreTools.Models/BSP/VerticesLump.cs
@@ -0,0 +1,15 @@
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// This lump simply consists of all vertices of the BSP tree.
+ /// They are stored as a primitve array of triples of floats.
+ ///
+ ///
+ public sealed class VerticesLump : Lump
+ {
+ ///
+ /// Vertices
+ ///
+ public Vector3D[]? Vertices { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/BSP/VisibilityLump.cs b/SabreTools.Models/BSP/VisibilityLump.cs
new file mode 100644
index 0000000..b648517
--- /dev/null
+++ b/SabreTools.Models/BSP/VisibilityLump.cs
@@ -0,0 +1,18 @@
+namespace SabreTools.Models.BSP
+{
+ ///
+ /// The VIS lump contains data, which is irrelevant to the actual
+ /// BSP tree, but offers a way to boost up the speed of the
+ /// renderer significantly. Especially complex maps profit from
+ /// the use if this data. This lump contains the so-called
+ /// Potentially Visible Sets (PVS) (also called VIS lists) in the
+ /// same amout of leaves of the tree, the user can enter (often
+ /// referred to as VisLeaves). The visiblilty lists are stored as
+ /// sequences of bitfields, which are run-length encoded.
+ ///
+ ///
+ public sealed class VisibilityLump
+ {
+ public byte[]? Data { get; set; }
+ }
+}
\ No newline at end of file