From a309e8467b05a5c9893a87ec2e78f5fead99d323 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Mon, 13 Jun 2022 23:55:16 -0600 Subject: [PATCH] testmaps: add qbsp_q1_sealing.map --- common/bsputils.cc | 26 +++++++ include/common/bsputils.hh | 1 + qbsp/test_qbsp.cc | 36 ++++++++++ testmaps/qbsp_q1_sealing.map | 129 +++++++++++++++++++++++++++++++++++ 4 files changed, 192 insertions(+) create mode 100644 testmaps/qbsp_q1_sealing.map diff --git a/common/bsputils.cc b/common/bsputils.cc index 02502d33..bf85663f 100644 --- a/common/bsputils.cc +++ b/common/bsputils.cc @@ -448,6 +448,32 @@ const mleaf_t* BSP_FindLeafAtPoint(const mbsp_t* bsp, const dmodelh2_t* model, c return BSP_FindLeafAtPoint_r(bsp, model->headnode[0], point); } +static int BSP_FindClipnodeAtPoint_r( + const mbsp_t *bsp, const int clipnodenum, const qvec3d &point) +{ + if (clipnodenum < 0) { + // actually contents + return clipnodenum; + } + + const auto *node = &bsp->dclipnodes.at(clipnodenum); + const vec_t dist = bsp->dplanes[node->planenum].distance_to_fast(point); + + if (dist >= 0) { + return BSP_FindClipnodeAtPoint_r(bsp, node->children[0], point); + } else { + return BSP_FindClipnodeAtPoint_r(bsp, node->children[1], point); + } +} + +int BSP_FindContentsAtPoint(const mbsp_t *bsp, int hull, const dmodelh2_t *model, const qvec3d &point) +{ + if (hull == 0) { + return BSP_FindLeafAtPoint_r(bsp, model->headnode[0], point)->contents; + } + return BSP_FindClipnodeAtPoint_r(bsp, model->headnode.at(hull), point); +} + std::vector Leaf_Markfaces(const mbsp_t* bsp, const mleaf_t* leaf) { std::vector result; diff --git a/include/common/bsputils.hh b/include/common/bsputils.hh index 9377fe9d..45c10239 100644 --- a/include/common/bsputils.hh +++ b/include/common/bsputils.hh @@ -70,6 +70,7 @@ const bsp2_dnode_t *BSP_FindNodeAtPoint( const mbsp_t *bsp, const dmodelh2_t *model, const qvec3d &point, const qvec3d &wanted_normal); const mleaf_t *BSP_FindLeafAtPoint(const mbsp_t *bsp, const dmodelh2_t *model, const qvec3d &point); +int BSP_FindContentsAtPoint(const mbsp_t *bsp, int hull, const dmodelh2_t *model, const qvec3d &point); std::vector Leaf_Markfaces(const mbsp_t *bsp, const mleaf_t *leaf); std::vector Leaf_Brushes(const mbsp_t *bsp, const mleaf_t *leaf); diff --git a/qbsp/test_qbsp.cc b/qbsp/test_qbsp.cc index c81e606a..bbc24396 100644 --- a/qbsp/test_qbsp.cc +++ b/qbsp/test_qbsp.cc @@ -1278,6 +1278,42 @@ TEST_CASE("qbsp_q2_detail_seals", "[testmaps_q2][!mayfail]") { CHECK(Q2_CONTENTS_SOLID == BSP_FindLeafAtPoint(&bsp, &bsp.dmodels[0], in_void)->contents); } +/** + * Q1 sealing test: + * - hull0 can use Q2 method (fill inside) + * - hull1+ can't, because it would cause areas containing no entities but connected by a thin gap to the + * rest of the world to get sealed off as solid. + **/ +TEST_CASE("qbsp_q1_sealing", "[testmaps_q1][!mayfail]") { + const mbsp_t bsp = LoadTestmap("qbsp_q1_sealing.map"); + + CHECK(GAME_QUAKE == bsp.loadversion->game->id); + + const qvec3d in_start_room {-192, 144, 104}; + const qvec3d in_emptyroom {-168, 544, 104}; + const qvec3d in_void {-16, -800, 56}; + const qvec3d connected_by_thin_gap {72, 136, 104}; + + // check leaf contents in hull 0 + CHECK(CONTENTS_EMPTY == BSP_FindLeafAtPoint(&bsp, &bsp.dmodels[0], in_start_room)->contents); + CHECK(CONTENTS_SOLID == BSP_FindLeafAtPoint(&bsp, &bsp.dmodels[0], in_emptyroom)->contents); // can get sealed, since there are no entities + CHECK(CONTENTS_SOLID == BSP_FindLeafAtPoint(&bsp, &bsp.dmodels[0], in_void)->contents); + CHECK(CONTENTS_EMPTY == BSP_FindLeafAtPoint(&bsp, &bsp.dmodels[0], connected_by_thin_gap)->contents); + + // check leaf contents in hull 1 + CHECK(CONTENTS_EMPTY == BSP_FindContentsAtPoint(&bsp, 1, &bsp.dmodels[0], in_start_room)); + CHECK(CONTENTS_EMPTY == BSP_FindContentsAtPoint(&bsp, 1, &bsp.dmodels[0], in_emptyroom)); + CHECK(CONTENTS_SOLID == BSP_FindContentsAtPoint(&bsp, 1, &bsp.dmodels[0], in_void)); + CHECK(CONTENTS_EMPTY == BSP_FindContentsAtPoint(&bsp, 1, &bsp.dmodels[0], connected_by_thin_gap)); + + // check leaf contents in hull 2 + CHECK(CONTENTS_EMPTY == BSP_FindContentsAtPoint(&bsp, 2, &bsp.dmodels[0], in_start_room)); + CHECK(CONTENTS_EMPTY == BSP_FindContentsAtPoint(&bsp, 2, &bsp.dmodels[0], in_emptyroom)); + CHECK(CONTENTS_SOLID == BSP_FindContentsAtPoint(&bsp, 2, &bsp.dmodels[0], in_void)); + CHECK(CONTENTS_EMPTY == BSP_FindContentsAtPoint(&bsp, 2, &bsp.dmodels[0], connected_by_thin_gap)); +} + + TEST_CASE("winding", "[benchmark]") { ankerl::nanobench::Bench bench; diff --git a/testmaps/qbsp_q1_sealing.map b/testmaps/qbsp_q1_sealing.map new file mode 100644 index 00000000..d0b82854 --- /dev/null +++ b/testmaps/qbsp_q1_sealing.map @@ -0,0 +1,129 @@ +// Game: Quake +// Format: Standard +// entity 0 +{ +"classname" "worldspawn" +"wad" "deprecated/free_wad.wad" +// brush 0 +{ +( -64 256 192 ) ( -64 32 192 ) ( -64 256 16 ) bolt9 0 -28 0 1 1 +( -48 32 16 ) ( -64 32 16 ) ( -48 32 192 ) bolt9 0 0 0 1 1 +( -48 256 36 ) ( -64 256 36 ) ( -48 32 36 ) bolt9 0 0 0 1 1 +( -48 32 192 ) ( -64 32 192 ) ( -48 256 192 ) bolt9 0 0 0 1 1 +( -48 256 192 ) ( -64 256 192 ) ( -48 256 16 ) bolt9 0 0 0 1 1 +( -48 32 192 ) ( -48 256 192 ) ( -48 32 16 ) bolt9 0 0 0 1 1 +} +// brush 1 +{ +( -304 32 16 ) ( -304 256 16 ) ( -304 32 192 ) bolt9 0 0 0 1 1 +( -304 32 192 ) ( -288 32 192 ) ( -304 32 16 ) bolt9 0 0 0 1 1 +( -304 32 16 ) ( -288 32 16 ) ( -304 256 16 ) bolt9 0 0 0 1 1 +( -304 256 192 ) ( -288 256 192 ) ( -304 32 192 ) bolt9 0 0 0 1 1 +( -304 256 16 ) ( -288 256 16 ) ( -304 256 192 ) bolt9 0 0 0 1 1 +( -288 32 16 ) ( -288 32 192 ) ( -288 256 16 ) bolt9 0 0 0 1 1 +} +// brush 2 +{ +( -288 256 192 ) ( -288 240 192 ) ( -288 256 16 ) bolt9 0 0 0 1 1 +( -64 240 192 ) ( -64 240 16 ) ( -288 240 192 ) bolt9 0 0 0 1 1 +( -288 256 16 ) ( -288 240 16 ) ( -64 256 16 ) bolt9 0 0 0 1 1 +( -64 256 192 ) ( -64 240 192 ) ( -288 256 192 ) bolt9 0 0 0 1 1 +( -64 256 192 ) ( -288 256 192 ) ( -64 256 16 ) bolt9 0 0 0 1 1 +( 224 256 16 ) ( 224 240 16 ) ( 224 256 192 ) bolt9 0 0 0 1 1 +} +// brush 3 +{ +( -288 32 16 ) ( -288 48 16 ) ( -288 32 192 ) bolt9 0 0 0 1 1 +( -64 32 16 ) ( -288 32 16 ) ( -64 32 192 ) bolt9 0 0 0 1 1 +( -64 32 16 ) ( -64 48 16 ) ( -288 32 16 ) bolt9 0 0 0 1 1 +( -288 32 192 ) ( -288 48 192 ) ( -64 32 192 ) bolt9 0 0 0 1 1 +( -288 48 16 ) ( -64 48 16 ) ( -288 48 192 ) bolt9 0 0 0 1 1 +( 224 32 192 ) ( 224 48 192 ) ( 224 32 16 ) bolt9 0 0 0 1 1 +} +// brush 4 +{ +( -288 48 192 ) ( -288 48 176 ) ( -288 240 192 ) bolt9 0 0 0 1 1 +( -64 48 192 ) ( -64 48 176 ) ( -288 48 192 ) bolt9 0 0 0 1 1 +( -64 240 176 ) ( -288 240 176 ) ( -64 48 176 ) bolt9 0 0 0 1 1 +( -64 240 192 ) ( -64 48 192 ) ( -288 240 192 ) bolt9 0 0 0 1 1 +( -288 240 192 ) ( -288 240 176 ) ( -64 240 192 ) bolt9 0 0 0 1 1 +( 224 240 192 ) ( 224 240 176 ) ( 224 48 192 ) bolt9 0 0 0 1 1 +} +// brush 5 +{ +( -288 240 16 ) ( -288 240 32 ) ( -288 48 16 ) bolt9 0 0 0 1 1 +( -288 48 16 ) ( -288 48 32 ) ( -64 48 16 ) bolt9 0 0 0 1 1 +( -288 240 16 ) ( -288 48 16 ) ( -64 240 16 ) bolt9 0 0 0 1 1 +( -288 48 32 ) ( -288 240 32 ) ( -64 48 32 ) bolt9 0 0 0 1 1 +( -64 240 16 ) ( -64 240 32 ) ( -288 240 16 ) bolt9 0 0 0 1 1 +( 224 48 16 ) ( 224 48 32 ) ( 224 240 16 ) bolt9 0 0 0 1 1 +} +// brush 6 +{ +( -64 656 192 ) ( -64 432 192 ) ( -64 656 16 ) bolt9 0 0 0 1 1 +( -48 432 16 ) ( -64 432 16 ) ( -48 432 192 ) bolt9 0 0 0 1 1 +( -48 656 16 ) ( -64 656 16 ) ( -48 432 16 ) bolt9 0 0 0 1 1 +( -48 432 192 ) ( -64 432 192 ) ( -48 656 192 ) bolt9 0 0 0 1 1 +( -48 656 192 ) ( -64 656 192 ) ( -48 656 16 ) bolt9 0 0 0 1 1 +( -48 432 192 ) ( -48 656 192 ) ( -48 432 16 ) bolt9 0 0 0 1 1 +} +// brush 7 +{ +( -304 432 16 ) ( -304 656 16 ) ( -304 432 192 ) bolt9 0 0 0 1 1 +( -304 432 192 ) ( -288 432 192 ) ( -304 432 16 ) bolt9 0 0 0 1 1 +( -304 432 16 ) ( -288 432 16 ) ( -304 656 16 ) bolt9 0 0 0 1 1 +( -304 656 192 ) ( -288 656 192 ) ( -304 432 192 ) bolt9 0 0 0 1 1 +( -304 656 16 ) ( -288 656 16 ) ( -304 656 192 ) bolt9 0 0 0 1 1 +( -288 432 16 ) ( -288 432 192 ) ( -288 656 16 ) bolt9 0 0 0 1 1 +} +// brush 8 +{ +( -288 656 192 ) ( -288 640 192 ) ( -288 656 16 ) bolt9 0 0 0 1 1 +( -64 640 192 ) ( -64 640 16 ) ( -288 640 192 ) bolt9 0 0 0 1 1 +( -288 656 16 ) ( -288 640 16 ) ( -64 656 16 ) bolt9 0 0 0 1 1 +( -64 656 192 ) ( -64 640 192 ) ( -288 656 192 ) bolt9 0 0 0 1 1 +( -64 656 192 ) ( -288 656 192 ) ( -64 656 16 ) bolt9 0 0 0 1 1 +( -64 656 16 ) ( -64 640 16 ) ( -64 656 192 ) bolt9 0 0 0 1 1 +} +// brush 9 +{ +( -288 432 16 ) ( -288 448 16 ) ( -288 432 192 ) bolt9 0 0 0 1 1 +( -64 432 16 ) ( -288 432 16 ) ( -64 432 192 ) bolt9 0 0 0 1 1 +( -64 432 16 ) ( -64 448 16 ) ( -288 432 16 ) bolt9 0 0 0 1 1 +( -288 432 192 ) ( -288 448 192 ) ( -64 432 192 ) bolt9 0 0 0 1 1 +( -288 448 16 ) ( -64 448 16 ) ( -288 448 192 ) bolt9 0 0 0 1 1 +( -64 432 192 ) ( -64 448 192 ) ( -64 432 16 ) bolt9 0 0 0 1 1 +} +// brush 10 +{ +( -288 448 192 ) ( -288 448 176 ) ( -288 640 192 ) bolt9 0 0 0 1 1 +( -64 448 192 ) ( -64 448 176 ) ( -288 448 192 ) bolt9 0 0 0 1 1 +( -64 640 176 ) ( -288 640 176 ) ( -64 448 176 ) bolt9 0 0 0 1 1 +( -64 640 192 ) ( -64 448 192 ) ( -288 640 192 ) bolt9 0 0 0 1 1 +( -288 640 192 ) ( -288 640 176 ) ( -64 640 192 ) bolt9 0 0 0 1 1 +( -64 640 192 ) ( -64 640 176 ) ( -64 448 192 ) bolt9 0 0 0 1 1 +} +// brush 11 +{ +( -288 640 16 ) ( -288 640 32 ) ( -288 448 16 ) bolt9 0 0 0 1 1 +( -288 448 16 ) ( -288 448 32 ) ( -64 448 16 ) bolt9 0 0 0 1 1 +( -288 640 16 ) ( -288 448 16 ) ( -64 640 16 ) bolt9 0 0 0 1 1 +( -288 448 32 ) ( -288 640 32 ) ( -64 448 32 ) bolt9 0 0 0 1 1 +( -64 640 16 ) ( -64 640 32 ) ( -288 640 16 ) bolt9 0 0 0 1 1 +( -64 448 16 ) ( -64 448 32 ) ( -64 640 16 ) bolt9 0 0 0 1 1 +} +// brush 12 +{ +( 208 48 32 ) ( 208 49 32 ) ( 208 48 33 ) bolt9 0 0 0 1 1 +( 208 48 32 ) ( 208 48 33 ) ( 209 48 32 ) bolt9 0 0 0 1 1 +( 208 48 32 ) ( 209 48 32 ) ( 208 49 32 ) bolt9 0 0 0 1 1 +( 224 240 192 ) ( 224 241 192 ) ( 225 240 192 ) bolt9 0 0 0 1 1 +( 224 240 40 ) ( 225 240 40 ) ( 224 240 41 ) bolt9 0 0 0 1 1 +( 224 240 40 ) ( 224 240 41 ) ( 224 241 40 ) bolt9 0 0 0 1 1 +} +} +// entity 1 +{ +"classname" "info_player_start" +"origin" "-240 80 56" +}