summaryrefslogtreecommitdiff
path: root/shaders/post/grain.glsl
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 07:41:35 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commit411d0b6059192b75853e220e1242b694ae461a3e (patch)
tree50f8bb207f3cdda497bdd84658a2d3ea74b4bc2b /shaders/post/grain.glsl
parentda920ca49e3f5d1649e811bbdc3ddba482c6aae4 (diff)
parent5526c68beec454cfe607a579723b97b4848e7d3a (diff)
downloadpardes-411d0b6059192b75853e220e1242b694ae461a3e.tar.gz
pardes-411d0b6059192b75853e220e1242b694ae461a3e.zip
Merge: 9P rounds 9-17 + render DPI, dark tints, G4-G10
Diffstat (limited to 'shaders/post/grain.glsl')
-rw-r--r--shaders/post/grain.glsl32
1 files changed, 32 insertions, 0 deletions
diff --git a/shaders/post/grain.glsl b/shaders/post/grain.glsl
new file mode 100644
index 00000000..61c51492
--- /dev/null
+++ b/shaders/post/grain.glsl
@@ -0,0 +1,32 @@
+// Grain: the page's own ground takes a fine, still grain, like paper. Only
+// pixels of the page's colour (iBackgroundColor) are grained: no glyph, no
+// selection, no tag or rule, and nothing in pardesSpare. The grain averages
+// to the page, is a logical pixel big (pardesScale), and never moves, so it
+// costs no frames. At most 1.5, 3 and 5 of 255 at levels 1 to 3, and never
+// more than pardesCap, which keeps the text on it at its own contrast or 4.5.
+// It is a Shadertoy file: pardes puts its prefix before it.
+
+float amplitude() { return min(pardesByLevel(1.5, 3.0, 5.0) / 255.0, pardesCap); }
+
+// An integer hash of the grain cell: white, with no pattern to see.
+float hash(uvec2 p) {
+ uint h = p.x * 1664525u + p.y * 1013904223u;
+ h ^= h >> 16;
+ h *= 2246822519u;
+ h ^= h >> 13;
+ h *= 3266489917u;
+ h ^= h >> 16;
+ return float(h) / 4294967295.0;
+}
+
+void mainImage(out vec4 fragColor, in vec2 fragCoord) {
+ vec2 uv = fragCoord / iResolution.xy;
+ vec4 frame = texture(iChannel0, uv);
+ fragColor = frame;
+ vec3 page = iBackgroundColor.rgb;
+ if (any(greaterThan(abs(frame.rgb - page), vec3(0.75 / 255.0))) || pardesSpared(fragCoord)) return;
+ uvec2 cell = uvec2(fragCoord / max(1.0, pardesScale));
+ // Two hashes summed: a triangular spread, softer than a flat one.
+ float n = hash(cell) + hash(cell + uvec2(7919u, 104729u)) - 1.0;
+ fragColor = vec4(clamp(page + n * amplitude(), 0.0, 1.0), frame.a);
+}