diff --git a/SabreTools.Models/BSP/AmbientIndexLump.cs b/SabreTools.Models/BSP/AmbientIndexLump.cs new file mode 100644 index 0000000..a7b6fd4 --- /dev/null +++ b/SabreTools.Models/BSP/AmbientIndexLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class AmbientIndexLump : Lump + { + /// + /// Indicies + /// + public LeafAmbientIndex[]? Indicies { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/AmbientLightingLump.cs b/SabreTools.Models/BSP/AmbientLightingLump.cs new file mode 100644 index 0000000..1f764a0 --- /dev/null +++ b/SabreTools.Models/BSP/AmbientLightingLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class AmbientLightingLump : Lump + { + /// + /// Lightings + /// + public LeafAmbientLighting[]? Lightings { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/Brush.cs b/SabreTools.Models/BSP/Brush.cs new file mode 100644 index 0000000..e3db6c5 --- /dev/null +++ b/SabreTools.Models/BSP/Brush.cs @@ -0,0 +1,33 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// The brush lump (Lump 18) contains all brushes that were + /// present in the original VMF file before compiling. + /// Unlike faces, brushes are constructive solid geometry (CSG) + /// defined by planes instead of edges and vertices. It is the + /// presence of the brush and brushside lumps in Source BSP + /// files that makes decompiling them a much easier job than + /// for GoldSrc files, which lacked this info. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class Brush + { + /// + /// First brushside + /// + public int FirstSide; + + /// + /// Number of brushsides + /// + public int NumSides; + + /// + /// Contents flags + /// + public VbspContents Contents; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/BrushesLump.cs b/SabreTools.Models/BSP/BrushesLump.cs new file mode 100644 index 0000000..f11807f --- /dev/null +++ b/SabreTools.Models/BSP/BrushesLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class BrushesLump : Lump + { + /// + /// Brushes + /// + public Brush[]? Brushes { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/Brushside.cs b/SabreTools.Models/BSP/Brushside.cs new file mode 100644 index 0000000..5281a87 --- /dev/null +++ b/SabreTools.Models/BSP/Brushside.cs @@ -0,0 +1,48 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// Planenum is an index info the plane array, giving the plane + /// corresponding to this brushside. Texinfo and dispinfo are + /// references into the texture and displacement info lumps. + /// Bevel is zero for normal brush sides, but 1 if the side is + /// a bevel plane (which seem to be used for collision detection). + /// + /// Unlike the face array, brushsides are not culled (removed) + /// where they touch the void. Void-facing sides do however have + /// their texinfo entry changed to the tools/toolsnodraw texture + /// during the compile process. Note there is no direct way of + /// linking brushes and brushsides and the corresponding face array + /// entries which are used to render that brush. Brushsides are + /// used by the engine to calculate all player physics collision + /// with world brushes. (Vphysics objects use lump 29 instead.) + /// + /// The maximum number of brushsides is 65536 (MAX_MAP_BRUSHSIDES). + /// The maximum number of brushsides on a single brush is 128 (MAX_BRUSH_SIDES). + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class Brushside + { + /// + /// Facing out of the leaf + /// + public ushort PlaneNum; + + /// + /// Texture info + /// + public short TextureInfo; + + /// + /// Displacement info + /// + public short DisplacementInfo; + + /// + /// Is the side a bevel plane? + /// + public short Bevel; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/BrushsidesLump.cs b/SabreTools.Models/BSP/BrushsidesLump.cs new file mode 100644 index 0000000..1bf1a4d --- /dev/null +++ b/SabreTools.Models/BSP/BrushsidesLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class BrushsidesLump : Lump + { + /// + /// Brushsides + /// + public Brushside[]? Brushsides { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/Face.cs b/SabreTools.Models/BSP/BspFace.cs similarity index 97% rename from SabreTools.Models/BSP/Face.cs rename to SabreTools.Models/BSP/BspFace.cs index 6f77968..543f1ed 100644 --- a/SabreTools.Models/BSP/Face.cs +++ b/SabreTools.Models/BSP/BspFace.cs @@ -24,7 +24,7 @@ namespace SabreTools.Models.BSP /// /// [StructLayout(LayoutKind.Sequential)] - public sealed class Face + public sealed class BspFace { /// /// Plane the face is parallel to @@ -61,6 +61,6 @@ namespace SabreTools.Models.BSP /// Offsets into the raw lightmap data; if less than zero, /// then a lightmap was not baked for the given face. /// - public int LightmapOffsetCount; + public int LightmapOffset; } } \ No newline at end of file diff --git a/SabreTools.Models/BSP/BspFacesLump.cs b/SabreTools.Models/BSP/BspFacesLump.cs new file mode 100644 index 0000000..cb52c83 --- /dev/null +++ b/SabreTools.Models/BSP/BspFacesLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class BspFacesLump : Lump + { + /// + /// Faces + /// + public BspFace[]? Faces { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/BspFile.cs b/SabreTools.Models/BSP/BspFile.cs new file mode 100644 index 0000000..e86992a --- /dev/null +++ b/SabreTools.Models/BSP/BspFile.cs @@ -0,0 +1,89 @@ +namespace SabreTools.Models.BSP +{ + /// + /// Half-Life Level + /// + /// + /// + public sealed class BspFile + { + /// + /// Header data + /// + public BspHeader? Header { get; set; } + + #region Lumps + + /// + /// LUMP_ENTITIES [0] + /// + public EntitiesLump? Entities { get; set; } + + /// + /// LUMP_PLANES [1] + /// + public PlanesLump? PlanesLump { get; set; } + + /// + /// LUMP_TEXTURES [2] + /// + public TextureLump? TextureLump { get; set; } + + /// + /// LUMP_VERTICES [3] + /// + public VerticesLump? VerticesLump { get; set; } + + /// + /// LUMP_NODES [5] + /// + public BspNodesLump? NodesLump { get; set; } + + /// + /// LUMP_TEXINFO [6] + /// + public BspTexinfoLump? TexinfoLump { get; set; } + + /// + /// LUMP_FACES [7] + /// + public BspFacesLump? FacesLump { get; set; } + + /// + /// LUMP_LIGHTING [8] + /// + public LightmapLump? LightmapLump { get; set; } + + /// + /// LUMP_CLIPNODES [9] + /// s + public ClipnodesLump? ClipnodesLump { get; set; } + + /// + /// LUMP_LEAVES [10] + /// + public BspLeavesLump? LeavesLump { get; set; } + + /// + /// LUMP_MARKSURFACES [11] + /// + public MarksurfacesLump? MarksurfacesLump { get; set; } + + /// + /// LUMP_EDGES [12] + /// + public EdgesLump? EdgesLump { get; set; } + + /// + /// LUMP_SURFEDGES [13] + /// + public SurfedgesLump? SurfedgesLump { get; set; } + + /// + /// LUMP_MODELS [14] + /// + public BspModelsLump? ModelsLump { get; set; } + + #endregion + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/Header.cs b/SabreTools.Models/BSP/BspHeader.cs similarity index 86% rename from SabreTools.Models/BSP/Header.cs rename to SabreTools.Models/BSP/BspHeader.cs index a776593..19fd419 100644 --- a/SabreTools.Models/BSP/Header.cs +++ b/SabreTools.Models/BSP/BspHeader.cs @@ -5,7 +5,7 @@ namespace SabreTools.Models.BSP /// /// [StructLayout(LayoutKind.Sequential)] - public sealed class Header + public sealed class BspHeader { /// /// Version @@ -17,6 +17,6 @@ namespace SabreTools.Models.BSP /// Lumps /// /// 15 entries - public LumpTableEntry[]? Lumps { get; set; } + public BspLumpEntry[]? Lumps { get; set; } } } \ No newline at end of file diff --git a/SabreTools.Models/BSP/Leaf.cs b/SabreTools.Models/BSP/BspLeaf.cs similarity index 97% rename from SabreTools.Models/BSP/Leaf.cs rename to SabreTools.Models/BSP/BspLeaf.cs index 64f9219..d70cad5 100644 --- a/SabreTools.Models/BSP/Leaf.cs +++ b/SabreTools.Models/BSP/BspLeaf.cs @@ -24,12 +24,12 @@ namespace SabreTools.Models.BSP /// /// [StructLayout(LayoutKind.Sequential)] - public sealed class Leaf + public sealed class BspLeaf { /// /// Contents enumeration /// - public Contents Contents; + public BspContents Contents; /// /// Offset into the visibility lump diff --git a/SabreTools.Models/BSP/BspLeavesLump.cs b/SabreTools.Models/BSP/BspLeavesLump.cs new file mode 100644 index 0000000..e51a2f1 --- /dev/null +++ b/SabreTools.Models/BSP/BspLeavesLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class BspLeavesLump : Lump + { + /// + /// Leaves + /// + public BspLeaf[]? Leaves { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/LumpTableEntry.cs b/SabreTools.Models/BSP/BspLumpEntry.cs similarity index 92% rename from SabreTools.Models/BSP/LumpTableEntry.cs rename to SabreTools.Models/BSP/BspLumpEntry.cs index 875837e..7c6b89b 100644 --- a/SabreTools.Models/BSP/LumpTableEntry.cs +++ b/SabreTools.Models/BSP/BspLumpEntry.cs @@ -5,7 +5,7 @@ namespace SabreTools.Models.BSP /// /// [StructLayout(LayoutKind.Sequential)] - public sealed class LumpTableEntry + public class BspLumpEntry { /// /// File offset to data diff --git a/SabreTools.Models/BSP/Model.cs b/SabreTools.Models/BSP/BspModel.cs similarity index 89% rename from SabreTools.Models/BSP/Model.cs rename to SabreTools.Models/BSP/BspModel.cs index 1cd65f8..af9b0b9 100644 --- a/SabreTools.Models/BSP/Model.cs +++ b/SabreTools.Models/BSP/BspModel.cs @@ -22,19 +22,17 @@ namespace SabreTools.Models.BSP /// /// [StructLayout(LayoutKind.Sequential)] - public sealed class Model + public sealed class BspModel { /// /// Defines bounding box /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public float[]? Mins = new float[3]; + public Vector3D Mins; /// /// Defines bounding box /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public float[]? Maxs = new float[3]; + public Vector3D Maxs; /// /// Coordinates to move the coordinate system diff --git a/SabreTools.Models/BSP/BspModelsLump.cs b/SabreTools.Models/BSP/BspModelsLump.cs new file mode 100644 index 0000000..7817973 --- /dev/null +++ b/SabreTools.Models/BSP/BspModelsLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class BspModelsLump : Lump + { + /// + /// Model + /// + public BspModel[]? Models { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/Node.cs b/SabreTools.Models/BSP/BspNode.cs similarity index 95% rename from SabreTools.Models/BSP/Node.cs rename to SabreTools.Models/BSP/BspNode.cs index 9968b1c..e5e027c 100644 --- a/SabreTools.Models/BSP/Node.cs +++ b/SabreTools.Models/BSP/BspNode.cs @@ -21,8 +21,9 @@ namespace SabreTools.Models.BSP /// first of nFaces surfaces contained in this node. /// /// + /// [StructLayout(LayoutKind.Sequential)] - public sealed class Node + public class BspNode { /// /// Index into Planes lump diff --git a/SabreTools.Models/BSP/BspNodesLump.cs b/SabreTools.Models/BSP/BspNodesLump.cs new file mode 100644 index 0000000..26a09d5 --- /dev/null +++ b/SabreTools.Models/BSP/BspNodesLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class BspNodesLump : Lump + { + /// + /// Nodes + /// + public BspNode[]? Nodes { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/Texinfo.cs b/SabreTools.Models/BSP/BspTexinfo.cs similarity index 97% rename from SabreTools.Models/BSP/Texinfo.cs rename to SabreTools.Models/BSP/BspTexinfo.cs index 1860400..c739cc3 100644 --- a/SabreTools.Models/BSP/Texinfo.cs +++ b/SabreTools.Models/BSP/BspTexinfo.cs @@ -17,7 +17,7 @@ namespace SabreTools.Models.BSP /// /// [StructLayout(LayoutKind.Sequential)] - public sealed class Texinfo + public sealed class BspTexinfo { /// /// S-vector diff --git a/SabreTools.Models/BSP/BspTexinfoLump.cs b/SabreTools.Models/BSP/BspTexinfoLump.cs new file mode 100644 index 0000000..fe4ad5c --- /dev/null +++ b/SabreTools.Models/BSP/BspTexinfoLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class BspTexinfoLump : Lump + { + /// + /// Texinfos + /// + public BspTexinfo[]? Texinfos { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/CDispCornerNeighbors.cs b/SabreTools.Models/BSP/CDispCornerNeighbors.cs new file mode 100644 index 0000000..ba286dc --- /dev/null +++ b/SabreTools.Models/BSP/CDispCornerNeighbors.cs @@ -0,0 +1,17 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class CDispCornerNeighbors + { + /// + /// Indices of neighbors. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public ushort[] Neighbors = new ushort[4]; + + public byte NeighborCount; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/CDispNeighbor.cs b/SabreTools.Models/BSP/CDispNeighbor.cs new file mode 100644 index 0000000..416188e --- /dev/null +++ b/SabreTools.Models/BSP/CDispNeighbor.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class CDispNeighbor + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public CDispSubNeighbor[]? SubNeighbors = new CDispSubNeighbor[2]; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/CDispSubNeighbor.cs b/SabreTools.Models/BSP/CDispSubNeighbor.cs new file mode 100644 index 0000000..2a2fd28 --- /dev/null +++ b/SabreTools.Models/BSP/CDispSubNeighbor.cs @@ -0,0 +1,32 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class CDispSubNeighbor + { + /// + /// This indexes into ddispinfos. + /// + /// 0xFFFF if there is no neighbor here. + public ushort NeighborIndex; + + /// + /// (CCW) rotation of the neighbor wrt this displacement. + /// + public byte NeighborOrientation; + + // These use the NeighborSpan type. + + /// + /// Where the neighbor fits onto this side of our displacement. + /// + public byte Span; + + /// + /// Where we fit onto our neighbor. + /// + public byte NeighborSpan; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/ClipnodesLump.cs b/SabreTools.Models/BSP/ClipnodesLump.cs index 13d8dde..70f8f51 100644 --- a/SabreTools.Models/BSP/ClipnodesLump.cs +++ b/SabreTools.Models/BSP/ClipnodesLump.cs @@ -1,13 +1,5 @@ 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 { diff --git a/SabreTools.Models/BSP/ColorRGBExp32.cs b/SabreTools.Models/BSP/ColorRGBExp32.cs new file mode 100644 index 0000000..a991ea0 --- /dev/null +++ b/SabreTools.Models/BSP/ColorRGBExp32.cs @@ -0,0 +1,20 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// 4-byte lightmap structure + /// + /// + [StructLayout(LayoutKind.Sequential)] + public struct ColorRGBExp32 + { + public byte Red; + + public byte Green; + + public byte Blue; + + public sbyte Exponent; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/CompressedLightCube.cs b/SabreTools.Models/BSP/CompressedLightCube.cs new file mode 100644 index 0000000..b0ab729 --- /dev/null +++ b/SabreTools.Models/BSP/CompressedLightCube.cs @@ -0,0 +1,16 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// The lighting data for each sample is represented by an array + /// of 6 ColorRGBExp32 + /// + /// + [StructLayout(LayoutKind.Sequential)] + public struct CompressedLightCube + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public ColorRGBExp32[]? Colors; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/Constants.cs b/SabreTools.Models/BSP/Constants.cs index a7de4cf..78ca0e6 100644 --- a/SabreTools.Models/BSP/Constants.cs +++ b/SabreTools.Models/BSP/Constants.cs @@ -1,6 +1,7 @@ namespace SabreTools.Models.BSP { /// + /// public static class Constants { #region Header @@ -8,7 +9,12 @@ namespace SabreTools.Models.BSP /// /// Number of lumps in a BSP /// - public const int HEADER_LUMPS = 15; + public const int BSP_HEADER_LUMPS = 15; + + /// + /// Number of lumps in a VBSP + /// + public const int VBSP_HEADER_LUMPS = 64; #endregion @@ -55,5 +61,40 @@ namespace SabreTools.Models.BSP public const int MIPLEVELS = 4; #endregion + + #region VBSP + + public static readonly byte[] SignatureBytes = [0x56, 0x42, 0x53, 0x50]; + + public const string SignatureString = "VBSP"; + + public const uint SignatureUInt32 = 0x50534256; + + #endregion + + #region LZMA + + public static readonly byte[] LzmaHeaderBytes = [0x4C, 0x5A, 0x4D, 0x41]; + + public const string LzmaHeaderString = "LZMA"; + + public const uint LzmaHeaderUInt32 = 0x414D5A4C; + + #endregion + + #region Overlay + + public const int OVERLAY_BSP_FACE_COUNT = 64; + + #endregion + + #region Worldlights + + /// + /// This says that the light was put into the per-leaf ambient cubes. + /// + public const int DWL_FLAGS_INAMBIENTCUBE = 0x0001; + + #endregion } } \ No newline at end of file diff --git a/SabreTools.Models/BSP/Cubemap.cs b/SabreTools.Models/BSP/Cubemap.cs new file mode 100644 index 0000000..a79bd3d --- /dev/null +++ b/SabreTools.Models/BSP/Cubemap.cs @@ -0,0 +1,50 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// The dcubemapsample_t structure defines the location of a + /// env_cubemap entity in the map. The origin member contains + /// integer x,y,z coordinates of the cubemap, and the size member + /// is resolution of the cubemap, specified as 2^(size-1) pixels + /// square. If set as 0, the default size of 6 (32x32 pixels) is + /// used. There can be a maximum of 1024 (MAX_MAP_CUBEMAPSAMPLES) + /// cubemaps in a file. + /// + /// When the "buildcubemaps" console command is performed, six + /// snapshots of the map (one for each direction) are taken at the + /// location of each env_cubemap entity. These snapshots are stored + /// in a multi-frame texture (vtf) file, which is added to the + /// Pakfile lump (see above). The textures are named cX_Y_Z.vtf, + /// where (X,Y,Z) are the (integer) coordinates of the corresponding + /// cubemap. + /// + /// Faces containing materials that are environment mapped (e.g. + /// shiny textures) reference their assigned cubemap through their + /// material name. A face with a material named (e.g.) walls/shiny.vmt + /// is altered (new Texinfo & Texdata entries are created) to refer + /// to a renamed material maps/mapname/walls/shiny_X_Y_Z.vmt, where + /// (X,Y,Z) are the cubemap coordinates as before. This .vmt file + /// is also stored in the Pakfile, and references the cubemap .vtf + /// file through its $envmap property. + /// + /// Version 20 files contain extra cX_Y_Z.hdr.vtf files in the + /// Pakfile lump, containing HDR texture files in RGBA16161616F + /// (16-bit per channel) format. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class Cubemap + { + /// + /// Position of light snapped to the nearest integer + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public int[]? Origin = new int[3]; + + /// + /// Resolution of cubemap, 0 - default + /// + public int Size; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/CubemapsLump.cs b/SabreTools.Models/BSP/CubemapsLump.cs new file mode 100644 index 0000000..f2299d6 --- /dev/null +++ b/SabreTools.Models/BSP/CubemapsLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class CubemapsLump : Lump + { + /// + /// Cubemaps + /// + public Cubemap[]? Cubemaps { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/DispInfo.cs b/SabreTools.Models/BSP/DispInfo.cs new file mode 100644 index 0000000..fe50a4c --- /dev/null +++ b/SabreTools.Models/BSP/DispInfo.cs @@ -0,0 +1,93 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// The structure is 176 bytes long. The startPosition element is the + /// coordinates of the first corner of the displacement. DispVertStart + /// and DispTriStart are indices into the DispVerts and DispTris lumps. + /// The power entry gives the number of subdivisions in the displacement + /// surface - allowed values are 2, 3 and 4, and these correspond to 4, + /// 8 and 16 subdivisions on each side of the displacement surface. + /// The structure also references any neighbouring displacements on the + /// sides or the corners of this displacement through the EdgeNeighbors + /// and CornerNeighbors members. There are complex rules governing the + /// order that these neighbour displacements are given; see the comments + /// in bspfile.h for more. The MapFace value is an index into the face + /// array and is face that was turned into a displacement surface. + /// This face is used to set the texture and overall physical location + /// and boundaries of the displacement. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class DispInfo + { + /// + /// Start position used for orientation + /// + public Vector3D startPosition; + + /// + /// Index into LUMP_DISP_VERTS. + /// + public int DispVertStart; + + /// + /// Index into LUMP_DISP_TRIS. + /// + public int DispTriStart; + + /// + /// Power - indicates size of surface (2^power 1) + /// + public int Power; + + /// + /// Minimum tesselation allowed + /// + public int MinTess; + + /// + /// Lighting smoothing angle + /// + public float SmoothingAngle; + + /// + /// Surface contents + /// + public int Contents; + + /// + /// Which map face this displacement comes from. + /// + public ushort MapFace; + + /// + /// Index into ddisplightmapalpha. + /// + public int LightmapAlphaStart; + + /// + /// Index into LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS. + /// + public int LightmapSamplePositionStart; + + /// + /// Indexed by NEIGHBOREDGE_ defines. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public CDispNeighbor[]? EdgeNeighbors = new CDispNeighbor[4]; + + /// + /// Indexed by CORNER_ defines. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public CDispCornerNeighbors[]? CornerNeighbors = new CDispCornerNeighbors[4]; + + /// + /// Active verticies + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public uint[]? AllowedVerts = new uint[10]; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/DispInfosLump.cs b/SabreTools.Models/BSP/DispInfosLump.cs new file mode 100644 index 0000000..216c7ba --- /dev/null +++ b/SabreTools.Models/BSP/DispInfosLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class DispInfosLump : Lump + { + /// + /// Infos + /// + public DispInfo[]? Infos { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/DispTri.cs b/SabreTools.Models/BSP/DispTri.cs new file mode 100644 index 0000000..56444a4 --- /dev/null +++ b/SabreTools.Models/BSP/DispTri.cs @@ -0,0 +1,19 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// he DispTris lump (Lump 48) contains "triangle tags" or flags + /// related to the properties of a particular triangle in the + /// displacement mesh. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class DispTri + { + /// + /// Displacement triangle tags. + /// + public DispTriTag Tags; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/DispTrisLump.cs b/SabreTools.Models/BSP/DispTrisLump.cs new file mode 100644 index 0000000..511f45e --- /dev/null +++ b/SabreTools.Models/BSP/DispTrisLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class DispTrisLump : Lump + { + /// + /// Tris + /// + public DispTri[]? Tris { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/DispVert.cs b/SabreTools.Models/BSP/DispVert.cs new file mode 100644 index 0000000..c30fbc9 --- /dev/null +++ b/SabreTools.Models/BSP/DispVert.cs @@ -0,0 +1,33 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// The DispVerts lump (Lump 33) contains the vertex data of the displacements. + /// vec is the normalized vector of the offset of each displacement vertex from + /// its original (flat) position; dist is the distance the offset has taken + /// place; and alpha is the alpha-blending of the texture at that vertex. + /// + /// A displacement of power p references (2^p + 1)^2 dispverts in the array, + /// starting from the DispVertStart index. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class DispVert + { + /// + /// Vector field defining displacement volume. + /// + public Vector3D Vec; + + /// + /// Displacement distances. + /// + public float Dist; + + /// + /// "Per vertex" alpha values. + /// + public float Alpha; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/DispVertsLump.cs b/SabreTools.Models/BSP/DispVertsLump.cs new file mode 100644 index 0000000..d4d5597 --- /dev/null +++ b/SabreTools.Models/BSP/DispVertsLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class DispVertsLump : Lump + { + /// + /// Verts + /// + public DispVert[]? Verts { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/Edge.cs b/SabreTools.Models/BSP/Edge.cs index c449d52..db50752 100644 --- a/SabreTools.Models/BSP/Edge.cs +++ b/SabreTools.Models/BSP/Edge.cs @@ -7,6 +7,7 @@ namespace SabreTools.Models.BSP /// face. Each edge is pointing to the start and end vertex of the edge. /// /// + /// [StructLayout(LayoutKind.Sequential)] public sealed class Edge { diff --git a/SabreTools.Models/BSP/EdgesLump.cs b/SabreTools.Models/BSP/EdgesLump.cs index 8b35925..e39d8dd 100644 --- a/SabreTools.Models/BSP/EdgesLump.cs +++ b/SabreTools.Models/BSP/EdgesLump.cs @@ -1,10 +1,7 @@ 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 { /// diff --git a/SabreTools.Models/BSP/EntitiesLump.cs b/SabreTools.Models/BSP/EntitiesLump.cs new file mode 100644 index 0000000..89a1b8f --- /dev/null +++ b/SabreTools.Models/BSP/EntitiesLump.cs @@ -0,0 +1,12 @@ +namespace SabreTools.Models.BSP +{ + /// + /// + public sealed class EntitiesLump : Lump + { + /// + /// Entities + /// + public Entity[]? Entities { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/Entity.cs b/SabreTools.Models/BSP/Entity.cs index fe3631a..0bdf8ba 100644 --- a/SabreTools.Models/BSP/Entity.cs +++ b/SabreTools.Models/BSP/Entity.cs @@ -17,6 +17,7 @@ namespace SabreTools.Models.BSP /// interpreted by the engine. /// /// + /// public sealed class Entity { /// diff --git a/SabreTools.Models/BSP/EntityLump.cs b/SabreTools.Models/BSP/EntityLump.cs deleted file mode 100644 index 8bba1b5..0000000 --- a/SabreTools.Models/BSP/EntityLump.cs +++ /dev/null @@ -1,25 +0,0 @@ -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 index d853e44..bd35f9e 100644 --- a/SabreTools.Models/BSP/Enums.cs +++ b/SabreTools.Models/BSP/Enums.cs @@ -3,7 +3,7 @@ using System; namespace SabreTools.Models.BSP { /// - public enum Contents : int + public enum BspContents : int { CONTENTS_EMPTY = -1, CONTENTS_SOLID = -2, @@ -22,9 +22,257 @@ namespace SabreTools.Models.BSP CONTENTS_TRANSLUCENT = -15, } + /// + [Flags] + public enum VbspContents : uint + { + /// + /// No contents + /// + CONTENTS_EMPTY = 0x00000000, + + /// + /// An eye is never valid in a solid + /// + CONTENTS_SOLID = 0x00000001, + + /// + /// Translucent, but not watery (glass) + /// + CONTENTS_WINDOW = 0x00000002, + + /// + /// Unused + /// + CONTENTS_AUX = 0x00000004, + + /// + /// Alpha-tested "grate" textures. Bullets/sight pass through, + /// but solids don't + /// + CONTENTS_GRATE = 0x00000008, + + /// + /// Set via %CompileSlime. Unlike Quake II, slime does not do + /// damage; a separate trigger_hurt should be used for this. + /// + CONTENTS_SLIME = 0x00000010, + + /// + /// Set via %CompileWater. + /// + CONTENTS_WATER = 0x00000020, + + /// + /// Unknown purpose; only set by %CompilePlayerControlClip. + /// + CONTENTS_MIST = 0x00000040, + + /// + /// Block AI line of sight + /// + CONTENTS_BLOCKLOS = 0x00000040, + + /// + /// Things that cannot be seen through (may be non-solid though) + /// + CONTENTS_OPAQUE = 0x00000080, + + /// + /// Unknown + /// + CONTENTS_TESTFOGVOLUME = 0x00000100, + + /// + /// Unused + /// + CONTENTS_UNUSED = 0x00000200, + + /// + /// Unused + /// + CONTENTS_UNUSED6 = 0x00000400, + + /// + /// If it's visible, grab from the top + update LAST_VISIBLE_CONTENTS + /// if not visible, then grab from the bottom. + /// + CONTENTS_BLOCKLIGHT = 0x00000400, + + /// + /// Per team contents used to differentiate collisions + /// between players and objects on different teams + /// + CONTENTS_TEAM1 = 0x00000800, + + /// + /// Per team contents used to differentiate collisions + /// between players and objects on different teams + /// + CONTENTS_TEAM2 = 0x00001000, + + /// + /// Ignore CONTENTS_OPAQUE on surfaces that have SURF_NODRAW + /// + CONTENTS_IGNORE_NODRAW_OPAQUE = 0x00002000, + + /// + /// Hits entities which are MOVETYPE_PUSH (doors, plats, etc.) + /// + CONTENTS_MOVEABLE = 0x00004000, + + /// + /// Is an areaportal. + /// + CONTENTS_AREAPORTAL = 0x00008000, + + /// + /// Solid to players, including bots. + /// + CONTENTS_PLAYERCLIP = 0x00010000, + + /// + /// Solid to monsters, better known in Source as NPCs. Also solid + /// to bots in CSGO, even though they are players. + /// + CONTENTS_MONSTERCLIP = 0x00020000, + + /// + /// Currents can be added to any other contents, and may be mixed + /// + CONTENTS_CURRENT_0 = 0x00040000, + + /// + /// Currents can be added to any other contents, and may be mixed + /// + CONTENTS_CURRENT_90 = 0x00080000, + + /// + /// Currents can be added to any other contents, and may be mixed + /// + CONTENTS_CURRENT_180 = 0x00100000, + + /// + /// Currents can be added to any other contents, and may be mixed + /// + CONTENTS_CURRENT_270 = 0x00200000, + + /// + /// Currents can be added to any other contents, and may be mixed + /// + CONTENTS_CURRENT_UP = 0x00400000, + + /// + /// Currents can be added to any other contents, and may be mixed + /// + CONTENTS_CURRENT_DOWN = 0x00800000, + + /// + /// Unknown + /// + CONTENTS_BRUSH_PAINT = 0x00040000, + + /// + /// Unknown + /// + CONTENTS_GRENADECLIP = 0x00080000, + + /// + /// Unknown + /// + CONTENTS_DRONECLIP = 0x00100000, + + /// + /// Removed before bsping an entity + /// + CONTENTS_ORIGIN = 0x01000000, + + /// + /// Should never be on a brush, only in game + /// + CONTENTS_MONSTER = 0x02000000, + + /// + /// Solid to point traces (ex hitscan weapons) and non-debris + /// physics objects[confirm]. Non-solid to QPhysics entities, + /// such as players. + /// + CONTENTS_DEBRIS = 0x04000000, + + /// + /// Brushes to be added after vis leafs + /// + CONTENTS_DETAIL = 0x08000000, + + /// + /// Auto set if any surface has trans + /// + CONTENTS_TRANSLUCENT = 0x10000000, + + /// + /// Is a ladder + /// + CONTENTS_LADDER = 0x20000000, + + /// + /// Use accurate hitboxes on trace + /// + CONTENTS_HITBOX = 0x40000000, + } + + /// + [Flags] + public enum DispTriTag : ushort + { + DISPTRI_TAG_SURFACE = 0x01, + DISPTRI_TAG_WALKABLE = 0x02, + DISPTRI_TAG_BUILDABLE = 0x04, + DISPTRI_FLAG_SURFPROP1 = 0x08, + DISPTRI_FLAG_SURFPROP2 = 0x10, + } + + /// + public enum EmitType + { + /// + /// 90 degree spotlight + /// + EMIT_SURFACE, + + /// + /// Simple point light source + /// + EMIT_POINT, + + /// + /// Spotlight with penumbra + /// + EMIT_SPOTLIGHT, + + /// + /// Directional light with no falloff + /// (surface must trace to SKY texture) + /// + EMIT_SKYLIGHT, + + /// + /// Linear falloff, non-lambertian + /// + EMIT_QUAKELIGHT, + + /// + /// Spherical light source with no falloff + /// (surface must trace to SKY texture) + /// + EMIT_SKYAMBIENT, + } + /// + /// public enum LumpType : int { + #region BSP and VBSP + /// /// The entity lump is basically a pure ASCII text section. /// It consists of the string representations of all entities, @@ -46,12 +294,14 @@ namespace SabreTools.Models.BSP /// directly within the BSP file instead of storing them in /// external WAD files. /// + /// LUMP_TEXDATA in VBSP 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_VERTEXES in VBSP LUMP_VERTICES = 3, /// @@ -96,16 +346,19 @@ namespace SabreTools.Models.BSP /// This lump contains the so-called clipnodes, which build a second /// BSP tree used only for collision detection. /// + /// LUMP_OCCLUSION in VBSP LUMP_CLIPNODES = 9, /// /// The leaves lump contains the leaves of the BSP tree. /// + /// LUMP_LEAFS in VBSP LUMP_LEAVES = 10, /// /// The marksurfaces lump is a simple array of short integers. /// + /// LUMP_FACEIDS in VBSP LUMP_MARKSURFACES = 11, /// @@ -131,6 +384,331 @@ namespace SabreTools.Models.BSP /// bounding box spaned by the first to members of this struct. /// LUMP_MODELS = 14, + + #endregion + + #region VBSP Only + + /// + /// Internal world lights converted from the entity lump + /// + LUMP_WORLDLIGHTS = 15, + + /// + /// Index to faces in each leaf + /// + LUMP_LEAFFACES = 16, + + /// + /// Index to brushes in each leaf + /// + LUMP_LEAFBRUSHES = 17, + + /// + /// Brush array + /// + LUMP_BRUSHES = 18, + + /// + /// Brushside array + /// + LUMP_BRUSHSIDES = 19, + + /// + /// Area array + /// + LUMP_AREAS = 20, + + /// + /// Portals between areas + /// + LUMP_AREAPORTALS = 21, + + /// Source 2004 + LUMP_PORTALS = 22, + + /// + /// Unused + /// + /// Source 2007/2009 + LUMP_UNUSED0 = 22, + + /// + /// Static props convex hull lists + /// + /// Source (L4D2 Branch) + LUMP_PROPCOLLISION = 22, + + /// + /// Leaves that are enterable by the player + /// + /// Source 2004 + LUMP_CLUSTERS = 23, + + /// + /// Unused + /// + /// Source 2007/2009 + LUMP_UNUSED1 = 23, + + /// + /// Static prop convex hulls + /// + /// Source (L4D2 Branch) + LUMP_PROPHULLS = 23, + + /// + /// Vertices of portal polygons + /// + /// Source 2004 + LUMP_PORTALVERTS = 24, + + /// + /// Unused + /// + /// Source 2007/2009 + LUMP_UNUSED2 = 24, + + /// + /// Used to store client side entities (Similar to Lump #0) + /// + /// Source (TacInt branch) + LUMP_FAKEENTITIES = 24, + + /// + /// Static prop collision vertices + /// + /// Source (L4D2 Branch) + LUMP_PROPHULLVERTS = 24, + + /// Source 2004 + LUMP_CLUSTERPORTALS = 25, + + /// + /// Unused + /// + /// Source 2007/2009 + LUMP_UNUSED3 = 25, + + /// + /// Static prop per hull triangle index start/count + /// + /// Source (L4D2 Branch) + LUMP_PROPTRIS = 25, + + /// + /// Displacement surface array + /// + LUMP_DISPINFO = 26, + + /// + /// Brush faces array before splitting + /// + LUMP_ORIGINALFACES = 27, + + /// + /// Displacement physics collision data + /// + LUMP_PHYSDISP = 28, + + /// + /// Physics collision data + /// + LUMP_PHYSCOLLIDE = 29, + + /// + /// Face plane normals + /// + LUMP_VERTNORMALS = 30, + + /// + /// Face plane normal index array + /// + LUMP_VERTNORMALINDICES = 31, + + /// + /// Displacement lightmap alphas (unused/empty since Source 2006) + /// + LUMP_DISP_LIGHTMAP_ALPHAS = 32, + + /// + /// Vertices of displacement surface meshes + /// + LUMP_DISP_VERTS = 33, + + /// + /// Displacement lightmap sample positions + /// + LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS = 34, + + /// + /// Game-specific data lump + /// + LUMP_GAME_LUMP = 35, + + /// + /// Data for leaf nodes that are inside water + /// + LUMP_LEAFWATERDATA = 36, + + /// + /// Water polygon data + /// + LUMP_PRIMITIVES = 37, + + /// + /// Water polygon vertices + /// + LUMP_PRIMVERTS = 38, + + /// + /// Water polygon vertex index array + /// + LUMP_PRIMINDICES = 39, + + /// + /// Embedded uncompressed or LZMA-compressed Zip-format file + /// + LUMP_PAKFILE = 40, + + /// + /// Clipped portal polygon vertices + /// + LUMP_CLIPPORTALVERTS = 41, + + /// + /// env_cubemap location array + /// + LUMP_CUBEMAPS = 42, + + /// + /// Texture name data + /// + LUMP_TEXDATA_STRING_DATA = 43, + + /// + /// Index array into texdata string data + /// + LUMP_TEXDATA_STRING_TABLE = 44, + + /// + /// info_overlay data array + /// + LUMP_OVERLAYS = 45, + + /// + /// Distance from leaves to water + /// + LUMP_LEAFMINDISTTOWATER = 46, + + /// + /// Macro texture info for faces + /// + LUMP_FACE_MACRO_TEXTURE_INFO = 47, + + /// + /// Displacement surface triangles + /// + LUMP_DISP_TRIS = 48, + + /// + /// Compressed win32-specific Havok terrain surface collision data. + /// Deprecated and no longer used. + /// + /// Source 2004 + LUMP_PHYSCOLLIDESURFACE = 49, + + /// + /// Static prop triangle and string data + /// + /// Source (L4D2 Branch) + LUMP_PROP_BLOB = 49, + + /// + /// Tied to any entity that uses the overlay_transition helper in FGD + /// + LUMP_WATEROVERLAYS = 50, + + /// + /// Alternate lightdata implementation for Xbox + /// + /// Source 2006 + LUMP_LIGHTMAPPAGES = 51, + + /// + /// Index of LUMP_LEAF_AMBIENT_LIGHTING_HDR + /// + /// Source 2007/2009 + LUMP_LEAF_AMBIENT_INDEX_HDR = 51, + + /// + /// Alternate lightdata indices for Xbox + /// + /// Source 2006 + LUMP_LIGHTMAPPAGEINFOS = 52, + + /// + /// Index of LUMP_LEAF_AMBIENT_LIGHTING + /// + /// Source 2007/2009 + LUMP_LEAF_AMBIENT_INDEX = 52, + + /// + /// HDR lightmap samples + /// + LUMP_LIGHTING_HDR = 53, + + /// + /// Internal HDR world lights converted from the entity lump + /// + LUMP_WORLDLIGHTS_HDR = 54, + + /// + /// Per-leaf ambient light samples (HDR) + /// + LUMP_LEAF_AMBIENT_LIGHTING_HDR = 55, + + /// + /// Per-leaf ambient light samples (LDR) + /// + LUMP_LEAF_AMBIENT_LIGHTING = 56, + + /// + /// XZip version of pak file for Xbox. Deprecated. + /// + LUMP_XZIPPAKFILE = 57, + + /// + /// HDR maps may have different face data + /// + LUMP_FACES_HDR = 58, + + /// + /// Extended level-wide flags. Not present in all levels. + /// + LUMP_MAP_FLAGS = 59, + + /// + /// Fade distances for overlays + /// + LUMP_OVERLAY_FADES = 60, + + /// + /// System level settings (min/max CPU & GPU to render this overlay) + /// + LUMP_OVERLAY_SYSTEM_LEVELS = 61, + + /// + /// PhysX model of the World Brush. + /// + LUMP_PHYSLEVEL = 62, + + /// + /// Displacement multiblend info + /// + LUMP_DISP_MULTIBLEND = 63, + + #endregion } /// @@ -147,6 +725,194 @@ namespace SabreTools.Models.BSP PLANE_ANYZ = 5, } + /// + [Flags] + public enum StaticPropFlags : uint + { + /// + /// Set by engine at runtime if the model fades out at a distance. + /// + STATIC_PROP_FLAG_FADES = 0x01, + + /// + /// Set by engine at runtime if the model's lighting origin is + /// different from its position in the world. + /// + STATIC_PROP_USE_LIGHTING_ORIGIN = 0x02, + + /// + /// Computed at run time based on dx level + /// + STATIC_PROP_NO_DRAW = 0x04, + + /// + /// Set if disableflashlight is enabled. + /// + STATIC_PROP_NO_FLASHLIGHT = 0x04, + + /// + /// Set if ignorenormals is enabled. + /// + STATIC_PROP_IGNORE_NORMALS = 0x08, + + /// + /// Set if disableshadows is enabled. + /// + STATIC_PROP_NO_SHADOW = 0x10, + + /// + /// Set if disableshadows is enabled. + /// + STATIC_PROP_SCREEN_SPACE_FADE = 0x20, + + /// + /// Set if drawinfastreflection is enabled. + /// + STATIC_PROP_MARKED_FOR_FAST_REFLECTION = 0x20, + + /// + /// In vrad, compute lighting at lighting origin, + /// not for each vertex + /// + STATIC_PROP_NO_PER_VERTEX_LIGHTING = 0x40, + + /// + /// Disable self shadowing in vrad + /// + STATIC_PROP_NO_SELF_SHADOWING = 0x80, + + /// + /// Whether we should do per-texel lightmaps in vrad + /// + STATIC_PROP_NO_PER_TEXEL_LIGHTING = 0x100, + } + + /// + [Flags] + public enum StaticPropFlagsEx : uint + { + /// + /// Set if disableshadowdepth is enabled. + /// + STATIC_PROP_FLAGS_EX_DISABLE_SHADOW_DEPTH = 0x00000001, + + /// + /// Automatically set at runtime + /// + STATIC_PROP_FLAGS_EX_DISABLE_CSM = 0x00000002, + + /// + /// Set if enablelightbounce is enabled. + /// + STATIC_PROP_FLAGS_EX_ENABLE_LIGHT_BOUNCE = 0x00000004, + } + + /// + [Flags] + public enum SurfaceFlag : uint + { + /// + /// Normally set on any surface that matches a RAD file entry; + /// not actually written to the BSP, unlike Quake II. + /// + SURF_LIGHT = 0x0001, + + /// + /// Deprecated: Legacy Quake II flag; deprecated in favor of + /// surface properties. + /// + SURF_SLICK = 0x0002, + + /// + /// Shows only the 2D skybox. Set via $Compile2DSky + /// + SURF_SKY2D = 0x0002, + + /// + /// Shows both the 2D and 3D skybox. Set via $CompileSky + /// + SURF_SKY = 0x0004, + + /// + /// Tells VVIS and the engine renderer that the surface is water. + /// Set via %CompileWater, but not %CompileSlime. + /// + SURF_WARP = 0x0008, + + /// + /// Surface is translucent, either via $translucent or $alpha. + /// + SURF_TRANS = 0x0010, + + /// + /// Deprecated: Legacy Quake II flag; deprecated in favor of + /// surface properties. + /// + SURF_WET = 0x0020, + + /// + /// Set via %NoPortal + /// + SURF_NOPORTAL = 0x0020, + + /// + /// Deprecated: Legacy Quake II flag; deprecated in favor of + /// material proxies. + /// + SURF_FLOWING = 0x0040, + + /// + /// Set via %CompileTrigger. Doesn't do anything in the PC versions. + /// + SURF_TRIGGER = 0x0040, + + /// + /// Set via %CompileNoDraw + /// + SURF_NODRAW = 0x0080, + + /// + /// Set via %CompileHint + /// + SURF_HINT = 0x0100, + + /// + /// Set via %CompileSkip. Should never be used on anything except + /// a hint brush. + /// + SURF_SKIP = 0x0200, + + /// + /// Don't calculate light + /// + SURF_NOLIGHT = 0x0400, + + /// + /// Calculate three lightmaps for the surface for bumpmapping + /// + SURF_BUMPLIGHT = 0x0800, + + /// + /// Don't receive shadows + /// + SURF_NOSHADOWS = 0x1000, + + /// + /// Don't receive decals + /// + SURF_NODECALS = 0x2000, + + /// + /// Don't subdivide patches on this surface + /// + SURF_NOCHOP = 0x4000, + + /// + /// Surface is part of a hitbox + /// + SURF_HITBOX = 0x8000, + } + /// [Flags] public enum TextureFlag : uint diff --git a/SabreTools.Models/BSP/FacesLump.cs b/SabreTools.Models/BSP/FacesLump.cs deleted file mode 100644 index 2c5a00c..0000000 --- a/SabreTools.Models/BSP/FacesLump.cs +++ /dev/null @@ -1,31 +0,0 @@ -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 deleted file mode 100644 index 2cc23bf..0000000 --- a/SabreTools.Models/BSP/File.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace SabreTools.Models.BSP -{ - /// - /// Half-Life Level - /// - /// - /// - public sealed class File - { - /// - /// Header data - /// - public Header? Header { get; set; } - - /// - /// Lump data - /// - /// 15 entries - public Lump[]? Lumps { get; set; } = new Lump[Constants.HEADER_LUMPS]; - } -} \ No newline at end of file diff --git a/SabreTools.Models/BSP/GameLump.cs b/SabreTools.Models/BSP/GameLump.cs new file mode 100644 index 0000000..0f85848 --- /dev/null +++ b/SabreTools.Models/BSP/GameLump.cs @@ -0,0 +1,22 @@ +namespace SabreTools.Models.BSP +{ + /// + /// The Game lump (Lump 35) seems to be intended to be used for + /// map data that is specific to a particular game using the Source + /// engine, so that the file format can be extended without altering + /// the previously defined format. + /// + /// + public sealed class GameLump + { + /// + /// Number of game lumps + /// + public int LumpCount; + + /// + /// + /// + public GameLumpDirectory[]? Directories; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/GameLumpDirectory.cs b/SabreTools.Models/BSP/GameLumpDirectory.cs new file mode 100644 index 0000000..7e6fd0a --- /dev/null +++ b/SabreTools.Models/BSP/GameLumpDirectory.cs @@ -0,0 +1,40 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// The Game lump (Lump 35) seems to be intended to be used for + /// map data that is specific to a particular game using the Source + /// engine, so that the file format can be extended without altering + /// the previously defined format. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class GameLumpDirectory + { + /// + /// Gamelump ID + /// + public int Id; + + /// + /// Flags + /// + public ushort Flags; + + /// + /// Gamelump version + /// + public ushort Version; + + /// + /// Offset to this gamelump + /// + public int FileOffset; + + /// + /// Length + /// + public int FileLength; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/LeafAmbientIndex.cs b/SabreTools.Models/BSP/LeafAmbientIndex.cs new file mode 100644 index 0000000..7c29a26 --- /dev/null +++ b/SabreTools.Models/BSP/LeafAmbientIndex.cs @@ -0,0 +1,17 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// To associate each leaf with its collection of ambient samples, + /// the ambient lighting index lumps (Lumps 51 and 52) are used. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class LeafAmbientIndex + { + public ushort AmbientSampleCount; + + public ushort FirstAmbientSample; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/LeafAmbientLighting.cs b/SabreTools.Models/BSP/LeafAmbientLighting.cs new file mode 100644 index 0000000..646a512 --- /dev/null +++ b/SabreTools.Models/BSP/LeafAmbientLighting.cs @@ -0,0 +1,41 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// The ambient lighting lumps (Lumps 55 and 56) are present in + /// BSP version 20 and later. Lump 55 is used for HDR lighting, + /// and Lump 56 is used for LDR lighting. These lumps are used to + /// store the volumetric ambient lighting information in each leaf + /// (i.e. lighting information for entities such as NPCs, the + /// viewmodel, and non-static props). Prior to version 20, this + /// data was stored in the leaf lump (Lump 10), in the dleaf_t + /// structure, with far less precision than this newer lump allows. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class LeafAmbientLighting + { + public CompressedLightCube Cube; + + /// + /// Fixed point fraction of leaf bounds + /// + public byte X; + + /// + /// Fixed point fraction of leaf bounds + /// + public byte Y; + + /// + /// Fixed point fraction of leaf bounds + /// + public byte Z; + + /// + /// Unused + /// + public byte Pad; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/LeafBrushesLump.cs b/SabreTools.Models/BSP/LeafBrushesLump.cs new file mode 100644 index 0000000..5b71819 --- /dev/null +++ b/SabreTools.Models/BSP/LeafBrushesLump.cs @@ -0,0 +1,16 @@ +namespace SabreTools.Models.BSP +{ + /// + /// The leafbrush lump (Lump 17) is an array of unsigned shorts which are + /// used to map from brushes referenced in the leaf structure to indices in + /// the brush array. + /// + /// + public sealed class LeafBrushesLump : Lump + { + /// + /// Map + /// + public ushort[]? Map { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/LeafFacesLump.cs b/SabreTools.Models/BSP/LeafFacesLump.cs new file mode 100644 index 0000000..5c338f5 --- /dev/null +++ b/SabreTools.Models/BSP/LeafFacesLump.cs @@ -0,0 +1,16 @@ +namespace SabreTools.Models.BSP +{ + /// + /// The leafface lump (Lump 16) is an array of unsigned shorts which are + /// used to map from faces referenced in the leaf structure to indices in + /// the face array. + /// + /// + public sealed class LeafFacesLump : Lump + { + /// + /// Map + /// + public ushort[]? Map { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/LeavesLump.cs b/SabreTools.Models/BSP/LeavesLump.cs deleted file mode 100644 index 65eabf3..0000000 --- a/SabreTools.Models/BSP/LeavesLump.cs +++ /dev/null @@ -1,31 +0,0 @@ -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/Lump.cs b/SabreTools.Models/BSP/Lump.cs index 6dd4e8f..6ba4ce1 100644 --- a/SabreTools.Models/BSP/Lump.cs +++ b/SabreTools.Models/BSP/Lump.cs @@ -4,6 +4,7 @@ namespace SabreTools.Models.BSP /// Represents a common Lump type /// /// + /// public abstract class Lump { // No shared fields between types diff --git a/SabreTools.Models/BSP/LzmaHeader.cs b/SabreTools.Models/BSP/LzmaHeader.cs new file mode 100644 index 0000000..9e48f2b --- /dev/null +++ b/SabreTools.Models/BSP/LzmaHeader.cs @@ -0,0 +1,40 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// BSP files for console platforms such as PlayStation 3 and + /// Xbox 360 usually have their lumps compressed with LZMA. + /// In this case, the lump data starts with the following header + /// (from public/tier1/lzmaDecoder.h), which is used in place of + /// the standard 13-byte LZMA header. + /// + /// lzmaSize denotes the size (in bytes) of compressed data, it + /// is equal to the size of a lump minus 17 bytes (lzma header). + /// actualSize denotes the size of decompressed data. properties[5] + /// field are used solely for LZMA decoding. + /// + /// There are two special cases for compression: LUMP_PAKFILE is never + /// compressed as a lump (the contents of the zip are compressed instead) + /// and each of the game lumps in LUMP_GAME_LUMP are compressed individually. + /// The compressed size of a game lump can be determined by subtracting + /// the current game lump's offset with that of the next entry. For this + /// reason, when game lumps are compressed the last game lump is always + /// an empty dummy which only contains the offset. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class LzmaHeader + { + public uint Id; + + /// Little-endian + public uint ActualSize; + + /// Little-endian + public uint LzmaSize; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public byte[]? Properties = new byte[5]; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/ModelsLump.cs b/SabreTools.Models/BSP/ModelsLump.cs deleted file mode 100644 index ac4874f..0000000 --- a/SabreTools.Models/BSP/ModelsLump.cs +++ /dev/null @@ -1,29 +0,0 @@ -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/OccluderData.cs b/SabreTools.Models/BSP/OccluderData.cs new file mode 100644 index 0000000..dad2784 --- /dev/null +++ b/SabreTools.Models/BSP/OccluderData.cs @@ -0,0 +1,40 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// The doccluderdata_t structure contains flags and dimensions + /// of the occluder, as well as the area where it remains. + /// firstpoly is the first index into the doccluderpolydata_t + /// with a total of polycount entries. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class OccluderData + { + public int Flags; + + /// + /// Index into doccluderpolys + /// + public int FirstPoly; + + /// + /// Amount of polygons + /// + public int PolyCount; + + /// + /// Minima of all vertices + /// + public Vector3D Mins; + + /// + /// Maxima of all vertices + /// + public Vector3D Maxs; + + /// Since v1 + public int Area; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/OccluderPolyData.cs b/SabreTools.Models/BSP/OccluderPolyData.cs new file mode 100644 index 0000000..824c2b5 --- /dev/null +++ b/SabreTools.Models/BSP/OccluderPolyData.cs @@ -0,0 +1,29 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// Occluder polygons are stored in the doccluderpolydata_t + /// structure and contain the firstvertexindex field, which + /// is the first index into the vertex array of the occluder, + /// which are again indices for the vertex array of the vertex + /// lump (Lump 3). The total number of vertex indices is + /// stored in vertexcount. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class OccluderPolyData + { + /// + /// Index into doccludervertindices + /// + public int FirstVertexIndex; + + /// + /// Amount of vertex indices + /// + public int VertexCount; + + public int PlanEnum; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/OcclusionLump.cs b/SabreTools.Models/BSP/OcclusionLump.cs new file mode 100644 index 0000000..35780f8 --- /dev/null +++ b/SabreTools.Models/BSP/OcclusionLump.cs @@ -0,0 +1,46 @@ +namespace SabreTools.Models.BSP +{ + /// + /// The occlusion lump (Lump 9) contains the polygon geometry and some + /// flags used by func_occluder entities. Unlike other brush entities, + /// func_occluders don't use the 'model' key in the entity lump. + /// Instead, the brushes are split from the entities during the compile + /// process and numeric occluder keys are assigned as 'occludernum'. + /// Brush sides textured with tools/toolsoccluder or tools/toolstrigger + /// are then stored together with the occluder keys and some additional + /// info in this lump. + /// + /// The lump is divided into three parts and begins with a integer value + /// with the total number of occluders, followed by an array of + /// doccluderdata_t fields of the same size. The next part begins with + /// another integer value, this time for the total number of occluder + /// polygons, as well as an array of doccluderpolydata_t fields of equal + /// size. Part three begins with another integer value for the amount of + /// occluder polygon vertices, followed by an array of integer values for + /// the vertex indices, again of the same size. + /// + /// + public sealed class OcclusionLump : Lump + { + public int Count; + + /// + /// + /// + public OccluderData[]? Data; + + public int PolyDataCount; + + /// + /// + /// + public OccluderPolyData[]? PolyData; + + public int VertexIndexCount; + + /// + /// + /// + public int[]? VertexIndices; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/Overlay.cs b/SabreTools.Models/BSP/Overlay.cs new file mode 100644 index 0000000..da46db7 --- /dev/null +++ b/SabreTools.Models/BSP/Overlay.cs @@ -0,0 +1,48 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// Unlike the simpler decals (infodecal entities), info_overlays + /// are removed from the entity lump and stored separately in the + /// Overlay lump (Lump 45). + /// + /// The FaceCountAndRenderOrder member is split into two parts; + /// the lower 14 bits are the number of faces that the overlay + /// appears on, with the top 2 bits being the render order of + /// the overlay (for overlapping decals). The Ofaces array, which + /// is 64 elements in size (OVERLAY_BSP_FACE_COUNT) are the indices + /// into the face array indicating which map faces the overlay + /// should be displayed on. The other elements set the texture, + /// scale, and orientation of the overlay decal. There is no + /// enforced limit on overlays inside the engine. VBSP enforces + /// a limit of 512 (MAX_MAP_OVERLAYS, 1024 in Counter-Strike: + /// Global Offensive), but custom compilers can circumvent this. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class Overlay + { + public int Id; + + public short TexInfo; + + public ushort FaceCountAndRenderOrder; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.OVERLAY_BSP_FACE_COUNT)] + public int[]? Ofaces = new int[Constants.OVERLAY_BSP_FACE_COUNT]; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public float[]? U = new float[2]; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public float[]? V = new float[2]; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public Vector3D[]? UVPoints = new Vector3D[4]; + + public Vector3D Origin; + + public Vector3D BasisNormal; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/OverlaysLump.cs b/SabreTools.Models/BSP/OverlaysLump.cs new file mode 100644 index 0000000..cb2fb6e --- /dev/null +++ b/SabreTools.Models/BSP/OverlaysLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class OverlaysLump : Lump + { + /// + /// Overlays + /// + public Overlay[]? Overlays { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/Plane.cs b/SabreTools.Models/BSP/Plane.cs index 4aa5ac4..ad81add 100644 --- a/SabreTools.Models/BSP/Plane.cs +++ b/SabreTools.Models/BSP/Plane.cs @@ -18,6 +18,7 @@ namespace SabreTools.Models.BSP /// computations. /// /// + /// [StructLayout(LayoutKind.Sequential)] public sealed class Plane { diff --git a/SabreTools.Models/BSP/PlaneLump.cs b/SabreTools.Models/BSP/PlanesLump.cs similarity index 52% rename from SabreTools.Models/BSP/PlaneLump.cs rename to SabreTools.Models/BSP/PlanesLump.cs index d4c44bb..2e47b0b 100644 --- a/SabreTools.Models/BSP/PlaneLump.cs +++ b/SabreTools.Models/BSP/PlanesLump.cs @@ -1,11 +1,8 @@ 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 + /// + public sealed class PlanesLump : Lump { /// /// Planes diff --git a/SabreTools.Models/BSP/QAngle.cs b/SabreTools.Models/BSP/QAngle.cs new file mode 100644 index 0000000..b9f1b0b --- /dev/null +++ b/SabreTools.Models/BSP/QAngle.cs @@ -0,0 +1,17 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// QAngle is a C++ class in Source that represents a three-dimensional + /// extrinsic Tait-Bryan rotations following the right-hand rule, offset + /// from the cardinal Z axis. + /// + [StructLayout(LayoutKind.Sequential)] + public struct QAngle + { + 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/StaticPropDictLump.cs b/SabreTools.Models/BSP/StaticPropDictLump.cs new file mode 100644 index 0000000..42a3218 --- /dev/null +++ b/SabreTools.Models/BSP/StaticPropDictLump.cs @@ -0,0 +1,24 @@ +namespace SabreTools.Models.BSP +{ + /// + /// Of interest is the gamelump which is used to store prop_static entities, + /// which uses the gamelump ID of 'sprp' ASCII (1936749168 decimal). Unlike + /// most other entities, static props are not stored in the entity lump. The + /// gamelump formats used in Source are defined in the public/gamebspfile.h + /// header file. + /// + /// The first element of the static prop game lump is the dictionary; this is + /// an integer count followed by the list of model (prop) names used in the map + /// + /// + public sealed class StaticPropDictLump + { + public int DictEntries; + + /// + /// Model name + /// + /// [dictEntries][128] + public char[,]? Name; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/StaticPropLeafLump.cs b/SabreTools.Models/BSP/StaticPropLeafLump.cs new file mode 100644 index 0000000..00693ea --- /dev/null +++ b/SabreTools.Models/BSP/StaticPropLeafLump.cs @@ -0,0 +1,18 @@ +namespace SabreTools.Models.BSP +{ + /// + /// Presumably, this array is used to index into the leaf lump + /// to locate the leaves that each prop static is located in. + /// Note that a prop static may span several leaves. + /// + /// + public sealed class StaticPropLeafLump + { + public int LeafEntries; + + /// + /// + /// + public ushort[]? Leaf; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/StaticPropLump.cs b/SabreTools.Models/BSP/StaticPropLump.cs new file mode 100644 index 0000000..deb90cf --- /dev/null +++ b/SabreTools.Models/BSP/StaticPropLump.cs @@ -0,0 +1,185 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// The coordinates of the prop are given by the Origin member; its + /// orientation (pitch, yaw, roll) is given by the Angles entry, which + /// is a 3-float vector. The PropType element is an index into the + /// dictionary of prop model names, given above. The other elements + /// correspond to the location of the prop in the BSP structure of the + /// map, its lighting, and other entity properties as set in Hammer. + /// The other elements (ForcedFadeScale, etc.) are only present in the + /// static prop structure if the gamelump's specified version is high enough + /// (see dgamelump_t.version); both version 4 and version 5 static prop + /// gamelumps are used in official Half-Life 2 maps. Version 6 has been + /// encountered in Team Fortress 2; Version 7 is used in some Left 4 Dead + /// maps, and a modified version 7 is present in Zeno Clash maps. Version 8 + /// is used predominantly in Left 4 Dead, and version 9 in Left 4 Dead 2. + /// The new version 10 appears in Tactical Intervention. Version 11 is used in + /// Counter-Strike: Global Offensive since the addition of uniform prop scaling + /// (before this it was version 10). After version 7, DX level options were + /// removed. In version 11 XBox 360 flags were removed. + /// + /// Version 7* is used by games built on Source 2013 Multiplayer + /// ( Team Fortress 2, Counter-Strike: Source, etc.) and may come across as + /// either version 7 or 10. Specifically, Team Fortress 2 has referred to it + /// as version 7 in the past but now refers to it as version 10 even though + /// they are identical. This version's structure is based on version 6 but + /// rearranged such that Flags is an int and at the bottom, above two new + /// entries. These new entries (LightmapResX and LightmapResY) control the + /// width and height of the prop's lightmap image and are specific to this + /// version. + /// + /// + public sealed class StaticPropLump + { + #region v4 + + /// + /// Origin + /// + public Vector3D Origin; + + /// + /// Orientation (pitch yaw roll) + /// + public QAngle Angles; + + #endregion + + #region v4 + + /// + /// Index into model name dictionary + /// + public ushort PropType; + + /// + /// Index into leaf array + /// + public ushort FirstLeaf; + + public ushort LeafCount; + + /// + /// Solidity type + /// + public byte Solid; + + #endregion + + #region Every version except v7* + + [MarshalAs(UnmanagedType.U1)] + public StaticPropFlags FlagsV4; + + #endregion + + #region v4 still + + /// + /// Model skin numbers + /// + public int Skin; + + public float FadeMinDist; + + public float FadeMaxDist; + + /// + /// For lighting + /// + public Vector3D LightingOrigin; + + #endregion + + #region Since v5 + + /// + /// Fade distance scale + /// + public float ForcedFadeScale; + + #endregion + + #region v6, v7, and v7* only + + /// + /// Minimum DirectX version to be visible + /// + public ushort MinDXLevel; + + /// + /// Maximum DirectX version to be visible + /// + public ushort MaxDXLevel; + + #endregion + + #region v7* only + + [MarshalAs(UnmanagedType.U4)] + public byte FlagsV7; + + /// + /// Lightmap image width + /// + public ushort LightmapResX; + + /// + /// Lightmap image height + /// + public ushort LightmapResY; + + #endregion + + #region Since v8 + + public byte MinCPULevel; + + public byte MaxCPULevel; + + public byte MinGPULevel; + + public byte MaxGPULevel; + + #endregion + + #region Since v7 + + /// + /// Per instance color and alpha modulation + /// + public ColorRGBExp32 DiffuseModulation; + + #endregion + + #region v9 and v10 only + + /// + /// If true, don't show on XBox 360 (4-bytes long) + /// + public bool DisableX360; + + #endregion + + #region Since v10 + + /// + /// Further bitflags. + /// + public StaticPropFlagsEx FlagsEx; + + #endregion + + #region Since v11 + + /// + /// Prop scale + /// + public float UniformScale; + + #endregion + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/SurfedgesLump.cs b/SabreTools.Models/BSP/SurfedgesLump.cs index 3cd1888..5ec7fc2 100644 --- a/SabreTools.Models/BSP/SurfedgesLump.cs +++ b/SabreTools.Models/BSP/SurfedgesLump.cs @@ -11,6 +11,7 @@ namespace SabreTools.Models.BSP /// used. /// /// + /// public sealed class SurfedgesLump : Lump { /// diff --git a/SabreTools.Models/BSP/Texdata.cs b/SabreTools.Models/BSP/Texdata.cs new file mode 100644 index 0000000..f6726d7 --- /dev/null +++ b/SabreTools.Models/BSP/Texdata.cs @@ -0,0 +1,40 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// The reflectivity vector corresponds to the RGB components of the reflectivity + /// of the texture, as derived from the material's .vtf file. This is probably + /// used in radiosity (lighting) calculations of what light bounces from the + /// texture's surface. The nameStringTableID is an index into the TexdataStringTable + /// array (below). The other members relate to the texture's source image. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class Texdata + { + /// + /// RGB reflectivity + /// + public Vector3D Reflectivity; + + /// + /// Index into TexdataStringTable + /// + public int NameStringTableID; + + /// + /// Source image + /// + public int Width; + + /// + /// Source image + /// + public int Height; + + public int ViewWidth; + + public int ViewHeight; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/TexdataLump.cs b/SabreTools.Models/BSP/TexdataLump.cs new file mode 100644 index 0000000..fed59bb --- /dev/null +++ b/SabreTools.Models/BSP/TexdataLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class TexdataLump : Lump + { + /// + /// Texdatas + /// + public Texdata[]? Texdatas { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/TexdataStringData.cs b/SabreTools.Models/BSP/TexdataStringData.cs new file mode 100644 index 0000000..9361582 --- /dev/null +++ b/SabreTools.Models/BSP/TexdataStringData.cs @@ -0,0 +1,15 @@ +namespace SabreTools.Models.BSP +{ + /// + /// The TexdataStringData lump consists of concatenated null-terminated + /// strings giving the texture name. + /// + /// + public sealed class TexdataStringData : Lump + { + /// + /// Strings + /// + public string[]? Strings { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/TexdataStringTable.cs b/SabreTools.Models/BSP/TexdataStringTable.cs new file mode 100644 index 0000000..6c03dd1 --- /dev/null +++ b/SabreTools.Models/BSP/TexdataStringTable.cs @@ -0,0 +1,15 @@ +namespace SabreTools.Models.BSP +{ + /// + /// The TexdataStringTable (Lump 44) is an array of integers which + /// are offsets into the TexdataStringData (lump 43). + /// + /// + public sealed class TexdataStringTable : Lump + { + /// + /// Offsets + /// + public int[]? Offsets { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/TexinfoLump.cs b/SabreTools.Models/BSP/TexinfoLump.cs deleted file mode 100644 index 0583a33..0000000 --- a/SabreTools.Models/BSP/TexinfoLump.cs +++ /dev/null @@ -1,24 +0,0 @@ -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/VbspFace.cs b/SabreTools.Models/BSP/VbspFace.cs new file mode 100644 index 0000000..d08e6ea --- /dev/null +++ b/SabreTools.Models/BSP/VbspFace.cs @@ -0,0 +1,105 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// The face lump (Lump 7) contains the major geometry of the map, + /// used by the game engine to render the viewpoint of the player. + /// The face lump contains faces after they have undergone the BSP + /// splitting process; they therefore do not directly correspond to + /// the faces of brushes created in Hammer. Faces are always flat, + /// convex polygons, though they can contain edges that are co-linear. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class VbspFace + { + /// + /// The plane number + /// + public ushort PlaneNum; + + /// + /// Faces opposite to the node's plane direction + /// + public byte Side; + + /// + /// of on node, 0 if in leaf + /// + public byte OnNode; + + /// + /// Index of the first surfedge + /// + public int FirstEdgeIndex; + + /// + /// Number of consecutive surfedges + /// + public short NumberOfEdges; + + /// + /// Index of the texture info structure + /// + public short TextureInfoIndex; + + /// + /// Index of the displacement info structure + /// + public short DisplacementInfoIndex; + + /// + /// ? + /// + public short SurfaceFogVolumeID; + + /// + /// Switchable lighting info + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[]? Styles = new byte[4]; + + /// + /// Offset into lightmap lump + /// + public int LightmapOffset; + + /// + /// Face area in units^2 + /// + public float Area; + + /// + /// Texture lighting info + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public int[]? LightmapTextureMinsInLuxels = new int[2]; + + /// + /// Texture lighting info + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public int[]? LightmapTextureSizeInLuxels = new int[2]; + + /// + /// Original face this was split from + /// + public int OrigFace; + + /// + /// Primitives + /// + public ushort PrimitiveCount; + + /// + /// First primitive ID + /// + public ushort FirstPrimitiveID; + + /// + /// Lightmap smoothing group + /// + public uint SmoothingGroups; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/VbspFacesLump.cs b/SabreTools.Models/BSP/VbspFacesLump.cs new file mode 100644 index 0000000..f5f261e --- /dev/null +++ b/SabreTools.Models/BSP/VbspFacesLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class VbspFacesLump : Lump + { + /// + /// Faces + /// + public VbspFace[]? Faces { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/VbspFile.cs b/SabreTools.Models/BSP/VbspFile.cs new file mode 100644 index 0000000..4b255e1 --- /dev/null +++ b/SabreTools.Models/BSP/VbspFile.cs @@ -0,0 +1,363 @@ +namespace SabreTools.Models.BSP +{ + /// + /// Half-Life Level + /// + /// + /// + public sealed class VbspFile + { + /// + /// Header data + /// + public VbspHeader? Header { get; set; } + + #region Lumps + + /// + /// LUMP_ENTITIES [0] + /// + public EntitiesLump? Entities { get; set; } + + /// + /// LUMP_PLANES [1] + /// + public PlanesLump? PlanesLump { get; set; } + + /// + /// LUMP_TEXDATA [2] + /// + public TexdataLump? TexdataLump { get; set; } + + /// + /// LUMP_VERTEXES [3] + /// + public VerticesLump? VerticesLump { get; set; } + + /// + /// LUMP_VISIBILITY [4] + /// + public VisibilityLump? VisibilityLump { get; set; } + + /// + /// LUMP_NODES [5] + /// + public VbspNodesLump? NodesLump { get; set; } + + /// + /// LUMP_TEXINFO [6] + /// + public VbspTexinfoLump? TexinfoLump { get; set; } + + /// + /// LUMP_FACES [7] + /// + public VbspFacesLump? FacesLump { get; set; } + + /// + /// LUMP_LIGHTING [8] + /// + public LightmapLump? LightmapLump { get; set; } + + /// + /// LUMP_OCCLUSION [9] + /// s + public OcclusionLump? OcclusionLump { get; set; } + + /// + /// LUMP_LEAVES [10] + /// + public VbspLeavesLump? LeavesLump { get; set; } + + /// + /// LUMP_FACEIDS [11] + /// + public MarksurfacesLump? MarksurfacesLump { get; set; } + + /// + /// LUMP_EDGES [12] + /// + public EdgesLump? EdgesLump { get; set; } + + /// + /// LUMP_SURFEDGES [13] + /// + public SurfedgesLump? SurfedgesLump { get; set; } + + /// + /// LUMP_MODELS [14] + /// + public VbspModelsLump? ModelsLump { get; set; } + + /// + /// LUMP_WORLDLIGHTS [15] + /// + public WorldLightsLump? LDRWorldLightsLump { get; set; } + + /// + /// LUMP_LEAFFACES [16] + /// + public LeafFacesLump? LeafFacesLump { get; set; } + + /// + /// LUMP_LEAFBRUSHES [17] + /// + public LeafBrushesLump? LeafBrushesLump { get; set; } + + /// + /// LUMP_BRUSHES [18] + /// + public BrushesLump? BrushesLump { get; set; } + + /// + /// LUMP_BRUSHSIDES [19] + /// + public BrushsidesLump? BrushsidesLump { get; set; } + + /// + /// LUMP_AREAS [20] + /// + /// TODO: Find definition and implement + // public AreasLump? AreasLump { get; set; } + + /// + /// LUMP_AREAPORTALS [21] + /// + /// TODO: Find definition and implement + // public AreaPortalsLump? AreaPortalsLump { get; set; } + + /// + /// LUMP_PORTALS / LUMP_UNUSED0 / LUMP_PROPCOLLISION [22] + /// + /// TODO: Find definition and implement + // public PortalsLump? PortalsLump { get; set; } + + /// + /// LUMP_CLUSTERS / LUMP_UNUSED1 / LUMP_PROPHULLS [23] + /// + /// TODO: Find definition and implement + // public ClustersLump? ClustersLump { get; set; } + + /// + /// LUMP_PORTALVERTS / LUMP_UNUSED2 / LUMP_FAKEENTITIES / LUMP_PROPHULLVERTS [24] + /// + /// TODO: Find definition and implement + // public PortalVertsLump? PortalVertsLump { get; set; } + + /// + /// LUMP_CLUSTERPORTALS / LUMP_UNUSED3 / LUMP_PROPTRIS [25] + /// + /// TODO: Find definition and implement + // public ClusterPortalsLump? ClusterPortalsLump { get; set; } + + /// + /// LUMP_DISPINFO [26] + /// + public DispInfosLump? DispInfoLump { get; set; } + + /// + /// LUMP_ORIGINALFACES [27] + /// + public VbspFacesLump? OriginalFacesLump { get; set; } + + /// + /// LUMP_PHYSDISP [28] + /// + /// TODO: Find definition and implement + // public PhysDispLump? PhysDispLump { get; set; } + + // TODO: Implement Lump 29 + // https://developer.valvesoftware.com/wiki/BSP_(Source)#Physics + + /// + /// LUMP_VERTNORMALS [30] + /// + /// TODO: Find definition and implement + // public VertNormalsLump? VertNormalsLump { get; set; } + + /// + /// LUMP_VERTNORMALINDICES [31] + /// + /// TODO: Find definition and implement + // public VertNormalIndicesLump? VertNormalIndicesLump { get; set; } + + /// + /// LUMP_DISP_LIGHTMAP_ALPHAS [32] + /// + /// TODO: Find definition and implement + // public DispLightmapAlphasLump? DispLightmapAlphasLump { get; set; } + + /// + /// LUMP_DISP_VERTS [33] + /// + public DispVertsLump? DispVertLump { get; set; } + + /// + /// LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS [34] + /// + /// TODO: Find definition and implement + // public DispLightmapSamplePositions? DispLightmapSamplePositions { get; set; } + + /// + /// LUMP_GAME_LUMP [35] + /// + public GameLump? GameLump { get; set; } + + /// + /// LUMP_LEAFWATERDATA [36] + /// + /// TODO: Find definition and implement + // public LeafWaterDataLump? LeafWaterDataLump { get; set; } + + /// + /// LUMP_PRIMITIVES [37] + /// + /// TODO: Find definition and implement + // public PrimitivesLump? PrimitivesLump { get; set; } + + /// + /// LUMP_PRIMVERTS [38] + /// + /// TODO: Find definition and implement + // public PrimVertsLump? PrimVertsLump { get; set; } + + /// + /// LUMP_PRIMINDICES [39] + /// + /// TODO: Find definition and implement + // public PrimIndicesLump? PrimIndicesLump { get; set; } + + // TODO: Implement Lump 40 + // https://developer.valvesoftware.com/wiki/BSP_(Source)#Pakfile + + /// + /// LUMP_CLIPPORTALVERTS [41] + /// + /// TODO: Find definition and implement + // public ClipPortalVertsLump? ClipPortalVertsLump { get; set; } + + /// + /// LUMP_CUBEMAPS [42] + /// + public CubemapsLump? CubemapLump { get; set; } + + /// + /// LUMP_TEXDATA_STRING_DATA [43] + /// + public TexdataStringData? TexdataStringData { get; set; } + + /// + /// LUMP_TEXDATA_STRING_TABLE [44] + /// + public TexdataStringTable? TexdataStringTable { get; set; } + + /// + /// LUMP_OVERLAYS [45] + /// + public OverlaysLump? OverlaysLump { get; set; } + + /// + /// LUMP_LEAFMINDISTTOWATER [46] + /// + /// TODO: Find definition and implement + // public LeafMindIsToWaterLump? LeafMindIsToWaterLump { get; set; } + + /// + /// LUMP_FACE_MACRO_TEXTURE_INFO [47] + /// + /// TODO: Find definition and implement + // public FaceMacroTextureInfoLump? FaceMacroTextureInfoLump { get; set; } + + /// + /// LUMP_DISP_TRIS [48] + /// + public DispTrisLump? DispTrisLump { get; set; } + + /// + /// LUMP_PHYSCOLLIDESURFACE / LUMP_PROP_BLOB [49] + /// + /// TODO: Find definition and implement + // public PhysCollideSurfaceLump? PhysCollideSurfaceLump { get; set; } + + /// + /// LUMP_WATEROVERLAYS [50] + /// + /// TODO: Find definition and implement + // public WaterOverlaysLump? WaterOverlaysLump { get; set; } + + /// + /// LUMP_LIGHTMAPPAGES / LUMP_LEAF_AMBIENT_INDEX_HDR [51] + /// + public AmbientIndexLump? HDRAmbientIndexLump { get; set; } + + /// + /// LUMP_LIGHTMAPPAGEINFOS / LUMP_LEAF_AMBIENT_INDEX [52] + /// + public AmbientIndexLump? LDRAmbientIndexLump { get; set; } + + /// + /// LUMP_LIGHTING_HDR [53] + /// + /// TODO: Find definition and implement + // public LightingHdrLump? LightingHdrLump { get; set; } + + /// + /// LUMP_WORLDLIGHTS_HDR [54] + /// + public WorldLightsLump? WorldLightsLump { get; set; } + + /// + /// LUMP_LEAF_AMBIENT_LIGHTING_HDR [55] + /// + public AmbientLightingLump? HDRAmbientLightingLump { get; set; } + + /// + /// LUMP_LEAF_AMBIENT_LIGHTING [56] + /// + public AmbientLightingLump? LDRAmbientLightingLump { get; set; } + + /// + /// LUMP_XZIPPAKFILE [57] + /// + /// TODO: Find definition and implement + // public XzipPakFileLump? XzipPakFileLump { get; set; } + + /// + /// LUMP_FACES_HDR [58] + /// + /// TODO: Find definition and implement + // public FacesHdrLump? FacesHdrLump { get; set; } + + /// + /// LUMP_MAP_FLAGS [59] + /// + /// TODO: Find definition and implement + // public MapFlagsLump? MapFlagsLump { get; set; } + + /// + /// LUMP_OVERLAY_FADES [60] + /// + /// TODO: Find definition and implement + // public OverlayFadesLump? OverlayFadesLump { get; set; } + + /// + /// LUMP_OVERLAY_SYSTEM_LEVELS [61] + /// + /// TODO: Find definition and implement + // public OverlaySystemLevelsLump? OverlaySystemLevelsLump { get; set; } + + /// + /// LUMP_PHYSLEVEL [62] + /// + /// TODO: Find definition and implement + // public PhysLevelLump? PhysLevelLump { get; set; } + + /// + /// LUMP_DISP_MULTIBLEND [64] + /// + /// TODO: Find definition and implement + // public DispMultiBlendLump? DispMultiBlendLump { get; set; } + + #endregion + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/VbspHeader.cs b/SabreTools.Models/BSP/VbspHeader.cs new file mode 100644 index 0000000..2b9e8ee --- /dev/null +++ b/SabreTools.Models/BSP/VbspHeader.cs @@ -0,0 +1,33 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class VbspHeader + { + /// + /// BSP file signature + /// + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)] + public string? Signature; + + /// + /// BSP file version + /// + /// 17,18,19,20,21,22,23,25,27,29 + public int Version; + + /// + /// Lump directory array + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.VBSP_HEADER_LUMPS)] + public VbspLumpEntry[]? Lumps = new VbspLumpEntry[Constants.VBSP_HEADER_LUMPS]; + + /// + /// The map's revision (iteration, version) number. + /// + public int MapRevision; + } +} diff --git a/SabreTools.Models/BSP/VbspLeaf.cs b/SabreTools.Models/BSP/VbspLeaf.cs new file mode 100644 index 0000000..29f8ad6 --- /dev/null +++ b/SabreTools.Models/BSP/VbspLeaf.cs @@ -0,0 +1,99 @@ +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. + /// + /// + public sealed class VbspLeaf + { + /// + /// Contents enumeration + /// + public VbspContents Contents; + + /// + /// Cluster this leaf is in + /// + public short Cluster; + + /// + /// Area this leaf is in and flags + /// + /// area:9, flags:7 + public short AreaFlags; + + /// + /// For frustum culling + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public short[] Mins = new short[3]; + + /// + /// For frustum culling + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public short[] Maxs = new short[3]; + + /// + /// Index into leaffaces + /// + public ushort FirstLeafFace; + + /// + /// Count of leaffaces + /// + public ushort NumLeafFaces; + + /// + /// Index into leafbrushes + /// + public ushort FirstLeafBrush; + + /// + /// Count of leafbrushes + /// + public ushort NumLeafBrushes; + + /// + /// -1 for not in water + /// + public short LeafWaterDataID; + + #region Lump Version 0 + + /// + /// Precaculated light info for entities. + /// + public CompressedLightCube AmbientLighting; + + #endregion + + #region Lump Version 1+ + + /// + /// Padding to 4-byte boundary + /// + public short Padding; + + #endregion + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/VbspLeavesLump.cs b/SabreTools.Models/BSP/VbspLeavesLump.cs new file mode 100644 index 0000000..037ef4a --- /dev/null +++ b/SabreTools.Models/BSP/VbspLeavesLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class VbspLeavesLump : Lump + { + /// + /// Leaves + /// + public VbspLeaf[]? Leaves { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/VBSP/Lump.cs b/SabreTools.Models/BSP/VbspLumpEntry.cs similarity index 55% rename from SabreTools.Models/VBSP/Lump.cs rename to SabreTools.Models/BSP/VbspLumpEntry.cs index 686b9d0..b298af8 100644 --- a/SabreTools.Models/VBSP/Lump.cs +++ b/SabreTools.Models/BSP/VbspLumpEntry.cs @@ -1,24 +1,22 @@ using System.Runtime.InteropServices; -namespace SabreTools.Models.VBSP +namespace SabreTools.Models.BSP { /// + /// [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - public sealed class Lump + public sealed class VbspLumpEntry : BspLumpEntry { - public uint Offset; - - public uint Length; - /// - /// Default to zero. + /// Lump format version /// public uint Version; /// - /// Default to (char)0, (char)0, (char)0, (char)0. + /// Lump ident code /// + /// Default to 0, 0, 0, 0 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public char[]? FourCC; + public byte[]? FourCC = new byte[4]; } } diff --git a/SabreTools.Models/BSP/VbspModel.cs b/SabreTools.Models/BSP/VbspModel.cs new file mode 100644 index 0000000..84cb3be --- /dev/null +++ b/SabreTools.Models/BSP/VbspModel.cs @@ -0,0 +1,45 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// A Model, in the terminology of the BSP file format, is a collection + /// of brushes and faces, often called a "bmodel". It should not be + /// confused with the prop models used in Hammer, which are usually + /// called "studiomodels" in the SDK source. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class VbspModel + { + /// + /// Bounding box + /// + public Vector3D Mins; + + /// + /// Bounding box + /// + public Vector3D Maxs; + + /// + /// For sounds or lights + /// + public Vector3D OriginVector; + + /// + /// Index into nodes + /// + public int HeadNode; + + /// + /// Index into faces + /// + public int FirstFaceIndex; + + /// + /// Count of faces + /// + public int FacesCount; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/VbspModelsLump.cs b/SabreTools.Models/BSP/VbspModelsLump.cs new file mode 100644 index 0000000..1bd4a39 --- /dev/null +++ b/SabreTools.Models/BSP/VbspModelsLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class VbspModelsLump : Lump + { + /// + /// Model + /// + public VbspModel[]? Models { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/NodesLump.cs b/SabreTools.Models/BSP/VbspNode.cs similarity index 73% rename from SabreTools.Models/BSP/NodesLump.cs rename to SabreTools.Models/BSP/VbspNode.cs index 8e3b1b2..3bc8844 100644 --- a/SabreTools.Models/BSP/NodesLump.cs +++ b/SabreTools.Models/BSP/VbspNode.cs @@ -1,3 +1,5 @@ +using System.Runtime.InteropServices; + namespace SabreTools.Models.BSP { /// @@ -19,11 +21,19 @@ namespace SabreTools.Models.BSP /// first of nFaces surfaces contained in this node. /// /// - public sealed class NodesLump : Lump + /// + [StructLayout(LayoutKind.Sequential)] + public class VbspNode : BspNode { /// - /// Nodes + /// If all leaves below this node are in the same area, then + /// this is the area index. If not, this is -1. /// - public Node[]? Nodes { get; set; } + public short Area; + + /// + /// Pad to 32 bytes length + /// + public short Padding; } } \ No newline at end of file diff --git a/SabreTools.Models/BSP/VbspNodesLump.cs b/SabreTools.Models/BSP/VbspNodesLump.cs new file mode 100644 index 0000000..9530d8d --- /dev/null +++ b/SabreTools.Models/BSP/VbspNodesLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class VbspNodesLump : Lump + { + /// + /// Nodes + /// + public VbspNode[]? Nodes { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/VbspTexinfo.cs b/SabreTools.Models/BSP/VbspTexinfo.cs new file mode 100644 index 0000000..b0d1cd7 --- /dev/null +++ b/SabreTools.Models/BSP/VbspTexinfo.cs @@ -0,0 +1,72 @@ +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 VbspTexinfo + { + /// + /// Texture S-vector + /// + public Vector3D TextureSVector; + + /// + /// Texture shift in the S direction + /// + public float TextureSShift; + + /// + /// Texture T-vector + /// + public Vector3D TextureTVector; + + /// + /// Texture shift in the T direction + /// + public float TextureTShift; + + /// + /// Lightmap S-vector + /// + public Vector3D LightmapSVector; + + /// + /// Lightmap shift in the S direction + /// + public float LightmapSShift; + + /// + /// Lightmap T-vector + /// + public Vector3D LightmapTVector; + + /// + /// Lightmap shift in the T direction + /// + public float LightmapTShift; + + /// + /// Texture flags + /// + public TextureFlag Flags; + + /// + /// Pointer to texture name, size, etc. + /// + public int TexData; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/VbspTexinfoLump.cs b/SabreTools.Models/BSP/VbspTexinfoLump.cs new file mode 100644 index 0000000..02f766b --- /dev/null +++ b/SabreTools.Models/BSP/VbspTexinfoLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class VbspTexinfoLump : Lump + { + /// + /// Texinfos + /// + public VbspTexinfo[]? Texinfos { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/VerticesLump.cs b/SabreTools.Models/BSP/VerticesLump.cs index c89b6c9..0c73806 100644 --- a/SabreTools.Models/BSP/VerticesLump.cs +++ b/SabreTools.Models/BSP/VerticesLump.cs @@ -5,6 +5,7 @@ namespace SabreTools.Models.BSP /// They are stored as a primitve array of triples of floats. /// /// + /// public sealed class VerticesLump : Lump { /// diff --git a/SabreTools.Models/BSP/VisibilityLump.cs b/SabreTools.Models/BSP/VisibilityLump.cs index b648517..5b4f8ec 100644 --- a/SabreTools.Models/BSP/VisibilityLump.cs +++ b/SabreTools.Models/BSP/VisibilityLump.cs @@ -11,8 +11,12 @@ namespace SabreTools.Models.BSP /// sequences of bitfields, which are run-length encoded. /// /// + /// public sealed class VisibilityLump { - public byte[]? Data { get; set; } + public int NumClusters { get; set; } + + /// [numclusters][2] + public int[,]? ByteOffsets { get; set; } } } \ No newline at end of file diff --git a/SabreTools.Models/BSP/WorldLight.cs b/SabreTools.Models/BSP/WorldLight.cs new file mode 100644 index 0000000..fd10eb9 --- /dev/null +++ b/SabreTools.Models/BSP/WorldLight.cs @@ -0,0 +1,70 @@ +using System.Runtime.InteropServices; + +namespace SabreTools.Models.BSP +{ + /// + /// The worldlights lumps (Lump 15 for LDR and Lump 54 for HDR) + /// contain information on each static light entity in the world, + /// and are used to provide direct lighting for dynamically lit entities. + /// The data is generated by VRAD from the entity lump. VRAD uses + /// information from these lumps instead of referring to light + /// entities from Entity lump. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public sealed class WorldLight + { + public Vector3D Origin; + + public Vector3D Intensity; + + /// + /// For surfaces and spotlights + /// + public Vector3D Normal; + + public int Cluster; + + public EmitType EmitType; + + public int Style; + + /// + /// Start of penumbra for emit_spotlight + /// + public float StopDot; + + /// + /// End of penumbra for emit_spotlight + /// + public float StopDot2; + + public float Exponent; + + /// + /// Cutoff distance + /// + public float Radius; + + // falloff for emit_spotlight + emit_point: + // 1 / (constant_attn + linear_attn * dist + quadratic_attn * dist^2) + + public float ConstantAttn; + + public float LinearAttn; + + public float QuadraticAttn; + + /// + /// Uses a combination of the DWL_FLAGS_ defines. + /// + public int Flags; + + public int Texinfo; + + /// + /// Entity that this light it relative to + /// + public int Owner; + } +} \ No newline at end of file diff --git a/SabreTools.Models/BSP/WorldLightsLump.cs b/SabreTools.Models/BSP/WorldLightsLump.cs new file mode 100644 index 0000000..ea554b3 --- /dev/null +++ b/SabreTools.Models/BSP/WorldLightsLump.cs @@ -0,0 +1,11 @@ +namespace SabreTools.Models.BSP +{ + /// + public sealed class WorldLightsLump : Lump + { + /// + /// WorldLights + /// + public WorldLight[]? WorldLights { get; set; } + } +} \ No newline at end of file diff --git a/SabreTools.Models/VBSP/Constants.cs b/SabreTools.Models/VBSP/Constants.cs deleted file mode 100644 index 4611345..0000000 --- a/SabreTools.Models/VBSP/Constants.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace SabreTools.Models.VBSP -{ - public static class Constants - { - public static readonly byte[] SignatureBytes = [0x56, 0x42, 0x53, 0x50]; - - public const string SignatureString = "VBSP"; - - public const uint SignatureUInt32 = 0x50534256; - - /// - /// Total number of lumps in the package - /// - public const int HL_VBSP_LUMP_COUNT = 64; - - /// - /// Index for the entities lump - /// - public const int HL_VBSP_LUMP_ENTITIES = 0; - - /// - /// Index for the pakfile lump - /// - public const int HL_VBSP_LUMP_PAKFILE = 40; - } -} \ No newline at end of file diff --git a/SabreTools.Models/VBSP/File.cs b/SabreTools.Models/VBSP/File.cs deleted file mode 100644 index edd1bfd..0000000 --- a/SabreTools.Models/VBSP/File.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace SabreTools.Models.VBSP -{ - /// - /// Half-Life 2 Level - /// - /// - public sealed class File - { - /// - /// Directory header data - /// - public Header? Header { get; set; } - } -} \ No newline at end of file diff --git a/SabreTools.Models/VBSP/Header.cs b/SabreTools.Models/VBSP/Header.cs deleted file mode 100644 index 9376d3c..0000000 --- a/SabreTools.Models/VBSP/Header.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace SabreTools.Models.VBSP -{ - /// - public sealed class Header - { - /// - /// BSP file signature. - /// - public string? Signature { get; set; } - - /// - /// BSP file version. - /// - /// - /// 19-20: Source - /// 21: Source - The lump version property was moved to the start of the struct. - /// 0x00040014: Dark Messiah - Looks like the 32 bit version has been split into two 16 bit fields. - /// - public int Version { get; set; } - - /// - /// Lumps. - /// - public Lump?[]? Lumps { get; set; } - - /// - /// The map's revision (iteration, version) number. - /// - public int MapRevision { get; set; } - } -} diff --git a/SabreTools.Models/VBSP/LumpHeader.cs b/SabreTools.Models/VBSP/LumpHeader.cs deleted file mode 100644 index a42c0ba..0000000 --- a/SabreTools.Models/VBSP/LumpHeader.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Runtime.InteropServices; - -namespace SabreTools.Models.VBSP -{ - /// - [StructLayout(LayoutKind.Sequential)] - public sealed class LumpHeader - { - public int LumpOffset; - - public int LumpID; - - public int LumpVersion; - - public int LumpLength; - - public int MapRevision; - } -}