#include #include #include #include #include #include #include #include TEST_SUITE("common") { TEST_CASE("StripFilename") { REQUIRE("/home/foo" == fs::path("/home/foo/bar.txt").parent_path()); REQUIRE("" == fs::path("bar.txt").parent_path()); } TEST_CASE("q1 contents") { auto *game_q1 = bspver_q1.game; const auto solid = game_q1->create_solid_contents(); const auto detail_solid = game_q1->create_detail_solid_contents(solid); const auto detail_wall = game_q1->create_detail_wall_contents(solid); const auto detail_fence = game_q1->create_detail_fence_contents(solid); const auto detail_illusionary = game_q1->create_detail_illusionary_contents(solid); const std::array test_contents{game_q1->create_contents_from_native(CONTENTS_EMPTY), game_q1->create_contents_from_native(CONTENTS_SOLID), game_q1->create_contents_from_native(CONTENTS_WATER), game_q1->create_contents_from_native(CONTENTS_SLIME), game_q1->create_contents_from_native(CONTENTS_LAVA), game_q1->create_contents_from_native(CONTENTS_SKY), detail_solid, detail_wall, detail_fence, detail_illusionary}; SUBCASE("solid combined with others") { CHECK(game_q1->contents_to_native(solid) == CONTENTS_SOLID); for (const auto &c : test_contents) { auto combined = game_q1->combine_contents(solid, c); CHECK(game_q1->contents_to_native(combined) == CONTENTS_SOLID); CHECK(combined.is_solid(game_q1)); CHECK(!combined.is_any_detail(game_q1)); } } SUBCASE("detail_illusionary plus water") { auto combined = game_q1->combine_contents(detail_illusionary, game_q1->create_contents_from_native(CONTENTS_WATER)); CHECK(game_q1->contents_to_native(combined) == CONTENTS_WATER); CHECK(combined.is_detail_illusionary(game_q1)); } SUBCASE("detail_solid plus water") { auto combined = game_q1->combine_contents(detail_solid, game_q1->create_contents_from_native(CONTENTS_WATER)); CHECK(combined.is_any_solid(game_q1)); CHECK(combined.is_detail_solid(game_q1)); CHECK(!combined.is_liquid(game_q1)); CHECK(!combined.is_solid(game_q1)); } SUBCASE("detail_solid plus sky") { auto combined = game_q1->combine_contents(detail_solid, game_q1->create_contents_from_native(CONTENTS_SKY)); CHECK(!combined.is_detail_solid(game_q1)); CHECK(combined.is_sky(game_q1)); CHECK(!combined.is_solid(game_q1)); } } TEST_CASE("cluster_contents") { for (auto *bspver : bspversions) { auto *game = bspver->game; if (!game) continue; SUBCASE(bspver->name) { const auto solid = game->create_solid_contents(); const auto solid_detail = game->create_detail_solid_contents(solid); const auto empty = game->create_empty_contents(); auto solid_solid_cluster = game->cluster_contents(solid_detail, solid_detail); CAPTURE(solid_solid_cluster.to_string(game)); CHECK(solid_solid_cluster.is_detail_solid(game)); auto solid_empty_cluster = game->cluster_contents(solid_detail, empty); CAPTURE(solid_empty_cluster.to_string(game)); // it's empty because of the rule that: // - if all leaves in the cluster are solid, it means you can't see in, and there's no visportal // - otherwise, you can see in, and it needs a visportal 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)); } } } TEST_CASE("q1 origin") { auto *game = bspver_q1.game; auto origin = game->face_get_contents("origin", {}, {}); CHECK(origin.is_origin(game)); CHECK(!origin.is_empty(game)); } TEST_CASE("q2 origin") { auto *game = bspver_q2.game; auto origin = game->face_get_contents("", {}, game->create_contents_from_native(Q2_CONTENTS_ORIGIN)); CHECK(origin.is_origin(game)); CHECK(!origin.is_empty(game)); } TEST_CASE("shared content flag tests") { for (auto *bspver : bspversions) { auto *game = bspver->game; if (!game) continue; SUBCASE(bspver->name) { const auto solid = game->create_solid_contents(); const auto detail_solid = game->create_detail_solid_contents(solid); const auto detail_wall = game->create_detail_wall_contents(solid); const auto detail_fence = game->create_detail_fence_contents(solid); const auto detail_illusionary = game->create_detail_illusionary_contents(solid); CAPTURE(solid.to_string(game)); CAPTURE(detail_solid.to_string(game)); CAPTURE(detail_wall.to_string(game)); CAPTURE(detail_fence.to_string(game)); CAPTURE(detail_illusionary.to_string(game)); SUBCASE("is_empty") { CHECK(game->create_empty_contents().is_empty(game)); CHECK(!solid.is_empty(game)); CHECK(!detail_solid.is_empty(game)); CHECK(!detail_wall.is_empty(game)); CHECK(!detail_fence.is_empty(game)); CHECK(!detail_illusionary.is_empty(game)); } SUBCASE("is_any_detail") { CHECK(!solid.is_any_detail(game)); CHECK(detail_solid.is_any_detail(game)); CHECK(detail_wall.is_any_detail(game)); CHECK(detail_fence.is_any_detail(game)); CHECK(detail_illusionary.is_any_detail(game)); } SUBCASE("is_any_solid") { CHECK(solid.is_any_solid(game)); CHECK(detail_solid.is_any_solid(game)); CHECK(!detail_wall.is_any_solid(game)); CHECK(!detail_fence.is_any_solid(game)); CHECK(!detail_illusionary.is_any_solid(game)); } SUBCASE("is_detail_solid") { CHECK(!solid.is_detail_solid(game)); CHECK(detail_solid.is_detail_solid(game)); CHECK(!detail_wall.is_detail_solid(game)); CHECK(!detail_fence.is_detail_solid(game)); CHECK(!detail_illusionary.is_detail_solid(game)); } SUBCASE("is_detail_wall") { CHECK(!solid.is_detail_wall(game)); CHECK(!detail_solid.is_detail_wall(game)); CHECK(detail_wall.is_detail_wall(game)); CHECK(!detail_fence.is_detail_wall(game)); CHECK(!detail_illusionary.is_detail_wall(game)); } SUBCASE("is_detail_fence") { CHECK(!solid.is_detail_fence(game)); CHECK(!detail_solid.is_detail_fence(game)); CHECK(!detail_wall.is_detail_fence(game)); CHECK(detail_fence.is_detail_fence(game)); CHECK(!detail_illusionary.is_detail_fence(game)); } SUBCASE("is_detail_illusionary") { CHECK(!solid.is_detail_illusionary(game)); CHECK(!detail_solid.is_detail_illusionary(game)); CHECK(!detail_wall.is_detail_illusionary(game)); CHECK(!detail_fence.is_detail_illusionary(game)); CHECK(detail_illusionary.is_detail_illusionary(game)); } } } } TEST_CASE("q2 contents") { auto *game_q2 = bspver_q2.game; const std::array test_contents{ game_q2->create_contents_from_native(Q2_CONTENTS_EMPTY), game_q2->create_contents_from_native(Q2_CONTENTS_SOLID), game_q2->create_contents_from_native(Q2_CONTENTS_WINDOW), game_q2->create_contents_from_native(Q2_CONTENTS_AUX), game_q2->create_contents_from_native(Q2_CONTENTS_LAVA), game_q2->create_contents_from_native(Q2_CONTENTS_SLIME), game_q2->create_contents_from_native(Q2_CONTENTS_WATER), game_q2->create_contents_from_native(Q2_CONTENTS_MIST), game_q2->create_contents_from_native(Q2_CONTENTS_DETAIL | Q2_CONTENTS_SOLID), game_q2->create_contents_from_native(Q2_CONTENTS_DETAIL | Q2_CONTENTS_WINDOW), game_q2->create_contents_from_native(Q2_CONTENTS_DETAIL | Q2_CONTENTS_AUX), game_q2->create_contents_from_native(Q2_CONTENTS_DETAIL | Q2_CONTENTS_LAVA), game_q2->create_contents_from_native(Q2_CONTENTS_DETAIL | Q2_CONTENTS_SLIME), game_q2->create_contents_from_native(Q2_CONTENTS_DETAIL | Q2_CONTENTS_WATER), game_q2->create_contents_from_native(Q2_CONTENTS_DETAIL | Q2_CONTENTS_MIST) }; SUBCASE("solid combined with others") { auto solid = game_q2->create_solid_contents(); CHECK(game_q2->contents_to_native(solid) == Q2_CONTENTS_SOLID); for (const auto &c : test_contents) { // solid is treated specially in Q2 and wipes out any other content // flags when combined auto combined = game_q2->contents_remap_for_export( game_q2->combine_contents(solid, c), gamedef_t::remap_type_t::leaf); CHECK(game_q2->contents_to_native(combined) == Q2_CONTENTS_SOLID); CHECK(combined.is_solid(game_q2)); } } SUBCASE("water combined with others") { contentflags_t water = game_q2->create_contents_from_native(Q2_CONTENTS_WATER); for (const auto &c : test_contents) { auto combined = game_q2->combine_contents(water, c); SUBCASE(fmt::format("water combined with {}", c.to_string(game_q2)).c_str()) { if (!(game_q2->contents_to_native(c) & Q2_CONTENTS_SOLID)) { CHECK(game_q2->contents_to_native(combined) == (Q2_CONTENTS_WATER | game_q2->contents_to_native(c))); } } } } } TEST_CASE("q1 contents roundtrip") { auto *game_q1 = bspver_q1.game; for (int i = CONTENTS_EMPTY; i >= CONTENTS_MIN; --i) { contentflags_t test_internal = game_q1->create_contents_from_native(i); uint32_t test_out = game_q1->contents_to_native(test_internal); INFO("contents " << i); CHECK(test_out == i); } } TEST_CASE("q2 contents roundtrip") { auto *game_q2 = bspver_q2.game; CHECK(game_q2->contents_to_native(game_q2->create_contents_from_native(0)) == 0); for (int i = 0; i <= 31; ++i) { uint32_t test_in = nth_bit(i); contentflags_t test_internal = game_q2->create_contents_from_native(test_in); uint32_t test_out = game_q2->contents_to_native(test_internal); INFO("contents bit " << i); CHECK(test_out == test_in); } } TEST_CASE("imglib png loader") { auto *game = bspver_q2.game; auto wal_metadata_path = std::filesystem::path(testmaps_dir) / "q2_wal_metadata"; settings::common_settings settings; settings.paths.add_value(wal_metadata_path.string(), settings::source::COMMANDLINE); game->init_filesystem("placeholder.map", settings); auto [texture, resolve, data] = img::load_texture("e1u1/yellow32x32", false, game, settings); REQUIRE(texture); CHECK(texture->meta.name == "e1u1/yellow32x32"); CHECK(texture->meta.width == 32); CHECK(texture->meta.height == 32); CHECK(texture->meta.extension.value() == img::ext::STB); CHECK(!texture->meta.color_override); CHECK(texture->width == 32); CHECK(texture->height == 32); CHECK(texture->width_scale == 1); CHECK(texture->height_scale == 1); } } TEST_SUITE("qmat") { TEST_CASE("transpose") { // clang-format off auto in = qmat::row_major( {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}); auto exp = qmat::row_major( {1.0, 4.0, 2.0, 5.0, 3.0, 6.0}); // clang-format on CHECK(in.transpose() == exp); } }