BSPParser
Simple and modern library for parsing the Valve BSP format
Loading...
Searching...
No Matches
bsp.hpp
1#pragma once
2
3#include "errors.hpp"
4#include "phys-model.hpp"
5#include "displacements/triangulated-displacement.hpp"
6#include "enums/lump.hpp"
7#include "helpers/offset-data-view.hpp"
8#include "helpers/zip.hpp"
9#include "structs/common.hpp"
10#include "structs/detail-props.hpp"
11#include "structs/displacements.hpp"
12#include "structs/geometry.hpp"
13#include "structs/headers.hpp"
14#include "structs/models.hpp"
15#include "structs/static-props.hpp"
16#include "structs/textures.hpp"
17#include <format>
18#include <span>
19#include <string>
20#include <variant>
21#include <vector>
22
23namespace BspParser {
29 struct Bsp {
30 explicit Bsp(std::span<const std::byte> data);
31
32 std::span<const std::byte> data;
33
34 const Structs::Header* header = nullptr;
35
36 std::span<const Structs::GameLump> gameLumps;
37
38 std::span<const Structs::Vector> vertices;
39 std::span<const Structs::Plane> planes;
40 std::span<const Structs::Edge> edges;
41 std::span<const int32_t> surfaceEdges;
42 std::span<const Structs::Face> faces;
43
44 std::span<const Structs::TexInfo> textureInfos;
45 std::span<const Structs::TexData> textureDatas;
46 std::span<const int32_t> textureStringTable;
47 std::span<const char> textureStringData;
48
49 std::span<const Structs::Model> models;
50
51 std::span<const Structs::DispInfo> displacementInfos;
52 std::span<const Structs::DispVert> displacementVertices;
53
58 std::vector<TriangulatedDisplacement> displacements;
59
60 std::vector<PhysModel> physicsModels;
61
62 std::vector<Zip::ZipFileEntry> compressedPakfile;
63
64 // std::span<const Structs::DetailObjectDict> detailObjectDictionary;
65 // std::span<const Structs::DetailObject> detailObjects;
66
67 std::optional<std::span<const Structs::StaticPropDict>> staticPropDictionary = std::nullopt;
68 std::optional<std::span<const Structs::StaticPropLeaf>> staticPropLeaves = std::nullopt;
69
70 std::optional<std::variant<
71 std::span<const Structs::StaticPropV4>,
72 std::span<const Structs::StaticPropV5>,
73 std::span<const Structs::StaticPropV6>,
74 std::span<const Structs::StaticPropV7Multiplayer2013>>>
75 staticProps = std::nullopt;
76
82
83 private:
84 template <typename LumpType>
85 std::span<const LumpType> parseLump(Enums::Lump lump, size_t maxItems = std::numeric_limits<size_t>::max()) {
86 const auto& lumpHeader = header->lumps.at(static_cast<size_t>(lump));
87
88 assertLumpHeaderValid(lump, lumpHeader);
89
90 if (lumpHeader.length % sizeof(LumpType) != 0) {
91 throw Errors::InvalidBody(
92 lump,
93 std::format(
94 "Lump header has length ({}) which is not a multiple of the size of its item type ({})",
95 lumpHeader.length,
96 sizeof(LumpType)
97 )
98 );
99 }
100
101 const auto numItems = lumpHeader.length / sizeof(LumpType);
102 if (numItems > maxItems) {
103 throw Errors::InvalidBody(
104 lump, std::format("Number of lump items ({}) exceeds source engine maximum ({})", numItems, maxItems)
105 );
106 }
107
108 return std::span<const LumpType>(reinterpret_cast<const LumpType*>(&data[lumpHeader.offset]), numItems);
109 }
110
111 [[nodiscard]] std::span<const Structs::GameLump> parseGameLumpHeaders() const;
112
113 [[nodiscard]] std::vector<PhysModel> parsePhysCollideLump() const;
114
115 template <class StaticProp>
116 [[nodiscard]] std::span<const StaticProp> parseStaticPropLump(const Structs::GameLump& lumpHeader) {
117 if (lumpHeader.offset < 0) {
118 throw Errors::InvalidBody(
119 Enums::Lump::GameLump,
120 std::format("Static prop game lump header has a negative offset ({})", lumpHeader.offset)
121 );
122 }
123
124 if (lumpHeader.length < 0) {
125 throw Errors::InvalidBody(
126 Enums::Lump::GameLump,
127 std::format("Static prop game lump header has a negative length ({})", lumpHeader.length)
128 );
129 }
130
131 if (lumpHeader.offset + lumpHeader.length > data.size_bytes()) {
132 throw Errors::OutOfBoundsAccess(
133 Enums::Lump::GameLump,
134 std::format(
135 "Static prop game lump header has offset + length ({}) overrunning the file ({})",
136 lumpHeader.offset + lumpHeader.length,
137 data.size_bytes()
138 )
139 );
140 }
141
142 const auto dictionaryData = Internal::OffsetDataView(std::span(&data[lumpHeader.offset], lumpHeader.length));
143 const auto numDictionaryEntries = dictionaryData.parseStruct<int32_t>(
144 0, "Static prop game lump length is shorter than a single int32 for the dictionary count"
145 );
146 staticPropDictionary = dictionaryData.parseStructArray<Structs::StaticPropDict>(
147 sizeof(int32_t), numDictionaryEntries, "Static prop game lump dictionary entries overflowed the lump"
148 );
149
150 const auto leafData =
151 dictionaryData.withRelativeOffset(sizeof(int32_t) + numDictionaryEntries * sizeof(Structs::StaticPropDict));
152 const auto numLeaves = leafData.parseStruct<int32_t>(
153 0, "Static prop game lump length is shorter than its dictionary entries plus a single int32 for the leaf count"
154 );
155 staticPropLeaves = leafData.parseStructArray<Structs::StaticPropLeaf>(
156 sizeof(int32_t), numLeaves, "Static prop game lump leaves overflowed the lump"
157 );
158
159 const auto propData = leafData.withRelativeOffset(sizeof(int32_t) + numLeaves * sizeof(Structs::StaticPropLeaf));
160 const auto numProps = propData.parseStruct<int32_t>(
161 0, "Static prop game lump length is shorter than its dictionary, leaves, and a single int32 for the prop count"
162 );
163 const auto props = propData.parseStructArray<StaticProp>(
164 sizeof(int32_t), numProps, "Static prop game lump props overflowed the lump"
165 );
166
167 return props;
168 }
169
170 [[nodiscard]] std::vector<Zip::ZipFileEntry> parsePakfileLump() const;
171
172 void assertLumpHeaderValid(Enums::Lump lump, const Structs::Lump& lumpHeader) const;
173
174 [[nodiscard]] TriangulatedDisplacement createTriangulatedDisplacement(
175 const Structs::DispInfo& displacementInfo
176 ) const;
177 };
178}
Definition: BSPParser.hpp:8
Definition: bsp.hpp:29
void smoothNeighbouringDisplacements()
Definition: bsp.cpp:93
std::vector< TriangulatedDisplacement > displacements
Definition: bsp.hpp:58
Definition: headers.hpp:33
std::array< Lump, HEADER_LUMPS > lumps
Definition: headers.hpp:47