qbsp: add -missing_textures_as_zero_size flag to allow writing 0x0 textures when a texture is missing

this allows us to write the texture name, but it's non-standard.

light: warn when a surface light template doesn't match any faces in the bsp
This commit is contained in:
Eric Wasylishen 2023-12-21 00:05:40 -07:00
parent c62633f1a3
commit f0c8d92993
6 changed files with 47 additions and 3 deletions

3
.gitignore vendored
View File

@ -28,7 +28,8 @@ testmaps/quake_map_source/*.prt
testmaps/quake_map_source/*.pts
testmaps/quake_map_source/*.vis
testmaps/quake_map_source/*.texinfo
testmaps/quake_map_source/*.bsp.json
testmaps/quake_map_source/*.json
testmaps/quake_map_source/*.obj
**/autosave
CMakeSettings.json
sphinx-venv

View File

@ -195,7 +195,7 @@ void dmiptexlump_t::stream_write(std::ostream &stream) const
// write out the miptex offsets
for (auto &texture : textures) {
if (!texture.name[0] || texture.width == 0 || texture.height == 0) {
if (texture.null_texture) {
// dummy texture
stream <= static_cast<int32_t>(-1);
continue;
@ -213,7 +213,7 @@ void dmiptexlump_t::stream_write(std::ostream &stream) const
}
for (auto &texture : textures) {
if (texture.name[0] && texture.width && texture.height) {
if (!texture.null_texture) {
// fix up the padding to match the above conditions
if (stream.tellp() % 4) {
constexpr const char pad[4]{};

View File

@ -187,6 +187,7 @@ public:
setting_invertible_bool transwater;
setting_bool transsky;
setting_bool notextures;
setting_bool missing_textures_as_zero_size;
setting_enum<conversion_t> convertmapformat;
setting_invertible_bool oldaxis;
setting_bool forcegoodtree;

View File

@ -1511,6 +1511,15 @@ static void MakeSurfaceLights(const mbsp_t *bsp)
logging::print("Creating surface lights for texture \"{}\" from template at ({})\n", tex,
entity->epairs->get("origin"));
// Warning if no faces exist matching the texture
const bool found_face = std::any_of(bsp->dfaces.begin(), bsp->dfaces.end(), [&](const mface_t &face) -> bool {
return !Q_strcasecmp(Face_TextureName(bsp, &face), entity->epairs->get("_surface"));
});
if (!found_face) {
logging::print("WARNING: no faces found with texture {} (qbsp may have been run with .wad's missing?)\n",
entity->epairs->get("_surface"));
}
}
}

View File

@ -479,6 +479,8 @@ qbsp_settings::qbsp_settings()
transsky{this, "transsky", false, &map_development_group, "compute portal information for transparent sky"},
notextures{this, "notex", false, &common_format_group,
"write only placeholder textures to depend upon replacements, keep file sizes down, or to skirt copyrights"},
missing_textures_as_zero_size{this, "missing_textures_as_zero_size", false, &common_format_group,
"write missing textures as 0x0"},
convertmapformat{this, "convert", conversion_t::none,
{{"quake", conversion_t::quake}, {"quake2", conversion_t::quake2}, {"valve", conversion_t::valve},
{"bp", conversion_t::bp}},
@ -1539,6 +1541,15 @@ static void LoadTextureData()
header.height = miptex.height;
header.offsets = {0, 0, 0, 0};
if (!miptex.name[0])
miptex.null_texture = true;
if (!qbsp_options.missing_textures_as_zero_size.value()) {
if (miptex.width == 0 || miptex.height == 0) {
miptex.null_texture = true;
}
}
omemstream stream(miptex.data.data(), miptex.data.size());
stream <= header;
}

View File

@ -1969,6 +1969,28 @@ TEST_CASE("q1_missing_texture")
CHECK(6 == bsp.dfaces.size());
}
TEST_CASE("q1_missing_texture, -missing_textures_as_zero_size")
{
const auto [bsp, bspx, prt] = LoadTestmap("q1_missing_texture.map", {"-missing_textures_as_zero_size"});
REQUIRE(2 == bsp.dtex.textures.size());
// FIXME: we shouldn't really be writing skip
// (our test data includes an actual "skip" texture,
// so that gets included in the bsp.)
CHECK("skip" == bsp.dtex.textures[0].name);
CHECK(!bsp.dtex.textures[0].null_texture);
CHECK(64 == bsp.dtex.textures[0].width);
CHECK(64 == bsp.dtex.textures[0].height);
CHECK("somemissingtext" == bsp.dtex.textures[1].name);
CHECK(!bsp.dtex.textures[1].null_texture);
CHECK(0 == bsp.dtex.textures[1].width);
CHECK(0 == bsp.dtex.textures[1].height);
CHECK(6 == bsp.dfaces.size());
}
TEST_CASE("q1 notex")
{
const auto [bsp, bspx, prt] = LoadTestmap("q1_cube.map", {"-notex"});