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:
parent
e61998dd54
commit
b33e792458
|
|
@ -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";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue