17 |
Unofficial BSP v30 File Spec
18 |
19 |
Table of content
20 |
21 | - Introduction
22 | - Header
23 | - LUMP_ENTITIES
24 | - LUMP_PLANES
25 | - LUMP_TEXTURES
26 | - LUMP_VERTICES
27 | - LUMP_VISIBILITY
28 | - LUMP_NODES
29 | - LUMP_TEXINFO
30 | - LUMP_FACES
31 | - LUMP_LIGHTING
32 | - LUMP_CLIPNODES
33 | - LUMP_LEAVES
34 | - LUMP_MARKSURFACES
35 | - LUMP_EDGES
36 | - LUMP_SURFEDGES
37 | - LUMP_MODELS
38 |
39 |
40 |
41 |
42 |
43 | The following file specification concerns the BSP file format version
44 | 30, as it has been designed by the game developper Valve and used in
45 | their famous GoldSrc Engine. The file extension is ".bsp".
46 |
47 |
48 |
49 | Important: The following informations do NOT rely on any
50 | officially published file specification from Valve Corporation.
51 | The file format is still in use by the proprietary Half-Life Engine
52 | (better known name of the GoldSrc Engine) implying that there is no
53 | public source code of either the file loader or renderer.
54 | The following specification has been put together based on informations
55 | from the open source project Black Engine as well as the compilers included in the Half-Life SDK which also contains their source.
56 |
57 |
58 |
59 | This file spec uses constructs from the C programming language to
60 | describe the different data structures used in the BSP file format.
61 | Architecture dependent datatypes like integers are replaced by
62 | exact-width integer types of the C99 standard in the stdint.h header
63 | file, to provide more flexibillity when using x64 platforms.
64 | Basic knowledge about Binary Space Partitioning
65 | is recommended.
66 |
67 | There is a common struct used to represent a point in 3-dimensional
68 | space which is used throughout the file spec and the code of the hlbsp
69 | project.
70 |
71 |
72 |
73 | #include <stdint.h>
74 |
75 | typedef struct _VECTOR3D
76 | {
77 | float x, y, z;
78 | } VECTOR3D;
79 |
80 |
81 |
82 |
83 | Like almost every file also a BSP file starts with a specific file header which is constucted as follows:
84 |
85 |
86 |
87 | #define LUMP_ENTITIES 0
88 | #define LUMP_PLANES 1
89 | #define LUMP_TEXTURES 2
90 | #define LUMP_VERTICES 3
91 | #define LUMP_VISIBILITY 4
92 | #define LUMP_NODES 5
93 | #define LUMP_TEXINFO 6
94 | #define LUMP_FACES 7
95 | #define LUMP_LIGHTING 8
96 | #define LUMP_CLIPNODES 9
97 | #define LUMP_LEAVES 10
98 | #define LUMP_MARKSURFACES 11
99 | #define LUMP_EDGES 12
100 | #define LUMP_SURFEDGES 13
101 | #define LUMP_MODELS 14
102 | #define HEADER_LUMPS 15
103 |
104 | typedef struct _BSPHEADER
105 | {
106 | int32_t nVersion; // Must be 30 for a valid HL BSP file
107 | BSPLUMP lump[HEADER_LUMPS]; // Stores the directory of lumps
108 | } BSPHEADER;
109 |
110 |
111 | The file header begins with an 32bit integer containing the file version
112 | of the BSP file (the magic number). This should be 30 for a valid BSP
113 | file used by the Half-Life Engine.
114 | Subseqently, there is an array of entries for the so-called lumps. A
115 | lump is more or less a section of the file containing a specific type of
116 | data. The lump entries in the file header address these lumps, accessed
117 | by the 15 predefined indexes. A lump entry struct is defined as
118 | follows:
119 |
120 |
121 |
122 | typedef struct _BSPLUMP
123 | {
124 | int32_t nOffset; // File offset to data
125 | int32_t nLength; // Length of data
126 | } BSPLUMP;
127 |
128 |
129 | To read the different lumps from the given BSP file, every lump entry
130 | file states the beginning of each lump as an offset relativly to the
131 | beginning of the file. Additionally, the lump entry also gives the
132 | length of the addressed lump in bytes.
133 |
134 | The Half-Life BSP compilers also define several constants for the
135 | maximum size of each lump, as they use static, global arrays to hold the
136 | data. The hlbsp project uses malloc() to allocate the required memory
137 | for each lump depending on their actual size.
138 |
139 |
140 |
141 | #define MAX_MAP_HULLS 4
142 |
143 | #define MAX_MAP_MODELS 400
144 | #define MAX_MAP_BRUSHES 4096
145 | #define MAX_MAP_ENTITIES 1024
146 | #define MAX_MAP_ENTSTRING (128*1024)
147 |
148 | #define MAX_MAP_PLANES 32767
149 | #define MAX_MAP_NODES 32767
150 | #define MAX_MAP_CLIPNODES 32767
151 | #define MAX_MAP_LEAFS 8192
152 | #define MAX_MAP_VERTS 65535
153 | #define MAX_MAP_FACES 65535
154 | #define MAX_MAP_MARKSURFACES 65535
155 | #define MAX_MAP_TEXINFO 8192
156 | #define MAX_MAP_EDGES 256000
157 | #define MAX_MAP_SURFEDGES 512000
158 | #define MAX_MAP_TEXTURES 512
159 | #define MAX_MAP_MIPTEX 0x200000
160 | #define MAX_MAP_LIGHTING 0x200000
161 | #define MAX_MAP_VISIBILITY 0x200000
162 |
163 | #define MAX_MAP_PORTALS 65536
164 |
165 |
166 | The following sections will focus on every lump of the BSP file.
167 |
168 |
169 |
170 |
171 |
172 | The entity lump is basically a pure ASCII text section. It consists of
173 | the string representations of all entities, which are copied directly
174 | from the input file to the output BSP file by the compiler.
175 | An entity might look like this:
176 |
177 |
178 |
179 | {
180 | "origin" "0 0 -64"
181 | "angles" "0 0 0"
182 | "classname" "info_player_start"
183 | }
184 |
185 |
186 | Every entity begins and ends with curly brackets. Inbetween there are
187 | the attributes of the entity, one in each line, which are pairs of
188 | strings enclosed by quotes. The first string is the name of the
189 | attribute (the key), the second one its value. The attribute "classname"
190 | is mandatory for every entity specifiying its type and therefore, how
191 | it is interpreted by the engine.
192 |
193 |
194 |
195 | The map compilers also define two constants for the maximum length of key and value:
196 |
197 |
198 |
199 | #define MAX_KEY 32
200 | #define MAX_VALUE 1024
201 |
202 |
203 |
204 |
205 | This lump is a simple array of binary data structures:
206 |
207 |
208 |
209 | #define PLANE_X 0 // Plane is perpendicular to given axis
210 | #define PLANE_Y 1
211 | #define PLANE_Z 2
212 | #define PLANE_ANYX 3 // Non-axial plane is snapped to the nearest
213 | #define PLANE_ANYY 4
214 | #define PLANE_ANYZ 5
215 |
216 | typedef struct _BSPPLANE
217 | {
218 | VECTOR3D vNormal; // The planes normal vector
219 | float fDist; // Plane equation is: vNormal * X = fDist
220 | int32_t nType; // Plane type, see #defines
221 | } BSPPLANE;
222 |
223 |
224 | Each of this structures defines a plane in 3-dimensional space by using the Hesse normal form:
225 |
226 |
227 |
228 | normal * point - distance = 0
229 |
230 |
231 |
232 | Where vNormal is the normalized normal vector of the plane and fDist is
233 | the distance of the plane to the origin of the coord system.
234 | Additionally, the structure also saves an integer describing the
235 | orientation of the plane in space. If nType equals PLANE_X, then the
236 | normal of the plane will be parallel to the x axis, meaning the plane is
237 | perpendicular to the x axis. If nType equals PLANE_ANYX, then the
238 | plane's normal is nearer to the x axis then to any other axis. This
239 | information is used by the renderer to speed up some computations.
240 |
241 |
242 |
243 |
244 |
245 | The texture lump is somehow a bit more complex then the other lumps,
246 | because it is possible to save textures directly within the BSP file
247 | instead of storing them in external WAD files. This lump also starts with a small header:
248 |
249 |
250 |
251 | typedef struct _BSPTEXTUREHEADER
252 | {
253 | uint32_t nMipTextures; // Number of BSPMIPTEX structures
254 | } BSPTEXTUREHEADER;
255 |
256 |
257 | The header only consists of an unsigned 32bit integer indicating the
258 | number of stored or referenced textures in the texture lump. After the
259 | header follows an array of 32bit offsets pointing to the beginnings of
260 | the seperate textures.
261 |
262 |
263 |
264 | typedef int32_t BSPMIPTEXOFFSET;
265 |
266 |
267 | Every offset gives the distance in bytes from the beginning of the
268 | texture lump to one of the beginnings of the BSPMIPTEX structure, which
269 | are equal in count to the value given in the texture header.
270 |
271 |
272 |
273 | #define MAXTEXTURENAME 16
274 | #define MIPLEVELS 4
275 | typedef struct _BSPMIPTEX
276 | {
277 | char szName[MAXTEXTURENAME]; // Name of texture
278 | uint32_t nWidth, nHeight; // Extends of the texture
279 | uint32_t nOffsets[MIPLEVELS]; // Offsets to texture mipmaps BSPMIPTEX;
280 | } BSPMIPTEX;
281 |
282 |
283 | Each of this structs describes a texture.
284 | The name of the texture is a string and may be 16 characters long
285 | (including the null-character at the end, char equals a 8bit signed
286 | integer).
287 | The name of the texture is needed, if the texture has to be found and
288 | loaded from an external WAD file. Furthermore, the struct contains the
289 | width and height of the texture.
290 | The 4 offsets at the end can either be zero, if the texture is stored in
291 | an external WAD file, or point to the beginnings of the binary texture
292 | data within the texture lump relative to the beginning of it's BSPMIPTEX
293 | struct.
294 |
295 |
296 |
297 |
298 |
299 | This lump simply consists of all vertices of the BSP tree. They are stored as a primitve array of triples of floats.
300 |
301 |
302 |
303 | typedef VECTOR3D BSPVERTEX;
304 |
305 |
306 | Each of this triples, obviously, represents a point in 3-dimensional space by giving its three coordinates.
307 |
308 |
309 |
310 |
311 |
312 | The VIS lump contains data, which is irrelevant to the actual BSP tree,
313 | but offers a way to boost up the speed of the renderer significantly.
314 | Especially complex maps profit from the use if this data. This lump
315 | contains the so-called Potentially Visible Sets (PVS) (also called VIS
316 | lists) in the same amout of leaves of the tree, the user can enter
317 | (often referred to as VisLeaves). The visiblilty lists are stored as
318 | sequences of bitfields, which are run-length encoded.
319 | Important: The generation of the VIS data is a very time
320 | consuming process (several hours) and also done by a seperate compiler.
321 | It can therefore be skipped when compiling the map, resulting in BSP
322 | files with no VIS data at all!
323 |
324 |
325 |
326 |
327 |
328 | This lump is simple again and contains an array of binary structures, the nodes, which are a major part of the BSP tree.
329 |
330 |
331 |
332 | typedef struct _BSPNODE
333 | {
334 | uint32_t iPlane; // Index into Planes lump
335 | int16_t iChildren[2]; // If > 0, then indices into Nodes // otherwise bitwise inverse indices into Leafs
336 | int16_t nMins[3], nMaxs[3]; // Defines bounding box
337 | uint16_t firstFace, nFaces; // Index and count into Faces
338 | } BSPNODE;
339 |
340 |
341 | Every BSPNODE structure represents a node in the BSP tree and every node
342 | equals more or less a division step of the BSP algorithm. Therefore,
343 | each node has an index (iPlane) referring to a plane in the plane lump
344 | which devides the node into its two child nodes. The childnodes are also
345 | stored as indexes. Contrary to the plane index, the node index for the
346 | child is signed. If the index is larger than 0, the index indicates a
347 | child node. If it is equal to or smaller than zero (no valid array
348 | index), the bitwise inversed value of the index gives an index into the
349 | leaves lump. Additionally two points (nMins, nMaxs) span the bounding
350 | box (AABB, axis aligned bounding box) delimitting the space of the node.
351 | Finally firstFace indexes into the face lump and spezifies the first of
352 | nFaces surfaces contained in this node.
353 |
354 |
355 |
356 |
357 |
358 | The texinfo lump contains informations about how textures are applied to
359 | surfaces. The lump itself is an array of binary data structures.
360 |
361 |
362 |
363 | typedef struct _BSPTEXTUREINFO
364 | {
365 | VECTOR3D vS;
366 | float fSShift; // Texture shift in s direction
367 | VECTOR3D vT;
368 | float fTShift; // Texture shift in t direction
369 | uint32_t iMiptex; // Index into textures array
370 | uint32_t nFlags; // Texture flags, seem to always be 0
371 | } BSPTEXTUREINFO;
372 |
373 | This struct is mainly responsible for the calculation of the texture
374 | coordinates (vS, fSShift, vT, fTShift). This values determine the
375 | position of the texture on the surface. The iMiptex integer refers to
376 | the textures in the texture lump and would be the index in an array of
377 | BSPMITEX structs. Finally, there are 4 Bytes used for flags. Somehow
378 | they seem to always be 0;
379 |
380 |
381 |
382 |
383 |
384 | The face lump contains the surfaces of the scene. Once again an array of structs:
385 |
386 |
387 |
388 | typedef struct _BSPFACE
389 | {
390 | uint16_t iPlane; // Plane the face is parallel to
391 | uint16_t nPlaneSide; // Set if different normals orientation
392 | uint32_t iFirstEdge; // Index of the first surfedge
393 | uint16_t nEdges; // Number of consecutive surfedges
394 | uint16_t iTextureInfo; // Index of the texture info structure
395 | uint8_t nStyles[4]; // Specify lighting styles
396 | uint32_t nLightmapOffset; // Offsets into the raw lightmap data
397 | } BSPFACE;
398 |
399 |
400 | The first number of this data structure is an index into the planes lump
401 | giving a plane which is parallel to this face (meaning they share the
402 | same normal). The second value may be seen as a boolean. If nPlaneSide
403 | equals 0, then the normal vector of this face equals the one of the
404 | parallel plane exactly. Otherwise, the normal of the plane has to be
405 | multiplied by -1 to point into the right direction. Afterwards we have
406 | an index into the surfedges lump, as well as the count of consecutive
407 | surfedges from that position. Furthermore there is an index into the
408 | texture info lump, which is used to find the BSPTEXINFO structure needed
409 | to calculate the texture coordinates for this face. Afterwards, there
410 | are four bytes giving some lighting information (partly used by the
411 | renderer to hide sky surfaces). Finally we have an offset in byes giving
412 | the beginning of the binary lightmap data of this face in the lighting
413 | lump.
414 |
415 |
416 |
417 |
418 |
419 | This is one of the largest lumps in the BSP file. The lightmap lump
420 | stores all lightmaps used in the entire map. The lightmaps are arrays of
421 | triples of bytes (3 channel color, RGB) and stored continuously.
422 |
423 |
424 |
425 |
426 |
427 | This lump contains the so-called clipnodes, which build a second BSP tree used only for collision detection.
428 |
429 |
430 |
431 | typedef struct _BSPCLIPNODE
432 | {
433 | int32_t iPlane; // Index into planes
434 | int16_t iChildren[2]; // negative numbers are contents
435 | } BSPCLIPNODE;
436 |
437 |
438 | This structure is a reduced form of the BSPNODE struct from the nodes
439 | lump. Also the BSP tree built by the clipnodes is simpler than the one
440 | described by the BSPNODEs to accelerate collision calculations.
441 |
442 |
443 |
444 |
445 |
446 | The leaves lump contains the leaves of the BSP tree. Another array of binary structs:
447 |
448 |
449 |
450 | #define CONTENTS_EMPTY -1
451 | #define CONTENTS_SOLID -2
452 | #define CONTENTS_WATER -3
453 | #define CONTENTS_SLIME -4
454 | #define CONTENTS_LAVA -5
455 | #define CONTENTS_SKY -6
456 | #define CONTENTS_ORIGIN -7
457 | #define CONTENTS_CLIP -8
458 | #define CONTENTS_CURRENT_0 -9
459 | #define CONTENTS_CURRENT_90 -10
460 | #define CONTENTS_CURRENT_180 -11
461 | #define CONTENTS_CURRENT_270 -12
462 | #define CONTENTS_CURRENT_UP -13
463 | #define CONTENTS_CURRENT_DOWN -14
464 | #define CONTENTS_TRANSLUCENT -15
465 |
466 | typedef struct _BSPLEAF
467 | {
468 | int32_t nContents; // Contents enumeration
469 | int32_t nVisOffset; // Offset into the visibility lump
470 | int16_t nMins[3], nMaxs[3]; // Defines bounding box
471 | uint16_t iFirstMarkSurface, nMarkSurfaces; // Index and count into marksurfaces array
472 | uint8_t nAmbientLevels[4]; // Ambient sound levels
473 | } BSPLEAF;
474 |
475 |
476 | The first entry of this struct is the type of the content of this leaf.
477 | It can be one of the predefined values, found in the compiler source
478 | codes, and is litte relevant for the actual rendering process. All the
479 | more important is the next integer containing the offset into the vis
480 | lump. It defines the start of the raw PVS data for this leaf. If this
481 | value equals -1, no VIS lists are available for this leaf, usually if
482 | the map has been built without the VIS compiler. The next two 16bit
483 | integer triples span the bounding box of this leaf. Furthermore, the
484 | struct contains an index pointing into the array of marksurfaces loaded
485 | from the marksufaces lump as well as the number of consecutive
486 | marksurfaces belonging to this leaf. The marksurfaces are looped through
487 | during the rendering process and point to the actual faces. The final 4
488 | bytes somehow spezify the volume of the ambient sounds.
489 |
490 |
491 |
492 |
493 |
494 | The marksurfaces lump is a simple array of short integers.
495 |
496 |
497 |
498 | typedef uint16_t BSPMARKSURFACE;
499 |
500 |
501 | This lump is a simple table for redirecting the marksurfaces indexes in
502 | the leafs to the actial face indexes. A leaf inserts it's marksurface
503 | indexes into this array and gets the associated faces contained within
504 | this leaf.
505 |
506 |
507 |
508 |
509 |
510 | The edges are defined as an array of structs:
511 |
512 |
513 |
514 | typedef struct _BSPEDGE
515 | {
516 | uint16_t iVertex[2]; // Indices into vertex array
517 | } BSPEDGE;
518 |
519 |
520 | The edges delimit the face and further refer to the vertices of the
521 | face. Each edge is pointing to the start and end vertex of the edge.
522 |
523 |
524 |
525 |
526 |
527 | Another array of integers.
528 |
529 |
530 |
531 | typedef int32_t BSPSURFEDGE;
532 |
533 |
534 | This lump represents pretty much the same mechanism as the marksurfaces.
535 | A face can insert its surfedge indexes into this array to get the
536 | corresponding edges delimitting the face and further pointing to the
537 | vertexes, which are required for rendering. The index can be positive or
538 | negative. If the value of the surfedge is positive, the first vertex of
539 | the edge is used as vertex for rendering the face, otherwise, the value
540 | is multiplied by -1 and the second vertex of the indexed edge is used.
541 |
542 |
543 |
544 |
545 |
546 | Array of structs:
547 |
548 |
549 |
550 | #define MAX_MAP_HULLS 4
551 |
552 | typedef struct _BSPMODEL
553 | {
554 | float nMins[3], nMaxs[3]; // Defines bounding box
555 | VECTOR3D vOrigin; // Coordinates to move the // coordinate system
556 | int32_t iHeadnodes[MAX_MAP_HULLS]; // Index into nodes array
557 | int32_t nVisLeafs; // ???
558 | int32_t iFirstFace, nFaces; // Index and count into faces
559 | } BSPMODEL;
560 |
561 |
562 | A model is kind of a mini BSP tree. Its size is determinded by the
563 | bounding box spaned by the first to members of this struct. The major
564 | difference between a model and the BSP tree holding the scene is that
565 | the models use a local coordinate system for their vertexes and just
566 | state its origin in world coordinates. During rendering the coordinate
567 | system is translated to the origin of the model (glTranslate()) and
568 | moved back after the models BSP tree has been traversed. Furthermore
569 | their are 4 indexes into node arrays. The first one has proofed to index
570 | the root node of the mini BSP tree used for rendering. The other three
571 | indexes could probably be used for collision detection, meaning they
572 | point into the clipnodes, but I am not sure about this. The meaning of
573 | the next value is also somehow unclear to me. Finally their are direct
574 | indexes into the faces array, not taking the redirecting by the
575 | marksurfaces.
576 |
577 |
578 |
579 |
580 |
--------------------------------------------------------------------------------