qbsp: fix q2 liquids not mirrored

This commit is contained in:
Eric Wasylishen 2022-06-10 23:29:28 -06:00
parent 121c6384fe
commit 5372c4a568
5 changed files with 42 additions and 18 deletions

View File

@ -86,6 +86,8 @@ struct gamedef_generic_t : public gamedef_t
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_are_solid(const contentflags_t &) const { throw std::bad_cast(); }
bool contents_are_sky(const contentflags_t &) const { throw std::bad_cast(); }
@ -263,6 +265,18 @@ struct gamedef_q1_like_t : public gamedef_t
return contents.native == CONTENTS_EMPTY;
}
bool contents_are_mirrored(const contentflags_t &contents) const
{
if (contents.extended & CFLAGS_BMODEL_MIRROR_INSIDE) {
return true;
}
// If the brush is non-solid, mirror faces for the inside view
return (contents.native == CONTENTS_WATER)
|| (contents.native == CONTENTS_SLIME)
|| (contents.native == CONTENTS_LAVA);
}
bool contents_are_solid(const contentflags_t &contents) const
{
if (contents.extended & CFLAGS_CONTENTS_MASK)
@ -650,6 +664,14 @@ struct gamedef_q2_t : public gamedef_t
return !(contents.native & Q2_ALL_VISIBLE_CONTENTS);
}
bool contents_are_mirrored(const contentflags_t &contents) const
{
// fixme-brushbsp: support some way of opting out of mirrorinside
// If the brush is non-solid, mirror faces for the inside view
return !(contents.native & Q2_CONTENTS_SOLID);
}
bool contents_are_solid(const contentflags_t &contents) const
{
if (contents.extended & CFLAGS_CONTENTS_MASK)
@ -1124,6 +1146,11 @@ bool contentflags_t::is_empty(const gamedef_t *game) const
return game->contents_are_empty(*this);
}
bool contentflags_t::is_mirrored(const gamedef_t *game) const
{
return game->contents_are_mirrored(*this);
}
bool contentflags_t::is_solid(const gamedef_t *game) const
{
return game->contents_are_solid(*this);

View File

@ -605,6 +605,8 @@ struct contentflags_t
bool is_empty(const gamedef_t *game) const;
bool is_mirrored(const gamedef_t *game) const;
// detail solid or structural solid
bool is_any_solid(const gamedef_t *game) const {
return is_solid(game)
@ -1815,6 +1817,7 @@ struct gamedef_t
virtual bool contents_are_detail_fence(const contentflags_t &contents) const = 0;
virtual bool contents_are_detail_illusionary(const contentflags_t &contents) const = 0;
virtual bool contents_are_empty(const contentflags_t &contents) const = 0;
virtual bool contents_are_mirrored(const contentflags_t &contents) 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

@ -54,7 +54,7 @@ bool Light_PointInSolid(const mbsp_t *bsp, const dmodelh2_t *model, const qvec3d
bool Light_PointInWorld(const mbsp_t *bsp, const qvec3d &point);
std::vector<const mface_t *> BSP_FindFacesAtPoint(
const mbsp_t *bsp, const dmodelh2_t *model, const qvec3d &point, const qvec3d &wantedNormal);
const mbsp_t *bsp, const dmodelh2_t *model, const qvec3d &point, const qvec3d &wantedNormal = qvec3d(0,0,0));
/**
* Searches for a face touching a point and facing a certain way.
* Sometimes (water, sky?) there will be 2 overlapping candidates facing opposite ways, the provided normal

View File

@ -654,26 +654,10 @@ static void AddFaceToTree_r(mapentity_t* entity, face_t *face, brush_t *srcbrush
for (face_t *part : faces) {
node->facelist.push_back(part);
// fixme-brushbsp: move to contentflags_t helper
/*
* If the brush is non-solid, mirror faces for the inside view
*/
bool mirror = (srcbrush->contents.extended & CFLAGS_BMODEL_MIRROR_INSIDE);
if (!(srcbrush->contents.is_solid(options.target_game) ||
srcbrush->contents.is_any_detail(options.target_game) ||
srcbrush->contents.is_sky(options.target_game))) {
mirror = true;
}
if (mirror) {
if (srcbrush->contents.is_mirrored(options.target_game)) {
node->facelist.push_back(MirrorFace(part));
}
}
// fixme-brushbsp: need to continue clipping it down the bsp tree,
// this currently leaves bits floating in the void that happen to touch splitting nodes
return;
}

View File

@ -1179,6 +1179,7 @@ TEST_CASE("lavawater", "[testmaps_q2]") {
/**
* Weird mystery issue with a func_wall with broken collision
* (ended up being a PLANE_X/Y/Z plane with negative facing normal, which is illegal - engine assumes they are positive)
*/
TEST_CASE("qbsp_q2_bmodel_collision", "[testmaps_q2]") {
const mbsp_t bsp = LoadTestmapQ2("qbsp_q2_bmodel_collision.map");
@ -1190,6 +1191,15 @@ TEST_CASE("qbsp_q2_bmodel_collision", "[testmaps_q2]") {
CHECK(Q2_CONTENTS_SOLID == BSP_FindLeafAtPoint(&bsp, &bsp.dmodels[1], in_bmodel)->contents);
}
TEST_CASE("q2_liquids", "[testmaps_q2]")
{
const mbsp_t bsp = LoadTestmapQ2("q2_liquids.map");
// water is two sided
const qvec3d water_top {-116, -168, 144};
CHECK(2 == BSP_FindFacesAtPoint(&bsp, &bsp.dmodels[0], water_top).size());
}
TEST_CASE("winding", "[benchmark]") {
ankerl::nanobench::Bench bench;