BSPX is a format originally invented by Tonik, I believe, and is already implemented in both ezQuake and FTE. It is not so much a format itself, but more of an extensible way to shove additional lumps within an existing BSP. Typically these additional lumps will provide supplemental information or replace existing info. BSPX itself can logically be applied to the BSP file format of Quake, Quake II, or Quake III. BSPX itself can be defined in just the following two structures: 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; The bspx_header_t struct can be found immediately following the BSP's standard header. It is only valid if the standard header specifies no lump as starting at that location, and if the magic id matches. The engine can then walk the lump list looking for lumps that it recognises. Unknown lumps MUST be ignored. These lumps are currently defined: RGBLIGHTING: (applies to fte, ezquake, qss) This is equivelent to the information stored in a .lit file (sans header), and must contain the same number of samples as the lightmap lump would normally contain, because it doesn't make much sense otherwise. Presence of this lump permits omitting the regular mono lightmap to save space, but doing so will harm compatibility. LIGHTING_E5BGR9: (applies to fte, parsed by qss only as a fallback) This is a more advanced alternative to RGBLIGHTING. Each luxel is a E5BGR9 int32 packed value (ie: on little-endian machines, the exponent is the high 5 bits), resulting in what is effectively a memory-efficient floating point rgb value. This lightmap format virtually removes all oversaturation limits, and promises greater precision in dark areas too. This format is directly supported on ALL OpenGL[ES] 3.0+ gpus (aka: GL_EXT_texture_shared_exponent). As a floating point format, a logical value of 1.0 is considered as identity (instead of 255 being an [overbright] multiplier of 2.0). Lighting values are always assumed to be linear. LIGHTINGDIR: (applies to fte) This lump contains averaged surface-space light directions (read: deluxemap), equivelent to fte's .lux file, or dp's .dlit files (sans header). (as unorm values, these need to be biased before use). If bumpmaps or specular maps are not available then the effects of this may not be significant/noticable. LMSHIFT: (applies to fte, qss) This is a series of per-surface bytes. Each byte provides the (1<=mid[2])<<0) | ((y>=mid[1])<<1) | ((x>=mid[0])<<2) #define LGNODE_LEAF (1u<<31) #define LGNODE_MISSING (1u<<30) } lgnode[numnodes]; uint32_t numleafs; blob { ivec3_t mins; ivec3_t size; blob { byte stylecount; //compression... struct { byte stylenum; //which lightstyle to scale the rgb values by byte rgb[3]; //the actual sample } [stylecount]; } perpoint[size[0]*size[1]*size[2]]; } lgleaf[numleafs]; The nodes exists to provide support for sparse data, allowing solid unplayable areas of the map to be omitted entirely. Convert the sample position you want into an index, walk the tree until either missing or leaf. If leaf then index and add up the weighted rgb values. If missing or stylecount is 0xff then there's no data at that point. You should sample the 8 points around your target position and weight+blend them - with the missing values compensated for by increasing the weight of the other samples so that an object next to a wall does not become black/fullbright/ugly. Misalignment and leaf compression means it must be repacked at load time for efficient access (which is likely to mean stylecount gets clamped to 4). Does not support HDR nor 16bit styles. Other features: FTE supports mipmaps with all four offsets set to 0 as external textures. Such texture will ignore gl_load24bit, treating it as always enabled. This saves space and simplifies copyright ownership without resulting in untextured maps (when the textures are actually available, anyway). Misc Compatibility Concerns: mipmap lump - mipmaps with all four offsets set to 0 are external textures and contain no actual data. Note that vanilla quake will glitch out if given such a texture, although its unlikely to crash. hulls - presence of BRUSHLIST allows hulls 1 and 2 to be ommitted. This will crash vanilla glquake but not winquake, and can be reproduced with the vanilla tools too. lightmap sizes - winquake is limited to 18*18 lightmaps. Many quake engines support up to 256*256 now (AFTER lmscale). Note that such large lightmaps are not recommended due to all the resulting texture switches.