mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-08 10:03:51 +00:00
feat(editor): add --center-mesh and --flip-mesh-normals quick fixes
Two convenience commands for the common "fix imported mesh" cases: --center-mesh <wom-base> Translates the mesh so the bounds center lands at the origin. Useful when an OBJ comes in with its pivot in some weird corner and the user wants center-pivoted placement. Pure translation — shape unchanged, radius preserved. --flip-mesh-normals <wom-base> Inverts every vertex normal. Use case: an OBJ with flipped winding renders inside-out — flipping normals fixes shading without re-winding the index buffer (which would also need batch-aware care). Also useful for skybox-like inside-facing meshes. Verified: cube translated to (5,0,0) → center brings it back to ±0.5 with shift line "(-5, -0, -0)" reported; flip reports 24 vertices touched. Brings command count to 221 (kArgRequired 202).
This commit is contained in:
parent
488fbda0d4
commit
2cb079549e
1 changed files with 78 additions and 0 deletions
|
|
@ -548,6 +548,10 @@ static void printUsage(const char* argv0) {
|
|||
std::printf(" Drop bones / animations from a WOM in place (smaller file, static-only use)\n");
|
||||
std::printf(" --rotate-mesh <wom-base> <x|y|z> <degrees>\n");
|
||||
std::printf(" Rotate every vertex + normal around the chosen axis by <degrees>\n");
|
||||
std::printf(" --center-mesh <wom-base>\n");
|
||||
std::printf(" Translate so the bounds center lands at origin (no scale/rotation change)\n");
|
||||
std::printf(" --flip-mesh-normals <wom-base>\n");
|
||||
std::printf(" Invert every vertex normal (use for inside-out meshes or two-sided pre-flip)\n");
|
||||
std::printf(" --add-item <zoneDir> <name> [id] [quality] [displayId] [itemLevel]\n");
|
||||
std::printf(" Append one item entry to <zoneDir>/items.json (auto-creates the file)\n");
|
||||
std::printf(" --list-items <zoneDir> [--json]\n");
|
||||
|
|
@ -965,6 +969,7 @@ int main(int argc, char* argv[]) {
|
|||
"--gen-mesh-stairs", "--gen-texture-gradient",
|
||||
"--scale-mesh", "--translate-mesh", "--strip-mesh",
|
||||
"--gen-texture-noise", "--rotate-mesh",
|
||||
"--center-mesh", "--flip-mesh-normals",
|
||||
"--validate-glb", "--info-glb", "--info-glb-tree", "--info-glb-bytes",
|
||||
"--validate-jsondbc", "--check-glb-bounds", "--validate-stl",
|
||||
"--validate-png", "--validate-blp",
|
||||
|
|
@ -16483,6 +16488,79 @@ int main(int argc, char* argv[]) {
|
|||
wom.boundMin.x, wom.boundMin.y, wom.boundMin.z,
|
||||
wom.boundMax.x, wom.boundMax.y, wom.boundMax.z);
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--center-mesh") == 0 && i + 1 < argc) {
|
||||
// Translate the mesh so the bounds center lands at the
|
||||
// origin. Convenience for "this mesh's pivot is in some
|
||||
// weird corner — make it center-pivoted." Doesn't change
|
||||
// shape, just shifts.
|
||||
std::string womBase = argv[++i];
|
||||
if (womBase.size() >= 4 &&
|
||||
womBase.substr(womBase.size() - 4) == ".wom") {
|
||||
womBase = womBase.substr(0, womBase.size() - 4);
|
||||
}
|
||||
if (!wowee::pipeline::WoweeModelLoader::exists(womBase)) {
|
||||
std::fprintf(stderr,
|
||||
"center-mesh: %s.wom does not exist\n", womBase.c_str());
|
||||
return 1;
|
||||
}
|
||||
auto wom = wowee::pipeline::WoweeModelLoader::load(womBase);
|
||||
if (!wom.isValid()) {
|
||||
std::fprintf(stderr,
|
||||
"center-mesh: failed to load %s.wom\n", womBase.c_str());
|
||||
return 1;
|
||||
}
|
||||
glm::vec3 center = (wom.boundMin + wom.boundMax) * 0.5f;
|
||||
for (auto& v : wom.vertices) v.position -= center;
|
||||
for (auto& b : wom.bones) b.pivot -= center;
|
||||
wom.boundMin -= center;
|
||||
wom.boundMax -= center;
|
||||
// Radius is preserved (pure translation).
|
||||
if (!wowee::pipeline::WoweeModelLoader::save(wom, womBase)) {
|
||||
std::fprintf(stderr,
|
||||
"center-mesh: failed to save %s.wom\n", womBase.c_str());
|
||||
return 1;
|
||||
}
|
||||
std::printf("Centered %s.wom (shifted by %g, %g, %g)\n",
|
||||
womBase.c_str(), -center.x, -center.y, -center.z);
|
||||
std::printf(" new bounds : (%.3f, %.3f, %.3f) - (%.3f, %.3f, %.3f)\n",
|
||||
wom.boundMin.x, wom.boundMin.y, wom.boundMin.z,
|
||||
wom.boundMax.x, wom.boundMax.y, wom.boundMax.z);
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--flip-mesh-normals") == 0 && i + 1 < argc) {
|
||||
// Invert every vertex normal. Use case: an OBJ imported
|
||||
// with flipped winding renders inside-out — flipping the
|
||||
// normals makes shading correct without re-winding the
|
||||
// index buffer (which would also need batch-aware care).
|
||||
// Also useful for skybox-like meshes where the "outside"
|
||||
// texture should appear when looking from inside.
|
||||
std::string womBase = argv[++i];
|
||||
if (womBase.size() >= 4 &&
|
||||
womBase.substr(womBase.size() - 4) == ".wom") {
|
||||
womBase = womBase.substr(0, womBase.size() - 4);
|
||||
}
|
||||
if (!wowee::pipeline::WoweeModelLoader::exists(womBase)) {
|
||||
std::fprintf(stderr,
|
||||
"flip-mesh-normals: %s.wom does not exist\n",
|
||||
womBase.c_str());
|
||||
return 1;
|
||||
}
|
||||
auto wom = wowee::pipeline::WoweeModelLoader::load(womBase);
|
||||
if (!wom.isValid()) {
|
||||
std::fprintf(stderr,
|
||||
"flip-mesh-normals: failed to load %s.wom\n",
|
||||
womBase.c_str());
|
||||
return 1;
|
||||
}
|
||||
for (auto& v : wom.vertices) v.normal = -v.normal;
|
||||
if (!wowee::pipeline::WoweeModelLoader::save(wom, womBase)) {
|
||||
std::fprintf(stderr,
|
||||
"flip-mesh-normals: failed to save %s.wom\n",
|
||||
womBase.c_str());
|
||||
return 1;
|
||||
}
|
||||
std::printf("Flipped normals on %s.wom (%zu vertices)\n",
|
||||
womBase.c_str(), wom.vertices.size());
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--add-texture-to-zone") == 0 && i + 2 < argc) {
|
||||
// Import an existing PNG into a zone directory. Useful
|
||||
// for the "I have an artist-painted texture, get it into
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue