luv

Workshop wiki

luvcraft.lisp

mcclim/luvcraft.lisp

system luvcraft/mcclim · 40 definitions · on GitHub

McCLIM command surfaces inside luvcraft. The frame shares the world's native canvas and GPU device; its mirror retains painter-ordered semantic commands and dense buffers which the world or HUD pass replays directly.

in-package#:mcluv
defclassluvcraft-widget-overlay
session:initarg:session:readerwidget-overlay-session
frame:initarg:frame:readerwidget-overlay-frame

Where the widget is in the world. Written once for a widget fixed to a wall, and each frame for one carried in the hand.

center:initarg:center:initformnil:accessorwidget-overlay-center
right-axis:initarg:right-axis:initformnil:accessorwidget-overlay-right-axis
up-axis:initarg:up-axis:initformnil:accessorwidget-overlay-up-axis
normal-axis:initarg:normal-axis:initformnil:accessorwidget-overlay-normal-axis
defclassluvcraft-direct-widget-overlay
render-target-texture:initformnil:accessorwidget-overlay-render-target-texture
:documentation

A McCLIM surface whose ordered semantic commands enter its final pass.

Embedded mirrors retain dense command buffers rather than a pane-sized raster texture. Solids, analytic paint, images, and Slug text are evaluated at the actual destination pixel.

defclassluvcraft-world-widget-overlay
:documentation

A direct McCLIM surface mounted in the 3D scene.

defclassluvcraft-hud-widget-overlay
:documentation

A direct McCLIM surface mounted in the presentation HUD.

defgenericluvcraft-widget-target-format
overlaysessionsurface-texture
:documentation

Return the application attachment format used to encode overlay.

surface-texture is NIL at the pre-pass refresh boundary and the concrete drawable during replay.

defmethodluvcraft-widget-target-format
sessionsurface-texture
declare
ignoreoverlaysessionsurface-texture
luvcraft::+luvcraft-scene-color-format+
defmethodluvcraft-widget-target-format
sessionsurface-texture
declare
ignoreoverlay
ifsurface-texture
luv:gpu-texture-formatsurface-texture
luv:canvas-format
luvcraft::luvcraft-session-contextsession
defgenericluvcraft-widget-render-target
overlaysessionsurface-texture
:documentation

Return the actual texture attachment receiving overlay this frame.

defmethodluvcraft-widget-render-target
sessionsurface-texture
declare
ignoreoverlaysurface-texture
defmethodluvcraft-widget-render-target
sessionsurface-texture
declare
ignoreoverlaysurface-texture
defmethodluvcraft:refresh-luvcraft-overlay:after

This refresh boundary precedes every game render pass. A widget whose McCLIM command stream did not change must nevertheless replace stale live shader pipelines before encode becomes replay-only.

prepare-gpu-mirror-compositor
widget-overlay-mirroroverlay
:target-format:depth-stencil
eval-when
:load-toplevel:execute

These method coordinates moved from the world-only class to the shared direct compositor. DEFMethod replaces one coordinate but cannot know that an old coordinate has become obsolete in a durable image.

flet
forget-method
namequalifiersspecializer-names
when
fboundpname
let*
generic
fdefinitionname
specializers
mapcar#'find-classspecializer-names
method
find-methodgenericqualifiersspecializersnil
whenmethod
remove-methodgenericmethod
defmethoddirect-gpu-mirror-depth-stencil
declare
ignoreoverlay
'
:format:depth32-float

Every command in one retained stream belongs to the same authored

plane, but separate analytic pipelines can round the projected depth in

opposite directions. ALWAYS preserves McCLIM painter order without

coplanar z-fighting; the application orders complete panels far to near.

:depth-write-enabledt:depth-compare:always
defmethoddirect-gpu-mirror-depth-stencil
declare
ignoreoverlay
nil
defmethodluvcraft:luvcraft-overlay-stage
declare
ignoreoverlay
:world-panel
defmethodluvcraft:luvcraft-world-panel-depth

Return overlay's signed distance along session's camera forward axis.

let*
camera
luvcraft:luvcraft-session-camerasession
camera-position
luvcraft:camera-positioncamera
center
widget-overlay-centeroverlay
multiple-value-bind
ignored-rightignored-upforward
declare
ignoreignored-rightignored-up
+
*
-
vec:vec3-xcenter
vec:vec3-xcamera-position
vec:vec3-xforward
*
-
vec:vec3-ycenter
vec:vec3-ycamera-position
vec:vec3-yforward
*
-
vec:vec3-zcenter
vec:vec3-zcamera-position
vec:vec3-zforward
defmethodprepare-mirror-compositor-revision
mirrorrevision

Publication is itself a preparation boundary. A world widget's final attachment is the floating-point scene target, not its McCLIM canvas; preparing the canvas format here would needlessly replace the scene cohort before the ordinary pre-pass refresh restored it.

defunplace-widget-overlay-on-surface
overlaydisplaysession

Put overlay where display's surface is this frame.

Asked at draw time, because the surface may be a phone in a moving hand; for a wall the answer is the same every frame and costs a few vector ops.

multiple-value-bind
centerright-axisup-axisnormal-axis
luvcraft:terminal-surface-panel-frame
luvcraft:terminal-display-surfacedisplay
session
setf
widget-overlay-centeroverlay
center
widget-overlay-right-axisoverlay
right-axis
widget-overlay-up-axisoverlay
up-axis
widget-overlay-normal-axisoverlay
normal-axis
overlay
defunworld-device-clip-state
overlaysessionwidthheight

Return center, right, up, and normal clip vectors for overlay's surface.

let*
camera
luvcraft:luvcraft-session-camerasession
camera-position
luvcraft:camera-positioncamera
flet
lane-vector
offset
vec:make-vec3
arefuniformsoffset
arefuniforms
+offset1
arefuniforms
+offset2
difference
leftright
vec:make-vec3
-
vec:vec3-xleft
vec:vec3-xright
-
vec:vec3-yleft
vec:vec3-yright
-
vec:vec3-zleft
vec:vec3-zright
let
right
lane-vector4
up
lane-vector8
forward
lane-vector12
x-scale
arefuniforms16
y-scale
arefuniforms17
z-scale
arefuniforms18
z-offset
arefuniforms19
labels
clip-vector
vectorpoint-p
let*
relative
ifpoint-p
differencevectorcamera-position
vector
view-x
vec:vec3-dotrelativeright
view-y
vec:vec3-dotrelativeup
view-z
vec:vec3-dotrelativeforward
list
*view-xx-scale
-
*view-yy-scale
+
*view-zz-scale
ifpoint-pz-offset0.0
view-z
make-array16:element-type'single-float:initial-contents
mapcar
lambda
value
coercevalue'single-float
append
clip-vector
widget-overlay-centeroverlay
t
clip-vector
widget-overlay-right-axisoverlay
nil
clip-vector
widget-overlay-up-axisoverlay
nil
clip-vector
widget-overlay-normal-axisoverlay
nil
defunwidget-overlay-logical-size
overlay

Return overlay's McCLIM surface size without requiring a backing texture.

multiple-value-list
gpu-mirror-logical-size
widget-overlay-mirroroverlay
luv:zdefun
prepare-direct-widget-overlay:zone:mcluv/prepare-overlay
overlaysessionsurface-texturestate
"Publish STATE and return the destination frame's affine resources."
let*
render-target
luvcraft-widget-render-targetoverlaysessionsurface-texture
target-format
luvcraft-widget-target-formatoverlaysessionrender-target
ensure-direct-gpu-mirror-pipelinesoverlaytarget-formatdepth-stencil
let
frame-state
ensure-direct-widget-frame-stateoverlaysurface-texture
setf
widget-overlay-render-stateoverlay
state
widget-overlay-render-target-textureoverlay
render-target
luv:write-buffer
direct-widget-frame-bufferframe-state
state
frame-state
defunensure-luvcraft-widget-chassis-pipeline
overlay

Return the opaque game-world housing pipeline for overlay.

The housing is deliberately an application adapter. It is not part of the shared semantic McCLIM compositor used by luft and other applications.

or
gethash:chassis
direct-widget-pipelinesoverlay
let
creatednil
completed-pnil
unwind-protect
labels
create
descriptor
let
resource
luv:create
direct-widget-deviceoverlay
descriptor
pushresourcecreated
resource
let*
vertex
create
luv:make-shader-module-descriptor:label"Luvcraft McCLIM chassis vertex":language:mathematical:code
fragment
create
luv:make-shader-module-descriptor:label"Luvcraft McCLIM chassis fragment":language:mathematical:code
pipeline
create
luv:make-render-pipeline-descriptor:label"Luvcraft McCLIM terminal chassis":layout
direct-widget-shape-layoutoverlay
:vertex`
:module,vertex
:fragment`
:module,fragment:targets
:format,
direct-widget-target-formatoverlay
:blend:premultiplied-alpha
:depth-stencil
direct-widget-depth-stenciloverlay
:primitive'
:topology:triangle-strip
setf
gethash:chassis
direct-widget-pipelinesoverlay
pipeline
direct-widget-resourcesoverlay
nconccreated
direct-widget-resourcesoverlay
completed-pt
pipeline
unlesscompleted-p
dolist
resourcecreated
ignore-errors
luv:destroyresource
luv:zdefmethod
luvcraft:encode-luvcraft-overlay:zone:mcluv/encode-chassis
sessionpasssurface-texture
let
mirror
widget-overlay-mirroroverlay
when
let*
viewport-size
luv:canvas-extent
luvcraft::luvcraft-session-contextsession
state
world-device-clip-stateoverlaysession
firstviewport-size
secondviewport-size
frame-state
prepare-direct-widget-overlayoverlaysessionsurface-texturestate

The physical housing is game geometry; only the CLIM screen itself comes from the retained semantic stream.

luv:set-bind-grouppass0
direct-widget-frame-shape-bind-groupframe-state
dotimes
layer3
luv:drawpass41
*layer4
overlay
defmethodluvcraft:encode-luvcraft-overlay:before
sessionpasssurface-texture
declare
ignoresessionpasssurface-texture

Primary methods set this only when they actually draw their backing layer. A hidden inventory or fully retracted metabar must not replay the previous visible frame's text.

setf
widget-overlay-render-stateoverlay
nil
widget-overlay-render-target-textureoverlay
nil
luv:zdefmethod
luvcraft:encode-luvcraft-overlay:zone:mcluv/encode-commands:value
length
gpu-mirror-prepared-commands
widget-overlay-mirroroverlay
:after
sessionpasssurface-texture
"Replay OVERLAY's retained McCLIM commands in exact painter order."
alexandria:when-let
state
widget-overlay-render-stateoverlay
encode-direct-gpu-mirroroverlaypass
widget-overlay-render-target-textureoverlay
state:frame-texturesurface-texture
overlay
defunbarycentric-coordinates
xyabc
destructuring-bind
axay&restignored-a
a
declare
ignoreignored-a
destructuring-bind
bxby&restignored-b
b
declare
ignoreignored-b
destructuring-bind
cxcy&restignored-c
c
declare
ignoreignored-c
let
denominator
+
*
-bycy
-axcx
*
-cxbx
-aycy
unless
zeropdenominator
let*
wa
/
+
*
-bycy
-xcx
*
-cxbx
-ycy
denominator
wb
/
+
*
-cyay
-xcx
*
-axcx
-ycy
denominator
wc
-1.0wawb
when
and
>=wa0.0
>=wb0.0
>=wc0.0
listwawbwc
defunperspective-texture-coordinate
weightsvertices
let
normalizer0.0
u0.0
v0.0
loopforweightinweightsforvertexinverticesforreciprocal-w=
/1.0
thirdvertex
forcorrected=
*weightreciprocal-w
do
incfnormalizercorrected
incfu
*corrected
fourthvertex
incfv
*corrected
fifthvertex
values
/unormalizer
/vnormalizer
defunluvcraft-widget-texture-coordinate
overlayxy

Project canvas X,Y through overlay's last rendered screen quadrilateral.

let
state
widget-overlay-render-stateoverlay
when
andstate
loopforuin'
0.01.00.01.0
forvin'
0.00.01.01.0
always

Project into the window's own coordinates rather than the drawable's. A pointer event carries the position SDL reports, which is in logical points; on a dense display the drawable is a multiple of that, and hit-testing a point against a quad projected into pixels misses by exactly the display's scale factor -- which is why no widget overlay could be clicked at all on a Retina Mac.

