mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-08 10:03:51 +00:00
feat(editor): add --gen-mesh-stairs procedural staircase
Procedural straight staircase along +X with N steps and configurable
rise/run/width. Each step is a closed box (24 verts / 12 tris) with
flat per-face normals, sharing no vertices with neighbors so shading
reads as crisp steps without smoothing tricks.
Defaults (5 steps / 0.2 / 0.3 / 1.0) yield ~1m tall × 1.5m long ×
1m wide — a believable single flight. Step count clamped to 1..256
so a typo can't accidentally generate a million-step mesh.
Useful for level-design placeholders ("I need a staircase up to
this platform"), test-bench geometry for camera/movement work, and
quick prototyping of stepped terrain.
Verified: 5-step default → 120 verts / 60 tris / 1.5L × 1H × 1W
span; custom 8/0.25/0.4/1.5 → 192 verts / 96 tris / 3.2 × 2.0 × 1.5;
steps=0 → exit 1 with range error. Brings command count to 209.
This commit is contained in:
parent
3404910231
commit
98c9b3c624
1 changed files with 130 additions and 0 deletions
|
|
@ -532,6 +532,8 @@ static void printUsage(const char* argv0) {
|
|||
std::printf(" Synthesize a procedural WOM primitive with proper normals, UVs, and bounds\n");
|
||||
std::printf(" --gen-mesh-textured <wom-base> <cube|plane|sphere|cylinder|torus> <colorHex|pattern> [size]\n");
|
||||
std::printf(" Compose a procedural mesh + matching PNG texture wired into the WOM's batch\n");
|
||||
std::printf(" --gen-mesh-stairs <wom-base> <steps> [stepHeight] [stepDepth] [width]\n");
|
||||
std::printf(" Procedural straight staircase along +X with N steps (default 5 / 0.2 / 0.3 / 1.0)\n");
|
||||
std::printf(" --add-texture-to-mesh <wom-base> <png-path> [batchIdx]\n");
|
||||
std::printf(" Bind an existing PNG into a WOM's texturePaths and point batchIdx (default 0) at it\n");
|
||||
std::printf(" --add-item <zoneDir> <name> [id] [quality] [displayId] [itemLevel]\n");
|
||||
|
|
@ -940,6 +942,7 @@ int main(int argc, char* argv[]) {
|
|||
"--bench-migrate-data-tree", "--list-data-tree-largest",
|
||||
"--export-data-tree-md", "--gen-texture", "--gen-mesh", "--gen-mesh-textured",
|
||||
"--add-texture-to-mesh", "--add-texture-to-zone",
|
||||
"--gen-mesh-stairs",
|
||||
"--validate-glb", "--info-glb", "--info-glb-tree", "--info-glb-bytes",
|
||||
"--validate-jsondbc", "--check-glb-bounds", "--validate-stl",
|
||||
"--validate-png", "--validate-blp",
|
||||
|
|
@ -15325,6 +15328,133 @@ int main(int argc, char* argv[]) {
|
|||
std::printf(" vertices : %zu\n", wom.vertices.size());
|
||||
std::printf(" texture : %s (wired into batch 0)\n", pngLeaf.c_str());
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--gen-mesh-stairs") == 0 && i + 2 < argc) {
|
||||
// Procedural straight staircase along +X. N steps with
|
||||
// configurable rise/run/width. Each step is a closed
|
||||
// box, sharing no vertices with neighbors so per-face
|
||||
// normals are flat (looks correct without smoothing).
|
||||
//
|
||||
// Defaults: 5 steps, stepHeight=0.2, stepDepth=0.3,
|
||||
// width=1.0 — roughly 1m tall × 1.5m long × 1m wide,
|
||||
// a believable single flight.
|
||||
//
|
||||
// Useful for level-design placeholders ("I need a staircase
|
||||
// up to this platform"), test-bench geometry for camera/
|
||||
// movement, and quick prototyping of stepped terrain.
|
||||
std::string womBase = argv[++i];
|
||||
int steps = 5;
|
||||
float stepHeight = 0.2f, stepDepth = 0.3f, width = 1.0f;
|
||||
try { steps = std::stoi(argv[++i]); }
|
||||
catch (...) {
|
||||
std::fprintf(stderr,
|
||||
"gen-mesh-stairs: <steps> must be an integer\n");
|
||||
return 1;
|
||||
}
|
||||
if (steps < 1 || steps > 256) {
|
||||
std::fprintf(stderr,
|
||||
"gen-mesh-stairs: steps %d out of range (1..256)\n", steps);
|
||||
return 1;
|
||||
}
|
||||
if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
try { stepHeight = std::stof(argv[++i]); } catch (...) {}
|
||||
}
|
||||
if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
try { stepDepth = std::stof(argv[++i]); } catch (...) {}
|
||||
}
|
||||
if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
try { width = std::stof(argv[++i]); } catch (...) {}
|
||||
}
|
||||
if (stepHeight <= 0 || stepDepth <= 0 || width <= 0) {
|
||||
std::fprintf(stderr,
|
||||
"gen-mesh-stairs: dimensions must be positive\n");
|
||||
return 1;
|
||||
}
|
||||
if (womBase.size() >= 4 &&
|
||||
womBase.substr(womBase.size() - 4) == ".wom") {
|
||||
womBase = womBase.substr(0, womBase.size() - 4);
|
||||
}
|
||||
wowee::pipeline::WoweeModel wom;
|
||||
wom.name = std::filesystem::path(womBase).stem().string();
|
||||
wom.version = 3;
|
||||
auto addV = [&](float x, float y, float z,
|
||||
float nx, float ny, float nz,
|
||||
float u, float v) -> uint32_t {
|
||||
wowee::pipeline::WoweeModel::Vertex vtx;
|
||||
vtx.position = glm::vec3(x, y, z);
|
||||
vtx.normal = glm::vec3(nx, ny, nz);
|
||||
vtx.texCoord = glm::vec2(u, v);
|
||||
wom.vertices.push_back(vtx);
|
||||
return static_cast<uint32_t>(wom.vertices.size() - 1);
|
||||
};
|
||||
float halfW = width * 0.5f;
|
||||
// Each step is a box from y=0 to y=(k+1)*stepHeight,
|
||||
// depth-wise from x=k*stepDepth to x=(k+1)*stepDepth,
|
||||
// width-wise from z=-halfW to z=+halfW. Six faces per
|
||||
// step, four verts each = 24 verts / 12 tris per step.
|
||||
for (int k = 0; k < steps; ++k) {
|
||||
float x0 = k * stepDepth;
|
||||
float x1 = (k + 1) * stepDepth;
|
||||
float y0 = 0.0f;
|
||||
float y1 = (k + 1) * stepHeight;
|
||||
float z0 = -halfW;
|
||||
float z1 = halfW;
|
||||
struct Face { float nx, ny, nz; float verts[4][3]; };
|
||||
Face faces[6] = {
|
||||
{ 0, 1, 0, {{x0,y1,z0},{x1,y1,z0},{x1,y1,z1},{x0,y1,z1}}}, // top +Y
|
||||
{ 0, -1, 0, {{x0,y0,z0},{x0,y0,z1},{x1,y0,z1},{x1,y0,z0}}}, // bot -Y
|
||||
{-1, 0, 0, {{x0,y0,z0},{x0,y1,z0},{x0,y1,z1},{x0,y0,z1}}}, // back -X
|
||||
{ 1, 0, 0, {{x1,y0,z0},{x1,y0,z1},{x1,y1,z1},{x1,y1,z0}}}, // front+X (riser)
|
||||
{ 0, 0, -1, {{x0,y0,z0},{x1,y0,z0},{x1,y1,z0},{x0,y1,z0}}}, // -Z
|
||||
{ 0, 0, 1, {{x0,y0,z1},{x0,y1,z1},{x1,y1,z1},{x1,y0,z1}}}, // +Z
|
||||
};
|
||||
float uvs[4][2] = {{0,0},{1,0},{1,1},{0,1}};
|
||||
for (auto& f : faces) {
|
||||
uint32_t base = static_cast<uint32_t>(wom.vertices.size());
|
||||
for (int q = 0; q < 4; ++q) {
|
||||
addV(f.verts[q][0], f.verts[q][1], f.verts[q][2],
|
||||
f.nx, f.ny, f.nz, uvs[q][0], uvs[q][1]);
|
||||
}
|
||||
wom.indices.push_back(base + 0);
|
||||
wom.indices.push_back(base + 1);
|
||||
wom.indices.push_back(base + 2);
|
||||
wom.indices.push_back(base + 0);
|
||||
wom.indices.push_back(base + 2);
|
||||
wom.indices.push_back(base + 3);
|
||||
}
|
||||
}
|
||||
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;
|
||||
wowee::pipeline::WoweeModel::Batch b;
|
||||
b.indexStart = 0;
|
||||
b.indexCount = static_cast<uint32_t>(wom.indices.size());
|
||||
b.textureIndex = 0;
|
||||
b.blendMode = 0;
|
||||
b.flags = 0;
|
||||
wom.batches.push_back(b);
|
||||
wom.texturePaths.push_back("");
|
||||
std::filesystem::path womPath(womBase);
|
||||
std::filesystem::create_directories(womPath.parent_path());
|
||||
if (!wowee::pipeline::WoweeModelLoader::save(wom, womBase)) {
|
||||
std::fprintf(stderr,
|
||||
"gen-mesh-stairs: failed to save %s.wom\n", womBase.c_str());
|
||||
return 1;
|
||||
}
|
||||
std::printf("Wrote %s.wom\n", womBase.c_str());
|
||||
std::printf(" steps : %d\n", steps);
|
||||
std::printf(" stepHt : %.3f\n", stepHeight);
|
||||
std::printf(" stepDep : %.3f\n", stepDepth);
|
||||
std::printf(" width : %.3f\n", width);
|
||||
std::printf(" vertices : %zu (%d per step × %d)\n",
|
||||
wom.vertices.size(), 24, steps);
|
||||
std::printf(" triangles : %zu\n", wom.indices.size() / 3);
|
||||
std::printf(" span : %.3fL × %.3fH × %.3fW\n",
|
||||
steps * stepDepth, steps * stepHeight, width);
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--add-texture-to-mesh") == 0 && i + 2 < argc) {
|
||||
// Manual companion to --gen-mesh-textured. Binds an
|
||||
// existing PNG to a WOM by appending it to texturePaths
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue