From 13312096ea3eeb7cedd8576b3dd8b7b8a2f65dcc Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sat, 9 May 2026 14:43:21 -0700 Subject: [PATCH] feat(editor): add --gen-mesh-mortar-pestle alchemy primitive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 90th procedural mesh: a wider-than-tall closed cylinder (the mortar bowl) with a thin tall closed cylinder (the pestle) rising from its center. Bowl reads as carved stone or wood; pestle reads as a small grinding rod centered in the rim. Distinct from existing kitchenware primitives: • --gen-mesh-cauldron — large + has supporting legs • --gen-mesh-chalice — 3-tier goblet, no separate utensil • --gen-mesh-mug — handled drinking cup • --gen-mesh-bowl — does not exist; this primitive covers the small-bowl + tool case Useful for: alchemy lab counters, kitchen / cooking-stove dressing, herbalist shop interiors, witchcraft NPCs, quest-giver desks for "grind these herbs" objectives. 124 verts / 112 tris at default 14 sides — two simple closed cylinders sharing a single batch with shared texture coords. --- tools/editor/cli_arg_required.cpp | 2 +- tools/editor/cli_gen_mesh.cpp | 49 +++++++++++++++++++++++++++++++ tools/editor/cli_help.cpp | 2 ++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/tools/editor/cli_arg_required.cpp b/tools/editor/cli_arg_required.cpp index 14aeb141..bd4a7fde 100644 --- a/tools/editor/cli_arg_required.cpp +++ b/tools/editor/cli_arg_required.cpp @@ -77,7 +77,7 @@ const char* const kArgRequired[] = { "--gen-mesh-lantern", "--gen-mesh-chalice", "--gen-mesh-standing-torch", "--gen-mesh-scroll-case", "--gen-mesh-stove", "--gen-mesh-well-pail", - "--gen-mesh-mug", + "--gen-mesh-mug", "--gen-mesh-mortar-pestle", "--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 30a20606..d1eaefa8 100644 --- a/tools/editor/cli_gen_mesh.cpp +++ b/tools/editor/cli_gen_mesh.cpp @@ -5213,6 +5213,54 @@ int handleMug(int& i, int argc, char** argv) { return 0; } +int handleMortarPestle(int& i, int argc, char** argv) { + // Mortar and pestle: a wider-than-tall closed cylinder + // (the mortar bowl) with a thin tall closed cylinder + // (the pestle) standing inside its rim. The bowl reads + // as carved stone or wood; the pestle reads as a small + // grinding rod. The 90th procedural mesh primitive. + // + // Distinct from --gen-mesh-cauldron (much larger, with + // legs) and --gen-mesh-chalice (3-tier goblet with no + // separate utensil). + std::string womBase = argv[++i]; + float bowlR = 0.06f; + float bowlH = 0.05f; + float pestleR = 0.012f; + float pestleH = 0.10f; + int sides = 14; + parseOptFloat(i, argc, argv, bowlR); + parseOptFloat(i, argc, argv, bowlH); + parseOptFloat(i, argc, argv, pestleR); + parseOptFloat(i, argc, argv, pestleH); + parseOptInt(i, argc, argv, sides); + if (bowlR <= 0 || bowlH <= 0 || pestleR <= 0 || pestleH <= 0 || + pestleR >= bowlR || sides < 6 || sides > 64) { + std::fprintf(stderr, + "gen-mesh-mortar-pestle: dims > 0; sides 6..64; " + "pestleR < bowlR\n"); + return 1; + } + stripExt(womBase, ".wom"); + wowee::pipeline::WoweeModel wom; + initWomDefaults(wom, womBase); + // Bowl sits on the ground; pestle is centered laterally + // and rises up out of the bowl. + addClosedCylinderY(wom, bowlR, 0.0f, bowlH, sides); + addClosedCylinderY(wom, pestleR, bowlH * 0.5f, + bowlH * 0.5f + pestleH, sides); + finalizeAsSingleBatch(wom); + setCenteredBoundsXZ(wom, bowlR, bowlR, bowlH + pestleH); + if (!saveWomOrError(wom, womBase, "gen-mesh-mortar-pestle")) return 1; + printWomWrote(womBase); + std::printf(" bowl : R=%.3f x %.3f tall (%d sides)\n", + bowlR, bowlH, sides); + std::printf(" pestle : R=%.3f x %.3f tall\n", + pestleR, pestleH); + printWomMeshStats(wom); + 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 @@ -7591,6 +7639,7 @@ constexpr MeshEntry kMeshTable[] = { {"--gen-mesh-stove", 1, handleStove}, {"--gen-mesh-well-pail", 1, handleWellPail}, {"--gen-mesh-mug", 1, handleMug}, + {"--gen-mesh-mortar-pestle", 1, handleMortarPestle}, {"--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 524e5dec..1e9df634 100644 --- a/tools/editor/cli_help.cpp +++ b/tools/editor/cli_help.cpp @@ -342,6 +342,8 @@ void printUsage(const char* argv0) { std::printf(" Wooden well-pail: closed cylindrical body + thin horizontal handle bar above (water-haul / mop-bucket prop)\n"); std::printf(" --gen-mesh-mug [bodyR] [bodyH] [handleW] [handleH] [handleArm] [sides]\n"); std::printf(" Drinking mug / tankard: closed cylinder body + side handle slab (tavern / banquet / inn dressing)\n"); + std::printf(" --gen-mesh-mortar-pestle [bowlR] [bowlH] [pestleR] [pestleH] [sides]\n"); + std::printf(" Mortar + pestle: wide squat cylinder (bowl) + thin tall cylinder rising from inside (alchemy / kitchen)\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");