fix(render): a dense trace is drawn one column at a time, not as a polyline
An LOD envelope staged as a polyline moirés. level_for() sizes a bucket at one to two pixel columns and Envelope emits two points per bucket, so a column carries three or four near-vertical hairlines at as many sub-pixel phases; under src-alpha compositing its brightness is then a non-linear function of those phases, the pattern repeats at the beat between the bucket pitch and the pixel pitch, and a pan sweeps the beat so the banding crawls. draw_traces now reduces such a window onto the pixel grid: one exactly vertical segment per integer column of the axes, from the lowest to the highest screen y any gathered point put in it, flushed in framebuffer pixels with the snap on. One phase for the whole trace, so there is nothing left to beat -- and the geometry becomes O(axes.w) rather than O(buckets). Gated on the gathered density rather than on the level (the raw path beats the same way), and on Envelope alone. A hole stays a hole, disjoint neighbours are joined so a fast edge keeps it, and a span under the stroke is drawn as the stroke since the shader caps nothing. It is the one carve-out in u_snap's data/chrome rule: a column is a pixel column, and the y bounds it reports are untouched. Measured by the new test as the number of distinct coverage levels in the ink -- 4 against the polyline's 126, with 627 segments against 60 054. A count of partially covered pixels was tried first and separates nothing (577 against 652): a 1.5 px stroke's fringe always spills into the next column. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
bee318870f
commit
e81e84645f
5 files changed
+301
-3
No files matched your search
@@ -29,6 +29,11 @@ namespace plot {
|
||||
struct FrameStats {
|
||||
u32 raw_traces = 0; ///< traces drawn from raw samples (level 0)
|
||||
u32 lod_traces = 0; ///< traces drawn from a min/max pyramid level
|
||||
/// Traces whose geometry was reduced onto the pixel grid: one vertical segment
|
||||
/// per column, lit from that column's own extremes. Counts a trace from either
|
||||
/// path above -- the reduction is about the *density* of the gathered points,
|
||||
/// not about which level produced them.
|
||||
u32 column_traces = 0;
|
||||
u64 visible_samples = 0; ///< samples the gathered windows covered, summed
|
||||
u32 staged_segments = 0; ///< line segments staged, all colour groups
|
||||
u32 staged_markers = 0; ///< marker shapes staged over the traces
|
||||
@@ -500,6 +505,16 @@ class Renderer {
|
||||
/// The data helpers take it too; they read the axes rect and the transforms it
|
||||
/// pins.
|
||||
void draw_traces(const Plot& plot, const PlotLayout& layout);
|
||||
/// One gathered window reduced onto the pixel grid and staged in framebuffer
|
||||
/// pixels: for each integer column of `layout.axes`, one exactly vertical
|
||||
/// segment from the lowest to the highest screen y any gathered point put in
|
||||
/// it. Returns how many columns were staged (0 stages nothing); the caller
|
||||
/// flushes with `pixel_mapping()` and `snap = true`.
|
||||
///
|
||||
/// `gather_` is the input, read with the same origin `draw_traces` asked the
|
||||
/// series for. See `draw_traces` for when this path is taken and why.
|
||||
u32 stage_trace_columns(const Plot& plot, const PlotLayout& layout, const Trace& trace,
|
||||
f64 x_origin, u32 points);
|
||||
/// The cursors, both orientations: one stroke per cursor, placed at the coordinate its own
|
||||
/// orientation owns (`Plot::cursor_screen_coordinate()`) and spanning the other axis' whole
|
||||
/// range, in its own colour -- or in the accent at handle width while it is hovered or
|
||||
@@ -611,7 +626,11 @@ class Renderer {
|
||||
render::TextBatch glyphs_under_;
|
||||
render::TextBatch glyphs_over_;
|
||||
std::vector<f32> gather_; ///< scratch for one gathered window, re-used
|
||||
std::vector<f32> staged_; ///< scratch for one staged window, re-used
|
||||
/// One (lowest y, highest y) pair per pixel column of the axes, re-used:
|
||||
/// `stage_trace_columns()`'s working set. Two floats per column, so an 8K-wide
|
||||
/// axis is 64 kB -- bounded by the *screen*, where `gather_` is bounded by the
|
||||
/// window.
|
||||
std::vector<f32> columns_;
|
||||
mutable std::vector<u8> readback_; ///< dump_frame_ppm's row buffer
|
||||
|
||||
/// The host's `GL_COLOR_CLEAR_VALUE`, queried on the first `begin_frame()` (GL
|
||||
|
||||
Reference in new issue
Block a user