luvcraft/capture.lisp
A still wants a useful initial neighborhood. A film must not publish a late chunk halfway through a supposedly continuous authored shot.
encode-luvcraft-frame resolves its scene into target. The shared
capture transaction owns the following target-to-buffer copy.
Release per-target frame state cached while encoding target.
Detach the dying target's identity before any native release can signal, so cleanup remains idempotent under a partial driver failure.
The target is still alive here. Never leave its identity and the bind groups that name it retained in the long-lived renderer.
Render session once offscreen and write its native GPU frame to PNG.
This works for both live and hidden sessions. The call returns only after GPU
readback and compressed PNG writing have completed; it does not inspect the
host window or depend on the window being visible. camera-pose may be a pose
or a function of session evaluated on the canvas thread; the session camera is
restored before the call returns. metadata-function, when supplied, is called
there under the capture pose and its value is returned last.
Return a visible rgba temporal derivative and normalized summary values.
With previous-previous, compute the absolute second temporal derivative;
otherwise compute the absolute first derivative. rgb channel order is
irrelevant because the output is grayscale. Values returned after the image
are normalized mean magnitude, maximum magnitude, and changed-pixel fraction.
Write temporal derivative metric rows to a small CSV file.
Open a hidden SDL canvas, render one block-world frame, and save it.
The sky clock arrives pinned at noon so captures stay byte-deterministic;
pass an unpinned clock to photograph another time of day. A capture never
runs the frame simulation, so any animals it wants in shot arrive already
placed in critters rather than growing around a player.
Authored hidden captures name output pixels explicitly.
Live-window screenshots retain the session's native Retina
presentation extent through capture-luvcraft-screenshot.
Render a native-resolution close-up of the world Slug text proof.
The wide viewport and enlarged world-space text make outline, band-selection, and coverage defects visible without scaling up a smaller raster afterward. #9G0Z19
Capture count hidden block-world frames into directory.
Each frame reuses one hidden SDL canvas on provider, advances camera's yaw by
yaw-step, moves forward-step world units along its initial heading, and moves
the evaluated sky by day-step day fractions. day-start can replace the
clock's initial time. When difference-scale is non-NIL, also write amplified
first and second frame derivatives plus a CSV of unscaled normalized metrics.
shadow-diagnostic-p replaces block materials with direct-shadow visibility so
the derivatives are not confounded by albedo, sky colour, or fog changes.
This is a consecutive-view capture, not a set of independently restarted
scenes.
Temporal evidence requires a fixed scene. The ordinary capture threshold of nine products is enough for a useful screenshot but allowed later desired chunks to publish in the middle of a derivative sequence.
(application)Return APPLICATION's open LUV canvas for a native GPU capture. The shared implementation derives the presentation context and device through CANVAS-CONTEXT and CONTEXT-DEVICE; applications do not repeat those hooks.
(application capture)Prepare APPLICATION for CAPTURE on the calling thread. This is the place to wait for application-specific readiness and to quiesce a normal frame loop. CAPTURE's canvas, context, device, extent, and format are already established, but its shared GPU resources do not exist yet. CLEANUP-CAPTURE is called even when…
One screenshot or film transaction around an application-owned frame. The object is control-plane state, allocated once per capture. TARGET and READBACK-BUFFER are dense GPU resources owned and destroyed by the shared capture implementation.
(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.
(application capture encoder target extent)Encode APPLICATION's complete visible frame into offscreen TARGET. This method runs on the canvas's native frame thread. ENCODER is open and owned by the shared implementation; EXTENT is the fixed two-dimensional capture extent. The method must not finish or submit ENCODER and must not destroy TARGET. Its primary…
(camera)(capture indicator &optional default)(camera pose)(session target)(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.
(&body body)(name &body body)(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.
(renderer resource)(application capture)Undo application-owned CAPTURE preparation on the calling thread. When shared GPU resources were created they are still alive and visible through CAPTURE-TARGET and CAPTURE-READBACK-BUFFER during this method. Applications with target-keyed GPU caches should synchronously evict those entries on their canvas thread…
A native destination with a lifetime and frame clock.
Logical conjunction of tests and raw truth values.
(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 pathname &key camera-pose metadata-function
(include-hud-p t) (include-viewmodel-p t))Render SESSION once offscreen and write its native GPU frame to PNG. This works for both live and hidden sessions. The call returns only after GPU readback and compressed PNG writing have completed; it does not inspect the host window or depend on the window being visible. CAMERA-POSE may be a pose or a function of…
(application pathname &key options (label "application screenshot"))Render APPLICATION offscreen and write its native-resolution PNG. OPTIONS is an application-owned property list interpreted by the capture protocol methods. Return PATHNAME, packed pixels, width, height, color format, and the optional metadata value from ENCODE-CAPTURE-FRAME.
(current previous scale &optional previous-previous)Return a visible RGBA temporal derivative and normalized summary values. With PREVIOUS-PREVIOUS, compute the absolute second temporal derivative; otherwise compute the absolute first derivative. RGB channel order is irrelevant because the output is grayscale. Values returned after the image are normalized mean…
Test whether two compatible scalars are equal.
The non-negative remainder of integer division.
Division of two represented quantities.
Addition over compatible quantities.
The componentwise absolute value of a raw value.
Subtraction or unary negation.
Multiplication and scalar scaling.
The minimum of compatible quantities.
The maximum of compatible quantities.
Convert one scalar float or unsigned value to a 32-bit float.
(pathname rows)(directory index &optional (prefix "block-world"))(pathname &key
(title "luv hidden block world")
(width 960) (height 640)
(world (make-empty-little-block-world))
(mesher (make-instance 'exposed-face-mesher))
(camera (make-instance 'fly-camera))
(critters (make-instance 'critter-population))
(provider *gpu-provider*)
(world-text-string nil)
(world-text-distance 8.0)
(world-text-lift 3.0)
(world-text-units-per-em 0.55)
(sky-clock (make-instance 'sky-clock
:pinned-day-fraction 0.5))
(sky-profile (make-default-sky-profile)))Open a hidden SDL canvas, render one block-world frame, and save it. The sky clock arrives pinned at noon so captures stay byte-deterministic; pass an unpinned clock to photograph another time of day. A capture never runs the frame simulation, so any animals it wants in shot arrive already placed in CRITTERS rather…
(&key (chunk-width 16)
(chunk-height 16)
(chunk-depth 16)
(seed 121))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 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…
(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.
(pathname &key (provider *gpu-provider*))Render a native-resolution close-up of the world Slug text proof. The wide viewport and enlarged world-space text make outline, band-selection, and coverage defects visible without scaling up a smaller raster afterward. #9G0Z19
(x y z)(directory &key
(count 6)
(title "luv hidden block world")
(width 960) (height 640)
(yaw-step 0.35)
(forward-step 0.0)
day-start
(day-step 0.0)
difference-scale
(shadow-diagnostic-p nil)
(pathname-prefix "block-world")
(world (make-empty-little-block-world))
(mesher (make-instance 'exposed-face-mesher))
(camera (make-instance 'fly-camera))
(critters (make-instance 'critter-population))
(provider *gpu-provider*)
(sky-clock (make-instance 'sky-clock
:pinned-day-fraction 0.5))
(sky-profile (make-default-sky-profile)))Capture COUNT hidden block-world frames into DIRECTORY. Each frame reuses one hidden SDL canvas on PROVIDER, advances CAMERA's yaw by YAW-STEP, moves FORWARD-STEP world units along its initial heading, and moves the evaluated sky by DAY-STEP day fractions. DAY-START can replace the clock's initial time. When…
(camera)(camera)Logical disjunction of tests and raw truth values.
(pathname pixels width height format)Intent: distinguish “a shaped run renders” from evidence that Slug's edge coverage and geometry expansion are correct across backends. Evidence needed: exercise the portable draw on Vulkan, compare boundary pixels with a small CPU winding oracle, and test dynamic dilation on geometry whose undilated quad actually…
Direct luvcraft framebuffer capture for live use, smoke tests, and CI.