fix(render): clip grid, traces, regions and cursors to the plot area
This commit is contained in:
1 parent
d853db62ae
commit
2d819c4228
3 files changed
+610
-7
No files matched your search
@@ -111,6 +111,12 @@ class Renderer {
|
||||
/// bottom-left origin once, clears that region to `style().background` and
|
||||
/// empties the staging batches.
|
||||
///
|
||||
/// The scissor that bounds the clear is the frame's *baseline clip*: it stays engaged,
|
||||
/// set to the same viewport rect, so every pass of the frame is bounded by the region
|
||||
/// the host gave the renderer -- and `draw()` narrows and releases it again around the
|
||||
/// passes that draw inside a plot's axes (see `set_clip()`). `end_frame()` turns the
|
||||
/// scissor test off again, so a host never inherits a clip it did not ask for.
|
||||
///
|
||||
/// It is also where the instance stores wait -- once each -- for the previous
|
||||
/// frame's draws to retire the ring they read, before this frame writes any
|
||||
/// slot (see `InstanceStore::begin_frame`): a frame never synchronises with the
|
||||
@@ -152,14 +158,30 @@ class Renderer {
|
||||
/// line geometry staged with everything else, the names are glyphs on the text
|
||||
/// path, and both read the boxes `PlotLayout::legend` measured. It is the last
|
||||
/// line batch, so the legend cannot be drawn under a trace, and it leaves no GL
|
||||
/// state of its own -- the frame's blend and its neighbours' scissor already say
|
||||
/// everything a fill and a hairline border need (see end_frame's residue list).
|
||||
/// state of its own: it is drawn inside the same axes clip the interior passes share,
|
||||
/// and the frame's blend already says everything a fill and a hairline border need
|
||||
/// (see end_frame's residue list).
|
||||
///
|
||||
/// Regions are part of that same evidence: the fill is one instance of the line
|
||||
/// pipeline (`fill_pixels()`, the primitive the legend panel uses), the bounds are
|
||||
/// vertical strokes and the label is a staged glyph run, so a frame with regions
|
||||
/// leaves behind exactly what a frame without them does.
|
||||
void draw(Plot& plot);
|
||||
///
|
||||
/// **The clip** is the one piece of state the frame moves to keep data inside the plot
|
||||
/// area (spec §13): the passes that draw *inside* `axes` -- grid, traces, regions,
|
||||
/// cursors, the measurement band, annotations and the legend -- run with the scissor
|
||||
/// narrowed to `layout().axes`, intersected with the frame's viewport, while the axis
|
||||
/// lines (chrome drawn on the rect's own edge, which overhangs it by half a stroke) and
|
||||
/// the tick labels and titles (outside the rect by design) run with the frame's viewport
|
||||
/// clip. A sample outside the visible range, or a segment the gathered window's slack
|
||||
/// hangs past the end of the window, therefore cannot be drawn over the label strips --
|
||||
/// or, in a `Figure`, into the row above.
|
||||
///
|
||||
/// Nothing moves to make that happen: the clip is a GL state change and not a geometry
|
||||
/// one, so the vertices staged, the transforms and the data-space invariant are exactly
|
||||
/// what they were.
|
||||
|
||||
/// Draws a whole `Figure`: every row in its own rect, then the figure's one shared
|
||||
/// x axis.
|
||||
|
||||
@@ -192,6 +214,16 @@ class Renderer {
|
||||
/// vertex array 0, program 0, `GL_ARRAY_BUFFER` 0, texture unit 0 active and
|
||||
/// nothing bound to `GL_TEXTURE_2D` on it, blending off, scissoring off, and the
|
||||
/// viewport left at the frame's rect (the caller sets its own for the next pass).
|
||||
///
|
||||
/// The scissor is the other piece of state a frame moves, and it ends the frame *off*:
|
||||
/// `begin_frame()` engages it on the frame's viewport -- the box the clear uses --
|
||||
/// `draw()` narrows it to a plot's `axes` for the interior passes and releases it back to
|
||||
/// the viewport for the labels and titles, and this turns the test off. A host is
|
||||
/// therefore never left holding a clip it did not ask for: not the axes rect of the last
|
||||
/// interior pass, and not the viewport's either. The box itself is left at the viewport's
|
||||
/// own rect, which is where that release puts it, so a host that enables the scissor
|
||||
/// again without setting one gets the region the frame drew in.
|
||||
|
||||
/// The one piece of global state the frame *changed* is handed back rather than
|
||||
/// left where the frame wanted it: the clear colour, which is
|
||||
/// `style().background` only for the duration of the frame. GL keeps no history
|
||||
@@ -338,6 +370,29 @@ class Renderer {
|
||||
/// is texture-bound, so this runs once per frame, after all line geometry.
|
||||
void flush_text() noexcept;
|
||||
|
||||
/// Narrows the frame's clip to `rect` -- framebuffer pixels, top-left origin, like every
|
||||
/// `Rect` here -- and *intersects* it with the frame's viewport, so the clip can only
|
||||
/// ever be smaller than the region the frame owns: a rect the layout got wrong, or one
|
||||
/// that reaches past the frame, clips the interior passes away rather than letting them
|
||||
/// paint over the host's surface. Enables `GL_SCISSOR_TEST`; `clear_clip()` puts it back.
|
||||
///
|
||||
/// The box is integral and GL's origin is bottom-left, so this is also where a `Rect`
|
||||
/// becomes a scissor box, and it rounds *inward* -- see `clip_to()`. Called once per
|
||||
/// plot with `layout().axes`, and released again before the passes that draw outside the
|
||||
/// axes (see `draw_plot()`).
|
||||
void set_clip(const Rect& rect) noexcept;
|
||||
/// Puts the frame's clip back to its viewport: the state `begin_frame()` leaves, and the
|
||||
/// one the axis lines, the tick labels and the axis titles run with -- chrome that lives
|
||||
/// outside `axes` by design, and would be erased under the axes clip.
|
||||
void clear_clip() noexcept;
|
||||
/// The one place a scissor box is computed from a rect's four edges: clamped to the
|
||||
/// framebuffer's rows, rounded *inward* (`ceil` the near edges, `floor` the far ones) so
|
||||
/// the box holds only pixels the rect entirely contains -- rounding outward would let a
|
||||
/// trace's half-pixel fringe past the edge it is being kept behind -- and flipped to GL's
|
||||
/// bottom-left origin. An empty or unordered rect (a degenerate axes, or a NaN) sets an
|
||||
/// empty box, which rejects every fragment: the honest meaning of "clip to nothing".
|
||||
void clip_to(f32 x0, f32 y0, f32 x1, f32 y1) noexcept;
|
||||
|
||||
/// Fills `rect` -- in framebuffer pixels, like `Rect` -- with `color`, in one
|
||||
/// instance: a horizontal stroke whose width is the rect's height *is* the rect,
|
||||
/// because a stroke's quad is its perpendicular width and the fragment shader
|
||||
|
||||
Reference in new issue
Block a user