From 812797f7ed5a6253635349dcf85d055fae44d0ad Mon Sep 17 00:00:00 2001 From: Jonathan Date: Fri, 10 Jun 2022 06:29:14 -0400 Subject: [PATCH] enable lighting for warp/sky in Q2 simplify bitflag definitions change nudging light warning to make more sense another #define -> constexpr pass --- CMakeLists.txt | 2 +- bspinfo/main.cc | 2 +- bsputil/bsputil.cc | 2 +- bsputil/decompile.cpp | 2 +- common/bspfile.cc | 47 +++--- common/entdata.cc | 4 - common/log.cc | 2 +- common/settings.cc | 2 +- include/common/bitflags.hh | 9 +- include/common/bspfile.hh | 300 +++++++++++++++++++------------------ include/common/cmdlib.hh | 59 ++++++-- include/common/log.hh | 10 +- include/light/litfile.hh | 2 +- include/vis/leafbits.hh | 4 +- light/entities.cc | 4 +- light/light.cc | 7 +- light/litfile.cc | 2 +- qbsp/map.cc | 4 +- qbsp/tjunc.cc | 2 +- vis/soundpvs.cc | 8 +- vis/vis.cc | 6 +- 21 files changed, 261 insertions(+), 219 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b42a391c..3963058b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,7 +42,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD 99) -add_definitions(-DERICWTOOLS_VERSION=${GIT_DESCRIBE}) +add_definitions(-DERICWTOOLS_VERSION="${GIT_DESCRIBE}") if (WIN32) set("NO_ITERATOR_DEBUG" FALSE CACHE BOOL "Whether to use MSVC iterator debugging or not") diff --git a/bspinfo/main.cc b/bspinfo/main.cc index 90fc03e5..c8698c35 100644 --- a/bspinfo/main.cc +++ b/bspinfo/main.cc @@ -89,7 +89,7 @@ settings::common_settings options; int main(int argc, char **argv) { - printf("---- bspinfo / ericw-tools " stringify(ERICWTOOLS_VERSION) " ----\n"); + fmt::print("---- bspinfo / ericw-tools {} ----\n", ERICWTOOLS_VERSION); if (argc == 1) { printf("usage: bspinfo bspfile [bspfiles]\n"); exit(1); diff --git a/bsputil/bsputil.cc b/bsputil/bsputil.cc index ac4ab030..86e439e5 100644 --- a/bsputil/bsputil.cc +++ b/bsputil/bsputil.cc @@ -464,7 +464,7 @@ int main(int argc, char **argv) bspdata_t bspdata; mbsp_t &bsp = bspdata.bsp.emplace(); - printf("---- bsputil / ericw-tools " stringify(ERICWTOOLS_VERSION) " ----\n"); + fmt::print("---- bsputil / ericw-tools {} ----\n", ERICWTOOLS_VERSION); if (argc == 1) { printf( "usage: bsputil [--replace-entities] [--extract-entities] [--extract-textures] [--convert bsp29|bsp2|bsp2rmq|q2bsp] [--check] [--modelinfo]\n" diff --git a/bsputil/decompile.cpp b/bsputil/decompile.cpp index 178f3941..19aaa642 100644 --- a/bsputil/decompile.cpp +++ b/bsputil/decompile.cpp @@ -542,7 +542,7 @@ static const char *DefaultOriginTexture(const mbsp_t *bsp) static const char *DefaultTextureForContents(const mbsp_t *bsp, const contentflags_t &contents) { if (bsp->loadversion->game->id == GAME_QUAKE_II) { - int visible = contents.native & ((Q2_LAST_VISIBLE_CONTENTS << 1) - 1); + int visible = contents.native & Q2_ALL_VISIBLE_CONTENTS; if (visible & Q2_CONTENTS_WATER) { return "e1u1/water4"; diff --git a/common/bspfile.cc b/common/bspfile.cc index 7f5f90d6..fb3625b6 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -58,15 +58,15 @@ struct gamedef_generic_t : public gamedef_t int32_t contents_priority(const contentflags_t &) const { throw std::bad_cast(); } - contentflags_t create_extended_contents(const int32_t &) const { throw std::bad_cast(); } + contentflags_t create_extended_contents(const uint16_t &) const { throw std::bad_cast(); } - contentflags_t create_empty_contents(const int32_t &) const { throw std::bad_cast(); } + contentflags_t create_empty_contents(const uint16_t &) const { throw std::bad_cast(); } - contentflags_t create_solid_contents(const int32_t &) const { throw std::bad_cast(); } + contentflags_t create_solid_contents(const uint16_t &) const { throw std::bad_cast(); } - contentflags_t create_sky_contents(const int32_t &) const { throw std::bad_cast(); } + contentflags_t create_sky_contents(const uint16_t &) const { throw std::bad_cast(); } - contentflags_t create_liquid_contents(const int32_t &, const int32_t &) const { throw std::bad_cast(); } + contentflags_t create_liquid_contents(const int32_t &, const uint16_t &) const { throw std::bad_cast(); } bool contents_are_empty(const contentflags_t &) const { throw std::bad_cast(); } @@ -167,30 +167,30 @@ struct gamedef_q1_like_t : public gamedef_t } } - contentflags_t create_extended_contents(const int32_t &cflags) const { return {0, cflags}; } + contentflags_t create_extended_contents(const uint16_t &cflags) const { return {0, cflags}; } - contentflags_t create_empty_contents(const int32_t &cflags = 0) const + contentflags_t create_empty_contents(const uint16_t &cflags = 0) const { Q_assert(!(cflags & CFLAGS_CONTENTS_MASK)); return {CONTENTS_EMPTY, cflags}; } - contentflags_t create_solid_contents(const int32_t &cflags = 0) const + contentflags_t create_solid_contents(const uint16_t &cflags = 0) const { Q_assert(!(cflags & CFLAGS_CONTENTS_MASK)); return {CONTENTS_SOLID, cflags}; } - contentflags_t create_sky_contents(const int32_t &cflags = 0) const + contentflags_t create_sky_contents(const uint16_t &cflags = 0) const { Q_assert(!(cflags & CFLAGS_CONTENTS_MASK)); return {CONTENTS_SKY, cflags}; } - contentflags_t create_liquid_contents(const int32_t &liquid_type, const int32_t &cflags = 0) const + contentflags_t create_liquid_contents(const int32_t &liquid_type, const uint16_t &cflags = 0) const { Q_assert(!(cflags & CFLAGS_CONTENTS_MASK)); @@ -426,12 +426,9 @@ struct gamedef_q2_t : public gamedef_t max_entity_key = 256; } - bool surf_is_lightmapped(const surfflags_t &flags) const - { - return !(flags.native & (Q2_SURF_WARP | Q2_SURF_SKY | Q2_SURF_NODRAW)); // mxd. +Q2_SURF_NODRAW - } + bool surf_is_lightmapped(const surfflags_t &flags) const { return !(flags.native & Q2_SURF_NODRAW); } - bool surf_is_subdivided(const surfflags_t &flags) const { return !(flags.native & (Q2_SURF_WARP | Q2_SURF_SKY)); } + bool surf_is_subdivided(const surfflags_t &flags) const { return true; } bool surfflags_are_valid(const surfflags_t &flags) const { @@ -447,7 +444,7 @@ struct gamedef_q2_t : public gamedef_t contentflags_t cluster_contents(const contentflags_t &contents0, const contentflags_t &contents1) const { - contentflags_t c = {contents0.native | contents1.native, contents0.extended | contents1.extended}; + contentflags_t c = {contents0.native | contents1.native, static_cast(contents0.extended | contents1.extended)}; // a cluster may include some solid detail areas, but // still be seen into @@ -459,7 +456,7 @@ struct gamedef_q2_t : public gamedef_t int32_t get_content_type(const contentflags_t &contents) const { - return contents.native & (((Q2_LAST_VISIBLE_CONTENTS << 1) - 1) | + return contents.native & (Q2_ALL_VISIBLE_CONTENTS | (Q2_CONTENTS_PLAYERCLIP | Q2_CONTENTS_MONSTERCLIP | Q2_CONTENTS_ORIGIN | Q2_CONTENTS_TRANSLUCENT | Q2_CONTENTS_AREAPORTAL)); } @@ -475,7 +472,7 @@ struct gamedef_q2_t : public gamedef_t } else if (contents.extended & CFLAGS_ILLUSIONARY_VISBLOCKER) { return 2; } else { - switch (contents.native & ((Q2_LAST_VISIBLE_CONTENTS << 1) - 1)) { + switch (contents.native & Q2_ALL_VISIBLE_CONTENTS) { case Q2_CONTENTS_SOLID: return 10; case Q2_CONTENTS_WINDOW: return 9; case Q2_CONTENTS_AUX: return 5; @@ -488,15 +485,15 @@ struct gamedef_q2_t : public gamedef_t } } - contentflags_t create_extended_contents(const int32_t &cflags) const { return {0, cflags}; } + contentflags_t create_extended_contents(const uint16_t &cflags) const { return {0, cflags}; } - contentflags_t create_empty_contents(const int32_t &cflags) const { return {0, cflags}; } + contentflags_t create_empty_contents(const uint16_t &cflags) const { return {0, cflags}; } - contentflags_t create_solid_contents(const int32_t &cflags) const { return {Q2_CONTENTS_SOLID, cflags}; } + contentflags_t create_solid_contents(const uint16_t &cflags) const { return {Q2_CONTENTS_SOLID, cflags}; } - contentflags_t create_sky_contents(const int32_t &cflags) const { return create_solid_contents(cflags); } + contentflags_t create_sky_contents(const uint16_t &cflags) const { return create_solid_contents(cflags); } - contentflags_t create_liquid_contents(const int32_t &liquid_type, const int32_t &cflags) const + contentflags_t create_liquid_contents(const int32_t &liquid_type, const uint16_t &cflags) const { switch (liquid_type) { case CONTENTS_WATER: return {Q2_CONTENTS_WATER, cflags}; @@ -515,7 +512,7 @@ struct gamedef_q2_t : public gamedef_t return false; // HACK: needs to return false in order for LinkConvexFaces to assign Q2_CONTENTS_AREAPORTAL // to the leaf - return !(contents.native & ((Q2_LAST_VISIBLE_CONTENTS << 1) - 1)); + return !(contents.native & Q2_ALL_VISIBLE_CONTENTS); } bool contents_are_solid(const contentflags_t &contents) const @@ -542,7 +539,7 @@ struct gamedef_q2_t : public gamedef_t bool contents_are_valid(const contentflags_t &contents, bool strict) const { // check that we don't have more than one visible contents type - const int32_t x = (contents.native & ((Q2_LAST_VISIBLE_CONTENTS << 1) - 1)); + const int32_t x = contents.native & Q2_ALL_VISIBLE_CONTENTS; if ((x & (x - 1)) != 0) { return false; } diff --git a/common/entdata.cc b/common/entdata.cc index 42351fa7..2fa38b61 100644 --- a/common/entdata.cc +++ b/common/entdata.cc @@ -138,8 +138,6 @@ std::vector EntData_Parse(const std::string &entdata) if (parser.token == "}") break; - if (parser.token.length() > MAX_ENT_KEY - 1) - FError("Key length > {}: '{}'", MAX_ENT_KEY - 1, parser.token); std::string keystr = parser.token; @@ -149,8 +147,6 @@ std::vector EntData_Parse(const std::string &entdata) if (parser.token == "}") FError("closing brace without data"); - if (parser.token.length() > MAX_ENT_VALUE - 1) - FError("Value length > {}", MAX_ENT_VALUE - 1); entity.set(keystr, parser.token); } diff --git a/common/log.cc b/common/log.cc index be46cba9..928bb9ae 100644 --- a/common/log.cc +++ b/common/log.cc @@ -49,7 +49,7 @@ void init(const fs::path &filename, const settings::common_settings &settings) { if (settings.log.value()) { logfile.open(filename); - fmt::print(logfile, "---- {} / ericw-tools " stringify(ERICWTOOLS_VERSION) " ----\n", settings.programName); + fmt::print(logfile, "---- {} / ericw-tools {} ----\n", settings.programName, ERICWTOOLS_VERSION); } } diff --git a/common/settings.cc b/common/settings.cc index 3eb5f7be..ce00efae 100644 --- a/common/settings.cc +++ b/common/settings.cc @@ -167,7 +167,7 @@ std::vector setting_container::parse(parser_base_t &parser) void common_settings::setParameters(int argc, const char **argv) { programName = fs::path(argv[0]).stem().string(); - fmt::print("---- {} / ericw-tools " stringify(ERICWTOOLS_VERSION) " ----\n", programName); + fmt::print("---- {} / ericw-tools {} ----\n", programName, ERICWTOOLS_VERSION); } void common_settings::postinitialize(int argc, const char **argv) diff --git a/include/common/bitflags.hh b/include/common/bitflags.hh index e1866eee..2b9be1dd 100644 --- a/include/common/bitflags.hh +++ b/include/common/bitflags.hh @@ -77,4 +77,11 @@ public: inline bool operator==(const Enum &r) const { return _bits == bitflags(r)._bits; } inline bool operator!=(const Enum &r) const { return _bits != bitflags(r)._bits; } -}; \ No newline at end of file +}; + +// fetch integral representation of the value at bit N +template +constexpr auto nth_bit(T l) +{ + return static_cast(1) << l; +} \ No newline at end of file diff --git a/include/common/bspfile.hh b/include/common/bspfile.hh index 04af5ef3..e14c5e70 100644 --- a/include/common/bspfile.hh +++ b/include/common/bspfile.hh @@ -32,41 +32,6 @@ #include #include -/* upper design bounds */ - -#define MAX_MAP_HULLS_Q1 4 -#define MAX_MAP_HULLS_H2 8 - -#define MAX_MAP_MODELS 256 -#define MAX_MAP_BRUSHES 4096 -#define MAX_MAP_PLANES 16384 -#define MAX_MAP_NODES 32767 /* negative shorts are contents */ -#define MAX_MAP_CLIPNODES 65520 /* = 0xfff0; larger are contents */ -#define MAX_MAP_LEAFS 32767 /* BSP file format limitation */ -#define MAX_MAP_VERTS 65535 -#define MAX_MAP_FACES 65535 -#define MAX_MAP_MARKSURFACES 65535 -#define MAX_MAP_TEXINFO 8192 -#define MAX_MAP_EDGES 256000 -#define MAX_MAP_SURFEDGES 512000 -#define MAX_MAP_MIPTEX 0x0800000 -#define MAX_MAP_LIGHTING 0x8000000 -#define MAX_MAP_VISIBILITY 0x8000000 - -/* key / value pair sizes */ -#define MAX_ENT_KEY 32 -#define MAX_ENT_VALUE 1024 - -#define NO_VERSION -1 - -#define BSPVERSION 29 -#define BSP2RMQVERSION (('B' << 24) | ('S' << 16) | ('P' << 8) | '2') -#define BSP2VERSION ('B' | ('S' << 8) | ('P' << 16) | ('2' << 24)) -#define BSPHLVERSION 30 // 24bit lighting, and private palettes in the textures lump. -#define Q2_BSPIDENT (('P' << 24) + ('S' << 16) + ('B' << 8) + 'I') -#define Q2_BSPVERSION 38 -#define Q2_QBISMIDENT (('P' << 24) + ('S' << 16) + ('B' << 8) + 'Q') - struct lump_t { int32_t fileofs; @@ -75,45 +40,60 @@ struct lump_t auto stream_data() { return std::tie(fileofs, filelen); } }; -#define LUMP_ENTITIES 0 -#define LUMP_PLANES 1 -#define LUMP_TEXTURES 2 -#define LUMP_VERTEXES 3 -#define LUMP_VISIBILITY 4 -#define LUMP_NODES 5 -#define LUMP_TEXINFO 6 -#define LUMP_FACES 7 -#define LUMP_LIGHTING 8 -#define LUMP_CLIPNODES 9 -#define LUMP_LEAFS 10 -#define LUMP_MARKSURFACES 11 -#define LUMP_EDGES 12 -#define LUMP_SURFEDGES 13 -#define LUMP_MODELS 14 +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. -#define BSP_LUMPS 15 +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, -#define Q2_LUMP_ENTITIES 0 -#define Q2_LUMP_PLANES 1 -#define Q2_LUMP_VERTEXES 2 -#define Q2_LUMP_VISIBILITY 3 -#define Q2_LUMP_NODES 4 -#define Q2_LUMP_TEXINFO 5 -#define Q2_LUMP_FACES 6 -#define Q2_LUMP_LIGHTING 7 -#define Q2_LUMP_LEAFS 8 -#define Q2_LUMP_LEAFFACES 9 -#define Q2_LUMP_LEAFBRUSHES 10 -#define Q2_LUMP_EDGES 11 -#define Q2_LUMP_SURFEDGES 12 -#define Q2_LUMP_MODELS 13 -#define Q2_LUMP_BRUSHES 14 -#define Q2_LUMP_BRUSHSIDES 15 -#define Q2_LUMP_POP 16 -#define Q2_LUMP_AREAS 17 -#define Q2_LUMP_AREAPORTALS 18 + BSP_LUMPS +}; -#define Q2_HEADER_LUMPS 19 +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 bspx_header_t { @@ -164,6 +144,8 @@ inline qvec aabb_maxs_cast(const qvec &f, const char *overflow_messa numeric_cast(f[2], overflow_message)}; } +constexpr size_t MAX_MAP_HULLS_H2 = 8; + struct dmodelh2_t { qvec3f mins; @@ -196,6 +178,8 @@ constexpr ADest array_cast(const ASrc &src, const char *overflow_message = "src" return dest; } +constexpr size_t MAX_MAP_HULLS_Q1 = 4; + struct dmodelq1_t { qvec3f mins; @@ -518,13 +502,17 @@ struct dplane_t : qplane3f // Q1 contents -constexpr int CONTENTS_EMPTY = -1; -constexpr int CONTENTS_SOLID = -2; -constexpr int CONTENTS_WATER = -3; -constexpr int CONTENTS_SLIME = -4; -constexpr int CONTENTS_LAVA = -5; -constexpr int CONTENTS_SKY = -6; -constexpr int CONTENTS_MIN = CONTENTS_SKY; +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 +}; // Q2 contents (from qfiles.h) @@ -532,63 +520,67 @@ constexpr int CONTENTS_MIN = CONTENTS_SKY; // a given brush can contribute multiple content bits // multiple brushes can be in a single leaf -// these definitions also need to be in q_shared.h! - // lower bits are stronger, and will eat weaker brushes completely -constexpr int Q2_CONTENTS_SOLID = 1; // an eye is never valid in a solid -constexpr int Q2_CONTENTS_WINDOW = 2; // translucent, but not watery -constexpr int Q2_CONTENTS_AUX = 4; -constexpr int Q2_CONTENTS_LAVA = 8; -constexpr int Q2_CONTENTS_SLIME = 16; -constexpr int Q2_CONTENTS_WATER = 32; -constexpr int Q2_CONTENTS_MIST = 64; -constexpr int Q2_LAST_VISIBLE_CONTENTS = 64; +enum q2_contents_t : int32_t +{ + 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, -constexpr int Q2_CONTENTS_LIQUID = (Q2_CONTENTS_LAVA | Q2_CONTENTS_SLIME | Q2_CONTENTS_WATER); // mxd + Q2_CONTENTS_LIQUID = (Q2_CONTENTS_LAVA | Q2_CONTENTS_SLIME | Q2_CONTENTS_WATER), // mxd -// remaining contents are non-visible, and don't eat brushes + // remaining contents are non-visible, and don't eat brushes -constexpr int Q2_CONTENTS_AREAPORTAL = 0x8000; + Q2_CONTENTS_AREAPORTAL = nth_bit(15), -constexpr int Q2_CONTENTS_PLAYERCLIP = 0x10000; -constexpr int Q2_CONTENTS_MONSTERCLIP = 0x20000; + Q2_CONTENTS_PLAYERCLIP = nth_bit(16), + Q2_CONTENTS_MONSTERCLIP = nth_bit(17), -// currents can be added to any other contents, and may be mixed -constexpr int Q2_CONTENTS_CURRENT_0 = 0x40000; -constexpr int Q2_CONTENTS_CURRENT_90 = 0x80000; -constexpr int Q2_CONTENTS_CURRENT_180 = 0x100000; -constexpr int Q2_CONTENTS_CURRENT_270 = 0x200000; -constexpr int Q2_CONTENTS_CURRENT_UP = 0x400000; -constexpr int Q2_CONTENTS_CURRENT_DOWN = 0x800000; + // 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), -constexpr int Q2_CONTENTS_ORIGIN = 0x1000000; // removed before bsping an entity + Q2_CONTENTS_ORIGIN = nth_bit(24), // removed before bsping an entity -constexpr int Q2_CONTENTS_MONSTER = 0x2000000; // should never be on a brush, only in game -constexpr int Q2_CONTENTS_DEADMONSTER = 0x4000000; -constexpr int Q2_CONTENTS_DETAIL = 0x8000000; // brushes to be added after vis leafs -constexpr int Q2_CONTENTS_TRANSLUCENT = 0x10000000; // auto set if any surface has trans -constexpr int Q2_CONTENTS_LADDER = 0x20000000; + 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) +}; // Special contents flags for the compiler only -constexpr int CFLAGS_STRUCTURAL_COVERED_BY_DETAIL = (1 << 0); -constexpr int CFLAGS_WAS_ILLUSIONARY = (1 << 1); /* was illusionary, got changed to something else */ -constexpr int CFLAGS_BMODEL_MIRROR_INSIDE = - (1 << 3); /* set "_mirrorinside" "1" on a bmodel to mirror faces for when the player is inside. */ -constexpr int CFLAGS_NO_CLIPPING_SAME_TYPE = - (1 << 4); /* Don't clip the same content type. mostly intended for CONTENTS_DETAIL_ILLUSIONARY */ -// only one of these flags below should ever be set. -constexpr int CFLAGS_HINT = (1 << 5); -constexpr int CFLAGS_CLIP = (1 << 6); -constexpr int CFLAGS_ORIGIN = (1 << 7); -constexpr int CFLAGS_DETAIL = (1 << 8); -constexpr int CFLAGS_DETAIL_ILLUSIONARY = (1 << 9); -constexpr int CFLAGS_DETAIL_FENCE = (1 << 10); -constexpr int CFLAGS_ILLUSIONARY_VISBLOCKER = (1 << 11); -// all of the detail values -constexpr int CFLAGS_DETAIL_MASK = (CFLAGS_DETAIL | CFLAGS_DETAIL_ILLUSIONARY | CFLAGS_DETAIL_FENCE); -// all of the special content types -constexpr int CFLAGS_CONTENTS_MASK = - (CFLAGS_HINT | CFLAGS_CLIP | CFLAGS_ORIGIN | CFLAGS_DETAIL_MASK | CFLAGS_ILLUSIONARY_VISBLOCKER); +enum extended_cflags_t : uint16_t +{ + CFLAGS_STRUCTURAL_COVERED_BY_DETAIL = nth_bit(0u), + CFLAGS_WAS_ILLUSIONARY = nth_bit(1), /* was illusionary, got changed to something else */ + CFLAGS_BMODEL_MIRROR_INSIDE = nth_bit(3), /* set "_mirrorinside" "1" on a bmodel to mirror faces for when the player is inside. */ + CFLAGS_NO_CLIPPING_SAME_TYPE = nth_bit(4), /* Don't clip the same content type. mostly intended for CONTENTS_DETAIL_ILLUSIONARY */ + // only one of these flags below should ever be set. + CFLAGS_HINT = nth_bit(5), + CFLAGS_CLIP = nth_bit(6), + CFLAGS_ORIGIN = nth_bit(7), + CFLAGS_DETAIL = nth_bit(8), + CFLAGS_DETAIL_ILLUSIONARY = nth_bit(9), + CFLAGS_DETAIL_FENCE = nth_bit(10), + CFLAGS_ILLUSIONARY_VISBLOCKER = nth_bit(11), + // all of the detail values + CFLAGS_DETAIL_MASK = (CFLAGS_DETAIL | CFLAGS_DETAIL_ILLUSIONARY | CFLAGS_DETAIL_FENCE), + // all of the special content types + CFLAGS_CONTENTS_MASK = + (CFLAGS_HINT | CFLAGS_CLIP | CFLAGS_ORIGIN | CFLAGS_DETAIL_MASK | CFLAGS_ILLUSIONARY_VISBLOCKER) +}; struct gamedef_t; @@ -598,7 +590,7 @@ struct contentflags_t int32_t native; // extra flags, specific to BSP only - int32_t extended; + uint16_t extended; // for CFLAGS_STRUCTURAL_COVERED_BY_DETAIL int32_t covered_native; @@ -816,24 +808,30 @@ private: }; // Q1 Texture flags. -#define TEX_SPECIAL 1 /* sky or slime, no lightmap or 256 subdivision */ +enum q1_surf_flags_t : int32_t +{ + TEX_SPECIAL = nth_bit(0) /* sky or slime, no lightmap or 256 subdivision */ +}; // Q2 Texture flags. -#define Q2_SURF_LIGHT 0x1 // value will hold the light strength +enum q2_surf_flags_t : int32_t +{ + Q2_SURF_LIGHT = nth_bit(0), // value will hold the light strength -#define Q2_SURF_SLICK 0x2 // effects game physics + Q2_SURF_SLICK = nth_bit(1), // effects game physics -#define Q2_SURF_SKY 0x4 // don't draw, but add to skybox -#define Q2_SURF_WARP 0x8 // turbulent water warp -#define Q2_SURF_TRANS33 0x10 -#define Q2_SURF_TRANS66 0x20 -#define Q2_SURF_FLOWING 0x40 // scroll towards angle -#define Q2_SURF_NODRAW 0x80 // don't bother referencing the texture + 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 -#define Q2_SURF_HINT 0x100 // make a primary bsp splitter -#define Q2_SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes + Q2_SURF_HINT = nth_bit(8), // make a primary bsp splitter + Q2_SURF_SKIP = nth_bit(9), // ONLY FOR HINT! "nodraw" = Q1 "skip" -#define Q2_SURF_TRANSLUCENT (Q2_SURF_TRANS33 | Q2_SURF_TRANS66) // mxd + Q2_SURF_TRANSLUCENT = (Q2_SURF_TRANS33 | Q2_SURF_TRANS66), // mxd +}; struct surfflags_t { @@ -1160,11 +1158,15 @@ struct q2_dface_qbism_t * all other leafs need visibility info */ /* Ambient Sounds */ -#define AMBIENT_WATER 0 -#define AMBIENT_SKY 1 -#define AMBIENT_SLIME 2 -#define AMBIENT_LAVA 3 -constexpr size_t NUM_AMBIENTS = 4; +enum ambient_type_t : uint8_t +{ + AMBIENT_WATER, + AMBIENT_SKY, + AMBIENT_SLIME, + AMBIENT_LAVA, + + NUM_AMBIENTS = 4 +}; struct mleaf_t { @@ -1790,11 +1792,11 @@ struct gamedef_t virtual contentflags_t cluster_contents(const contentflags_t &contents0, const contentflags_t &contents1) const = 0; virtual int32_t get_content_type(const contentflags_t &contents) const = 0; virtual int32_t contents_priority(const contentflags_t &contents) const = 0; - virtual contentflags_t create_extended_contents(const int32_t &cflags = 0) const = 0; - virtual contentflags_t create_empty_contents(const int32_t &cflags = 0) const = 0; - virtual contentflags_t create_solid_contents(const int32_t &cflags = 0) const = 0; - virtual contentflags_t create_sky_contents(const int32_t &cflags = 0) const = 0; - virtual contentflags_t create_liquid_contents(const int32_t &liquid_type, const int32_t &cflags = 0) const = 0; + virtual contentflags_t create_extended_contents(const uint16_t &cflags = 0) const = 0; + virtual contentflags_t create_empty_contents(const uint16_t &cflags = 0) const = 0; + virtual contentflags_t create_solid_contents(const uint16_t &cflags = 0) const = 0; + virtual contentflags_t create_sky_contents(const uint16_t &cflags = 0) const = 0; + virtual contentflags_t create_liquid_contents(const int32_t &liquid_type, const uint16_t &cflags = 0) const = 0; virtual bool contents_are_empty(const contentflags_t &contents) const = 0; virtual bool contents_are_solid(const contentflags_t &contents) const = 0; virtual bool contents_are_sky(const contentflags_t &contents) const = 0; @@ -1809,6 +1811,8 @@ struct gamedef_t virtual const std::vector &get_default_palette() const = 0; }; +constexpr int32_t NO_VERSION = -1; + // BSP version struct & instances struct bspversion_t { diff --git a/include/common/cmdlib.hh b/include/common/cmdlib.hh index 8dd90cf4..f0f5871a 100644 --- a/include/common/cmdlib.hh +++ b/include/common/cmdlib.hh @@ -32,21 +32,36 @@ #include #include -#define stringify__(x) #x -#define stringify(x) stringify__(x) - -#ifdef _WIN32 -#define Q_strncasecmp _strnicmp -#define Q_strcasecmp _stricmp -#elif defined(__has_include) && __has_include() +#if defined(__has_include) && __has_include() #include -#define Q_strncasecmp strncasecmp -#define Q_strcasecmp strcasecmp -#else -#define Q_strncasecmp strnicmp -#define Q_strcasecmp stricmp #endif +inline int32_t Q_strncasecmp(const char *a, const char *b, size_t maxcount) +{ + return +#ifdef _WIN32 + _strnicmp +#elif defined(__has_include) && __has_include() + strncasecmp +#else + strnicmp +#endif + (a, b, maxcount); +} + +inline int32_t Q_strcasecmp(const char *a, const char *b) +{ + return +#ifdef _WIN32 + _stricmp +#elif defined(__has_include) && __has_include() + strcasecmp +#else + stricmp +#endif + (a, b); +} + bool string_iequals(const std::string &a, const std::string &b); // mxd struct case_insensitive_hash @@ -255,7 +270,9 @@ inline float BigFloat(float l) /** * assertion macro that is used in all builds (debug/release) */ -#define Q_assert(x) logging::assert_((x), stringify(x), __FILE__, __LINE__) +#define Q_stringify__(x) #x +#define Q_stringify(x) Q_stringify__(x) +#define Q_assert(x) logging::assert_((x), Q_stringify(x), __FILE__, __LINE__) #define Q_assert_unreachable() Q_assert(false) @@ -470,6 +487,14 @@ inline std::enable_if_t +inline std::enable_if_t, std::ostream &> operator<=( + std::ostream &s, const T &obj) +{ + s <= reinterpret_cast &>(obj); + return s; +} + template inline std::istream &operator>=(std::istream &s, padding &) { @@ -611,6 +636,14 @@ inline std::enable_if_t +inline std::enable_if_t, std::istream &> operator>=( + std::istream &s, T &obj) +{ + s >= reinterpret_cast &>(obj); + return s; +} + template constexpr bool numeric_cast_will_overflow(const Src &value) { diff --git a/include/common/log.hh b/include/common/log.hh index 42d78db9..bd0cff34 100644 --- a/include/common/log.hh +++ b/include/common/log.hh @@ -43,11 +43,11 @@ namespace logging enum class flag : uint8_t { NONE = 0, // none of the below (still prints though) - DEFAULT = 1 << 0, // prints everywhere - VERBOSE = 1 << 1, // prints everywhere, if enabled - PROGRESS = 1 << 2, // prints only to stdout - PERCENT = 1 << 3, // prints everywhere, if enabled - STAT = 1 << 4, // prints everywhere, if enabled + DEFAULT = nth_bit(0), // prints everywhere + VERBOSE = nth_bit(1), // prints everywhere, if enabled + PROGRESS = nth_bit(2), // prints only to stdout + PERCENT = nth_bit(3), // prints everywhere, if enabled + STAT = nth_bit(4), // prints everywhere, if enabled ALL = 0xFF }; diff --git a/include/light/litfile.hh b/include/light/litfile.hh index 2f30372b..bf24323b 100644 --- a/include/light/litfile.hh +++ b/include/light/litfile.hh @@ -21,7 +21,7 @@ #include -#define LIT_VERSION 1 +constexpr int32_t LIT_VERSION = 1; struct litheader_t { diff --git a/include/vis/leafbits.hh b/include/vis/leafbits.hh index 0f1fe6a1..508fcc3f 100644 --- a/include/vis/leafbits.hh +++ b/include/vis/leafbits.hh @@ -98,7 +98,7 @@ public: constexpr uint32_t *data() { return bits; } constexpr const uint32_t *data() const { return bits; } - constexpr bool operator[](const size_t &index) const { return !!(bits[index >> shift] & (1UL << (index & mask))); } + constexpr bool operator[](const size_t &index) const { return !!(bits[index >> shift] & nth_bit(index & mask)); } struct reference { @@ -119,5 +119,5 @@ public: } }; - constexpr reference operator[](const size_t &index) { return {bits, index >> shift, static_cast(1) << (index & mask)}; } + constexpr reference operator[](const size_t &index) { return {bits, index >> shift, nth_bit(index & mask)}; } }; diff --git a/light/entities.cc b/light/entities.cc index f4e62b0a..2cd6363c 100644 --- a/light/entities.cc +++ b/light/entities.cc @@ -687,7 +687,7 @@ void Matrix4x4_CM_Projection_Inf(std::array &proj, vec_t fovx, vec_t proj[2] = 0; proj[6] = 0; - proj[10] = -1 * ((vec_t)(1 << 21) / (1 << 22)); + proj[10] = -1 * 0.5; proj[14] = -2 * neard * nudge; proj[3] = 0; @@ -1026,7 +1026,7 @@ static qvec3d FixLightOnFace(const mbsp_t *bsp, const qvec3d &point) } } - logging::print("WARNING: couldn't nudge light in solid at {}\n", point); + logging::print("WARNING: couldn't nudge light out of solid at {}\n", point); return point; } diff --git a/light/light.cc b/light/light.cc index 37ea761d..92fe1cf8 100644 --- a/light/light.cc +++ b/light/light.cc @@ -407,6 +407,11 @@ static void FindModelInfo(const mbsp_t *bsp) Q_assert(modelinfo.size() == bsp->dmodels.size()); } +// FIXME: in theory can't we calculate the exact amount of +// storage required? we'd have to expand it by 4 to account for +// lightstyles though +static constexpr size_t MAX_MAP_LIGHTING = 0x8000000; + /* * ============= * LightWorld @@ -455,7 +460,7 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale) if (lmshift_lump != bspdata->bspx.entries.end()) { for (int i = 0; i < bsp.dfaces.size(); i++) - faces_sup[i].lmscale = 1 << reinterpret_cast(lmshift_lump->second.lumpdata.get())[i]; + faces_sup[i].lmscale = nth_bit(reinterpret_cast(lmshift_lump->second.lumpdata.get())[i]); } else { for (int i = 0; i < bsp.dfaces.size(); i++) faces_sup[i].lmscale = modelinfo.at(0)->lightmapscale; diff --git a/light/litfile.cc b/light/litfile.cc index 1eb11c99..47fda418 100644 --- a/light/litfile.cc +++ b/light/litfile.cc @@ -57,7 +57,7 @@ void WriteLitFile(const mbsp_t *bsp, facesup_t *facesup, const fs::path &filenam extents[i * 2 + 0] = LittleShort(facesup[i].extent[0]); extents[i * 2 + 1] = LittleShort(facesup[i].extent[1]); j = 0; - while ((1u << j) < facesup[i].lmscale) + while (nth_bit(j) < facesup[i].lmscale) j++; shifts[i] = j; } diff --git a/qbsp/map.cc b/qbsp/map.cc index 397d52f1..0fe79e01 100644 --- a/qbsp/map.cc +++ b/qbsp/map.cc @@ -1416,12 +1416,12 @@ static void ParseTextureDef(parser_t &parser, mapface_t &mapface, const mapbrush for (int i = 0; i < 8; i++) { if (!got) { - if (mapface.contents.native & (1 << i)) { + if (mapface.contents.native & nth_bit(i)) { got = true; continue; } } else { - mapface.contents.native &= ~(1 << i); + mapface.contents.native &= ~nth_bit(i); } } } diff --git a/qbsp/tjunc.cc b/qbsp/tjunc.cc index afe5d640..d53a972c 100644 --- a/qbsp/tjunc.cc +++ b/qbsp/tjunc.cc @@ -51,7 +51,7 @@ static wedge_t *pWEdges; //============================================================================ -#define NUM_HASH 1024 +constexpr size_t NUM_HASH = 1024; static wedge_t *wedge_hash[NUM_HASH]; static qvec3d hash_min, hash_scale; diff --git a/vis/soundpvs.cc b/vis/soundpvs.cc index c0bdcc02..f12604eb 100644 --- a/vis/soundpvs.cc +++ b/vis/soundpvs.cc @@ -65,7 +65,7 @@ void CalcAmbientSounds(mbsp_t *bsp) mleaf_t *leaf, *hit; uint8_t *vis; float d, maxd; - int ambient_type; + ambient_type_t ambient_type; float dists[NUM_AMBIENTS]; float vol; @@ -85,7 +85,7 @@ void CalcAmbientSounds(mbsp_t *bsp) } for (j = 0; j < portalleafs_real; j++) { - if (!(vis[j >> 3] & (1 << (j & 7)))) + if (!(vis[j >> 3] & nth_bit(j & 7))) continue; // @@ -181,7 +181,7 @@ void CalcPHS(mbsp_t *bsp) if (!bitbyte) continue; for (int32_t k = 0; k < 8; k++) { - if (!(bitbyte & (1 << k))) + if (!(bitbyte & nth_bit(k))) continue; // OR this pvs row into the phs int32_t index = ((j << 3) + k); @@ -196,7 +196,7 @@ void CalcPHS(mbsp_t *bsp) } } for (int32_t j = 0; j < portalleafs; j++) - if (uncompressed[j >> 3] & (1 << (j & 7))) + if (uncompressed[j >> 3] & nth_bit(j & 7)) count++; // diff --git a/vis/vis.cc b/vis/vis.cc index b90a46b5..efb92ba4 100644 --- a/vis/vis.cc +++ b/vis/vis.cc @@ -352,7 +352,7 @@ static void PortalCompleted(portal_t *completed) */ while (changed) { bit = ffsl(changed) - 1; - changed &= ~(1UL << bit); + changed &= ~nth_bit(bit); leafnum = (j << leafbits_t::shift) + bit; UpdateMightsee(leafs + leafnum, myleaf); } @@ -443,7 +443,7 @@ static void ClusterFlow(int clusternum, leafbits_t &buffer, mbsp_t *bsp) outbuffer = uncompressed_q2 + clusternum * leafbytes; for (i = 0; i < portalleafs; i++) { if (buffer[i]) { - outbuffer[i >> 3] |= (1 << (i & 7)); + outbuffer[i >> 3] |= nth_bit(i & 7); numvis++; } } @@ -451,7 +451,7 @@ static void ClusterFlow(int clusternum, leafbits_t &buffer, mbsp_t *bsp) outbuffer = uncompressed + clusternum * leafbytes_real; for (i = 0; i < portalleafs_real; i++) { if (buffer[bsp->dleafs[i + 1].cluster]) { - outbuffer[i >> 3] |= (1 << (i & 7)); + outbuffer[i >> 3] |= nth_bit(i & 7); numvis++; } }