From 00efa6e67d1b56ab93606098ea511f7fd0e791be Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 7 Sep 2021 01:41:32 -0400 Subject: [PATCH] Fix operator< Introduce gamedef, to reduce rewriting of data in bspversions fix name of needs_subdivision include value in texinfo, in prep for Q2 --- common/bspfile.cc | 102 +++++++++++++++++++++++++++++--------- common/bsputils.cc | 8 +-- include/common/bspfile.hh | 34 +++++++++---- include/qbsp/map.hh | 3 +- include/qbsp/qbsp.hh | 14 ++++-- light/entities.cc | 2 +- light/imglib.cc | 6 +-- light/light.cc | 14 ++---- light/ltface.cc | 4 +- light/trace.cc | 2 +- light/trace_embree.cc | 6 +-- qbsp/brush.cc | 10 ++-- qbsp/csg4.cc | 9 ++-- qbsp/map.cc | 55 ++++++++++---------- qbsp/qbsp.cc | 10 ++-- qbsp/surfaces.cc | 4 +- qbsp/writebsp.cc | 8 +-- vis/vis.cc | 16 +++--- 18 files changed, 181 insertions(+), 126 deletions(-) diff --git a/common/bspfile.cc b/common/bspfile.cc index 10a1f908..aca3dcb6 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -22,34 +22,88 @@ #include #include -bool q1_surf_is_lightmapped(const surfflags_t &flags) { - return !(flags.native & TEX_SPECIAL); -} +struct gamedef_generic_t : public gamedef_t { + gamedef_generic_t() + { + id = GAME_UNKNOWN; + base_dir = nullptr; + } -bool q2_surf_is_lightmapped(const surfflags_t &flags) { - 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 { + throw std::bad_cast(); + } -bool q1_surf_needs_subdivision(const surfflags_t &flags) { - return flags.native & TEX_SPECIAL; -} + bool surf_is_subdivided(const surfflags_t &flags) const { + throw std::bad_cast(); + } +}; -bool q2_surf_needs_subdivision(const surfflags_t &flags) { - return flags.native & (Q2_SURF_WARP | Q2_SURF_SKY); -} +template +struct gamedef_q1_like_t : public gamedef_t { + gamedef_q1_like_t() + { + this->id = id; + has_rgb_lightmap = false; + base_dir = "ID1"; + } -/* game, colored lightmap, surf_is_lightmapped surf_needs_subdivision */ -const bspversion_t bspver_generic { NO_VERSION, NO_VERSION, "mbsp", "generic BSP", GAME_UNKNOWN }; -const bspversion_t bspver_q1 { BSPVERSION, NO_VERSION, "bsp29", "Quake BSP", GAME_QUAKE, false, q1_surf_is_lightmapped, q1_surf_needs_subdivision }; -const bspversion_t bspver_bsp2 { BSP2VERSION, NO_VERSION, "bsp2", "Quake BSP2", GAME_QUAKE, false, q1_surf_is_lightmapped, q1_surf_needs_subdivision }; -const bspversion_t bspver_bsp2rmq { BSP2RMQVERSION, NO_VERSION, "bsp2rmq", "Quake BSP2-RMQ", GAME_QUAKE, false, q1_surf_is_lightmapped, q1_surf_needs_subdivision }; -/* Hexen II doesn't use a separate version, but we can still use a separate tag/name for it */ -const bspversion_t bspver_h2 { BSPVERSION, NO_VERSION, "hexen2", "Hexen II BSP", GAME_HEXEN_II, false, q1_surf_is_lightmapped, q1_surf_needs_subdivision }; -const bspversion_t bspver_h2bsp2 { BSP2VERSION, NO_VERSION, "hexen2bsp2", "Hexen II BSP2", GAME_HEXEN_II, false, q1_surf_is_lightmapped, q1_surf_needs_subdivision }; -const bspversion_t bspver_h2bsp2rmq { BSP2RMQVERSION, NO_VERSION, "hexen2bsp2rmq", "Hexen II BSP2-RMQ", GAME_HEXEN_II, false, q1_surf_is_lightmapped, q1_surf_needs_subdivision }; -const bspversion_t bspver_hl { BSPHLVERSION, NO_VERSION, "hl", "Half-Life BSP", GAME_HALF_LIFE, true, q1_surf_is_lightmapped, q1_surf_needs_subdivision }; -const bspversion_t bspver_q2 { Q2_BSPIDENT, Q2_BSPVERSION, "q2bsp", "Quake II BSP", GAME_QUAKE_II, true, q2_surf_is_lightmapped, q2_surf_needs_subdivision }; -const bspversion_t bspver_qbism { Q2_QBISMIDENT, Q2_BSPVERSION, "qbism", "Quake II Qbism BSP", GAME_QUAKE_II, true, q2_surf_is_lightmapped, q2_surf_needs_subdivision }; + bool surf_is_lightmapped(const surfflags_t &flags) const { + return !(flags.native & TEX_SPECIAL); + } + + bool surf_is_subdivided(const surfflags_t &flags) const { + return !(flags.native & TEX_SPECIAL); + } +}; + +struct gamedef_h2_t : public gamedef_q1_like_t { + gamedef_h2_t() + { + base_dir = "DATA1"; + } +}; + +struct gamedef_hl_t : public gamedef_q1_like_t { + gamedef_hl_t() + { + has_rgb_lightmap = true; + base_dir = "VALVE"; + } +}; + +struct gamedef_q2_t : public gamedef_t { + gamedef_q2_t() + { + this->id = GAME_QUAKE_II; + has_rgb_lightmap = true; + base_dir = "BASEQ2"; + } + + 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_subdivided(const surfflags_t &flags) const { + return !(flags.native & (Q2_SURF_WARP | Q2_SURF_SKY)); + } +}; + +static const gamedef_generic_t gamedef_generic; +const bspversion_t bspver_generic { NO_VERSION, NO_VERSION, "mbsp", "generic BSP", &gamedef_generic }; +static const gamedef_q1_like_t gamedef_q1; +const bspversion_t bspver_q1 { BSPVERSION, NO_VERSION, "bsp29", "Quake BSP", &gamedef_q1 }; +const bspversion_t bspver_bsp2 { BSP2VERSION, NO_VERSION, "bsp2", "Quake BSP2", &gamedef_q1 }; +const bspversion_t bspver_bsp2rmq { BSP2RMQVERSION, NO_VERSION, "bsp2rmq", "Quake BSP2-RMQ", &gamedef_q1 }; +/* Hexen II doesn't use a separate version, but we can still use a separate tag/name for it */ +static const gamedef_h2_t gamedef_h2; +const bspversion_t bspver_h2 { BSPVERSION, NO_VERSION, "hexen2", "Hexen II BSP", &gamedef_h2 }; +const bspversion_t bspver_h2bsp2 { BSP2VERSION, NO_VERSION, "hexen2bsp2", "Hexen II BSP2", &gamedef_h2 }; +const bspversion_t bspver_h2bsp2rmq { BSP2RMQVERSION, NO_VERSION, "hexen2bsp2rmq", "Hexen II BSP2-RMQ", &gamedef_h2 }; +static const gamedef_hl_t gamedef_hl; +const bspversion_t bspver_hl { BSPHLVERSION, NO_VERSION, "hl", "Half-Life BSP", &gamedef_hl }; +static const gamedef_q2_t gamedef_q2; +const bspversion_t bspver_q2 { Q2_BSPIDENT, Q2_BSPVERSION, "q2bsp", "Quake II BSP", &gamedef_q2 }; +const bspversion_t bspver_qbism { Q2_QBISMIDENT, Q2_BSPVERSION, "qbism", "Quake II Qbism BSP", &gamedef_q2 }; static const char * BSPVersionString(const bspversion_t *version) diff --git a/common/bsputils.cc b/common/bsputils.cc index 44b1b8f8..d4a1e567 100644 --- a/common/bsputils.cc +++ b/common/bsputils.cc @@ -189,7 +189,7 @@ bool Face_IsLightmapped(const mbsp_t *bsp, const bsp2_dface_t *face) if (texinfo == nullptr) return false; - return bsp->loadversion->surf_is_lightmapped(texinfo->flags); + return bsp->loadversion->game->surf_is_lightmapped(texinfo->flags); } const float *GetSurfaceVertexPoint(const mbsp_t *bsp, const bsp2_dface_t *f, int v) @@ -215,7 +215,7 @@ TextureName_Contents(const char *texname) bool //mxd ContentsOrSurfaceFlags_IsTranslucent(const mbsp_t *bsp, const int contents_or_surf_flags) { - if (bsp->loadversion->game == GAME_QUAKE_II) + if (bsp->loadversion->game->id == GAME_QUAKE_II) return (contents_or_surf_flags & Q2_SURF_TRANSLUCENT) && ((contents_or_surf_flags & Q2_SURF_TRANSLUCENT) != Q2_SURF_TRANSLUCENT); // Don't count KMQ2 fence flags combo as translucent else return contents_or_surf_flags == CONTENTS_WATER || contents_or_surf_flags == CONTENTS_LAVA || contents_or_surf_flags == CONTENTS_SLIME; @@ -230,7 +230,7 @@ Face_IsTranslucent(const mbsp_t *bsp, const bsp2_dface_t *face) int //mxd. Returns CONTENTS_ value for Q1, Q2_SURF_ bitflags for Q2... Face_ContentsOrSurfaceFlags(const mbsp_t *bsp, const bsp2_dface_t *face) { - if (bsp->loadversion->game == GAME_QUAKE_II) { + if (bsp->loadversion->game->id == GAME_QUAKE_II) { const gtexinfo_t *info = Face_Texinfo(bsp, face); return info->flags.native; } else { @@ -275,7 +275,7 @@ static bool Light_PointInSolid_r(const mbsp_t *bsp, const int nodenum, const vec const mleaf_t *leaf = BSP_GetLeafFromNodeNum(bsp, nodenum); //mxd - if (bsp->loadversion->game == GAME_QUAKE_II) { + if (bsp->loadversion->game->id == GAME_QUAKE_II) { return leaf->contents & Q2_CONTENTS_SOLID; } diff --git a/include/common/bspfile.hh b/include/common/bspfile.hh index cfae1100..e9720118 100644 --- a/include/common/bspfile.hh +++ b/include/common/bspfile.hh @@ -21,6 +21,7 @@ #define __COMMON_BSPFILE_H__ #include +#include #include #include @@ -373,7 +374,7 @@ struct surfflags_t { uint8_t minlight; // red minlight colors for this face - uint8_t minlight_color[3]; + std::array minlight_color; // if non zero, overrides _phong_angle for concave joints uint8_t phong_angle_concave; @@ -980,13 +981,29 @@ typedef struct { bspxentry_t *bspxentries; } bspdata_t; -// native game ID target -enum bspgame_t { +// native game target ID +enum gameid_t { GAME_UNKNOWN, GAME_QUAKE, GAME_HEXEN_II, GAME_HALF_LIFE, - GAME_QUAKE_II + GAME_QUAKE_II, + + GAME_TOTAL +}; + +// Game definition, which contains data specific to +// the game a BSP version is being compiled for. +struct gamedef_t +{ + gameid_t id; + + bool has_rgb_lightmap; + + const char *base_dir; + + virtual bool surf_is_lightmapped(const surfflags_t &flags) const = 0; + virtual bool surf_is_subdivided(const surfflags_t &flags) const = 0; }; // BSP version struct & instances @@ -1000,13 +1017,8 @@ struct bspversion_t const char *short_name; /* full display name for printing */ const char *name; - /* game ID */ - bspgame_t game; - /* whether the game natively has a colored lightmap or not */ - /* TODO: move to a game-specific table */ - bool rgb_lightmap; - bool (*surf_is_lightmapped)(const surfflags_t &flags); - bool (*surf_needs_subdivision)(const surfflags_t &flags); + /* game ptr */ + const gamedef_t *game; }; extern const bspversion_t bspver_generic; diff --git a/include/qbsp/map.hh b/include/qbsp/map.hh index 2fba7049..1306eb79 100644 --- a/include/qbsp/map.hh +++ b/include/qbsp/map.hh @@ -206,8 +206,7 @@ struct extended_tx_info_t { }; int FindMiptex(const char *name); -int FindTexinfo(mtexinfo_t *texinfo, surfflags_t flags); //FIXME: Make this take const texinfo -int FindTexinfoEnt(mtexinfo_t *texinfo, mapentity_t *entity); //FIXME: Make this take const texinfo +int FindTexinfo(const mtexinfo_t &texinfo, surfflags_t flags); void PrintEntity(const mapentity_t *entity); const char *ValueForKey(const mapentity_t *entity, const char *key); diff --git a/include/qbsp/qbsp.hh b/include/qbsp/qbsp.hh index b62481a4..28229eb6 100644 --- a/include/qbsp/qbsp.hh +++ b/include/qbsp/qbsp.hh @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -141,14 +142,17 @@ enum { #include #include +using stvecs = std::array, 2>; + typedef struct mtexinfo_s { - float vecs[2][4]; /* [s/t][xyz offset] */ - int32_t miptex; - surfflags_t flags; - int outputnum; // -1 until added to bsp + stvecs vecs; /* [s/t][xyz offset] */ + int32_t miptex = 0; + surfflags_t flags = {}; + int32_t value = 0; // Q2-specific + int outputnum = -1; // -1 until added to bsp constexpr auto as_tuple() const { - return std::tie(vecs, miptex, flags); + return std::tie(vecs, miptex, flags, value); } constexpr bool operator<(const mtexinfo_s &other) const { diff --git a/light/entities.cc b/light/entities.cc index fb0dc67f..df720d78 100644 --- a/light/entities.cc +++ b/light/entities.cc @@ -1579,7 +1579,7 @@ static void MakeSurfaceLights(const mbsp_t *bsp) for (int i = 0; i < bsp->numleafs; i++) { const mleaf_t *leaf = bsp->dleafs + i; - const qboolean underwater = ((bsp->loadversion->game == GAME_QUAKE_II) ? (leaf->contents & Q2_CONTENTS_LIQUID) : leaf->contents != CONTENTS_EMPTY); //mxd + const qboolean underwater = ((bsp->loadversion->game->id == GAME_QUAKE_II) ? (leaf->contents & Q2_CONTENTS_LIQUID) : leaf->contents != CONTENTS_EMPTY); //mxd for (int k = 0; k < leaf->nummarksurfaces; k++) { const int facenum = bsp->dleaffaces[leaf->firstmarksurface + k]; diff --git a/light/imglib.cc b/light/imglib.cc index a8d468c6..5b4280c2 100644 --- a/light/imglib.cc +++ b/light/imglib.cc @@ -44,7 +44,7 @@ void // WHO TOUCHED MY PALET? LoadPalette(bspdata_t *bspdata) { // Load Quake 2 palette - if (bspdata->loadversion->game == GAME_QUAKE_II) { + if (bspdata->loadversion->game->id == GAME_QUAKE_II) { uint8_t *palette; char path[1024]; char colormap[] = "pics/colormap.pcx"; @@ -66,7 +66,7 @@ LoadPalette(bspdata_t *bspdata) for (int i = 0; i < 768; i++) thepalette[i] = palette[i]; - } else if (bspdata->loadversion->game == GAME_HEXEN_II) { + } else if (bspdata->loadversion->game->id == GAME_HEXEN_II) { // Copy Hexen 2 palette for (int i = 0; i < 768; i++) thepalette[i] = hexen2palette[i]; @@ -721,7 +721,7 @@ void // Expects correct palette and game/mod paths to be set LoadOrConvertTextures(mbsp_t *bsp) { // Load or convert textures... - if (bsp->loadversion->game == GAME_QUAKE_II) + if (bsp->loadversion->game->id == GAME_QUAKE_II) LoadTextures(bsp); else if (bsp->texdatasize > 0) ConvertTextures(bsp); diff --git a/light/light.cc b/light/light.cc index 45540b78..3c226ff9 100644 --- a/light/light.cc +++ b/light/light.cc @@ -439,7 +439,7 @@ LightWorld(bspdata_t *bspdata, qboolean forcedscale) CalculateVertexNormals(bsp); const qboolean bouncerequired = cfg_static.bounce.boolValue() && (debugmode == debugmode_none || debugmode == debugmode_bounce || debugmode == debugmode_bouncelights); //mxd - const qboolean isQuake2map = bsp->loadversion->game == GAME_QUAKE_II; //mxd + const qboolean isQuake2map = bsp->loadversion->game->id == GAME_QUAKE_II; //mxd if (bouncerequired || isQuake2map) { MakeTextureColors(bsp); @@ -470,7 +470,7 @@ LightWorld(bspdata_t *bspdata, qboolean forcedscale) // Transfer greyscale lightmap (or color lightmap for Q2/HL) to the bsp and update lightdatasize if (!litonly) { free(bsp->dlightdata); - if (bsp->loadversion->rgb_lightmap) { + if (bsp->loadversion->game->has_rgb_lightmap) { bsp->lightdatasize = lit_file_p; bsp->dlightdata = (uint8_t *)malloc(bsp->lightdatasize); memcpy(bsp->dlightdata, lit_filebase, bsp->lightdatasize); @@ -537,11 +537,7 @@ LoadExtendedTexinfoFlags(const char *sourcefilename, const mbsp_t *bsp) static const char* //mxd GetBaseDirName(bspdata_t *bspdata) { - if (bspdata->loadversion->game == GAME_QUAKE_II) - return "BASEQ2"; - if (bspdata->loadversion->game == GAME_HEXEN_II) - return "DATA1"; - return "ID1"; + return bspdata->loadversion->game->base_dir; } //obj @@ -1194,7 +1190,7 @@ light_main(int argc, const char **argv) ConvertBSPFormat(&bspdata, &bspver_generic); //mxd. Use 1.0 rangescale as a default to better match with qrad3/arghrad - if ((loadversion->game == GAME_QUAKE_II) && !cfg.rangescale.isChanged()) + if ((loadversion->game->id == GAME_QUAKE_II) && !cfg.rangescale.isChanged()) { const auto rs = new lockable_vec_t(cfg.rangescale.primaryName(), 1.0f, 0.0f, 100.0f); cfg.rangescale = *rs; // Gross hacks to avoid displaying this in OptionsSummary... @@ -1234,7 +1230,7 @@ light_main(int argc, const char **argv) if (!onlyents) { - if (!loadversion->rgb_lightmap) { + if (!loadversion->game->has_rgb_lightmap) { CheckLitNeeded(cfg); } SetupDirt(cfg); diff --git a/light/ltface.cc b/light/ltface.cc index de30cadc..8cba774f 100644 --- a/light/ltface.cc +++ b/light/ltface.cc @@ -3081,7 +3081,7 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const continue; // skip lightmaps where all samples have brightness below 1 - if (bsp->loadversion->game == GAME_QUAKE_II) { // HACK: don't do this on Q2. seems if all styles are 0xff, the face is drawn fullbright instead of black (Q1) + if (bsp->loadversion->game->id == GAME_QUAKE_II) { // HACK: don't do this on Q2. seems if all styles are 0xff, the face is drawn fullbright instead of black (Q1) const float maxb = Lightmap_MaxBrightness(&lightmap, lightsurf); if (maxb < 1) continue; @@ -3147,7 +3147,7 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const int lightofs; // Q2/HL native colored lightmaps - if (bsp->loadversion->rgb_lightmap) { + if (bsp->loadversion->game->has_rgb_lightmap) { lightofs = lit - lit_filebase; } else { lightofs = out - filebase; diff --git a/light/trace.cc b/light/trace.cc index 38972c82..0e0876f8 100644 --- a/light/trace.cc +++ b/light/trace.cc @@ -716,7 +716,7 @@ TraceFaces (traceinfo_t *ti, int node, const vec3_t start, const vec3_t end) // only solid and sky faces stop the trace. bool issolid, issky; //mxd - if(bsp_static->loadversion->game == GAME_QUAKE_II) { + if(bsp_static->loadversion->game->id == GAME_QUAKE_II) { issolid = !(fi->content_or_surf_flags & Q2_SURF_TRANSLUCENT); issky = (fi->content_or_surf_flags & Q2_SURF_SKY); } else { diff --git a/light/trace_embree.cc b/light/trace_embree.cc index a15ce166..f9bf52c4 100644 --- a/light/trace_embree.cc +++ b/light/trace_embree.cc @@ -353,7 +353,7 @@ Embree_FilterFuncN(const struct RTCFilterFunctionNArguments* args) //mxd bool isFence, isGlass; - if(bsp_static->loadversion->game == GAME_QUAKE_II) { + if(bsp_static->loadversion->game->id == GAME_QUAKE_II) { const int surf_flags = Face_ContentsOrSurfaceFlags(bsp_static, face); isFence = ((surf_flags & Q2_SURF_TRANSLUCENT) == Q2_SURF_TRANSLUCENT); // KMQuake 2-specific. Use texture alpha chanel when both flags are set. isGlass = !isFence && (surf_flags & Q2_SURF_TRANSLUCENT); @@ -558,7 +558,7 @@ MakeFaces_r(const mbsp_t *bsp, const int nodenum, std::vector *planes, const int leafnum = -nodenum - 1; const mleaf_t *leaf = &bsp->dleafs[leafnum]; - if ((bsp->loadversion->game == GAME_QUAKE_II) ? (leaf->contents & Q2_CONTENTS_SOLID) : leaf->contents == CONTENTS_SOLID) { + if ((bsp->loadversion->game->id == GAME_QUAKE_II) ? (leaf->contents & Q2_CONTENTS_SOLID) : leaf->contents == CONTENTS_SOLID) { std::vector leaf_windings = Leaf_MakeFaces(bsp, leaf, *planes); for (winding_t *w : leaf_windings) { result->push_back(w); @@ -630,7 +630,7 @@ Embree_TraceInit(const mbsp_t *bsp) const int contents_or_surf_flags = Face_ContentsOrSurfaceFlags(bsp, face); //mxd const gtexinfo_t *texinfo = Face_Texinfo(bsp, face); - const bool is_q2 = bsp->loadversion->game == GAME_QUAKE_II; + const bool is_q2 = bsp->loadversion->game->id == GAME_QUAKE_II; //mxd. Skip NODRAW faces, but not SKY ones (Q2's sky01.wal has both flags set) if(is_q2 && (contents_or_surf_flags & Q2_SURF_NODRAW) && !(contents_or_surf_flags & Q2_SURF_SKY)) diff --git a/qbsp/brush.cc b/qbsp/brush.cc index b2d5609c..0238e75d 100644 --- a/qbsp/brush.cc +++ b/qbsp/brush.cc @@ -439,11 +439,11 @@ CreateBrushFaces(const mapentity_t *src, hullbrush_t *hullbrush, // account for texture offset, from txqbsp-xt if (options.fixRotateObjTexture) { const mtexinfo_t &texinfo = map.mtexinfos.at(mapface->texinfo); - mtexinfo_t texInfoNew; + mtexinfo_t texInfoNew = texinfo; + texInfoNew.outputnum = -1; vec3_t vecs[2]; int k, l; - memcpy(&texInfoNew, &texinfo, sizeof(texInfoNew)); for (k=0; k<2; k++) { for (l=0; l<3; l++) { vecs[k][l] = texinfo.vecs[k][l]; @@ -453,7 +453,7 @@ CreateBrushFaces(const mapentity_t *src, hullbrush_t *hullbrush, texInfoNew.vecs[0][3] += DotProduct( rotate_offset, vecs[0] ); texInfoNew.vecs[1][3] += DotProduct( rotate_offset, vecs[1] ); - mapface->texinfo = FindTexinfo( &texInfoNew, texInfoNew.flags ); + mapface->texinfo = FindTexinfo(texInfoNew, texInfoNew.flags); } VectorCopy(mapface->plane.normal, plane.normal); @@ -487,7 +487,7 @@ CreateBrushFaces(const mapentity_t *src, hullbrush_t *hullbrush, (rotate_offset[0] != 0.0 || rotate_offset[1] != 0.0 || rotate_offset[2] != 0.0) && rottype == rotation_t::hipnotic && (hullnum >= 0) // hullnum < 0 corresponds to -wrbrushes clipping hulls - && options.target_version->game != GAME_HEXEN_II; // never do this in Hexen 2 + && options.target_version->game->id != GAME_HEXEN_II; // never do this in Hexen 2 if (shouldExpand) { vec_t delta; @@ -930,7 +930,7 @@ brush_t *LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, int conte facelist = CreateBrushFaces(src, &hullbrush, rotate_offset, rottype, hullnum); } } - else if (options.target_version->game == GAME_HEXEN_II) + else if (options.target_version->game->id == GAME_HEXEN_II) { if (hullnum == 1) { vec3_t size[2] = { {-16, -16, -32}, {16, 16, 24} }; diff --git a/qbsp/csg4.cc b/qbsp/csg4.cc index 6b71d1a9..39054679 100644 --- a/qbsp/csg4.cc +++ b/qbsp/csg4.cc @@ -53,16 +53,13 @@ MakeSkipTexinfo() // FindMiptex, FindTexinfo not threadsafe std::unique_lock lck { csgfaces_lock }; - int texinfo; - mtexinfo_t mt; + mtexinfo_t mt { }; mt.miptex = FindMiptex("skip"); mt.flags = { 0, TEX_EXFLAG_SKIP }; memset(&mt.vecs, 0, sizeof(mt.vecs)); - - texinfo = FindTexinfo(&mt, mt.flags); - - return texinfo; + + return FindTexinfo(mt, mt.flags); } /* diff --git a/qbsp/map.cc b/qbsp/map.cc index 6e1513ea..77f1c131 100644 --- a/qbsp/map.cc +++ b/qbsp/map.cc @@ -112,7 +112,7 @@ public: static texdef_valve_t TexDef_BSPToValve(const float in_vecs[2][4]); static qvec2f projectToAxisPlane(const vec3_t snapped_normal, qvec3f point); static texdef_quake_ed_noshift_t Reverse_QuakeEd(qmat2x2f M, const qbsp_plane_t *plane, bool preserveX); -static void SetTexinfo_QuakeEd_New(const qbsp_plane_t *plane, const vec_t shift[2], vec_t rotate, const vec_t scale[2], float out_vecs[2][4]); +static void SetTexinfo_QuakeEd_New(const qbsp_plane_t *plane, const vec_t shift[2], vec_t rotate, const vec_t scale[2], stvecs &out_vecs); static void TestExpandBrushes(const mapentity_t *src); const mapface_t &mapbrush_t::face(int i) const { @@ -172,7 +172,7 @@ FindMiptex(const char *name) const char *pathsep; int i; - if (options.target_version->game != GAME_QUAKE_II) { + if (options.target_version->game->id != GAME_QUAKE_II) { /* Ignore leading path in texture names (Q2 map compatibility) */ pathsep = strrchr(name, '/'); if (pathsep) @@ -185,7 +185,7 @@ FindMiptex(const char *name) } /* Handle animating textures carefully */ - if (options.target_version->game != GAME_QUAKE_II) { + if (options.target_version->game->id != GAME_QUAKE_II) { if (name[0] == '+') { AddAnimTex(name); i = map.nummiptex(); @@ -256,33 +256,29 @@ Returns a global texinfo number =============== */ int -FindTexinfo(mtexinfo_t *texinfo, surfflags_t flags) +FindTexinfo(const mtexinfo_t &texinfo, surfflags_t flags) { - /* Set the texture flags */ - texinfo->flags = flags; - texinfo->outputnum = -1; - // NaN's will break mtexinfo_lookup, since they're being used as a std::map key and don't compare properly with <. // They should have been stripped out already in ValidateTextureProjection. for (int i=0;i<2;i++) { for (int j=0;j<4;j++) { - Q_assert(!std::isnan(texinfo->vecs[i][j])); + Q_assert(!std::isnan(texinfo.vecs[i][j])); } } // check for an exact match in the reverse lookup - const auto it = map.mtexinfo_lookup.find(*texinfo); + const auto it = map.mtexinfo_lookup.find(texinfo); if (it != map.mtexinfo_lookup.end()) { return it->second; } /* Allocate a new texinfo at the end of the array */ const int num_texinfo = static_cast(map.mtexinfos.size()); - map.mtexinfos.push_back(*texinfo); - map.mtexinfo_lookup[*texinfo] = num_texinfo; + map.mtexinfos.push_back(texinfo); + map.mtexinfo_lookup[texinfo] = num_texinfo; // catch broken < implementations in mtexinfo_t - assert(map.mtexinfo_lookup.find(*texinfo) != map.mtexinfo_lookup.end()); + assert(map.mtexinfo_lookup.find(texinfo) != map.mtexinfo_lookup.end()); return num_texinfo; } @@ -299,14 +295,14 @@ normalize_color_format(vec3_t color) } } -int -FindTexinfoEnt(mtexinfo_t *texinfo, const mapentity_t *entity) +static int +FindTexinfoEnt(const mtexinfo_t &texinfo, const mapentity_t *entity) { surfflags_t flags {}; - const char *texname = map.miptex.at(texinfo->miptex).name.c_str(); + const char *texname = map.miptex.at(texinfo.miptex).name.c_str(); const int shadow = atoi(ValueForKey(entity, "_shadow")); // These flags are pulled from surf flags in Q2. - if (options.target_version->game != GAME_QUAKE_II) { + if (options.target_version->game->id != GAME_QUAKE_II) { if (IsSkipName(texname)) flags.extended |= TEX_EXFLAG_SKIP; if (IsHintName(texname)) @@ -422,7 +418,7 @@ ParseEpair(parser_t *parser, mapentity_t *entity) // Quake II uses multiple starts for level transitions/backtracking. // TODO: instead, this should check targetnames. There should only be // one info_player_start per targetname in Q2. - if (options.target_version->game != GAME_QUAKE_II && (rgfStartSpots & info_player_start)) + if (options.target_version->game->id != GAME_QUAKE_II && (rgfStartSpots & info_player_start)) Message(msgWarning, warnMultipleStarts); rgfStartSpots |= info_player_start; } else if (!Q_strcasecmp(epair->value, "info_player_deathmatch")) { @@ -498,7 +494,7 @@ ParseExtendedTX(parser_t *parser) return result; } -static qmat4x4f texVecsTo4x4Matrix(const qbsp_plane_t &faceplane, const float in_vecs[2][4]) +static qmat4x4f texVecsTo4x4Matrix(const qbsp_plane_t &faceplane, const stvecs &in_vecs) { // [s] // T * vec = [t] @@ -545,7 +541,7 @@ static float extractRotation(qmat2x2f m) { static qvec2f evalTexDefAtPoint(const texdef_quake_ed_t &texdef, const qbsp_plane_t *faceplane, const qvec3f point) { - float temp[2][4]; + stvecs temp; SetTexinfo_QuakeEd_New(faceplane, texdef.shift, texdef.rotate, texdef.scale, temp); const qmat4x4f worldToTexSpace_res = texVecsTo4x4Matrix(*faceplane, temp); @@ -608,7 +604,7 @@ qvec2f normalizeShift(const texture_t *texture, const qvec2f &in) /// `texture` is optional. If given, the "shift" values can be normalized static texdef_quake_ed_t -TexDef_BSPToQuakeEd(const qbsp_plane_t &faceplane, const texture_t *texture, const float in_vecs[2][4], const vec3_t facepoints[3]) +TexDef_BSPToQuakeEd(const qbsp_plane_t &faceplane, const texture_t *texture, const stvecs &in_vecs, const vec3_t facepoints[3]) { // First get the un-rotated, un-scaled unit texture vecs (based on the face plane). vec3_t snapped_normal; @@ -892,7 +888,7 @@ Reverse_QuakeEd(qmat2x2f M, const qbsp_plane_t *plane, bool preserveX) } static void -SetTexinfo_QuakeEd_New(const qbsp_plane_t *plane, const vec_t shift[2], vec_t rotate, const vec_t scale[2], float out_vecs[2][4]) +SetTexinfo_QuakeEd_New(const qbsp_plane_t *plane, const vec_t shift[2], vec_t rotate, const vec_t scale[2], stvecs &out_vecs) { vec_t sanitized_scale[2]; for (int i=0; i<2; i++) { @@ -1011,7 +1007,7 @@ SetTexinfo_QuakeEd(const qbsp_plane_t *plane, const vec3_t planepts[3], const ve if (false) { // Self-test of SetTexinfo_QuakeEd_New - float check[2][4]; + stvecs check; SetTexinfo_QuakeEd_New(plane, shift, rotate, scale, check); for (int i=0; i<2; i++) { for (int j=0; j<4; j++) { @@ -1174,7 +1170,7 @@ static void ComputeAxisBase( const vec3_t normal_unsanitized, vec3_t texX, vec3_ } static void -SetTexinfo_BrushPrimitives(const vec3_t texMat[2], const vec3_t faceNormal, int texWidth, int texHeight, float vecs[2][4]) +SetTexinfo_BrushPrimitives(const vec3_t texMat[2], const vec3_t faceNormal, int texWidth, int texHeight, stvecs &vecs) { vec3_t texX, texY; @@ -1214,7 +1210,7 @@ SetTexinfo_BrushPrimitives(const vec3_t texMat[2], const vec3_t faceNormal, int vecs[1][3] = texHeight * texMat[1][2]; } -static void BSP_GetSTCoordsForPoint(const vec_t *point, const int texSize[2], const float in_vecs[2][4], vec_t *st_out) +static void BSP_GetSTCoordsForPoint(const vec_t *point, const int texSize[2], const stvecs &in_vecs, vec_t *st_out) { for (int i=0; i<2; i++) { st_out[i] = (point[0] * in_vecs[i][0] @@ -1226,7 +1222,7 @@ static void BSP_GetSTCoordsForPoint(const vec_t *point, const int texSize[2], co // From FaceToBrushPrimitFace in GtkRadiant static texdef_brush_primitives_t -TexDef_BSPToBrushPrimitives(const qbsp_plane_t plane, const int texSize[2], const float in_vecs[2][4]) +TexDef_BSPToBrushPrimitives(const qbsp_plane_t plane, const int texSize[2], const stvecs &in_vecs) { vec3_t texX, texY; ComputeAxisBase( plane.normal, texX, texY ); @@ -1474,6 +1470,7 @@ void mapface_t::set_texvecs(const std::array &vecs) { // start with a copy of the current texinfo structure mtexinfo_t texInfoNew = map.mtexinfos.at(this->texinfo); + texInfoNew.outputnum = -1; // update vecs for (int i=0; i<2; i++) { @@ -1482,7 +1479,7 @@ void mapface_t::set_texvecs(const std::array &vecs) } } - this->texinfo = FindTexinfo( &texInfoNew, texInfoNew.flags ); + this->texinfo = FindTexinfo(texInfoNew, texInfoNew.flags); } bool @@ -1573,7 +1570,7 @@ ParseBrushFace(parser_t *parser, const mapbrush_t *brush, const mapentity_t *ent ValidateTextureProjection(*face, &tx); - face->texinfo = FindTexinfoEnt(&tx, entity); + face->texinfo = FindTexinfoEnt(tx, entity); return face; } @@ -1972,7 +1969,7 @@ LoadMapFile(void) } static texdef_valve_t -TexDef_BSPToValve(const float in_vecs[2][4]) +TexDef_BSPToValve(const stvecs &in_vecs) { texdef_valve_t res; diff --git a/qbsp/qbsp.cc b/qbsp/qbsp.cc index 788dba9c..03d4fe8b 100644 --- a/qbsp/qbsp.cc +++ b/qbsp/qbsp.cc @@ -575,7 +575,7 @@ CreateHulls(void) if (options.target_version == &bspver_hl) CreateSingleHull(3); - else if (options.target_version->game == GAME_HEXEN_II) + else if (options.target_version->game->id == GAME_HEXEN_II) { /*note: h2mp doesn't use hull 2 automatically, however gamecode can explicitly set ent.hull=3 to access it*/ CreateSingleHull(3); CreateSingleHull(4); @@ -622,11 +622,7 @@ EnsureTexturesLoaded() static const char* //mxd GetBaseDirName(const bspversion_t *bspver) { - if (bspver->game == GAME_QUAKE_II) - return "BASEQ2"; - if (bspver->game == GAME_HEXEN_II) - return "DATA1"; - return "ID1"; + return bspver->game->base_dir; } /* @@ -977,7 +973,7 @@ ParseOptions(char *szOptions) } // force specific flags for Q2 - if (options.target_version->game == GAME_QUAKE_II) { + if (options.target_version->game->id == GAME_QUAKE_II) { options.fNoclip = true; } } diff --git a/qbsp/surfaces.cc b/qbsp/surfaces.cc index 2196ea7d..4ddff864 100644 --- a/qbsp/surfaces.cc +++ b/qbsp/surfaces.cc @@ -47,9 +47,9 @@ SubdivideFace(face_t *f, face_t **prevptr) /* special (non-surface cached) faces don't need subdivision */ tex = &map.mtexinfos.at(f->texinfo); - // FIXME: Q2 + if (tex->flags.extended & (TEX_EXFLAG_SKIP | TEX_EXFLAG_HINT) || - options.target_version->surf_needs_subdivision(tex->flags)) + !options.target_version->game->surf_is_subdivided(tex->flags)) return; //subdivision is pretty much pointless other than because of lightmap block limits //one lightmap block will always be added at the end, for smooth interpolation diff --git a/qbsp/writebsp.cc b/qbsp/writebsp.cc index c07fc7d9..b1d6b972 100644 --- a/qbsp/writebsp.cc +++ b/qbsp/writebsp.cc @@ -31,7 +31,7 @@ static void AssertVanillaContentType(int content) { // TODO - if (options.target_version->game == GAME_QUAKE_II) { + if (options.target_version->game->id == GAME_QUAKE_II) { return; } @@ -72,7 +72,7 @@ RemapContentsForExport(int content) content = RemapContentsForExport_(content); // TODO - if (options.target_version->game == GAME_QUAKE_II) { + if (options.target_version->game->id == GAME_QUAKE_II) { switch (content) { case CONTENTS_EMPTY: return 0; @@ -124,7 +124,7 @@ int ExportMapTexinfo(int texinfonum) { mtexinfo_t *src = &map.mtexinfos.at(texinfonum); - if (src->outputnum != PLANENUM_LEAF) + if (src->outputnum != -1) return src->outputnum; // this will be the index of the exported texinfo in the BSP lump @@ -292,7 +292,7 @@ ExportDrawNodes(mapentity_t *entity, node_t *node) if (node->children[i]->planenum == PLANENUM_LEAF) { // In Q2, all leaves must have their own ID even if they share solidity. // (probably for collision purposes? makes sense given they store leafbrushes) - if (options.target_version->game != GAME_QUAKE_II && node->children[i]->contents == CONTENTS_SOLID) + if (options.target_version->game->id != GAME_QUAKE_II && node->children[i]->contents == CONTENTS_SOLID) dnode->children[i] = -1; else { int nextLeafIndex = static_cast(map.exported_leafs.size()); diff --git a/vis/vis.cc b/vis/vis.cc index 7bf5e4fd..9fba659e 100644 --- a/vis/vis.cc +++ b/vis/vis.cc @@ -571,7 +571,7 @@ LeafFlow(int leafnum, mleaf_t *dleaf, const mbsp_t *bsp) /* * flow through all portals, collecting visible bits */ - outbuffer = (bsp->loadversion->game == GAME_QUAKE_II ? uncompressed_q2 : uncompressed) + leafnum * leafbytes; + outbuffer = (bsp->loadversion->game->id == GAME_QUAKE_II ? uncompressed_q2 : uncompressed) + leafnum * leafbytes; leaf = &leafs[leafnum]; for (i = 0; i < leaf->numportals; i++) { p = leaf->portals[i]; @@ -653,7 +653,7 @@ ClusterFlow(int clusternum, leafbits_t *buffer, const mbsp_t *bsp) */ numvis = 0; - if (bsp->loadversion->game == GAME_QUAKE_II) { + if (bsp->loadversion->game->id == GAME_QUAKE_II) { outbuffer = uncompressed_q2 + clusternum * leafbytes; for (i = 0; i < portalleafs; i++) { if (TestLeafBit(buffer, i)) { @@ -688,7 +688,7 @@ ClusterFlow(int clusternum, leafbits_t *buffer, const mbsp_t *bsp) } /* Allocate for worst case where RLE might grow the data (unlikely) */ - if (bsp->loadversion->game == GAME_QUAKE_II) { + if (bsp->loadversion->game->id == GAME_QUAKE_II) { compressed = static_cast(malloc(portalleafs * 2 / 8)); len = CompressRow(outbuffer, (portalleafs + 7) >> 3, compressed); } else { @@ -1061,7 +1061,7 @@ LoadPortals(char *name, mbsp_t *bsp) if (count != 2) Error("%s: unable to parse %s HEADER\n", __func__, PORTALFILE); - if (bsp->loadversion->game == GAME_QUAKE_II) { + if (bsp->loadversion->game->id == GAME_QUAKE_II) { portalleafs_real = bsp->numleafs; logprint("%6d leafs\n", portalleafs_real); logprint("%6d clusters\n", portalleafs); @@ -1101,7 +1101,7 @@ LoadPortals(char *name, mbsp_t *bsp) leafs = static_cast(malloc(portalleafs * sizeof(leaf_t))); memset(leafs, 0, portalleafs * sizeof(leaf_t)); - if (bsp->loadversion->game == GAME_QUAKE_II) { + if (bsp->loadversion->game->id == GAME_QUAKE_II) { originalvismapsize = portalleafs * ((portalleafs + 7) / 8); } else { originalvismapsize = portalleafs_real * ((portalleafs_real + 7) / 8); @@ -1180,7 +1180,7 @@ LoadPortals(char *name, mbsp_t *bsp) } /* Load the cluster expansion map if needed */ - if (bsp->loadversion->game == GAME_QUAKE_II) { + if (bsp->loadversion->game->id == GAME_QUAKE_II) { clustermap = static_cast(malloc(portalleafs_real * sizeof(int))); for (int32_t i = 0; i < bsp->numleafs; i++) { @@ -1333,7 +1333,7 @@ main(int argc, char **argv) StripExtension(statetmpfile); DefaultExtension(statetmpfile, ".vi0"); - if (bsp->loadversion->game != GAME_QUAKE_II) { + if (bsp->loadversion->game->id != GAME_QUAKE_II) { uncompressed = static_cast(calloc(portalleafs, leafbytes_real)); } else { uncompressed_q2 = static_cast(calloc(portalleafs, leafbytes)); @@ -1351,7 +1351,7 @@ main(int argc, char **argv) bsp->visdatasize, originalvismapsize); // no ambient sounds for Q2 - if (bsp->loadversion->game != GAME_QUAKE_II) { + if (bsp->loadversion->game->id != GAME_QUAKE_II) { CalcAmbientSounds(bsp); }