luvcraft/mesher.lisp
Preserve one exact layout identity while concatenating mesh products.
The sites in one chunk plus the one-cell sampling halo around it.
CONTENT-INDEX is a projection through palette, not the logical
:block-content declaration itself. The light lanes already have direct
represented field declarations and bind those below.
A frozen copy of the world vocabulary's members at capture time: the halo's u16 indices are closed by it. Its length is the ABSENT index, one past the last member, so a halo sample outside resident terrain is a distinct member of the snapshot's own vocabulary.
An immutable dense chunk plus one-cell halo transferred to a CPU worker.
The snapshot owns compact u16 columns whose indices are the world vocabulary's own offsets, frozen by copying the member vector; the copy's length stands for an absent sample. Cell identity does not cross the thread boundary, and the worker never observes live chunk storage.
Append one interleaved vertex without constructing tuple objects.
The fourth lane carries normalized raw light readings, not an art-directed bake: shader edits can change the response curve without remeshing the world. The final two scalars carry the atlas tile offset under the atlas mapping and the face's four ternary edge classifications. Atlas UV resolution and edge unpacking belong to the shaders, not vertex producers.
The half-texel inset is local to a tile, independent of which atlas lane owns it or how wide the materialization is.
The 3x3x3 resident chunk neighborhood needed by one chunk mesh.
Resolve once the chunks every visibility and AO sample can reach.
Resolve one nearby world site to its resident chunk and dense offset.
The 3x3x3 window owns availability; voxel-space and chunk-domain own the decomposition and storage order beneath it. See #K3KZTG.
Read a nearby world site with no coordinate objects or hash-key consing.
Return the dense one-cell-halo offset for a world site, or NIL outside.
Resolve one halo site without aggregate dispatch in the meshing loop.
Read one world site from a meshing sample source.
Return (VALUES BLOCK STATUS) where STATUS is :RESIDENT or :ABSENT. Meshing itself never chooses a representation: the live world, a preresolved chunk neighborhood, and an immutable worker snapshot each answer through their own method, and further sample sources only need to add one.
Read one site's published light from a meshing sample source.
Return (VALUES SKY BLOCK STATUS) with raw 0..15 levels. STATUS is
:RESIDENT or :ABSENT; an absent or unlit sample answers zeros, and the
corner-averaging rules decide what that means rather than any caller
falling through to block-solid-p.
What a fragment cannot know about its own face is what lies beyond its edges. The mesher does know, so it classifies each of a face's four in-plane boundaries once and hands the answer to the surface shader.
This is the difference between a block world that reads as carved solids and one that reads as a lit grid: rounding every face edge over would draw a seam across the middle of an open plain, where the face merely continues into an identically oriented neighbour and there is no edge at all.
-1 concave: a block rises across this edge, so the surface fillets into the inner corner and gathers a little occlusion there. 0 flush: the same plane continues; leave the surface alone. 1 convex: nothing beyond the edge, so the surface rounds over it.
Gathering.
The mesher starts by collecting everything it will ask of the block vocabulary, once per job, into a few flat tables indexed by palette position: occupancy, surface emission, and one atlas tile offset per face. The loop below then reads u16 palette indices and u8 light levels straight out of the halo columns and never consults a block object, a face object, or a generic function per sample. The vocabulary is small and closed -- it changes only when someone redefines a kind at the REPL -- so the gathering is cheap and the protocol generics still decide what each kind means. See #FIGJ9R.
Per-palette-index answers the mesher gathered before its dense loop.
Six tile offsets per palette index, in *BLOCK-FACES* order.
Project palette through the block protocol into flat per-index tables.
The tables have one more row than palette: the final row is the absent
sample, whose occupancy comes from the mesher's absent-neighbor policy.
Index zero is air (NIL); every other entry is a block kind. Faces are
numbered in *BLOCK-FACES* order.
One face's geometry, gathered once from its block-face object.
Four corners as (cx cy cz) triples, then local UV per corner.
The dense loop.
Return (VALUES AO sky BLOCK) for one vertex corner.
base is the halo offset of the face's own cell; nstep steps across the face
normal and S1STEP/S2STEP along the two in-plane directions the corner leans
toward. Occupancy and light averaging follow exactly the rules of the
former per-sample accessors: a solid cell holds no light, an absent sample
contributes nothing, and the diagonal is unreachable behind two sides.
Append one face's six vertices at fill and return the new fill position.
base is the halo offset of the cell at world (X Y Z); WIDTH/HEIGHT/DEPTH
are the halo dimensions. Vertex order and every lane value match what the
per-sample accessors produced, so existing meshes and tests agree.
In-plane axes as the fragment stage chooses them: U is X unless the normal is X (then Z); V is Y unless the normal is Y (then Z).
The two side axes a corner leans toward, in ascending axis order.
Mesh the interior of one halo'd dense chunk.
indices, sky and block-light are the halo columns whose dimensions are
width x height x depth (the chunk plus one cell on every side); the origin is
the world coordinate of the chunk's first interior cell.
Pass one: exposed-face masks and the exact face count.
*BLOCK-FACES* order: -x +x -y +y -z +z.
Pass two: emit every exposed face into an exactly sized array.
Mesh a live chunk by gathering it into a halo snapshot first.
Owner-side and worker-side meshing share one dense loop, so they are equal by construction rather than by parallel maintenance.
Copy chunk and its one-cell halo into immutable worker-owned columns.
Every resident chunk's indices are already offsets under world's vocabulary,
so the halo is gathered by plain slab copies from the up to 27 neighbours,
with no per-cell decomposition, translation, or block object lookup. The
vocabulary's members are frozen into the snapshot by copying; their count is
the index written for absent halo samples.
Which local range of the neighbour lands where.
Halo sample coordinate of local (lx0 ly0 lz0).
An immutable dense chunk plus one-cell halo transferred to a CPU worker. The snapshot owns compact u16 columns whose indices are the world vocabulary's own offsets, frozen by copying the member vector; the copy's length stands for an absent sample. Cell identity does not cross the thread boundary, and the worker…
(name)Return the represented-value declaration published by global NAME, or NIL.
((agent application-agent) &key)PROPERTY: VALUES; -- the property a keyword, the values a list written space-separated.
How the children of a list are arranged.
(declaration)Return DECLARATION's heterogeneous quantity layout, or NIL.
(declaration)Return DECLARATION's backend or Common Lisp representation type, or NIL.
A fixed product repeated through flat storage at a physical lane stride. The inherited extent and projections describe one stride period so existing projection tools continue to inspect an element. ELEMENT-LAYOUT retains the unpadded product definition; no runtime element object is implied.
Test whether two compatible scalars are equal.
Multiplication and scalar scaling.
(accumulator mesh)Logical conjunction of tests and raw truth values.
Logical negation of one test or raw truth value.
The sites in one chunk plus the one-cell sampling halo around it.
(chunk-domain)(domain)Return the exact number of sites in finite DOMAIN. This deliberately says nothing about coordinate or offset representation. Those mappings belong to concrete domain protocols and are added only when a client needs to traverse them.
Addition over compatible quantities.
(name-and-options &body lane-descriptions)Define fixed columnar storage whose exact extent comes from one DOMAIN. Each lane has the same syntax as DEFINE-COLUMNAR-BUFFER. The generated MAKE-NAME constructor takes DOMAIN first, asks DOMAIN-CARDINALITY for its exact extent, checks the row declaration once, and allocates one specialized array per lane. The…
(scheme)(snapshot)(snapshot)(snapshot)(snapshot)(snapshot)(row lane-name)(materialization field-name)Return the definition object retained by MATERIALIZATION for FIELD-NAME.
(mesher world chunk)(mesher snapshot)(vertices px py pz local-u local-v shade nx ny nz
sky-level block-level emission tile
edge-u-low edge-u-high edge-v-low edge-v-high)Append one interleaved vertex without constructing tuple objects. The fourth lane carries normalized raw light readings, not an art-directed bake: shader edits can change the response curve without remeshing the world. The final two scalars carry the atlas tile offset under the atlas mapping and the face's four…
Division of two represented quantities.
(x y z)The non-negative remainder of integer division.
Logical disjunction of tests and raw truth values.
(dx dy dz)(world chunk)(world x y z)(neighborhood x y z)Resolve one nearby world site to its resident chunk and dense offset. The 3x3x3 window owns availability; voxel-space and chunk-domain own the decomposition and storage order beneath it. See #K3KZTG.
(space x y z)Decompose a world site into chunk and local scalar components. Return CHUNK-X, CHUNK-Y, CHUNK-Z, LOCAL-X, LOCAL-Y, and LOCAL-Z without constructing coordinate objects. Euclidean division keeps every local component non-negative, including for negative world coordinates. This is the dense traversal counterpart of…
Subtraction or unary negation.
Test whether one compatible scalar is at most another.
(domain x y z)(window x y z)Resolve world site X,Y,Z through WINDOW. Return (VALUES MATERIALIZATION OFFSET AVAILABILITY). AVAILABILITY is :AVAILABLE or :UNAVAILABLE; field and subsystem policy must interpret that fact rather than making the spatial protocol call absence air, solid, zero, or open sky. Implementations keep their existing…
(neighborhood x y z)(column offset)(halo-domain x y z)(domain local-x local-y local-z)Test whether one compatible scalar is less than another.
(snapshot x y z)(snapshot x y z)(samples x y z)Read one world site from a meshing sample source. Return (VALUES BLOCK STATUS) where STATUS is :RESIDENT or :ABSENT. Meshing itself never chooses a representation: the live world, a preresolved chunk neighborhood, and an immutable worker snapshot each answer through their own method, and further sample sources only…
(world x y z)Return one site as BLOCK and :RESIDENT, or NIL and :ABSENT. This sparse world-coordinate accessor constructs coordinate descriptors and a chunk lookup key. It is appropriate for inspectors, ray hits, collision probes, and sparse interaction. Algorithms over many cells should select a chunk/domain once and use…
(samples x y z)Read one site's published light from a meshing sample source. Return (VALUES SKY BLOCK STATUS) with raw 0..15 levels. STATUS is :RESIDENT or :ABSENT; an absent or unlit sample answers zeros, and the corner-averaging rules decide what that means rather than any caller falling through to BLOCK-SOLID-P.
(block)(world x y z)(mesher palette)Project PALETTE through the block protocol into flat per-index tables. The tables have one more row than PALETTE: the final row is the absent sample, whose occupancy comes from the mesher's absent-neighbor policy. Index zero is air (NIL); every other entry is a block kind. Faces are numbered in *BLOCK-FACES* order.
(block)BLOCK's own linear material radiance, independent of propagated light.
(tile &optional (domain *block-atlas-tile-domain*))(block face)(face corner)Project CORNER onto FACE's plane as tile-local UV coordinates. The rule is read from the face's own outward normal rather than its name: horizontal faces map world X,Z straight across the tile, and lateral faces keep the world-horizontal axis as U while flipping world Y into V so tiles hang upright.
Face geometry gathered from *BLOCK-FACES*; NIL until first gathered.
(solid indices sky block-light absent base nstep s1step s2step)Return (VALUES AO SKY BLOCK) for one vertex corner. BASE is the halo offset of the face's own cell; NSTEP steps across the face normal and S1STEP/S2STEP along the two in-plane directions the corner leans toward. Occupancy and light averaging follow exactly the rules of the former per-sample accessors: a solid cell…
Headings, paragraphs, figures and their IDs, mentions, marks.
(tables faces vertices fill solid indices sky block-light
width height depth base palette-index face-index x y z)Append one face's six vertices at FILL and return the new fill position. BASE is the halo offset of the cell at world (X Y Z); WIDTH/HEIGHT/DEPTH are the halo dimensions. Vertex order and every lane value match what the per-sample accessors produced, so existing meshes and tests agree.
Compare compatible quantities and produce dimensionless values.
(mesher palette indices sky block-light width height depth
origin-x origin-y origin-z)Mesh the interior of one halo'd dense chunk. INDICES, SKY and BLOCK-LIGHT are the halo columns whose dimensions are WIDTH x HEIGHT x DEPTH (the chunk plus one cell on every side); the origin is the world coordinate of the chunk's first interior cell.
(&key (code t))(mesher snapshot)(world chunk dependency-stamp)Copy CHUNK and its one-cell halo into immutable worker-owned columns. Every resident chunk's indices are already offsets under WORLD's vocabulary, so the halo is gathered by plain slab copies from the up to 27 neighbours, with no per-cell decomposition, translation, or block object lookup. The vocabulary's members…
(vocabulary)((bindings materialization materialization-type) &body body)Borrow a fixed materialization's domain, extent, row, and raw lane arrays. BINDINGS is (DOMAIN EXTENT ROW-DECLARATION (ARRAY LANE-NAME) ...). The materialization is evaluated once and each array receives its precise specialized array type.
((domain palette indices) chunk &body body)(arguments)(chunk)Intent: establish the smallest reusable spatial substrate beneath the current light and meshing products. Add heap-allocation-free decomposition, primitive local stepping with explicit boundary crossings, storage-order site enumeration, and face enumeration to chunk-domain or one narrowly related voxel-domain…
Intent. Stop the mesher from asking a CLOS block object, through a generic function, what it is — once per neighbour sample, some twenty times per face. Gather instead: project the (small, closed) block vocabulary through block-solid-p, block-surface-emission and block-face-tile into flat per-offset tables once per…
Turning resident block data into exposed-face triangle meshes.
The result of meshing is deliberately mundane: interleaved position, UV/shade, and normal triples of single floats. Meshing always starts by gathering: a chunk and its one-cell halo are copied into an immutable
block-mesh-snapshotof u16 palette indices and u8 light levels (whether for a worker thread or for owner-side meshing), and the small closed block vocabulary is projected through its protocol generics into flat per-index tables once per job. The dense loop then reads only those columns and tables; no block object, face object, or generic function is consulted per sample.