From 85e02a6132decd8ef36a7ff4a1db936cd7ad346f Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sat, 9 May 2026 12:54:17 -0700 Subject: [PATCH] feat(editor): add --gen-mesh-mine-cart underground transport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 73rd procedural mesh primitive. Open-top mining cart on 4 wheel boxes: • bin: 5-piece basin construction (bottom slab + 4 perimeter walls), same arrangement as --gen-mesh-water-trough • wheels: 4 cube boxes at the corners, inset by wheelInset and sitting on the ground (y from 0 to 2*wheelR) • bin sits on top of the wheels at y = 2*wheelR All axis-aligned — exercises every shared helper. Useful for mines, dwarven forges, gnomish junk-yards, abandoned- tunnel set dressing, salvage scenes. Default 0.9 × 0.5 m bin with 0.08-radius wheels gives the classic narrow-gauge ore-cart silhouette. The 4-wall basin construction (verified via --info-mesh-stats: 6 non-manifold edges at the wall corners — same as --gen-mesh-water-trough's expected branchy edges) means the cart can hold collision- visible ore inside if a content author drops in another primitive. --- tools/editor/cli_arg_required.cpp | 2 +- tools/editor/cli_gen_mesh.cpp | 73 +++++++++++++++++++++++++++++++ tools/editor/cli_help.cpp | 2 + 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/tools/editor/cli_arg_required.cpp b/tools/editor/cli_arg_required.cpp index c3dac44f..d1aa193d 100644 --- a/tools/editor/cli_arg_required.cpp +++ b/tools/editor/cli_arg_required.cpp @@ -57,7 +57,7 @@ const char* const kArgRequired[] = { "--gen-mesh-training-dummy", "--gen-mesh-hitching-post", "--gen-mesh-outhouse", "--gen-mesh-forge", "--gen-mesh-archery-target", "--gen-mesh-gravel-pile", - "--gen-mesh-stone-bench", + "--gen-mesh-stone-bench", "--gen-mesh-mine-cart", "--gen-camp-pack", "--gen-blacksmith-pack", "--gen-village-pack", "--gen-temple-pack", "--gen-mesh-table", "--gen-mesh-lamppost", "--gen-mesh-bed", diff --git a/tools/editor/cli_gen_mesh.cpp b/tools/editor/cli_gen_mesh.cpp index 03f8e10a..488b5b3a 100644 --- a/tools/editor/cli_gen_mesh.cpp +++ b/tools/editor/cli_gen_mesh.cpp @@ -5161,6 +5161,78 @@ int handleTent(int& i, int argc, char** argv) { return 0; } +int handleMineCart(int& i, int argc, char** argv) { + // Mine cart: rectangular open-top bin on 4 wheel boxes. The + // bin uses the 5-piece basin construction from + // --gen-mesh-water-trough (bottom + 4 walls); wheels are + // 4 thin cube boxes at the corners. All axis-aligned — + // exercises every shared helper. Useful for mines, dwarven + // forges, gnomish junk-yards, abandoned-tunnel set dressing. + // The 73rd procedural mesh primitive. + std::string womBase = argv[++i]; + float length = 0.9f; + float width = 0.5f; + float bodyH = 0.45f; + float wallT = 0.04f; + float wheelR = 0.08f; // wheel half-edge (square approx) + float wheelInset = 0.05f; // wheel inset from cart corners + parseOptFloat(i, argc, argv, length); + parseOptFloat(i, argc, argv, width); + parseOptFloat(i, argc, argv, bodyH); + parseOptFloat(i, argc, argv, wallT); + parseOptFloat(i, argc, argv, wheelR); + parseOptFloat(i, argc, argv, wheelInset); + if (length <= 0 || width <= 0 || bodyH <= 0 || wallT <= 0 || + wallT * 2 >= std::min(length, width) || wallT >= bodyH || + wheelR <= 0 || wheelInset < 0 || + wheelInset * 2 + wheelR * 2 > std::min(length, width)) { + std::fprintf(stderr, + "gen-mesh-mine-cart: dims > 0; walls/wheels must fit\n"); + return 1; + } + stripExt(womBase, ".wom"); + wowee::pipeline::WoweeModel wom; + initWomDefaults(wom, womBase); + const float L2 = length * 0.5f; + const float W2 = width * 0.5f; + // Wheels first — sit on the ground (y from 0 to 2*wheelR), + // pushed inward from cart corners. + const float wheelY = wheelR; + const float wheelX = L2 - wheelInset - wheelR; + const float wheelZ = W2 - wheelInset - wheelR; + addFlatBox(wom, +wheelX, wheelY, +wheelZ, wheelR, wheelR, wheelR); + addFlatBox(wom, -wheelX, wheelY, +wheelZ, wheelR, wheelR, wheelR); + addFlatBox(wom, +wheelX, wheelY, -wheelZ, wheelR, wheelR, wheelR); + addFlatBox(wom, -wheelX, wheelY, -wheelZ, wheelR, wheelR, wheelR); + // Bin sits on top of the wheels: y from 2*wheelR to 2*wheelR+bodyH. + const float binBaseY = 2.0f * wheelR; + // Bin bottom slab. + addFlatBox(wom, 0.0f, binBaseY + wallT * 0.5f, 0.0f, + L2, wallT * 0.5f, W2); + // 4 perimeter walls. + const float wallCY = binBaseY + wallT + (bodyH - wallT) * 0.5f; + const float wallHY = (bodyH - wallT) * 0.5f; + addFlatBox(wom, +L2 - wallT * 0.5f, wallCY, 0.0f, + wallT * 0.5f, wallHY, W2); + addFlatBox(wom, -L2 + wallT * 0.5f, wallCY, 0.0f, + wallT * 0.5f, wallHY, W2); + const float innerL2 = L2 - wallT; + addFlatBox(wom, 0.0f, wallCY, +W2 - wallT * 0.5f, + innerL2, wallHY, wallT * 0.5f); + addFlatBox(wom, 0.0f, wallCY, -W2 + wallT * 0.5f, + innerL2, wallHY, wallT * 0.5f); + finalizeAsSingleBatch(wom); + setCenteredBoundsXZ(wom, L2, W2, binBaseY + bodyH); + if (!saveWomOrError(wom, womBase, "gen-mesh-mine-cart")) return 1; + printWomWrote(womBase); + std::printf(" bin : %.3f x %.3f x %.3f (wallT %.3f)\n", + length, width, bodyH, wallT); + std::printf(" wheels : 4 corners (R=%.3f, inset %.3f)\n", + wheelR, wheelInset); + printWomMeshStats(wom); + return 0; +} + int handleStoneBench(int& i, int argc, char** argv) { // Long stone bench: horizontal seat slab on 2 vertical block // supports near the ends. Distinct from --gen-mesh-bench @@ -6828,6 +6900,7 @@ constexpr MeshEntry kMeshTable[] = { {"--gen-mesh-archery-target", 1, handleArcheryTarget}, {"--gen-mesh-gravel-pile", 1, handleGravelPile}, {"--gen-mesh-stone-bench", 1, handleStoneBench}, + {"--gen-mesh-mine-cart", 1, handleMineCart}, {"--gen-camp-pack", 1, handleGenCampPack}, {"--gen-blacksmith-pack", 1, handleGenBlacksmithPack}, {"--gen-village-pack", 1, handleGenVillagePack}, diff --git a/tools/editor/cli_help.cpp b/tools/editor/cli_help.cpp index 38b896e7..86019add 100644 --- a/tools/editor/cli_help.cpp +++ b/tools/editor/cli_help.cpp @@ -280,6 +280,8 @@ void printUsage(const char* argv0) { std::printf(" Gravel pile: hash-distributed stone cubes in a conical heap (mining / construction / rubble)\n"); std::printf(" --gen-mesh-stone-bench [length] [depth] [seatH] [seatT] [supportW] [supportInset]\n"); std::printf(" Stone bench: long seat slab on 2 block supports near the ends (park / temple / ruined city)\n"); + std::printf(" --gen-mesh-mine-cart [length] [width] [bodyH] [wallT] [wheelR] [wheelInset]\n"); + std::printf(" Mine cart: open-top bin (5-piece basin) on 4 wheel boxes (mines / dwarven forges / junk yards)\n"); std::printf(" --gen-camp-pack \n"); std::printf(" Convenience: emit tent + firepit + bedroll + canopy + woodpile + haystack into outDir as 6 .wom files\n"); std::printf(" --gen-blacksmith-pack \n");