Two more print-pattern extractions for the gen-mesh side:
• printWomWrote(base) — the "Wrote <base>.wom" success line
every handler emits at the start of its stat report. 71
sites collapsed.
• printWomMeshStats(wom) — the canonical final 2-line pair
"vertices : N" / "triangles : T" emitted at the end of
every standard primitive's stat report. 49 sites collapsed.
Output bytes verified identical: firepit and tent surface
area / vertex / triangle counts unchanged.
The one remaining open-coded "Wrote" line is in
--gen-mesh-textured which writes both a .wom and a .png in
the same line — different signature, left unchanged.
These complete the print-helper trio (printPngWrote on the
texture side, printWomWrote + printWomMeshStats on the mesh
side). New primitives now end with one helper call instead
of three printfs.
21 procedural mesh handlers used the same two-line bounds
stanza for primitives whose footprint is symmetric in X+Z
and rises from y=0:
wom.boundMin = glm::vec3(-halfX, 0, -halfZ);
wom.boundMax = glm::vec3( halfX, maxY, halfZ);
Hoist into cli_box_emitter.hpp as inline setCenteredBoundsXZ
(WoweeModel&, halfX, halfZ, maxY). Each call site collapses
to one line.
Output bytes verified identical: firepit bbox 1.200 × 0.200
× 1.200 unchanged, haystack bbox 1.200 × 0.900 × 1.200
unchanged. Asymmetric bounds (e.g. handlePodium with
different X and Z extents on the min/max lines) are
deliberately left untouched — the helper only matches the
common symmetric case.
Two more boilerplate patterns repeated across cli_gen_mesh.cpp:
• init: 64 sites set wom.name = path-stem and wom.version = 3
in 3 lines. Hoisted to initWomDefaults(wom, base) — 1 line.
• save: 65 sites had identical 5-line "if save fails, fprintf
stderr and return 1" blocks. Hoisted to saveWomOrError(wom,
base, cmdName) returning bool, used as
`if (!saveWomOrError(...)) return 1;` — also 1 line.
Net cli_gen_mesh.cpp drops by ~254 lines (from 6424 to 6170).
Output bytes verified identical: firepit surface area 2.1100
m² unchanged, cube vertex/index/bounds counts unchanged.
After this batch's prior helpers (addFlatBox, addVertex,
stripExt, finalizeAsSingleBatch, parseOpt*), a typical new
gen-mesh handler now needs zero copy-paste boilerplate to
get a working primitive — every shared bit lives in
cli_box_emitter.hpp and cli_arg_parse.hpp.
53 procedural mesh primitives ended with the same 5-line
batch-finalization boilerplate:
wowee::pipeline::WoweeModel::Batch batch;
batch.indexStart = 0;
batch.indexCount = static_cast<uint32_t>(wom.indices.size());
batch.textureIndex = 0;
wom.batches.push_back(batch);
Hoist into cli_box_emitter.hpp as inline finalizeAsSingleBatch
(WoweeModel&). Each call site collapses to:
finalizeAsSingleBatch(wom);
cli_gen_mesh.cpp drops by ~210 lines. Output bytes verified
identical: firepit batch idx 0 / iStart 0 / iCount 360 /
opaque blend, surface area 2.1100 m² unchanged.
Procedural builders only ever emit one batch per primitive;
multi-batch primitives (none currently exist) would still
be free to construct batches manually.
64 sites in cli_gen_mesh.cpp open-coded the same 4-line
"strip .wom suffix from base path if user typed it" pattern:
if (womBase.size() >= 4 &&
womBase.substr(womBase.size() - 4) == ".wom") {
womBase = womBase.substr(0, womBase.size() - 4);
}
Hoist into cli_box_emitter.hpp as inline stripExt(string&,
const char*). Generic on the suffix string so future callers
can use it for ".wob" / ".woc" / ".png" too — uses
string::compare instead of substr to avoid the temporary
allocation the original did per check.
Each call site collapses to a single line:
stripExt(womBase, ".wom");
cli_gen_mesh.cpp drops by ~96 lines. Output bytes verified
identical: firepit surface area 2.1100 m² unchanged.
After the addBox extraction, 21 procedural mesh primitives
each still open-coded the same 5-line addV vertex-emit lambda.
Add inline addVertex(WoweeModel&, vec3, vec3, vec2) to
cli_box_emitter.hpp (header so the per-vertex hot loop stays
inlineable), plus a per-float overload for the four handlers
(--gen-mesh-stairs, --gen-mesh-tube, --gen-mesh-capsule,
--gen-mesh-arch) that compute pos/normal/uv components inline
rather than building intermediate glm vectors.
Each lambda site collapses from a 5-line body to a 3-line
forwarding wrapper. Output bytes verified identical via
--info-mesh-stats: firepit surface area 2.1100 m² unchanged
across all variants tested (stairs/tube/capsule/arch/
firepit/mushroom).
Sets up the pattern so the next "shared mesh helper" is one
line of include, not another paste-in.
36 procedural mesh primitives in cli_gen_mesh.cpp each open-
coded the same ~30-line lambda for emitting a flat-shaded
axis-aligned box (per-face vertices for unique normals,
6 faces × 4 verts × 2 tris). Hoist the implementation into
cli_box_emitter.{hpp,cpp} as addFlatBox(WoweeModel&, ...)
with two overloads:
• addFlatBox(wom, cx, cy, cz, hx, hy, hz)
center + half-extents form, used by 34 primitives
• addFlatBox(wom, glm::vec3 lo, glm::vec3 hi)
lo/hi corners form, used by --gen-mesh-archway and
--gen-mesh-fence which compute corners directly
Each lambda site collapses from ~30 lines to a 3-line thin
wrapper: cli_gen_mesh.cpp drops from 7374 to 6989 lines.
Output bytes verified identical via --info-mesh-stats
(firepit surface area 2.1100 m² unchanged, vertex/triangle
counts match across firepit/canopy/dock/archway/fence).
Future box-based primitives now opt in by including one
header instead of pasting the lambda again.