Another project
1struct Frame {
2 clip_from_world: mat4x4<f32>,
3 stroke_color: vec4<f32>,
4 construction: vec4<f32>,
5 pixels_per_mm: f32,
6 dash_period_px: f32,
7 dash_on_ratio: f32,
8 _pad: f32,
9};
10
11struct Instance {
12 @location(0) a: vec2<f32>,
13 @location(1) b: vec2<f32>,
14 @location(2) half_width_px: f32,
15 @location(3) pick_id: u32,
16 @location(4) style_bits: u32,
17};
18
19struct VsOut {
20 @builtin(position) clip: vec4<f32>,
21 @location(0) local_px: vec2<f32>,
22 @location(1) length_px: f32,
23 @location(2) half_width_px: f32,
24 @location(3) @interpolate(flat) style_bits: u32,
25 @location(4) @interpolate(flat) pick_id: u32,
26};
27
28struct FsOut {
29 @location(0) color: vec4<f32>,
30 @location(1) pick_id: u32,
31};
32
33@group(0) @binding(0) var<uniform> u: Frame;
34
35const CORNERS: array<vec2<f32>, 6> = array<vec2<f32>, 6>(
36 vec2<f32>(0.0, 0.0),
37 vec2<f32>(1.0, 0.0),
38 vec2<f32>(0.0, 1.0),
39 vec2<f32>(0.0, 1.0),
40 vec2<f32>(1.0, 0.0),
41 vec2<f32>(1.0, 1.0),
42);
43
44const CONSTRUCTION_BIT: u32 = 1u;
45
46@vertex
47fn vs(@builtin(vertex_index) vid: u32, inst: Instance) -> VsOut {
48 var corners = CORNERS;
49 let corner = corners[vid];
50 let d_mm = inst.b - inst.a;
51 let len_mm = length(d_mm);
52 let safe = max(len_mm, 1.0e-9);
53 let t_hat = select(vec2<f32>(1.0, 0.0), d_mm / safe, len_mm > 1.0e-9);
54 let n_hat = vec2<f32>(-t_hat.y, t_hat.x);
55
56 let expand_mm = (inst.half_width_px + 1.0) / u.pixels_per_mm;
57 let along_mm = mix(-expand_mm, len_mm + expand_mm, corner.x);
58 let perp_mm = mix(-expand_mm, expand_mm, corner.y);
59
60 let world_mm = inst.a + along_mm * t_hat + perp_mm * n_hat;
61 let clip = u.clip_from_world * vec4<f32>(world_mm, 0.0, 1.0);
62
63 var out: VsOut;
64 out.clip = clip;
65 out.local_px = vec2<f32>(along_mm, perp_mm) * u.pixels_per_mm;
66 out.length_px = len_mm * u.pixels_per_mm;
67 out.half_width_px = inst.half_width_px;
68 out.style_bits = inst.style_bits;
69 out.pick_id = inst.pick_id;
70 return out;
71}
72
73@fragment
74fn fs(in: VsOut) -> FsOut {
75 let along = clamp(in.local_px.x, 0.0, in.length_px);
76 let dx = in.local_px.x - along;
77 let dy = in.local_px.y;
78 let d_px = sqrt(dx * dx + dy * dy);
79 let aa = 0.5;
80 let coverage = 1.0 - smoothstep(in.half_width_px - aa, in.half_width_px + aa, d_px);
81 if (coverage <= 0.0) {
82 discard;
83 }
84
85 let is_construction = (in.style_bits & CONSTRUCTION_BIT) != 0u;
86 let dash_visible = !is_construction
87 || u.dash_period_px <= 0.0
88 || fract(along / u.dash_period_px) <= u.dash_on_ratio;
89 let color_coverage = select(0.0, coverage, dash_visible);
90
91 let base = select(u.stroke_color, u.construction, is_construction);
92 let a = base.a * color_coverage;
93
94 var out: FsOut;
95 out.color = vec4<f32>(base.rgb * a, a);
96 out.pick_id = in.pick_id;
97 return out;
98}