Implement game-agnostic Brush_GetContents
This commit is contained in:
parent
6856789eef
commit
c37ec80667
|
|
@ -33,7 +33,7 @@ struct gamedef_generic_t : public gamedef_t
|
|||
|
||||
bool surf_is_subdivided(const surfflags_t &) const { throw std::bad_cast(); }
|
||||
|
||||
bool surfflags_are_valid(const surfflags_t &flags) const { throw std::bad_cast(); }
|
||||
bool surfflags_are_valid(const surfflags_t &) const { throw std::bad_cast(); }
|
||||
|
||||
contentflags_t cluster_contents(const contentflags_t &, const contentflags_t &) const { throw std::bad_cast(); }
|
||||
|
||||
|
|
@ -51,11 +51,11 @@ struct gamedef_generic_t : public gamedef_t
|
|||
|
||||
contentflags_t create_liquid_contents(const int32_t &, const int32_t &) const { throw std::bad_cast(); }
|
||||
|
||||
bool contents_are_empty(const contentflags_t &contents) const { throw std::bad_cast(); }
|
||||
bool contents_are_empty(const contentflags_t &) const { throw std::bad_cast(); }
|
||||
|
||||
bool contents_are_solid(const contentflags_t &contents) const { throw std::bad_cast(); }
|
||||
bool contents_are_solid(const contentflags_t &) const { throw std::bad_cast(); }
|
||||
|
||||
bool contents_are_sky(const contentflags_t &contents) const { throw std::bad_cast(); }
|
||||
bool contents_are_sky(const contentflags_t &) const { throw std::bad_cast(); }
|
||||
|
||||
bool contents_are_liquid(const contentflags_t &) const { throw std::bad_cast(); }
|
||||
|
||||
|
|
@ -63,9 +63,11 @@ struct gamedef_generic_t : public gamedef_t
|
|||
|
||||
bool portal_can_see_through(const contentflags_t &, const contentflags_t &) const { throw std::bad_cast(); }
|
||||
|
||||
std::string get_contents_display(const contentflags_t &contents) const { throw std::bad_cast(); }
|
||||
std::string get_contents_display(const contentflags_t &) const { throw std::bad_cast(); }
|
||||
|
||||
const std::initializer_list<aabb3d> &get_hull_sizes() const { throw std::bad_cast(); }
|
||||
|
||||
contentflags_t face_get_contents(const std::string &, const surfflags_t &, const contentflags_t &) const { throw std::bad_cast(); };
|
||||
};
|
||||
|
||||
template<gameid_t ID>
|
||||
|
|
@ -245,6 +247,31 @@ struct gamedef_q1_like_t : public gamedef_t
|
|||
|
||||
return hulls;
|
||||
}
|
||||
|
||||
contentflags_t face_get_contents(const std::string &texname, const surfflags_t &flags, const contentflags_t &) const
|
||||
{
|
||||
// check for strong content indicators
|
||||
if (!Q_strcasecmp(texname.data(), "origin")) {
|
||||
return create_extended_contents(CFLAGS_ORIGIN);
|
||||
} else if (!Q_strcasecmp(texname.data(), "hint")) {
|
||||
return create_extended_contents(CFLAGS_HINT);
|
||||
} else if (!Q_strcasecmp(texname.data(), "clip")) {
|
||||
return create_extended_contents(CFLAGS_CLIP);
|
||||
} else if (texname[0] == '*') {
|
||||
if (!Q_strncasecmp(texname.data() + 1, "lava", 4)) {
|
||||
return create_liquid_contents(CONTENTS_LAVA);
|
||||
} else if (!Q_strncasecmp(texname.data() + 1, "slime", 5)) {
|
||||
return create_liquid_contents(CONTENTS_SLIME);
|
||||
} else {
|
||||
return create_liquid_contents(CONTENTS_WATER);
|
||||
}
|
||||
} else if (!Q_strncasecmp(texname.data(), "sky", 3)) {
|
||||
return create_sky_contents();
|
||||
} else {
|
||||
// and anything else is assumed to be a regular solid.
|
||||
return create_solid_contents();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct gamedef_h2_t : public gamedef_q1_like_t<GAME_HEXEN_II>
|
||||
|
|
@ -312,7 +339,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)) |
|
||||
(Q2_CONTENTS_PLAYERCLIP | Q2_CONTENTS_MONSTERCLIP);
|
||||
(Q2_CONTENTS_PLAYERCLIP | Q2_CONTENTS_MONSTERCLIP | Q2_CONTENTS_ORIGIN | Q2_CONTENTS_DETAIL | Q2_CONTENTS_TRANSLUCENT | Q2_CONTENTS_AREAPORTAL);
|
||||
}
|
||||
|
||||
int32_t contents_priority(const contentflags_t &contents) const
|
||||
|
|
@ -457,6 +484,51 @@ struct gamedef_q2_t : public gamedef_t
|
|||
static constexpr std::initializer_list<aabb3d> hulls = {};
|
||||
return hulls;
|
||||
}
|
||||
|
||||
contentflags_t face_get_contents(const std::string &texname, const surfflags_t &flags, const contentflags_t &contents) const
|
||||
{
|
||||
contentflags_t surf_contents = contents;
|
||||
|
||||
if (flags.native & (Q2_SURF_TRANS33 | Q2_SURF_TRANS66)) {
|
||||
surf_contents.native |= Q2_CONTENTS_TRANSLUCENT;
|
||||
|
||||
if (surf_contents.native & Q2_CONTENTS_SOLID) {
|
||||
surf_contents.native = (surf_contents.native & ~Q2_CONTENTS_SOLID) | Q2_CONTENTS_WINDOW;
|
||||
}
|
||||
}
|
||||
|
||||
// add extended flags that we may need
|
||||
if (surf_contents.native & Q2_CONTENTS_DETAIL) {
|
||||
surf_contents.extended |= CFLAGS_DETAIL;
|
||||
}
|
||||
|
||||
if (surf_contents.native & (Q2_CONTENTS_MONSTERCLIP | Q2_CONTENTS_PLAYERCLIP)) {
|
||||
surf_contents.extended |= CFLAGS_CLIP;
|
||||
}
|
||||
|
||||
if (surf_contents.native & Q2_CONTENTS_ORIGIN) {
|
||||
surf_contents.extended |= CFLAGS_ORIGIN;
|
||||
}
|
||||
|
||||
if (surf_contents.native & Q2_CONTENTS_MIST) {
|
||||
surf_contents.extended |= CFLAGS_DETAIL_ILLUSIONARY;
|
||||
}
|
||||
|
||||
if (flags.native & Q2_SURF_HINT) {
|
||||
surf_contents.extended |= CFLAGS_HINT;
|
||||
}
|
||||
|
||||
// FIXME: this is a bit of a hack, but this is because clip
|
||||
// and liquids and stuff are already handled *like* detail by
|
||||
// the compiler.
|
||||
if (surf_contents.extended & CFLAGS_DETAIL) {
|
||||
if (!(surf_contents.native & Q2_CONTENTS_SOLID)) {
|
||||
surf_contents.extended &= ~CFLAGS_DETAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return surf_contents;
|
||||
}
|
||||
};
|
||||
|
||||
// Game definitions, used for the bsp versions below
|
||||
|
|
|
|||
|
|
@ -1762,6 +1762,7 @@ struct gamedef_t
|
|||
virtual bool portal_can_see_through(const contentflags_t &contents0, const contentflags_t &contents1) const = 0;
|
||||
virtual std::string get_contents_display(const contentflags_t &contents) const = 0;
|
||||
virtual const std::initializer_list<aabb3d> &get_hull_sizes() const = 0;
|
||||
virtual contentflags_t face_get_contents(const std::string &texname, const surfflags_t &flags, const contentflags_t &contents) const = 0;
|
||||
};
|
||||
|
||||
// BSP version struct & instances
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ struct mapface_t
|
|||
surfflags_t flags { };
|
||||
|
||||
// Q2 stuff
|
||||
int contents = 0;
|
||||
contentflags_t contents { };
|
||||
int value = 0;
|
||||
|
||||
bool set_planepts(const std::array<qvec3d, 3> &pts);
|
||||
|
|
|
|||
|
|
@ -107,7 +107,6 @@ enum
|
|||
#include <common/mathlib.hh>
|
||||
#include <qbsp/winding.hh>
|
||||
|
||||
|
||||
struct mtexinfo_t
|
||||
{
|
||||
texvecf vecs; /* [s/t][xyz offset] */
|
||||
|
|
|
|||
102
qbsp/brush.cc
102
qbsp/brush.cc
|
|
@ -691,53 +691,30 @@ static void ExpandBrush(hullbrush_t *hullbrush, const aabb3d &hull_size, const f
|
|||
|
||||
static const int DetailFlag = (1 << 27);
|
||||
|
||||
// FIXME: move this to earlier into the map process, like in
|
||||
// texdef parsing or something
|
||||
static bool Brush_IsDetail(const mapbrush_t *mapbrush)
|
||||
{
|
||||
const mapface_t &mapface = mapbrush->face(0);
|
||||
|
||||
if ((mapface.contents & DetailFlag) == DetailFlag) {
|
||||
if ((mapface.contents.native & DetailFlag) == DetailFlag) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static contentflags_t Brush_GetContents_Q1(const mapbrush_t *mapbrush)
|
||||
static contentflags_t Brush_GetContents(const mapbrush_t *mapbrush)
|
||||
{
|
||||
const char *texname;
|
||||
// use the first side as the base contents value
|
||||
contentflags_t base_contents;
|
||||
|
||||
// check for strong content indicators
|
||||
for (int i = 0; i < mapbrush->numfaces; i++) {
|
||||
const mapface_t &mapface = mapbrush->face(i);
|
||||
{
|
||||
const mapface_t &mapface = mapbrush->face(0);
|
||||
const mtexinfo_t &texinfo = map.mtexinfos.at(mapface.texinfo);
|
||||
texname = map.miptexTextureName(texinfo.miptex).c_str();
|
||||
|
||||
if (!Q_strcasecmp(texname, "origin"))
|
||||
return options.target_game->create_extended_contents(CFLAGS_ORIGIN);
|
||||
else if (!Q_strcasecmp(texname, "hint"))
|
||||
return options.target_game->create_extended_contents(CFLAGS_HINT);
|
||||
else if (!Q_strcasecmp(texname, "clip"))
|
||||
return options.target_game->create_extended_contents(CFLAGS_CLIP);
|
||||
else if (texname[0] == '*') {
|
||||
if (!Q_strncasecmp(texname + 1, "lava", 4))
|
||||
return options.target_game->create_liquid_contents(CONTENTS_LAVA);
|
||||
else if (!Q_strncasecmp(texname + 1, "slime", 5))
|
||||
return options.target_game->create_liquid_contents(CONTENTS_SLIME);
|
||||
else
|
||||
return options.target_game->create_liquid_contents(CONTENTS_WATER);
|
||||
} else if (!Q_strncasecmp(texname, "sky", 3))
|
||||
return options.target_game->create_sky_contents();
|
||||
base_contents = options.target_game->face_get_contents(mapface.texname.data(), texinfo.flags, mapface.contents);
|
||||
}
|
||||
|
||||
// and anything else is assumed to be a regular solid.
|
||||
return options.target_game->create_solid_contents();
|
||||
}
|
||||
|
||||
static contentflags_t Brush_GetContents_Q2(const mapbrush_t *mapbrush)
|
||||
{
|
||||
bool is_trans = false;
|
||||
bool is_hint = false;
|
||||
contentflags_t contents = {mapbrush->face(0).contents};
|
||||
|
||||
// validate that all of the sides have valid contents
|
||||
for (int i = 0; i < mapbrush->numfaces; i++) {
|
||||
const mapface_t &mapface = mapbrush->face(i);
|
||||
const mtexinfo_t &texinfo = map.mtexinfos.at(mapface.texinfo);
|
||||
|
|
@ -746,64 +723,20 @@ static contentflags_t Brush_GetContents_Q2(const mapbrush_t *mapbrush)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!is_trans && (texinfo.flags.native & (Q2_SURF_TRANS33 | Q2_SURF_TRANS66))) {
|
||||
is_trans = true;
|
||||
}
|
||||
contentflags_t contents = options.target_game->face_get_contents(mapface.texname.data(), texinfo.flags, mapface.contents);
|
||||
|
||||
if (!is_hint && (texinfo.flags.native & Q2_SURF_HINT)) {
|
||||
is_hint = true;
|
||||
}
|
||||
|
||||
if (mapface.contents != contents.native) {
|
||||
LogPrint("mixed face contents ({} != {} at line {})\n",
|
||||
if (!contents.types_equal(base_contents, options.target_game)) {
|
||||
LogPrint("mixed face contents ({} != {}) at line {}\n",
|
||||
contentflags_t{mapface.contents}.to_string(options.target_game),
|
||||
contents.to_string(options.target_game), mapface.linenum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if any side is translucent, mark the contents
|
||||
// and change solid to window
|
||||
if (is_trans) {
|
||||
contents.native |= Q2_CONTENTS_TRANSLUCENT;
|
||||
if (contents.native & Q2_CONTENTS_SOLID) {
|
||||
contents.native = (contents.native & ~Q2_CONTENTS_SOLID) | Q2_CONTENTS_WINDOW;
|
||||
}
|
||||
}
|
||||
// make sure we found a valid type
|
||||
Q_assert(base_contents.is_valid(options.target_game, false));
|
||||
|
||||
// add extended flags that we may need
|
||||
if (contents.native & Q2_CONTENTS_DETAIL) {
|
||||
contents.extended |= CFLAGS_DETAIL;
|
||||
}
|
||||
|
||||
if (contents.native & (Q2_CONTENTS_MONSTERCLIP | Q2_CONTENTS_PLAYERCLIP)) {
|
||||
contents.extended |= CFLAGS_CLIP;
|
||||
}
|
||||
|
||||
if (contents.native & Q2_CONTENTS_ORIGIN) {
|
||||
contents.extended |= CFLAGS_ORIGIN;
|
||||
}
|
||||
|
||||
if (contents.native & Q2_CONTENTS_MIST) {
|
||||
contents.extended |= CFLAGS_DETAIL_ILLUSIONARY;
|
||||
}
|
||||
|
||||
if (is_hint) {
|
||||
contents.extended |= CFLAGS_HINT;
|
||||
}
|
||||
|
||||
// FIXME: this is a bit of a hack, but this is because clip
|
||||
// and liquids and stuff are already handled *like* detail by
|
||||
// the compiler.
|
||||
if (contents.extended & CFLAGS_DETAIL) {
|
||||
if (!(contents.native & Q2_CONTENTS_SOLID)) {
|
||||
contents.extended &= ~CFLAGS_DETAIL;
|
||||
}
|
||||
}
|
||||
|
||||
Q_assert(contents.is_valid(options.target_game, false));
|
||||
|
||||
return contents;
|
||||
return base_contents;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -979,9 +912,6 @@ void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnu
|
|||
/* Origin brush support */
|
||||
rotation_t rottype = rotation_t::none;
|
||||
|
||||
// TODO: move to game
|
||||
auto Brush_GetContents = (options.target_game->id == GAME_QUAKE_II) ? Brush_GetContents_Q2 : Brush_GetContents_Q1;
|
||||
|
||||
for (int i = 0; i < src->nummapbrushes; i++) {
|
||||
const mapbrush_t *mapbrush = &src->mapbrush(i);
|
||||
const contentflags_t contents = Brush_GetContents(mapbrush);
|
||||
|
|
|
|||
14
qbsp/map.cc
14
qbsp/map.cc
|
|
@ -1370,7 +1370,7 @@ static void ParseTextureDef(parser_t &parser, mapface_t &mapface, const mapbrush
|
|||
|
||||
tx->miptex = FindMiptex(mapface.texname.c_str(), extinfo.info);
|
||||
|
||||
mapface.contents = extinfo.info->contents;
|
||||
mapface.contents = { extinfo.info->contents };
|
||||
tx->flags = mapface.flags = {extinfo.info->flags};
|
||||
tx->value = mapface.value = extinfo.info->value;
|
||||
|
||||
|
|
@ -1546,18 +1546,18 @@ mapbrush_t ParseBrush(parser_t &parser, const mapentity_t *entity)
|
|||
if (options.target_game->id == GAME_QUAKE_II) {
|
||||
// translucent objects are automatically classified as detail
|
||||
if ((face->flags.native & (Q2_SURF_TRANS33 | Q2_SURF_TRANS66)) ||
|
||||
(face->contents & (Q2_CONTENTS_PLAYERCLIP | Q2_CONTENTS_MONSTERCLIP))) {
|
||||
face->contents |= Q2_CONTENTS_DETAIL;
|
||||
(face->contents.native & (Q2_CONTENTS_PLAYERCLIP | Q2_CONTENTS_MONSTERCLIP))) {
|
||||
face->contents.native |= Q2_CONTENTS_DETAIL;
|
||||
}
|
||||
|
||||
if (!(face->contents &
|
||||
if (!(face->contents.native &
|
||||
(((Q2_LAST_VISIBLE_CONTENTS << 1) - 1) | Q2_CONTENTS_PLAYERCLIP | Q2_CONTENTS_MONSTERCLIP))) {
|
||||
face->contents |= Q2_CONTENTS_SOLID;
|
||||
face->contents.native |= Q2_CONTENTS_SOLID;
|
||||
}
|
||||
|
||||
// hints and skips are never detail, and have no content
|
||||
if (face->flags.native & (Q2_SURF_HINT | Q2_SURF_SKIP)) {
|
||||
face->contents = 0;
|
||||
face->contents.native = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1789,7 +1789,7 @@ void ProcessAreaPortal(mapentity_t *entity)
|
|||
FError("func_areaportal can only be a single brush");
|
||||
|
||||
map.brushes[entity->firstmapbrush].contents = Q2_CONTENTS_AREAPORTAL;
|
||||
map.faces[map.brushes[entity->firstmapbrush].firstface].contents = Q2_CONTENTS_AREAPORTAL;
|
||||
map.faces[map.brushes[entity->firstmapbrush].firstface].contents.native = Q2_CONTENTS_AREAPORTAL;
|
||||
entity->areaportalnum = ++map.numareaportals;
|
||||
// set the portal number as "style"
|
||||
SetKeyValue(entity, "style", std::to_string(map.numareaportals).c_str());
|
||||
|
|
|
|||
Loading…
Reference in New Issue