← gridmesh · version 0.2.6
32 public items, in source order. Generated from the registry index, which re-derives them from the package source at publish time — so a signature here is the one that version actually ships.
pub struct CellRef { ck: integer, ix: integer }
A coord→cell-index reference, stored in the spatial-index hash keyed on the encoded coordinate ck.
pub fn enc_coord(x: integer, y: integer) -> integer
Encode an offset coord into one integer key. The hex world is small; ±2^20 per axis covers it with room to spare and stays within i64.
pub fn build_index(xs: const vector<integer>, ys: const vector<integer>) -> hash<CellRef[ck]>
Build the coord→cell-index spatial index for a placement-ordered cell list given as parallel (xs, ys). O(N), built once and reusable across neighbour/on-axis queries.
pub fn axial_dq(d: integer) -> integer
Axial unit-direction components for hex axis d (0..5), via 60°·d. Branch form avoids per-call vector-literal allocation.
pub fn axial_dr(d: integer) -> integer
The r half of that same direction. Read as a PAIR with axial_dq — one direction, two components, and neither is meaningful alone.
pub fn step_x(x: integer, y: integer, d: integer, k: integer) -> integer
Offset coord k steps from (x, y) along hex axis d.
pub fn step_y(_x: integer, y: integer, d: integer, k: integer) -> integer
The y half of the pair. Row parity does not reach it — a step along an axis moves whole rows — which is why this ignores x where step_x cannot.
pub fn idx_at(cidx: const hash<CellRef[ck]>, x: integer, y: integer) -> integer
snap index of the cell at (x, y), or -1 if none. (cidx not index — index is a reserved keyed-collection-type keyword in loft.)
pub fn nbr_count_idx(cidx: const hash<CellRef[ck]>, cx: integer, cy: integer) -> integer
Index-backed filled-neighbour count (distance 1) — the 6 axis-1 cells.
pub struct SegMesh { kinds: vector<u8>, x0s: vector<single>, y0s: vector<single>, z0s: vector<single>, x1s: vector<single>, y1s: vector<single>, z1s: vector<single>, colors: vector<u8>, cell_ix: vector<integer> }
── B1: SegMesh accumulator ──────────────────────────────────────────
Struct-of-arrays line-segment mesh for segment/ribbon consumers (the crystal rule). Each segment is a 3D line (x0,y0,z0)→(x1,y1,z1) with a kind, a colour, and the OWNING cell index (cell_ix) — the latter lets a consumer attribute a segment back to its cell (e.g. GPU bloom-from- centre keyed by cell age) and lets the dirty-rebuild find-and-replace a cell's segments. Coordinates are single (f32 — the GPU VBO format, no precision loss vs what is rendered) and kind/colour are u8 (M1 narrowing: ~60 % less memory than the i64/f64 prototype).
pub fn seg_mesh_new() -> SegMesh
An empty segment mesh: the nine parallel arrays emit_segment appends into. Flat and parallel rather than a vector of records, so a chunk rebuild concatenates (seg_mesh_append) instead of walking a structure.
pub fn emit_segment(m: SegMesh, kind: integer, x0: float, y0: float, z0: float, x1: float, y1: float, z1: float, color: integer, owner: integer)
Append one segment owned by cell owner. Callers pass float coords and integer kind/colour; they are narrowed to the storage width here.
pub fn seg_len(m: const SegMesh) -> integer
Number of segments in the mesh.
pub fn seg_mesh_append(dst: SegMesh, src: const SegMesh)
Append all of src's segments onto dst (concatenate the nine parallel arrays). Used to assemble a render-group mesh from its chunks' CACHED meshes and to concatenate chunk meshes into a full build — order-preserving, so the consumer can rely on a stable per-group draw order.
pub struct ChunkKey { ck: integer, cx: integer, cy: integer }
A chunk-space coordinate. ck = enc_coord(cx, cy) is its identity for dedup in the dirty index.
pub fn chunk_of(x: integer, y: integer, shift: integer) -> ChunkKey
The chunk owning offset coord (x, y) for a field with shift (chunk = 1<<shift cells per axis; shift 5 = the moros 32×32 chunk).
pub struct ChunkField { layout: integer, xs: vector<integer>, ys: vector<integer>, cidx: hash<CellRef[ck]>, chunk_shift: integer, halo_k: integer, dirty: hash<ChunkKey[ck]>, buckets: hash<ChunkBucket[ck]> }
A grid of cells partitioned into chunks: the cell coordinates, a coordinate-to-cell index, and the dirty chunks and per-chunk buckets kept up to date as cells are added. field_new makes one and field_add_cell grows it.
pub fn field_new(layout: integer, xs: vector<integer>, ys: vector<integer>, chunk_shift: integer, halo_k: integer) -> ChunkField
Build a field from placement-ordered coords. layout is 0 (odd-row offset coordinates, the only layout); chunk_shift makes a chunk 1 << chunk_shift cells a side; halo_k is how far across a border a rule may read. The dirty index starts empty; the spatial index (cidx) and the chunk->cell partition (buckets) are built once (O(N)) and maintained incrementally thereafter (field_add_cell), so a later collect_dirty_inputs is O(dirty), not O(N).
pub fn field_add_cell(f: ChunkField, x: integer, y: integer)
Edit — append a new cell (its index = old len(xs)), add it to its chunk's bucket (O(1) amortised), and mark its chunk (+ halo-border neighbours) dirty. Keeping the bucket current here is what makes collect_dirty_inputs O(dirty) rather than a full re-partition.
pub fn field_mark_dirty(f: ChunkField, x: integer, y: integer)
Edit — RECOLOUR an existing cell: mark its chunk (+ halo border) dirty without touching the coord arrays or index (the cell stays; only its consumer-side payload — colour/height — changed). Erase uses field_remove_cell instead (it must also drop the cell from the index).
pub fn field_remove_cell(f: ChunkField, x: integer, y: integer)
Edit — REMOVE an existing cell: drop it from the spatial index (cidx) and its chunk bucket, then mark its chunk (+ halo border) dirty. The MIRROR of field_add_cell, sharing mark_borders so a removal flows through the IDENTICAL incremental rebuild path as a paint. The coord slot in xs/ys is deliberately LEFT in place (not compacted): cell indices the field already handed out stay stable, so a consumer's parallel per-cell arrays (e.g. the projector's bloom births, indexed by cell index) are not invalidated. The orphaned slot is never read again — its index is in no bucket and no longer in cidx — and re-painting the same coord allocates a FRESH index (field_add_cell appends), so identity is never reused.
pub fn clear_dirty(f: ChunkField)
Clear the dirty index after a rebuild.
pub fn dirty_count(f: const ChunkField) -> integer
Number of chunks currently dirty (verification / O(dirty) sizing).
pub fn chunk_is_dirty(f: const ChunkField, x: integer, y: integer) -> boolean
Is the chunk owning (x, y) currently marked dirty?
pub struct ChunkInput { key: ChunkKey, cell_ixs: vector<integer>, halo_ixs: vector<integer> }
── B3: ChunkInput + per-chunk gather ─────────────────────────────────
What a per-cell RULE needs for ONE chunk: the indices of the cells it OWNS (emit geometry for these) + the ≤halo_k border-neighbour cells in OTHER chunks it may READ as context. COMPACT — no payload, and NO copy of the shared spatial index (cidx). The rule receives cidx SEPARATELY as a read-only ref (keyed params don't deep-copy) and par forwards it as a context arg, so the per-chunk working set stays small and cache-resident (copying the whole index per chunk would be O(N)).
pub fn all_inputs(f: const ChunkField, halo_k: integer) -> vector<ChunkInput>
One ChunkInput per chunk that holds cells (the full-build work-list). Reads the wired-in f.buckets (no re-partition).
pub fn collect_dirty_inputs(f: const ChunkField, halo_k: integer) -> vector<ChunkInput>
One ChunkInput per DIRTY chunk (the incremental-rebuild work-list). Iterates ONLY the dirty set and looks up each dirty chunk's bucket — so the cost is O(dirty chunks × their cells), independent of total N. A dirty chunk with no owned cells (a halo-marked empty neighbour) is skipped. Clear the dirty index after rebuilding.
pub struct GroupKey { gk: integer, gx: integer, gy: integer }
One render group: (gx, gy) its position in group coordinates (chunk coordinates divided by group_dim), gk the two encoded as one key. group_of answers it.
pub struct GroupInput { key: GroupKey, chunk_cks: vector<integer> }
The chunk ck's a group contains that actually hold cells (the assemble work-list). No mesh here — gridmesh partitions; the consumer owns meshes.
pub fn group_of(cx: integer, cy: integer, group_dim: integer) -> GroupKey
The group owning CHUNK coord (cx, cy): chunk-space divided by group_dim. Uses chunk_div so any group_dim works (not just powers of two) — a free dial.
pub fn all_groups(f: const ChunkField, group_dim: integer) -> vector<GroupInput>
One GroupInput per group that holds cells (the full-build work-list). O(chunks): each non-empty chunk dedups into its group's chunk list.
pub fn collect_dirty_groups(f: const ChunkField, group_dim: integer) -> vector<GroupInput>
One GroupInput per DIRTY group (the incremental re-upload work-list). A group is dirty if any of its chunks is dirty; its chunk_cks lists ALL its member chunks that hold cells (so the consumer reassembles the group's VBO from those chunks' CACHED meshes — unchanged chunks copied, not rebuilt).
FLAT COST: derives the dirty groups from f.dirty (O(dirty)), then for each enumerates its group_dim × group_dim member chunk coords analytically and probes f.buckets — O(dirty groups × group_dim²), independent of total N. (Never scans all chunks, which would make per-edit cost grow with N.)