mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-08 01:53:52 +00:00
feat(editor): add --rotate-mesh completing the basic transform set
Rotates every vertex position and normal around the chosen axis (x, y, or z) by <degrees>. Bone pivots also rotate so the skeleton stays in sync. Bounds are recomputed from rotated positions (axis-aligned bbox can grow under non-90° rotations). Standard right-hand rule: positive degrees rotate counter-clockwise when looking down the axis from positive infinity. Math is hand-rolled (no glm::rotate dependency) for clarity at the call site. Together with --scale-mesh and --translate-mesh this completes the basic transform set. Useful for "imported mesh is on its side" or "the orientation flipped between Blender and Wowee" cleanup. Verified: 2×2 plane on XY rotated 90° around X correctly lands on XZ (bounds (-1,0,-1)..(1,0,1)); bad axis 'w' rejected with exit 1. Brings command count to 219 — kArgRequired entry 200.
This commit is contained in:
parent
9f50e23016
commit
488fbda0d4
1 changed files with 95 additions and 1 deletions
|
|
@ -546,6 +546,8 @@ static void printUsage(const char* argv0) {
|
|||
std::printf(" Offset every vertex and bounds by (dx, dy, dz)\n");
|
||||
std::printf(" --strip-mesh <wom-base> [--bones] [--anims] [--all]\n");
|
||||
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(" --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");
|
||||
|
|
@ -962,7 +964,7 @@ int main(int argc, char* argv[]) {
|
|||
"--add-texture-to-mesh", "--add-texture-to-zone",
|
||||
"--gen-mesh-stairs", "--gen-texture-gradient",
|
||||
"--scale-mesh", "--translate-mesh", "--strip-mesh",
|
||||
"--gen-texture-noise",
|
||||
"--gen-texture-noise", "--rotate-mesh",
|
||||
"--validate-glb", "--info-glb", "--info-glb-tree", "--info-glb-bytes",
|
||||
"--validate-jsondbc", "--check-glb-bounds", "--validate-stl",
|
||||
"--validate-png", "--validate-blp",
|
||||
|
|
@ -16389,6 +16391,98 @@ int main(int argc, char* argv[]) {
|
|||
static_cast<long long>(bytesAfter) -
|
||||
static_cast<long long>(bytesBefore));
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--rotate-mesh") == 0 && i + 3 < argc) {
|
||||
// Rotate every vertex position and normal around the
|
||||
// chosen axis (x, y, or z) by <degrees>. Bone pivots
|
||||
// also rotate so the skeleton stays in sync. Bounds are
|
||||
// recomputed from rotated positions (axis-aligned bbox
|
||||
// grows during rotation).
|
||||
std::string womBase = argv[++i];
|
||||
std::string axisStr = argv[++i];
|
||||
float degrees = 0.0f;
|
||||
try { degrees = std::stof(argv[++i]); }
|
||||
catch (...) {
|
||||
std::fprintf(stderr,
|
||||
"rotate-mesh: <degrees> must be a number\n");
|
||||
return 1;
|
||||
}
|
||||
if (!std::isfinite(degrees)) {
|
||||
std::fprintf(stderr,
|
||||
"rotate-mesh: degrees must be finite\n");
|
||||
return 1;
|
||||
}
|
||||
std::transform(axisStr.begin(), axisStr.end(), axisStr.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
int axis = -1;
|
||||
if (axisStr == "x") axis = 0;
|
||||
else if (axisStr == "y") axis = 1;
|
||||
else if (axisStr == "z") axis = 2;
|
||||
else {
|
||||
std::fprintf(stderr,
|
||||
"rotate-mesh: axis must be x, y, or z (got '%s')\n",
|
||||
axisStr.c_str());
|
||||
return 1;
|
||||
}
|
||||
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,
|
||||
"rotate-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,
|
||||
"rotate-mesh: failed to load %s.wom\n", womBase.c_str());
|
||||
return 1;
|
||||
}
|
||||
float rad = degrees * 3.14159265358979f / 180.0f;
|
||||
float cs = std::cos(rad), sn = std::sin(rad);
|
||||
// Rotation around each axis: standard right-hand rule.
|
||||
auto rot = [axis, cs, sn](glm::vec3 v) -> glm::vec3 {
|
||||
if (axis == 0) {
|
||||
return glm::vec3(v.x,
|
||||
cs * v.y - sn * v.z,
|
||||
sn * v.y + cs * v.z);
|
||||
}
|
||||
if (axis == 1) {
|
||||
return glm::vec3( cs * v.x + sn * v.z,
|
||||
v.y,
|
||||
-sn * v.x + cs * v.z);
|
||||
}
|
||||
return glm::vec3(cs * v.x - sn * v.y,
|
||||
sn * v.x + cs * v.y,
|
||||
v.z);
|
||||
};
|
||||
for (auto& v : wom.vertices) {
|
||||
v.position = rot(v.position);
|
||||
v.normal = rot(v.normal);
|
||||
}
|
||||
for (auto& b : wom.bones) {
|
||||
b.pivot = rot(b.pivot);
|
||||
}
|
||||
// Recompute bounds from rotated vertices (axis-aligned
|
||||
// bbox can only grow under rotation, so reuse the loop).
|
||||
wom.boundMin = glm::vec3(1e30f);
|
||||
wom.boundMax = glm::vec3(-1e30f);
|
||||
for (const auto& v : wom.vertices) {
|
||||
wom.boundMin = glm::min(wom.boundMin, v.position);
|
||||
wom.boundMax = glm::max(wom.boundMax, v.position);
|
||||
}
|
||||
wom.boundRadius = glm::length(wom.boundMax - wom.boundMin) * 0.5f;
|
||||
if (!wowee::pipeline::WoweeModelLoader::save(wom, womBase)) {
|
||||
std::fprintf(stderr,
|
||||
"rotate-mesh: failed to save %s.wom\n", womBase.c_str());
|
||||
return 1;
|
||||
}
|
||||
std::printf("Rotated %s.wom by %g° around %s\n",
|
||||
womBase.c_str(), degrees, axisStr.c_str());
|
||||
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], "--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