// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2026 Martino Ferrari #pragma once namespace plot::render { /// GLSL source of the instanced antialiased line pipeline. /// /// The vertex shader takes one segment per instance (`a_p0` at location 0, /// `a_p1` at location 1, both with a vertex attribute divisor of 1), expands it /// in pixel space along its normal by `u_width * 0.5 + 1.0` pixels of AA fringe, /// and emits a four-vertex `GL_TRIANGLE_STRIP` quad whose corners come from /// `gl_VertexID` (0 and 1 are the two sides of `a_p0`, 2 and 3 of `a_p1`). It /// outputs `v_dist`, the signed distance from the segment axis in pixels, and /// `v_along`, the distance travelled from `a_p0` in pixels. /// /// Uniforms: `u_scale` (vec2, data space to pixels), `u_offset` (vec2, pixels), /// `u_viewport` (vec2, pixels), `u_width` (float, pixels), `u_aa` (float, the AA /// fringe half-width in pixels -- the style's `line_aa_px` in device pixels, /// clamped at 0.25), `u_color` (vec4). /// `plot::Rect` is top-left origin while GL is bottom-left, so the y axis is /// flipped exactly once, here. /// /// A degenerate segment (`a_p0 == a_p1`) keeps a finite normal and is stretched /// into a square mark one stroke width and fringe across, rather than /// collapsing to zero area and rasterising nothing — the dense path stages /// `min == max` buckets as exactly such segments. /// /// The fragment shader discards outside the fringe and ramps alpha over the last /// pixel of the half width with `smoothstep`, which is what keeps a 1px trace /// from aliasing into dashes. extern const char* const kLineVS; extern const char* const kLineFS; /// GLSL source of the instanced text pipeline. /// /// One glyph cell per instance, every attribute with a vertex attribute divisor /// of 1: `a_pos` at location 0 is the cell's top-left corner in Rect pixels, /// `a_uv` at location 1 is the glyph rect's normalised top-left in the atlas and /// `a_axis` at location 2 is the cell's local +x axis, a unit vector in pixels. /// /// The vertex shader builds the cell from that basis and its perpendicular -- /// the cell's own +v direction -- so `a_axis` of `(0, -1)` draws a run that /// advances up the screen, and it maps `a_uv` over the cell with the same /// handedness, so a glyph's top row stays its top row however the cell is /// turned. It also passes the cell's origin through `flat`, which is the bound /// the fragment shader filters against. /// /// The fragment shader converts back to texels and blends the four texels the /// fragment sits between, **clamped to the instance's own cell**. Filtering is /// the shader's, not the sampler's: every fetch is an explicit texel centre, so /// `GL_NEAREST` stays correct, and the clamp keeps a footprint reaching past a /// cell edge from blending in the neighbouring glyph of what is a tight, /// unpadded strip of cells. A point sample would have been enough only at an /// integer scale: at the library's own default of a 12 px style on the 13 px /// embedded bake it *deleted* one of every 8 columns and one of every 17 rows of /// every glyph. At scale 1 with a whole pen the two taps coincide and the result /// is exactly as crisp as a point sample. The instance's own `a_colour` tints the /// straight alpha -- per vertex, so one draw can carry runs of several colours. /// /// Uniforms: `u_viewport` (vec2, pixels), `u_px_range` (vec2, the glyph cell's /// size on screen in pixels), `u_glyph_uv` (vec2, the glyph cell's size in /// normalised atlas coordinates -- one size for the whole draw, since every /// glyph of a frame comes from one atlas; read in *both* stages, the fragment /// one needing it for the clamp), `u_tex_size` (vec2, atlas size in texels), /// `u_atlas` (sampler2D, unit 0). extern const char* const kTextVS; extern const char* const kTextFS; } // namespace plot::render