This website is still under construction.


BSP (Binary Space Partitioning) is file format used by GoldSource to store map data. The name is based on BSP rendering and it is optimized for it. Documentation I found: For creating map yourself, I recommend Valve Hammer Editor (3.x) or Sledge Editor.
I created my test map using Valve Hammer Editor 3.4, Build 2363 (for Counter-Strike 1.6).

Data

All data are Little Endian.
Header
Size (bytes) Data Type Name Description
4 byte[4]
or
unsigned int16
Version Version of BSP file.
0x1E000000 = 30
4 int16
or
unsigned int16
File Offset of Entities Lump Entities Lump .
4 int16
or
unsigned int16
Length in bytes of Entities Lump
4 int16
or
unsigned int16
File Offset of Planes Lump Planes Lump .
4 int16
or
unsigned int16
Length in bytes of Planes Lump
4 int16
or
unsigned int16
File Offset of Textures Lump Textures Lump .
4 int16
or
unsigned int16
Length in bytes of Textures Lump
4 int16
or
unsigned int16
File Offset of Vertices Lump Vertices Lump .
4 int16
or
unsigned int16
Length in bytes of Vertices Lump
4 int16
or
unsigned int16
File Offset of Visibility Lump Visibility Lump .
4 int16
or
unsigned int16
Length in bytes of Visibility Lump
4 int16
or
unsigned int16
File Offset of Nodes Lump Nodes Lump .
4 int16
or
unsigned int16
Length in bytes of Nodes Lump
4 int16
or
unsigned int16
File Offset of TextureInfo Lump TextureInfo Lump .
4 int16
or
unsigned int16
Length in bytes of TextureInfo Lump
4 int16
or
unsigned int16
File Offset of Faces Lump Faces Lump .
4 int16
or
unsigned int16
Length in bytes of Faces Lump
4 int16
or
unsigned int16
File Offset of Lighting Lump Lighting Lump .
4 int16
or
unsigned int16
Length in bytes of Lighting Lump
4 int16
or
unsigned int16
File Offset of ClipNodes Lump ClipNodes Lump .
4 int16
or
unsigned int16
Length in bytes of ClipNodes Lump
4 int16
or
unsigned int16
File Offset of Leaves Lump Leaves Lump .
4 int16
or
unsigned int16
Length in bytes of Leaves Lump
4 int16
or
unsigned int16
File Offset of MarkSurfaces Lump MarkSurfaces Lump .
4 int16
or
unsigned int16
Length in bytes of MarkSurfaces Lump
4 int16
or
unsigned int16
File Offset of Edges Lump Edges Lump .
4 int16
or
unsigned int16
Length in bytes of Edges Lump
4 int16
or
unsigned int16
File Offset of SurfaceEdges Lump SurfaceEdges Lump .
4 int16
or
unsigned int16
Length in bytes of SurfaceEdges Lump
4 int16
or
unsigned int16
File Offset of Models Lump Models Lump .
4 int16
or
unsigned int16
Length in bytes of Models Lump
#define LUMP_ENTITIES 0 #define LUMP_PLANES 1 #define LUMP_TEXTURES 2 #define LUMP_VERTICES 3 #define LUMP_VISIBILITY 4 #define LUMP_NODES 5 #define LUMP_TEXTURE_INFO 6 #define LUMP_FACES 7 #define LUMP_LIGHTING 8 #define LUMP_CLIP_NODES 9 #define LUMP_LEAVES 10 #define LUMP_MARKSURFACE 11 #define LUMP_EDGES 12 #define LUMP_SURFACE_EDGES 13 #define LUMP_MODELS 14 #define LUMPS_COUNT 15 typedef struct BSP_Lump_t { uint32_t Offset; uint32_t Length; } BSP_Lump; typedef struct BSP_Header_t { unit8_t Version[4]; BSP_Lump Lumps[LUMPS_COUNT]; } BSP_Header;

Entities

