Kelsidavis-WoWee/tools/editor/cli_box_emitter.hpp
Kelsi 4573ff6c9f refactor(editor): extract setCenteredBoundsXZ helper
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.
2026-05-09 12:18:26 -07:00

128 lines
5.2 KiB
C++

#pragma once
#include "pipeline/wowee_model.hpp"
#include <glm/glm.hpp>
#include <cstdint>
#include <cstdio>
#include <filesystem>
#include <string>
namespace wowee {
namespace editor {
namespace cli {
// Initialize a fresh WoweeModel with the canonical procedural-
// primitive defaults: name derived from the base path's stem and
// version 3 (current). 64 handlers in cli_gen_mesh.cpp open-coded
// this 3-line block before extraction.
inline void initWomDefaults(wowee::pipeline::WoweeModel& wom,
const std::string& base) {
wom.name = std::filesystem::path(base).stem().string();
wom.version = 3;
}
// Set the WoweeModel's bound box for a primitive whose footprint
// is symmetric around the origin in X+Z and rises from y=0 to
// y=maxY. 21+ procedural mesh handlers use this exact pattern;
// extracting collapses two-line stanzas to one call.
inline void setCenteredBoundsXZ(wowee::pipeline::WoweeModel& wom,
float halfX, float halfZ, float maxY) {
wom.boundMin = glm::vec3(-halfX, 0.0f, -halfZ);
wom.boundMax = glm::vec3( halfX, maxY, halfZ);
}
// Save a WoweeModel and report a stderr message on failure.
// Returns true on success so the caller can do
// `if (!saveWomOrError(...)) return 1;`. The cmdName is included
// in the error message for context.
inline bool saveWomOrError(const wowee::pipeline::WoweeModel& wom,
const std::string& base,
const char* cmdName) {
if (wowee::pipeline::WoweeModelLoader::save(wom, base)) return true;
std::fprintf(stderr, "%s: failed to save %s.wom\n",
cmdName, base.c_str());
return false;
}
// Strip a file-extension suffix from a base path if present. Used
// pervasively by --gen-mesh-* / --bake-* / --info-* handlers that
// accept either `path/foo` or `path/foo.ext` as input — the loader
// expects the bare base, so the trailing ".wom" / ".wob" / ".woc"
// must be removed if the user typed it.
//
// Pattern was open-coded as a 4-line if-block in 64+ sites
// across cli_gen_mesh.cpp; hoisted here for one-line callers.
inline void stripExt(std::string& base, const char* ext) {
std::size_t extLen = 0;
while (ext[extLen]) ++extLen;
if (base.size() >= extLen &&
base.compare(base.size() - extLen, extLen, ext) == 0) {
base.resize(base.size() - extLen);
}
}
// Append a single batch covering ALL of wom.indices to wom.batches.
// Called at the end of every gen-mesh primitive (the procedural
// builders emit just one batch per primitive). The same 4-line
// "construct + populate + push" boilerplate was repeated in 53
// handlers before extraction.
inline void finalizeAsSingleBatch(wowee::pipeline::WoweeModel& wom) {
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);
}
// Append one vertex (position, normal, UV) to a WoweeModel and
// return its newly-assigned index. Inline because the procedural
// mesh primitives call this thousands of times per build and the
// abstraction shouldn't cost a function-call frame each time.
// Pre-extraction this was the same 5-line lambda copy-pasted into
// 21 different handlers.
inline uint32_t addVertex(wowee::pipeline::WoweeModel& wom,
glm::vec3 p, glm::vec3 n, glm::vec2 uv) {
wowee::pipeline::WoweeModel::Vertex vtx;
vtx.position = p;
vtx.normal = n;
vtx.texCoord = uv;
wom.vertices.push_back(vtx);
return static_cast<uint32_t>(wom.vertices.size() - 1);
}
// Per-float overload used by handlers that compute pos/normal/uv
// components inline rather than building intermediate glm vectors
// (--gen-mesh-stairs, --gen-mesh-tube, --gen-mesh-capsule,
// --gen-mesh-arch). Same semantics as the vec3/vec2 form.
inline uint32_t addVertex(wowee::pipeline::WoweeModel& wom,
float px, float py, float pz,
float nx, float ny, float nz,
float u, float v) {
return addVertex(wom, glm::vec3(px, py, pz), glm::vec3(nx, ny, nz),
glm::vec2(u, v));
}
// Append a flat-shaded axis-aligned box to a WoweeModel. The box
// is centered at (cx, cy, cz) with half-extents (hx, hy, hz). Each
// of the 6 faces emits its own 4 vertices with the face's outward
// normal, so adjacent faces don't share normals — exactly what
// flat shading needs. UVs are 0..1 across each face.
//
// Used pervasively by --gen-mesh-* primitives that build meshes
// from axis-aligned box primitives (firepit stones, dock pilings,
// canopy posts, woodpile logs, tent walls before the door cutout
// added one-off triangles, etc.). Hoisted out of cli_gen_mesh.cpp
// where 36 identical lambdas duplicated this implementation.
void addFlatBox(wowee::pipeline::WoweeModel& wom,
float cx, float cy, float cz,
float hx, float hy, float hz);
// Overload taking lower/upper corner positions (lo, hi). Some
// callers (--gen-mesh-archway, --gen-mesh-fence) compute corners
// directly rather than center+halfsize.
void addFlatBox(wowee::pipeline::WoweeModel& wom,
glm::vec3 lo, glm::vec3 hi);
} // namespace cli
} // namespace editor
} // namespace wowee