From 13bf99a7f339b43990fc8473df5d7e64c7cdc90d Mon Sep 17 00:00:00 2001 From: Jonathan Date: Sat, 11 Jun 2022 09:19:51 -0400 Subject: [PATCH] fix test cases (implement equals(game) properly, and `is_empty` is false depending on get_content_type for Q2 now) remove unnecessary condition from Q2 contents_are_empty since areaportals are already considered a valid non-empty type via get_content_type --- common/bspfile.cc | 40 +++++++++++++++++++++++++++------------ include/common/bspfile.hh | 8 ++------ include/common/qvec.hh | 4 ---- qbsp/brush.cc | 2 +- qbsp/merge.cc | 3 ++- 5 files changed, 33 insertions(+), 24 deletions(-) diff --git a/common/bspfile.cc b/common/bspfile.cc index ed1997c0..2b0f1efb 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -72,6 +72,8 @@ struct gamedef_generic_t : public gamedef_t contentflags_t create_detail_solid_contents(const contentflags_t &original) const { throw std::bad_cast(); } + bool contents_are_type_equal(const contentflags_t &self, const contentflags_t &other) const { throw std::bad_cast(); } + bool contents_are_equal(const contentflags_t &self, const contentflags_t &other) const { throw std::bad_cast(); } bool contents_are_any_detail(const contentflags_t &) const { throw std::bad_cast(); } @@ -130,7 +132,7 @@ struct q1_contentflags_data constexpr bool operator==(const q1_contentflags_data &other) const { return origin == other.origin && clip == other.clip; } constexpr bool operator!=(const q1_contentflags_data &other) const { return !(*this == other); } - constexpr explicit operator bool() const { return origin && clip; } + constexpr explicit operator bool() const { return origin || clip; } }; template @@ -156,7 +158,7 @@ struct gamedef_q1_like_t : public gamedef_t contentflags_t cluster_contents(const contentflags_t &contents0, const contentflags_t &contents1) const { - if (contents0 == contents1) + if (contents0.equals(this, contents1)) return contents0; /* @@ -251,7 +253,7 @@ struct gamedef_q1_like_t : public gamedef_t return {0, CFLAGS_DETAIL}; } - bool contents_are_equal(const contentflags_t &self, const contentflags_t &other) const + bool contents_are_type_equal(const contentflags_t &self, const contentflags_t &other) const { if (self.game_data.has_value() != other.game_data.has_value()) { return false; @@ -268,6 +270,11 @@ struct gamedef_q1_like_t : public gamedef_t self.native == other.native; } + bool contents_are_equal(const contentflags_t &self, const contentflags_t &other) const + { + return contents_are_type_equal(self, other); + } + bool contents_are_any_detail(const contentflags_t &contents) const { // in Q1, there are only CFLAGS_DETAIL, CFLAGS_DETAIL_ILLUSIONARY, or CFLAGS_DETAIL_FENCE @@ -314,7 +321,7 @@ struct gamedef_q1_like_t : public gamedef_t bool contents_clip_same_type(const contentflags_t &self, const contentflags_t &other) const { - return self == other && self.clips_same_type.value_or(true); + return self.equals(this, other) && self.clips_same_type.value_or(true); } bool contents_are_empty(const contentflags_t &contents) const @@ -377,7 +384,7 @@ struct gamedef_q1_like_t : public gamedef_t bool portal_can_see_through(const contentflags_t &contents0, const contentflags_t &contents1) const { /* If contents values are the same and not solid, can see through */ - return !(contents0.is_solid(this) || contents1.is_solid(this)) && contents0 == contents1; + return !(contents0.is_solid(this) || contents1.is_solid(this)) && contents0.equals(this, contents1); } bool contents_seals_map(const contentflags_t &contents) const override @@ -672,12 +679,18 @@ struct gamedef_q2_t : public gamedef_t return result; } - bool contents_are_equal(const contentflags_t &self, const contentflags_t &other) const + bool contents_are_type_equal(const contentflags_t &self, const contentflags_t &other) const { return (self.extended & CFLAGS_CONTENTS_MASK) == (other.extended & CFLAGS_CONTENTS_MASK) && get_content_type(self) == get_content_type(other); } + bool contents_are_equal(const contentflags_t &self, const contentflags_t &other) const + { + return (self.extended & CFLAGS_CONTENTS_MASK) == (other.extended & CFLAGS_CONTENTS_MASK) && + self.native == other.native; + } + bool contents_are_any_detail(const contentflags_t &contents) const { return ((contents.native & Q2_CONTENTS_DETAIL) != 0); @@ -746,11 +759,7 @@ struct gamedef_q2_t : public gamedef_t if (contents.extended & CFLAGS_CONTENTS_MASK) return false; - if (contents.native & Q2_CONTENTS_AREAPORTAL) - return false; // HACK: needs to return false in order for LinkConvexFaces to assign Q2_CONTENTS_AREAPORTAL - // to the leaf - - return !(contents.native & Q2_ALL_VISIBLE_CONTENTS); + return !get_content_type(contents); } bool contents_are_solid(const contentflags_t &contents) const @@ -1179,9 +1188,16 @@ bool surfflags_t::is_valid(const gamedef_t *game) const return game->surfflags_are_valid(*this); } +bool contentflags_t::equals(const gamedef_t *game, const contentflags_t &other) const +{ + return game->contents_are_equal(*this, other) && + mirror_inside == other.mirror_inside && + clips_same_type == other.clips_same_type; +} + bool contentflags_t::types_equal(const contentflags_t &other, const gamedef_t *game) const { - return game->contents_are_equal(*this, other); + return game->contents_are_type_equal(*this, other); } int32_t contentflags_t::priority(const gamedef_t *game) const diff --git a/include/common/bspfile.hh b/include/common/bspfile.hh index f487ae7f..d14b6ace 100644 --- a/include/common/bspfile.hh +++ b/include/common/bspfile.hh @@ -598,12 +598,7 @@ struct contentflags_t // don't check this directly, use `will_clip_same_type` to allow the game to decide. std::optional clips_same_type = std::nullopt; - constexpr bool operator==(const contentflags_t &other) const - { - return native == other.native && extended == other.extended; - } - - constexpr bool operator!=(const contentflags_t &other) const { return !(*this == other); } + bool equals(const gamedef_t *game, const contentflags_t &other) const; // is any kind of detail? (solid, liquid, etc.) bool is_any_detail(const gamedef_t *game) const; @@ -1817,6 +1812,7 @@ struct gamedef_t virtual contentflags_t create_detail_illusionary_contents(const contentflags_t &original) const = 0; virtual contentflags_t create_detail_fence_contents(const contentflags_t &original) const = 0; virtual contentflags_t create_detail_solid_contents(const contentflags_t &original) const = 0; + virtual bool contents_are_type_equal(const contentflags_t &self, const contentflags_t &other) const = 0; virtual bool contents_are_equal(const contentflags_t &self, const contentflags_t &other) const = 0; virtual bool contents_are_any_detail(const contentflags_t &contents) const = 0; virtual bool contents_are_detail_solid(const contentflags_t &contents) const = 0; diff --git a/include/common/qvec.hh b/include/common/qvec.hh index c0abd81e..1ed37b6c 100644 --- a/include/common/qvec.hh +++ b/include/common/qvec.hh @@ -1134,10 +1134,6 @@ struct twosided // swap the front and back values constexpr void swap() { std::swap(front, back); } - - // equality checks - constexpr bool operator==(const twosided &other) const { return front == other.front && back == other.back; } - constexpr bool operator!=(const twosided &other) const { return !(*this == other); } }; namespace qv { diff --git a/qbsp/brush.cc b/qbsp/brush.cc index 5b1c6874..aadfe8ca 100644 --- a/qbsp/brush.cc +++ b/qbsp/brush.cc @@ -940,7 +940,7 @@ static void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int * include them in the model bounds so collision detection works * correctly. */ - if (contents.is_clip(options.target_game) && hullnum != HULL_COLLISION) { + if (hullnum != HULL_COLLISION && contents.is_clip(options.target_game)) { if (hullnum == 0) { std::optional brush = LoadBrush(src, mapbrush, contents, rotate_offset, rottype, hullnum); diff --git a/qbsp/merge.cc b/qbsp/merge.cc index 2a5d4181..c045d37e 100644 --- a/qbsp/merge.cc +++ b/qbsp/merge.cc @@ -69,7 +69,8 @@ static face_t *TryMerge(face_t *f1, face_t *f2) bool keep1, keep2; if (!f1->w.size() || !f2->w.size() || f1->planeside != f2->planeside || f1->texinfo != f2->texinfo || - f1->contents != f2->contents || f1->lmshift != f2->lmshift) + !f1->contents[0].equals(options.target_game, f2->contents[0]) || !f1->contents[1].equals(options.target_game, f2->contents[1]) || + f1->lmshift[0] != f2->lmshift[0] || f1->lmshift[1] != f2->lmshift[1]) return NULL; // find a common edge