From db3d49adb0bdea082a193bff547ef6e153d81d64 Mon Sep 17 00:00:00 2001
From: ickk <git@ickk.io>
Date: Sun, 27 Nov 2022 01:36:29 +1100
Subject: [PATCH] subpixel rendering

---
 src/render/unified/shader.wgsl | 39 ++++++++++++++++++++++++++++------
 1 file changed, 32 insertions(+), 7 deletions(-)

diff --git a/src/render/unified/shader.wgsl b/src/render/unified/shader.wgsl
index 3aac721..7ff2276 100644
--- a/src/render/unified/shader.wgsl
+++ b/src/render/unified/shader.wgsl
@@ -61,6 +61,27 @@ fn sdRoundBox(p: vec2<f32>, b: vec2<f32>, r: f32) -> f32 {
     return min(max(q.x, q.y), 0.0) + length(max(q, vec2<f32>(0.0))) - r;
 }
 
+fn median3(v: vec3<f32>) -> f32 {
+    return max(min(v.x, v.y), min(max(v.x, v.y), v.z));
+}
+
+fn sample_subpixel(coords: vec2<f32>, dim: vec2<f32>, arr: i32, scale: f32) -> f32 {
+    var contrib = 0.;
+    // collect a few samples
+    let sample = textureSample(font_texture, font_sampler, vec2(coords.xy), arr);
+    contrib += clamp((median3(sample.rgb) - 0.5) * scale + 0.5, 0., 1.);
+    let sample = textureSample(font_texture, font_sampler, vec2(coords.xy) + vec2(-dim.x, dim.y) / 3., arr);
+    contrib += clamp((median3(sample.rgb) - 0.5) * scale + 0.5, 0., 1.);
+    let sample = textureSample(font_texture, font_sampler, vec2(coords.xy) + vec2(-dim.x, -dim.y) / 3., arr);
+    contrib += clamp((median3(sample.rgb) - 0.5) * scale + 0.5, 0., 1.);
+    let sample = textureSample(font_texture, font_sampler, vec2(coords.xy) + vec2(dim.x, dim.y) / 3., arr);
+    contrib += clamp((median3(sample.rgb) - 0.5) * scale + 0.5, 0., 1.);
+    let sample = textureSample(font_texture, font_sampler, vec2(coords.xy) + vec2(dim.x, -dim.y) / 3., arr);
+    contrib += clamp((median3(sample.rgb) - 0.5) * scale + 0.5, 0., 1.);
+    // take the average
+    return (contrib / 5.);
+}
+
 @fragment
 fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
     if quad_type.t == 0 {
@@ -77,14 +98,18 @@ fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
         return vec4<f32>(in.color.rgb, rect_dist * in.color.a);
     }
     if quad_type.t == 1 {
-        var px_range = 5.0;
+        var px_range = 5.;
         var tex_dimensions = textureDimensions(font_texture);
-        var msdf_unit = vec2<f32>(px_range, px_range) / vec2<f32>(f32(tex_dimensions.x), f32(tex_dimensions.y));
-        var x = textureSample(font_texture, font_sampler, vec2<f32>(in.uv.x, 1.0 - in.uv.y), i32(in.uv.z));
-        var v = max(min(x.r, x.g), min(max(x.r, x.g), x.b));
-        var sig_dist = (v - 0.5) * dot(msdf_unit, 0.5 / fwidth(in.uv.xy));
-        var a = clamp(sig_dist + 0.5, 0.0, 1.0);
-        return vec4<f32>(in.color.rgb, a);
+        var msdf_unit = vec2(px_range, px_range) / vec2(f32(tex_dimensions.x), f32(tex_dimensions.y));
+        let scale = dot(msdf_unit, 0.5 / fwidth(in.uv.xy));
+        let subpixel_dimensions = vec2(fwidth(in.uv.x) / 3., fwidth(in.uv.y));
+
+        let red = sample_subpixel(vec2(in.uv.x - subpixel_dimensions.x, 1.0 - in.uv.y), subpixel_dimensions, i32(in.uv.z), scale);
+        let green = sample_subpixel(vec2(in.uv.x, 1.0 - in.uv.y), subpixel_dimensions, i32(in.uv.z), scale);
+        let blue = sample_subpixel(vec2(in.uv.x + subpixel_dimensions.y, 1.0 - in.uv.y), subpixel_dimensions, i32(in.uv.z), scale);
+        let alpha = (red + green + blue) / 3.;
+
+        return vec4(red * in.color.r, green * in.color.g, blue * in.color.b, alpha);
     }
     if quad_type.t == 2 {
         var bs = min(in.border_radius, min(in.size.x, in.size.y));
-- 
GitLab