diff --git a/include/common/bspfile_q1.hh b/include/common/bspfile_q1.hh index 1aa29e4b..341b6ba1 100644 --- a/include/common/bspfile_q1.hh +++ b/include/common/bspfile_q1.hh @@ -104,6 +104,8 @@ enum q1_contents_t : int32_t CONTENTS_MIN = CONTENTS_SKY }; +constexpr static int BSPXBRUSHES_CONTENTS_CLIP = -8; + struct bsp29_dnode_t { int32_t planenum; diff --git a/qbsp/qbsp.cc b/qbsp/qbsp.cc index 4560a69b..57fa62cf 100644 --- a/qbsp/qbsp.cc +++ b/qbsp/qbsp.cc @@ -1324,7 +1324,7 @@ static bspxbrushes_permodel BSPX_Brushes_AddModel(int modelnum, const std::vecto case CONTENTS_LAVA: case CONTENTS_SKY: if (contents.is_clip(qbsp_options.target_game)) { - perbrush.contents = -8; + perbrush.contents = BSPXBRUSHES_CONTENTS_CLIP; } else { perbrush.contents = contents.native; } @@ -1334,7 +1334,7 @@ static bspxbrushes_permodel BSPX_Brushes_AddModel(int modelnum, const std::vecto // break; default: { if (contents.is_clip(qbsp_options.target_game)) { - perbrush.contents = -8; + perbrush.contents = BSPXBRUSHES_CONTENTS_CLIP; } else { logging::print("WARNING: Unknown contents: {}. Translating to solid.\n", contents.to_string(qbsp_options.target_game)); diff --git a/testmaps/q1_hull1_content_types.map b/testmaps/q1_hull1_content_types.map index 9952f53b..f5f6c141 100644 --- a/testmaps/q1_hull1_content_types.map +++ b/testmaps/q1_hull1_content_types.map @@ -104,6 +104,15 @@ ( 272 16 0 ) ( 273 16 0 ) ( 272 16 1 ) sky3 [ -1 0 0 0 ] [ 0 0 -1 -16 ] 0 1 1 ( 272 48 0 ) ( 272 48 1 ) ( 272 49 0 ) sky3 [ 0 1 0 -32 ] [ 0 0 -1 -16 ] 0 1 1 } +// brush 11 +{ +( 560 16 16 ) ( 560 -16 16 ) ( 560 -16 -16 ) clip [ 0 0 -1.0000000000000002 32 ] [ 0 -1.0000000000000002 0 -64 ] 0 1 1 +( 560 -16 16 ) ( 592 -16 16 ) ( 592 -16 -16 ) clip [ 1.0000000000000002 0 0 0 ] [ 0 0 1.0000000000000002 32 ] 0 1 1 +( 592 -16 -16 ) ( 592 16 -16 ) ( 560 16 -16 ) clip [ 1 0 0 0 ] [ 0 -1 0 -64 ] 0 1 1 +( 560 16 16 ) ( 592 16 16 ) ( 592 -16 16 ) clip [ 1 0 0 0 ] [ 0 -1 0 -64 ] 0 1 1 +( 592 16 -16 ) ( 592 16 16 ) ( 560 16 16 ) clip [ 1.0000000000000002 0 0 0 ] [ 0 0 -1.0000000000000002 -32 ] 0 1 1 +( 592 -16 16 ) ( 592 16 16 ) ( 592 16 -16 ) clip [ 0 0 1.0000000000000002 96 ] [ 0 -1.0000000000000002 0 -64 ] 0 1 1 +} } // entity 1 { diff --git a/tests/test_qbsp.cc b/tests/test_qbsp.cc index 680900b4..2ce7b098 100644 --- a/tests/test_qbsp.cc +++ b/tests/test_qbsp.cc @@ -1696,6 +1696,7 @@ TEST_CASE("q1_hull1_content_types" * doctest::test_suite("testmaps_q1")) {{448, -64, 0}, {CONTENTS_EMPTY, new_leaf, CONTENTS_EMPTY}}, // func_detail_illusionary + _mirrorinside is empty in hull1 {{512, 0, 0}, {CONTENTS_SOLID, shared_leaf_0, CONTENTS_SOLID}}, // func_detail_wall is solid in hull1 + {{576, 0, 0}, {CONTENTS_EMPTY, new_leaf, CONTENTS_SOLID}}, // clip is empty in hull0, solid in hull1 }; for (const auto &[point, expected_types] : expected) { @@ -2008,3 +2009,42 @@ TEST_CASE("wrbrushes + misc_external_map") REQUIRE(brush.bounds.maxs() == qvec3f{64,64,16}); REQUIRE(brush.bounds.mins() == qvec3f{-64,-64,-16}); } + +TEST_CASE("wrbrushes content types") +{ + const auto [bsp, bspx, prt] = LoadTestmap("q1_hull1_content_types.map", {"-wrbrushes"}); + + const bspxbrushes lump = deserialize(bspx.at("BRUSHLIST")); + REQUIRE(lump.models.size() == 1); + + auto &model = lump.models.at(0); + REQUIRE(model.numfaces == 0); // all faces are axial + REQUIRE(model.modelnum == 0); + + const std::vector expected { + CONTENTS_SOLID, + CONTENTS_SOLID, + CONTENTS_SOLID, + CONTENTS_SOLID, + CONTENTS_SOLID, + CONTENTS_SOLID, + CONTENTS_WATER, + CONTENTS_SLIME, + CONTENTS_LAVA, + CONTENTS_SOLID, + CONTENTS_SKY, + BSPXBRUSHES_CONTENTS_CLIP, + CONTENTS_SOLID, // detail solid in source map + CONTENTS_SOLID, // detail fence in source map + CONTENTS_SOLID, // FIXME: detail illusionary brush should be omitted + CONTENTS_SOLID, // detail fence in source map + CONTENTS_SOLID, // FIXME: detail illusionary brush should be omitted + CONTENTS_SOLID // detail wall in source map + }; + REQUIRE(model.brushes.size() == expected.size()); + + for (size_t i = 0; i < expected.size(); ++i) { + INFO("brush ", i); + CHECK(expected[i] == model.brushes[i].contents); + } +}