luvcraft/render.lisp
write-buffer writes mapped host-visible memory directly. Animated
streams therefore belong to the presentation slot: reacquiring this
slot is the proof that the GPU has finished reading its previous data.
The lens chain reads three different sources through one layout: the scene once, then each reduced attachment in turn.
Return the unique GPU resources retained by one drawable frame state.
The shadow's biases and filter radii are knobs: read at frame-pack time into the shadow control lanes, so a turn shows on the next frame.
Check the host texture format against the block shader's decoded result.
Make an outlined pixel-sized crosshair at screen X,Y, or at the centre.
Charcoal establishes a crisp edge on both snow and foliage; the smaller white pair is emitted afterward and paints over it.
Make the quad the cursor shader draws its arrow inside, tip at screen X,Y.
Only the hotspot and the scale live here: each vertex carries its offset from the tip in the shader's design grid, and the fragment stage turns that into the outline, the fill, and the shadow.
The arrow starts at the design grid's origin and runs to the extent its own outline reaches; the margin leaves room for the antialiased edge and the shadow cast down and to the right.
Make the one fullscreen triangle in normalized clip coordinates.
Pack a texel-stable orthographic light-space transform as four vec4 rows.
Returns the rows and the anchor to hand back next frame. The anchor is the
world point the light-space texel lattice is built around: it follows the
camera in whole texels of the current light basis, so camera translation
never moves the lattice by a fraction of a texel, and the sun's rotation
turns the lattice about the camera rather than about the world origin.
Without an anchor the camera position itself starts one.
Texel snapping stabilizes the map against translation but can do nothing about rotation, so the free choice of roll about the light axis is worth making well. World up is a continuous reference -- the tilted orbit never reaches the Y pole -- but it is a badly conditioned one: the sun's angle to it changes all day, the transverse component collapses toward the orbit tilt as the sun climbs, and the roll rate consequently peaks at noon, spinning the whole texel grid under the world exactly when the sun is highest. The sun's own axis of revolution keeps a constant angle to the sun at every hour, so the basis it induces simply turns with the day. #0604PY measures both the gain at noon and what it costs at dusk.
Rotation still slides the lattice under the world, by the angle times the distance from the pivot. Snapping the camera to a lattice through the world origin put that pivot at the origin, so a player standing a few hundred units out watched every shadow edge vibrate a texel many times a second however slow the day. The pivot is instead a persistent anchor that walks toward the camera in whole texels of this frame's basis: the lattice never shifts under translation, and it rotates about a point within a texel of the eye. The anchor is kept in double precision so that the walk does not itself wobble the lattice. #QWTQ6R
Pack the frame environment: camera lanes plus the evaluated sky.
Lane order must match *FRAME-UNIFORM-MEMBERS* exactly; the construction-time
check in block-world-camera-uniform-size keeps the two honest. camera-lanes
may replace the session camera's own five lanes with a camera expressed in
some other space; the environment lanes are packed the same either way.
The sky's cloud deck drifts, so the frame environment carries a bounded elapsed time alongside the fog band it shares a lane with.
The zenith and horizon lanes' spare w carry the target's height and width in pixels: what a vertex stage needs to size a pixel.
The texture resource owns atlas extent. Meshes retain only a tile offset under the mapping which painted that resource, so replacing it with a wider atlas needs no remesh.
Grading is art direction, not architecture: these are the live knobs the presentation stack reads every frame, so a SLY eval can retune the whole look of the running game without rebuilding a pipeline.
Engage the focus-plane background blur without a modal focus.
The focus plane is the depth at the centre of the frame, so a film shot that wants a subject sharp against a blurred background aims the centre ray at ground or blocks standing at the subject's distance. A global rather than a binding because the presentation uniform is packed on the canvas thread, not the thread directing the film.
How much of the blurred bright-pass image is added back in linear light.
The chain's kernel is wide and runs twice, so this is a glow spread over a sixth of the frame rather than a halo: past about a third it stops reading as light around the sun and starts reading as fog over everything.
The sun's presentation UV and how strongly it counts as on screen.
The weight fades the solar lens effects out as the disc leaves the frame or falls behind the camera, so a turn of the head does not pop the shafts.
Pack the presentation environment: texel sizes, lens gains, and the sun.
Lane order must match *POST-UNIFORM-MEMBERS* exactly; the construction-time
check in luvcraft-post-uniform-size keeps the two honest.
The presentation buffer byte size derived from the shader-visible block.
Presentation uniform ABI mismatch: the shader block occupies ~ ~D bytes but the host packs ~D.
Flatten block's byte-offset members into frame-buffer float positions.
This is deliberately luvcraft's fixed 32-bit-lane ABI adapter, not a claim about general uniform-block packing. The shader owns offsets and member quantities; the host independently owns the product it writes.
The frame buffer byte size derived from the shader-visible block layout.
Checked against the host's packed frame data at construction, so growing the frame uniform cannot silently diverge between shader and host.
Frame uniform ABI mismatch: the shader block occupies ~D ~ bytes but the host packs ~D.
Adopt resource into renderer's single release inventory.
Drop resource from renderer's inventory for immediate release.
Bind one lens-chain source: a sampled texture, linear filter, uniforms.
The reduced attachment size the lens chain runs at, at least one texel.
Everything below is sized to the frame rather than to the world, which
means a window resize invalidates all of it at once. Keeping the whole
set behind one constructor is what lets start-luvcraft and a live resize
agree on formats and usages without either one drifting.
Create the scene and presentation attachments as one GPU-object cohort.
The scene is drawn at render-extent into a linear HDR colour attachment with
its own depth buffer and reduced lens chain. World-space application panels
draw analytically into a transparent colour/depth pair at presentation-extent;
the presentation shader depth-composes that pair over the scaled scene before
native-density HUD and the complete surface copy.
Preserve the originating creation failure and make a best effort
to retire every partial candidate, even if one destroy also errs.
Adopt and atomically publish attachments as one frame-sized cohort.
Everything that may allocate is complete before either owner slot is changed. FRAME-ATTACHMENTS is the sole reader-visible publication.
Return renderer's currently published extent-sized GPU objects.
Release an unpublished or superseded attachment cohort from renderer.
Release renderer's currently published frame-sized image cohort.
Return the GPU objects in an attachment candidate, excluding its extents.
One fullscreen lens-chain stage, named by the fragment method it runs.
---------------------------------------------------------------------
The physics sphere drawer: the live pipeline and shared quad behind the
scene pass's instanced body draw. It registers through the overlay
protocol -- the renderer's own pipeline inventory is a closed slot set
-- so refresh-luvcraft-shaders rebuilds its shader methods and session
teardown releases it, but its draw is not an overlay's: the bodies are
encoded with the rest of the world geometry, where the cubes drew.
Owns the sphere pipeline and the one six-vertex quad every body shares.
Deliberately nothing: the bodies are drawn from the scene pass proper, before the player's arms and the particles, where the cubes once drew.
Create the sphere pipeline and quad for session and register the drawer.
The lowering has no fragment-depth output, so the quads test the terrain's depth without writing their own.
Forget every cached per-drawable binding, which names images that are gone.
The bind groups are keyed by drawable, not by size, so nothing else would notice that their scene, depth, and lens-chain views belong to the previous window. Dropping them here makes the next frame rebuild them against the attachments the renderer actually holds.
Release renderer's pipelines and GPU resources exactly once.
Likewise, failed resources remain in the one owner inventory.
Transactionally replace every extent-sized image owned by renderer.
The new cohort exists before any old object is released. If
creation fails, make-luvcraft-frame-attachments destroys its
partial candidate and the installed renderer remains coherent.
Vertex writes also precede publication so a failed write leaves
the old extent installed and makes the next frame retry.
Publication precedes retirement. Even if a backend reports a destruction failure, every reader now observes the complete new cohort instead of a half-cleared renderer.
Rebuild session's frame-sized images when either frame extent changes.
A Retina canvas has two deliberately different extents: the game scene renders once per logical point, while presentation and direct application UI render once per physical drawable pixel. This runs at the top of a frame, after the backend has synchronized the drawable and inside the callback which owns GPU replacement. The outgoing images stay alive until their last submission completes.
Pointer intent belongs to the session. The normal frame-boundary update replaces the renderer's centred candidate and retains DIRTY-P if its buffer write fails.
Return session's native-density world panels in painter order.
The canvas callback is the ownership boundary for all GPU replacement. MOP notifications from SLY workers have only marked these artifacts dirty.
The film's clock runs on the world's frames, so it advances here, before anything is encoded: the upload is an ordinary queue write, not part of this frame's command stream.
The same counts the benchmark records per sample, drawn against the live timeline so a frame-time spike can be read against the world that produced it.
An animal standing in the sun casts a shadow like anything else solid; a tumbling smash fragment deliberately does not.
So do the balls, drops, and gobbets: things with weight. The scene draws them as true spheres; a depth map is happy with the little turning cubes.
The sky triangle fills the frame before block geometry, with depth writes disabled; the clear value remains only a safe fallback.
The physics bodies, as ray-traced spheres: one instanced draw of camera-facing quads, records already ordered farthest first because the sphere pipeline blends without writing depth. The block pipeline and its bindings are restored afterwards for the player body and the particles, which expect them.
Before the text, so a caption drawn over the screen wins.
First-person geometry is above every world participant regardless of overlay attachment order. It still lives in the scene texture (and therefore the lens/grade chain), unlike the later HUD pass.
A held item's own geometry follows the analytic hands so glass, buttons, and live displays remain legible in the grip; neither body nor item enters the shadow map.
The lens chain: bright pass, separable blur, radial sun sweep. Each stage is one fullscreen triangle over the reduced attachment pair, leaving the blurred bloom in the primary and the shafts in the secondary for presentation to add back.
The separable pair runs twice. Convolving the thirteen-tap kernel with itself widens the glow by the square root of two without a second pair of attachments or a second pipeline, and the second pass is what turns a visible halo into light.
Retained application panels stay world-projected, but they are not another low-resolution scene material. Draw their analytic command streams at the physical presentation extent into a transparent HDR layer. Far-to-near ordering gives each panel ordinary painter semantics; its depth writes use :ALWAYS because independently generated coplanar analytic vertices are not bit-identical enough for an equality depth test. The final native depth is then compared with the logical scene depth in the post shader.
KMSDRM has no native cursor plane. A focused CLIM view still gets the same absolute pointer events as any other backend, so draw the crosshair geometry at their last position after the HUD itself.
Motion events publish only the newest pointer state. Consume it once at the frame boundary, no matter how many reports SDL drained.
Return the world X and Z the session's neighbourhood is centred on.
Advance session's animals and keep its neighbourhood populated with them.
Advance session to the time its acquired frame is expected to be visible.
Scene participants own their behavior while core owns the frame clock. An embodied agent therefore advances here without making core depend on the agent system which specializes this open protocol.
A moving interaction takes its turn after the world it moves in and before the player controller, which stands down while it carries them.
Held controls have immediate authority over the player's legs. Move To is still a useful player primitive, but touching movement cancels it instead of fighting a hidden autopilot.
Acquisition is the timing boundary: simulation and every visual clock now describe the beat this particular drawable is predicted to reach, not when the outer timer happened to ask for work.
PRESENTATION encloses acquisition and submission now, so remove the explicitly measured application phases nested inside it. This preserves the sample's old meaning while letting acquisition choose the frame's target time.
The frame mark closes Tracy's frame outside every zone above, which is what lets the viewer draw a frame-time graph and say which frame a zone belongs to.
Offer a scroll to whatever owns focus, then to the overlays.
The player's own view does not scroll -- the wheel is not a camera control here -- so an unconsumed wheel event is simply the end of the matter.
The window losing the pointer outright ends any capture owed back to a modal interaction: coming back to the game is a click either way.
The window is going; the film's sound must not outlive it, playing on from a session nobody can see until something releases it.
Republish both block atlases into session without invalidating its meshes.
If *BLOCK-ATLAS-TILE-CAPACITY* changed, replace the renderer-owned textures
and discard binding caches which name their old views. Vertices carry only
tile-local coordinates and mapping-scoped offsets; the next frame publishes
the replacement texture's width through the frame uniform.
Prepare the complete owner inventory before publishing any of the four mutually dependent atlas handles.
The candidate is now authoritative. A failure while retiring the predecessor must neither roll it back nor destroy the newly published textures during unwind.
Republish session's block atlases while its canvas cannot render them.
NIL means "as much of this display as comfortably fits"; a capture asks for the exact frame it intends to write out. A KMSDRM console can only present at a real display mode, so the environment may pin the canvas to the panel's native size.
A hidden capture wanting animals in frame hands in a population it has already placed; the ordinary game grows its own around the player as it plays.
The world-text banner is a proof of the Slug path, not scenery: a caller that wants one asks for it, and the ordinary game sky stays empty.
Open a little CPU-meshed block world.
Click to capture the pointer, look with the mouse, walk with WASD, and jump with Space. Once captured, left click removes the block at the centre of view and right click places the selected block. Number keys select materials, middle click picks the targeted material, Shift sprints, and Escape releases the pointer. In the complete game, I opens the player inventory.
Everything also works without a pointer: the arrow keys look around, E places the selected block, X removes the targeted block, C picks its material, and M toggles pointer capture for machines whose pointing device has no buttons. Control-Q quits from anywhere, saving the world on the way out.
Pass :provider to select the Vulkan or Metal relationship without changing
world, simulation, streaming, or frame orchestration. Pass :visible-p NIL to
keep the SDL window hidden while still exercising the real presentation path.
Pass :frames-per-second NIL for a capture-only demand clock. On KMSDRM any
non-NIL value selects display-paced animation because FIFO scanout, rather
than an independent host timer, owns the available frame rate. Pass
:fullscreen-p T to open on the whole display, and leave :width and :height
NIL to let the display choose a comfortable window. A high-pixel-density
drawable is requested by default; the scene remains at logical resolution and
the final application UI uses every physical pixel.
Keep the native window hidden until its first complete terrain frame has been presented. Showing it here would expose black initialization and sky-only streaming states.
FFmpeg has to be dlopened before the canvas exists. Film is now a live terminal-wall mode, so waiting until the user opens its browser would attempt the first dlopen under Cocoa's running canvas and hang. Preload the libraries here; no decoder or file is opened until Film is chosen.
Both extent classes come from one constructor, which a live window or drawable resize calls again as one cohort.
Presentation and the lens chain read continuous images rather than a texel grid; the five-sample gaussian below is only a nine-tap kernel because it filters linearly.
The four lens stages differ only in which mathematical fragment method they name; everything else about them is the same fullscreen triangle over the same layout.
Preserve asynchronous residency after startup, but do not publish the window until the nearest immutable mesh is ready.
The window is mapped before that first frame rather than
after it. A Wayland surface that has never been mapped
receives no frame callbacks, and a FIFO present waits for
one, so presenting first and showing afterwards is a wait
for a frame that cannot arrive until the wait ends.
Nothing can break that tie from outside either:
show-canvas runs on the canvas thread, which is the very
thread the present is holding. Waiting for the mesh is
what keeps the window from opening on an empty world; the
frame merely has to come second.
Startup failed and its condition is already on its way out, so trouble releasing the half-built session is warned about rather than signalled -- signalling here would replace the error that actually explains why the game did not open.
Release session after its stop controller granted this caller ownership.
The stop controller guarantees that this owner is beside the canvas thread. Leave that thread alive until the capture transaction has encoded and evicted its target-keyed frame state.
First stop future frames, then cross the native frame boundary. This method only runs beside the canvas thread: the controller rejects a synchronous owner or waiter on that thread.
A synchronous no-op after changing the clock is the frame-boundary barrier: no encoder can still be borrowing application resources.
Stop CPU publication before releasing any render-owned destination.
The session coordinates one renderer owner; it no longer reproduces the renderer's pipeline and resource inventories during teardown.
The window and the device are last and are never skipped: they are the two handles whose loss would leave something on the desktop that nothing can close.
Stop session exactly once and publish its result to every caller.
The sole owner attempts every named release step and closes the canvas and
device last. Concurrent and later callers observe the same values or
release-error without releasing a native handle twice.
Framebuffer pixels per unit of the cursor shader's design grid.
Design-grid slack around the arrow for its shadow and antialiased edge.
(name value &key type quantity documentation)Define an ordinary constant which publishes its represented quantity. The runtime value remains the unwrapped result of VALUE. TYPE states its Common Lisp representation independently of QUANTITY's semantic declaration; VALUE-DECLARATION-FOR retrieves the latter at definition boundaries.
Constant depth bias applied to every shadow comparison.
Depth bias scaled by the receiver's slope to the light.
PCF radius in shadow texels when the sun is a point.
PCF radius in shadow texels at the sun's widest.
(name (&key label (group :grading) documentation
(class ''scalar-knob)
quantity (type 'single-float)
unit-label minimum maximum step)
place)Define NAME as a knob of CLASS over the setf-able PLACE. PLACE may refer to SESSION, so a knob can live on the session -- its sky clock, its player -- as well as in a special. QUANTITY is a quantity plist as DEFINE-QUANTITY-CONSTANT takes, (:quantity ... :unit ...); it and TYPE make the knob's declaration, which…
(object)(format)The colour transfer a sampled texture FORMAT applies before shader math. This describes representation decoding, not a quantity. Alpha remains linear for the sRGB formats; the transfer names their RGB-channel behavior.
Logical conjunction of tests and raw truth values.
(width height &optional x y)Subtraction or unary negation.
Division of two represented quantities.
Multiplication and scalar scaling.
Addition over compatible quantities.
(vertices declaration-name vertex-count shader-specification)(width height x y)Make the quad the cursor shader draws its arrow inside, tip at screen X,Y. Only the hotspot and the scale live here: each vertex carries its offset from the tip in the shader's design grid, and the fragment stage turns that into the outline, the fill, and the shadow.
(role stage)Return the current durable shader specification for ROLE and STAGE.
(camera sky &optional anchor)Pack a texel-stable orthographic light-space transform as four vec4 rows. Returns the rows and the ANCHOR to hand back next frame. The anchor is the world point the light-space texel lattice is built around: it follows the camera in whole texels of the current light basis, so camera translation never moves the…
(x y z)(camera)(camera)(camera)(vector scale)(vector)()The axis the sun revolves around: world Z, because the orbit is a circle in the X/Y plane displaced along Z. Anything which needs a stable reference direction transverse to the sun should use this rather than world up. The sun's angle to this axis is the same at every hour, so a basis built from it is uniformly well…
(left right)Logical disjunction of tests and raw truth values.
(left right)(vector axis)(session width height &key camera-lanes)Pack the frame environment: camera lanes plus the evaluated sky. Lane order must match *FRAME-UNIFORM-MEMBERS* exactly; the construction-time check in BLOCK-WORLD-CAMERA-UNIFORM-SIZE keeps the two honest. CAMERA-LANES may replace the session camera's own five lanes with a camera expressed in some other space; the…
(session)The frame buffer byte size derived from the shader-visible block layout. Checked against the host's packed frame data at construction, so growing the frame uniform cannot silently diverge between shader and host.
(view previous inspection-parameters ink-strength player
&optional (bevel-width luft:+mesh-bevel-width+) (exposure 1.0f0))(clock profile)The non-negative remainder of integer division.
How many tiles wide a newly materialized block atlas texture is.
Test whether two compatible scalars are equal.
PROPERTY: VALUES; -- the property a keyword, the values a list written space-separated.
(name)Return the represented-value declaration published by global NAME, or NIL.
(declaration)Return DECLARATION's backend or Common Lisp representation type, or NIL.
Overall scene exposure multiplied into the sky profile's own exposure.
Draw the crosshair. A film shot is not aiming at anything.
Engage the focus-plane background blur without a modal focus. The focus plane is the depth at the centre of the frame, so a film shot that wants a subject sharp against a blurred background aims the centre ray at ground or blocks standing at the subject's distance. A global rather than a binding because the…
How much of the blurred bright-pass image is added back in linear light. The chain's kernel is wide and runs twice, so this is a glow spread over a sixth of the frame rather than a halo: past about a third it stops reading as light around the sun and starts reading as fog over everything.
How strongly sunlight scattered around the solar disc streaks the frame.
Corner falloff of the presented frame, as a fraction of full brightness.
Luminance at which a fragment starts contributing to the bloom chain.
Per-tap attenuation along a light shaft; nearer one reaches further.
(camera sky width height)The sun's presentation UV and how strongly it counts as on screen. The weight fades the solar lens effects out as the disc leaves the frame or falls behind the camera, so a turn of the head does not pop the shafts.
(camera)Test whether one compatible scalar is at most another.
The maximum of compatible quantities.
The componentwise absolute value of a raw value.
(edge0 edge1 value)(session width height
&optional (presentation-width width) (presentation-height height))Pack the presentation environment: texel sizes, lens gains, and the sun. Lane order must match *POST-UNIFORM-MEMBERS* exactly; the construction-time check in LUVCRAFT-POST-UNIFORM-SIZE keeps the two honest.
(session)(extent)(block)The host byte size implied by BLOCK's shader-visible vec4-lane layout. Hosts allocating a backing buffer should derive their size here rather than repeating the lane arithmetic as a literal.
(block)Flatten BLOCK's byte-offset members into frame-buffer float positions. This is deliberately luvcraft's fixed 32-bit-lane ABI adapter, not a claim about general uniform-block packing. The shader owns offsets and member quantities; the host independently owns the product it writes.
(declaration)Return DECLARATION's homogeneous quantity specification, or NIL.
How the children of a list are arranged.
(declaration)Return DECLARATION's heterogeneous quantity layout, or NIL.
(positions specification)(extent projections)(left right)(declaration)Return the source form which established DECLARATION.
(renderer resource)(renderer resource)(renderer resource)(handle)Logically invalidate HANDLE immediately. Native teardown may be deferred until submitted work which captured HANDLE has completed.
(session uniform-buffer view label)(device descriptor)Asks the DEVICE for a handle to newly created instance of some object fulfilling the DESCRIPTOR.
How much smaller each bloom chain attachment is than the frame.
(&key
(title "luv little block world — click, look, walk")
;; NIL means "as much of this display as
;; comfortably fits"; a capture asks for the
;; exact frame it intends to write out. A
;; KMSDRM console can only present at a real
;; display mode, so the environment may pin
;; the canvas to the panel's native size.
(width (let ((value (uiop:getenv "LUVCRAFT_WIDTH")))
(and value (parse-integer value))))
(height (let ((value (uiop:getenv "LUVCRAFT_HEIGHT")))
(and value (parse-integer value))))
(frames-per-second 60)
(visible-p t)
(fullscreen-p nil)
(high-pixel-density-p t)
(world (make-empty-little-block-world))
(mesher (make-instance
'exposed-face-mesher))
(camera (make-instance 'fly-camera))
player
(selected-block *stone-block*)
(inventory (make-block-inventory))
quit-function
;; A hidden capture wanting animals in frame
;; hands in a population it has already
;; placed; the ordinary game grows its own
;; around the player as it plays.
(critters
(make-instance 'critter-population))
checkpoint-writer
(provider *gpu-provider*)
(sky-clock (make-instance 'sky-clock))
(sky-profile (make-default-sky-profile))
(shadow-diagnostic-p nil)
;; The world-text banner is a proof of the
;; Slug path, not scenery: a caller that
;; wants one asks for it, and the ordinary
;; game sky stays empty.
(world-text-string nil)
(world-text-font-pathname
(cl-dejavu:font-pathname "DejaVuSans.ttf"))
(world-text-distance 8.0)
(world-text-lift 3.0)
(world-text-units-per-em 0.55)
(video-pathname nil)
(video-distance 13.0)
(video-lift 4.5)
(video-height 5.0)
(residency-radius 6)
(publication-limit 2)
(load-schedule-limit 4)
(mesh-capture-limit 1))Open a little CPU-meshed block world. Click to capture the pointer, look with the mouse, walk with WASD, and jump with Space. Once captured, left click removes the block at the centre of view and right click places the selected block. Number keys select materials, middle click picks the targeted material, Shift…
(device context render-extent presentation-extent)Create the scene and presentation attachments as one GPU-object cohort. The scene is drawn at RENDER-EXTENT into a linear HDR colour attachment with its own depth buffer and reduced lens chain. World-space application panels draw analytically into a transparent colour/depth pair at PRESENTATION-EXTENT; the…
A MuPDF context: its allocator, its store, and its error stack.
(&optional (stream *standard-output*))The linear HDR attachment format shared by every scene-stage pipeline.
The reduced-resolution attachment format of the bloom and shaft chain.
(&body body)(name &body body)(renderer attachments)(attachments)(renderer resources)(&body body)(renderer)(device layout role label)(&key role (stage :fragment) vertex-role label device layout vertex-module
vertex-buffers target-format target-blend primitive depth-stencil)Create and install a live mathematical render pipeline. VERTEX-MODULE is borrowed when VERTEX-ROLE is NIL and STAGE is not :VERTEX. Every module compiled from ROLE or VERTEX-ROLE is owned by the returned artifact and retired on replacement or explicit release.
(session)Owns the sphere pipeline and the one six-vertex quad every body shares.
(overlay)The live shader pipelines OVERLAY owns, so the session can count them among its own; none by default.
(overlay session pass surface-texture)Encode OVERLAY into SESSION's open scene PASS for SURFACE-TEXTURE.
(overlay)Release resources owned by an object attached to luvcraft.
(artifact)(session)(session overlay)Attach OVERLAY at SESSION's next native frame boundary and return it. ADD consumes a newly offered OVERLAY on both success and terminal rejection. Once SESSION begins stopping, the rejected overlay is released exactly once before APPLICATION-ATTACHMENT-CLOSED is signalled.
(context surface-texture)Return the stable presentation slot key for SURFACE-TEXTURE in CONTEXT. Applications use this to retain per-frame resources without assuming that a backend returns the same Lisp wrapper every time it revisits a native drawable.
(run device uniform-buffer)(renderer)Forget every cached per-drawable binding, which names images that are gone. The bind groups are keyed by drawable, not by size, so nothing else would notice that their scene, depth, and lens-chain views belong to the previous window. Dropping them here makes the next frame rebuild them against the attachments the…
(component)Release every resource owned by COMPONENT. Component release is an owner boundary: callers name the component once, rather than reproducing its private resource inventory.
The sole owner of a session's frame attachments, layouts, pipelines, and per-drawable GPU state. The session coordinates this owner with simulation, streaming, overlays, and presentation; it does not duplicate its inventory.
The named live-pipeline slots whose values form the renderer inventory.
(renderer)(component extents)Replace COMPONENT's frame-sized state at a frame boundary. EXTENTS names both the expensive game-scene resolution and the final drawable-matched resolution where native-density application UI is composed.
(session)Rebuild SESSION's frame-sized images when either frame extent changes. A Retina canvas has two deliberately different extents: the game scene renders once per logical point, while presentation and direct application UI render once per physical drawable pixel. This runs at the top of a frame, after the backend has…
A native destination with a lifetime and frame clock.
(context)Return CONTEXT's configured drawable extent as (WIDTH HEIGHT), or NIL.
(category control &rest arguments)Write one timestamped line about CATEGORY, formatted from CONTROL. CATEGORY is a keyword naming the subsystem -- :canvas, :watchdog, :vulkan -- so a reader can tell at a glance which machine is talking.
(overlay)Return where OVERLAY draws: :SCENE, :WORLD-PANEL, :VIEWMODEL, :HUD, or :NONE. Scene overlays inhabit world depth; viewmodels are first-person geometry above the world but below held items and the crosshair. World panels retain world projection and depth while drawing analytic application graphics at native…
Test whether one compatible scalar is greater than another.
(overlay session)Return OVERLAY's positive camera-space depth for world-panel ordering. Native-density panels are alpha-composited far to near before their completed depth layer meets the game scene. Non-spatial panel implementations may keep the stable attachment order by returning the default zero depth.
(name-and-options lambda-list &body body)Define a function whose complete dynamic extent is an ambient trace zone. The inferred name is PACKAGE/FUNCTION. Use (NAME :ZONE ZONE-NAME) to provide a more semantic name and :VALUE FORM to attach a Tracy work count.
Sample a two-dimensional texture through a sampler at a UV coordinate.
((sample accessor zone) &body body)(screen camera)(screen device)Decode up to the picture that is due now and upload it. Return true if so. Pictures that came due while the last world frame was being drawn are decoded and discarded rather than shown, so the film keeps the world's time instead of the renderer's. A film with sound keeps the sound's time instead: the ear is the…
(specification &body body)Measure BODY with concise ambient zone syntax. SPECIFICATION is either a zone name or (NAME :VALUE FORM). This is the ordinary spelling for a meaningful region inside a definition; ZDEFUN and ZDEFMETHOD cover whole definitions.
((session overlay phase) &body body)Run BODY for OVERLAY; an error is OVERLAY's alone. It is retained on the session's canvas with its backtrace, logged, and the overlay is taken out of the session -- a paint bug in a gadget must not take the world with it. Returns BODY's values, or NIL when the overlay failed.
(overlay session)Publish any complete pending render state for OVERLAY at a frame boundary.
An explicitly owned AVFrame.
(system)(population world)(session)(session)(world)(name value)(session)(encoder descriptor)(pass-encoder pipeline)(pass-encoder index bind-group)(pass-encoder slot buffer &key (offset 0))(pass-encoder vertex-count
&optional (instance-count 1) (first-vertex 0) (first-instance 0))(pass-encoder)(encoder texture usage)Prepare TEXTURE for semantic USAGE in ENCODER's following commands. The backend owns any layout transition, hazard barrier, or validation needed to realize the usage. Application code does not dispatch on the backend. #T5MQO0
(session)(screen device uniform-buffer)Logical negation of one test or raw truth value.
(player)(player)(session seconds)(population world seconds)(population world x z)Keep POPULATION's animals living on resident terrain near X,Z. Called once a frame beside residency: animals which have wandered out of the neighbourhood are forgotten, and a couple of deterministic candidate sites are offered to the population's species until it is as full as it wants to be.
(session timestamp)The minimum of compatible quantities.
(clock seconds)(system seconds)(session seconds)(session seconds)Step the session's physics as many fixed steps as SECONDS owe, then build this frame's sphere instance and shadow cube streams.
(overlay session seconds)Advance OVERLAY's simulation state by SECONDS at the frame boundary.
(focus session seconds)Let FOCUS take its own turn in SESSION's simulation, before the player's. A focus which only reads input needs nothing here; a moving one -- a mount, a vehicle, a cutscene -- does its own work in this method.
(focus)Whether FOCUS moves the player itself instead of the player controller. A terminal on a wall leaves the player standing in front of it and the ordinary scalar controller keeps running. A mount does not: it carries the player, so the controller must stand down for as long as the interaction lasts.
(intent)(body &optional (detail "superseded"))Test whether one compatible scalar is at least another.
(body world seconds)(camera player)Advance the scalar player controller by one small physics step. INTENT is what the player is trying to do rather than what they pressed: the controller asks for directions and a hurry, and never learns that there is a keyboard.
(session seconds)(body session seconds)(session timestamp &optional sample)()Describe luvcraft's plots to a viewer, once per connection. Plot configuration reaches only a viewer that is already listening, and a capture may begin at any frame, so the description is re-sent on each fresh connection rather than once at startup.
(context function)(&optional name)End the current Tracy frame, or the secondary frame set called NAME. Marking frames is what gives the viewer its frame-time graph, and what lets it say which frame a zone belongs to.
A scroll, carrying where the pointer was and how far the wheel turned. The amounts are in wheel notches rather than pixels, positive up and right, already corrected for a natural-scrolling platform -- what the window system says the user asked for, not what the hardware reported.
(session canvas event)(session event)(canvas enabled)Capture or release relative pointer motion for CANVAS.
(item body session button)The player clicked BUTTON while BODY held ITEM. Return true when the item did something with the click, so it does not go on to edit the world; the default hand holds things but does nothing with them.
(session action)(session)(session)(session)Request SESSION's one orderly teardown beside its native canvas thread. Native close and commands may call this without waiting. Exactly one worker runs the PLAY-level quit callback when present, or the session teardown itself otherwise; repeated requests still defer native close to that same owner.
(screen)(session)Republish both block atlases into SESSION without invalidating its meshes. If *BLOCK-ATLAS-TILE-CAPACITY* changed, replace the renderer-owned textures and discard binding caches which name their old views. Vertices carry only tile-local coordinates and mapping-scoped offsets; the next frame publishes the replacement…
(queue destination data data-layout size)()Return the little world's horizontal RGBA8 atlas as packed pixel words. RGB is the material's procedural colour and A is opaque coverage. The array spans the full tile capacity; tiles past the painted count stay zero, waiting for a material to claim them.
()Return the relief-correlated tangent-space normal atlas as packed RGBA8. RGB is a linear encoded unit normal and A is the procedural height from which it was derived. This is a derived materialization, not an authored asset.
(session)(function &optional (canvases (open-canvases)))(&key (chunk-width 16)
(chunk-height 16)
(chunk-depth 16)
(seed 121))(&key (blocks (placeable-block-kinds)) (quantity nil))Make an inventory containing BLOCKS in display and number-key order. QUANTITY is the initial count of every material, or NIL for creative-mode unlimited supply.
The living animals near the player, and how to find more.
If you're lucky, someone has bound this to a working GPU-PROVIDER.
Mutable time-of-day state owned by a luvcraft session. SLY can pause it, set a time, change its rate, or pin it without restarting.
(&key (title "luv canvas") (width 800) (height 600)
x y (visible-p t) (fullscreen-p nil)
(high-pixel-density-p nil)
(clock (make-demand-clock))
(time (make-lazy-clock))
(presentation-api :vulkan))Construct an unrealized SDL canvas. WIDTH or HEIGHT may be NIL, which asks the display for a size when the window is finally created.
(provider)Return the SDL presentation policy required by GPU PROVIDER.
(camera)A video file playing on one world rectangle.
(&optional directory)Load libavutil, libavcodec, and libavformat, and check their versions. DIRECTORY is useful for builds which have not been installed. When it is NIL, LUV_FFMPEG_LIBDIR is consulted before the platform soname search. Signals LIBAV-VERSION-MISMATCH when a loaded library disagrees with the headers this system was…
(provider &optional descriptor)(canvas gpu-provider &optional configuration)Create a GPU presentation relationship between CANVAS and GPU-PROVIDER. When CONFIGURATION is omitted, return the context unconfigured.
(&key (name "luv single CPU producer"))Make one sleeping SB-CONCURRENCY mailbox worker. There is intentionally no pool yet. One worker proves the ownership and publication protocol, prevents CPU oversubscription, and keeps completion order intelligible while taking expensive work out of an owner callback.
(world)Subscribe a fresh lighting state to WORLD's content and residency hooks. Chunks already resident at attachment are treated as arrivals, so the first reconcile lights a caller-built world without a separate protocol.
(device)(device glyph-cache camera target-format string font-pathname
&key (distance 8.0) (lift 3.0) (world-units-per-em 0.55))Shape STRING once and create a depth-tested world text run on DEVICE. The run owns dense placement/model data and its live pipeline; GLYPH-CACHE owns font-and-glyph device resources reusable across runs. See #QW7P96.
(device camera pathname target-format
&key (distance 12.0) (lift 4.0) (height 4.5) rectangle (loop-p t)
(hardware :auto))Open PATHNAME and build a world screen playing it, facing CAMERA. HEIGHT is the screen's height in cells; its width follows the film's aspect. When RECTANGLE is supplied, it is called with that aspect and returns the lower-left origin, right edge, and up edge of an authored world rectangle. HARDWARE is NIL, :AUTO, or…
(canvas &key (name "canvas application"))(session)(session)(session)Start SESSION's optional background lobby service and return it.
(session)Attach the player HUD supplied by the loaded presentation system. LUVCRAFT/CORE deliberately has no presentation-system dependency. LUVCRAFT/MCCLIM specializes this at the session boundary and returns its attached overlay.
Protocol class for objects receiving canvas events.
(session &key minimum (timeout 10.0))Wait outside frame encoding for a useful initial set of chunk meshes. MINIMUM defaults to nine or the whole desired set when it is smaller. The visible startup path asks only for the nearest product before its first presentation; deterministic captures wait for the broader default set.
(canvas function)Run FUNCTION with a timestamp on CANVAS's native frame/event thread. The initial native implementation is synchronous: the caller waits for the function's values. The protocol leaves room for a real frame scheduler.
A policy object deciding when a canvas should run frames.
(frame-function)(frame-function &key (frames-per-second 60))(system &key (timeout 10.0))(session)(session overlay &key (release-p t))Detach OVERLAY at a frame boundary and optionally release it there. The no-release path is intentionally preserved for FUSE-LUVCRAFT-OVERLAY: that path may run inside a frame whose command stream still borrows OVERLAY.
(session)Release SESSION after its stop controller has granted sole ownership.
(application)Close APPLICATION's capture gate and wait for its active capture to leave. The caller must run beside the canvas thread while a capture is active. The active capture may still need that thread for its final frame and cache cleanup; waiting on the canvas thread would deadlock it and is rejected explicitly.
()Terminally detach Luvcraft's current controller without waiting on it. Detachment is atomic and precedes release, so a later game session obtains a fresh controller even while the prior capture finishes on its owner thread.
(screen)Release SCREEN's pipeline, GPU resources, and open film. Each step is contained so that a failure early on cannot strand the film's decoder or the resources after it; the failures travel out through whatever release report is running. See WITH-RELEASE-REPORT.
(screen)(session)Stop SESSION exactly once and publish its result to every caller. The sole owner attempts every named release step and closes the canvas and device last. Concurrent and later callers observe the same values or RELEASE-ERROR without releasing a native handle twice.
All named failures from a completed release sequence.
(application)Close APPLICATION's capture admission without waiting for active work. This is safe on a canvas thread. Return true when this call closed admission, or NIL when shutdown had already been requested.
(controller function)Run FUNCTION as CONTROLLER's sole teardown, or observe its published result. A concurrent caller waits while the owner runs. A later caller receives the same values or signals the same condition without running FUNCTION again.
Intent: #X9Q2YS removed the field-wide receiver-plane acne and left cast shadows shimmering anyway. Play reported the residue as worst near noon, which is a strong clue: a defect with a preferred hour has a mechanism that depends on the sun's elevation. Evidence: – A frozen-sun, frozen-camera control over 20 frames…
Intent: play still reported every cast shadow flickering and jittering whenever the clock ran, at any day length, and calm only once the clock stopped. #0604PY had already chosen the best roll for the light basis; the residue was too fast and too uniform to be roll. Evidence: – The live capture at day fraction 0.42,…
Frame encoding, input handling, and the luvcraft session lifecycle.
The canvas frame callback is the ownership boundary for all GPU replacement: shader refresh, mesh publication, and uniform updates all happen here, on the thread that owns the swapchain. This file also owns canvas event handling and the START/STOP pair that creates and releases the renderer and the other explicitly owned application components.