Moves all six world-asset interchange handlers (--export-wob-glb,
--export-wob-obj, --import-wob-obj, --export-whm-glb,
--export-whm-obj, --export-woc-obj) out of main.cpp into a new
cli_world_io.{hpp,cpp} module. WOB / WHM / WOC are our open
replacements for proprietary WMO / ADT-heightmap / ADT-collision
data; these are the bridge that lets the open formats round-trip
through Blender, MeshLab, Three.js, and the rest of the standard
3D toolchain.
main.cpp shrinks by 858 lines (8,997 to 8,140). The single-mesh
--import-obj handler stays inline for now -- it shadow-mirrors
cli_wom_io's --import-stl semantics and will move there next.
40th procedural mesh: simple 5-box table — flat top slab on
4 vertical corner legs. Pairs with --gen-mesh-bench /
--gen-mesh-throne / --gen-mesh-bookshelf for taverns,
dining halls, libraries, and study set dressing.
Defaults to 1.6 × 1.0 base × 0.85 tall, 0.10-square legs,
0.06-thick top — sensible dining-table proportions.
Customizable per dimension so a single primitive covers
desks, end tables, and big banquet tables.
Moves the four WOM interchange-format handlers (--export-obj,
--export-glb, --export-stl, --import-stl) out of main.cpp into
a new cli_wom_io.{hpp,cpp} module. WOM is our open M2
replacement; these are the bridge that lets it round-trip
through every external 3D tool — Blender, Three.js, slicers,
CAD packages — so the open format is actually useful.
main.cpp shrinks by 467 lines (9,464 to 8,997). The five WOB
and WHM exporters (--export-wob-glb, --export-whm-glb, etc.)
remain inline for a follow-up extraction.
32nd procedural texture: classic V-shaped herringbone done as
horizontal strips of parallel slanted lines whose slant
direction flips every strip. Implementation is a per-pixel
shear: shifting x by the row's local-y collapses each diagonal
into a vertical band in shifted-x space, so a single modulo
picks line vs background.
Useful for parquet floors, brick patios, fabric weaves, fish
scale-style chain mail, anywhere needing a strong directional
pattern. Two-color, defaults to 32-px strips with 12-px line
spacing and 4-px line width.
Moves all 4 GLB introspection handlers (--validate-glb /
--info-glb shared, --info-glb-tree, --info-glb-bytes,
--check-glb-bounds) out of main.cpp into a new
cli_glb_inspect.{hpp,cpp} module. GLB is our open replacement
for proprietary M2/WMO bake outputs, so these belong with the
other open-format tooling.
main.cpp shrinks by 657 lines (10,121 to 9,464). Every
handler preserves its --json output mode for machine-readable
reports.
39th procedural mesh: 5-panel cabinet (back / left / right /
top / bottom) divided into N bays by N-1 horizontal shelves,
with rows of pseudo-random book boxes on each level. Book
widths and heights vary per bay (seeded by bay index so
re-generating the same shelf gives the same layout) so the
result reads as a stocked library instead of a perfect grid.
Defaults to 1.5x2.0x0.4 with 4 shelves (~72 books). Useful
for studies, libraries, mage towers, anywhere that needs
filled-out furniture set dressing.
Moves the four structural validators for INTEROP file formats
(--validate-stl, --validate-png, --validate-blp, --validate-jsondbc)
out of main.cpp into a new cli_validate_interop.{hpp,cpp} module.
These check files coming in/out of wowee from third-party tools,
distinct from cli_format_validate.cpp which validates the native
open formats (WOM, WOB, WOC, WHM).
main.cpp shrinks by 524 lines (10,644 to 10,121). Each validator
preserves its --json output mode for machine-readable reports.
31st procedural texture: classic argyle pattern done by working
in a 45-rotated coord system (u, v) = (x+y, x-y) so lozenges
become axis-aligned squares for the checkerboard step. Diagonal
stitch lines fall out of u%cell and v%cell crossing zero.
Three-color: A/B for the alternating diamond fill, third color
for the diagonal stitch overlay. Defaults to 64-pixel cells with
2-pixel stitches. Useful for sweater fabric, seat cushions,
heraldic banner overlays.
Moves the five single-file format converters (--convert-m2,
--convert-wmo, --convert-dbc-json, --convert-json-dbc,
--convert-blp-png) out of two dedicated post-loop blocks in
main.cpp into a new cli_convert_single.{hpp,cpp} module. The
batch wrappers in cli_convert.cpp keep working — they shell
out to wowee_editor with these flags.
main.cpp shrinks by ~335 lines (10,979 → 10,644). The two
trailing for-loops were dead code after wiring the dispatcher
into the main loop, so they're gone too.
38th procedural mesh: classic 6-sided coffin with the
narrow-head / wide-shoulder / tapered-foot top-down profile
that's instantly recognizable from any angle. Built as 6 side
quads + top lid fan + bottom panel fan, all with face-shared
normals so it shades cleanly under any lighting.
Pairs with --gen-mesh-grave for graveyard set dressing.
Defaults to 2.0×0.8×0.6 (length × shoulder-width × height).
Moves the four schema-migration handlers (--migrate-wom,
--migrate-zone, --migrate-project, --migrate-jsondbc) out of
main.cpp into a new cli_migrate.{hpp,cpp} module. Same
behavior — they're idempotent in-place upgraders for older
WOM revisions and JSON DBC sidecar schemas. main.cpp shrinks
by 282 lines (11,261 → 10,979).
3-color crossing-band pattern: 6-band repeat sequence (A A B
C C B) per axis, with the pixel color at any position being
the average of the horizontal-band and vertical-band colors.
That averaging at intersections produces the characteristic
diamond grid of Scottish tartans without explicit "weave"
math — the band overlap pattern just falls out.
Defaults: bandPx=32 (repeat=192px). Useful for clan banners,
kilts, blanket textures, fabric set dressing. Brings the
procedural texture pattern set to 33.
Moves the 3D-export bake handlers out of main.cpp:
--bake-zone-glb --bake-zone-stl --bake-zone-obj
--bake-project-obj --bake-project-stl --bake-project-glb
The STL + GLB project bakes share a combined dispatcher (one
function with internal STL-vs-GLB branching) since they walk
the same per-zone asset list and only differ in the output
emission code.
main.cpp drops 12,119 → 11,261 lines (-858). The combined-OR
opener spanning multiple lines created a parse-error fragment
in the extraction; caught + manually fixed before commit
(same pattern as the WOM info attachments/particles/sequences
extraction).
5-box composite: low pedestal slab + seat block + tall
vertical backrest at -Z + 2 small armrests on the +X/-X
sides. Pedestal is wider than the seat for a stable
foundation, seat thickness is 30% of total seat height.
Defaults: seatW=0.8, seatH=0.5, backH=1.5, pedSize=1.2.
Useful for throne rooms, hero seats, judgement halls,
royal court set dressing. Brings the procedural mesh
primitive set to 37.
Moves the report-export handlers (md / csv / html / sha256 /
graphviz) for zone & project audits out of main.cpp:
--export-zone-summary-md --export-zone-csv
--export-zone-checksum --export-project-checksum
--validate-project-checksum --export-zone-html
--export-project-html --export-project-md
--export-quest-graph
Also moves the file-scope wowee_sha256 namespace (the SHA-256
implementation that the checksum exporters use) into the new
module's anonymous namespace — it had no other callers in
main.cpp so no cross-TU coupling needed.
main.cpp drops 13,120 → 12,119 lines (-1,001). Build error
during extraction (missing #include <unordered_set>) caught
and fixed.
Vertical color gradient from dark (bottom) to hot (top), mixed
with multi-octave smooth noise so the flame boundary wavers
randomly rather than reading as a clean horizontal line.
Vertical position curve is squared so the dark stays dark
longer and the hot saturates faster — matches real-flame
appearance where most of the body is dark with a bright tip.
Useful for torches, braziers, magical effects, lava-zone set
dressing, fireplace texture details. Brings the procedural
texture pattern set to 32.
Moves the four extracted-Data-tree audit handlers out of main:
--info-extract (per-extension counts + bytes)
--info-extract-tree (per-directory rollup)
--info-extract-budget (proprietary share + open-format gap)
--list-missing-sidecars (find unconverted .m2/.wmo/.blp/.dbc)
All four operate on a Blizzard-format extracted Data tree —
they audit what's there and what's missing in the migration
from proprietary formats to open ones.
main.cpp drops 13,485 → 13,120 lines (-365). Behavior verified
by re-running --info-extract on a test zone (same output).
Square cage frame: top + bottom thin slabs + 4 corner posts
(thicker than bars) + N evenly-spaced bars per side. Bars on
each side span perpendicular to that side's plane so the
cage reads as enclosed from any viewing angle.
Defaults: width=1.5, height=2.0, barsPerSide=5, barR=0.04.
Useful for prison cells, animal pens, dungeon set dressing,
caged exhibits. Brings the procedural mesh primitive set to 36.
Moves the items.json read-only inspection handlers out of
main.cpp:
--list-items --info-item
--validate-items --validate-project-items
--info-project-items
Item editing handlers (--add-item, --set-item, --remove-item,
--add-quest-reward-item) stay in main.cpp since they share
state with quest reward editing logic and would need a
broader extraction.
main.cpp drops 13,887 → 13,485 lines (-402). Behavior
verified by re-running --list-items on a non-items zone
(same error message).
Water-color background with N branching coral structures
that grow from the bottom edge upward. Each branch walks a
curved path (random angle drift) drawing a thick stroke,
splitting into thinner sub-branches at random intervals so
the result reads as organic coral rather than straight lines.
Iterative stack-based growth (no recursion) with split cap
at 256 to bound runtime. Defaults: branchCount=12, seed=1.
Useful for underwater zones, ocean floor, mer-people set
dressing, swamp coral fungi. Brings the procedural texture
pattern set to 31.
Moves the NPC spawn / object placer audit + ground-snap
handlers out of main.cpp:
--snap-zone-to-ground --snap-project-to-ground
--audit-zone-spawns --audit-project-spawns
--list-zone-spawns --list-project-spawns
--diff-zone-spawns --info-spawn
All operate on creatures.json + objects.json sidecars and
the WHM terrain heightfield via WoweeTerrainLoader.
main.cpp drops 14,628 → 13,887 lines (-741). Behavior verified
by re-running --audit-zone-spawns on a test zone (PASSED with
0 issues, same as before).
Stack of N square blocks with alternating widths: even-indexed
blocks (0, 2, 4...) get full base width, odd blocks (1, 3, 5...)
get 70% — gives the carved-segment look characteristic of
totem poles.
Defaults: baseW=0.5, 5 segments, segH=0.5. Useful for tribal
zones, druid groves, fairgrounds, primitive village markers.
Brings the procedural mesh primitive set to 35.
Picks up two stragglers that should have been part of the
content-info family extraction in c519ee3 — they were earlier
in main.cpp (lines 1079, 1139) than the contiguous block I
extracted, so the prior pass missed them. Moving them now
puts the entire creature/object/quest inspection family in
one translation unit (18 handlers total).
main.cpp drops 14,732 → 14,628 lines (-104). Behavior
verified by re-running --info-quests on a non-zone path
(same error message).
Solid PCB background plus N traces that walk the surface in
orthogonal Manhattan style — each trace alternates random
horizontal + vertical segments (3-6 segments per trace,
8-32 px each), with a 3×3 "via" dot at every corner so the
routing reads as intentional rather than random scribbles.
Defaults: traceCount=24, seed=1. Useful for sci-fi panels,
hacker zones, magitek/arcanocore set dressing, robot
texture details. Brings the procedural texture pattern set
to 30.
Moves the file-comparison handlers out of main.cpp into their
own translation unit:
--diff-wcp --diff-zone
--diff-glb --diff-wom
--diff-wob --diff-whm
--diff-woc --diff-jsondbc
--diff-extract --diff-checksum
main.cpp drops 15,653 → 14,732 lines (-921). One build error
during extraction (missing #include for NpcSpawner /
ObjectPlacer / QuestEditor used by --diff-zone) caught by
build and fixed.
6-component composite: square base slab + 4 cylindrical
pillars (12-segment, inset by pillarR so they sit fully on
the base) + flat roof slab on top with 5% overhang past the
base footprint. Pillars + roof create an open canopy.
Defaults: size=1.5, pillarH=2, pillarR=0.1, roofT=0.15.
Useful for wayside shrines, gazebos, well covers, market
stalls, religious altars in temples. Brings the procedural
mesh primitive set to 34.
Milestone: kArgRequired entries reaches 300.
Moves the seven proprietary-data-tree handlers out of main.cpp:
--migrate-data-tree --bench-migrate-data-tree
--list-data-tree-largest --export-data-tree-md
--info-data-tree --strip-data-tree
--audit-data-tree
All operate on a Blizzard-format extracted Data tree (the .m2/
.skin/.wmo/.blp/.dbc files) — they audit, migrate, or strip
proprietary-format files in support of the open-format
migration story.
Original placement spanned two sub-blocks (12546-12892 and
13093-13417 in main.cpp) interrupted by --gen-texture and
--add-texture-to-zone in the middle. Extraction collapses
both sub-blocks into one cohesive translation unit.
main.cpp drops 16,321 → 15,653 lines (-668). Behavior verified
by re-running --info-data-tree against a missing directory.
3-octave smooth noise field thresholded by `coverage` to make
rust blob regions, blended with the metal base color via a
0.12-wide smoothstep so patches feather into clean metal
rather than stepping. Per-pixel grain jitter on top so neither
material reads as flat.
Defaults: coverage=0.4 (~40% rust), seed=1. Useful for
weathered armor, abandoned machinery, ruined castle gates,
shipwreck debris. Brings the procedural texture pattern
set to 29.
Moves the three zone & project metadata inspection handlers
out of main.cpp:
--info-zone (single zone.json print)
--info-zone-overview (high-level zone digest)
--info-project-overview (per-zone summary table for a project)
All three load zone.json via wowee::editor::ZoneManifest.
main.cpp drops 16,564 → 16,321 lines (-243). Behavior verified
by re-running --info-zone + --info-project-overview against
existing test zones.
Three-box composite: long thin seat plank on top + 2 leg
slabs at the ends (positioned at 90% along the bench length
to leave a small overhang on each side). Legs are vertical
Y-aligned slabs spanning the full height from floor to
bottom-of-seat, ~5% of bench length thick.
Defaults: length=1.5, seatY=0.5, seatT=0.06, seatW=0.4. Useful
for taverns, plazas, roadside rest stops, council halls.
Brings the procedural mesh primitive set to 33.
Per-cell hash picks one of 3 colors for each square tile, with
1-pixel black grout on the top + left edges of every cell so
tiles read as physically separated. Exit log breaks down how
many tiles got each color so callers can verify the seed
distribution.
Defaults: tilePx=16, seed=1. Useful for cathedral floors,
stained-glass set dressing, ornate plaza paving. Brings the
procedural texture pattern set to 28.
Moves the six WoWee Content Pack (.wcp) handlers out of
main.cpp:
--list-wcp --info-wcp
--info-pack-budget --info-pack-tree
--pack-wcp --unpack-wcp
All six defer to wowee::editor::ContentPacker for actual pack
I/O; the handlers just parse args and format output, so the
extraction has no behavioral impact on the pack format itself.
main.cpp drops 17,766 → 17,505 lines (-261). Behavior verified
by re-running --info-wcp on a missing file (same error message).
Two-box composite: a wider low base + a vertical tablet
centered on top. Base is deeper than tablet (1.5×) and base
height is 20% of tablet height — proportions that read as a
stable foundation supporting an upright stone.
Defaults: tablet 0.6×1.0×0.15, base width 0.8. Useful for
graveyards, undead zones, memorial set dressing, ruined
chapel courtyards. Brings the procedural mesh primitive set
to 32.
Moves the proprietary-format inspection commands out of main.cpp
into their own translation unit. Each reads a Blizzard-format
file and prints its structure:
--info-png --info-blp
--info-m2 --info-wmo
--info-adt --info-jsondbc
main.cpp drops 18,198 → 17,766 lines (-432). Behavior verified
by re-running --info-png on a generated noise texture.
Solid wall background plus N vine paths that walk upward from
the bottom edge with a smooth cosine drift + tiny per-step
horizontal jitter. Each vine paints 2 pixels wide on every row
it visits so the trail reads as a thin band rather than a
single-pixel line.
Defaults: vineCount=8, seed=1. Useful for ruined castle walls,
overgrown ruins, jungle temple textures, ivy-covered facades.
Brings the procedural texture pattern set to 27.
Moves the four bulk format-conversion handlers out of main.cpp:
--convert-m2-batch (M2 → WOM)
--convert-wmo-batch (WMO → WOB)
--convert-blp-batch (BLP → PNG)
--convert-dbc-batch (DBC → JSON)
These all share the same pattern: walk srcDir recursively for
files of the input extension and fan out to the single-file
--convert-* counterpart via subprocess (preserving the existing
per-file logic as the source of truth, no duplication).
Single-file converters (--convert-m2, --convert-wmo, etc.) and
the --migrate-* meta-commands still live in main.cpp; they're
in dedicated argv-rescan loops that need a different extraction
approach.
main.cpp drops 18,396 → 18,198 lines (-198). Behavior verified
by re-running --convert-blp-batch with a missing directory and
confirming the same error message.
Composite banner: 12-segment vertical pole cylinder with top
and bottom caps + a rectangular flag attached at the top of
the pole, draped along -Z. The flag is two-sided (front faces
+X, back faces -X) so it reads from both viewing angles
without needing backface-culling-disabled materials.
Defaults: poleH=3, poleR=0.05, flagW=0.8, flagH=1.2. Useful
for guild halls, faction territory markers, military camps,
parade dressing. Brings the procedural mesh primitive set
to 31.
Moves the open-format validation + project-audit handlers out
of main.cpp:
--validate --validate-wom
--validate-wob --validate-woc
--validate-whm --validate-all
--validate-project --validate-project-open-only
--audit-project --bench-audit-project
--bench-validate-project
Also moves the four shared validate*Errors helpers (validateWom/
Wob/Woc/WhmErrors, ~365 lines) into the same module's anonymous
namespace — they were file-scope helpers in main.cpp used only
by these handlers, so co-locating eliminates the cross-TU
coupling.
main.cpp drops 19,446 → 18,396 lines (-1,050). Two build errors
caught during extraction (wrong include path for the WHM loader
header; missing #include for ContentPacker / std::set / std::map);
all fixed before commit.
Solid background fill plus randomly placed stars at varied
brightness — most stars dim (30-65% blend toward star color),
occasional bright stars (85-100% blend) — so the sky reads
with depth rather than as uniform noise. Exit log breaks down
how many bright vs faint stars actually landed.
Defaults: density=0.005 (~0.5% of pixels become stars), seed=1.
Useful for skybox top-faces, distant night sky planes, magical
constellation set dressing. Brings the procedural texture
pattern set to 26.
Moves the WOM model inspection commands out of main.cpp:
--info (bare WOM summary)
--info-batches (per-batch material info)
--info-textures (texture path list)
--info-doodads (WOB doodad set / instance list)
--info-attachments ⎫ combined handler with same M2 load +
--info-particles ⎬ skin merge but different sub-array
--info-sequences ⎭ iteration
--info-bones (bone hierarchy)
--export-bones-dot (Graphviz DOT output)
main.cpp drops 20,005 → 19,446 lines (-559). Behavior verified
by running --info, --info-batches, --info-textures on a fresh
WOM. Build error during extraction (combined-or handler header
spanned 4 lines, the transform script only stripped the first;
also missing #include for WoweeBuildingLoader) caught by build
and fixed before commit.
Composite cart: rectangular bed box + 2 axis-along-Z cylindrical
wheels mounted on each side at the bottom of the bed. Each wheel
has 16 angular segments + front/back caps. Bed sits at y=wheelR
so the wheels touch the ground at y=0.
Defaults: 1.6×0.8×0.5 bed, wheelR=0.35. Useful for medieval
village clutter, market scenes, NPC vendor decoration. Brings
the procedural mesh primitive set to 30.
Moves the WOM mesh editing/transform handlers out of main.cpp:
--add-texture-to-mesh --scale-mesh
--translate-mesh --strip-mesh
--rotate-mesh --center-mesh
--flip-mesh-normals --mirror-mesh
--smooth-mesh-normals --merge-meshes
These are the post-generation manipulators (load → mutate → save)
distinct from the geometry generators in cli_gen_mesh.cpp and
the heightmap I/O in cli_mesh_io.cpp.
main.cpp drops 20,741 → 20,005 lines (-736). Behavior verified
by piping a fresh cube through scale → translate → center.
Multi-octave cosine-product noise (4 octaves at doubling
frequency, halving amplitude) thresholded by `coverage` so
values above the threshold blend toward cloud color and below
fade to sky. A 0.15-wide smoothstep band feathers cloud edges
instead of stepping hard.
Defaults: coverage=0.5 (mixed clouds), seed=1. Useful for
skybox cubemaps, distant sky planes, atmospheric backdrop
art. Brings the procedural texture pattern set to 25.
Moves the three mesh-PNG bridge handlers (--displace-mesh,
--gen-mesh-from-heightmap, --export-mesh-heightmap) out of
main.cpp into their own translation unit. These three are
distinct from the gen-mesh-* primitive generators in that
they read or write external image files rather than synthesize
geometry from parameters alone.
main.cpp drops 21,061 → 20,741 lines (-320). Behavior verified
by re-running gen-mesh-from-heightmap → validate-wom → and
displace-mesh on a fresh plane.
Composite mushroom: 12-segment cylindrical stalk + 16×8
hemisphere cap on top (top half of a UV sphere). Cap radius
is independent of stalk radius so the silhouette can match
anything from a slim toadstool to a wide morel. Stalk has a
bottom cap and the hemisphere's lower edge is sealed against
a flat -Y disc (the "gills") so the mesh is watertight from
all viewing angles.
Defaults: stalkR=0.1, stalkH=0.6, capR=0.4. Useful for
forest decoration, swamp zones, fairy-ring set dressing.
Brings the procedural mesh primitive set to 29.
Moves the bare --gen-mesh dispatcher (cube/plane/sphere/cylinder/
torus/cone/ramp internal switch — 391 lines) and the related
--gen-mesh-textured handler (~72 lines) into the existing
cli_gen_mesh.cpp module.
The bare --gen-mesh handler renamed to handleMeshDispatch since
'handleMesh' would shadow the dispatcher class. --gen-mesh-textured
matched first in the dispatch chain to keep the longer-name
convention consistent with --gen-texture-noise vs -noise-color.
main.cpp drops 21,526 → 21,061 lines (-465). Behavior verified
by re-running --gen-mesh cube/sphere/torus.
Vertical streaks of varying brightness (per-column hash gives
each streak a stable shade in 0.85..1.10) sway-warped per-row
via a slow cosine offset, plus dark vertical cracks at random
columns where bark splits as the trunk expands.
Defaults: density=0.04 (~4% of columns become cracks), seed=1.
Useful for tree-trunk textures, wooden palisades, bark-clad
buildings. Brings the procedural texture pattern set to 24.
Moves stairs, grid, disc, tube, capsule, arch, pyramid, fence,
and tree into the existing cli_gen_mesh.cpp module. Together
with the 12 composite props extracted in 00754941 and the
anvil added in cd4bdfec, the module now contains 22 of the
28 procedural mesh primitives.
Remaining mesh handlers in main.cpp: --gen-mesh dispatcher
(cube/plane/sphere/cylinder/torus/cone/ramp), --gen-mesh-from-
heightmap, --gen-mesh-textured. Those have specialized I/O or
embedded sub-dispatch and will move in a follow-up batch.
main.cpp drops 22,681 → 21,526 lines (-1,155). Behavior
verified by re-running stairs/disc/fence/tree.
Composite anvil silhouette: 4-step pedestal (wide base → narrow
waist → wide cap → flat work face), each step a single addBox
call, plus a 4-vertex tapered prism for the horn extending in
+X past the face. The prism's 4 side triangles converge to a
single tip vertex (the horn point), with a sealed base square
behind it.
Defaults: length=1.0, width=0.4, hornLen=0.5, bodyH=0.5. Useful
for blacksmith shops, dwarven forges, weapon-crafting set
dressing. Brings the procedural mesh primitive set to 28.
Added directly to cli_gen_mesh.cpp — proves the modular file
accepts new primitives the same way as extracted ones.