/** * Shared geometry helpers for stacked hex shells (frozen ice cap, liquid * water cap). Both shells share the same primitive — one merged hex prism * per submerged tile, top at the waterline, walls down to the tile's own * mineral cap — but layer their own material and mutation API on top. * * Centralising the geometry build, the per-tile vertex slots and the * `writeTilePrism` re-extrusion keeps the two shells in lockstep on the * topology contract: same vertex layout (top fan first, walls after), * same `faceToTileId` mapping, same height conventions. Caller code in * `buildSolidShell` and `buildLiquidShell` only adds a material + a few * tile-level mutations. */ import * as THREE from 'three'; import type { Tile } from '../../geometry/hexasphere.types'; import type { TerrainLevel } from '../types/terrain.types'; /** Per-tile vertex slot in the merged shell buffer. */ export interface TileSlot { tile: Tile; /** Underlying mineral elevation (band space) — wall starts here. */ baseBand: number; /** First vertex of the slot in the merged buffer. */ start: number; /** Vertex count owned by this slot in the merged buffer. */ count: number; } /** Inputs to {@link buildHexShellGeometry}. */ export interface HexShellGeometryConfig { tiles: readonly Tile[]; baseElevation: ReadonlyMap; topElevation: number; palette: TerrainLevel[]; bodyRadius: number; coreRadius: number; /** * When `true`, only the top fan of each prism is emitted — no walls. * Used by the liquid shell where the cap is a flat surface at the * waterline (a column of water has no visible "side" on a translucent * sheet). Defaults to `false` (full prism, ice-cap style). */ topOnly?: boolean; } /** Output of {@link buildHexShellGeometry}. */ export interface HexShellGeometry { /** Merged non-indexed buffer geometry, one prism per eligible tile. */ merged: THREE.BufferGeometry; /** Per-tile slot — addresses the slot's vertex range in `merged`. */ slots: readonly TileSlot[]; /** O(1) tile id → slot lookup. */ slotByTileId: Map; /** `faceToTileId[i]` returns the tile id of the i-th triangle. */ faceToTileId: readonly number[]; /** Live position attribute reference — patched by `writeTilePrism`. */ positionAttr: THREE.BufferAttribute; /** Live normal attribute reference — patched by `writeTilePrism`. */ normalAttr: THREE.BufferAttribute; /** Bridge between the prism extrusion frame and the body's coreRadius. */ heightOffset: number; /** Mutable per-tile current top band — updated by callers on mutation. */ currentTopBand: Map; } /** * Linearly interpolates between palette band heights so a fractional band * resolves to a smooth world-space height. Out-of-range bands clamp. */ export declare function bandToWorldHeight(band: number, palette: TerrainLevel[]): number; /** * Re-extrudes the prism geometry of a tile into the shared position * buffer at the tile's known vertex range. Used both at build time and * at runtime (mining, sea-level slider). * * When `topBand <= baseBand` the prism is fully collapsed: every vertex * of the slot range — top cap AND walls — is forced onto the tile's base * centre point. All triangles thus degenerate (zero-area), the GPU drops * them at primitive-assembly time, and the raycaster never hits them. * * `heightOffset` shifts every band height to the absolute world frame * `buildPrismGeometry` expects (`tileLen + delta`). * * `topOnly` mirrors {@link HexShellGeometryConfig.topOnly}: when `true`, * only the top fan is rewritten — the slot was built without walls so * there's nothing else to patch. */ export declare function writeTilePrism(positions: Float32Array, normals: Float32Array, slot: TileSlot, topBand: number, palette: TerrainLevel[], heightOffset: number, topOnly?: boolean): void; /** * Builds the merged hex-shell geometry from a set of tiles. Tiles missing * from `baseElevation`, or whose base sits at or above `topElevation`, * are skipped. The result is always a single non-indexed buffer ready to * be wrapped in a mesh by the caller — material choice + mutation API * are intentionally NOT included here. * * Returns `null` when no tile is eligible — lets the caller decide * whether to allocate a placeholder mesh or skip rendering entirely. */ export declare function buildHexShellGeometry(config: HexShellGeometryConfig): HexShellGeometry | null; /** * Vertex-count of the top fan for a tile. The prism geometry emits the * top fan first (`n` triangles × 3 vertices, where `n` is the tile's * boundary length: 5 for pentagons, 6 for hexagons), so the first * `topFanVertexCount` vertices of a slot are guaranteed to belong to * the top cap. */ export declare function topFanVertexCount(tile: Tile): number; //# sourceMappingURL=hexShellGeometry.d.ts.map