ID = 0
Entity lump is simple text lump.
1 byte = 1 character
Each line ends by 0x0A byte (\A).
Example (from test map):
{ "wad" "\half-life\cstrike\chateau.wad;\half-life\cstrike\cs_bdog.wad;\half-life\valve\halflife.wad;" "mapversion" "220" "MaxRange" "4096" "classname" "worldspawn" "classname" "worldspawn" } { "origin" "0 -256 64" "angles" "0 90 0" "classname" "info_player_start" } { "origin" "0 256 64" "angles" "0 270 0" "classname" "info_player_deathmatch" } { "origin" "0 0 192" "_light" "255 255 128 200" "classname" "light" } { "origin" "0 -448 192" "_light" "0 128 255 200" "classname" "light" } { "origin" "0 448 192" "_light" "255 0 0 200" "classname" "light" } { "origin" "448 0 192" "_light" "255 255 255 200" "classname" "light" } { "model" "*1" "team" "2" "classname" "func_buyzone" } { "model" "*2" "team" "1" "classname" "func_buyzone" } { "model" "*3" "material" "1" "health" "100" "rendercolor" "0 0 0" "spawnflags" "256" "classname" "func_breakable" }
Rules: Important notices:

Planes

ID = 1
Planes Lump is simple array of binary data.
Length of each structure are 20 bytes. That means this lump must have maximum length divisible by 20.
Planes Lump
Size (bytes) Data Type Name Description
12 float[3]
or
Vector3D
Normal Plane's Normal Vector.
4 float Distance Plane equation: Normal * X = Distance
4 int32_t
or
uint32_t
Type Plane type.
  1. X
  2. Y
  3. Z
  4. Any X
  5. Any Y
  6. Any Z
Values 0-2 mean that the plane is perpendicular to given axis.
Values 3-5 are non-axial and given axis is the nearest.

Used by renderer to speed up some computations.
typedef struct Vector3D_t { float X; float Y; float Z; } Vector3D; typedef struct BSP_Planes_Lump_t { Vector3D Normal; float Distance; uint32_t Type; } BSP_Planes_Lump;
The structure defines the plane in 3-dimensional space using Hesse normal form.
Normal * Point - Distance = 0

Textures

ID = 2
This lump is more complex then others.
It starts with header of offsets.
Textures Lump
Size (bytes) Data Type Name Description
4 uint32_t Texture Count Total number of textured (stored or referenced).
Count * 4 int32_t[Count]
or
uint32_t[Count]
Offsets for each texture Offsets from start of this lump to each texture.
typedef struct BSP_Textures_Lump_Header { uint32_t Count; uint32_t* Offsets; } BSP_Textures_Lump_Header;
On each offset is structure for the texture itself.
Textures Lump - Texture
Size (bytes) Data Type Name Description
16 char[16]
or
byte[16]
Name Name of this texture.
4 int32_t
or
uint32_t
Width Width of this texture.
4 int32_t
or
uint32_t
Height Height of this texture.
8 int32_t[4]
or
uint32_t[4]
MipMaps Offset to data of 4 MipMaps.
  1. Main texture.
  2. Half dimensions.
  3. Quarter dimensions.
  4. dimensions.
[0,0,0,0] for external textures (stored in WAD 3 files).
typedef struct BSP_Textures_Lump_Texture_t { char Name[16]; uint32_t Width; uint32_t Height; uint32_t MipMapOffsets[4]; } BSP_Textures_Lump_Texture;
If MipMap Offsets are not [0,0,0,0], then they are relative to start of the texture structure. After last MipMap, there is palette of colors because textures are stored as byte array pointing to colors in the palette.
typedef struct Color_24b_t { uint8_t Red; uint8_t Green; uint8_t Blue; } Color_24b; Color_24b Color[256];

Vertices

ID = 3
Vertices Lump is simple array of Vector3D (3 float coordinates, 12 bytes).
The Lump must be divisible by 12.
typedef struct Vector3D_t { float X; float Y; float Z; } Vector3D;
For converting into OBJ, I had to change coordinates to [-x, z, y]

Visibility

