Another project
1struct Frame {
2 viewport_px: vec2<f32>,
3 _pad: vec2<f32>,
4};
5
6@group(0) @binding(0) var<uniform> u: Frame;
7
8struct VsOut {
9 @builtin(position) clip: vec4<f32>,
10 @location(0) local_px: vec2<f32>,
11 @location(1) half_px: vec2<f32>,
12 @location(2) fill: vec4<f32>,
13 @location(3) border: vec4<f32>,
14 @location(4) border_thickness_px: f32,
15 @location(5) corner_radius_px: f32,
16};
17
18@vertex
19fn vs(
20 @builtin(vertex_index) vid: u32,
21 @location(0) rect_xywh_px: vec4<f32>,
22 @location(1) fill: vec4<f32>,
23 @location(2) border: vec4<f32>,
24 @location(3) thickness_radius: vec2<f32>,
25) -> VsOut {
26 var corners = array<vec2<f32>, 6>(
27 vec2<f32>(0.0, 0.0),
28 vec2<f32>(1.0, 0.0),
29 vec2<f32>(0.0, 1.0),
30 vec2<f32>(1.0, 0.0),
31 vec2<f32>(1.0, 1.0),
32 vec2<f32>(0.0, 1.0),
33 );
34 let c = corners[vid];
35 let pos_px = rect_xywh_px.xy + c * rect_xywh_px.zw;
36 let half_px = rect_xywh_px.zw * 0.5;
37 let center_px = rect_xywh_px.xy + half_px;
38 let local_px = pos_px - center_px;
39 let ndc = vec2<f32>(
40 (pos_px.x / u.viewport_px.x) * 2.0 - 1.0,
41 1.0 - (pos_px.y / u.viewport_px.y) * 2.0,
42 );
43 var out: VsOut;
44 out.clip = vec4<f32>(ndc, 0.0, 1.0);
45 out.local_px = local_px;
46 out.half_px = half_px;
47 out.fill = fill;
48 out.border = border;
49 out.border_thickness_px = thickness_radius.x;
50 out.corner_radius_px = thickness_radius.y;
51 return out;
52}
53
54fn sd_rounded_rect(p: vec2<f32>, half: vec2<f32>, r: f32) -> f32 {
55 let smaller_half = min(half.x, half.y);
56 let r_clamped = clamp(r, 0.0, smaller_half);
57 let q = abs(p) - half + vec2<f32>(r_clamped, r_clamped);
58 let outside = length(max(q, vec2<f32>(0.0, 0.0)));
59 let inside = min(max(q.x, q.y), 0.0);
60 return outside + inside - r_clamped;
61}
62
63@fragment
64fn fs(in: VsOut) -> @location(0) vec4<f32> {
65 let aa = 0.5;
66 let sd_outer = sd_rounded_rect(in.local_px, in.half_px, in.corner_radius_px);
67 let cov_outer = clamp(0.5 - sd_outer / aa, 0.0, 1.0);
68 if in.border_thickness_px <= 0.0 {
69 return in.fill * cov_outer;
70 }
71 let inner_half = max(in.half_px - vec2<f32>(in.border_thickness_px, in.border_thickness_px), vec2<f32>(0.0, 0.0));
72 let inner_radius = max(in.corner_radius_px - in.border_thickness_px, 0.0);
73 let sd_inner = sd_rounded_rect(in.local_px, inner_half, inner_radius);
74 let cov_inner = clamp(0.5 - sd_inner / aa, 0.0, 1.0);
75 let cov_border = max(cov_outer - cov_inner, 0.0);
76 let fill_premul = in.fill * cov_inner;
77 let border_premul = in.border * cov_border;
78 let inv_border_alpha = 1.0 - border_premul.a;
79 return border_premul + fill_premul * inv_border_alpha;
80}