rsplot 0.5.0

silx-style scientific plotting for egui, rendered with wgpu
Documentation
// Fill shader: fill the band between a data-space polyline and its baseline.
//
// A non-instanced draw of 6 * (segment count) vertices builds two triangles per
// segment — a quad whose top edge is the curve (points[seg], points[seg+1]) and
// whose bottom edge is the baseline at the same x (baseline[seg], baseline[seg
// +1]). Unlike the line, there is no pixel-space expansion: the vertices are the
// data coordinates themselves, transformed straight to clip space. Drawn before
// the line so the stroke sits on top of its own fill (silx fill, §13 B1).

struct Params {
    ortho: mat4x4<f32>,
    color: vec4<f32>,        // linear premultiplied RGBA
    axis_log: vec2<f32>,     // 1.0 if that axis is log10, else 0.0
};

@group(0) @binding(0) var<uniform> params: Params;
@group(0) @binding(1) var<storage, read> points: array<vec2<f32>>;
@group(0) @binding(2) var<storage, read> baseline: array<f32>;

const INV_LN10: f32 = 0.4342944819032518;

fn apply_scale(p: vec2<f32>) -> vec2<f32> {
    return vec2<f32>(
        select(p.x, log(p.x) * INV_LN10, params.axis_log.x > 0.5),
        select(p.y, log(p.y) * INV_LN10, params.axis_log.y > 0.5),
    );
}

@vertex
fn vs_main(@builtin(vertex_index) vid: u32) -> @builtin(position) vec4<f32> {
    let seg = vid / 6u;
    let corner = vid % 6u;

    // Per-corner endpoint selector (0 = segment start, 1 = end) and whether the
    // corner is on the baseline (1) or the curve (0), for the two triangles
    // (curve0, base0, curve1) and (curve1, base0, base1).
    var endpoint = array<u32, 6>(0u, 0u, 1u, 1u, 0u, 1u);
    var is_base = array<u32, 6>(0u, 1u, 0u, 0u, 1u, 1u);

    let ep = endpoint[corner];
    let pt = points[seg + ep];
    // Clamp guards the 1-element placeholder bound when a curve is not filled.
    let bi = min(seg + ep, arrayLength(&baseline) - 1u);
    let yv = select(pt.y, baseline[bi], is_base[corner] == 1u);

    return params.ortho * vec4<f32>(apply_scale(vec2<f32>(pt.x, yv)), 0.0, 1.0);
}

@fragment
fn fs_main() -> @location(0) vec4<f32> {
    return params.color;
}