From 8adbeb237d3fe9b262ddb462fb85a2e15790c345 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sat, 9 May 2026 13:21:03 -0700 Subject: [PATCH] feat(editor): add --gen-mesh-planter-box garden flowerbox MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 78th procedural mesh primitive. Long open-top wooden planter with a visible soil-fill block: • 5-piece basin construction (bottom slab + 4 perimeter walls), same arrangement as --gen-mesh-water-trough • soil block filling the inner cavity from floor up to soilTopFrac × height (default 85%), slightly inset from walls so it visually sits "inside" the wood Distinct from --gen-mesh-water-trough (square basin without a soil-fill block) — planter-box is the long elongated garden variant. Useful for window sills, kitchen herb gardens, balcony planters, monastery cloister-walk container plants, market-stall produce display trays. The 6 non-manifold edges (--info-mesh-stats) are at the 4-wall corners — same expected pattern as water-trough, where the inner walls share corner positions with each other. Milestone: kArgRequired now reaches 411 documented flags. --- tools/editor/cli_arg_required.cpp | 1 + tools/editor/cli_gen_mesh.cpp | 70 +++++++++++++++++++++++++++++++ tools/editor/cli_help.cpp | 2 + 3 files changed, 73 insertions(+) diff --git a/tools/editor/cli_arg_required.cpp b/tools/editor/cli_arg_required.cpp index c3d190bb..9b06aa7f 100644 --- a/tools/editor/cli_arg_required.cpp +++ b/tools/editor/cli_arg_required.cpp @@ -60,6 +60,7 @@ const char* const kArgRequired[] = { "--gen-mesh-stone-bench", "--gen-mesh-mine-cart", "--gen-mesh-hitching-rail", "--gen-mesh-pillar-row", "--gen-mesh-statue-base", "--gen-mesh-bird-bath", + "--gen-mesh-planter-box", "--gen-camp-pack", "--gen-blacksmith-pack", "--gen-village-pack", "--gen-temple-pack", "--gen-graveyard-pack", "--gen-garden-pack", "--gen-dock-pack", "--gen-tavern-pack", diff --git a/tools/editor/cli_gen_mesh.cpp b/tools/editor/cli_gen_mesh.cpp index d221171d..44d0dc71 100644 --- a/tools/editor/cli_gen_mesh.cpp +++ b/tools/editor/cli_gen_mesh.cpp @@ -5161,6 +5161,75 @@ int handleTent(int& i, int argc, char** argv) { return 0; } +int handlePlanterBox(int& i, int argc, char** argv) { + // Window-sill / garden planter box: long open-top wooden + // basin (5-piece bottom + 4 walls construction) plus a + // visible "soil" slab inside that fills most of the cavity + // a bit below the rim — the natural "filled with potting + // dirt" look. Distinct from --gen-mesh-water-trough (square + // basin without a soil-fill block) — planter-box is the + // long elongated garden variant. The 78th procedural mesh + // primitive. + std::string womBase = argv[++i]; + float length = 1.2f; + float width = 0.30f; + float height = 0.30f; + float wallT = 0.04f; + float soilTopFrac = 0.85f; // soil top as fraction of height + parseOptFloat(i, argc, argv, length); + parseOptFloat(i, argc, argv, width); + parseOptFloat(i, argc, argv, height); + parseOptFloat(i, argc, argv, wallT); + parseOptFloat(i, argc, argv, soilTopFrac); + if (length <= 0 || width <= 0 || height <= 0 || wallT <= 0 || + wallT * 2 >= std::min(length, width) || wallT >= height || + soilTopFrac <= 0.0f || soilTopFrac > 1.0f) { + std::fprintf(stderr, + "gen-mesh-planter-box: dims > 0; soilTopFrac (0,1]\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; + // Bottom slab (planter floor). + addFlatBox(wom, 0.0f, wallT * 0.5f, 0.0f, L2, wallT * 0.5f, W2); + // 4 perimeter walls (same scheme as --gen-mesh-water-trough). + const float wallCY = wallT + (height - wallT) * 0.5f; + const float wallHY = (height - 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); + // Soil block: fills the inner cavity from the floor up to + // soilTopFrac * height. Slightly inset so it visually sits + // "inside" the walls instead of breaking the wall texture. + const float soilTopY = height * soilTopFrac; + const float soilCY = wallT + (soilTopY - wallT) * 0.5f; + const float soilHY = (soilTopY - wallT) * 0.5f; + if (soilHY > 0.0f) { + const float innerW2 = W2 - wallT; + addFlatBox(wom, 0.0f, soilCY, 0.0f, + innerL2 - 0.005f, soilHY, innerW2 - 0.005f); + } + finalizeAsSingleBatch(wom); + setCenteredBoundsXZ(wom, L2, W2, height); + if (!saveWomOrError(wom, womBase, "gen-mesh-planter-box")) return 1; + printWomWrote(womBase); + std::printf(" box : %.3fL x %.3fW x %.3fH (wallT %.3f)\n", + length, width, height, wallT); + std::printf(" soil : top at %.0f%% of height\n", + soilTopFrac * 100.0f); + printWomMeshStats(wom); + return 0; +} + int handleBirdBath(int& i, int argc, char** argv) { // Garden bird-bath: thin cylindrical stem topped by a wide // shallow disc basin. Distinct from --gen-mesh-fountain @@ -7253,6 +7322,7 @@ constexpr MeshEntry kMeshTable[] = { {"--gen-mesh-pillar-row", 1, handlePillarRow}, {"--gen-mesh-statue-base", 1, handleStatueBase}, {"--gen-mesh-bird-bath", 1, handleBirdBath}, + {"--gen-mesh-planter-box", 1, handlePlanterBox}, {"--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 ee83b965..3eee4cc5 100644 --- a/tools/editor/cli_help.cpp +++ b/tools/editor/cli_help.cpp @@ -300,6 +300,8 @@ void printUsage(const char* argv0) { std::printf(" Statue base: 3-tier pedestal (plinth + body + capital) for monuments / hero memorials\n"); std::printf(" --gen-mesh-bird-bath [stemR] [stemH] [basinR] [basinH] [sides]\n"); std::printf(" Bird bath: thin cylindrical stem topped by a wide shallow basin disc (small garden water feature)\n"); + std::printf(" --gen-mesh-planter-box [length] [width] [height] [wallT] [soilTopFrac]\n"); + std::printf(" Planter box: long open-top wood basin + visible soil-fill block (window sills / kitchen / balcony)\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");