diff --git a/README.md b/README.md index 7bc4347..425e485 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ Hex patterns, include patterns and magic files for the use with the ImHex Hex Ed | DS_Store | `application/octet-stream` | [`patterns/dsstore.hexpat`](patterns/dsstore.hexpat) | .DS_Store file format | | UEFI | | [`patterns/uefi.hexpat`](patterns/uefi.hexpat)` | UEFI structs for parsing efivars | | EVTX | | [`patterns/evtx.hexpat`](patterns/evtx.hexpat) | MS Windows Vista Event Log | +| BSP | | [`patterns/bsp_goldsrc.hexpat`](patterns/bsp_goldsrc.hexpat) | GoldSrc engine maps format (used in Half-Life 1) | ### Scripts diff --git a/patterns/bsp_goldsrc.hexpat b/patterns/bsp_goldsrc.hexpat new file mode 100644 index 0000000..4f3058c --- /dev/null +++ b/patterns/bsp_goldsrc.hexpat @@ -0,0 +1,208 @@ +#include +#include +#include + +#pragma endian little + +#define HEADER_LUMPS 15 +#define MAX_MAP_HULLS 4 +#define NUM_AMBIENTS 4 +#define MAXLIGHTMAPS 4 + +enum LumpIndex : u32 { + Entities, + Planes, + Textures, + Vertexes, + Visibility, + Nodes, + Texinfo, + Faces, + Lighting, + Clipnodes, + Leafs, + Marksurfaces, + Edges, + Surfedges, + Models, +}; + +struct vec3f +{ + float x, y, z; +}; + +struct dlump_t +{ + s32 fileofs; + s32 filelen; +}; + +struct dheader_t +{ + s32 version; + dlump_t lumps[HEADER_LUMPS]; + std::assert(version == 30, "This version of BSP format is unsupported."); +}; + +struct dmodel_t +{ + vec3f mins; + vec3f maxs; + vec3f origin; // for sounds or lights + s32 headnode[MAX_MAP_HULLS]; + s32 visleafs; // not including the solid leaf 0 + s32 firstface; + s32 numfaces; +}; + +struct dplane_t +{ + vec3f normal; + float dist; + s32 type; +}; + +struct dtexinfo_t +{ + float vecs[8]; // texmatrix [s/t][xyz offset] + s32 miptex; + s16 flags; + s16 faceinfo; // -1 no face info otherwise dfaceinfo_t +}; + +struct dleaf_t +{ + s32 contents; + s32 visofs; // -1 = no visibility info + s16 mins[3]; + s16 maxs[3]; + u16 firstmarksurface; + u16 nummarksurfaces; + u8 ambient_level[NUM_AMBIENTS]; +}; + +struct dnode_t +{ + s32 planenum; + s16 children[2]; // negative numbers are -(leafs + 1), not nodes + s16 mins[3]; + s16 maxs[3]; + u16 firstface; + u16 numfaces; // counting both sides +}; + +struct dface_t +{ + u16 planenum; + s16 side; + s32 firstedge; + s16 numedges; + s16 texinfo; + u8 styles[MAXLIGHTMAPS]; + s32 lightofs; // start of [numstyles*surfsize] samples +}; + +struct dedge_t +{ + u16 v[2]; // indices of vertexes +}; + +struct dclipnode_t +{ + s32 planenum; + s16 children[2]; +}; + +using dmarkface_t = u16; +using dsurfedge_t = s32; +using dvertex_t = vec3f; + +fn get_miptex_pixeldata_size(auto width, auto height, auto offset) { + if (offset != 0) { + return std::mem::align_to(4, width * height * 85 / 64 + sizeof(u16) + 768); + } + else { + return 0; + } +}; + +struct miptex_t +{ + char name[16]; + u32 width; + u32 height; + u32 offsets[4]; // four mip maps stored + u8 pixeldata[get_miptex_pixeldata_size(width, height, offsets[0])]; +}; + +dheader_t file_header @ 0x00; + +fn get_lump_element_count(auto index, auto elem_size) { + return file_header.lumps[index].filelen / elem_size; +}; + +fn get_lump_address(auto index) { + return file_header.lumps[index].fileofs; +}; + +fn get_miptex_ptr_base(auto offset) { + return file_header.lumps[LumpIndex::Textures].fileofs; +}; + +struct MiptexPointer +{ + miptex_t *data: u32 [[pointer_base("get_miptex_ptr_base"), inline]]; +}; + +struct dmiptexlump_t +{ + s32 nummiptex; + MiptexPointer dataofs[nummiptex]; +}; + +struct VisibilityData +{ + u8 data[file_header.lumps[LumpIndex::Visibility].filelen]; + u8 pad[std::mem::align_to(4, sizeof(this)) - sizeof(this)]; +}; + +struct LightmapData +{ + u8 data[file_header.lumps[LumpIndex::Lighting].filelen]; + u8 pad[std::mem::align_to(4, sizeof(this)) - sizeof(this)]; +}; + +struct EntityData +{ + char text[]; + u8 pad[std::mem::align_to(4, sizeof(this)) - sizeof(this)]; +}; + +s32 models_count = get_lump_element_count(LumpIndex::Models, sizeof(dmodel_t)); +s32 vertexes_count = get_lump_element_count(LumpIndex::Vertexes, sizeof(vec3f)); +s32 planes_count = get_lump_element_count(LumpIndex::Planes, sizeof(dplane_t)); +s32 leafs_count = get_lump_element_count(LumpIndex::Leafs, sizeof(dleaf_t)); +s32 nodes_count = get_lump_element_count(LumpIndex::Nodes, sizeof(dnode_t)); +s32 faces_count = get_lump_element_count(LumpIndex::Faces, sizeof(dface_t)); +s32 markfaces_count = get_lump_element_count(LumpIndex::Marksurfaces, sizeof(dmarkface_t)); +s32 surfedges_count = get_lump_element_count(LumpIndex::Surfedges, sizeof(dsurfedge_t)); +s32 edges_count = get_lump_element_count(LumpIndex::Edges, sizeof(dedge_t)); +s32 clipnodes_count = get_lump_element_count(LumpIndex::Clipnodes, sizeof(dclipnode_t)); +s32 texinfo_count = get_lump_element_count(LumpIndex::Texinfo, sizeof(dtexinfo_t)); + +dmodel_t models_lump[models_count] @ get_lump_address(LumpIndex::Models); +dvertex_t vertexes_lump[vertexes_count] @ get_lump_address(LumpIndex::Vertexes); +dplane_t planes_lump[planes_count] @ get_lump_address(LumpIndex::Planes); +dleaf_t leafs_lump[leafs_count] @ get_lump_address(LumpIndex::Leafs); +dnode_t nodes_lump[nodes_count] @ get_lump_address(LumpIndex::Nodes); +dface_t faces_lump[faces_count] @ get_lump_address(LumpIndex::Faces); +dmarkface_t markfaces_lump[markfaces_count] @ get_lump_address(LumpIndex::Marksurfaces); +dsurfedge_t surfedges_lump[surfedges_count] @ get_lump_address(LumpIndex::Surfedges); +dedge_t edges_lump[edges_count] @ get_lump_address(LumpIndex::Edges); +dclipnode_t clipnodes_lump[clipnodes_count] @ get_lump_address(LumpIndex::Clipnodes); +dtexinfo_t texinfo_lump[texinfo_count] @ get_lump_address(LumpIndex::Texinfo); +dmiptexlump_t textures_lump @ get_lump_address(LumpIndex::Textures); +VisibilityData visdata_lump @ get_lump_address(LumpIndex::Visibility); +LightmapData lightdata_lump @ get_lump_address(LumpIndex::Lighting); +EntityData entdata_lump @ get_lump_address(LumpIndex::Entities); diff --git a/tests/patterns/test_data/bsp_goldsrc.hexpat.bsp b/tests/patterns/test_data/bsp_goldsrc.hexpat.bsp new file mode 100644 index 0000000..9e1985c Binary files /dev/null and b/tests/patterns/test_data/bsp_goldsrc.hexpat.bsp differ