Module shaders

Source
Expand description

GLSL sources for every GPU effect (engine/gpu.rs compiles these).

Convention: one full-screen triangle vertex shader (VERT) plus a fragment shader per effect built from PRELUDE + the effect body. A per-effect body (everything below the divider near the bottom of this file) is a complete shader: it defines its own void main(), samples tex and mixes its result back through the mask itself — see “Rules every body below follows”.

The vec4 effect(vec4 src, vec2 uv) + MAIN convention is used only where the caller supplies the body: EffectKind::Shader (via user_shader) and gpu.rs’s COPY_BODY / MATTE_BODY. MAIN samples tex, calls effect and applies the mask, so those bodies never write out_color. fragment() does the assembly for both cases.

Uniforms available to every effect: sampler2D tex the layer being processed (straight alpha, top-down) vec2 u_res layer size in pixels float u_time clip-local seconds float u_scale canvas px per project px (pixel-sized params must multiply by this) float p0..p7 the effect parameters in EffectKind::params() order sampler2D u_mask mask coverage (1 = apply); u_has_mask is 0 when there is none Fragment output is out_color (straight alpha).

Textures are uploaded top-down and the vertex shader flips the clip-space Y instead, so uv.y = 0 is the top of the image everywhere — in the sampler, in glReadPixels output and in egui.

Constants§

BLEND
Blend modes as a GLSL function (vec3 blend(int mode, vec3 s, vec3 d)) mirroring engine::blend. The int is BlendMode::ALL’s index — see blend_index in engine/gpu.rs.
BLOB_TRACK 🔒
Overlay for the colour tracker: tints everything within Tolerance of the target and draws a crosshair at the centroid.
BLUR 🔒
24-tap Vogel disc, Gaussian-weighted; radius p0 project px.
CHROMA_KEY 🔒
Chroma key: distance in the Cb/Cr plane to the key colour, with spill removal, matte erode/dilate (p7 project px, + shrinks) and a show-mask switch (p5).
COLOR 🔒
Saturation + hue matrix (same feColorMatrix pair as the CPU path), then brightness/contrast/gamma.
COLOR_REPLACE 🔒
Replace one colour with another: RGB distance to the source colour, faded out over Tolerance .. Tolerance + Softness (distance normalised so 1.0 is black-to-white).
COMPOSITE
Composite/transform shader: samples a layer through an inverse 3x3 (perspective-capable) matrix with the chosen Scaler (0 = nearest, 1 = bilinear, 2 = bicubic Catmull-Rom) and blends it onto the canvas. Appended to PRELUDE + BLEND. u_inv maps canvas pixels (y down) to layer uv.
CROP 🔒
Left/Right/Top/Bottom fractions cut away (alpha 0) with a p4 feather.
CURVES 🔒
Twelve knots (master, R, G, B) driving a monotone cubic through (0,0) (.25,a) (.5,b) (.75,c) (1,1). Fritsch-Carlson tangents keep the spline monotone, so a curve never folds back on itself. Declares p8..p11 itself: PRELUDE only carries p0..p7.
EDGE_GLOW 🔒
Sobel on luma with the tap spacing set by Width (p1) - a wider kernel is the cheap stand-in for dilating the edge - then a coloured glow, optionally over the source.
FLIP 🔒
p0 = horizontal, p1 = vertical (>= 0.5 = on).
GRAYSCALE 🔒
HUE_SHIFT 🔒
Hue rotate (p0 degrees), saturation multiply (p1) and lightness offset (p2) in HSL.
INVERT 🔒
JPEG_COMPRESS 🔒
JPEG-ish: the block DC (4 taps) is quantised coarsely, the AC residual more coarsely still, and the chroma optionally read from a 2x2 grid (4:2:0). This is an approximation - there is no DCT here, but the visible artefacts (blocking, colour smear, banding) track Quality the same way.
LEVELS 🔒
In black/white, gamma, out black/white (same convention as Color’s gamma: v^(1/g)).
MAIN
Entry point appended after a vec4 effect(vec4 src, vec2 uv) body: sample, run effect, mask. Used by user_shader (EffectKind::Shader) and gpu.rs’s copy/matte programs only — the built-in bodies below write out_color themselves.
MASK
Mask rasteriser (rect / ellipse / polygon / path with feather, expand, invert, rotation). Appended to PRELUDE; everything is in canvas pixels, relative to the layer centre. Writes coverage to every channel so it reads as .r (a matte) or as alpha.
MOTION_BLUR 🔒
Shutter-window average of the frames gpu.rs supplies.
PIXELATE 🔒
Snap to a p0-project-px block grid and sample its centre.
PRELUDE
Shared header: version, precision, varyings, the uniform block and helpers (rgb<->hsl, luma, hash noise, clamped sampling, mask application).
REC_DOT 🔒
Blinking record dot in a corner (p2: 0 = top-left, 1 = top-right, 2 = bottom-left, 3 = bottom-right) plus an optional HH:MM:SS timecode drawn as seven-segment quads from the clip-local time.
SHARPEN 🔒
Unsharp mask against a 3x3 box at p1 project px spacing.
THRESHOLD 🔒
Hard/soft threshold on luma, or per channel when p2 >= 0.5.
TINT 🔒
Mix towards (p0,p1,p2) 0..255 by p3.
VERT
Full-screen triangle; no vertex buffer needed (gl_VertexID based).
VHS 🔒
One-pass VHS: per-line tracking jitter, chroma bleed to the right of an edge, luma noise, scanlines, sharpening ringing, a head-switching band at the bottom and tape-wear dropouts. Cheap approximations of what ntsc-rs models properly - no line-rate filtering, no real comb filter.
VIGNETTE 🔒
Darken outside p0 (fraction of the half diagonal) with p1 softness by p2.

Functions§

body
Body for each EffectKind that runs on the GPU. None = geometric or CPU-only.
fragment
The complete fragment source for one effect, or None when it has no GPU body.
user_shader
Wrap a user shader body (EffectKind::Shader) so it sees the same prelude and knobs u1..u8. The body must define vec4 effect(vec4 src, vec2 uv) (see model::DEFAULT_SHADER).