mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-07 09:33:51 +00:00
feat(editor): add --diff-wom completing the diff suite for models
Structural compare of two WOM models. Useful for verifying that
--migrate-wom or a round-trip through OBJ/glTF/STL preserved the
right counts:
wowee_editor --diff-wom orig back
Diff: orig.wom vs back.wom
a b
version : 1 1
vertices : 5 5
indices : 18 18
triangles : 6 6
textures : 0 0
bones : 0 0
animations : 0 0
batches : 0 0
name : Pyramid Pyramid
bounds : match
IDENTICAL
Compares sizes only (vertex / index / bone / animation / batch /
texture counts) plus name and bounds. Bounds match-with-epsilon
(0.01 unit slop, generous since positions are typically yards) so
text-format round-trips that perturb the last bit don't false-flag.
Pointwise vertex compare is intentionally not done — it would be
O(n²) and brittle to tiny float diffs from format conversions.
Diff family is now complete:
--diff-wcp (archive vs archive)
--diff-zone (unpacked zone dir vs zone dir)
--diff-glb (glTF binary vs glTF binary)
--diff-wom (WOM model vs WOM model)
Verified: identical pair reports IDENTICAL exit 0; pair with 1 extra
vertex + extra triangle + name change correctly reports 4 DIFFs
(verts/indices/triangles/name) with exit 1.
This commit is contained in:
parent
468a1b8ede
commit
8dc91adc52
1 changed files with 98 additions and 0 deletions
|
|
@ -598,6 +598,8 @@ static void printUsage(const char* argv0) {
|
|||
std::printf(" Compare two zone dirs (creatures/objects/quests/manifest); exit 0 if identical\n");
|
||||
std::printf(" --diff-glb <a> <b> [--json]\n");
|
||||
std::printf(" Compare two glTF 2.0 binaries structurally; exit 0 if identical\n");
|
||||
std::printf(" --diff-wom <a-base> <b-base> [--json]\n");
|
||||
std::printf(" Compare two WOM models (verts, indices, bones, anims, batches, bounds)\n");
|
||||
std::printf(" --pack-wcp <zone> [dst] Pack a zone dir/name into a .wcp archive and exit\n");
|
||||
std::printf(" --unpack-wcp <wcp> [dst] Extract a WCP archive (default dst=custom_zones/) and exit\n");
|
||||
std::printf(" --list-commands Print every recognized --flag, one per line, and exit\n");
|
||||
|
|
@ -674,6 +676,11 @@ int main(int argc, char* argv[]) {
|
|||
"--diff-glb requires <a.glb> <b.glb>\n");
|
||||
return 1;
|
||||
}
|
||||
if (std::strcmp(argv[i], "--diff-wom") == 0 && i + 2 >= argc) {
|
||||
std::fprintf(stderr,
|
||||
"--diff-wom requires <a-base> <b-base>\n");
|
||||
return 1;
|
||||
}
|
||||
if (std::strcmp(argv[i], "--diff-wcp") == 0 && i + 2 >= argc) {
|
||||
std::fprintf(stderr, "--diff-wcp requires two paths\n");
|
||||
return 1;
|
||||
|
|
@ -2821,6 +2828,97 @@ int main(int argc, char* argv[]) {
|
|||
return 0;
|
||||
}
|
||||
return 1;
|
||||
} else if (std::strcmp(argv[i], "--diff-wom") == 0 && i + 2 < argc) {
|
||||
// Structural compare of two WOM models. Useful for verifying
|
||||
// that a --migrate-wom or round-trip through OBJ/glTF/STL
|
||||
// preserved the right counts. Compares sizes only — point-
|
||||
// wise vertex compare would be O(n²) and brittle to minor
|
||||
// float diffs from format conversions.
|
||||
std::string aBase = argv[++i];
|
||||
std::string bBase = argv[++i];
|
||||
bool jsonOut = (i + 1 < argc &&
|
||||
std::strcmp(argv[i + 1], "--json") == 0);
|
||||
if (jsonOut) i++;
|
||||
for (auto* base : {&aBase, &bBase}) {
|
||||
if (base->size() >= 4 &&
|
||||
base->substr(base->size() - 4) == ".wom") {
|
||||
*base = base->substr(0, base->size() - 4);
|
||||
}
|
||||
}
|
||||
for (const auto& base : {aBase, bBase}) {
|
||||
if (!wowee::pipeline::WoweeModelLoader::exists(base)) {
|
||||
std::fprintf(stderr,
|
||||
"diff-wom: WOM not found: %s.wom\n", base.c_str());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
auto a = wowee::pipeline::WoweeModelLoader::load(aBase);
|
||||
auto b = wowee::pipeline::WoweeModelLoader::load(bBase);
|
||||
// Each row is (label, a-value, b-value) so the table renders
|
||||
// straight.
|
||||
struct Row {
|
||||
const char* label;
|
||||
long long av, bv;
|
||||
};
|
||||
std::vector<Row> rows = {
|
||||
{"version", a.version, b.version},
|
||||
{"vertices", (long long)a.vertices.size(), (long long)b.vertices.size()},
|
||||
{"indices", (long long)a.indices.size(), (long long)b.indices.size()},
|
||||
{"triangles", (long long)(a.indices.size()/3),(long long)(b.indices.size()/3)},
|
||||
{"textures", (long long)a.texturePaths.size(),(long long)b.texturePaths.size()},
|
||||
{"bones", (long long)a.bones.size(), (long long)b.bones.size()},
|
||||
{"animations",(long long)a.animations.size(),(long long)b.animations.size()},
|
||||
{"batches", (long long)a.batches.size(), (long long)b.batches.size()},
|
||||
};
|
||||
// Bounds compare with float epsilon since round-trips through
|
||||
// text formats can perturb the last bit. 0.01-unit slop is
|
||||
// generous (positions are typically in yards, ~1m).
|
||||
auto closeBounds = [](const glm::vec3& x, const glm::vec3& y) {
|
||||
return std::abs(x.x - y.x) < 0.01f &&
|
||||
std::abs(x.y - y.y) < 0.01f &&
|
||||
std::abs(x.z - y.z) < 0.01f;
|
||||
};
|
||||
bool boundsMatch = closeBounds(a.boundMin, b.boundMin) &&
|
||||
closeBounds(a.boundMax, b.boundMax) &&
|
||||
std::abs(a.boundRadius - b.boundRadius) < 0.01f;
|
||||
int diffs = 0;
|
||||
for (const auto& r : rows) if (r.av != r.bv) diffs++;
|
||||
if (!boundsMatch) diffs++;
|
||||
bool nameMatch = (a.name == b.name);
|
||||
if (!nameMatch) diffs++;
|
||||
if (jsonOut) {
|
||||
nlohmann::json j;
|
||||
j["a"] = aBase + ".wom";
|
||||
j["b"] = bBase + ".wom";
|
||||
for (const auto& r : rows) {
|
||||
j[r.label] = {{"a", r.av}, {"b", r.bv}};
|
||||
}
|
||||
j["name"] = {{"a", a.name}, {"b", b.name}};
|
||||
j["boundsMatch"] = boundsMatch;
|
||||
j["totalDiffs"] = diffs;
|
||||
j["identical"] = (diffs == 0);
|
||||
std::printf("%s\n", j.dump(2).c_str());
|
||||
return diffs == 0 ? 0 : 1;
|
||||
}
|
||||
std::printf("Diff: %s.wom vs %s.wom\n", aBase.c_str(), bBase.c_str());
|
||||
std::printf(" a b\n");
|
||||
for (const auto& r : rows) {
|
||||
std::printf(" %-12s: %12lld %12lld %s\n",
|
||||
r.label, r.av, r.bv,
|
||||
r.av == r.bv ? "" : "DIFF");
|
||||
}
|
||||
std::printf(" %-12s: %-13s %-13s %s\n",
|
||||
"name",
|
||||
a.name.substr(0, 13).c_str(),
|
||||
b.name.substr(0, 13).c_str(),
|
||||
nameMatch ? "" : "DIFF");
|
||||
std::printf(" %-12s: %s\n", "bounds",
|
||||
boundsMatch ? "match" : "DIFF");
|
||||
if (diffs == 0) {
|
||||
std::printf(" IDENTICAL\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
} else if (std::strcmp(argv[i], "--list-wcp") == 0 && i + 1 < argc) {
|
||||
// Like --info-wcp but prints every file path. Useful for spotting
|
||||
// missing or unexpected entries before unpacking.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue