diff --git a/common/imglib.cc b/common/imglib.cc index 4b4079b0..39733168 100644 --- a/common/imglib.cc +++ b/common/imglib.cc @@ -331,8 +331,10 @@ std::tuple, fs::resolve_result, fs::data> load_textu { fs::path prefix{}; - if (!no_prefix && game->id == GAME_QUAKE_II) { - prefix = "textures"; + if (!no_prefix) { + if (game->id == GAME_QUAKE_II || !mip_only) { + prefix = "textures"; + } } std::vector exts; diff --git a/qbsp/qbsp.cc b/qbsp/qbsp.cc index 61d8422d..33dec578 100644 --- a/qbsp/qbsp.cc +++ b/qbsp/qbsp.cc @@ -1540,7 +1540,10 @@ static void LoadTextureData() miptex.name = map.miptex[i].name; { - auto [tex, pos, file] = img::load_texture(map.miptex[i].name, true, qbsp_options.target_game, qbsp_options, false, true); + // i.e. only allow loose (non-.wad) textures if -notex is in use + const bool mip_only = !qbsp_options.notextures.value(); + + auto [tex, pos, file] = img::load_texture(map.miptex[i].name, true, qbsp_options.target_game, qbsp_options, false, mip_only); if (!tex) { if (pos.archive) { diff --git a/testmaps/q1_loose_textures.map b/testmaps/q1_loose_textures.map new file mode 100644 index 00000000..b37cd362 --- /dev/null +++ b/testmaps/q1_loose_textures.map @@ -0,0 +1,67 @@ +// Game: Generic +// Format: Standard +// entity 0 +{ +"classname" "worldspawn" +"_tb_textures" "textures" +// brush 0 +{ +( -64 -64 -16 ) ( -64 -63 -16 ) ( -64 -64 -15 ) floor_purple_c 0 0 0 1 1 +( -64 -224 -16 ) ( -64 -224 -15 ) ( -63 -224 -16 ) floor_purple_c 0 0 0 1 1 +( -64 -64 -16 ) ( -63 -64 -16 ) ( -64 -63 -16 ) floor_purple_c 0 0 0 1 1 +( 64 64 16 ) ( 64 65 16 ) ( 65 64 16 ) floor_purple_c 0 0 0 1 1 +( 64 64 16 ) ( 65 64 16 ) ( 64 64 17 ) floor_purple_c 0 0 0 1 1 +( 304 64 16 ) ( 304 64 17 ) ( 304 65 16 ) floor_purple_c 0 0 0 1 1 +} +// brush 1 +{ +( -80 -64 -32 ) ( -80 -63 -32 ) ( -80 -64 -31 ) wall_tan_a 0 -16 0 1 1 +( -64 -224 -32 ) ( -64 -224 -31 ) ( -63 -224 -32 ) wall_tan_a 0 -16 0 1 1 +( -64 -64 16 ) ( -63 -64 16 ) ( -64 -63 16 ) wall_tan_a 0 0 0 1 1 +( 64 64 144 ) ( 64 65 144 ) ( 65 64 144 ) wall_tan_a 0 0 0 1 1 +( 64 64 0 ) ( 65 64 0 ) ( 64 64 1 ) wall_tan_a 0 -16 0 1 1 +( -64 -64 -32 ) ( -64 -64 -31 ) ( -64 -63 -32 ) wall_tan_a 0 -16 0 1 1 +} +// brush 2 +{ +( -80 -64 -32 ) ( -80 -63 -32 ) ( -80 -64 -31 ) wall_tan_a 0 -16 0 1 1 +( 64 64 0 ) ( 64 64 1 ) ( 65 64 0 ) wall_tan_a 0 -16 0 1 1 +( -64 -64 16 ) ( -63 -64 16 ) ( -64 -63 16 ) wall_tan_a 0 0 0 1 1 +( 64 64 144 ) ( 64 65 144 ) ( 65 64 144 ) wall_tan_a 0 0 0 1 1 +( 64 80 0 ) ( 65 80 0 ) ( 64 80 1 ) wall_tan_a 0 -16 0 1 1 +( 304 -64 -32 ) ( 304 -64 -31 ) ( 304 -63 -32 ) wall_tan_a 0 -16 0 1 1 +} +// brush 3 +{ +( 304 -64 -32 ) ( 304 -63 -32 ) ( 304 -64 -31 ) wall_tan_a 0 -16 0 1 1 +( 64 -224 0 ) ( 64 -224 1 ) ( 65 -224 0 ) wall_tan_a 0 -16 0 1 1 +( -64 -64 16 ) ( -63 -64 16 ) ( -64 -63 16 ) wall_tan_a 0 0 0 1 1 +( 64 64 144 ) ( 64 65 144 ) ( 65 64 144 ) wall_tan_a 0 0 0 1 1 +( 64 80 0 ) ( 65 80 0 ) ( 64 80 1 ) wall_tan_a 0 -16 0 1 1 +( 320 -64 -32 ) ( 320 -64 -31 ) ( 320 -63 -32 ) wall_tan_a 0 -16 0 1 1 +} +// brush 4 +{ +( -64 -64 -32 ) ( -64 -63 -32 ) ( -64 -64 -31 ) wall_tan_a 0 -16 0 1 1 +( 64 -240 0 ) ( 64 -240 1 ) ( 65 -240 0 ) wall_tan_a 0 -16 0 1 1 +( -64 -64 16 ) ( -63 -64 16 ) ( -64 -63 16 ) wall_tan_a 0 0 0 1 1 +( 64 64 144 ) ( 64 65 144 ) ( 65 64 144 ) wall_tan_a 0 0 0 1 1 +( 64 -224 0 ) ( 65 -224 0 ) ( 64 -224 1 ) wall_tan_a 0 -16 0 1 1 +( 320 -64 -32 ) ( 320 -64 -31 ) ( 320 -63 -32 ) wall_tan_a 0 -16 0 1 1 +} +// brush 5 +{ +( -64 -64 144 ) ( -64 -63 144 ) ( -64 -64 145 ) floor_purple_c 0 -32 0 1 1 +( -64 -224 144 ) ( -64 -224 145 ) ( -63 -224 144 ) floor_purple_c 0 -32 0 1 1 +( -64 -64 144 ) ( -63 -64 144 ) ( -64 -63 144 ) floor_purple_c 0 0 0 1 1 +( 64 64 176 ) ( 64 65 176 ) ( 65 64 176 ) floor_purple_c 0 0 0 1 1 +( 64 64 176 ) ( 65 64 176 ) ( 64 64 177 ) floor_purple_c 0 -32 0 1 1 +( 304 64 176 ) ( 304 64 177 ) ( 304 65 176 ) floor_purple_c 0 -32 0 1 1 +} +} +// entity 1 +{ +"classname" "info_player_start" +"origin" "224 -144 40" +"angle" "180" +} diff --git a/testmaps/q1_loose_textures/textures/floor_purple_c.png b/testmaps/q1_loose_textures/textures/floor_purple_c.png new file mode 100644 index 00000000..9954d687 Binary files /dev/null and b/testmaps/q1_loose_textures/textures/floor_purple_c.png differ diff --git a/testmaps/q1_loose_textures/textures/lq_dev_readme.txt b/testmaps/q1_loose_textures/textures/lq_dev_readme.txt new file mode 100644 index 00000000..59c7775b --- /dev/null +++ b/testmaps/q1_loose_textures/textures/lq_dev_readme.txt @@ -0,0 +1,5 @@ +everything in lq_dev/ is under the cc0 licence + +love + +-misslavender \ No newline at end of file diff --git a/testmaps/q1_loose_textures/textures/wall_tan_a.png b/testmaps/q1_loose_textures/textures/wall_tan_a.png new file mode 100644 index 00000000..40963cde Binary files /dev/null and b/testmaps/q1_loose_textures/textures/wall_tan_a.png differ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cca831e6..35225455 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -27,7 +27,7 @@ if (NOT EMBREE_TBB_DLL STREQUAL EMBREE_TBB_DLL-NOTFOUND) message(STATUS "Found embree EMBREE_TBB_DLL: ${EMBREE_TBB_DLL}") endif() -target_link_libraries(tests libqbsp liblight libvis libbsputil common TBB::tbb TBB::tbbmalloc GTest::gtest fmt::fmt nanobench::nanobench) +target_link_libraries(tests libqbsp liblight libvis libbsputil common TBB::tbb TBB::tbbmalloc GTest::gtest GTest::gmock fmt::fmt nanobench::nanobench) # HACK: copy .dll dependencies add_custom_command(TARGET tests POST_BUILD diff --git a/tests/test_qbsp.cc b/tests/test_qbsp.cc index e18b0552..6ee9e308 100644 --- a/tests/test_qbsp.cc +++ b/tests/test_qbsp.cc @@ -14,12 +14,14 @@ #include #include +#include #include #include #include #include #include #include +#include #include "testutils.hh" #include "test_main.hh" @@ -102,14 +104,18 @@ std::tuple> LoadTestmap( auto wal_metadata_path = std::filesystem::path(testmaps_dir) / "q2_wal_metadata"; - std::vector args{"", // the exe path, which we're ignoring in this case - "-path", wal_metadata_path.string()}; + std::vector args{""}; // the exe path, which we're ignoring in this case + if (std::ranges::find(extra_args, "-path") == extra_args.end()) { + extra_args.push_back("-path"); + extra_args.push_back(wal_metadata_path.string()); + } if (!tests_verbose) { args.push_back("-noverbose"); } else { args.push_back("-nopercent"); args.push_back("-loghulls"); + args.push_back("-verbose"); } for (auto &arg : extra_args) { @@ -1576,6 +1582,42 @@ TEST(testmapsQ1, wadExternal) EXPECT_EQ(bsp.dtex.textures[3].data.size(), sizeof(dmiptex_t)); } +TEST(testmapsQ1, looseTextures) +{ + SCOPED_TRACE("loose textures are only loaded when -notex is in use"); + + auto q1_loose_textures_path = std::filesystem::path(testmaps_dir) / "q1_loose_textures"; + + const auto [bsp, bspx, prt] = LoadTestmapQ1("q1_loose_textures.map", + {"-path", q1_loose_textures_path.string(), "-notex"}); + + EXPECT_EQ(GAME_QUAKE, bsp.loadversion->game->id); + + // FIXME: we shouldn't really write out skip + const miptex_t &skip = bsp.dtex.textures[0]; + EXPECT_EQ(skip.name, ""); + EXPECT_TRUE(skip.null_texture); + EXPECT_EQ(skip.width, 0); + EXPECT_EQ(skip.height, 0); + EXPECT_EQ(skip.data.size(), 0); + + const miptex_t &floor_purple_c = bsp.dtex.textures[1]; + EXPECT_EQ(floor_purple_c.name, "floor_purple_c"); + EXPECT_FALSE(floor_purple_c.null_texture); + EXPECT_EQ(floor_purple_c.width, 64); + EXPECT_EQ(floor_purple_c.height, 64); + EXPECT_EQ(floor_purple_c.data.size(), sizeof(dmiptex_t)); + EXPECT_THAT(floor_purple_c.offsets, testing::ElementsAre(0, 0, 0, 0)); + + const miptex_t &wall_tan_a = bsp.dtex.textures[2]; + EXPECT_EQ(wall_tan_a.name, "wall_tan_a"); + EXPECT_FALSE(wall_tan_a.null_texture); + EXPECT_EQ(wall_tan_a.width, 64); + EXPECT_EQ(wall_tan_a.height, 64); + EXPECT_EQ(wall_tan_a.data.size(), sizeof(dmiptex_t)); + EXPECT_THAT(wall_tan_a.offsets, testing::ElementsAre(0, 0, 0, 0)); +} + TEST(testmapsQ1, looseTexturesIgnored) { SCOPED_TRACE("q1 should only load textures from .wad's. loose textures should not be included.");