move clip-own-typeness over to gamedef & contentflags (fixes Q2 edge case with a solid version of a type bordering a translucent version)

This commit is contained in:
Jonathan 2022-06-11 06:01:36 -04:00
parent e61998dd54
commit b33e792458
5 changed files with 41 additions and 21 deletions

View File

@ -85,9 +85,11 @@ struct gamedef_generic_t : public gamedef_t
bool contents_are_detail_illusionary(const contentflags_t &contents) const { throw std::bad_cast(); }
bool contents_are_empty(const contentflags_t &) const { throw std::bad_cast(); }
bool contents_are_mirrored(const contentflags_t &) const { throw std::bad_cast(); }
bool contents_clip_same_type(const contentflags_t &, const contentflags_t &) const { throw std::bad_cast(); }
bool contents_are_solid(const contentflags_t &) const { throw std::bad_cast(); }
bool contents_are_sky(const contentflags_t &) const { throw std::bad_cast(); }
@ -262,7 +264,7 @@ struct gamedef_q1_like_t : public gamedef_t
// if we have mirrorinside set, go ahead
if (contents.mirror_inside.has_value()) {
return contents.mirror_inside.value();
}
}
// If the brush is non-solid, mirror faces for the inside view
return (contents.native == CONTENTS_WATER)
@ -270,6 +272,11 @@ struct gamedef_q1_like_t : public gamedef_t
|| (contents.native == CONTENTS_LAVA);
}
bool contents_clip_same_type(const contentflags_t &self, const contentflags_t &other) const
{
return self == other && self.clips_same_type.value_or(true);
}
bool contents_are_empty(const contentflags_t &contents) const
{
if (contents.extended & CFLAGS_CONTENTS_MASK)
@ -665,6 +672,11 @@ struct gamedef_q2_t : public gamedef_t
// contents to default to not mirroring the insides.
return !(contents.native & (Q2_CONTENTS_SOLID | Q2_CONTENTS_AUX));
}
bool contents_clip_same_type(const contentflags_t &self, const contentflags_t &other) const
{
return (self.native & Q2_ALL_VISIBLE_CONTENTS) == (other.native & Q2_ALL_VISIBLE_CONTENTS) && self.clips_same_type.value_or(true);
}
bool contents_are_empty(const contentflags_t &contents) const
{
@ -1152,6 +1164,11 @@ bool contentflags_t::is_mirrored(const gamedef_t *game) const
return game->contents_are_mirrored(*this);
}
bool contentflags_t::will_clip_same_type(const gamedef_t *game, const contentflags_t &other) const
{
return game->contents_clip_same_type(*this, other);
}
bool contentflags_t::is_empty(const gamedef_t *game) const
{
return game->contents_are_empty(*this);
@ -1182,11 +1199,10 @@ std::string contentflags_t::to_string(const gamedef_t *game) const
std::string s = game->get_contents_display(*this);
// FIXME: how do we conditionally display this only when it matters (when it's not default basically)?
s += fmt::format("|MIRROR_INSIDE[{}]", mirror_inside.has_value() ? (mirror_inside.value() ? "true" : "false") : "nullopt");
s += fmt::format("|MIRROR_INSIDE[{}]", mirror_inside.has_value() ? (clips_same_type.value() ? "true" : "false") : "nullopt");
s += fmt::format("|CLIPS_SAME_TYPE[{}]", clips_same_type.has_value() ? (mirror_inside.value() ? "true" : "false") : "nullopt");
if (extended & CFLAGS_NO_CLIPPING_SAME_TYPE) {
s += "|NO_CLIPPING_SAME_TYPE";
}
if (extended & CFLAGS_HINT) {
s += "|HINT";
}

View File

@ -563,7 +563,6 @@ enum q2_contents_t : int32_t
// Special contents flags for the compiler only
enum extended_cflags_t : uint16_t
{
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),
@ -590,9 +589,13 @@ struct contentflags_t
uint16_t extended;
// the value set directly from `_mirrorinside` on the brush, if available.
// don't use this directly, use `is_mirror_inside` to allow the game to decide.
// don't check this directly, use `is_mirror_inside` to allow the game to decide.
std::optional<bool> mirror_inside = std::nullopt;
// Don't clip the same content type. mostly intended for CONTENTS_DETAIL_ILLUSIONARY.
// don't check this directly, use `will_clip_same_type` to allow the game to decide.
std::optional<bool> clips_same_type = std::nullopt;
constexpr bool operator==(const contentflags_t &other) const
{
return native == other.native && extended == other.extended;
@ -605,9 +608,13 @@ struct contentflags_t
bool is_detail_solid(const gamedef_t *game) const;
bool is_detail_fence(const gamedef_t *game) const;
bool is_detail_illusionary(const gamedef_t *game) const;
bool is_mirrored(const gamedef_t *game) const;
contentflags_t &set_mirrored(const std::optional<bool> &mirror_inside_value) { mirror_inside = mirror_inside_value; return *this; }
inline bool will_clip_same_type(const gamedef_t *game) const { return will_clip_same_type(game, *this); }
bool will_clip_same_type(const gamedef_t *game, const contentflags_t &other) const;
contentflags_t &set_clips_same_type(const std::optional<bool> &clips_same_type_value) { clips_same_type = clips_same_type_value; return *this; }
bool is_empty(const gamedef_t *game) const;
@ -629,8 +636,6 @@ struct contentflags_t
constexpr bool is_origin() const { return extended & CFLAGS_ORIGIN; }
constexpr bool clips_same_type() const { return !(extended & CFLAGS_NO_CLIPPING_SAME_TYPE); }
bool is_fence(const gamedef_t *game) const {
return is_detail_fence(game) || is_detail_illusionary(game);
}
@ -1822,6 +1827,7 @@ struct gamedef_t
virtual bool contents_are_detail_illusionary(const contentflags_t &contents) const = 0;
virtual bool contents_are_mirrored(const contentflags_t &contents) const = 0;
virtual bool contents_are_empty(const contentflags_t &contents) const = 0;
virtual bool contents_clip_same_type(const contentflags_t &self, const contentflags_t &other) const = 0;
virtual bool contents_are_solid(const contentflags_t &contents) const = 0;
virtual bool contents_are_sky(const contentflags_t &contents) const = 0;
virtual bool contents_are_liquid(const contentflags_t &contents) const = 0;

View File

@ -862,7 +862,8 @@ static void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int
const std::optional<bool> mirrorinside = mirrorinside_set ? decltype(mirrorinside)(atoi(ValueForKey(src, "_mirrorinside")) ? true : false) : std::nullopt;
/* _noclipfaces */
const bool noclipfaces = !!atoi(ValueForKey(src, "_noclipfaces"));
const bool noclipfaces_set = *ValueForKey(src, "_mirrorinside");
const std::optional<bool> noclipfaces = mirrorinside_set ? decltype(noclipfaces)(atoi(ValueForKey(src, "_noclipfaces")) ? false : true) : std::nullopt;
const bool func_illusionary_visblocker = (0 == Q_strcasecmp(classname, "func_illusionary_visblocker"));
@ -969,10 +970,7 @@ static void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int
// apply extended flags
contents.set_mirrored(mirrorinside);
if (noclipfaces) {
contents.extended |= CFLAGS_NO_CLIPPING_SAME_TYPE;
}
contents.set_clips_same_type(noclipfaces);
if (func_illusionary_visblocker) {
contents.extended |= CFLAGS_ILLUSIONARY_VISBLOCKER;
}

View File

@ -262,7 +262,7 @@ static bool ShouldClipbrushEatBrush(const brush_t &brush, const brush_t &clipbru
}
if (clipbrush.contents.types_equal(brush.contents, options.target_game)) {
return clipbrush.contents.clips_same_type();
return clipbrush.contents.will_clip_same_type(options.target_game);
}
return false;
@ -426,7 +426,7 @@ Returns a >= b as far as brush clipping
bool BrushGE(const brush_t& a, const brush_t& b)
{
// same contents clip each other
if (a.contents == b.contents && a.contents.clips_same_type()) {
if (a.contents == b.contents && a.contents.will_clip_same_type(options.target_game)) {
// map file order
return a.file_order > b.file_order;
}

View File

@ -574,11 +574,11 @@ static std::list<face_t *> ClipFacesToTree_r(node_t *node, const brush_t *srcbru
return {};
}
// translucent contents also clip faces
if (node->contents == srcbrush->contents
&& srcbrush->contents.clips_same_type()) {
// see what the game thinks about the clip
if (srcbrush->contents.will_clip_same_type(options.target_game, node->contents)) {
return {};
}
// other content types let the faces thorugh
return faces;
}