From e7695d6e3b2213362be6c32db5b548c722eae6ef Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sat, 9 May 2026 14:23:23 -0700 Subject: [PATCH] feat(editor): add --gen-mesh-well-pail wooden bucket primitive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 86th procedural mesh primitive. Wooden well-pail / mop- bucket: • body — closed cylindrical Y-axis cylinder via addClosedCylinderY (collision-watertight) • handle — thin horizontal box floating handleArc above the rim, spanning at least bodyR×2 wide so its ends align with the rim's outside edge Without rotation the handle is a straight bar rather than a true semicircle, but the bucket-with-handle silhouette still reads correctly. handleArc parameter controls the gap between rim and handle (small = handle touches rim; larger = bucket-being-carried look). Useful for well scenes (pairs with --gen-mesh-well), servant-corridor mop scenes, kitchen prep stations, homestead exteriors, dwarven mine shafts, ocean-ship swabbing decks. Watertight under weld (verified 102 manifold edges, 0 boundary, 0 non-manifold). --- tools/editor/cli_arg_required.cpp | 2 +- tools/editor/cli_gen_mesh.cpp | 52 +++++++++++++++++++++++++++++++ tools/editor/cli_help.cpp | 2 ++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/tools/editor/cli_arg_required.cpp b/tools/editor/cli_arg_required.cpp index f2fa5afa..0b01c0aa 100644 --- a/tools/editor/cli_arg_required.cpp +++ b/tools/editor/cli_arg_required.cpp @@ -70,7 +70,7 @@ const char* const kArgRequired[] = { "--gen-mesh-planter-box", "--gen-mesh-urn", "--gen-mesh-candle", "--gen-mesh-lantern", "--gen-mesh-chalice", "--gen-mesh-standing-torch", "--gen-mesh-scroll-case", - "--gen-mesh-stove", + "--gen-mesh-stove", "--gen-mesh-well-pail", "--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 356600f9..c8a30396 100644 --- a/tools/editor/cli_gen_mesh.cpp +++ b/tools/editor/cli_gen_mesh.cpp @@ -5161,6 +5161,57 @@ int handleTent(int& i, int argc, char** argv) { return 0; } +int handleWellPail(int& i, int argc, char** argv) { + // Wooden well-pail / bucket: a closed cylindrical body + // (collision-watertight) plus a thin horizontal handle bar + // floating just above the open-top side. Without rotation + // the handle is a straight box rather than a true semicircle, + // but the silhouette still reads as a bucket. The 86th + // procedural mesh primitive. + std::string womBase = argv[++i]; + float bodyR = 0.14f; + float bodyH = 0.18f; + float handleW = 0.32f; // horizontal extent of handle + float handleT = 0.015f; // handle thickness + float handleArc = 0.08f; // distance handle floats above the rim + int sides = 14; + parseOptFloat(i, argc, argv, bodyR); + parseOptFloat(i, argc, argv, bodyH); + parseOptFloat(i, argc, argv, handleW); + parseOptFloat(i, argc, argv, handleT); + parseOptFloat(i, argc, argv, handleArc); + parseOptInt(i, argc, argv, sides); + if (bodyR <= 0 || bodyH <= 0 || handleW <= 0 || handleT <= 0 || + handleArc < 0 || sides < 6 || sides > 64 || + handleW * 0.5f < bodyR) { + std::fprintf(stderr, + "gen-mesh-well-pail: dims > 0; sides 6..64; " + "handleW/2 >= bodyR\n"); + return 1; + } + stripExt(womBase, ".wom"); + wowee::pipeline::WoweeModel wom; + initWomDefaults(wom, womBase); + addClosedCylinderY(wom, bodyR, 0.0f, bodyH, sides); + // Handle: thin box centered above the rim, spanning the + // pail diameter plus a small overhang so its ends look like + // they meet the rim's outside. + const float handleCY = bodyH + handleArc + handleT * 0.5f; + addFlatBox(wom, 0.0f, handleCY, 0.0f, + handleW * 0.5f, handleT * 0.5f, handleT * 0.5f); + finalizeAsSingleBatch(wom); + float maxR = std::max(bodyR, handleW * 0.5f); + float topY = bodyH + handleArc + handleT; + setCenteredBoundsXZ(wom, maxR, maxR, topY); + if (!saveWomOrError(wom, womBase, "gen-mesh-well-pail")) return 1; + printWomWrote(womBase); + std::printf(" body : R=%.3f x %.3f tall\n", bodyR, bodyH); + std::printf(" handle : %.3f wide x %.3f thick at +%.3f arc\n", + handleW, handleT, handleArc); + printWomMeshStats(wom); + return 0; +} + int handleStove(int& i, int argc, char** argv) { // Pot-bellied wood stove: wide cylindrical body + thin // tall chimney column rising from the top of the body. @@ -7486,6 +7537,7 @@ constexpr MeshEntry kMeshTable[] = { {"--gen-mesh-standing-torch", 1, handleStandingTorch}, {"--gen-mesh-scroll-case", 1, handleScrollCase}, {"--gen-mesh-stove", 1, handleStove}, + {"--gen-mesh-well-pail", 1, handleWellPail}, {"--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 7d91ad00..fe854a4c 100644 --- a/tools/editor/cli_help.cpp +++ b/tools/editor/cli_help.cpp @@ -334,6 +334,8 @@ void printUsage(const char* argv0) { std::printf(" Scroll case: thin tall cylinder + optional wider cap (set capR=0 to skip) — libraries / mage scenes\n"); std::printf(" --gen-mesh-stove [bodyR] [bodyH] [chimneyR] [chimneyH] [sides]\n"); std::printf(" Pot-bellied stove: round cylindrical body + thin chimney column on top (cottage / workshop heating)\n"); + std::printf(" --gen-mesh-well-pail [bodyR] [bodyH] [handleW] [handleT] [handleArc] [sides]\n"); + std::printf(" Wooden well-pail: closed cylindrical body + thin horizontal handle bar above (water-haul / mop-bucket prop)\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");