mcclim/paper.lisp
How many texture pixels wide a sheet is drawn.
Sized for reading distance, which is the only distance at which a page of ten point body text is legible at all -- on paper too. At 500 the body landed on ten pixels a line and broke up; much past this it is being minified instead, and the mirror texture has no mipmaps, so that aliases rather than softens.
How many tall. open-luvcraft-paper rebinds this to the first page's own
proportions before making the frame, so the quad hung in the world is the
sheet itself -- there is no surround, and so nothing to decide what to put
in it.
How much texture is left around the sheet. Zero, because the texture is cut to the page: the sheet is the whole quad and its edge is the page edge.
How far off the sheet the type stands, in world units.
Ink on paper is not coplanar with it. Nor can it be here: glyphs at exactly the sheet's depth lose the depth test against the sheet and come out hollow.
The page's own size in points and its lines, refetched when the page turns. Extraction is a few milliseconds and the page turns rarely, so there is nothing to be gained by doing it anywhere but here.
Measure the current page and pull its lines out of the document.
Where the sheet sits in the texture, and how many texture pixels a point is.
Measured from the texture the pane actually has rather than from the parameter it was asked for: the first page decides the shape, later pages of the same document need not be the same shape, and a page that is not gets centred with paper around it rather than stretched.
Paint the sheet, and only the sheet. The type is world geometry.
Move delta pages, staying inside the document.
Setting the page as geometry
One text run holds every line of the page. The whole page shares one glyph atlas and one instanced draw, which is why the lines are shaped separately but their instance records are concatenated: the atlas is a property of the glyph set, and a set assembled from the whole page is one binding rather than one per line.
The faces a page is set in.
Condensed on purpose. The documents this reads are set in Palatino-like faces and the ordinary DejaVu serif is about a third wider, which is what forced the old raster path to squeeze every line to make it fit. A condensed face lands close enough that the lines simply sit where the document put them.
The face to set a run in, from what the document says it used.
The sheet's top-left corner and the unit vectors that span it.
Returns the corner, a unit vector along the page's own left-to-right, a unit vector along its top-to-bottom, and how many world units a PDF point is.
UP-AXIS points down the texture, so the top-left corner is one half-axis back along both. The type also stands a fraction of a centimetre off the sheet: glyphs exactly coplanar with the paper lose the depth test against it and come out hollow, which is the same reason a terminal wall lifts its glyph run off its blocks.
Instance records placing one shaped line on the sheet at its own baseline.
Where the pen starts, in world space.
make-world-text-instances centres a run on its own inked
extents, so the centre that puts the pen where it belongs is
the pen displaced by half of those extents.
Shape every line of the current page and place it on the sheet.
Returns the concatenated instance data, every glyph placement, and the atlas they share, or NIL when the page has no drawable text.
Shape first, so the atlas is packed once for the whole page.
The overlay
Build or republish the page's glyph run when the page has changed.
Called at a frame boundary rather than from inside the pass: this creates pipelines and buffers, and the pass is no place to do that.
The scene pass draws into the session's colour texture, not into the swapchain surface; a pipeline built for the surface format is rejected as an incompatible render pass.
Replay the retained analytic sheet before its independently shaped Slug text. Clear the automatic :AFTER replay marker so the paper cannot be drawn over its own ink.
The type is a second draw in the same pass, in world space, sharing the scene's own frame uniform rather than the compositor's.
A wheel over the sheet turns pages, one notch at a time.
Clicking the right half goes forward, the left half back.
Mounting it
Hang pathname in front of session's camera as a sheet standing in the world.
A sheet of paper is not a screen bolted to a wall, so this does not go through the terminal's display modes: it is its own object, placed where the player is looking and focused with TAB like anything else.
The texture is cut to the first page's proportions, so the quad hung in the world is the sheet and there is no surround to fill. The size is passed to the frame rather than bound around it: the layout is consulted somewhere the binding does not reach, and a page-shaped parameter that quietly failed to apply is how the sheet came out landscape.
How many texture pixels wide a sheet is drawn. Sized for reading distance, which is the only distance at which a page of ten point body text is legible at all -- on paper too. At 500 the body landed on ten pixels a line and broke up; much past this it is being minified instead, and the mirror texture has no mipmaps,…
How many tall. OPEN-LUVCRAFT-PAPER rebinds this to the first page's own proportions before making the frame, so the quad hung in the world is the sheet itself -- there is no surround, and so nothing to decide what to put in it.
(session &key (pathname *paper-document-pathname*)
(distance 1.05) (width 1.25)
(right-offset 0.0))Hang PATHNAME in front of SESSION's camera as a sheet standing in the world. A sheet of paper is not a screen bolted to a wall, so this does not go through the terminal's display modes: it is its own object, placed where the player is looking and focused with TAB like anything else.
How much texture is left around the sheet. Zero, because the texture is cut to the page: the sheet is the whole quad and its edge is the page edge.
How far off the sheet the type stands, in world units. Ink on paper is not coplanar with it. Nor can it be here: glyphs at exactly the sheet's depth lose the depth test against the sheet and come out hollow.
An open document and the context it was opened in.
(&optional (text *page*) (name "test"))(frame)An explicitly owned AVFrame.
(document number)The maximum of compatible quantities.
(document number)Page NUMBER's text as one TEXT-RUN per typeset line. Positions are in PDF points with the origin at the page's top left, which is the orientation MuPDF's structured text already uses and the one a drawing surface wants. MuPDF writes the font after the line it applies to, so a line is held back until the font element…
(frame texture-width texture-height)Where the sheet sits in the texture, and how many texture pixels a point is. Measured from the texture the pane actually has rather than from the parameter it was asked for: the first page decides the shape, later pages of the same document need not be the same shape, and a page that is not gets centred with paper…
Subtraction or unary negation.
Multiplication and scalar scaling.
The minimum of compatible quantities.
Division of two represented quantities.
((pane lobby-hud-pane) region)(sheet x1 y1 x2 y2 &rest options
&key (radius 7) (filled t) &allow-other-keys)(x1 y1 x2 y2 start-color end-color)(frame)(frame)A direct GPU target for an ordered LUV-GPU-MEDIUM drawing stream. An embedded mirror retains an immutable prepared CPU revision for the game's final pass; a standalone mirror renders into its native canvas drawable.
(frame delta)(document)Addition over compatible quantities.
Test whether two compatible scalars are equal.
The faces a page is set in. Condensed on purpose. The documents this reads are set in Palatino-like faces and the ordinary DejaVu serif is about a third wider, which is what forced the old raster path to squeeze every line to make it fit. A condensed face lands close enough that the lines simply sit where the…
(font-name)Logical disjunction of tests and raw truth values.
(overlay)The sheet's top-left corner and the unit vectors that span it. Returns the corner, a unit vector along the page's own left-to-right, a unit vector along its top-to-bottom, and how many world units a PDF point is.
(vector)(vector scale)(origin &rest vector-scales)(overlay run atlas glyphs shaped font-loader)(arguments)(draws shaped font-loader)(glyphs atlas center right up scale min-x min-y max-x max-y
&key (ink '(0.96 0.32 0.48)))Build one dense model-and-atlas record per drawable glyph occurrence. INK is the linear RGB carried in the record's three spare lanes.
(overlay)Shape every line of the current page and place it on the sheet. Returns the concatenated instance data, every glyph placement, and the atlas they share, or NIL when the page has no drawable text.
(cache font-pathname string &key direction)(shaped font-loader cache font-pathname)(cache glyphs)A direct McCLIM surface mounted in the 3D scene.
(overlay)(handle)Logically invalidate HANDLE immediately. Native teardown may be deferred until submitted work which captured HANDLE has completed.
(overlay session)Build or republish the page's glyph run when the page has changed. Called at a frame boundary rather than from inside the pass: this creates pipelines and buffers, and the pass is no place to do that.
(device)(run device string glyphs atlas instance-data)Publish one complete replacement instance population into RUN. The caller owns the semantic candidate. This function creates and fills its new GPU buffer before installing the new string, glyph, atlas, CPU-data, and buffer cohort. Native destruction of the predecessor remains submission-aware through the backend's…
(device target-format string font-pathname shaped glyphs atlas center
world-units-per-em instance-data &key (label "world HarfBuzz Slug text"))Create one owned Slug draw batch from caller-positioned GLYPHS. The caller owns the semantic placement policy and supplies the dense instance records. This is the shared GPU boundary for ordinary shaped runs and the unified terminal surface in #7ZM22R.
(overlay run frame device)(run device uniform-buffer)(name-and-options &rest method-tail)Define a method whose complete dynamic extent is an ambient trace zone. The inferred name includes the generic function, non-T required specializers, and qualifiers. :ZONE and :VALUE have the same meaning as in ZDEFUN.
(overlay session pass surface-texture)Encode OVERLAY into SESSION's open scene PASS for SURFACE-TEXTURE.
(context)Return CONTEXT's configured drawable extent as (WIDTH HEIGHT), or NIL.
(overlay session width height)Replay COMPOSITOR's textureless McCLIM mirror into PASS under affine STATE. DESTINATION-TEXTURE describes the open pass for format and clipping. FRAME-TEXTURE names the bounded in-flight presentation slot whose host-visible buffers are safe to update; normally both arguments are the same texture.
(pass-encoder pipeline)(pass-encoder slot buffer &key (offset 0))(pass-encoder index bind-group)(pass-encoder vertex-count
&optional (instance-count 1) (first-vertex 0) (first-instance 0))(overlay session)Publish any complete pending render state for OVERLAY at a frame boundary.
(focus session canvas event)Handle EVENT while FOCUS owns SESSION's modal player interaction.
A native destination with a lifetime and frame clock.
(session)(overlay session canvas event)Handle EVENT projected onto OVERLAY, returning true when consumed.
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.
(overlay x y)Test whether one compatible scalar is less than another.
(overlay)Release resources owned by an object attached to luvcraft.
(document)A McCLIM frame manager constrained by luv's current native host.
(pathname &key context)(mirror)(camera)(x y z)(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.
(overlay)(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.
A sheet of PDF paper, standing in the luvcraft world.
The page is split the way #S8LIJP says to split it: the sheet is one retained analytic primitive and the type is world geometry. Both enter the game's final pass directly; there is no pane raster or texture blit.
The text is not in the texture at all. MuPDF gives back each typeset line with its baseline, its size, and the font it was set in; those are shaped through Slug and emitted as world-space glyph instances on the sheet's own plane, the same way a terminal wall emits its screen. Slug evaluates the outlines in the fragment shader at whatever resolution the pixel has, so the page is as sharp far away as it is up close -- which is the whole point, and which drawing the text into the texture could not do at any texture size (#I3G0S7).