1pub const F32: &str = r#"const WORKGROUP_SIZE: u32 = {{WORKGROUP_SIZE}}u;
2
3struct VertexRaw {
4 data: array<f32, 12u>,
5};
6
7struct LineParams {
8 color: vec4<f32>,
9 count: u32,
10 half_width_data: f32,
11 line_style: u32,
12 thick: u32,
13};
14
15@group(0) @binding(0)
16var<storage, read> buf_x: array<f32>;
17
18@group(0) @binding(1)
19var<storage, read> buf_y: array<f32>;
20
21@group(0) @binding(2)
22var<storage, read_write> out_vertices: array<VertexRaw>;
23
24@group(0) @binding(3)
25var<uniform> params: LineParams;
26
27fn should_draw(segment: u32, style: u32) -> bool {
28 switch(style) {
29 case 0u: { return true; } // Solid
30 case 1u: { return (segment % 4u) < 2u; } // Dashed: on,on,off,off
31 case 2u: { return (segment % 4u) < 2u; } // Dotted approximated via dashed pattern
32 case 3u: {
33 let m = segment % 6u;
34 return (m < 2u) || (m == 3u); // DashDot: on,on,off,on,off,off
35 }
36 default: { return true; }
37 }
38}
39
40fn write_vertex(index: u32, pos: vec2<f32>, color: vec4<f32>) {
41 var vertex: VertexRaw;
42 vertex.data[0u] = pos.x;
43 vertex.data[1u] = pos.y;
44 vertex.data[2u] = 0.0;
45 vertex.data[3u] = color.x;
46 vertex.data[4u] = color.y;
47 vertex.data[5u] = color.z;
48 vertex.data[6u] = color.w;
49 vertex.data[7u] = 0.0;
50 vertex.data[8u] = 0.0;
51 vertex.data[9u] = 1.0;
52 vertex.data[10u] = 0.0;
53 vertex.data[11u] = 0.0;
54 out_vertices[index] = vertex;
55}
56
57@compute @workgroup_size(WORKGROUP_SIZE)
58fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
59 if (params.count < 2u) {
60 return;
61 }
62 let segments = params.count - 1u;
63 let idx = gid.x;
64 if (idx >= segments) {
65 return;
66 }
67
68 let p0 = vec2<f32>(buf_x[idx], buf_y[idx]);
69 let p1 = vec2<f32>(buf_x[idx + 1u], buf_y[idx + 1u]);
70 let delta = p1 - p0;
71 let len = length(delta);
72 let draw = should_draw(idx, params.line_style) && (len != 0.0);
73 var color = params.color;
74 if (!draw) {
75 color.w = 0.0;
76 }
77
78 let thick = params.thick != 0u;
79 if (!thick) {
80 let base = idx * 2u;
81 write_vertex(base + 0u, p0, color);
82 write_vertex(base + 1u, p1, color);
83 return;
84 }
85
86 if (!draw) {
87 let base = idx * 6u;
88 // Emit fully transparent degenerate geometry for skipped/degenerate segments.
89 write_vertex(base + 0u, p0, color);
90 write_vertex(base + 1u, p0, color);
91 write_vertex(base + 2u, p0, color);
92 write_vertex(base + 3u, p0, color);
93 write_vertex(base + 4u, p0, color);
94 write_vertex(base + 5u, p0, color);
95 return;
96 }
97
98 var half_width = params.half_width_data;
99 if (half_width < 0.0001) {
100 half_width = 0.0001;
101 }
102 let dir = normalize(delta);
103 let normal = vec2<f32>(-dir.y, dir.x);
104 let offset = normal * half_width;
105 let v0 = p0 + offset;
106 let v1 = p1 + offset;
107 let v2 = p1 - offset;
108 let v3 = p0 - offset;
109
110 let base = idx * 6u;
111 write_vertex(base + 0u, v0, params.color);
112 write_vertex(base + 1u, v1, params.color);
113 write_vertex(base + 2u, v2, params.color);
114 write_vertex(base + 3u, v0, params.color);
115 write_vertex(base + 4u, v2, params.color);
116 write_vertex(base + 5u, v3, params.color);
117}
118"#;
119
120pub const F64: &str = r#"const WORKGROUP_SIZE: u32 = {{WORKGROUP_SIZE}}u;
121
122struct VertexRaw {
123 data: array<f32, 12u>,
124};
125
126struct LineParams {
127 color: vec4<f32>,
128 count: u32,
129 half_width_data: f32,
130 line_style: u32,
131 thick: u32,
132};
133
134@group(0) @binding(0)
135var<storage, read> buf_x: array<f64>;
136
137@group(0) @binding(1)
138var<storage, read> buf_y: array<f64>;
139
140@group(0) @binding(2)
141var<storage, read_write> out_vertices: array<VertexRaw>;
142
143@group(0) @binding(3)
144var<uniform> params: LineParams;
145
146fn should_draw(segment: u32, style: u32) -> bool {
147 switch(style) {
148 case 0u: { return true; }
149 case 1u: { return (segment % 4u) < 2u; }
150 case 2u: { return (segment % 4u) < 2u; }
151 case 3u: {
152 let m = segment % 6u;
153 return (m < 2u) || (m == 3u);
154 }
155 default: { return true; }
156 }
157}
158
159fn write_vertex(index: u32, pos: vec2<f32>, color: vec4<f32>) {
160 var vertex: VertexRaw;
161 vertex.data[0u] = pos.x;
162 vertex.data[1u] = pos.y;
163 vertex.data[2u] = 0.0;
164 vertex.data[3u] = color.x;
165 vertex.data[4u] = color.y;
166 vertex.data[5u] = color.z;
167 vertex.data[6u] = color.w;
168 vertex.data[7u] = 0.0;
169 vertex.data[8u] = 0.0;
170 vertex.data[9u] = 1.0;
171 vertex.data[10u] = 0.0;
172 vertex.data[11u] = 0.0;
173 out_vertices[index] = vertex;
174}
175
176@compute @workgroup_size(WORKGROUP_SIZE)
177fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
178 if (params.count < 2u) {
179 return;
180 }
181 let segments = params.count - 1u;
182 let idx = gid.x;
183 if (idx >= segments) {
184 return;
185 }
186
187 let p0 = vec2<f32>(f32(buf_x[idx]), f32(buf_y[idx]));
188 let p1 = vec2<f32>(f32(buf_x[idx + 1u]), f32(buf_y[idx + 1u]));
189 let delta = p1 - p0;
190 let len = length(delta);
191 let draw = should_draw(idx, params.line_style) && (len != 0.0);
192 var color = params.color;
193 if (!draw) {
194 color.w = 0.0;
195 }
196
197 let thick = params.thick != 0u;
198 if (!thick) {
199 let base = idx * 2u;
200 write_vertex(base + 0u, p0, color);
201 write_vertex(base + 1u, p1, color);
202 return;
203 }
204
205 if (!draw) {
206 let base = idx * 6u;
207 write_vertex(base + 0u, p0, color);
208 write_vertex(base + 1u, p0, color);
209 write_vertex(base + 2u, p0, color);
210 write_vertex(base + 3u, p0, color);
211 write_vertex(base + 4u, p0, color);
212 write_vertex(base + 5u, p0, color);
213 return;
214 }
215
216 var half_width = params.half_width_data;
217 if (half_width < 0.0001) {
218 half_width = 0.0001;
219 }
220 let dir = normalize(delta);
221 let normal = vec2<f32>(-dir.y, dir.x);
222 let offset = normal * half_width;
223 let v0 = p0 + offset;
224 let v1 = p1 + offset;
225 let v2 = p1 - offset;
226 let v3 = p0 - offset;
227
228 let base = idx * 6u;
229 write_vertex(base + 0u, v0, params.color);
230 write_vertex(base + 1u, v1, params.color);
231 write_vertex(base + 2u, v2, params.color);
232 write_vertex(base + 3u, v0, params.color);
233 write_vertex(base + 4u, v2, params.color);
234 write_vertex(base + 5u, v3, params.color);
235}
236"#;
237
238pub const MARKER_F32: &str = r#"const WORKGROUP_SIZE: u32 = {{WORKGROUP_SIZE}}u;
239
240struct VertexRaw {
241 data: array<f32, 12u>,
242};
243
244struct MarkerParams {
245 color: vec4<f32>,
246 count: u32,
247 size: f32,
248 _pad: vec2<u32>,
249};
250
251@group(0) @binding(0)
252var<storage, read> buf_x: array<f32>;
253
254@group(0) @binding(1)
255var<storage, read> buf_y: array<f32>;
256
257@group(0) @binding(2)
258var<storage, read_write> out_vertices: array<VertexRaw>;
259
260@group(0) @binding(3)
261var<uniform> params: MarkerParams;
262
263@compute @workgroup_size(WORKGROUP_SIZE)
264fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
265 let idx = gid.x;
266 if (idx >= params.count) {
267 return;
268 }
269
270 let px = buf_x[idx];
271 let py = buf_y[idx];
272
273 let base = idx * 6u;
274 let corners = array<vec2<f32>, 6u>(
275 vec2<f32>(-1.0, -1.0),
276 vec2<f32>( 1.0, -1.0),
277 vec2<f32>( 1.0, 1.0),
278 vec2<f32>(-1.0, -1.0),
279 vec2<f32>( 1.0, 1.0),
280 vec2<f32>(-1.0, 1.0)
281 );
282 for (var i: u32 = 0u; i < 6u; i = i + 1u) {
283 var vertex: VertexRaw;
284 vertex.data[0u] = px;
285 vertex.data[1u] = py;
286 vertex.data[2u] = 0.0;
287 vertex.data[3u] = params.color.x;
288 vertex.data[4u] = params.color.y;
289 vertex.data[5u] = params.color.z;
290 vertex.data[6u] = params.color.w;
291 vertex.data[7u] = 0.0;
292 vertex.data[8u] = 0.0;
293 vertex.data[9u] = params.size;
294 vertex.data[10u] = corners[i].x;
295 vertex.data[11u] = corners[i].y;
296 out_vertices[base + i] = vertex;
297 }
298}
299"#;
300
301pub const MARKER_F64: &str = r#"const WORKGROUP_SIZE: u32 = {{WORKGROUP_SIZE}}u;
302
303struct VertexRaw {
304 data: array<f32, 12u>,
305};
306
307struct MarkerParams {
308 color: vec4<f32>,
309 count: u32,
310 size: f32,
311 _pad: vec2<u32>,
312};
313
314@group(0) @binding(0)
315var<storage, read> buf_x: array<f64>;
316
317@group(0) @binding(1)
318var<storage, read> buf_y: array<f64>;
319
320@group(0) @binding(2)
321var<storage, read_write> out_vertices: array<VertexRaw>;
322
323@group(0) @binding(3)
324var<uniform> params: MarkerParams;
325
326@compute @workgroup_size(WORKGROUP_SIZE)
327fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
328 let idx = gid.x;
329 if (idx >= params.count) {
330 return;
331 }
332
333 let px = f32(buf_x[idx]);
334 let py = f32(buf_y[idx]);
335
336 let base = idx * 6u;
337 let corners = array<vec2<f32>, 6u>(
338 vec2<f32>(-1.0, -1.0),
339 vec2<f32>( 1.0, -1.0),
340 vec2<f32>( 1.0, 1.0),
341 vec2<f32>(-1.0, -1.0),
342 vec2<f32>( 1.0, 1.0),
343 vec2<f32>(-1.0, 1.0)
344 );
345 for (var i: u32 = 0u; i < 6u; i = i + 1u) {
346 var vertex: VertexRaw;
347 vertex.data[0u] = px;
348 vertex.data[1u] = py;
349 vertex.data[2u] = 0.0;
350 vertex.data[3u] = params.color.x;
351 vertex.data[4u] = params.color.y;
352 vertex.data[5u] = params.color.z;
353 vertex.data[6u] = params.color.w;
354 vertex.data[7u] = 0.0;
355 vertex.data[8u] = 0.0;
356 vertex.data[9u] = params.size;
357 vertex.data[10u] = corners[i].x;
358 vertex.data[11u] = corners[i].y;
359 out_vertices[base + i] = vertex;
360 }
361}
362"#;