summaryrefslogtreecommitdiff
path: root/shaders/post/vignette.glsl
blob: 30dc2e0fb9655ccd6676b68753492552bc2d6095 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Vignette: the window's corners fall a little into shade, in linear light,
// so the eye settles on the middle. Round, whatever the window's shape;
// nothing within half the way to a corner is touched. At most 28% at the
// far corners (level 3), and never more than pardesCap, so text and its
// selection keep their own contrast or 4.5. Tags, grips, notices and the
// cursor are left alone (pardesSpare): the focus indicators never darken.
// It is a Shadertoy file: pardes puts its prefix before it.

float strength() { return min(pardesByLevel(0.10, 0.18, 0.28), pardesCap); }

vec3 toLinear(vec3 c) {
    return mix(pow((c + 0.055) / 1.055, vec3(2.4)), c / 12.92, lessThanEqual(c, vec3(0.04045)));
}

vec3 toSrgb(vec3 c) {
    c = max(c, vec3(0.0));
    return mix(1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055, c * 12.92, lessThanEqual(c, vec3(0.0031308)));
}

float ign(vec2 p) {
    return fract(52.9829189 * fract(dot(p, vec2(0.06711056, 0.00583715))));
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = fragCoord / iResolution.xy;
    vec4 frame = texture(iChannel0, uv);
    if (pardesSpared(fragCoord)) {
        fragColor = frame;
        return;
    }
    // 0 at the middle, 1 at a corner, on a circle's measure.
    vec2 half_size = 0.5 * iResolution.xy;
    float r = length(fragCoord - half_size) / length(half_size);
    float shade = strength() * pow(smoothstep(0.5, 1.0, r), 1.5);
    vec3 srgb = toSrgb(toLinear(frame.rgb) * (1.0 - shade));
    srgb += (ign(fragCoord) - 0.5) / 255.0 * step(1e-4, shade);
    fragColor = vec4(clamp(srgb, 0.0, 1.0), frame.a);
}