diff --git a/common/bspfile.cc b/common/bspfile.cc index 94589140..0b69eb8a 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -70,6 +70,12 @@ struct gamedef_generic_t : public gamedef_t contentflags_t create_liquid_contents(const int32_t &, const int32_t &) const { throw std::bad_cast(); } + contentflags_t create_detail_illusionary_contents(const contentflags_t &original) const { throw std::bad_cast(); } + + contentflags_t create_detail_fence_contents(const contentflags_t &original) const { throw std::bad_cast(); } + + contentflags_t create_detail_solid_contents(const contentflags_t &original) const { throw std::bad_cast(); } + bool contents_are_any_detail(const contentflags_t &) const { throw std::bad_cast(); } bool contents_are_detail_solid(const contentflags_t &contents) const { throw std::bad_cast(); } @@ -213,6 +219,19 @@ struct gamedef_q1_like_t : public gamedef_t return {liquid_type, cflags}; } + contentflags_t create_detail_illusionary_contents(const contentflags_t &original) const { + // ignore the original contents in Q1 + return {0, CFLAGS_DETAIL_ILLUSIONARY}; + } + + contentflags_t create_detail_fence_contents(const contentflags_t &original) const { + return {0, CFLAGS_DETAIL_FENCE}; + } + + contentflags_t create_detail_solid_contents(const contentflags_t &original) const { + return {0, CFLAGS_DETAIL}; + } + bool contents_are_any_detail(const contentflags_t &contents) const { // in Q1, there are only CFLAGS_DETAIL, CFLAGS_DETAIL_ILLUSIONARY, or CFLAGS_DETAIL_FENCE @@ -555,6 +574,26 @@ struct gamedef_q2_t : public gamedef_t } } + contentflags_t create_detail_illusionary_contents(const contentflags_t &original) const { + contentflags_t result = original; + result.native &= ~Q2_CONTENTS_SOLID; + result.native |= Q2_CONTENTS_MIST | Q2_CONTENTS_DETAIL; + return result; + } + + contentflags_t create_detail_fence_contents(const contentflags_t &original) const { + contentflags_t result = original; + result.native &= ~Q2_CONTENTS_SOLID; + result.native |= (Q2_CONTENTS_WINDOW | Q2_CONTENTS_TRANSLUCENT | Q2_CONTENTS_DETAIL); + return result; + } + + contentflags_t create_detail_solid_contents(const contentflags_t &original) const { + contentflags_t result = original; + result.native |= (Q2_CONTENTS_SOLID | Q2_CONTENTS_DETAIL); + return result; + } + bool contents_are_any_detail(const contentflags_t &contents) const { return ((contents.native & Q2_CONTENTS_DETAIL) != 0); @@ -562,20 +601,32 @@ struct gamedef_q2_t : public gamedef_t bool contents_are_detail_solid(const contentflags_t &contents) const { - // fixme-brushbsp: check native flag - return ((contents.extended & CFLAGS_DETAIL) != 0); + int32_t test = (Q2_CONTENTS_DETAIL|Q2_CONTENTS_SOLID); + + return ((contents.native & test) == test); } bool contents_are_detail_fence(const contentflags_t &contents) const { - // fixme-brushbsp: check native flag - return ((contents.extended & CFLAGS_DETAIL_FENCE) != 0); + if (contents.native & Q2_CONTENTS_SOLID) { + return false; + } + + int32_t test = (Q2_CONTENTS_DETAIL|Q2_CONTENTS_WINDOW); + return ((contents.native & test) == test); } bool contents_are_detail_illusionary(const contentflags_t &contents) const { - // fixme-brushbsp: check native flag - return ((contents.extended & CFLAGS_DETAIL_ILLUSIONARY) != 0); + if (contents.native & Q2_CONTENTS_SOLID) { + return false; + } + + int32_t mist1_type = (Q2_CONTENTS_DETAIL|Q2_CONTENTS_MIST); + int32_t mist2_type = (Q2_CONTENTS_DETAIL|Q2_CONTENTS_AUX); + + return ((contents.native & mist1_type) == mist1_type) + || ((contents.native & mist2_type) == mist2_type); } bool contents_are_empty(const contentflags_t &contents) const @@ -740,6 +791,7 @@ struct gamedef_q2_t : public gamedef_t // 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. + // fixme-brushbsp: remove this if (surf_contents.extended & CFLAGS_DETAIL) { if (!(surf_contents.native & Q2_CONTENTS_SOLID)) { surf_contents.extended &= ~CFLAGS_DETAIL; diff --git a/include/common/bspfile.hh b/include/common/bspfile.hh index 281cb3df..b9c428dc 100644 --- a/include/common/bspfile.hh +++ b/include/common/bspfile.hh @@ -626,7 +626,9 @@ struct contentflags_t constexpr bool clips_same_type() const { return !(extended & CFLAGS_NO_CLIPPING_SAME_TYPE); } - constexpr bool is_fence() const { return (extended & (CFLAGS_DETAIL_FENCE | CFLAGS_DETAIL_ILLUSIONARY)) != 0; } + bool is_fence(const gamedef_t *game) const { + return is_detail_fence(game) || is_detail_illusionary(game); + } // check if this content's `type` - which is distinct from various // flags that turn things on/off - match. Exactly what the native @@ -1796,6 +1798,9 @@ struct gamedef_t virtual contentflags_t create_solid_contents(const int32_t &cflags = 0) const = 0; virtual contentflags_t create_sky_contents(const int32_t &cflags = 0) const = 0; virtual contentflags_t create_liquid_contents(const int32_t &liquid_type, const int32_t &cflags = 0) const = 0; + 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_any_detail(const contentflags_t &contents) const = 0; virtual bool contents_are_detail_solid(const contentflags_t &contents) const = 0; virtual bool contents_are_detail_fence(const contentflags_t &contents) const = 0; diff --git a/qbsp/brush.cc b/qbsp/brush.cc index 404e661d..7b0e05e1 100644 --- a/qbsp/brush.cc +++ b/qbsp/brush.cc @@ -896,11 +896,11 @@ static void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int /* turn solid brushes into detail, if we're in hull0 */ if (hullnum <= 0 && contents.is_solid(options.target_game)) { if (detail_illusionary) { - contents = {contents.native, CFLAGS_DETAIL_ILLUSIONARY}; + contents = options.target_game->create_detail_illusionary_contents(contents); } else if (detail_fence) { - contents = {contents.native, CFLAGS_DETAIL_FENCE}; + contents = options.target_game->create_detail_fence_contents(contents); } else if (detail) { - contents = {contents.native, CFLAGS_DETAIL}; + contents = options.target_game->create_detail_solid_contents(contents); } } @@ -950,7 +950,7 @@ static void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int contents type. */ if (hullnum <= 0 && mirrorinside) { - contents = {contents.native, CFLAGS_DETAIL_FENCE}; + contents = options.target_game->create_detail_fence_contents(contents); } } diff --git a/qbsp/csg4.cc b/qbsp/csg4.cc index 6154d34b..adae786e 100644 --- a/qbsp/csg4.cc +++ b/qbsp/csg4.cc @@ -300,7 +300,7 @@ static bool ShouldClipbrushEatBrush(const brush_t &brush, const brush_t &clipbru || (brush.contents.is_liquid(options.target_game) && clipbrush.contents.is_detail_illusionary(options.target_game)) - || (brush.contents.is_fence() && clipbrush.contents.is_liquid(options.target_game))) { + || (brush.contents.is_fence(options.target_game) && clipbrush.contents.is_liquid(options.target_game))) { return false; } diff --git a/qbsp/writebsp.cc b/qbsp/writebsp.cc index b777ed12..2690373c 100644 --- a/qbsp/writebsp.cc +++ b/qbsp/writebsp.cc @@ -36,13 +36,14 @@ static contentflags_t RemapContentsForExport(const contentflags_t &content) { if (content.is_detail_fence(options.target_game)) { /* - * A bit of a hack for Q2, to ensure that structural faces which are completely covered by CFLAGS_DETAIL_FENCE + * A bit of a hack for Q2, to ensure that structural faces which are completely covered by detail fence * still render. * * If we export the detail fence leaf as CONTENTS_SOLID, Q2 engines will refuse to render the covered sturctural * face because of a short-circuit in GL_DrawLeaf. */ if (options.target_game->id == GAME_QUAKE_II) { + // fixme-brushbsp: can remove this once we use WINDOW natively for detail_fence return {Q2_CONTENTS_WINDOW, 0}; } /*