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