From 19e479a8ff9a43e8421b55cc31f417a749734707 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 07:21:20 -0700 Subject: [PATCH] test(open-formats): add WOB doodad NaN scrub test Verifies the recent WOB doodad-transform sanitize. A WOB with NaN position/rotation/scale on a doodad should load with the doodad zeroed out (position/rotation 0, scale 1). Prevents regressing the GPU crash that NaN model matrices would cause. --- tests/test_open_formats.cpp | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/test_open_formats.cpp b/tests/test_open_formats.cpp index cdeed1ee..70d87262 100644 --- a/tests/test_open_formats.cpp +++ b/tests/test_open_formats.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include using namespace wowee::pipeline; @@ -611,6 +613,46 @@ TEST_CASE("WOC rejects absurdly large triangle counts", "[woc][hardening]") { std::filesystem::remove(path); } +TEST_CASE("WOB scrubs NaN doodad transform on load", "[wob][hardening]") { + ensureTestDir(); + std::string base = TEST_DIR + "/nan_doodad"; + std::string path = base + ".wob"; + { + std::ofstream f(path, std::ios::binary); + uint32_t magic = 0x31424F57; // "WOB1" + uint32_t gc = 0, pc = 0, dc = 1; + float boundRadius = 5.0f; + f.write(reinterpret_cast(&magic), 4); + f.write(reinterpret_cast(&gc), 4); + f.write(reinterpret_cast(&pc), 4); + f.write(reinterpret_cast(&dc), 4); + f.write(reinterpret_cast(&boundRadius), 4); + // Empty name string + uint16_t nameLen = 0; + f.write(reinterpret_cast(&nameLen), 2); + // Doodad with NaN position/rotation/scale + std::string mp = "Tree.wom"; + uint16_t mpLen = static_cast(mp.size()); + f.write(reinterpret_cast(&mpLen), 2); + f.write(mp.data(), mpLen); + float nan = std::numeric_limits::quiet_NaN(); + glm::vec3 nanv(nan, nan, nan); + f.write(reinterpret_cast(&nanv), 12); + f.write(reinterpret_cast(&nanv), 12); + f.write(reinterpret_cast(&nan), 4); + } + + auto bld = WoweeBuildingLoader::load(base); + // isValid requires a group — we deliberately wrote 0 groups to keep + // the test fixture small. Just check the doodad got loaded + scrubbed. + REQUIRE(bld.doodads.size() == 1); + REQUIRE(std::isfinite(bld.doodads[0].position.x)); + REQUIRE(bld.doodads[0].position == glm::vec3(0, 0, 0)); + REQUIRE(bld.doodads[0].rotation == glm::vec3(0, 0, 0)); + REQUIRE(bld.doodads[0].scale == 1.0f); + std::filesystem::remove(path); +} + TEST_CASE("WOC clamps out-of-range tile coords on load", "[woc][hardening]") { ensureTestDir(); std::string path = TEST_DIR + "/oor_tile_woc.woc";