glplot 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,889 @@
1
+ # --- SHARED UTILS ---
2
+
3
+ HEATMAP_FUNCS = r"""
4
+ vec3 heatmap_classic(float x) {
5
+ x = clamp(x, 0.0, 1.0);
6
+ return vec3(
7
+ smoothstep(0.0, 0.3, x),
8
+ smoothstep(0.3, 0.6, x),
9
+ smoothstep(0.6, 1.0, x)
10
+ );
11
+ }
12
+
13
+ vec3 heatmap_viridis_like(float x) {
14
+ x = clamp(x, 0.0, 1.0);
15
+ vec3 c0 = vec3(0.267, 0.005, 0.329);
16
+ vec3 c1 = vec3(0.283, 0.141, 0.458);
17
+ vec3 c2 = vec3(0.254, 0.265, 0.530);
18
+ vec3 c3 = vec3(0.207, 0.372, 0.553);
19
+ vec3 c4 = vec3(0.164, 0.471, 0.558);
20
+ vec3 c5 = vec3(0.128, 0.567, 0.551);
21
+ vec3 c6 = vec3(0.135, 0.659, 0.518);
22
+ vec3 c7 = vec3(0.267, 0.749, 0.441);
23
+ vec3 c8 = vec3(0.478, 0.821, 0.318);
24
+ vec3 c9 = vec3(0.741, 0.873, 0.150);
25
+
26
+ if (x < 0.11) return mix(c0, c1, x / 0.11);
27
+ if (x < 0.22) return mix(c1, c2, (x - 0.11) / 0.11);
28
+ if (x < 0.33) return mix(c2, c3, (x - 0.22) / 0.11);
29
+ if (x < 0.44) return mix(c3, c4, (x - 0.33) / 0.11);
30
+ if (x < 0.55) return mix(c4, c5, (x - 0.44) / 0.11);
31
+ if (x < 0.66) return mix(c5, c6, (x - 0.55) / 0.11);
32
+ if (x < 0.77) return mix(c6, c7, (x - 0.66) / 0.11);
33
+ if (x < 0.88) return mix(c7, c8, (x - 0.77) / 0.11);
34
+ return mix(c8, c9, (x - 0.88) / 0.12);
35
+ }
36
+
37
+ vec3 heatmap_plasma_like(float x) {
38
+ x = clamp(x, 0.0, 1.0);
39
+ vec3 c0 = vec3(0.050, 0.030, 0.528);
40
+ vec3 c1 = vec3(0.291, 0.071, 0.718);
41
+ vec3 c2 = vec3(0.507, 0.104, 0.749);
42
+ vec3 c3 = vec3(0.692, 0.165, 0.564);
43
+ vec3 c4 = vec3(0.845, 0.277, 0.388);
44
+ vec3 c5 = vec3(0.954, 0.468, 0.199);
45
+ vec3 c6 = vec3(0.940, 0.975, 0.131);
46
+
47
+ if (x < 0.16) return mix(c0, c1, x / 0.16);
48
+ if (x < 0.32) return mix(c1, c2, (x - 0.16) / 0.16);
49
+ if (x < 0.48) return mix(c2, c3, (x - 0.32) / 0.16);
50
+ if (x < 0.64) return mix(c3, c4, (x - 0.48) / 0.16);
51
+ if (x < 0.80) return mix(c4, c5, (x - 0.64) / 0.16);
52
+ return mix(c5, c6, (x - 0.80) / 0.20);
53
+ }
54
+
55
+ vec3 heatmap_inferno(float x) {
56
+ x = clamp(x, 0.0, 1.0);
57
+ vec3 c0 = vec3(0.000, 0.000, 0.016);
58
+ vec3 c1 = vec3(0.073, 0.038, 0.201);
59
+ vec3 c2 = vec3(0.243, 0.053, 0.404);
60
+ vec3 c3 = vec3(0.449, 0.111, 0.437);
61
+ vec3 c4 = vec3(0.665, 0.177, 0.366);
62
+ vec3 c5 = vec3(0.866, 0.301, 0.228);
63
+ vec3 c6 = vec3(0.976, 0.505, 0.096);
64
+ vec3 c7 = vec3(0.985, 0.768, 0.263);
65
+ vec3 c8 = vec3(0.988, 0.941, 0.729);
66
+
67
+ if (x < 0.125) return mix(c0, c1, x / 0.125);
68
+ if (x < 0.250) return mix(c1, c2, (x - 0.125) / 0.125);
69
+ if (x < 0.375) return mix(c2, c3, (x - 0.250) / 0.125);
70
+ if (x < 0.500) return mix(c3, c4, (x - 0.375) / 0.125);
71
+ if (x < 0.625) return mix(c4, c5, (x - 0.500) / 0.125);
72
+ if (x < 0.750) return mix(c5, c6, (x - 0.625) / 0.125);
73
+ if (x < 0.875) return mix(c6, c7, (x - 0.750) / 0.125);
74
+ return mix(c7, c8, (x - 0.875) / 0.125);
75
+ }
76
+
77
+ vec3 heatmap_turbo(float x) {
78
+ x = clamp(x, 0.0, 1.0);
79
+ const vec4 kL = vec4(0.23, 0.11, 0.32, 1.0);
80
+ const vec4 kH = vec4(0.92, 0.95, 0.64, 1.0);
81
+ const vec3 g0 = vec3(0.12, 0.01, 0.22);
82
+ const vec3 g1 = vec3(0.13, 0.15, 0.48);
83
+ const vec3 g2 = vec3(0.15, 0.65, 0.51);
84
+ const vec3 g3 = vec3(0.85, 0.60, 0.12);
85
+ const vec3 g4 = vec3(0.92, 0.11, 0.43);
86
+
87
+ if (x < 0.25) return mix(g0, g1, x / 0.25);
88
+ if (x < 0.50) return mix(g1, g2, (x - 0.25) / 0.25);
89
+ if (x < 0.75) return mix(g2, g3, (x - 0.50) / 0.25);
90
+ return mix(g3, g4, (x - 0.75) / 0.25);
91
+ }
92
+
93
+ vec3 heatmap_ink_fire(float x) {
94
+ x = clamp(x, 0.0, 1.0);
95
+ vec3 c0 = vec3(1.0, 1.0, 1.0); // White
96
+ vec3 c1 = vec3(1.0, 0.9, 0.2); // Yellow
97
+ vec3 c2 = vec3(1.0, 0.2, 0.1); // Red
98
+ vec3 c3 = vec3(0.4, 0.0, 0.0); // Dark Red
99
+ vec3 c4 = vec3(0.0, 0.0, 0.0); // Black
100
+
101
+ if (x < 0.25) return mix(c0, c1, x / 0.25);
102
+ if (x < 0.50) return mix(c1, c2, (x - 0.25) / 0.25);
103
+ if (x < 0.75) return mix(c2, c3, (x - 0.50) / 0.25);
104
+ return mix(c3, c4, (x - 0.75) / 0.25);
105
+ }
106
+
107
+ vec3 heatmap_magma(float x) {
108
+ x = clamp(x, 0.0, 1.0);
109
+ vec3 c0 = vec3(0.001, 0.000, 0.031);
110
+ vec3 c1 = vec3(0.170, 0.047, 0.360);
111
+ vec3 c2 = vec3(0.447, 0.051, 0.439);
112
+ vec3 c3 = vec3(0.729, 0.160, 0.345);
113
+ vec3 c4 = vec3(0.960, 0.419, 0.231);
114
+ vec3 c5 = vec3(0.988, 0.768, 0.470);
115
+ vec3 c6 = vec3(0.988, 0.988, 0.823);
116
+
117
+ if (x < 0.16) return mix(c0, c1, x / 0.16);
118
+ if (x < 0.32) return mix(c1, c2, (x - 0.16) / 0.16);
119
+ if (x < 0.48) return mix(c2, c3, (x - 0.32) / 0.16);
120
+ if (x < 0.64) return mix(c3, c4, (x - 0.48) / 0.16);
121
+ if (x < 0.80) return mix(c4, c5, (x - 0.64) / 0.16);
122
+ return mix(c5, c6, (x - 0.80) / 0.20);
123
+ }
124
+
125
+ vec3 heatmap_grayscale(float x) {
126
+ return vec3(clamp(x, 0.0, 1.0));
127
+ }
128
+
129
+ vec3 apply_heatmap(int scheme, float x) {
130
+ if (scheme == 1) return heatmap_viridis_like(x);
131
+ if (scheme == 2) return heatmap_plasma_like(x);
132
+ if (scheme == 3) return heatmap_inferno(x);
133
+ if (scheme == 4) return heatmap_turbo(x);
134
+ if (scheme == 5) return heatmap_ink_fire(x);
135
+ if (scheme == 6) return heatmap_magma(x);
136
+ if (scheme == 7) return heatmap_grayscale(x);
137
+ return heatmap_classic(x);
138
+ }
139
+ """
140
+
141
+ DENSITY_SCHEMES = [
142
+ "Classic (B-W-C)",
143
+ "Viridis",
144
+ "Plasma",
145
+ "Inferno",
146
+ "Turbo (Rainbow)",
147
+ "Ink Fire (White BG)",
148
+ "Magma",
149
+ "Grayscale"
150
+ ]
151
+
152
+ # ==============================================================================
153
+ # PASS 1: EXACT RENDERING (Primal Geometry)
154
+ # ==============================================================================
155
+
156
+ # --- LINES ---
157
+
158
+ EXACT_LINES_VS = r"""
159
+ #version 330 core
160
+ layout(location=0) in float a_t;
161
+ layout(location=1) in vec2 a_ab;
162
+ layout(location=2) in vec4 a_col;
163
+
164
+ uniform mat4 u_mvp;
165
+ uniform vec2 u_xrange;
166
+ uniform vec4 u_window;
167
+ uniform int u_use_color;
168
+ uniform float u_alpha;
169
+ uniform int u_enable_subsample;
170
+ uniform float u_keep_prob;
171
+ uniform int u_total_count;
172
+ uniform vec2 u_layer_offset;
173
+
174
+ out vec4 v_col;
175
+ flat out float v_id_norm;
176
+
177
+ void main() {
178
+ float x = mix(u_xrange.x, u_xrange.y, a_t);
179
+ float y = a_ab.x * x + a_ab.y;
180
+ vec2 w = vec2(x, y) + u_layer_offset;
181
+
182
+ gl_Position = u_mvp * vec4(w, 0.0, 1.0);
183
+
184
+ gl_ClipDistance[0] = w.x - u_window.x;
185
+ gl_ClipDistance[1] = u_window.y - w.x;
186
+ gl_ClipDistance[2] = w.y - u_window.z;
187
+ gl_ClipDistance[3] = u_window.w - w.y;
188
+
189
+ float l = u_window.x, r = u_window.y;
190
+ float xmin = u_xrange.x, xmax = u_xrange.y;
191
+ float xA = max(l, xmin);
192
+ float xB = min(r, xmax);
193
+ bool noOverlapX = (xA > xB);
194
+ float yA = a_ab.x * xA + a_ab.y;
195
+ float yB = a_ab.x * xB + a_ab.y;
196
+ float bottom = u_window.z, top = u_window.w;
197
+ bool outsideY = (yA > top && yB > top) || (yA < bottom && yB < bottom);
198
+
199
+ uint id = uint(gl_InstanceID);
200
+ v_id_norm = (u_total_count > 1) ? float(id) / float(u_total_count - 1) : 0.0;
201
+
202
+ id ^= id >> 17; id *= 0xed5ad4bbu; id ^= id >> 11;
203
+ id *= 0xac4c1b51u; id ^= id >> 15; id *= 0x31848babu;
204
+ float rnd = float(id & 0x00FFFFFFu) * (1.0/16777215.0);
205
+ bool drop = (u_enable_subsample == 1) && (rnd > u_keep_prob);
206
+
207
+ if (noOverlapX || outsideY || drop) {
208
+ gl_ClipDistance[0] = -1.0;
209
+ gl_ClipDistance[1] = -1.0;
210
+ gl_ClipDistance[2] = -1.0;
211
+ gl_ClipDistance[3] = -1.0;
212
+ }
213
+
214
+ v_col = (u_use_color == 1) ? a_col : vec4(0.0, 0.0, 0.0, 1.0);
215
+ v_col.a *= u_alpha;
216
+ }
217
+ """
218
+
219
+ WIDE_LINES_INSTANCED_VS = r"""
220
+ #version 330 core
221
+
222
+ layout(location=0) in vec2 a_corner; // (t, side): t in {0,1}, side in {-0.5,+0.5}
223
+ layout(location=1) in vec2 a_ab; // slope, intercept
224
+ layout(location=2) in vec4 a_col; // instanced color
225
+
226
+ uniform vec2 u_xrange;
227
+ uniform vec4 u_window; // l, r, b, t
228
+ uniform vec2 u_ndc_scale;
229
+ uniform vec2 u_ndc_offset;
230
+ uniform vec2 u_viewport_size;
231
+ uniform float u_width;
232
+ uniform float u_alpha;
233
+ uniform int u_use_color;
234
+ uniform float u_keep_prob;
235
+ uniform int u_total_count;
236
+ uniform vec2 u_layer_offset;
237
+
238
+ out vec4 v_col;
239
+ flat out float v_id_norm;
240
+
241
+ void main() {
242
+ uint id = uint(gl_InstanceID);
243
+ v_id_norm = (u_total_count > 1) ? float(id) / float(u_total_count - 1) : 0.0;
244
+
245
+ // Early probabilistic LOD
246
+ uint h = id;
247
+ h ^= h >> 17; h *= 0xed5ad4bbu; h ^= h >> 11;
248
+ h *= 0xac4c1b51u; h ^= h >> 15; h *= 0x31848babu;
249
+ float rnd = float(h & 0x00FFFFFFu) * (1.0 / 16777215.0);
250
+ bool drop = rnd > u_keep_prob;
251
+
252
+ float l = u_window.x;
253
+ float r = u_window.y;
254
+ float b = u_window.z;
255
+ float t = u_window.w;
256
+
257
+ float xmin = u_xrange.x;
258
+ float xmax = u_xrange.y;
259
+
260
+ float xA = max(l, xmin);
261
+ float xB = min(r, xmax);
262
+ bool noOverlapX = (xA > xB);
263
+
264
+ float yA = a_ab.x * xA + a_ab.y;
265
+ float yB = a_ab.x * xB + a_ab.y;
266
+ bool outsideY = (yA > t && yB > t) || (yA < b && yB < b);
267
+
268
+ if (drop || noOverlapX || outsideY) {
269
+ gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
270
+ v_col = vec4(0.0);
271
+ return;
272
+ }
273
+
274
+ float x0 = xmin;
275
+ float x1 = xmax;
276
+ float y0 = a_ab.x * x0 + a_ab.y;
277
+ float y1 = a_ab.x * x1 + a_ab.y;
278
+
279
+ vec2 ndc0 = (vec2(x0, y0) + u_layer_offset) * u_ndc_scale + u_ndc_offset;
280
+ vec2 ndc1 = (vec2(x1, y1) + u_layer_offset) * u_ndc_scale + u_ndc_offset;
281
+
282
+ vec2 dir_px = (ndc1 - ndc0) * (0.5 * u_viewport_size);
283
+ float len2 = dot(dir_px, dir_px);
284
+
285
+ vec2 n_px = (len2 > 1e-12)
286
+ ? normalize(vec2(-dir_px.y, dir_px.x))
287
+ : vec2(0.0, 1.0);
288
+
289
+ vec2 p_ndc = mix(ndc0, ndc1, a_corner.x);
290
+ p_ndc += n_px * ((u_width / u_viewport_size) * a_corner.y);
291
+
292
+ gl_Position = vec4(p_ndc, 0.0, 1.0);
293
+
294
+ v_col = (u_use_color == 1) ? a_col : vec4(0.0, 0.0, 0.0, 1.0);
295
+ v_col.a *= u_alpha;
296
+ }
297
+ """
298
+
299
+ EXACT_LINES_FS = r"""
300
+ #version 330 core
301
+ in vec4 v_col;
302
+ flat in float v_id_norm;
303
+ out vec4 FragColor;
304
+
305
+ uniform int u_use_colormap;
306
+ uniform int u_scheme;
307
+
308
+ """ + HEATMAP_FUNCS + r"""
309
+
310
+ void main() {
311
+ vec4 color = v_col;
312
+ if (u_use_colormap == 1) {
313
+ color.rgb = apply_heatmap(u_scheme, v_id_norm);
314
+ }
315
+ FragColor = color;
316
+ }
317
+ """
318
+
319
+ # --- SCATTERS ---
320
+
321
+ SCATTER_VS = r"""
322
+ #version 330 core
323
+ layout(location=0) in vec2 a_pos;
324
+ layout(location=1) in vec4 a_color;
325
+ uniform mat4 u_mvp;
326
+ uniform float u_size;
327
+ uniform float u_alpha;
328
+ uniform vec2 u_layer_offset;
329
+ out vec4 v_col;
330
+ void main() {
331
+ gl_Position = u_mvp * vec4(a_pos + u_layer_offset, 0.0, 1.0);
332
+ gl_PointSize = u_size;
333
+ v_col = a_color;
334
+ v_col.a *= u_alpha;
335
+ }
336
+ """
337
+
338
+ SCATTER_FS = r"""
339
+ #version 330 core
340
+ in vec4 v_col;
341
+ out vec4 FragColor;
342
+
343
+ uniform int u_outline_enabled;
344
+ uniform vec4 u_outline_color;
345
+ uniform float u_outline_width_px;
346
+ uniform float u_point_size_px;
347
+
348
+ void main() {
349
+ vec2 p = gl_PointCoord - vec2(0.5);
350
+ float r = length(p) * 2.0; // 0 center, ~1 edge
351
+
352
+ if (r > 1.0) discard;
353
+
354
+ float outline_frac = (u_point_size_px > 0.0)
355
+ ? clamp(u_outline_width_px / u_point_size_px, 0.0, 0.49)
356
+ : 0.0;
357
+
358
+ float fill_radius = 1.0 - 2.0 * outline_frac;
359
+
360
+ vec4 col = v_col;
361
+
362
+ if (u_outline_enabled == 1 && r > fill_radius) {
363
+ col.rgb = u_outline_color.rgb;
364
+ col.a *= u_outline_color.a;
365
+ }
366
+
367
+ // Soft edge antialiasing
368
+ float feather = fwidth(r) * 1.5;
369
+ col.a *= 1.0 - smoothstep(1.0 - feather, 1.0, r);
370
+
371
+ FragColor = col;
372
+ }
373
+ """
374
+
375
+ # --- STRIPS ---
376
+
377
+ STRIP_VS = r"""
378
+ #version 330 core
379
+ layout(location=0) in vec2 a_pos;
380
+ uniform mat4 u_mvp;
381
+ uniform vec4 u_color;
382
+ uniform float u_alpha;
383
+ uniform vec2 u_layer_offset;
384
+ out vec4 v_col;
385
+ void main() {
386
+ gl_Position = u_mvp * vec4(a_pos + u_layer_offset, 0.0, 1.0);
387
+ v_col = u_color;
388
+ v_col.a *= u_alpha;
389
+ }
390
+ """
391
+
392
+ STRIP_FS = r"""
393
+ #version 330 core
394
+ in vec4 v_col;
395
+ out vec4 FragColor;
396
+ void main() {
397
+ FragColor = v_col;
398
+ }
399
+ """
400
+
401
+ # --- WIDE LINES (Quad Expansion) ---
402
+
403
+ WIDE_LINE_VS = r"""
404
+ #version 330 core
405
+ layout(location=0) in vec2 a_pos;
406
+ layout(location=1) in vec2 a_next;
407
+ layout(location=2) in float a_side; // -1.0 or 1.0
408
+
409
+ uniform mat4 u_mvp;
410
+ uniform vec2 u_viewport_size;
411
+ uniform float u_width;
412
+ uniform vec4 u_color;
413
+ uniform float u_alpha;
414
+
415
+ out vec4 v_col;
416
+
417
+ void main() {
418
+ float width = max(1.0, u_width);
419
+
420
+ vec4 p1 = u_mvp * vec4(a_pos, 0.0, 1.0);
421
+ vec4 p2 = u_mvp * vec4(a_next, 0.0, 1.0);
422
+
423
+ vec2 ndc1 = p1.xy / p1.w;
424
+ vec2 ndc2 = p2.xy / p2.w;
425
+
426
+ // Direction and normal in screen space
427
+ vec2 dir = normalize((ndc2 - ndc1) * u_viewport_size);
428
+ vec2 norm = vec2(-dir.y, dir.x);
429
+
430
+ // Offset in NDC space
431
+ vec2 offset = norm * (width / u_viewport_size) * a_side;
432
+
433
+ // Determine if this vertex belongs to the start or end of the segment
434
+ // We assume 4 vertices per segment (0,1 at start; 2,3 at end)
435
+ float is_end = float(gl_VertexID % 4 >= 2);
436
+ vec4 p = mix(p1, p2, is_end);
437
+
438
+ p.xy += offset * p.w;
439
+
440
+ gl_Position = p;
441
+ v_col = u_color;
442
+ v_col.a *= u_alpha;
443
+ }
444
+ """
445
+
446
+ WIDE_LINE_FS = r"""
447
+ #version 330 core
448
+ in vec4 v_col;
449
+ out vec4 FragColor;
450
+ void main() {
451
+ FragColor = v_col;
452
+ }
453
+ """
454
+
455
+ # --- INSTANCED SEGMENTS (GPU Expansion) ---
456
+
457
+ WIDE_SEGMENT_INSTANCED_VS = r"""
458
+ #version 330 core
459
+
460
+ layout(location=0) in vec2 a_corner; // (t, side): t in {0,1}, side in {-0.5,+0.5}
461
+ layout(location=1) in vec2 i_p0; // segment start
462
+ layout(location=2) in vec2 i_p1; // segment end
463
+
464
+ uniform vec2 u_ndc_scale; // ( 2/(r-l), 2/(t-b) )
465
+ uniform vec2 u_ndc_offset; // (-(r+l)/(r-l), -(t+b)/(t-b))
466
+ uniform vec2 u_viewport_size; // framebuffer size in pixels
467
+ uniform vec4 u_color;
468
+ uniform float u_alpha;
469
+ uniform float u_width;
470
+ uniform float u_id_norm;
471
+ uniform vec2 u_layer_offset;
472
+
473
+ out vec4 v_col;
474
+ flat out float v_id_norm;
475
+
476
+ void main() {
477
+ vec2 ndc0 = (i_p0 + u_layer_offset) * u_ndc_scale + u_ndc_offset;
478
+ vec2 ndc1 = (i_p1 + u_layer_offset) * u_ndc_scale + u_ndc_offset;
479
+
480
+ // Convert NDC delta to pixels
481
+ vec2 dir_px = (ndc1 - ndc0) * (0.5 * u_viewport_size);
482
+ float len2 = dot(dir_px, dir_px);
483
+
484
+ vec2 n_px = (len2 > 1e-12)
485
+ ? normalize(vec2(-dir_px.y, dir_px.x))
486
+ : vec2(0.0, 1.0);
487
+
488
+ vec2 p_ndc = mix(ndc0, ndc1, a_corner.x);
489
+
490
+ // u_width is full width; offset from centerline is ±0.5*u_width
491
+ vec2 offset_ndc = n_px * (u_width / u_viewport_size) * a_corner.y;
492
+ p_ndc += offset_ndc;
493
+
494
+ gl_Position = vec4(p_ndc, 0.0, 1.0);
495
+
496
+ v_col = u_color;
497
+ v_col.a *= u_alpha;
498
+ v_id_norm = u_id_norm;
499
+ }
500
+ """
501
+
502
+ WIDE_SEGMENT_INSTANCED_FS = r"""
503
+ #version 330 core
504
+ in vec4 v_col;
505
+ flat in float v_id_norm;
506
+ out vec4 FragColor;
507
+
508
+ uniform int u_use_colormap;
509
+ uniform int u_scheme;
510
+
511
+ """ + HEATMAP_FUNCS + r"""
512
+
513
+ void main() {
514
+ vec4 color = v_col;
515
+ if (u_use_colormap == 1) {
516
+ color.rgb = apply_heatmap(u_scheme, v_id_norm);
517
+ }
518
+ FragColor = color;
519
+ }
520
+ """
521
+
522
+ WIDE_SEGMENT_DENSITY_FS = r"""
523
+ #version 330 core
524
+ in vec4 v_col;
525
+ layout(location=0) out float FragValue;
526
+
527
+ uniform int u_density_weighted;
528
+
529
+ void main() {
530
+ FragValue = (u_density_weighted == 1) ? v_col.a : 1.0;
531
+ }
532
+ """
533
+
534
+ # --- PATCHES ---
535
+
536
+ PATCH_VS = r"""
537
+ #version 330 core
538
+ layout(location=0) in vec2 a_pos;
539
+ uniform mat4 u_mvp;
540
+ uniform vec4 u_color;
541
+ uniform float u_alpha;
542
+ uniform vec2 u_layer_offset;
543
+ out vec4 v_col;
544
+ void main() {
545
+ gl_Position = u_mvp * vec4(a_pos + u_layer_offset, 0.0, 1.0);
546
+ v_col = u_color;
547
+ v_col.a *= u_alpha;
548
+ }
549
+ """
550
+
551
+ PATCH_FS = r"""
552
+ #version 330 core
553
+ in vec4 v_col;
554
+ out vec4 FragColor;
555
+ void main() {
556
+ FragColor = v_col;
557
+ }
558
+ """
559
+
560
+ # ==============================================================================
561
+ # PASS 2: DENSITY ACCUMULATION
562
+ # ==============================================================================
563
+
564
+ DENSITY_ACCUM_FS = r"""
565
+ #version 330 core
566
+ in vec4 v_col;
567
+ layout(location=0) out float FragValue;
568
+
569
+ uniform int u_density_weighted;
570
+
571
+ void main() {
572
+ FragValue = (u_density_weighted == 1) ? v_col.a : 1.0;
573
+ }
574
+ """
575
+
576
+ DENSITY_POINTS_VS = r"""
577
+ #version 330 core
578
+ layout(location=0) in vec2 a_pos;
579
+ layout(location=1) in vec4 a_col;
580
+ uniform mat4 u_mvp;
581
+ uniform float u_size;
582
+ uniform float u_alpha;
583
+ uniform vec2 u_layer_offset;
584
+ out float v_alpha;
585
+ void main() {
586
+ gl_Position = u_mvp * vec4(a_pos + u_layer_offset, 0.0, 1.0);
587
+ gl_PointSize = u_size;
588
+ v_alpha = a_col.a * u_alpha;
589
+ }
590
+ """
591
+
592
+ DENSITY_POINTS_FS = r"""
593
+ #version 330 core
594
+ in float v_alpha;
595
+ layout(location=0) out float FragValue;
596
+ void main() {
597
+ vec2 coord = gl_PointCoord - vec2(0.5);
598
+ if (dot(coord, coord) > 0.25) discard;
599
+ FragValue = v_alpha;
600
+ }
601
+ """
602
+
603
+ DENSITY_RESOLVE_FS = r"""
604
+ #version 330 core
605
+ #define log10(x) (log(x) / log(10.0))
606
+
607
+ in vec2 v_uv;
608
+ out vec4 FragColor;
609
+
610
+ uniform sampler2D u_tex;
611
+ uniform float u_gain;
612
+ uniform float u_log_scale;
613
+ uniform int u_scheme;
614
+
615
+ """ + HEATMAP_FUNCS + r"""
616
+
617
+ void main() {
618
+ float val = texture(u_tex, v_uv).r;
619
+ if (val <= 0.0) discard;
620
+
621
+ // Normalize log value
622
+ float norm = clamp(log10(1.0 + val * u_gain) / u_log_scale, 0.0, 1.0);
623
+ FragColor = vec4(apply_heatmap(u_scheme, norm), 1.0);
624
+ }
625
+ """
626
+
627
+ # ==============================================================================
628
+ # PASS 3: PICKING & INTERACTION
629
+ # ==============================================================================
630
+
631
+ PICKING_LINES_VS = r"""
632
+ #version 330 core
633
+ layout(location=0) in float a_t;
634
+ layout(location=1) in vec2 a_ab;
635
+
636
+ uniform mat4 u_mvp;
637
+ uniform vec2 u_xrange;
638
+ uniform vec4 u_window;
639
+ uniform vec2 u_layer_offset;
640
+ uniform int u_id_offset;
641
+
642
+ flat out int v_id;
643
+
644
+ void main() {
645
+ float x = mix(u_xrange.x, u_xrange.y, a_t);
646
+ float y = a_ab.x * x + a_ab.y;
647
+ vec2 w = vec2(x, y) + u_layer_offset;
648
+
649
+ gl_Position = u_mvp * vec4(w, 0.0, 1.0);
650
+
651
+ gl_ClipDistance[0] = w.x - u_window.x;
652
+ gl_ClipDistance[1] = u_window.y - w.x;
653
+ gl_ClipDistance[2] = w.y - u_window.z;
654
+ gl_ClipDistance[3] = u_window.w - w.y;
655
+
656
+ v_id = u_id_offset + gl_InstanceID + 1;
657
+ }
658
+ """
659
+
660
+ PICKING_LINES_FS = r"""
661
+ #version 330 core
662
+ flat in int v_id;
663
+ layout(location=0) out int FragID;
664
+ void main() {
665
+ FragID = v_id;
666
+ }
667
+ """
668
+
669
+ PICKING_SCATTER_VS = r"""
670
+ #version 330 core
671
+ layout(location=0) in vec2 a_pos;
672
+
673
+ uniform mat4 u_mvp;
674
+ uniform float u_size;
675
+ uniform int u_id_offset;
676
+ uniform vec2 u_layer_offset;
677
+
678
+ flat out int v_id;
679
+
680
+ void main() {
681
+ gl_Position = u_mvp * vec4(a_pos + u_layer_offset, 0.0, 1.0);
682
+ gl_PointSize = u_size;
683
+ v_id = u_id_offset + gl_VertexID + 1;
684
+ }
685
+ """
686
+
687
+ PICKING_SCATTER_FS = r"""
688
+ #version 330 core
689
+ flat in int v_id;
690
+ layout(location=0) out int FragID;
691
+
692
+ void main() {
693
+ vec2 coord = gl_PointCoord - vec2(0.5);
694
+ if (dot(coord, coord) > 0.25) discard;
695
+ FragID = v_id;
696
+ }
697
+ """
698
+
699
+ PICKING_STRIP_VS = r"""
700
+ #version 330 core
701
+ layout(location=0) in vec2 a_pos;
702
+
703
+ uniform mat4 u_mvp;
704
+ uniform int u_id;
705
+ uniform vec2 u_layer_offset;
706
+
707
+ flat out int v_id;
708
+
709
+ void main() {
710
+ gl_Position = u_mvp * vec4(a_pos + u_layer_offset, 0.0, 1.0);
711
+ v_id = u_id;
712
+ }
713
+ """
714
+
715
+ PICKING_STRIP_FS = r"""
716
+ #version 330 core
717
+ flat in int v_id;
718
+ layout(location=0) out int FragID;
719
+ void main() {
720
+ FragID = v_id;
721
+ }
722
+ """
723
+
724
+ PICKING_PATCH_VS = r"""
725
+ #version 330 core
726
+ layout(location=0) in vec2 a_pos;
727
+ uniform mat4 u_mvp;
728
+ uniform int u_id;
729
+ uniform vec2 u_layer_offset;
730
+ flat out int v_id;
731
+ void main() {
732
+ gl_Position = u_mvp * vec4(a_pos + u_layer_offset, 0.0, 1.0);
733
+ v_id = u_id;
734
+ }
735
+ """
736
+
737
+ PICKING_PATCH_FS = r"""
738
+ #version 330 core
739
+ flat in int v_id;
740
+ layout(location=0) out int FragID;
741
+ void main() {
742
+ FragID = v_id;
743
+ }
744
+ """
745
+
746
+ INTERACTION_FULLSCREEN_VS = r"""
747
+ #version 330 core
748
+ out vec2 v_uv;
749
+ const vec2 verts[4] = vec2[4](
750
+ vec2(-1.0, -1.0), vec2( 1.0, -1.0),
751
+ vec2(-1.0, 1.0), vec2( 1.0, 1.0)
752
+ );
753
+ void main() {
754
+ gl_Position = vec4(verts[gl_VertexID], 0.0, 1.0);
755
+ v_uv = verts[gl_VertexID] * 0.5 + 0.5;
756
+ }
757
+ """
758
+
759
+ CACHE_IMPOSTOR_FS = r"""
760
+ #version 330 core
761
+ in vec2 v_uv;
762
+ out vec4 FragColor;
763
+
764
+ uniform sampler2D u_tex;
765
+ uniform vec4 u_cache_window;
766
+ uniform vec4 u_cur_window;
767
+
768
+ void main() {
769
+ float wx = mix(u_cur_window.x, u_cur_window.y, v_uv.x);
770
+ float wy = mix(u_cur_window.z, u_cur_window.w, v_uv.y);
771
+
772
+ float cache_u = (wx - u_cache_window.x) / (u_cache_window.y - u_cache_window.x);
773
+ float cache_v = (wy - u_cache_window.z) / (u_cache_window.w - u_cache_window.z);
774
+
775
+ cache_u = clamp(cache_u, 0.0, 1.0);
776
+ cache_v = clamp(cache_v, 0.0, 1.0);
777
+ FragColor = texture(u_tex, vec2(cache_u, cache_v));
778
+ }
779
+ """
780
+
781
+ # ==============================================================================
782
+ # PASS 4: POST-PROCESSING
783
+ # ==============================================================================
784
+
785
+ POST_FX_VS = r"""
786
+ #version 330 core
787
+ out vec2 v_uv;
788
+
789
+ const vec2 verts[4] = vec2[4](
790
+ vec2(-1.0, -1.0),
791
+ vec2( 1.0, -1.0),
792
+ vec2(-1.0, 1.0),
793
+ vec2( 1.0, 1.0)
794
+ );
795
+
796
+ void main() {
797
+ vec2 p = verts[gl_VertexID];
798
+ v_uv = p * 0.5 + 0.5;
799
+ gl_Position = vec4(p, 0.0, 1.0);
800
+ }
801
+ """
802
+
803
+ GRADIENT_BG_FS = r"""
804
+ #version 330 core
805
+ in vec2 v_uv;
806
+ uniform vec3 u_top_color;
807
+ uniform vec3 u_bottom_color;
808
+ layout(location=0) out vec4 FragColor;
809
+
810
+ void main() {
811
+ FragColor = vec4(mix(u_bottom_color, u_top_color, v_uv.y), 1.0);
812
+ }
813
+ """
814
+
815
+ BLOOM_EXTRACT_FS = r"""
816
+ #version 330 core
817
+ in vec2 v_uv;
818
+ uniform sampler2D u_tex;
819
+ uniform float u_threshold;
820
+ layout(location=0) out vec4 FragColor;
821
+
822
+ void main() {
823
+ vec4 color = texture(u_tex, v_uv);
824
+ float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
825
+ if (brightness > u_threshold) {
826
+ FragColor = color;
827
+ } else {
828
+ FragColor = vec4(0.0, 0.0, 0.0, 1.0);
829
+ }
830
+ }
831
+ """
832
+
833
+ GAUSSIAN_BLUR_FS = r"""
834
+ #version 330 core
835
+ in vec2 v_uv;
836
+ uniform sampler2D u_tex;
837
+ uniform int u_horizontal;
838
+ uniform float u_radius;
839
+ layout(location=0) out vec4 FragColor;
840
+
841
+ void main() {
842
+ float weight[5] = float[](0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);
843
+ vec2 tex_offset = 1.0 / textureSize(u_tex, 0);
844
+ vec3 result = texture(u_tex, v_uv).rgb * weight[0];
845
+
846
+ if(u_horizontal == 1) {
847
+ for(int i = 1; i < 5; ++i) {
848
+ result += texture(u_tex, v_uv + vec2(tex_offset.x * float(i) * u_radius, 0.0)).rgb * weight[i];
849
+ result += texture(u_tex, v_uv - vec2(tex_offset.x * float(i) * u_radius, 0.0)).rgb * weight[i];
850
+ }
851
+ } else {
852
+ for(int i = 1; i < 5; ++i) {
853
+ result += texture(u_tex, v_uv + vec2(0.0, tex_offset.y * float(i) * u_radius)).rgb * weight[i];
854
+ result += texture(u_tex, v_uv - vec2(0.0, tex_offset.y * float(i) * u_radius)).rgb * weight[i];
855
+ }
856
+ }
857
+ FragColor = vec4(result, 1.0);
858
+ }
859
+ """
860
+
861
+ POST_COMPOSITE_FS = r"""
862
+ #version 330 core
863
+ in vec2 v_uv;
864
+ uniform sampler2D u_scene_tex;
865
+ uniform sampler2D u_bloom_tex;
866
+
867
+ uniform int u_bloom_enabled;
868
+ uniform float u_bloom_intensity;
869
+
870
+ layout(location=0) out vec4 FragColor;
871
+
872
+ void main() {
873
+ vec3 hdr_scene = texture(u_scene_tex, v_uv).rgb;
874
+ vec3 bloom = vec3(0.0);
875
+
876
+ if (u_bloom_enabled == 1) {
877
+ bloom = texture(u_bloom_tex, v_uv).rgb * u_bloom_intensity;
878
+ }
879
+
880
+ vec3 color = hdr_scene + bloom;
881
+
882
+ // HDR Tone mapping if bloom is present
883
+ if (u_bloom_enabled == 1) {
884
+ color = color / (color + vec3(1.0));
885
+ }
886
+
887
+ FragColor = vec4(color, 1.0);
888
+ }
889
+ """