From 1cddbf1ad973a377d95546a4354dda1efa15a167 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Mon, 13 Jun 2022 22:38:28 -0600 Subject: [PATCH 1/7] testqbsp: add qbsp_q2_seal_empty_rooms --- qbsp/test_qbsp.cc | 18 ++++ testmaps/qbsp_q2_seal_empty_rooms.map | 121 ++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 testmaps/qbsp_q2_seal_empty_rooms.map diff --git a/qbsp/test_qbsp.cc b/qbsp/test_qbsp.cc index f252fada..c4ef52e6 100644 --- a/qbsp/test_qbsp.cc +++ b/qbsp/test_qbsp.cc @@ -1246,6 +1246,24 @@ TEST_CASE("q2_liquids", "[testmaps_q2][!mayfail]") } +/** + * Empty rooms are sealed to solid in Q2 + **/ +TEST_CASE("qbsp_q2_seal_empty_rooms", "[testmaps_q2]") { + const mbsp_t bsp = LoadTestmapQ2("qbsp_q2_seal_empty_rooms.map"); + + CHECK(GAME_QUAKE_II == bsp.loadversion->game->id); + + const qvec3d in_start_room {-240, 80, 56}; + const qvec3d in_empty_room {-244, 476, 68}; + + // check leaf contents + CHECK(Q2_CONTENTS_EMPTY == BSP_FindLeafAtPoint(&bsp, &bsp.dmodels[0], in_start_room)->contents); + CHECK(Q2_CONTENTS_SOLID == BSP_FindLeafAtPoint(&bsp, &bsp.dmodels[0], in_empty_room)->contents); + + CHECK(8 == bsp.dleafs.size()); +} + TEST_CASE("winding", "[benchmark]") { ankerl::nanobench::Bench bench; diff --git a/testmaps/qbsp_q2_seal_empty_rooms.map b/testmaps/qbsp_q2_seal_empty_rooms.map new file mode 100644 index 00000000..6f4ffd6b --- /dev/null +++ b/testmaps/qbsp_q2_seal_empty_rooms.map @@ -0,0 +1,121 @@ +// Game: Quake 2 +// Format: Quake2 +// entity 0 +{ +"classname" "worldspawn" +"_tb_textures" "textures/e1u1" +"message" "Water brush has SKIP flag on the top face, makign it extend up to the ceiling" +// brush 0 +{ +( -64 256 192 ) ( -64 32 192 ) ( -64 256 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -48 32 16 ) ( -64 32 16 ) ( -48 32 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -48 256 16 ) ( -64 256 16 ) ( -48 32 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -48 32 192 ) ( -64 32 192 ) ( -48 256 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -48 256 192 ) ( -64 256 192 ) ( -48 256 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -48 32 192 ) ( -48 256 192 ) ( -48 32 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +// brush 1 +{ +( -304 32 16 ) ( -304 256 16 ) ( -304 32 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -304 32 192 ) ( -288 32 192 ) ( -304 32 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -304 32 16 ) ( -288 32 16 ) ( -304 256 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -304 256 192 ) ( -288 256 192 ) ( -304 32 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -304 256 16 ) ( -288 256 16 ) ( -304 256 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 32 16 ) ( -288 32 192 ) ( -288 256 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +// brush 2 +{ +( -288 256 192 ) ( -288 240 192 ) ( -288 256 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 240 192 ) ( -64 240 16 ) ( -288 240 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 256 16 ) ( -288 240 16 ) ( -64 256 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 256 192 ) ( -64 240 192 ) ( -288 256 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 256 192 ) ( -288 256 192 ) ( -64 256 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 256 16 ) ( -64 240 16 ) ( -64 256 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +// brush 3 +{ +( -288 32 16 ) ( -288 48 16 ) ( -288 32 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 32 16 ) ( -288 32 16 ) ( -64 32 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 32 16 ) ( -64 48 16 ) ( -288 32 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 32 192 ) ( -288 48 192 ) ( -64 32 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 48 16 ) ( -64 48 16 ) ( -288 48 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 32 192 ) ( -64 48 192 ) ( -64 32 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +// brush 4 +{ +( -288 48 192 ) ( -288 48 176 ) ( -288 240 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 48 192 ) ( -64 48 176 ) ( -288 48 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 240 176 ) ( -288 240 176 ) ( -64 48 176 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 240 192 ) ( -64 48 192 ) ( -288 240 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 240 192 ) ( -288 240 176 ) ( -64 240 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 240 192 ) ( -64 240 176 ) ( -64 48 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +// brush 5 +{ +( -288 240 16 ) ( -288 240 32 ) ( -288 48 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 48 16 ) ( -288 48 32 ) ( -64 48 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 240 16 ) ( -288 48 16 ) ( -64 240 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 48 32 ) ( -288 240 32 ) ( -64 48 32 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 240 16 ) ( -64 240 32 ) ( -288 240 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 48 16 ) ( -64 48 32 ) ( -64 240 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +// brush 6 +{ +( -64 656 192 ) ( -64 432 192 ) ( -64 656 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -48 432 16 ) ( -64 432 16 ) ( -48 432 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -48 656 16 ) ( -64 656 16 ) ( -48 432 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -48 432 192 ) ( -64 432 192 ) ( -48 656 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -48 656 192 ) ( -64 656 192 ) ( -48 656 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -48 432 192 ) ( -48 656 192 ) ( -48 432 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +// brush 7 +{ +( -304 432 16 ) ( -304 656 16 ) ( -304 432 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -304 432 192 ) ( -288 432 192 ) ( -304 432 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -304 432 16 ) ( -288 432 16 ) ( -304 656 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -304 656 192 ) ( -288 656 192 ) ( -304 432 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -304 656 16 ) ( -288 656 16 ) ( -304 656 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 432 16 ) ( -288 432 192 ) ( -288 656 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +// brush 8 +{ +( -288 656 192 ) ( -288 640 192 ) ( -288 656 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 640 192 ) ( -64 640 16 ) ( -288 640 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 656 16 ) ( -288 640 16 ) ( -64 656 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 656 192 ) ( -64 640 192 ) ( -288 656 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 656 192 ) ( -288 656 192 ) ( -64 656 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 656 16 ) ( -64 640 16 ) ( -64 656 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +// brush 9 +{ +( -288 432 16 ) ( -288 448 16 ) ( -288 432 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 432 16 ) ( -288 432 16 ) ( -64 432 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 432 16 ) ( -64 448 16 ) ( -288 432 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 432 192 ) ( -288 448 192 ) ( -64 432 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 448 16 ) ( -64 448 16 ) ( -288 448 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 432 192 ) ( -64 448 192 ) ( -64 432 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +// brush 10 +{ +( -288 448 192 ) ( -288 448 176 ) ( -288 640 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 448 192 ) ( -64 448 176 ) ( -288 448 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 640 176 ) ( -288 640 176 ) ( -64 448 176 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 640 192 ) ( -64 448 192 ) ( -288 640 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 640 192 ) ( -288 640 176 ) ( -64 640 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 640 192 ) ( -64 640 176 ) ( -64 448 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +// brush 11 +{ +( -288 640 16 ) ( -288 640 32 ) ( -288 448 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 448 16 ) ( -288 448 32 ) ( -64 448 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 640 16 ) ( -288 448 16 ) ( -64 640 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 448 32 ) ( -288 640 32 ) ( -64 448 32 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 640 16 ) ( -64 640 32 ) ( -288 640 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 448 16 ) ( -64 448 32 ) ( -64 640 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +} +// entity 1 +{ +"classname" "info_player_start" +"origin" "-240 80 56" +} From 4e7ecbf9fffd0d2c724461365b812afabee58be5 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Mon, 13 Jun 2022 22:50:01 -0600 Subject: [PATCH 2/7] testqbsp: add qbsp_q2_detail_seals --- qbsp/test_qbsp.cc | 16 +++++++- testmaps/qbsp_q2_detail_seals.map | 67 +++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 testmaps/qbsp_q2_detail_seals.map diff --git a/qbsp/test_qbsp.cc b/qbsp/test_qbsp.cc index c4ef52e6..90f3615c 100644 --- a/qbsp/test_qbsp.cc +++ b/qbsp/test_qbsp.cc @@ -1260,8 +1260,22 @@ TEST_CASE("qbsp_q2_seal_empty_rooms", "[testmaps_q2]") { // check leaf contents CHECK(Q2_CONTENTS_EMPTY == BSP_FindLeafAtPoint(&bsp, &bsp.dmodels[0], in_start_room)->contents); CHECK(Q2_CONTENTS_SOLID == BSP_FindLeafAtPoint(&bsp, &bsp.dmodels[0], in_empty_room)->contents); +} - CHECK(8 == bsp.dleafs.size()); +/** + * Detail seals in Q2 + **/ +TEST_CASE("qbsp_q2_detail_seals", "[testmaps_q2]") { + const mbsp_t bsp = LoadTestmapQ2("qbsp_q2_detail_seals.map"); + + CHECK(GAME_QUAKE_II == bsp.loadversion->game->id); + + const qvec3d in_start_room {-240, 80, 56}; + const qvec3d in_void {-336, 80, 56}; + + // check leaf contents + CHECK(Q2_CONTENTS_EMPTY == BSP_FindLeafAtPoint(&bsp, &bsp.dmodels[0], in_start_room)->contents); + CHECK(Q2_CONTENTS_SOLID == BSP_FindLeafAtPoint(&bsp, &bsp.dmodels[0], in_void)->contents); } TEST_CASE("winding", "[benchmark]") { diff --git a/testmaps/qbsp_q2_detail_seals.map b/testmaps/qbsp_q2_detail_seals.map new file mode 100644 index 00000000..a3ba0185 --- /dev/null +++ b/testmaps/qbsp_q2_detail_seals.map @@ -0,0 +1,67 @@ +// Game: Quake 2 +// Format: Quake2 +// entity 0 +{ +"classname" "worldspawn" +"_tb_textures" "textures/e1u1" +"message" "Detail brush seals the world" +// brush 0 +{ +( -64 256 192 ) ( -64 32 192 ) ( -64 256 16 ) e1u1/color1_6 0 0 0 1 1 134217728 0 0 +( -48 32 16 ) ( -64 32 16 ) ( -48 32 192 ) e1u1/color1_6 0 0 0 1 1 134217728 0 0 +( -48 256 16 ) ( -64 256 16 ) ( -48 32 16 ) e1u1/color1_6 0 0 0 1 1 134217728 0 0 +( -48 32 192 ) ( -64 32 192 ) ( -48 256 192 ) e1u1/color1_6 0 0 0 1 1 134217728 0 0 +( -48 256 192 ) ( -64 256 192 ) ( -48 256 16 ) e1u1/color1_6 0 0 0 1 1 134217728 0 0 +( -48 32 192 ) ( -48 256 192 ) ( -48 32 16 ) e1u1/color1_6 0 0 0 1 1 134217728 0 0 +} +// brush 1 +{ +( -304 32 16 ) ( -304 256 16 ) ( -304 32 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -304 32 192 ) ( -288 32 192 ) ( -304 32 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -304 32 16 ) ( -288 32 16 ) ( -304 256 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -304 256 192 ) ( -288 256 192 ) ( -304 32 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -304 256 16 ) ( -288 256 16 ) ( -304 256 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 32 16 ) ( -288 32 192 ) ( -288 256 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +// brush 2 +{ +( -288 256 192 ) ( -288 240 192 ) ( -288 256 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 240 192 ) ( -64 240 16 ) ( -288 240 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 256 16 ) ( -288 240 16 ) ( -64 256 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 256 192 ) ( -64 240 192 ) ( -288 256 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 256 192 ) ( -288 256 192 ) ( -64 256 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 256 16 ) ( -64 240 16 ) ( -64 256 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +// brush 3 +{ +( -288 32 16 ) ( -288 48 16 ) ( -288 32 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 32 16 ) ( -288 32 16 ) ( -64 32 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 32 16 ) ( -64 48 16 ) ( -288 32 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 32 192 ) ( -288 48 192 ) ( -64 32 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 48 16 ) ( -64 48 16 ) ( -288 48 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 32 192 ) ( -64 48 192 ) ( -64 32 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +// brush 4 +{ +( -288 48 192 ) ( -288 48 176 ) ( -288 240 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 48 192 ) ( -64 48 176 ) ( -288 48 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 240 176 ) ( -288 240 176 ) ( -64 48 176 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 240 192 ) ( -64 48 192 ) ( -288 240 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 240 192 ) ( -288 240 176 ) ( -64 240 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 240 192 ) ( -64 240 176 ) ( -64 48 192 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +// brush 5 +{ +( -288 240 16 ) ( -288 240 32 ) ( -288 48 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 48 16 ) ( -288 48 32 ) ( -64 48 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 240 16 ) ( -288 48 16 ) ( -64 240 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -288 48 32 ) ( -288 240 32 ) ( -64 48 32 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 240 16 ) ( -64 240 32 ) ( -288 240 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +( -64 48 16 ) ( -64 48 32 ) ( -64 240 16 ) e1u1/color1_6 0 0 0 1 1 0 0 0 +} +} +// entity 1 +{ +"classname" "info_player_start" +"origin" "-240 80 56" +} From 02665078335c02d62b8138e91cb86d066eeb4958 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Mon, 13 Jun 2022 23:37:46 -0600 Subject: [PATCH 3/7] testqbsp: tag qbsp_q2_detail_seals as mayfail --- qbsp/test_qbsp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qbsp/test_qbsp.cc b/qbsp/test_qbsp.cc index 90f3615c..c81e606a 100644 --- a/qbsp/test_qbsp.cc +++ b/qbsp/test_qbsp.cc @@ -1265,7 +1265,7 @@ TEST_CASE("qbsp_q2_seal_empty_rooms", "[testmaps_q2]") { /** * Detail seals in Q2 **/ -TEST_CASE("qbsp_q2_detail_seals", "[testmaps_q2]") { +TEST_CASE("qbsp_q2_detail_seals", "[testmaps_q2][!mayfail]") { const mbsp_t bsp = LoadTestmapQ2("qbsp_q2_detail_seals.map"); CHECK(GAME_QUAKE_II == bsp.loadversion->game->id); From a309e8467b05a5c9893a87ec2e78f5fead99d323 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Mon, 13 Jun 2022 23:55:16 -0600 Subject: [PATCH 4/7] 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" +} From 6c613b2b516bdb3b3d1c416cce37e218cdb6b4cb Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Tue, 14 Jun 2022 00:49:15 -0600 Subject: [PATCH 5/7] fix clangcl build --- common/bspfile.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/bspfile.cc b/common/bspfile.cc index 72ce3212..7d385c91 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -183,12 +183,12 @@ public: return !string_iequals(name, "hint"); } - constexpr contentflags_t create_sky_contents() const + contentflags_t create_sky_contents() const { return {CONTENTS_SKY}; } - constexpr contentflags_t create_liquid_contents(const int32_t &liquid_type) const + contentflags_t create_liquid_contents(const int32_t &liquid_type) const { return {liquid_type}; } From b9250d9243a54a39344831319942ff2e7e52f745 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Tue, 14 Jun 2022 00:52:15 -0600 Subject: [PATCH 6/7] fix Ubuntu build --- common/bspfile.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/bspfile.cc b/common/bspfile.cc index 7d385c91..fe874b8b 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -26,6 +26,8 @@ #include +#include + static std::vector make_palette(std::initializer_list bytes) { Q_assert((bytes.size() % 3) == 0); From bf36bd56f7b6139fe571abf26eb22911927282e3 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Tue, 14 Jun 2022 02:03:50 -0600 Subject: [PATCH 7/7] qbsp: fix qbsp_q1_sealing test case --- qbsp/qbsp.cc | 4 ++++ qbsp/test_qbsp.cc | 3 +-- testmaps/qbsp_q1_sealing.map | 5 +++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/qbsp/qbsp.cc b/qbsp/qbsp.cc index 55af126d..cac01810 100644 --- a/qbsp/qbsp.cc +++ b/qbsp/qbsp.cc @@ -750,6 +750,10 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum) // make a really good tree nodes = SolidBSP(entity, false); + // fill again so PruneNodes works + PortalizeEntity(entity, nodes, hullnum); + FillOutside(entity, nodes, hullnum); + PruneNodes(nodes); DetailToSolid(nodes); } } diff --git a/qbsp/test_qbsp.cc b/qbsp/test_qbsp.cc index bbc24396..cd638c4e 100644 --- a/qbsp/test_qbsp.cc +++ b/qbsp/test_qbsp.cc @@ -1284,7 +1284,7 @@ TEST_CASE("qbsp_q2_detail_seals", "[testmaps_q2][!mayfail]") { * - 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]") { +TEST_CASE("qbsp_q1_sealing", "[testmaps_q1]") { const mbsp_t bsp = LoadTestmap("qbsp_q1_sealing.map"); CHECK(GAME_QUAKE == bsp.loadversion->game->id); @@ -1313,7 +1313,6 @@ TEST_CASE("qbsp_q1_sealing", "[testmaps_q1][!mayfail]") { 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 index d0b82854..a510af05 100644 --- a/testmaps/qbsp_q1_sealing.map +++ b/testmaps/qbsp_q1_sealing.map @@ -127,3 +127,8 @@ "classname" "info_player_start" "origin" "-240 80 56" } +// entity 2 +{ +"classname" "light_fluorospark" +"origin" "-192 144 104" +}