feat: WOM renderable batches, JSON DBC test coverage

- WOM→M2 conversion now creates proper render batch (indexStart,
  indexCount, vertexStart, vertexCount), texture references, material
  with opaque blend mode — WOM models are now actually visible in the
  client renderer instead of being invisible geometry-only shells
- 5 new JSON DBC test cases: basic load with strings/ints, float values,
  empty records rejection, missing records key rejection, findRecordById
  lookup across 3 records
- Total: 278 assertions across 80 test cases, all passing
This commit is contained in:
Kelsi 2026-05-05 15:03:01 -07:00
parent 47eff19cb6
commit ad67700cb6
2 changed files with 100 additions and 0 deletions

View file

@ -479,6 +479,34 @@ std::shared_ptr<PendingTile> TerrainManager::prepareTile(int x, int y) {
for (uint32_t idx : wom.indices)
m2Model.indices.push_back(static_cast<uint16_t>(idx));
// Set up textures from WOM paths
for (const auto& texPath : wom.texturePaths) {
pipeline::M2Texture tex;
tex.type = 0;
tex.flags = 0;
tex.filename = texPath;
m2Model.textures.push_back(tex);
}
m2Model.textureLookup = {0};
// Create default render batch covering all geometry
pipeline::M2Batch batch{};
batch.flags = 0;
batch.shader = 0;
batch.textureCount = std::min(1u, static_cast<uint32_t>(wom.texturePaths.size()));
batch.textureIndex = 0;
batch.indexStart = 0;
batch.indexCount = static_cast<uint32_t>(m2Model.indices.size());
batch.vertexStart = 0;
batch.vertexCount = static_cast<uint32_t>(m2Model.vertices.size());
m2Model.batches.push_back(batch);
// Default opaque material
pipeline::M2Material mat;
mat.flags = 0;
mat.blendMode = 0;
m2Model.materials.push_back(mat);
pending->m2Models.push_back({modelId, std::move(m2Model), {}});
preparedModelIds.insert(modelId);
LOG_INFO("Loaded WOM model: ", womPath);

View file

@ -206,3 +206,75 @@ TEST_CASE("DBCFile getStringByOffset", "[dbc]") {
REQUIRE(dbc.getStringByOffset(1) == "Offset5");
REQUIRE(dbc.getStringByOffset(0).empty());
}
// ============== JSON DBC Tests ==============
static std::vector<uint8_t> buildJsonDBC(const std::string& json) {
return std::vector<uint8_t>(json.begin(), json.end());
}
TEST_CASE("JSON DBC basic load", "[dbc][json]") {
auto data = buildJsonDBC(R"({
"format": "wowee-dbc-json-1.0",
"fieldCount": 3,
"recordCount": 2,
"records": [
[1, "Fireball", 100],
[2, "Frostbolt", 200]
]
})");
DBCFile dbc;
REQUIRE(dbc.load(data));
REQUIRE(dbc.getRecordCount() == 2);
REQUIRE(dbc.getFieldCount() == 3);
REQUIRE(dbc.getUInt32(0, 0) == 1);
REQUIRE(dbc.getString(0, 1) == "Fireball");
REQUIRE(dbc.getUInt32(0, 2) == 100);
REQUIRE(dbc.getUInt32(1, 0) == 2);
REQUIRE(dbc.getString(1, 1) == "Frostbolt");
REQUIRE(dbc.getUInt32(1, 2) == 200);
}
TEST_CASE("JSON DBC with float values", "[dbc][json]") {
auto data = buildJsonDBC(R"({
"fieldCount": 2,
"records": [
[1, 3.14]
]
})");
DBCFile dbc;
REQUIRE(dbc.load(data));
REQUIRE(dbc.getUInt32(0, 0) == 1);
REQUIRE(dbc.getFloat(0, 1) == Catch::Approx(3.14f).margin(0.01f));
}
TEST_CASE("JSON DBC empty records", "[dbc][json]") {
auto data = buildJsonDBC(R"({"records": []})");
DBCFile dbc;
REQUIRE_FALSE(dbc.load(data));
}
TEST_CASE("JSON DBC missing records key", "[dbc][json]") {
auto data = buildJsonDBC(R"({"format": "test"})");
DBCFile dbc;
REQUIRE_FALSE(dbc.load(data));
}
TEST_CASE("JSON DBC findRecordById", "[dbc][json]") {
auto data = buildJsonDBC(R"({
"fieldCount": 2,
"records": [
[10, "Alpha"],
[20, "Beta"],
[30, "Gamma"]
]
})");
DBCFile dbc;
REQUIRE(dbc.load(data));
REQUIRE(dbc.findRecordById(20) == 1);
REQUIRE(dbc.findRecordById(30) == 2);
REQUIRE(dbc.findRecordById(99) == -1);
}