51st procedural texture: two interleaved sinusoidal strands
running along the Y axis. Each strand's X position oscillates
as W/4·sin(2π·y/period); the second strand is phase-shifted
by π so the two snake around each other forming the classic
helical twist of a tightened rope.
Within each strand, brightness rises from 0.55 at the edge
to 1.0 at the centerline (cos² falloff) — gives the rounded
3D appearance of cylindrical fibers without a separate
shadow pass.
Useful for hanging ropes, ship rigging, tied-bundle textures,
suspension bridges, market-stall awning ties, and any
"twisted cord" surface where a flat color would read as
ribbon rather than rope.
Default 24-pixel period with 8-pixel strands renders cleanly
at 256x256 with about 10 visible twists.
Convert any WOM mesh into a WOC collision file via
WoweeCollisionBuilder::addMesh, with optional --weld <eps>
that merges shared positions into a single canonical index
before baking. The weld pass is what makes per-face-shaded
procedural primitives produce a properly indexed collision
mesh — adjacent faces that previously authored 4 unique
verts per face now share 1 corner across all incident
faces, so raycasts can traverse edges naturally.
Also accepts --steep <deg> to control the walkable/steep
classification threshold (default 50° from horizontal,
matching the terrain pipeline).
Smoke-tested end-to-end:
• firepit: 240 verts → WOC with 120 tris (20 walkable
floor, 20 steep stone walls, rest neutral)
• tent_solid: 18 verts welds to 6, produces 8-tri WOC
• canopy: 216 → 56 weld, 108 tris, 30° steep cut
Pairs naturally with --info-mesh-stats --weld for
collision-quality QA before baking.
56th procedural mesh primitive. Builds a rectangular awning
on 4 corner posts with a flat overhead panel and optional
drape lips hanging down from each edge:
• 4 corner posts inset by postR so their outer faces line
up flush with the panel edges above
• flat panel slab spanning the full footprint, sitting on
top of the posts
• optional drape lips on all four panel edges (set drape=0
for a clean flat-top canopy with no hanging fabric)
All axis-aligned boxes; the no-drape variant is fully
watertight (verified via --info-mesh-stats --weld). Useful
for market-square stalls, vendor stations, alchemist booths,
caravan rest stops, and tournament viewing platforms.
Add --info-wob-stats reporting per-group + aggregate
triangle counts, surface area, edge analysis, and watertight
check for WOB buildings. Same flag surface as --info-mesh-stats
including --weld <eps> for true topological closure check
on per-face-vertex meshes.
Also fixes a correctness bug in the weld implementation
of --info-mesh-stats: the previous code used a 64-bit hash
of the quantized position as the equality key, which gave
false-positive collisions that incorrectly merged distinct
vertices. A unit cube's 8 corners collapsed to 2 positions
under the buggy hash. Replace with std::map keyed on the
actual quantized (qx, qy, qz) tuple so equality is exact.
Re-verified: cube 8→8 watertight YES; firepit 240→80
watertight YES (was wrongly reporting 56 unique with 48
non-manifold edges); tent_solid 18→6 watertight YES;
tent_fixed 21→9 with 5 boundary edges at the door perimeter
(correct — door is intentionally open).
50th procedural texture: smooth cosine ridges that lerp
between bgHex (trough) and hiHex (crest) over a configurable
period. Direction defaults to vertical ridges (wave varies
along X) — the standard corrugated-sheet-metal-roof look —
with optional horizontal mode for siding panels and pipe
texturing.
Useful for sheet-metal roofing, corrugated-iron walls,
sci-fi paneling, and any "ridged plate" surface where the
existing flat --gen-texture-metal would read as too uniform.
Default 16px period at 256x256 reads cleanly with about 16
ridges across the tile.
55th procedural mesh primitive. Builds the classic 3-2-1
firewood pyramid:
• 3 cylindrical logs along the bottom row, sitting on
the ground at radii apart
• 2 logs nestled in the gaps of the bottom row
• 1 log crowning the pile
Vertical step uses cos(30°) = sqrt(3)/2 so adjacent logs
touch tangentially, giving the close-packed look of a real
chopped-wood stack. Logs lie horizontally along the Z axis
with closed end caps; sides parameter controls cross-
section smoothness (default 12, range 6..64).
Pairs naturally with --gen-mesh-firepit and --gen-mesh-tent
for outdoor camp / homestead / lumberyard set dressing.
49th procedural texture: horizontal plank-floor pattern.
Each plank gets:
• a hash-derived per-plank brightness offset (-24..+24)
so adjacent boards read as separate pieces of wood
rather than one long stripe
• a 1px horizontal seam at its bottom edge
• a 1px vertical end-seam at a hash-jittered x position,
staggering plank ends across rows
• optional darker grain streaks at evenly-spaced columns
(jittered per plank so the pattern doesn't grid-align)
Useful for inn/tavern floors, ship deck planking, bridge
surfaces, market-stall counters, and any wood-floor surface
where the existing single-grain --gen-texture-wood would
read as one giant board.
Default 16px plank height with 5 grain streaks gives a
recognizable floor at 256x256 without aliasing.
Reports total surface area, per-triangle area histogram
(min/max/mean/median), edge analysis (boundary / manifold /
non-manifold counts), watertight check, and degenerate
triangle count for a single WOM.
Watertightness here is the topological notion: every edge
must be shared by exactly 2 triangles via shared vertex
indices. This is what collision bakes and physics queries
actually need — visually-closed primitives whose adjacent
faces don't weld vertices will (correctly) report as
non-watertight.
Already caught a real defect in handleTent's door-fan
triangulation: the fan covers the door cutout area with
a stray triangle and leaves a vertex unreferenced.
Edge analysis is gated by triCount <= 2M to keep the
unordered_map bounded for huge baked terrain meshes.
54th procedural mesh primitive. Builds a recognizable
campfire setup from axis-aligned boxes only:
• ring of N stone cubes evenly placed at radius ringR
around the firepit center, sitting on the ground
• two crossed log boxes at the center (one along X,
one along Z, slightly raised) — the unmistakable
visual cue separating a firepit from a generic
decorative stone ring
Pairs naturally with --gen-mesh-tent for outdoor camp
set dressing (Horde encampments, Defias hideouts, scout
overlooks). Default 0.5-radius ring with 8 stones reads
cleanly at 1:1 player scale.
48th procedural texture: brick-offset ring outlines. Even
and odd rows are shifted by half a cell width so each ring
interlocks visually with its neighbors above and below —
the classic chainmail-armor pattern. Each pixel is tested
against the nearest ring center; if its distance lies
inside [ringR - strokeW/2, ringR + strokeW/2] it's
painted as the ring color, otherwise background.
Useful for armor textures (mail tunics, helms, gauntlets),
metallic fabric set dressing on guard NPCs, and dungeon
gate/grate textures. Default ring radius 5 on a 14x10
brick spacing reads cleanly at 256x256 without aliasing.
53rd procedural mesh primitive. Builds a watertight A-frame
tent:
• two sloped roof panels meeting at a ridge that runs along
the X axis
• two triangular gables sealing the ends
• optional inverted-V door notch carved out of the +X gable
(parameterized by doorH and doorW; either set to 0 disables
the cutout for a solid gable)
• bottom face for collision-bake watertightness
Useful set dressing for Horde encampments, troll camps,
Defias bandit hideouts, scout/quartermaster overlooks, and
generic outdoor quest hubs.
Default footprint 1.6 x 1.0 with 0.9 ridge height and a
0.5 x 0.4 door notch — all dimensions overridable on the CLI.
47th procedural texture: knit fabric V-stitch — each stitch
occupies a cellW x cellH cell holding the V-shape made by
two diagonal strokes meeting at the apex (cellW/2, 0) and
dropping to the cell's bottom corners. Cells tile contiguously
in both axes giving the iconic chevron-zigzag appearance of
knitted fabric stitches.
Useful for sweater fabric, woolly NPC clothing, blanket
textures, mitten/scarf set dressing, dwarven knitwork.
Defaults to 16x12 cells with 2-px stroke width.
58th procedural mesh: 5-box double archway — 3 vertical posts
(left / shared center / right) plus 2 horizontal lintels each
spanning one opening. Pairs with the existing single
--gen-mesh-archway for plaza approaches, double-door tomb
fronts, formal garden entrances, paired temple entries.
Defaults to 1.40m × 2 openings with 2.40m opening height
(~3.16m total width × 2.60m height including lintels).
Splits the 138-line static-local kArgRequired array (the list
of flags requiring positional args) into a new
cli_arg_required.{hpp,cpp} module with extern linkage. Then
moves the three meta handlers that depended on it out of
main.cpp into cli_introspect.cpp:
- --validate-cli-help (uses the array for self-check)
- --version / -v (3-line printf)
- --help / -h (1-line passthrough)
main.cpp shrinks by 191 lines (677 to 486). Both the early
missing-argument detector in main() and --validate-cli-help
in cli_introspect.cpp now share one source of truth for the
arg-required list.