split bspfile.hh into multiple files which store the respective BSP info for the different BSP types; bspfile_generic stores the upper-most data (the superset of all BSP types), whereas the individual files contain the subsets.
This commit is contained in:
parent
740ab24626
commit
d872514b56
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,546 @@
|
|||
/* Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
See file, 'COPYING', for details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cinttypes>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "qvec.hh"
|
||||
|
||||
constexpr int32_t MBSPIDENT = -1;
|
||||
|
||||
constexpr size_t MAX_MAP_HULLS_H2 = 8;
|
||||
|
||||
struct dmodelh2_t
|
||||
{
|
||||
qvec3f mins;
|
||||
qvec3f maxs;
|
||||
qvec3f origin;
|
||||
std::array<int32_t, MAX_MAP_HULLS_H2> headnode; /* hexen2 only uses 6 */
|
||||
int32_t visleafs; /* not including the solid leaf 0 */
|
||||
int32_t firstface;
|
||||
int32_t numfaces;
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(mins, maxs, origin, headnode, visleafs, firstface, numfaces); }
|
||||
};
|
||||
|
||||
enum vistype_t
|
||||
{
|
||||
VIS_PVS,
|
||||
VIS_PHS
|
||||
};
|
||||
|
||||
// the visibility lump consists of a header with a count, then
|
||||
// byte offsets for the PVS and PHS of each cluster, then the raw
|
||||
// compressed bit vectors.
|
||||
struct mvis_t
|
||||
{
|
||||
std::vector<std::array<int32_t, 2>> bit_offsets;
|
||||
std::vector<uint8_t> bits;
|
||||
|
||||
inline size_t header_offset() const { return sizeof(int32_t) + (sizeof(int32_t) * bit_offsets.size() * 2); }
|
||||
|
||||
// set a bit offset of the specified cluster/vistype *relative to the start of the bits array*
|
||||
// (after the header)
|
||||
inline void set_bit_offset(vistype_t type, size_t cluster, size_t offset)
|
||||
{
|
||||
bit_offsets[cluster][type] = offset + header_offset();
|
||||
}
|
||||
|
||||
// fetch the bit offset of the specified cluster/vistype
|
||||
// relative to the start of the bits array
|
||||
inline int32_t get_bit_offset(vistype_t type, size_t cluster)
|
||||
{
|
||||
return bit_offsets[cluster][type] - header_offset();
|
||||
}
|
||||
|
||||
void resize(size_t numclusters) { bit_offsets.resize(numclusters); }
|
||||
|
||||
void stream_read(std::istream &stream, const lump_t &lump)
|
||||
{
|
||||
int32_t numclusters;
|
||||
|
||||
stream >= numclusters;
|
||||
|
||||
resize(numclusters);
|
||||
|
||||
// read cluster -> offset tables
|
||||
for (auto &bit_offset : bit_offsets)
|
||||
stream >= bit_offset;
|
||||
|
||||
// pull in final bit set
|
||||
auto remaining = lump.filelen - (static_cast<int32_t>(stream.tellg()) - lump.fileofs);
|
||||
bits.resize(remaining);
|
||||
stream.read(reinterpret_cast<char *>(bits.data()), remaining);
|
||||
}
|
||||
|
||||
void stream_write(std::ostream &stream) const
|
||||
{
|
||||
// no vis data
|
||||
if (!bit_offsets.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stream <= static_cast<int32_t>(bit_offsets.size());
|
||||
|
||||
// write cluster -> offset tables
|
||||
for (auto &bit_offset : bit_offsets)
|
||||
stream <= bit_offset;
|
||||
|
||||
// write bitset
|
||||
stream.write(reinterpret_cast<const char *>(bits.data()), bits.size());
|
||||
}
|
||||
};
|
||||
|
||||
constexpr size_t MIPLEVELS = 4;
|
||||
|
||||
struct dmiptex_t
|
||||
{
|
||||
std::array<char, 16> name;
|
||||
uint32_t width, height;
|
||||
std::array<int32_t, MIPLEVELS> offsets; /* four mip maps stored */
|
||||
|
||||
auto stream_data() { return std::tie(name, width, height, offsets); }
|
||||
};
|
||||
|
||||
// miptex in memory
|
||||
struct miptex_t
|
||||
{
|
||||
std::string name;
|
||||
uint32_t width, height;
|
||||
std::array<std::unique_ptr<uint8_t[]>, MIPLEVELS> data;
|
||||
|
||||
static inline uint8_t *copy_bytes(const uint8_t *in, size_t size)
|
||||
{
|
||||
uint8_t *bytes = new uint8_t[size];
|
||||
memcpy(bytes, in, size);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
miptex_t() = default;
|
||||
miptex_t(const miptex_t ©) : name(copy.name), width(copy.width), height(copy.height)
|
||||
{
|
||||
for (int32_t i = 0; i < data.size(); i++) {
|
||||
if (copy.data[i]) {
|
||||
data[i] = std::unique_ptr<uint8_t[]>(copy_bytes(copy.data[i].get(), (width >> i) * (height >> i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline miptex_t &operator=(const miptex_t ©)
|
||||
{
|
||||
name = copy.name;
|
||||
width = copy.width;
|
||||
height = copy.height;
|
||||
|
||||
for (int32_t i = 0; i < data.size(); i++) {
|
||||
if (copy.data[i]) {
|
||||
data[i] = std::unique_ptr<uint8_t[]>(copy_bytes(copy.data[i].get(), (width >> i) * (height >> i)));
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~miptex_t() { }
|
||||
|
||||
virtual size_t stream_size() const { return sizeof(dmiptex_t) + width * height / 64 * 85; }
|
||||
|
||||
virtual void stream_read(std::istream &stream)
|
||||
{
|
||||
auto start = stream.tellg();
|
||||
|
||||
dmiptex_t dtex;
|
||||
stream >= dtex;
|
||||
|
||||
name = dtex.name.data();
|
||||
|
||||
width = dtex.width;
|
||||
height = dtex.height;
|
||||
|
||||
for (size_t g = 0; g < MIPLEVELS; g++) {
|
||||
if (dtex.offsets[g] <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
stream.seekg(static_cast<uint32_t>(start) + dtex.offsets[g]);
|
||||
const size_t num_bytes = (dtex.width >> g) * (dtex.height >> g);
|
||||
uint8_t *bytes = new uint8_t[num_bytes];
|
||||
stream.read(reinterpret_cast<char *>(bytes), num_bytes);
|
||||
data[g] = std::unique_ptr<uint8_t[]>(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void stream_write(std::ostream &stream) const
|
||||
{
|
||||
std::array<char, 16> as_array{};
|
||||
memcpy(as_array.data(), name.c_str(), name.size());
|
||||
|
||||
stream <= as_array <= width <= height;
|
||||
|
||||
uint32_t header_end = sizeof(dmiptex_t);
|
||||
|
||||
for (size_t i = 0; i < MIPLEVELS; i++) {
|
||||
if (data[i] <= 0) {
|
||||
stream <= (uint32_t)0;
|
||||
} else {
|
||||
stream <= header_end;
|
||||
header_end += (width >> i) * (height >> i);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < MIPLEVELS; i++) {
|
||||
if (data[i]) {
|
||||
stream.write(reinterpret_cast<char *>(data[i].get()), (width >> i) * (height >> i));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Half Life miptex, which includes a palette
|
||||
struct miptexhl_t : miptex_t
|
||||
{
|
||||
std::vector<qvec3b> palette;
|
||||
|
||||
miptexhl_t() = default;
|
||||
|
||||
// convert miptex_t to miptexhl_t
|
||||
miptexhl_t(const miptex_t ©) : miptex_t(copy) { }
|
||||
|
||||
virtual size_t stream_size() const
|
||||
{
|
||||
return miptex_t::stream_size() + sizeof(uint16_t) + (palette.size() * sizeof(qvec3b));
|
||||
}
|
||||
|
||||
virtual void stream_read(std::istream &stream)
|
||||
{
|
||||
miptex_t::stream_read(stream);
|
||||
|
||||
uint16_t num_colors;
|
||||
stream >= num_colors;
|
||||
|
||||
palette.resize(num_colors);
|
||||
stream.read(reinterpret_cast<char *>(palette.data()), palette.size());
|
||||
}
|
||||
|
||||
virtual void stream_write(std::ostream &stream) const
|
||||
{
|
||||
miptex_t::stream_write(stream);
|
||||
|
||||
stream <= static_cast<uint16_t>(palette.size());
|
||||
|
||||
stream.write(reinterpret_cast<const char *>(palette.data()), palette.size());
|
||||
}
|
||||
};
|
||||
|
||||
// structured miptex container lump
|
||||
template<typename T>
|
||||
struct dmiptexlump_t
|
||||
{
|
||||
std::vector<T> textures;
|
||||
|
||||
dmiptexlump_t() = default;
|
||||
|
||||
// copy from a different lump type
|
||||
template<typename T2>
|
||||
dmiptexlump_t(const dmiptexlump_t<T2> ©)
|
||||
{
|
||||
textures.reserve(copy.textures.size());
|
||||
|
||||
for (auto &m : copy.textures) {
|
||||
textures.emplace_back(m);
|
||||
}
|
||||
}
|
||||
|
||||
void stream_read(std::istream &stream, const lump_t &lump)
|
||||
{
|
||||
int32_t nummiptex;
|
||||
stream >= nummiptex;
|
||||
|
||||
for (size_t i = 0; i < nummiptex; i++) {
|
||||
int32_t mipofs;
|
||||
|
||||
stream >= mipofs;
|
||||
|
||||
miptex_t &tex = textures.emplace_back();
|
||||
|
||||
if (mipofs < 0)
|
||||
continue;
|
||||
|
||||
auto pos = stream.tellg();
|
||||
|
||||
stream.seekg(lump.fileofs + mipofs);
|
||||
|
||||
tex.stream_read(stream);
|
||||
|
||||
stream.seekg(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void stream_write(std::ostream &stream) const
|
||||
{
|
||||
auto p = (size_t)stream.tellp();
|
||||
|
||||
stream <= static_cast<int32_t>(textures.size());
|
||||
|
||||
const size_t header_size = sizeof(int32_t) + (sizeof(int32_t) * textures.size());
|
||||
|
||||
size_t miptex_offset = 0;
|
||||
|
||||
for (auto &texture : textures) {
|
||||
if (!texture.name[0]) {
|
||||
stream <= static_cast<int32_t>(-1);
|
||||
continue;
|
||||
}
|
||||
stream <= static_cast<int32_t>(header_size + miptex_offset);
|
||||
|
||||
miptex_offset += texture.stream_size();
|
||||
|
||||
if ((p + miptex_offset) % 4) {
|
||||
miptex_offset += 4 - ((p + miptex_offset) % 4);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &texture : textures) {
|
||||
if (texture.name[0]) {
|
||||
if (stream.tellp() % 4) {
|
||||
constexpr const char pad[4]{};
|
||||
stream.write(pad, 4 - (stream.tellp() % 4));
|
||||
}
|
||||
texture.stream_write(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 0-2 are axial planes
|
||||
// 3-5 are non-axial planes snapped to the nearest
|
||||
enum class plane_type_t
|
||||
{
|
||||
PLANE_INVALID = -1,
|
||||
PLANE_X = 0,
|
||||
PLANE_Y = 1,
|
||||
PLANE_Z = 2,
|
||||
PLANE_ANYX = 3,
|
||||
PLANE_ANYY = 4,
|
||||
PLANE_ANYZ = 5,
|
||||
};
|
||||
|
||||
struct dplane_t : qplane3f
|
||||
{
|
||||
int32_t type;
|
||||
|
||||
[[nodiscard]] constexpr dplane_t operator-() const { return {qplane3f::operator-(), type}; }
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(normal, dist, type); }
|
||||
|
||||
// optimized case
|
||||
template<typename T>
|
||||
inline T distance_to_fast(const qvec<T, 3> &point) const
|
||||
{
|
||||
switch (static_cast<plane_type_t>(type)) {
|
||||
case plane_type_t::PLANE_X: return point[0] - dist;
|
||||
case plane_type_t::PLANE_Y: return point[1] - dist;
|
||||
case plane_type_t::PLANE_Z: return point[2] - dist;
|
||||
default: {
|
||||
return qplane3f::distance_to(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct bsp2_dnode_t
|
||||
{
|
||||
int32_t planenum;
|
||||
std::array<int32_t, 2> children; /* negative numbers are -(leafs+1), not nodes */
|
||||
qvec3f mins; /* for sphere culling */
|
||||
qvec3f maxs;
|
||||
uint32_t firstface;
|
||||
uint32_t numfaces; /* counting both sides */
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(planenum, children, mins, maxs, firstface, numfaces); }
|
||||
};
|
||||
|
||||
struct mtexinfo_t
|
||||
{
|
||||
texvecf vecs; // [s/t][xyz offset]
|
||||
surfflags_t flags; // native miptex flags + extended flags
|
||||
|
||||
// q1 only
|
||||
int32_t miptex;
|
||||
|
||||
// q2 only
|
||||
int32_t value; // light emission, etc
|
||||
std::array<char, 32> texture; // texture name (textures/*.wal)
|
||||
int32_t nexttexinfo = -1; // for animations, -1 = end of chain
|
||||
};
|
||||
|
||||
constexpr size_t MAXLIGHTMAPS = 4;
|
||||
|
||||
struct mface_t
|
||||
{
|
||||
int64_t planenum;
|
||||
int32_t side; // if true, the face is on the back side of the plane
|
||||
int32_t firstedge; /* we must support > 64k edges */
|
||||
int32_t numedges;
|
||||
int32_t texinfo;
|
||||
|
||||
/* lighting info */
|
||||
std::array<uint8_t, MAXLIGHTMAPS> styles;
|
||||
int32_t lightofs; /* start of [numstyles*surfsize] samples */
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(planenum, side, firstedge, numedges, texinfo, styles, lightofs); }
|
||||
};
|
||||
|
||||
/*
|
||||
* Note that children are interpreted as unsigned values now, so that we can
|
||||
* handle > 32k clipnodes. Values > 0xFFF0 can be assumed to be CONTENTS
|
||||
* values and can be read as the signed value to be compatible with the above
|
||||
* (i.e. simply subtract 65536).
|
||||
*/
|
||||
struct bsp2_dclipnode_t
|
||||
{
|
||||
int32_t planenum;
|
||||
std::array<int32_t, 2> children; /* negative numbers are contents */
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(planenum, children); }
|
||||
};
|
||||
|
||||
using bsp2_dedge_t = std::array<uint32_t, 2>; /* vertex numbers */
|
||||
|
||||
/*
|
||||
* leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas (except Q2)
|
||||
* all other leafs need visibility info
|
||||
*/
|
||||
/* Ambient Sounds */
|
||||
enum ambient_type_t : uint8_t
|
||||
{
|
||||
AMBIENT_WATER,
|
||||
AMBIENT_SKY,
|
||||
AMBIENT_SLIME,
|
||||
AMBIENT_LAVA,
|
||||
|
||||
NUM_AMBIENTS = 4
|
||||
};
|
||||
|
||||
struct mleaf_t
|
||||
{
|
||||
// bsp2_dleaf_t
|
||||
int32_t contents;
|
||||
int32_t visofs; /* -1 = no visibility info */
|
||||
qvec3f mins; /* for frustum culling */
|
||||
qvec3f maxs;
|
||||
uint32_t firstmarksurface;
|
||||
uint32_t nummarksurfaces;
|
||||
std::array<uint8_t, NUM_AMBIENTS> ambient_level;
|
||||
|
||||
// q2 extras
|
||||
int32_t cluster;
|
||||
int32_t area;
|
||||
uint32_t firstleafbrush;
|
||||
uint32_t numleafbrushes;
|
||||
};
|
||||
|
||||
struct darea_t
|
||||
{
|
||||
int32_t numareaportals;
|
||||
int32_t firstareaportal;
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(numareaportals, firstareaportal); }
|
||||
auto tuple() const { return std::tie(numareaportals, firstareaportal); }
|
||||
|
||||
// comparison operator for tests
|
||||
bool operator==(const darea_t &other) const { return tuple() == other.tuple(); }
|
||||
};
|
||||
|
||||
// each area has a list of portals that lead into other areas
|
||||
// when portals are closed, other areas may not be visible or
|
||||
// hearable even if the vis info says that it should be
|
||||
struct dareaportal_t
|
||||
{
|
||||
int32_t portalnum;
|
||||
int32_t otherarea;
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(portalnum, otherarea); }
|
||||
auto tuple() const { return std::tie(portalnum, otherarea); }
|
||||
|
||||
// comparison operator for tests
|
||||
bool operator==(const dareaportal_t &other) const { return tuple() == other.tuple(); }
|
||||
};
|
||||
|
||||
struct dbrush_t
|
||||
{
|
||||
int32_t firstside;
|
||||
int32_t numsides;
|
||||
int32_t contents;
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(firstside, numsides, contents); }
|
||||
};
|
||||
|
||||
struct q2_dbrushside_qbism_t
|
||||
{
|
||||
uint32_t planenum; // facing out of the leaf
|
||||
int32_t texinfo;
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(planenum, texinfo); }
|
||||
};
|
||||
|
||||
struct bspversion_t;
|
||||
|
||||
// "generic" bsp - superset of all other supported types
|
||||
struct mbsp_t
|
||||
{
|
||||
// the BSP version that we came from, if any
|
||||
const bspversion_t *loadversion;
|
||||
|
||||
std::vector<dmodelh2_t> dmodels;
|
||||
mvis_t dvis;
|
||||
std::vector<uint8_t> dlightdata;
|
||||
dmiptexlump_t<miptexhl_t> dtex;
|
||||
std::string dentdata;
|
||||
std::vector<mleaf_t> dleafs;
|
||||
std::vector<dplane_t> dplanes;
|
||||
std::vector<qvec3f> dvertexes;
|
||||
std::vector<bsp2_dnode_t> dnodes;
|
||||
std::vector<mtexinfo_t> texinfo;
|
||||
std::vector<mface_t> dfaces;
|
||||
std::vector<bsp2_dclipnode_t> dclipnodes;
|
||||
std::vector<bsp2_dedge_t> dedges;
|
||||
std::vector<uint32_t> dleaffaces;
|
||||
std::vector<uint32_t> dleafbrushes;
|
||||
std::vector<int32_t> dsurfedges;
|
||||
std::vector<darea_t> dareas;
|
||||
std::vector<dareaportal_t> dareaportals;
|
||||
std::vector<dbrush_t> dbrushes;
|
||||
std::vector<q2_dbrushside_qbism_t> dbrushsides;
|
||||
};
|
||||
|
||||
extern const bspversion_t bspver_generic;
|
||||
|
|
@ -0,0 +1,488 @@
|
|||
/* Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
See file, 'COPYING', for details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cinttypes>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include "qvec.hh"
|
||||
|
||||
constexpr int32_t BSPVERSION = 29;
|
||||
constexpr int32_t BSP2RMQVERSION = (('B' << 24) | ('S' << 16) | ('P' << 8) | '2');
|
||||
constexpr int32_t BSP2VERSION = ('B' | ('S' << 8) | ('P' << 16) | ('2' << 24));
|
||||
constexpr int32_t BSPHLVERSION = 30; // 24bit lighting, and private palettes in the textures lump.
|
||||
|
||||
enum q1_lump_t
|
||||
{
|
||||
LUMP_ENTITIES,
|
||||
LUMP_PLANES,
|
||||
LUMP_TEXTURES,
|
||||
LUMP_VERTEXES,
|
||||
LUMP_VISIBILITY,
|
||||
LUMP_NODES,
|
||||
LUMP_TEXINFO,
|
||||
LUMP_FACES,
|
||||
LUMP_LIGHTING,
|
||||
LUMP_CLIPNODES,
|
||||
LUMP_LEAFS,
|
||||
LUMP_MARKSURFACES,
|
||||
LUMP_EDGES,
|
||||
LUMP_SURFEDGES,
|
||||
LUMP_MODELS,
|
||||
|
||||
BSP_LUMPS
|
||||
};
|
||||
|
||||
struct dheader_t
|
||||
{
|
||||
int32_t ident;
|
||||
std::array<lump_t, BSP_LUMPS> lumps;
|
||||
|
||||
auto stream_data() { return std::tie(ident, lumps); }
|
||||
};
|
||||
|
||||
constexpr size_t MAX_MAP_HULLS_Q1 = 4;
|
||||
|
||||
struct dmodelq1_t
|
||||
{
|
||||
qvec3f mins;
|
||||
qvec3f maxs;
|
||||
qvec3f origin;
|
||||
std::array<int32_t, MAX_MAP_HULLS_Q1> headnode; /* 4 for backward compat, only 3 hulls exist */
|
||||
int32_t visleafs; /* not including the solid leaf 0 */
|
||||
int32_t firstface;
|
||||
int32_t numfaces;
|
||||
|
||||
dmodelq1_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
dmodelq1_t(const dmodelh2_t &model)
|
||||
: mins(model.mins), maxs(model.maxs), origin(model.origin),
|
||||
headnode(array_cast<decltype(headnode)>(model.headnode, "dmodelh2_t::headnode")), visleafs(model.visleafs),
|
||||
firstface(model.firstface), numfaces(model.numfaces)
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator dmodelh2_t() const
|
||||
{
|
||||
return {mins, maxs, origin, array_cast<decltype(dmodelh2_t::headnode)>(headnode, "dmodelh2_t::headnode"),
|
||||
visleafs, firstface, numfaces};
|
||||
}
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(mins, maxs, origin, headnode, visleafs, firstface, numfaces); }
|
||||
};
|
||||
|
||||
// Q1 contents
|
||||
|
||||
enum q1_contents_t : int32_t
|
||||
{
|
||||
CONTENTS_EMPTY = -1,
|
||||
CONTENTS_SOLID = -2,
|
||||
CONTENTS_WATER = -3,
|
||||
CONTENTS_SLIME = -4,
|
||||
CONTENTS_LAVA = -5,
|
||||
CONTENTS_SKY = -6,
|
||||
|
||||
CONTENTS_MIN = CONTENTS_SKY
|
||||
};
|
||||
|
||||
struct bsp29_dnode_t
|
||||
{
|
||||
int32_t planenum;
|
||||
std::array<int16_t, 2>
|
||||
children; /* negative numbers are -(leafs+1), not nodes. children[0] is front, children[1] is back */
|
||||
qvec3s mins; /* for sphere culling */
|
||||
qvec3s maxs;
|
||||
uint16_t firstface;
|
||||
uint16_t numfaces; /* counting both sides */
|
||||
|
||||
bsp29_dnode_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
bsp29_dnode_t(const bsp2_dnode_t &model)
|
||||
: planenum(model.planenum), children(array_cast<decltype(children)>(model.children, "dnode_t::children")),
|
||||
mins(aabb_mins_cast<int16_t>(model.mins, "dnode_t::mins")),
|
||||
maxs(aabb_maxs_cast<int16_t>(model.maxs, "dnode_t::maxs")),
|
||||
firstface(numeric_cast<uint16_t>(model.firstface, "dnode_t::firstface")),
|
||||
numfaces(numeric_cast<uint16_t>(model.numfaces, "dnode_t::numfaces"))
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator bsp2_dnode_t() const
|
||||
{
|
||||
return {planenum, array_cast<decltype(bsp2_dnode_t::children)>(children, "dnode_t::children"),
|
||||
aabb_mins_cast<float>(mins, "dnode_t::mins"), aabb_mins_cast<float>(maxs, "dnode_t::maxs"), firstface,
|
||||
numfaces};
|
||||
}
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(planenum, children, mins, maxs, firstface, numfaces); }
|
||||
};
|
||||
|
||||
struct bsp2rmq_dnode_t
|
||||
{
|
||||
int32_t planenum;
|
||||
std::array<int32_t, 2> children; /* negative numbers are -(leafs+1), not nodes */
|
||||
qvec3s mins; /* for sphere culling */
|
||||
qvec3s maxs;
|
||||
uint32_t firstface;
|
||||
uint32_t numfaces; /* counting both sides */
|
||||
|
||||
bsp2rmq_dnode_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
bsp2rmq_dnode_t(const bsp2_dnode_t &model)
|
||||
: planenum(model.planenum), children(model.children),
|
||||
mins(aabb_mins_cast<int16_t>(model.mins, "dnode_t::mins")),
|
||||
maxs(aabb_maxs_cast<int16_t>(model.maxs, "dnode_t::maxs")), firstface(model.firstface),
|
||||
numfaces(model.numfaces)
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator bsp2_dnode_t() const
|
||||
{
|
||||
return {planenum, children, aabb_mins_cast<float>(mins, "dnode_t::mins"),
|
||||
aabb_mins_cast<float>(maxs, "dnode_t::maxs"), firstface, numfaces};
|
||||
}
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(planenum, children, mins, maxs, firstface, numfaces); }
|
||||
};
|
||||
|
||||
/*
|
||||
* Clipnodes need to be stored as a 16-bit offset. Originally, this was a
|
||||
* signed value and only the positive values up to 32767 were available. Since
|
||||
* the negative range was unused apart from a few values reserved for flags,
|
||||
* this has been extended to allow up to 65520 (0xfff0) clipnodes (with a
|
||||
* suitably modified engine).
|
||||
*/
|
||||
struct bsp29_dclipnode_t
|
||||
{
|
||||
int32_t planenum;
|
||||
std::array<int16_t, 2> children; /* negative numbers are contents */
|
||||
|
||||
bsp29_dclipnode_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
bsp29_dclipnode_t(const bsp2_dclipnode_t &model)
|
||||
: planenum(model.planenum), children({downcast(model.children[0]), downcast(model.children[1])})
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator bsp2_dclipnode_t() const { return {planenum, {upcast(children[0]), upcast(children[1])}}; }
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(planenum, children); }
|
||||
|
||||
/* Slightly tricky since we support > 32k clipnodes */
|
||||
private:
|
||||
static constexpr int16_t downcast(const int32_t &v)
|
||||
{
|
||||
if (v < -15 || v > 0xFFF0)
|
||||
throw std::overflow_error("dclipmode_t::children");
|
||||
|
||||
return static_cast<int16_t>(v < 0 ? v + 0x10000 : v);
|
||||
}
|
||||
|
||||
static constexpr int32_t upcast(const int16_t &v)
|
||||
{
|
||||
int32_t child = (uint16_t)v;
|
||||
return child > 0xfff0 ? child - 0x10000 : child;
|
||||
}
|
||||
};
|
||||
|
||||
// Q1 Texture flags.
|
||||
enum q1_surf_flags_t : int32_t
|
||||
{
|
||||
TEX_SPECIAL = nth_bit(0) /* sky or slime, no lightmap or 256 subdivision */
|
||||
};
|
||||
|
||||
struct texinfo_t
|
||||
{
|
||||
texvecf vecs; /* [s/t][xyz offset] */
|
||||
int32_t miptex;
|
||||
int32_t flags;
|
||||
|
||||
texinfo_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
texinfo_t(const mtexinfo_t &model) : vecs(model.vecs), miptex(model.miptex), flags(model.flags.native) { }
|
||||
|
||||
// convert to mbsp_t
|
||||
operator mtexinfo_t() const { return {vecs, {flags}, miptex}; }
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(vecs, miptex, flags); }
|
||||
};
|
||||
|
||||
/*
|
||||
* Note that edge 0 is never used, because negative edge nums are used for
|
||||
* counterclockwise use of the edge in a face
|
||||
*/
|
||||
using bsp29_dedge_t = std::array<uint16_t, 2>; /* vertex numbers */
|
||||
|
||||
struct bsp29_dface_t
|
||||
{
|
||||
int16_t planenum;
|
||||
int16_t side;
|
||||
int32_t firstedge; /* we must support > 64k edges */
|
||||
int16_t numedges;
|
||||
int16_t texinfo;
|
||||
|
||||
/* lighting info */
|
||||
std::array<uint8_t, MAXLIGHTMAPS> styles;
|
||||
int32_t lightofs; /* start of [numstyles*surfsize] samples */
|
||||
|
||||
bsp29_dface_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
bsp29_dface_t(const mface_t &model)
|
||||
: planenum(numeric_cast<int16_t>(model.planenum, "dface_t::planenum")),
|
||||
side(numeric_cast<int16_t>(model.side, "dface_t::side")), firstedge(model.firstedge),
|
||||
numedges(numeric_cast<int16_t>(model.numedges, "dface_t::numedges")),
|
||||
texinfo(numeric_cast<int16_t>(model.texinfo, "dface_t::texinfo")), styles(model.styles),
|
||||
lightofs(model.lightofs)
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator mface_t() const { return {planenum, side, firstedge, numedges, texinfo, styles, lightofs}; }
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(planenum, side, firstedge, numedges, texinfo, styles, lightofs); }
|
||||
};
|
||||
|
||||
struct bsp2_dface_t
|
||||
{
|
||||
int32_t planenum;
|
||||
int32_t side; // if true, the face is on the back side of the plane
|
||||
int32_t firstedge; /* we must support > 64k edges */
|
||||
int32_t numedges;
|
||||
int32_t texinfo;
|
||||
|
||||
/* lighting info */
|
||||
std::array<uint8_t, MAXLIGHTMAPS> styles;
|
||||
int32_t lightofs; /* start of [numstyles*surfsize] samples */
|
||||
|
||||
bsp2_dface_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
bsp2_dface_t(const mface_t &model)
|
||||
: planenum(numeric_cast<int32_t>(model.planenum, "dface_t::planenum")), side(model.side),
|
||||
firstedge(model.firstedge), numedges(model.numedges), texinfo(model.texinfo), styles(model.styles),
|
||||
lightofs(model.lightofs)
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator mface_t() const { return {planenum, side, firstedge, numedges, texinfo, styles, lightofs}; }
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(planenum, side, firstedge, numedges, texinfo, styles, lightofs); }
|
||||
};
|
||||
|
||||
struct bsp29_dleaf_t
|
||||
{
|
||||
int32_t contents;
|
||||
int32_t visofs; /* -1 = no visibility info */
|
||||
qvec3s mins; /* for frustum culling */
|
||||
qvec3s maxs;
|
||||
uint16_t firstmarksurface;
|
||||
uint16_t nummarksurfaces;
|
||||
std::array<uint8_t, NUM_AMBIENTS> ambient_level;
|
||||
|
||||
bsp29_dleaf_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
bsp29_dleaf_t(const mleaf_t &model)
|
||||
: contents(model.contents), visofs(model.visofs), mins(aabb_mins_cast<int16_t>(model.mins, "dleaf_t::mins")),
|
||||
maxs(aabb_maxs_cast<int16_t>(model.maxs, "dleaf_t::maxs")),
|
||||
firstmarksurface(numeric_cast<uint16_t>(model.firstmarksurface, "dleaf_t::firstmarksurface")),
|
||||
nummarksurfaces(numeric_cast<uint16_t>(model.nummarksurfaces, "dleaf_t::nummarksurfaces")),
|
||||
ambient_level(model.ambient_level)
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator mleaf_t() const
|
||||
{
|
||||
return {contents, visofs, aabb_mins_cast<float>(mins, "dleaf_t::mins"),
|
||||
aabb_mins_cast<float>(maxs, "dleaf_t::maxs"), firstmarksurface, nummarksurfaces, ambient_level};
|
||||
}
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data()
|
||||
{
|
||||
return std::tie(contents, visofs, mins, maxs, firstmarksurface, nummarksurfaces, ambient_level);
|
||||
}
|
||||
};
|
||||
|
||||
struct bsp2rmq_dleaf_t
|
||||
{
|
||||
int32_t contents;
|
||||
int32_t visofs; /* -1 = no visibility info */
|
||||
qvec3s mins; /* for frustum culling */
|
||||
qvec3s maxs;
|
||||
uint32_t firstmarksurface;
|
||||
uint32_t nummarksurfaces;
|
||||
std::array<uint8_t, NUM_AMBIENTS> ambient_level;
|
||||
|
||||
bsp2rmq_dleaf_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
bsp2rmq_dleaf_t(const mleaf_t &model)
|
||||
: contents(model.contents), visofs(model.visofs), mins(aabb_mins_cast<int16_t>(model.mins, "dleaf_t::mins")),
|
||||
maxs(aabb_maxs_cast<int16_t>(model.maxs, "dleaf_t::maxs")), firstmarksurface(model.firstmarksurface),
|
||||
nummarksurfaces(model.nummarksurfaces), ambient_level(model.ambient_level)
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator mleaf_t() const
|
||||
{
|
||||
return {contents, visofs, aabb_mins_cast<float>(mins, "dleaf_t::mins"),
|
||||
aabb_mins_cast<float>(maxs, "dleaf_t::maxs"), firstmarksurface, nummarksurfaces, ambient_level};
|
||||
}
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data()
|
||||
{
|
||||
return std::tie(contents, visofs, mins, maxs, firstmarksurface, nummarksurfaces, ambient_level);
|
||||
}
|
||||
};
|
||||
|
||||
struct bsp2_dleaf_t
|
||||
{
|
||||
int32_t contents;
|
||||
int32_t visofs; /* -1 = no visibility info */
|
||||
qvec3f mins; /* for frustum culling */
|
||||
qvec3f maxs;
|
||||
uint32_t firstmarksurface;
|
||||
uint32_t nummarksurfaces;
|
||||
std::array<uint8_t, NUM_AMBIENTS> ambient_level;
|
||||
|
||||
bsp2_dleaf_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
bsp2_dleaf_t(const mleaf_t &model)
|
||||
: contents(model.contents), visofs(model.visofs), mins(model.mins), maxs(model.maxs),
|
||||
firstmarksurface(model.firstmarksurface), nummarksurfaces(model.nummarksurfaces),
|
||||
ambient_level(model.ambient_level)
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator mleaf_t() const
|
||||
{
|
||||
return {contents, visofs, mins, maxs, firstmarksurface, nummarksurfaces, ambient_level};
|
||||
}
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data()
|
||||
{
|
||||
return std::tie(contents, visofs, mins, maxs, firstmarksurface, nummarksurfaces, ambient_level);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Q1-esque maps can use one of these two.
|
||||
using dmodelq1_vector = std::vector<dmodelq1_t>;
|
||||
using dmodelh2_vector = std::vector<dmodelh2_t>;
|
||||
|
||||
// Q1-esque maps can use one of these two.
|
||||
using miptexq1_lump = dmiptexlump_t<miptex_t>;
|
||||
using miptexhl_lump = dmiptexlump_t<miptexhl_t>;
|
||||
|
||||
// type tag used for type inference
|
||||
struct q1bsp_tag_t
|
||||
{
|
||||
};
|
||||
|
||||
struct bsp29_t : q1bsp_tag_t
|
||||
{
|
||||
std::variant<std::monostate, dmodelq1_vector, dmodelh2_vector> dmodels;
|
||||
std::vector<uint8_t> dvisdata;
|
||||
std::vector<uint8_t> dlightdata;
|
||||
std::variant<std::monostate, miptexq1_lump, miptexhl_lump> dtex;
|
||||
std::string dentdata;
|
||||
std::vector<bsp29_dleaf_t> dleafs;
|
||||
std::vector<dplane_t> dplanes;
|
||||
std::vector<qvec3f> dvertexes;
|
||||
std::vector<bsp29_dnode_t> dnodes;
|
||||
std::vector<texinfo_t> texinfo;
|
||||
std::vector<bsp29_dface_t> dfaces;
|
||||
std::vector<bsp29_dclipnode_t> dclipnodes;
|
||||
std::vector<bsp29_dedge_t> dedges;
|
||||
std::vector<uint16_t> dmarksurfaces;
|
||||
std::vector<int32_t> dsurfedges;
|
||||
};
|
||||
|
||||
struct bsp2rmq_t : q1bsp_tag_t
|
||||
{
|
||||
std::variant<std::monostate, dmodelq1_vector, dmodelh2_vector> dmodels;
|
||||
std::vector<uint8_t> dvisdata;
|
||||
std::vector<uint8_t> dlightdata;
|
||||
std::variant<std::monostate, miptexq1_lump, miptexhl_lump> dtex;
|
||||
std::string dentdata;
|
||||
std::vector<bsp2rmq_dleaf_t> dleafs;
|
||||
std::vector<dplane_t> dplanes;
|
||||
std::vector<qvec3f> dvertexes;
|
||||
std::vector<bsp2rmq_dnode_t> dnodes;
|
||||
std::vector<texinfo_t> texinfo;
|
||||
std::vector<bsp2_dface_t> dfaces;
|
||||
std::vector<bsp2_dclipnode_t> dclipnodes;
|
||||
std::vector<bsp2_dedge_t> dedges;
|
||||
std::vector<uint32_t> dmarksurfaces;
|
||||
std::vector<int32_t> dsurfedges;
|
||||
};
|
||||
|
||||
struct bsp2_t : q1bsp_tag_t
|
||||
{
|
||||
std::variant<std::monostate, dmodelq1_vector, dmodelh2_vector> dmodels;
|
||||
std::vector<uint8_t> dvisdata;
|
||||
std::vector<uint8_t> dlightdata;
|
||||
std::variant<std::monostate, miptexq1_lump, miptexhl_lump> dtex;
|
||||
std::string dentdata;
|
||||
std::vector<bsp2_dleaf_t> dleafs;
|
||||
std::vector<dplane_t> dplanes;
|
||||
std::vector<qvec3f> dvertexes;
|
||||
std::vector<bsp2_dnode_t> dnodes;
|
||||
std::vector<texinfo_t> texinfo;
|
||||
std::vector<bsp2_dface_t> dfaces;
|
||||
std::vector<bsp2_dclipnode_t> dclipnodes;
|
||||
std::vector<bsp2_dedge_t> dedges;
|
||||
std::vector<uint32_t> dmarksurfaces;
|
||||
std::vector<int32_t> dsurfedges;
|
||||
};
|
||||
|
||||
extern const bspversion_t bspver_q1;
|
||||
extern const bspversion_t bspver_h2;
|
||||
extern const bspversion_t bspver_h2bsp2;
|
||||
extern const bspversion_t bspver_h2bsp2rmq;
|
||||
extern const bspversion_t bspver_bsp2;
|
||||
extern const bspversion_t bspver_bsp2rmq;
|
||||
extern const bspversion_t bspver_hl;
|
||||
|
|
@ -0,0 +1,445 @@
|
|||
/* Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
See file, 'COPYING', for details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cinttypes>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "qvec.hh"
|
||||
|
||||
constexpr int32_t Q2_BSPVERSION = 38;
|
||||
constexpr int32_t Q2_BSPIDENT = (('P' << 24) + ('S' << 16) + ('B' << 8) + 'I');
|
||||
constexpr int32_t Q2_QBISMIDENT = (('P' << 24) + ('S' << 16) + ('B' << 8) + 'Q');
|
||||
|
||||
enum q2_lump_t
|
||||
{
|
||||
Q2_LUMP_ENTITIES,
|
||||
Q2_LUMP_PLANES,
|
||||
Q2_LUMP_VERTEXES,
|
||||
Q2_LUMP_VISIBILITY,
|
||||
Q2_LUMP_NODES,
|
||||
Q2_LUMP_TEXINFO,
|
||||
Q2_LUMP_FACES,
|
||||
Q2_LUMP_LIGHTING,
|
||||
Q2_LUMP_LEAFS,
|
||||
Q2_LUMP_LEAFFACES,
|
||||
Q2_LUMP_LEAFBRUSHES,
|
||||
Q2_LUMP_EDGES,
|
||||
Q2_LUMP_SURFEDGES,
|
||||
Q2_LUMP_MODELS,
|
||||
Q2_LUMP_BRUSHES,
|
||||
Q2_LUMP_BRUSHSIDES,
|
||||
Q2_LUMP_POP,
|
||||
Q2_LUMP_AREAS,
|
||||
Q2_LUMP_AREAPORTALS,
|
||||
|
||||
Q2_HEADER_LUMPS
|
||||
};
|
||||
|
||||
struct q2_dheader_t
|
||||
{
|
||||
int32_t ident;
|
||||
int32_t version;
|
||||
std::array<lump_t, Q2_HEADER_LUMPS> lumps;
|
||||
|
||||
auto stream_data() { return std::tie(ident, version, lumps); }
|
||||
};
|
||||
|
||||
struct q2_dmodel_t
|
||||
{
|
||||
qvec3f mins;
|
||||
qvec3f maxs;
|
||||
qvec3f origin; // for sounds or lights
|
||||
int32_t headnode;
|
||||
int32_t firstface;
|
||||
int32_t numfaces; // submodels just draw faces
|
||||
// without walking the bsp tree
|
||||
|
||||
q2_dmodel_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
q2_dmodel_t(const dmodelh2_t &model)
|
||||
: mins(model.mins), maxs(model.maxs), origin(model.origin), headnode(model.headnode[0]),
|
||||
firstface(model.firstface), numfaces(model.numfaces)
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator dmodelh2_t() const
|
||||
{
|
||||
return {mins, maxs, origin, {headnode},
|
||||
0, // visleafs
|
||||
firstface, numfaces};
|
||||
}
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(mins, maxs, origin, headnode, firstface, numfaces); }
|
||||
};
|
||||
|
||||
|
||||
// Q2 contents (from qfiles.h)
|
||||
|
||||
// contents flags are seperate bits
|
||||
// a given brush can contribute multiple content bits
|
||||
// multiple brushes can be in a single leaf
|
||||
|
||||
// lower bits are stronger, and will eat weaker brushes completely
|
||||
enum q2_contents_t : int32_t
|
||||
{
|
||||
Q2_CONTENTS_EMPTY = 0,
|
||||
Q2_CONTENTS_SOLID = nth_bit(0), // an eye is never valid in a solid
|
||||
Q2_CONTENTS_WINDOW = nth_bit(1), // translucent, but not watery
|
||||
Q2_CONTENTS_AUX = nth_bit(2),
|
||||
Q2_CONTENTS_LAVA = nth_bit(3),
|
||||
Q2_CONTENTS_SLIME = nth_bit(4),
|
||||
Q2_CONTENTS_WATER = nth_bit(5),
|
||||
Q2_CONTENTS_MIST = nth_bit(6),
|
||||
Q2_LAST_VISIBLE_CONTENTS = Q2_CONTENTS_MIST,
|
||||
Q2_ALL_VISIBLE_CONTENTS = Q2_CONTENTS_SOLID | Q2_CONTENTS_WINDOW | Q2_CONTENTS_AUX | Q2_CONTENTS_LAVA |
|
||||
Q2_CONTENTS_SLIME | Q2_CONTENTS_WATER | Q2_CONTENTS_MIST,
|
||||
|
||||
Q2_CONTENTS_LIQUID = (Q2_CONTENTS_LAVA | Q2_CONTENTS_SLIME | Q2_CONTENTS_WATER), // mxd
|
||||
|
||||
// remaining contents are non-visible, and don't eat brushes
|
||||
|
||||
Q2_CONTENTS_AREAPORTAL = nth_bit(15),
|
||||
|
||||
Q2_CONTENTS_PLAYERCLIP = nth_bit(16),
|
||||
Q2_CONTENTS_MONSTERCLIP = nth_bit(17),
|
||||
|
||||
// currents can be added to any other contents, and may be mixed
|
||||
Q2_CONTENTS_CURRENT_0 = nth_bit(18),
|
||||
Q2_CONTENTS_CURRENT_90 = nth_bit(19),
|
||||
Q2_CONTENTS_CURRENT_180 = nth_bit(20),
|
||||
Q2_CONTENTS_CURRENT_270 = nth_bit(21),
|
||||
Q2_CONTENTS_CURRENT_UP = nth_bit(22),
|
||||
Q2_CONTENTS_CURRENT_DOWN = nth_bit(23),
|
||||
|
||||
Q2_CONTENTS_ORIGIN = nth_bit(24), // removed before bsping an entity
|
||||
|
||||
Q2_CONTENTS_MONSTER = nth_bit(25), // should never be on a brush, only in game
|
||||
Q2_CONTENTS_DEADMONSTER = nth_bit(26),
|
||||
Q2_CONTENTS_DETAIL = nth_bit(27), // brushes to be added after vis leafs
|
||||
Q2_CONTENTS_TRANSLUCENT = nth_bit(28), // auto set if any surface has trans
|
||||
Q2_CONTENTS_LADDER = nth_bit(29)
|
||||
};
|
||||
|
||||
struct q2_dnode_t
|
||||
{
|
||||
int32_t planenum;
|
||||
std::array<int32_t, 2> children; // negative numbers are -(leafs+1), not nodes
|
||||
qvec3s mins; // for frustom culling
|
||||
qvec3s maxs;
|
||||
uint16_t firstface;
|
||||
uint16_t numfaces; // counting both sides
|
||||
|
||||
q2_dnode_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
q2_dnode_t(const bsp2_dnode_t &model)
|
||||
: planenum(model.planenum), children(model.children),
|
||||
mins(aabb_mins_cast<int16_t>(model.mins, "dnode_t::mins")),
|
||||
maxs(aabb_maxs_cast<int16_t>(model.maxs, "dnode_t::maxs")),
|
||||
firstface(numeric_cast<uint16_t>(model.firstface, "dnode_t::firstface")),
|
||||
numfaces(numeric_cast<uint16_t>(model.numfaces, "dnode_t::numfaces"))
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator bsp2_dnode_t() const
|
||||
{
|
||||
return {planenum, children, aabb_mins_cast<float>(mins, "dnode_t::mins"),
|
||||
aabb_mins_cast<float>(maxs, "dnode_t::maxs"), firstface, numfaces};
|
||||
}
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(planenum, children, mins, maxs, firstface, numfaces); }
|
||||
};
|
||||
|
||||
using q2_dnode_qbism_t = bsp2_dnode_t;
|
||||
|
||||
// Q2 Texture flags.
|
||||
enum q2_surf_flags_t : int32_t
|
||||
{
|
||||
Q2_SURF_LIGHT = nth_bit(0), // value will hold the light strength
|
||||
|
||||
Q2_SURF_SLICK = nth_bit(1), // effects game physics
|
||||
|
||||
Q2_SURF_SKY = nth_bit(2), // don't draw, but add to skybox
|
||||
Q2_SURF_WARP = nth_bit(3), // turbulent water warp
|
||||
Q2_SURF_TRANS33 = nth_bit(4),
|
||||
Q2_SURF_TRANS66 = nth_bit(5),
|
||||
Q2_SURF_FLOWING = nth_bit(6), // scroll towards angle
|
||||
Q2_SURF_NODRAW = nth_bit(7), // don't bother referencing the texture
|
||||
|
||||
Q2_SURF_HINT = nth_bit(8), // make a primary bsp splitter
|
||||
Q2_SURF_SKIP = nth_bit(9), // ONLY FOR HINT! "nodraw" = Q1 "skip"
|
||||
|
||||
Q2_SURF_TRANSLUCENT = (Q2_SURF_TRANS33 | Q2_SURF_TRANS66), // mxd
|
||||
};
|
||||
|
||||
struct q2_texinfo_t
|
||||
{
|
||||
texvecf vecs; // [s/t][xyz offset]
|
||||
int32_t flags; // miptex flags + overrides
|
||||
int32_t value; // light emission, etc
|
||||
std::array<char, 32> texture; // texture name (textures/*.wal)
|
||||
int32_t nexttexinfo; // for animations, -1 = end of chain
|
||||
|
||||
q2_texinfo_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
q2_texinfo_t(const mtexinfo_t &model)
|
||||
: vecs(model.vecs), flags(model.flags.native), value(model.value), texture(model.texture),
|
||||
nexttexinfo(model.nexttexinfo)
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator mtexinfo_t() const { return {vecs, {flags}, -1, value, texture, nexttexinfo}; }
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(vecs, flags, value, texture, nexttexinfo); }
|
||||
};
|
||||
|
||||
struct q2_dface_t
|
||||
{
|
||||
uint16_t planenum; // NOTE: only difference from bsp29_dface_t
|
||||
int16_t side;
|
||||
int32_t firstedge; // we must support > 64k edges
|
||||
int16_t numedges;
|
||||
int16_t texinfo;
|
||||
|
||||
// lighting info
|
||||
std::array<uint8_t, MAXLIGHTMAPS> styles;
|
||||
int32_t lightofs; // start of [numstyles*surfsize] samples
|
||||
|
||||
q2_dface_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
q2_dface_t(const mface_t &model)
|
||||
: planenum(numeric_cast<uint16_t>(model.planenum, "dface_t::planenum")),
|
||||
side(numeric_cast<int16_t>(model.side, "dface_t::side")), firstedge(model.firstedge),
|
||||
numedges(numeric_cast<int16_t>(model.numedges, "dface_t::numedges")),
|
||||
texinfo(numeric_cast<int16_t>(model.texinfo, "dface_t::texinfo")), styles(model.styles),
|
||||
lightofs(model.lightofs)
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator mface_t() const { return {planenum, side, firstedge, numedges, texinfo, styles, lightofs}; }
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(planenum, side, firstedge, numedges, texinfo, styles, lightofs); }
|
||||
};
|
||||
|
||||
struct q2_dface_qbism_t
|
||||
{
|
||||
uint32_t planenum; // NOTE: only difference from bsp2_dface_t
|
||||
int32_t side;
|
||||
int32_t firstedge; // we must support > 64k edges
|
||||
int32_t numedges;
|
||||
int32_t texinfo;
|
||||
|
||||
// lighting info
|
||||
std::array<uint8_t, MAXLIGHTMAPS> styles;
|
||||
int32_t lightofs; // start of [numstyles*surfsize] samples
|
||||
|
||||
q2_dface_qbism_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
q2_dface_qbism_t(const mface_t &model)
|
||||
: planenum(numeric_cast<uint32_t>(model.planenum, "dface_t::planenum")), side(model.side),
|
||||
firstedge(model.firstedge), numedges(model.numedges), texinfo(model.texinfo), styles(model.styles),
|
||||
lightofs(model.lightofs)
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator mface_t() const { return {planenum, side, firstedge, numedges, texinfo, styles, lightofs}; }
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(planenum, side, firstedge, numedges, texinfo, styles, lightofs); }
|
||||
};
|
||||
|
||||
|
||||
struct q2_dleaf_t
|
||||
{
|
||||
int32_t contents; // OR of all brushes (not needed?)
|
||||
|
||||
int16_t cluster;
|
||||
int16_t area;
|
||||
|
||||
qvec3s mins; // for frustum culling
|
||||
qvec3s maxs;
|
||||
|
||||
uint16_t firstleafface;
|
||||
uint16_t numleaffaces;
|
||||
|
||||
uint16_t firstleafbrush;
|
||||
uint16_t numleafbrushes;
|
||||
|
||||
q2_dleaf_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
q2_dleaf_t(const mleaf_t &model)
|
||||
: contents(model.contents), cluster(numeric_cast<int16_t>(model.cluster, "dleaf_t::cluster")),
|
||||
area(numeric_cast<int16_t>(model.area, "dleaf_t::area")),
|
||||
mins(aabb_mins_cast<int16_t>(model.mins, "dleaf_t::mins")),
|
||||
maxs(aabb_mins_cast<int16_t>(model.maxs, "dleaf_t::maxs")),
|
||||
firstleafface(numeric_cast<uint16_t>(model.firstmarksurface, "dleaf_t::firstmarksurface")),
|
||||
numleaffaces(numeric_cast<uint16_t>(model.nummarksurfaces, "dleaf_t::nummarksurfaces")),
|
||||
firstleafbrush(numeric_cast<uint16_t>(model.firstleafbrush, "dleaf_t::firstleafbrush")),
|
||||
numleafbrushes(numeric_cast<uint16_t>(model.numleafbrushes, "dleaf_t::numleafbrushes"))
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator mleaf_t() const
|
||||
{
|
||||
return {contents, -1, aabb_mins_cast<float>(mins, "dleaf_t::mins"),
|
||||
aabb_mins_cast<float>(maxs, "dleaf_t::maxs"), firstleafface, numleaffaces, {}, cluster, area,
|
||||
firstleafbrush, numleafbrushes};
|
||||
}
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data()
|
||||
{
|
||||
return std::tie(
|
||||
contents, cluster, area, mins, maxs, firstleafface, numleaffaces, firstleafbrush, numleafbrushes);
|
||||
}
|
||||
};
|
||||
|
||||
struct q2_dleaf_qbism_t
|
||||
{
|
||||
int32_t contents; // OR of all brushes (not needed?)
|
||||
|
||||
int32_t cluster;
|
||||
int32_t area;
|
||||
|
||||
qvec3f mins; // for frustum culling
|
||||
qvec3f maxs;
|
||||
|
||||
uint32_t firstleafface;
|
||||
uint32_t numleaffaces;
|
||||
|
||||
uint32_t firstleafbrush;
|
||||
uint32_t numleafbrushes;
|
||||
|
||||
q2_dleaf_qbism_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
q2_dleaf_qbism_t(const mleaf_t &model)
|
||||
: contents(model.contents), cluster(model.cluster), area(model.area), mins(model.mins), maxs(model.maxs),
|
||||
firstleafface(model.firstmarksurface), numleaffaces(model.nummarksurfaces),
|
||||
firstleafbrush(model.firstleafbrush), numleafbrushes(model.numleafbrushes)
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator mleaf_t() const
|
||||
{
|
||||
return {
|
||||
contents, -1, mins, maxs, firstleafface, numleaffaces, {}, cluster, area, firstleafbrush, numleafbrushes};
|
||||
}
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data()
|
||||
{
|
||||
return std::tie(
|
||||
contents, cluster, area, mins, maxs, firstleafface, numleaffaces, firstleafbrush, numleafbrushes);
|
||||
}
|
||||
};
|
||||
|
||||
struct q2_dbrushside_t
|
||||
{
|
||||
uint16_t planenum; // facing out of the leaf
|
||||
int16_t texinfo;
|
||||
|
||||
q2_dbrushside_t() = default;
|
||||
|
||||
// convert from mbsp_t
|
||||
q2_dbrushside_t(const q2_dbrushside_qbism_t &model)
|
||||
: planenum(numeric_cast<uint16_t>(model.planenum, "dbrushside_t::planenum")),
|
||||
texinfo(numeric_cast<int16_t>(model.texinfo, "dbrushside_t::texinfo"))
|
||||
{
|
||||
}
|
||||
|
||||
// convert to mbsp_t
|
||||
operator q2_dbrushside_qbism_t() const { return {planenum, texinfo}; }
|
||||
|
||||
// serialize for streams
|
||||
auto stream_data() { return std::tie(planenum, texinfo); }
|
||||
};
|
||||
|
||||
// type tag used for type inference
|
||||
struct q2bsp_tag_t
|
||||
{
|
||||
};
|
||||
|
||||
struct q2bsp_t : q2bsp_tag_t
|
||||
{
|
||||
std::vector<q2_dmodel_t> dmodels;
|
||||
|
||||
mvis_t dvis;
|
||||
|
||||
std::vector<uint8_t> dlightdata;
|
||||
std::string dentdata;
|
||||
std::vector<q2_dleaf_t> dleafs;
|
||||
std::vector<dplane_t> dplanes;
|
||||
std::vector<qvec3f> dvertexes;
|
||||
std::vector<q2_dnode_t> dnodes;
|
||||
std::vector<q2_texinfo_t> texinfo;
|
||||
std::vector<q2_dface_t> dfaces;
|
||||
std::vector<bsp29_dedge_t> dedges;
|
||||
std::vector<uint16_t> dleaffaces;
|
||||
std::vector<uint16_t> dleafbrushes;
|
||||
std::vector<int32_t> dsurfedges;
|
||||
std::vector<darea_t> dareas;
|
||||
std::vector<dareaportal_t> dareaportals;
|
||||
std::vector<dbrush_t> dbrushes;
|
||||
std::vector<q2_dbrushside_t> dbrushsides;
|
||||
};
|
||||
|
||||
struct q2bsp_qbism_t : q2bsp_tag_t
|
||||
{
|
||||
std::vector<q2_dmodel_t> dmodels;
|
||||
mvis_t dvis;
|
||||
std::vector<uint8_t> dlightdata;
|
||||
std::string dentdata;
|
||||
std::vector<q2_dleaf_qbism_t> dleafs;
|
||||
std::vector<dplane_t> dplanes;
|
||||
std::vector<qvec3f> dvertexes;
|
||||
std::vector<q2_dnode_qbism_t> dnodes;
|
||||
std::vector<q2_texinfo_t> texinfo;
|
||||
std::vector<q2_dface_qbism_t> dfaces;
|
||||
std::vector<bsp2_dedge_t> dedges;
|
||||
std::vector<uint32_t> dleaffaces;
|
||||
std::vector<uint32_t> dleafbrushes;
|
||||
std::vector<int32_t> dsurfedges;
|
||||
std::vector<darea_t> dareas;
|
||||
std::vector<dareaportal_t> dareaportals;
|
||||
std::vector<dbrush_t> dbrushes;
|
||||
std::vector<q2_dbrushside_qbism_t> dbrushsides;
|
||||
};
|
||||
|
||||
extern const bspversion_t bspver_q2;
|
||||
extern const bspversion_t bspver_qbism;
|
||||
|
|
@ -706,7 +706,7 @@ public:
|
|||
|
||||
// generic case
|
||||
template<typename F>
|
||||
inline F distance_to(const qvec<F, 3> &point) const
|
||||
[[nodiscard]] inline F distance_to(const qvec<F, 3> &point) const
|
||||
{
|
||||
return qv::dot(point, normal) - dist;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue