luvcraft/app.lisp
Every scene stage writes linear radiance into a floating-point attachment instead of an already-encoded display image. A sun disc, a specular glint, or an emissive crystal is then allowed to be far brighter than display white, which is exactly the signal the bloom chain feeds on and the tonemapper rolls off. Only the final presentation image is an sRGB eight-bit surface.
The world point the shadow texel lattice pivots about;
shadow-frame-rows walks it after the camera in whole texels.
The player's own arms and hands, and what they hold. See BODY.LISP.
The things with weight: balls, drops, gobbets. See PHYSICS.LISP for the world and BALLS.LISP for what the game does with it. Made on the first frame, when there is a block world to collide with.
The CPU-side vertex stream the bodies are drawn from each frame, and how much of it the last build filled.
Where the world's springs stand, found from its authored edits.
When set, every presented frame is also copied into this texture, so something outside the window -- another process, through an IOSurface -- can watch the game.
Where the player is trying to turn the camera, urged by the arrow keys: a mouse for the mouseless console.
Whether mouse look was captured when the current modal focus was entered.
A modal interaction wants an ordinary cursor -- a terminal's own UI is clicked at a place on the screen, which relative pointer mode does not have -- so entering focus releases the capture. Remembering that it was held is what lets leaving focus put the player straight back into mouse look instead of making them click the world again.
Keep the established session-facing renderer vocabulary while making its storage and lifecycle belong to one semantic owner. These are methods, rather than captured closures, so a live class redefinition replaces the former slot-accessor methods at their ordinary CLOS coordinates.
Adopt a pre-renderer session's discarded slot values into one owner.
retired-values is the property list supplied by
update-instance-for-redefined-class. Unbound old slots remain unbound in the
new renderer; owned resource and frame-state collections retain identity.
Encode overlay into session's open scene pass for surface-texture.
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 presentation density. HUD overlays follow scene postprocessing. :NONE participates in no render pass.
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.
The live shader pipelines overlay owns, so the session can count them
among its own; none by default.
Publish any complete pending render state for overlay at a frame boundary.
Advance overlay's simulation state by seconds at the frame boundary.
Release resources owned by an object attached to luvcraft.
Evict overlay resources retained for one canvas frame-key.
Offscreen captures use a fresh target, so an overlay which caches per-frame GPU state must detach that entry before the shared capture target is destroyed.
Handle event projected onto overlay, returning true when consumed.
Notify focus that session has entered its interaction mode.
Notify focus that session has left its interaction mode.
Handle event while focus owns session's modal player interaction.
Offer event to controls which belong to focused focus, returning true when consumed.
This is narrower than the ordinary overlay event path: a focused world object may expose a HUD control without allowing an unconsumed click to fall through to block editing or to unrelated overlays.
Return a non-negative targeting score when focus can be entered by TAB.
Return focus's desired CAMERA-POSE in session, or NIL for an FOV-only cue.
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.
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.
Return left, top, right, and bottom pixel insets obscured by overlay.
Advance session's cinematic focus pose after ordinary player simulation.
Create and return a focusable interaction for targeted block, or NIL.
Create and return a focusable interaction for targeted critter, or NIL.
The animal counterpart of activate-luvcraft-target: an animal which can be
mounted answers with the ride, and one which cannot answers NIL and is simply
looked at.
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.
Start session's optional background lobby service and return it.
Cooperatively stop session's lobby service, if loaded.
Release session after its stop controller has granted sole ownership.
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.
Close capture admission on the native caller before its teardown worker exists. A capture which won the race remains safe to finish; no later request can enter behind the owner's eventual frame-boundary barrier.
Return a short string naming the keystroke that reaches thing, or NIL.
A control which draws its own key hint would be inventing one: the keys are decided in the command layer above, so the drawing asks rather than guesses, and a rebound key changes the label on the button.
Take mouse look back if the modal interaction just left had suspended it.
Mouse input and the cinematic return cannot both own the camera.
Finish the return before publishing capture, otherwise every mouse
delta is followed by advance-luvcraft-focus-camera pulling yaw and
pitch back toward the pose saved on entry.
Leave session's modal interaction, returning the object which was focused.
Publish the unfocused state before the callback so a callback may safely establish another focus without being cleared afterward.
Enter modal interaction with focus, suspending ordinary player input.
This is the common session transition behind using a world terminal or book, mounting a vehicle, and other interactions described by #8JCMA5.
Return the previous interaction all the way to the player's pose first. A direct focus-to-focus transition then borrows that same pose anew; recording before UNFOCUS would let its resume path consume the origin and leave the second interaction with nothing to return to.
Read the capture back after the previous focus has returned it, so a focus-to-focus move keeps mouse look owed to the player rather than forgetting it halfway.
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 failed in phase with condition: retain the failure and drop it.
The overlay's resources are not released here -- this may be mid-frame,
with its buffers still in the command stream -- so they are leaked, which
a development image can afford and a frame cannot.
Return the animal session's centre view ray reaches first, and how far.
An animal standing behind a wall is not targeted: whichever of the animal and the terrain the ray meets first is what the player is looking at.
Return or activate session's best currently targeted focusable object.
Leave modal focus, or enter the best overlay currently targeted by session.
Offer event to session's frontmost overlay and report consumption.
Return session's live canvas, or NIL while its native owner does not exist.
Run function at session's native frame boundary when one exists.
Startup and post-quiescence cleanup still execute directly. Once the canvas
is open, request-canvas-frame makes attachment mutation and GPU release part
of the native owner stream, after any frame which borrowed the overlay list,
and synchronously returns function's values or condition to the caller.
Recheck at publication: two callers may both have reached this boundary before either became visible.
ADD consumes a newly offered attachment on either outcome. A rejected constructor therefore unwinds with no frame, pipeline, worker, or other application resource stranded beside the game.
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.
An EQ object already owned by this session is not a fresh offer. Resolve that idempotent case before a closing canvas can reject the owner request and make the caller mistake registered state for unpublished state.
A native request can lose its closing-canvas race before the mutation starts. Once the application gate is terminal, name that semantic rejection instead of leaking the backend detail through ADD's ownership boundary.
Another serialized add may have published this same EQ object before our native request lost its close race.
request-canvas-frame can itself reject a closing canvas before the
mutation callback begins. The registry has not consumed overlay in
that case, so no frame can have borrowed it. Finish the transfer on
this caller: GPU destroy is synchronized by the backend retirement
ledger and is therefore safe even while terminal device teardown wins
the race beside us.
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.
Capture session's durable state and submit it to its asynchronous writer.
Every live shader pipeline coordinated by session, optional ones included.
Enumerate Luvcraft's per-pipeline artifacts for shared developer tools.
Install any successfully redefined block-world shader methods.
Raycast from session's camera through resident block terrain.
The tenth slot is the 0 key, so its chip says 0 rather than advertising a 10 key that does not exist.
Select the one-based numbered placeable material and update the title.
Give session any newly defined placeable materials, in number-key order.
The live half of adding a material: refresh-block-atlas repaints the wall,
and this puts the new block on the number row of a running session.
Existing entries keep their identity and quantities; entries the palette no
longer names stay reachable at the end, past the number keys.
Turn session's camera as its look intent urges: a mouse for the mouseless.
Select the material currently under the centre crosshair.
block has just been put down at X,Y,Z by the player in session.
Most blocks are inert and the default does nothing; a block that does something where it stands -- a film beside a wall -- answers here.
block has just been taken away from X,Y,Z by the player in session.
Apply action (:REMOVE or :PLACE) along session's centre view ray.
The ground is about to move: whatever was asleep on it must find out.
A block worth carrying is picked up rather than smashed away.
Creative materials are unlimited; a carried one is spent.
--------------------------------------------------------------------- The session's knobs: values that live on the session, its camera, its player, its sky clock, its animals. All are read every frame.
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.
(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.
The linear HDR attachment format shared by every scene-stage pipeline.
The reduced-resolution attachment format of the bloom and shaft chain.
How much smaller each bloom chain attachment is than the frame.
Protocol class for objects receiving canvas events.
A native destination with a lifetime and frame clock.
A MuPDF context: its allocator, its store, and its error stack.
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.
(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…
(&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.
The first-person body: two arms and what they hold.
A video file playing on one world rectangle.
A restartable radio whose worker publishes connection-scoped snapshots.
One body's movement will: which directions it is urging, and whether it owes a jump. The urges are named after the body's own frame -- :FORWARD, :BACKWARD, :LEFT, :RIGHT, and :SPRINT -- rather than after any key or axis, so the same intent serves a walking player and a ridden animal.
A one-shot publication boundary around exactly one teardown execution. The controller is a separate object owned by an application. One caller changes RUNNING to STOPPING and executes the teardown; every other blocking caller waits for the same result or condition. STOPPED is terminal, so no resource-owning body…
(&key (name "application") blocking-thread-p)Make a one-shot stop controller named NAME. BLOCKING-THREAD-P, when supplied, is a quick predicate which is true on a thread that may request a stop but must never own or wait for one.
Logical disjunction of tests and raw truth values.
A standard class whose annotated slots retain quantity declarations. Slot access and instance representation remain ordinary CLOS. The metaclass only makes definition-time meaning inspectable and inheritable. #OXBSAY
(session-accessor renderer-accessor &key setf)The former session slots transferred into a renderer by live migration.
How the children of a list are arranged.
The former session slots published together as one attachment cohort.
(session retired-values)Adopt a pre-renderer SESSION's discarded slot values into one owner. RETIRED-VALUES is the property list supplied by UPDATE-INSTANCE-FOR-REDEFINED-CLASS. Unbound old slots remain unbound in the new renderer; owned resource and frame-state collections retain identity.
((session luvcraft-session) added-slots discarded-slots retired-values
&rest initargs)Logical conjunction of tests and raw truth values.
(overlay session pass surface-texture)Encode OVERLAY into SESSION's open scene PASS for SURFACE-TEXTURE.
(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…
One authored solid and its vocabulary-closed material-placement field. The solid remains LUFT's topological truth. The sparse authored field stores only dense vocabulary offsets; semantic material objects remain at the scene boundary rather than being allocated per cell.
(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.
(overlay)The live shader pipelines OVERLAY owns, so the session can count them among its own; none by default.
(overlay session)Publish any complete pending render state for OVERLAY at a frame boundary.
(overlay session seconds)Advance OVERLAY's simulation state by SECONDS at the frame boundary.
(overlay)Release resources owned by an object attached to luvcraft.
(overlay frame-key)Evict OVERLAY resources retained for one canvas FRAME-KEY. Offscreen captures use a fresh target, so an overlay which caches per-frame GPU state must detach that entry before the shared capture target is destroyed.
(overlay session canvas event)Handle EVENT projected onto OVERLAY, returning true when consumed.
(focus session)Notify FOCUS that SESSION has entered its interaction mode.
(focus session)Notify FOCUS that SESSION has left its interaction mode.
(focus session canvas event)Handle EVENT while FOCUS owns SESSION's modal player interaction.
(focus session canvas event)Offer EVENT to controls which belong to focused FOCUS, returning true when consumed. This is narrower than the ordinary overlay event path: a focused world object may expose a HUD control without allowing an unconsumed click to fall through to block editing or to unrelated overlays.
(focus session)Return a non-negative targeting score when FOCUS can be entered by TAB.
(focus session)Return FOCUS's desired CAMERA-POSE in SESSION, or NIL for an FOV-only cue.
(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.
(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.
(overlay session)Return left, top, right, and bottom pixel insets obscured by OVERLAY.
(session)The maximum of compatible quantities.
Logical negation of one test or raw truth value.
(player)(x y z)(player)Addition over compatible quantities.
(player)(player)(position)(session seconds)The 50-degree vertical field of view used during modal focus.
(camera target seconds)Test whether one compatible scalar is less than another.
(camera pose)(block session hit)Create and return a focusable interaction for targeted BLOCK, or NIL.
(critter session)Create and return a focusable interaction for targeted CRITTER, or NIL. The animal counterpart of ACTIVATE-LUVCRAFT-TARGET: an animal which can be mounted answers with the ride, and one which cannot answers NIL and is simply looked at.
One individuated animal walking the block world.
(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.
(session)Start SESSION's optional background lobby service and return it.
(session)Release SESSION after its stop controller has granted sole ownership.
(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.
(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 &key thread-name)Request FUNCTION as CONTROLLER's teardown on one new worker thread. Return true and the worker when this call reserved ownership, or NIL and NIL when a stop was already requested or published. The worker contains any failure after publishing it; WAIT-FOR-CONTROLLED-STOP and synchronous callers receive that exact…
(thing)Return a short string naming the keystroke that reaches THING, or NIL. A control which draws its own key hint would be inventing one: the keys are decided in the command layer above, so the drawing asks rather than guesses, and a rebound key changes the label on the button.
(session)(intent)(canvas enabled)Capture or release relative pointer motion for CANVAS.
(session)(session focus)Enter modal interaction with FOCUS, suspending ordinary player input. This is the common session transition behind using a world terminal or book, mounting a vehicle, and other interactions described by #8JCMA5.
(camera)((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.
(&optional (depth *canvas-failure-backtrace-depth*))The current backtrace as text, from the frame that asked for it down to the pump: forms abbreviated, the frames of the capture itself left out.
(session overlay phase condition backtrace)OVERLAY failed in PHASE with CONDITION: retain the failure and drop it. The overlay's resources are not released here -- this may be mid-frame, with its buffers still in the command stream -- so they are leaked, which a development image can afford and a frame cannot.
(canvas phase condition backtrace)(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.
(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.
(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.
(session &key (max-distance +luvcraft-target-reach+))Return the animal SESSION's centre view ray reaches first, and how far. An animal standing behind a wall is not targeted: whichever of the animal and the terrain the ray meets first is what the player is looking at.
(camera)(population origin direction max-distance)(session &key (max-distance +luvcraft-target-reach+))Test whether two compatible scalars are equal.
(session)(session canvas event)(session function)Run FUNCTION at SESSION's native frame boundary when one exists. Startup and post-quiescence cleanup still execute directly. Once the canvas is open, REQUEST-CANVAS-FRAME makes attachment mutation and GPU release part of the native owner stream, after any frame which borrowed the overlay list, and synchronously…
(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.
(session overlay)(protected-form &body cleanup-forms)(controller function &key attachment already-attached-p)Call quick publication FUNCTION iff CONTROLLER is still running. The controller lock remains held across FUNCTION, making publication atomic with the RUNNING to STOPPING transition. FUNCTION and ALREADY-ATTACHED-P must therefore neither block nor reenter CONTROLLER. A true ALREADY-ATTACHED-P is an idempotent…
(name &body body)(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.
An application attachment was offered after terminal teardown began.
(controller)(handle)Logically invalidate HANDLE immediately. Native teardown may be deferred until submitted work which captured HANDLE has completed.
(session overlay release-p)(writer description)Submit immutable DESCRIPTION without waiting for filesystem I/O. Only the latest checkpoint which has not begun is retained. Return its monotonic ticket.
(world &key camera player selected-block carried)(inventory)(session)(renderer)(application)Return APPLICATION's live artifacts as a fresh list. The list is an enumeration, not a transfer of ownership. Applications with no live artifacts inherit the empty default. An artifact may represent one GPU pipeline, a complete renderer cohort, or another transactionally replaced application derivative; the…
(session)(application)(world origin direction occupied-p &key max-distance)Trace a ray through WORLD's resident lattice. Return a BLOCK-RAY-HIT and :HIT, NIL and :ABSENT when traversal reaches a non-resident chunk, or NIL and :MISS. ORIGIN and DIRECTION are VEC3 values in continuous cell coordinates. The caller owns and must supply the maximum ray distance appropriate to its interaction.
(block)(session)(inventory)The non-negative remainder of integer division.
(session number)(inventory)(session)Give SESSION any newly defined placeable materials, in number-key order. The live half of adding a material: REFRESH-BLOCK-ATLAS repaints the wall, and this puts the new block on the number row of a running session. Existing entries keep their identity and quantities; entries the palette no longer names stay…
(session)(scheme)One material in an inventory. A NIL quantity means unlimited supply.
Radians per second of camera turn while an arrow key is held.
(session seconds)(intent positive negative)Multiplication and scalar scaling.
The minimum of compatible quantities.
(session)(block session x y z)BLOCK has just been put down at X,Y,Z by the player in SESSION. Most blocks are inert and the default does nothing; a block that does something where it stands -- a film beside a wall -- answers here.
(block session x y z)BLOCK has just been taken away from X,Y,Z by the player in SESSION.
(session action)One named verb over a session.
(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…
(world x y z radius)(block world x y z)(system block coordinate)(block)Whether BLOCK is a thing a player picks up and carries, rather than a material the palette gives without limit. A film is; stone is not.
(inventory block &optional (quantity 1))Add QUANTITY of BLOCK to finite INVENTORY storage and return its entry. Adding to an unlimited entry leaves it unlimited. A previously unavailable block is appended, preserving the stable order of existing number keys.
(player x y z)(inventory block &optional (quantity 1))Consume QUANTITY of BLOCK and report success. Unlimited entries always succeed. Finite entries remain present at zero so the view and number-key ordering do not jump as blocks are used.
Division of two represented quantities.
(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…
(clock)A knob over a generalized boolean: on or off.
(population)luvcraft-session has about one hundred slots spanning world production, simulation, input, GPU attachments, layouts, pipelines, video, text, overlays, and frame state. luvcraft:start-luvcraft is 623 lines. During startup a GPU object can simultaneously be a lexical binding, a named session slot, an element of…
Luvcraft owns one optional modal focus independently of its overlay list. A focused object receives canvas events while ordinary walking, looking, block editing, jumping, and material selection are suspended. Entering or leaving focus clears held player input and releases relative-pointer capture, so a movement key…
The luvcraft application object and its direct interactions.
A
luvcraft-sessioncoordinates the canvas, GPU device, world, camera, player, and aluvcraft-rendererwhich solely owns the frame GPU artifacts. This file defines that coordinator plus the player-facing verbs: aiming along the view ray, selecting materials, and placing or removing blocks. Chunk streaming lives in streaming.lisp and frame rendering in render.lisp.