diff --git a/common/bspfile.cc b/common/bspfile.cc index 9fa1bcea..7aec366a 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -586,6 +586,11 @@ public: auto bits_a = contentflags_to_bits(contents0); auto bits_b = contentflags_to_bits(contents1); + // can't see through solid + if (bits_a.solid || bits_b.solid) { + return false; + } + bool a_translucent = transwater ? (bits_a.water || bits_a.slime || bits_a.lava) : false; bool b_translucent = transwater ? (bits_b.water || bits_b.slime || bits_b.lava) : false; @@ -597,9 +602,6 @@ public: if (bits_b.detail || b_translucent) bits_b = q1_contentflags_bits(); - if (bits_a.solid || bits_b.solid) - return false; // can't see through solid - if ((bits_a ^ bits_b).all_empty()) return true; // identical on both sides diff --git a/qbsp/prtfile.cc b/qbsp/prtfile.cc index 982b9065..f3595f5c 100644 --- a/qbsp/prtfile.cc +++ b/qbsp/prtfile.cc @@ -73,8 +73,14 @@ static void WritePortals_r(node_t *node, std::ofstream &portalFile, bool cluster front = clusters ? p->nodes[0]->viscluster : p->nodes[0]->visleafnum; back = clusters ? p->nodes[1]->viscluster : p->nodes[1]->visleafnum; - Q_assert(front != -1); - Q_assert(back != -1); + if (front == -1 || back == -1) { + auto front_contents = ClusterContents(p->nodes.front); + auto back_contents = ClusterContents(p->nodes.back); + + FError("front {}, cluster contents: {}. back {}, cluster contents: {}. portal: {}", front, + front_contents.to_string(qbsp_options.target_game), back, + back_contents.to_string(qbsp_options.target_game), w->center()); + } /* * sometimes planes get turned around when they are very near the diff --git a/testmaps/q1_detail_touching_water.map b/testmaps/q1_detail_touching_water.map new file mode 100644 index 00000000..bcff7046 --- /dev/null +++ b/testmaps/q1_detail_touching_water.map @@ -0,0 +1,168 @@ +// Game: Quake +// Format: Valve +// entity 0 +{ +"mapversion" "220" +"classname" "worldspawn" +"wad" "deprecated/free_wad.wad;deprecated/fence.wad;deprecated/origin.wad;deprecated/hintskip.wad" +"_wateralpha" "0.5" +"_tb_def" "builtin:Quake.fgd" +// brush 0 +{ +( -144 -192 48 ) ( -144 32 48 ) ( -144 -192 208 ) orangestuff8 [ 0 1 0 16 ] [ 0 0 -1 48 ] 0 1 1 +( -144 -640 208 ) ( -128 -640 208 ) ( -144 -640 48 ) orangestuff8 [ -1 0 0 -16 ] [ 0 0 -1 48 ] 180 1 1 +( -144 -192 48 ) ( -128 -192 48 ) ( -144 32 48 ) orangestuff8 [ 1 0 0 16 ] [ 0 -1 0 -16 ] 180 1 1 +( -144 32 336 ) ( -128 32 336 ) ( -144 -192 336 ) orangestuff8 [ -1 0 0 -16 ] [ 0 -1 0 -16 ] 180 1 1 +( -144 32 48 ) ( -128 32 48 ) ( -144 32 208 ) orangestuff8 [ 1 0 0 16 ] [ 0 0 -1 48 ] 180 1 1 +( -128 -192 48 ) ( -128 -192 208 ) ( -128 32 48 ) orangestuff8 [ 0 1 0 16 ] [ 0 0 -1 48 ] 0 1 1 +} +// brush 1 +{ +( -128 32 208 ) ( -128 16 208 ) ( -128 32 48 ) orangestuff8 [ 0 1 0 16 ] [ 0 0 -1 48 ] 0 1 1 +( 96 16 208 ) ( 96 16 48 ) ( -128 16 208 ) orangestuff8 [ 1 0 0 16 ] [ 0 0 -1 48 ] 180 1 1 +( -128 32 48 ) ( -128 16 48 ) ( 96 32 48 ) orangestuff8 [ 1 0 0 16 ] [ 0 -1 0 -16 ] 180 1 1 +( 96 32 336 ) ( 96 16 336 ) ( -128 32 336 ) orangestuff8 [ -1 0 0 -16 ] [ 0 -1 0 -16 ] 180 1 1 +( 96 32 208 ) ( -128 32 208 ) ( 96 32 48 ) orangestuff8 [ 1 0 0 16 ] [ 0 0 -1 48 ] 180 1 1 +( 464 32 48 ) ( 464 16 48 ) ( 464 32 208 ) orangestuff8 [ 0 -1 0 -16 ] [ 0 0 -1 48 ] 0 1 1 +} +// brush 2 +{ +( -128 -656 48 ) ( -128 -640 48 ) ( -128 -656 208 ) orangestuff8 [ 0 1 0 -32 ] [ 0 0 -1 48 ] 0 1 1 +( 464 -656 48 ) ( 240 -656 48 ) ( 464 -656 208 ) orangestuff8 [ -1 0 0 32 ] [ 0 0 -1 48 ] 180 1 1 +( 464 -656 48 ) ( 464 -640 48 ) ( 240 -656 48 ) orangestuff8 [ 1 0 0 -32 ] [ 0 -1 0 32 ] 180 1 1 +( 240 -656 336 ) ( 240 -640 336 ) ( 464 -656 336 ) orangestuff8 [ -1 0 0 32 ] [ 0 -1 0 32 ] 180 1 1 +( 240 -640 48 ) ( 464 -640 48 ) ( 240 -640 208 ) orangestuff8 [ -1 0 0 32 ] [ 0 0 -1 48 ] 180 1 1 +( 464 -656 208 ) ( 464 -640 208 ) ( 464 -656 48 ) orangestuff8 [ 0 -1 0 32 ] [ 0 0 -1 48 ] 0 1 1 +} +// brush 3 +{ +( -128 -176 352 ) ( -128 -176 336 ) ( -128 16 352 ) sky3 [ 0 1 0 16 ] [ 0 0 -1 64 ] 0 1 1 +( 96 -640 352 ) ( 96 -640 336 ) ( -128 -640 352 ) sky3 [ -1 0 0 -16 ] [ 0 0 -1 64 ] 180 1 1 +( 96 16 336 ) ( -128 16 336 ) ( 96 -176 336 ) sky3 [ -1 0 0 -16 ] [ 0 -1 0 -16 ] 180 1 1 +( 96 16 352 ) ( 96 -176 352 ) ( -128 16 352 ) sky3 [ -1 0 0 -16 ] [ 0 -1 0 -16 ] 180 1 1 +( -128 16 352 ) ( -128 16 336 ) ( 96 16 352 ) sky3 [ 1 0 0 16 ] [ 0 0 -1 64 ] 180 1 1 +( 464 16 352 ) ( 464 16 336 ) ( 464 -176 352 ) sky3 [ 0 -1 0 -16 ] [ 0 0 -1 64 ] 0 1 1 +} +// brush 4 +{ +( 464 -432 208 ) ( 464 -656 208 ) ( 464 -432 48 ) orangestuff8 [ 0 -1 0 32 ] [ 0 0 -1 48 ] 0 1 1 +( 480 -656 48 ) ( 464 -656 48 ) ( 480 -656 208 ) orangestuff8 [ -1 0 0 32 ] [ 0 0 -1 48 ] 180 1 1 +( 480 -432 48 ) ( 464 -432 48 ) ( 480 -656 48 ) orangestuff8 [ 1 0 0 -32 ] [ 0 -1 0 32 ] 180 1 1 +( 480 -656 336 ) ( 464 -656 336 ) ( 480 -432 336 ) orangestuff8 [ -1 0 0 32 ] [ 0 -1 0 32 ] 180 1 1 +( 480 16 208 ) ( 464 16 208 ) ( 480 16 48 ) orangestuff8 [ 1 0 0 -32 ] [ 0 0 -1 48 ] 180 1 1 +( 480 -656 208 ) ( 480 -432 208 ) ( 480 -656 48 ) orangestuff8 [ 0 -1 0 32 ] [ 0 0 -1 48 ] 0 1 1 +} +// brush 5 +{ +( 304 -304 64 ) ( 304 -288 64 ) ( 304 -288 192 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 48 ] 0 1 1 +( 176 -320 64 ) ( 256 -320 192 ) ( 256 -320 64 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 48 ] 180 1 1 +( -128 16 48 ) ( -128 -176 48 ) ( 96 16 48 ) orangestuff8 [ 1 0 0 16 ] [ 0 -1 0 -16 ] 180 1 1 +( -128 -176 64 ) ( -128 16 64 ) ( 96 -176 64 ) orangestuff8 [ 1 0 0 16 ] [ 0 -1 0 -16 ] 180 1 1 +( 128 -192 64 ) ( 224 -192 64 ) ( 224 -192 192 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 48 ] 180 1 1 +( 464 -176 48 ) ( 464 -176 64 ) ( 464 16 48 ) orangestuff8 [ 0 -1 0 -16 ] [ 0 0 -1 48 ] 0 1 1 +} +// brush 6 +{ +( 160 -288 -32 ) ( 160 -240 -32 ) ( 160 -240 96 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 -48 ] 0 1 1 +( 176 -320 -32 ) ( 256 -320 96 ) ( 256 -320 -32 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 -48 ] 180 1 1 +( -128 16 -48 ) ( -128 -176 -48 ) ( 96 16 -48 ) orangestuff8 [ 1 0 0 16 ] [ 0 -1 0 -16 ] 180 1 1 +( -128 -176 -32 ) ( -128 16 -32 ) ( 96 -176 -32 ) orangestuff8 [ 1 0 0 16 ] [ 0 -1 0 -16 ] 180 1 1 +( 128 -192 -32 ) ( 224 -192 -32 ) ( 224 -192 96 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 -48 ] 180 1 1 +( 304 -304 -32 ) ( 304 -288 96 ) ( 304 -288 -32 ) orangestuff8 [ 0 1 0 -16 ] [ 0 0 -1 -48 ] 0 1 1 +} +// brush 7 +{ +( -128 16 48 ) ( -128 16 64 ) ( -128 -176 48 ) orangestuff8 [ 0 1 0 16 ] [ 0 0 -1 48 ] 0 1 1 +( 176 -320 64 ) ( 256 -320 192 ) ( 256 -320 64 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 48 ] 180 1 1 +( -128 16 48 ) ( -128 -176 48 ) ( 96 16 48 ) orangestuff8 [ 1 0 0 16 ] [ 0 -1 0 -16 ] 180 1 1 +( -128 -176 64 ) ( -128 16 64 ) ( 96 -176 64 ) orangestuff8 [ 1 0 0 16 ] [ 0 -1 0 -16 ] 180 1 1 +( 128 -192 64 ) ( 224 -192 64 ) ( 224 -192 192 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 48 ] 180 1 1 +( 160 -288 64 ) ( 160 -240 192 ) ( 160 -240 64 ) orangestuff8 [ 0 1 0 -16 ] [ 0 0 -1 48 ] 0 1 1 +} +// brush 8 +{ +( 304 -288 -32 ) ( 304 -240 -32 ) ( 304 -240 96 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 -48 ] 0 1 1 +( 192 -320 -32 ) ( 272 -320 96 ) ( 272 -320 -32 ) orangestuff8 [ 1 0 0 -32 ] [ 0 0 -1 -48 ] 180 1 1 +( -112 16 -48 ) ( -112 -176 -48 ) ( 112 16 -48 ) orangestuff8 [ 1 0 0 0 ] [ 0 -1 0 -16 ] 180 1 1 +( -112 -176 48 ) ( -112 16 48 ) ( 112 -176 48 ) orangestuff8 [ 1 0 0 0 ] [ 0 -1 0 -16 ] 180 1 1 +( 144 -192 -32 ) ( 240 -192 -32 ) ( 240 -192 96 ) orangestuff8 [ -1 0 0 32 ] [ 0 0 -1 -48 ] 180 1 1 +( 320 -304 -32 ) ( 320 -288 96 ) ( 320 -288 -32 ) orangestuff8 [ 0 1 0 -16 ] [ 0 0 -1 -48 ] 0 1 1 +} +// brush 9 +{ +( 144 -288 -32 ) ( 144 -240 -32 ) ( 144 -240 96 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 -48 ] 0 1 1 +( 32 -320 -32 ) ( 112 -320 96 ) ( 112 -320 -32 ) orangestuff8 [ 1 0 0 0 ] [ 0 0 -1 -48 ] 180 1 1 +( -272 16 -48 ) ( -272 -176 -48 ) ( -48 16 -48 ) orangestuff8 [ 1 0 0 32 ] [ 0 -1 0 -16 ] 180 1 1 +( -272 -176 48 ) ( -272 16 48 ) ( -48 -176 48 ) orangestuff8 [ 1 0 0 32 ] [ 0 -1 0 -16 ] 180 1 1 +( -16 -192 -32 ) ( 80 -192 -32 ) ( 80 -192 96 ) orangestuff8 [ -1 0 0 0 ] [ 0 0 -1 -48 ] 180 1 1 +( 160 -304 -32 ) ( 160 -288 96 ) ( 160 -288 -32 ) orangestuff8 [ 0 1 0 -16 ] [ 0 0 -1 -48 ] 0 1 1 +} +// brush 10 +{ +( 160 -192 -48 ) ( 160 -191 -48 ) ( 160 -192 -47 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 -48 ] 0 1 1 +( 160 -192 -48 ) ( 160 -192 -47 ) ( 161 -192 -48 ) orangestuff8 [ -1.0000000000000002 0 0 0 ] [ 0 0 -1.0000000000000002 -48 ] 0 1 1 +( 160 -192 -48 ) ( 161 -192 -48 ) ( 160 -191 -48 ) orangestuff8 [ 0 -1.0000000000000002 0 16 ] [ -1.0000000000000002 0 0 48 ] 0 1 1 +( 304 -176 48 ) ( 304 -175 48 ) ( 305 -176 48 ) orangestuff8 [ 0 -1.0000000000000002 0 16 ] [ 1.0000000000000002 0 0 -16 ] 0 1 1 +( 304 -176 -32 ) ( 305 -176 -32 ) ( 304 -176 -31 ) orangestuff8 [ 1.0000000000000002 0 0 -48 ] [ 0 0 -1.0000000000000002 -48 ] 0 1 1 +( 304 -176 -32 ) ( 304 -176 -31 ) ( 304 -175 -32 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 -48 ] 0 1 1 +} +// brush 11 +{ +( 160 -336 -48 ) ( 160 -335 -48 ) ( 160 -336 -47 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 -48 ] 0 1 1 +( 160 -336 -48 ) ( 160 -336 -47 ) ( 161 -336 -48 ) orangestuff8 [ -1.0000000000000002 0 0 16 ] [ 0 0 -1.0000000000000002 -48 ] 0 1 1 +( 160 -336 -48 ) ( 161 -336 -48 ) ( 160 -335 -48 ) orangestuff8 [ 0 -1.0000000000000002 0 16 ] [ -1.0000000000000002 0 0 48 ] 0 1 1 +( 304 -320 48 ) ( 304 -319 48 ) ( 305 -320 48 ) orangestuff8 [ 0 -1.0000000000000002 0 16 ] [ 1.0000000000000002 0 0 -16 ] 0 1 1 +( 304 -320 -32 ) ( 305 -320 -32 ) ( 304 -320 -31 ) orangestuff8 [ 1.0000000000000002 0 0 32 ] [ 0 0 -1.0000000000000002 -48 ] 0 1 1 +( 304 -320 -32 ) ( 304 -320 -31 ) ( 304 -319 -32 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 -48 ] 0 1 1 +} +// brush 12 +{ +( -128 -192 64 ) ( -128 16 48 ) ( -128 16 64 ) orangestuff8 [ 0 1 0 16 ] [ 0 0 -1 48 ] 0 1 1 +( 464 -192 64 ) ( -128 -192 48 ) ( -128 -192 64 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 48 ] 180 1 1 +( 464 16 48 ) ( -128 -192 48 ) ( 464 -192 48 ) orangestuff8 [ 1 0 0 16 ] [ 0 -1 0 -16 ] 180 1 1 +( 464 16 64 ) ( -128 -192 64 ) ( -128 16 64 ) orangestuff8 [ 1 0 0 16 ] [ 0 -1 0 -16 ] 180 1 1 +( 464 16 64 ) ( -128 16 48 ) ( 464 16 48 ) orangestuff8 [ 1 0 0 16 ] [ 0 0 -1 48 ] 180 1 1 +( 464 16 64 ) ( 464 -192 48 ) ( 464 -192 64 ) orangestuff8 [ 0 -1 0 -16 ] [ 0 0 -1 48 ] 0 1 1 +} +// brush 13 +{ +( -128 -640 64 ) ( -128 -320 48 ) ( -128 -320 64 ) orangestuff8 [ 0 1 0 16 ] [ 0 0 -1 48 ] 0 1 1 +( 464 -640 64 ) ( -128 -640 48 ) ( -128 -640 64 ) orangestuff8 [ -1 0 0 -16 ] [ 0 0 -1 48 ] 180 1 1 +( 464 -320 48 ) ( -128 -640 48 ) ( 464 -640 48 ) orangestuff8 [ 1 0 0 16 ] [ 0 -1 0 -16 ] 180 1 1 +( 464 -320 64 ) ( -128 -640 64 ) ( -128 -320 64 ) orangestuff8 [ 1 0 0 16 ] [ 0 -1 0 -16 ] 180 1 1 +( 464 -320 64 ) ( -128 -320 48 ) ( 464 -320 48 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 48 ] 180 1 1 +( 464 -320 64 ) ( 464 -640 48 ) ( 464 -640 64 ) orangestuff8 [ 0 -1 0 -16 ] [ 0 0 -1 48 ] 0 1 1 +} +// brush 14 +{ +( 160 -320 32 ) ( 160 -319 32 ) ( 160 -320 33 ) *swater5 [ 0 -1 0 0 ] [ 0 0 -1 0 ] 0 1 1 +( 240 -320 64 ) ( 160 -240 64 ) ( 160 -240 192 ) *swater5 [ 0.7071067811865476 -0.7071067811865476 0 0 ] [ 0 0 -1 0 ] 0 1 1 +( 256 -320 32 ) ( 256 -320 33 ) ( 257 -320 32 ) *swater5 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 +( 256 -320 -32 ) ( 257 -320 -32 ) ( 256 -319 -32 ) *swater5 [ -1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 +( 304 -240 64 ) ( 304 -239 64 ) ( 305 -240 64 ) *swater5 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 +( 304 -192 48 ) ( 305 -192 48 ) ( 304 -192 49 ) *swater5 [ -1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 +( 304 -240 48 ) ( 304 -240 49 ) ( 304 -239 48 ) *swater5 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 +} +} +// entity 1 +{ +"classname" "info_player_start" +"origin" "-56 -96 120" +} +// entity 2 +{ +"classname" "ambient_drip" +"origin" "168 -296 200" +} +// entity 3 +{ +"classname" "func_detail" +// brush 0 +{ +( 160 -320 32 ) ( 160 -319 32 ) ( 160 -320 33 ) archeo3 [ 0 -1 0 0 ] [ 0 0 -1 0 ] 0 1 1 +( 256 -320 32 ) ( 256 -320 33 ) ( 257 -320 32 ) archeo3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 +( 256 -320 -32 ) ( 257 -320 -32 ) ( 256 -319 -32 ) archeo3 [ -1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 +( 304 -240 64 ) ( 304 -239 64 ) ( 305 -240 64 ) archeo3 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 +( 240 -320 64 ) ( 160 -240 192 ) ( 160 -240 64 ) archeo3 [ 0.7071067811865476 -0.7071067811865476 0 0 ] [ 0 0 -1 0 ] 0 1 1 +} +} diff --git a/tests/test_common.cc b/tests/test_common.cc index de5c8311..f5c8ab09 100644 --- a/tests/test_common.cc +++ b/tests/test_common.cc @@ -102,6 +102,9 @@ TEST_SUITE("common") CHECK(solid_empty_cluster.is_empty(game)); // this is a bit weird... CHECK(solid_empty_cluster.is_any_detail(game)); + + // check portal_can_see_through + CHECK(!game->portal_can_see_through(empty, solid_detail, true, true)); } } } diff --git a/tests/test_qbsp.cc b/tests/test_qbsp.cc index a88cd0df..a208ccdb 100644 --- a/tests/test_qbsp.cc +++ b/tests/test_qbsp.cc @@ -868,6 +868,13 @@ TEST_CASE("q1_sealing_contents" * doctest::test_suite("testmaps_q1")) CHECK(prt.has_value()); } +TEST_CASE("q1_detail_touching_water" * doctest::test_suite("testmaps_q1")) +{ + const auto [bsp, bspx, prt] = LoadTestmapQ1("q1_detail_touching_water.map"); + + CHECK(prt.has_value()); +} + TEST_CASE("detail_doesnt_remove_world_nodes" * doctest::test_suite("testmaps_q1")) { const auto [bsp, bspx, prt] = LoadTestmapQ1("qbsp_detail_doesnt_remove_world_nodes.map");