ID = 4
Borrowed from hlbsp project:
The VIS lump contains data, which is irrelevant to the actual BSP tree, but offers a way to boost up the speed of the renderer significantly. Especially complex maps profit from the use if this data. This lump contains the so-called Potentially Visible Sets (PVS) (also called VIS lists) in the same amout of leaves of the tree, the user can enter (often referred to as VisLeaves). The visiblilty lists are stored as sequences of bitfields, which are run-length encoded. Important: The generation of the VIS data is a very time consuming process (several hours) and also done by a seperate compiler. It can therefore be skipped when compiling the map, resulting in BSP files with no VIS data at all!

Nodes

ID = 5
Simple array of structure. Total length is 14 bytes (and this lump must be divisible by 14 again).
Nodes Lump
Size (bytes) Data Type Name Description
4 int32_t
or
uint32_t
Plane Index into Planes Lump
2 int16_t
or
uint16_t
1st Children Index If >0 then index into Nodes.
If <0 then bit inverted (~ operator) into Leaves
2 int16_t
or
uint16_t
2nd Children Index
6 int16_t[3] AABB Min Coordinates Coordinates of Axis Aligned Bounding Box.
6 int16_t[3] AABB Max Coordinates
2 int16_t
or
uint16_t
First Face Faces of this node.
Start index and number of faces.
2 int16_t
or
uint16_t
Face Count
May be in recursuin. ...

TextureInfo

ID = 6
TextureInfo Lump is referenced by Faces Lump and used to calculate UV Coordinates and Texture.
TextureInfo Lump
Size (bytes) Data Type Name Description
12 float[3]
or
Vector3D
Texture S Coordinates Used for calculating UV Coordinates.
Formula from Source BSP File Format - Texinfo
u = s.x * x + s.y * y + s.z * z + s_shift v = t.x * x + t.y * y + t.z * z + t_shift
x,y,z are coordinates of (build-time) position.
4 float Texture S Shift
12 float[3]
or
Vector3D
Texture T Coordinates
4 float Texture T Shift
4 int32_t
or
uint32_t
Texture Index Index into Texture in Textures Lump.
4 int32_t
or
uint32_t
Flags Texture Flags.
Probably similar to Source BSP File Format - Texinfo.
typedef struct BSP_TextureInfo_Lump_t { Vector3D S; float S_Shift; Vector3D T; float T_Shift; uint32_t Texture_Index; uint32_t Flags; } BSP_TextureInfo_Lump;

Faces

ID = 7
...
Faces Lump
Size (bytes) Data Type Name Description
2 int16_t
or
uint16_t
Plane Index Index into Planes Lump
2 int16_t
or
uint16_t
Plane Side Defines whenever is normal vector multiplied by -1 or not.
0 means not multiplied, otherwise multiplied by -1.
I do not know why there are 2 bytes for 1bit value and only 16bit number for Plane Index when on other places, there is 32bit number.
4 int32_t
or
uint32_t
First SurfaceEdge Indices into SurfaceEdges Lump.
2 int16_t
or
uint16_t
Number of SurfaceEdges
...
...

Lighting

ID = 8
Borrowed from hlbsp project: This is one of the largest lumps in the BSP file. The lightmap lump stores all lightmaps used in the entire map. The lightmaps are arrays of triples of bytes (3 channel color, RGB) and stored continuously. I did not figured out how this should be used.

ClipNodes

ID = 9
ClipNodes Lump is mostly similar to Nodes Lump but is used for collision detection. It is kept as simple as possible.
ClipNodes Lump
Size (bytes) Data Type Name Description
4 int32_t
or
uint32_t
Plane Index Index into Planes Lump
2 int16_t
or
uint16_t
1st Children Index Similar to Nodes' Children.
2 int16_t
or
uint16_t
2nd Children Index
...

Leaves

ID = 10
...

MarkSurfaces

ID = 11
...

Edges

ID = 12
...

SurfaceEdges

ID = 13
...

Models

ID = 14
...

Rendering

...