BSPX

BSPX is a standard for adding new lumps to , , and BSP files, which are used to add additional features to be used by source ports or custom renderers without breaking vanilla compatibility. As BSPX lumps are placed at the end of the BSP file, they are not loaded by vanilla engines, so a BSP with BSPX lumps is backwards compatible.
== Structure ==
typedef struct {
	char lumpname[24]; // up to 23 chars, zero-padded
	int fileofs; // from file start
	int filelen;
} bspx_lump_t;
typedef struct {
	char id[4]; // 'BSPX'
	int numlumps;
	bspx_lump_t lumps[1];
} bspx_header_t;
== Lumps ==
=== DECOUPLED_LM === 
"Decouples" lightmap scale, alignment, and rotation from those of texels.
Compile with ericw-tools using KV in worldspawn or in QBSP, wherein # is the luxel scale (like in face edit window).
The 2023 remaster uses with a luxel scale of 8 on all maps except for the Quake II 64 maps.
Unnecessary and possibly incompatible with Quake III's BSP format and derivatives, which store lightmaps as pages in the BSP file (or externally) instead of paginating at load time, and has no direct correlation between texel size and luxel size. Q3Map2 and some games support switch to use external TGA lightmaps, but for vanilla Quake III, use the parameter in the given material; see explanation.
=== LIGHTGRID_OCTREE ===
An -formatted 3D grid of RGB888 color values, used by dynamically lit models instead of being lit based upon the nearest (worldswawn) lightmap luxel or light_environment entity. 
This is used by all non-N64 maps in the 2023 remaster. 
Unnecessary with Quake III's BSP format and derivatives, which already contain lightgrids.
=== LIGHTING_E5BGR9 ===
Used for HDR lightmaps. Functions similarly to the RGBE8 lightmaps in , but with an additional bit of precision per color instead of having the exponent be 8 bits.
=== ENVMAP ===
Defines where cubemaps are found (Does not store the cubemaps themselves). Can be generated (alongside SURFENVMAP) from entities by loading the BSP in and running the console command. 
The following FGD entry represents the expected syntax:
@PointClass color(0 0 255) iconsprite("sprites/editor/env_cubemap.spr") = env_cubemap : 
	"An entity that creates a sample point for the Cubic Environment Map."
[
	size(choices) : "Cubemap Size" : 0 : "Resolution of the cubemap." =
	[
		0 : "Default"
		1 : "1x1"
		2 : "2x2"
		4 : "4x4"
		8 : "8x8"
		16 : "16x16"
		32 : "32x32"
		64 : "64x64"
		128 : "128x128"
		256 : "256x256"
	]
]
In the compiled lump, each envmap reference is stored much the same way:
struct
{
	vec3_t origin;
	int cubesize;
} envmaps[];
=== SURFENVMAP ===
Used alongside ENVMAP lump to store what cubemap index each brush surface should use.
Pretty simple:
struct
{
	unsigned int envmapindex;
} persurface[];
=== BRUSHLIST ===
Store actual brush information for collision, like , , and , allowing for arbitrary hull sizes. This also bypasses max clipnode limits without requiring an upgraded format such as BSP2.
Struct for each bmodel is like so:
struct {
	unsigned int ver = 1;
	unsigned int modelnum;		//inline model number. 0 for world, obviously.
	unsigned int numbrushes;	//size of following array.
	unsigned int numplanes;		//total count. for validation.
	struct
	{
		vec_t mins;
		vec_t maxs;
		signed short contents;
		unsigned short numplanes;
		{
			vec3_t 	normal;
			float 	dist;
		} planes[numplanes];
	} brush[numbrushes];
} permodel[];
Contents are stored as a signed short, matching the existing runtime contents values. Axial planes are not stored, but rather inferred based upon their normal, distance, and the brush's mins and maxs.
Only practical for clipnode-based formats like BSP29, BSP30, and BSP2 (BSP38 and derivatives store this information already).
=== ZIP_PAKFILE ===
A ZIP file, used like BSP's pakfile lump. For best compatibility, should be or uncompressed, and should be the last lump in the BSP.
The name of this lump is theoretical; the only source port which supports zip files embedded in the BSP is , which just looks for concatenated zip files, regardless of if they are formatted as a proper lump.
=== RGBLIGHTING ===
Equivalent to the 24-bit lightmap lump from a BSP30. Used as an alternative for external LIT files when using BSP29 or monochromatic BSP2, while maintaining a 8-bit monochromatic fallback for engines that don't support this lump.
Only practical for and engines; , , and map files store 24-bit true color lightmaps already.
=== VERTEXNORMALS ===
Stores vertex normal data for brushes, necessary for accurate smoothing when using real-time light sources instead of prebaked lightmaps. Surfaces that are shaded smooth should have the surface flag 0x00000800 set in their texinfo entry; surfaces without that flag are flat-shaded.
=== FACENORMALS ===
Used by ericw-tools instead of the VERTEXNORMALS lump.
=== LIGHTINGDIR ===
"Deluxemaps", designed for use with normal mapped surfaces that have lightmaps. Effectively a normal map which is stored like the lightmaps. 
=== LMSTYLE16 ===
Upgrade to the deprecated LMSTYLE lump, supporting up to 65k lightstyles. The number of styles per-face is variable (inferred via lump size vs surface count). These two changes make it suitable to be used even without LMSHIFT.
== Deprecated Lumps ==
These BSPX lumps have been deprecated by newer BSPX lumps. 
=== LMSHIFT ===
Defines lightmap scale for each surface. Renderers supporting this lump must support 256x256 (really 255x255) lightmaps, instead of only the usual 16x16 (really 15x15).
Unnecessary and possibly incompatible with Quake III BSPs and derivatives.
=== LMOFFSET ===
Required when using LMSHIFT to maintain compatibility with engines/renderers that do not support LMSHIFT.
=== LMSTYLE ===
Stores the 4 lightstyle indices for each surface; only makes sense when used in conjunction with LMSHIFT.
== External links ==
* BSPX spec in repo
Category:GoldSrc Technical