feat(render): style, GLSL line/text pipelines, staging batches, bitmap font
This commit is contained in:
1 parent
9a086b7d69
commit
7cbc1c9955
22 files changed
+1535
No files matched your search
@@ -0,0 +1,110 @@
|
||||
#include <plot/render/shaders.hpp>
|
||||
|
||||
// Both pipelines are `#version 330 core` and stay untouched by the upload
|
||||
// strategy: the 4.3+ path changes how vertex data reaches the GPU, never the
|
||||
// GLSL, so one program pair serves every context the library supports. The
|
||||
// declarations here are the contract the render layer's attribute layouts and
|
||||
// uniform setters mirror (see program.hpp, vertex_array.hpp, shaders.hpp).
|
||||
|
||||
namespace plot::render {
|
||||
|
||||
const char* const kLineVS = R"(#version 330 core
|
||||
layout(location = 0) in vec2 a_p0; // per-instance segment start, data space
|
||||
layout(location = 1) in vec2 a_p1; // per-instance segment end
|
||||
|
||||
uniform vec2 u_scale; // data -> pixels
|
||||
uniform vec2 u_offset; // pixels
|
||||
uniform vec2 u_viewport; // render target size, pixels
|
||||
uniform float u_width; // stroke width, pixels
|
||||
|
||||
out float v_dist; // signed distance to the segment axis, pixels
|
||||
out float v_along; // distance travelled from a_p0, pixels
|
||||
|
||||
void main() {
|
||||
vec2 p0 = a_p0 * u_scale + u_offset;
|
||||
vec2 p1 = a_p1 * u_scale + u_offset;
|
||||
vec2 d = p1 - p0;
|
||||
float len = length(d);
|
||||
// A degenerate segment has no direction: pin the normal so the quad stays
|
||||
// finite and the instance draws as a dot instead of NaN geometry.
|
||||
vec2 n = len > 1e-6 ? vec2(-d.y, d.x) / len : vec2(0.0, 1.0);
|
||||
float half_w = u_width * 0.5 + 1.0; // + one pixel of AA fringe
|
||||
|
||||
// gl_VertexID picks the corner: 0,1 are the sides of a_p0 and 2,3 of a_p1,
|
||||
// which is the order GL_TRIANGLE_STRIP expects.
|
||||
float side = (gl_VertexID & 1) == 0 ? -1.0 : 1.0;
|
||||
vec2 base = (gl_VertexID & 2) == 0 ? p0 : p1;
|
||||
vec2 px = base + n * (side * half_w);
|
||||
|
||||
// Rect is top-left origin, GL is bottom-left: flip y once, here, and never
|
||||
// again in the fragment shader or in a caller.
|
||||
vec2 ndc = vec2(px.x / u_viewport.x * 2.0 - 1.0, 1.0 - px.y / u_viewport.y * 2.0);
|
||||
gl_Position = vec4(ndc, 0.0, 1.0);
|
||||
|
||||
v_dist = side * half_w;
|
||||
v_along = (gl_VertexID & 2) == 0 ? 0.0 : len;
|
||||
}
|
||||
)";
|
||||
|
||||
const char* const kLineFS = R"(#version 330 core
|
||||
in float v_dist; // signed distance to the segment axis, pixels
|
||||
|
||||
uniform float u_width; // stroke width, pixels
|
||||
uniform vec4 u_color;
|
||||
|
||||
out vec4 o_color;
|
||||
|
||||
void main() {
|
||||
float half_w = u_width * 0.5;
|
||||
float d = abs(v_dist);
|
||||
if (d > half_w + 1.0) {
|
||||
discard; // outside the fringe; nothing to blend
|
||||
}
|
||||
// Ramp over the last pixel of the half width so a thin stroke keeps its
|
||||
// weight instead of aliasing into a dashed line.
|
||||
float alpha = 1.0 - smoothstep(half_w - 0.5, half_w + 0.5, d);
|
||||
o_color = vec4(u_color.rgb, u_color.a * alpha);
|
||||
}
|
||||
)";
|
||||
|
||||
const char* const kTextVS = R"(#version 330 core
|
||||
layout(location = 0) in vec2 a_pos; // per-instance glyph quad top-left, pixels
|
||||
layout(location = 1) in vec2 a_uv; // per-instance glyph atlas texel origin
|
||||
|
||||
uniform vec2 u_viewport; // render target size, pixels
|
||||
uniform vec2 u_px_range; // pixels per glyph cell on screen
|
||||
|
||||
out vec2 v_texel; // atlas texel coordinate of this fragment
|
||||
|
||||
const vec2 kGlyphTexels = vec2(8.0); // BitmapFont::kGlyphPx
|
||||
|
||||
void main() {
|
||||
vec2 corner = vec2(float(gl_VertexID & 1), float((gl_VertexID >> 1) & 1));
|
||||
vec2 px = a_pos + corner * u_px_range;
|
||||
// Rect is top-left origin, GL is bottom-left: the one and only y flip.
|
||||
vec2 ndc = vec2(px.x / u_viewport.x * 2.0 - 1.0, 1.0 - px.y / u_viewport.y * 2.0);
|
||||
gl_Position = vec4(ndc, 0.0, 1.0);
|
||||
v_texel = a_uv + corner * kGlyphTexels;
|
||||
}
|
||||
)";
|
||||
|
||||
const char* const kTextFS = R"(#version 330 core
|
||||
in vec2 v_texel; // atlas texel coordinate of this fragment
|
||||
|
||||
uniform sampler2D u_atlas; // GL_R8 glyph atlas, GL_NEAREST
|
||||
uniform vec2 u_tex_size; // atlas size in texels
|
||||
uniform vec4 u_color;
|
||||
|
||||
out vec4 o_color;
|
||||
|
||||
void main() {
|
||||
// Sample the centre of the texel the fragment lands in. GL_NEAREST alone
|
||||
// would tie at a texel boundary, where the driver may pick the neighbouring
|
||||
// glyph cell; rounding to a centre removes the tie by construction.
|
||||
vec2 texel = clamp(floor(v_texel), vec2(0.0), u_tex_size - vec2(1.0));
|
||||
float coverage = texture(u_atlas, (texel + vec2(0.5)) / u_tex_size).r;
|
||||
o_color = vec4(u_color.rgb, u_color.a * coverage);
|
||||
}
|
||||
)";
|
||||
|
||||
} // namespace plot::render
|
||||
Reference in new issue
Block a user