let*
canvas
luvcraft::luvcraft-session-canvas
widget-overlay-sessionoverlay
width
luv:canvas-widthcanvas
height
luv:canvas-heightcanvas
let*
first-triangle
listtop-lefttop-rightbottom-left
second-triangle
listbottom-lefttop-rightbottom-right
or
alexandria:when-let
weights
barycentric-coordinatesxytop-lefttop-rightbottom-left
multiple-value-list
perspective-texture-coordinateweightsfirst-triangle
alexandria:when-let
weights
barycentric-coordinatesxybottom-lefttop-rightbottom-right
multiple-value-list
perspective-texture-coordinateweightssecond-triangle
defuntranslated-widget-pointer-event
eventxy
etypecaseevent
luv:canvas-pointer-motion-event
make-instance
class-ofevent
:timestamp
luv:canvas-event-timestampevent
:xx:yy:delta-x0.0:delta-y0.0
luv:canvas-pointer-button-event
make-instance
class-ofevent
:timestamp
luv:canvas-event-timestampevent
:xx:yy:button
luv:canvas-pointer-event-buttonevent
:clicks
luv:canvas-pointer-event-clicksevent
defmethodluvcraft:handle-luvcraft-overlay-event
alexandria:when-let
uv
luvcraft-widget-texture-coordinateoverlay
luv:canvas-pointer-event-xevent
luv:canvas-pointer-event-yevent
let*
x
*
firstuv
firstsize
when
and
eq:left
luv:canvas-pointer-event-buttonevent
t
defmethodluvcraft:handle-luvcraft-focus-event
declare
ignoresession
luv:handle-canvas-event
widget-overlay-mirroroverlay
canvasevent
t
defmethodluvcraft:luvcraft-focus-score
declare
ignoresession
let*
canvas
luvcraft::luvcraft-session-canvas
widget-overlay-sessionoverlay
width
luv:canvas-widthcanvas
height
luv:canvas-heightcanvas

Pointer positions and this centre probe are both in SDL logical points. The semantic renderer still targets the full drawable extent; mixing those two coordinate spaces here displaced the focus ray on Retina.

defmethodluvcraft:release-luvcraft-overlay
let
frame
widget-overlay-frameoverlay
unless
eq:disowned
frame-stateframe
destroy-frameframe
overlay
defunadd-scaled-vector
origin&restvector-scales
let
x
vec:vec3-xorigin
y
vec:vec3-yorigin
z
vec:vec3-zorigin
loopfor
vectorscale
onvector-scalesby#'cddrdo
incfx
*
vec:vec3-xvector
scale
incfy
*
vec:vec3-yvector
scale
incfz
*
vec:vec3-zvector
scale
defunembed-luvcraft-frame
sessionframe&key
right-offset2.8

Embed enabled McCLIM frame in front of session's current camera.

let*
mirror
sheet-direct-mirror
frame-top-level-sheetframe
source-size
multiple-value-list
aspect
/
firstsource-size
secondsource-size
camera
luvcraft:luvcraft-session-camerasession
camera-position
luvcraft:camera-positioncamera
multiple-value-bind
rightignored-upforward
declare
ignoreignored-up
let
overlay
make-instance'luvcraft-world-widget-overlay:sessionsession:frameframe:mirrormirror:center
add-scaled-vectorcamera-positionforwarddistancerightright-offset
:right-axis:up-axis
vec:make-vec30.0
-
/widthaspect2.0
0.0
:normal-axis
vec:vec3-scaleforward-1.0
setf
mirror-compositormirror
overlay

The frame was enabled before it acquired its world compositor. Repaint once so text is retained for the scene pass but omitted from the backing texture.

overlay
defunopen-luvcraft-widget-lab
session&key
title"McCLIM gadget inside luvcraft"
right-offset2.8

Create a McCLIM terminal fixed in front of session's current world camera.

embed-luvcraft-framesession
open-widget-lab:titletitle:target
luvcraft:luvcraft-session-canvassession
:context
luvcraft::luvcraft-session-contextsession
:device
luvcraft::luvcraft-session-devicesession
:distancedistance:widthwidth:right-offsetright-offset
defunopen-luvcraft-surveyor-map
session&key
title"surveyor map"
right-offset0.0

Create and embed a live-world McCLIM surveyor map for session.

embed-luvcraft-framesession
open-surveyor-mapsession:titletitle:target
luvcraft:luvcraft-session-canvassession
:context
luvcraft::luvcraft-session-contextsession
:device
luvcraft::luvcraft-session-devicesession
:distancedistance:widthwidth:right-offsetright-offset
defunclose-luvcraft-widget-lab
overlay

Remove and release an open-luvcraft-widget-lab overlay.

check-typeoverlayluvcraft-widget-overlay
luvcraft:remove-luvcraft-overlay
widget-overlay-sessionoverlay
overlay
nil