Skip to main content

viewport_lib/resources/material/
colourmap_data.rs

1/// Built-in colourmap LUT data (256 RGBA samples each).
2///
3/// Each function returns a `[[u8; 4]; 256]` array suitable for uploading to a
4/// 256x1 GPU texture.  All values are in linear (non-sRGB) space to match the
5/// `Rgba8Unorm` texture format used by the LUT sampler.
6
7// ---------------------------------------------------------------------------
8// Helpers
9// ---------------------------------------------------------------------------
10
11#[inline]
12fn clamp01(x: f32) -> f32 {
13    x.clamp(0.0, 1.0)
14}
15
16#[inline]
17fn to_u8(x: f32) -> u8 {
18    (clamp01(x) * 255.0 + 0.5) as u8
19}
20
21// ---------------------------------------------------------------------------
22// Greyscale: linear ramp black -> white
23// ---------------------------------------------------------------------------
24
25/// Linear greyscale ramp from black (index 0) to white (index 255).
26pub fn greyscale_rgba() -> [[u8; 4]; 256] {
27    let mut lut = [[0u8; 4]; 256];
28    for i in 0..256 {
29        let v = i as u8;
30        lut[i] = [v, v, v, 255];
31    }
32    lut
33}
34
35// ---------------------------------------------------------------------------
36// Viridis: Smith 2015 polynomial approximation
37// ---------------------------------------------------------------------------
38
39/// Viridis colourmap : perceptually uniform, colourblind-friendly.
40///
41/// Uses the Smith 2015 polynomial approximation.
42pub fn viridis_rgba() -> [[u8; 4]; 256] {
43    let mut lut = [[0u8; 4]; 256];
44    for i in 0..256 {
45        let t = i as f32 / 255.0;
46        // Degree-6 polynomial approximation (Zucker/Smith coefficients).
47        // Range: dark purple (t=0) -> blue -> teal -> green -> yellow (t=1).
48        let r = 0.277_727_33
49            + t * (0.105_093_04
50                + t * (-0.330_861_83
51                    + t * (-4.634_230_5
52                        + t * (6.228_269_9 + t * (4.776_385_0 - t * 5.435_455_9)))));
53        let g = 0.005_407_345
54            + t * (1.404_613_5
55                + t * (0.214_847_56
56                    + t * (-5.799_101_0 + t * (14.179_933 + t * (-13.745_145 + t * 4.645_852_6)))));
57        let b = 0.334_099_81
58            + t * (1.384_590_2
59                + t * (0.095_095_16
60                    + t * (-19.332_441 + t * (56.690_552 + t * (-65.353_033 + t * 26.312_435)))));
61        lut[i] = [to_u8(r), to_u8(g), to_u8(b), 255];
62    }
63    lut
64}
65
66// ---------------------------------------------------------------------------
67// Plasma: polynomial approximation
68// ---------------------------------------------------------------------------
69
70/// Plasma colourmap : perceptually uniform, colourblind-friendly.
71///
72/// Uses a polynomial approximation of the Matplotlib plasma colourmap.
73pub fn plasma_rgba() -> [[u8; 4]; 256] {
74    let mut lut = [[0u8; 4]; 256];
75    for i in 0..256 {
76        let t = i as f32 / 255.0;
77        // Degree-6 polynomial approximation (Zucker/Kall coefficients).
78        // Range: dark blue (t=0) -> pink (t=0.5) -> orange -> yellow (t=1).
79        let r = 0.058_732_344
80            + t * (2.176_514_6
81                + t * (-2.689_460_5
82                    + t * (6.130_348_3 + t * (-11.107_436 + t * (10.023_066 - t * 3.658_713_8)))));
83        let g = 0.023_336_709
84            + t * (0.238_383_42
85                + t * (-7.455_851
86                    + t * (42.346_188 + t * (-82.666_31 + t * (71.413_62 - t * 22.931_534)))));
87        let b = 0.543_340_18
88            + t * (0.753_960_46
89                + t * (3.110_800
90                    + t * (-28.518_854 + t * (60.139_847 + t * (-54.072_186 + t * 18.191_908)))));
91        lut[i] = [to_u8(r), to_u8(g), to_u8(b), 255];
92    }
93    lut
94}
95
96// ---------------------------------------------------------------------------
97// Coolwarm: diverging blue -> white -> red (cubic Hermite)
98// ---------------------------------------------------------------------------
99
100/// Diverging coolwarm colourmap: blue at t=0, white at t=0.5, red at t=1.
101pub fn coolwarm_rgba() -> [[u8; 4]; 256] {
102    let mut lut = [[0u8; 4]; 256];
103
104    // Control points in linear [0,1] space.
105    let cold = [59.0 / 255.0_f32, 76.0 / 255.0, 192.0 / 255.0]; // blue
106    let mid = [220.0 / 255.0_f32, 220.0 / 255.0, 220.0 / 255.0]; // near-white
107    let warm = [180.0 / 255.0_f32, 4.0 / 255.0, 38.0 / 255.0]; // red
108
109    for i in 0..256 {
110        let t = i as f32 / 255.0;
111        // Piecewise smooth cubic Hermite blend across two halves.
112        let (r, g, b) = if t <= 0.5 {
113            let s = t * 2.0; // [0,1] in the cold half
114            let h = s * s * (3.0 - 2.0 * s); // smoothstep
115            (
116                cold[0] + h * (mid[0] - cold[0]),
117                cold[1] + h * (mid[1] - cold[1]),
118                cold[2] + h * (mid[2] - cold[2]),
119            )
120        } else {
121            let s = (t - 0.5) * 2.0; // [0,1] in the warm half
122            let h = s * s * (3.0 - 2.0 * s);
123            (
124                mid[0] + h * (warm[0] - mid[0]),
125                mid[1] + h * (warm[1] - mid[1]),
126                mid[2] + h * (warm[2] - mid[2]),
127            )
128        };
129        lut[i] = [to_u8(r), to_u8(g), to_u8(b), 255];
130    }
131    lut
132}
133
134// ---------------------------------------------------------------------------
135// Rainbow: HSV hue sweep 240 deg (blue) -> 0 deg (red) at full saturation/value
136// ---------------------------------------------------------------------------
137
138/// Rainbow colourmap: HSV hue sweep from 240 deg (blue) at t=0 to 0 deg (red) at t=1.
139pub fn rainbow_rgba() -> [[u8; 4]; 256] {
140    let mut lut = [[0u8; 4]; 256];
141    for i in 0..256 {
142        let t = i as f32 / 255.0;
143        // Hue sweeps from 240 deg down to 0 deg as t goes from 0 to 1.
144        let hue = 240.0 * (1.0 - t); // degrees
145        let (r, g, b) = hsv_to_rgb(hue, 1.0, 1.0);
146        lut[i] = [to_u8(r), to_u8(g), to_u8(b), 255];
147    }
148    lut
149}
150
151/// Convert HSV (hue in degrees [0,360), saturation [0,1], value [0,1]) to RGB.
152fn hsv_to_rgb(h: f32, s: f32, v: f32) -> (f32, f32, f32) {
153    if s == 0.0 {
154        return (v, v, v);
155    }
156    let h = h % 360.0;
157    let sector = (h / 60.0).floor() as i32;
158    let frac = h / 60.0 - sector as f32;
159    let p = v * (1.0 - s);
160    let q = v * (1.0 - s * frac);
161    let t = v * (1.0 - s * (1.0 - frac));
162    match sector {
163        0 => (v, t, p),
164        1 => (q, v, p),
165        2 => (p, v, t),
166        3 => (p, q, v),
167        4 => (t, p, v),
168        _ => (v, p, q),
169    }
170}
171
172// ---------------------------------------------------------------------------
173// Magma: exact 256-sample LUT sampled from matplotlib
174// ---------------------------------------------------------------------------
175
176/// Magma colourmap : perceptually uniform. Black/purple -> orange -> near-white.
177pub fn magma_rgba() -> [[u8; 4]; 256] {
178    [
179        [0, 0, 4, 255],
180        [1, 0, 5, 255],
181        [1, 1, 6, 255],
182        [1, 1, 8, 255],
183        [2, 1, 9, 255],
184        [2, 2, 11, 255],
185        [2, 2, 13, 255],
186        [3, 3, 15, 255],
187        [3, 3, 18, 255],
188        [4, 4, 20, 255],
189        [5, 4, 22, 255],
190        [6, 5, 24, 255],
191        [6, 5, 26, 255],
192        [7, 6, 28, 255],
193        [8, 7, 30, 255],
194        [9, 7, 32, 255],
195        [10, 8, 34, 255],
196        [11, 9, 36, 255],
197        [12, 9, 38, 255],
198        [13, 10, 41, 255],
199        [14, 11, 43, 255],
200        [16, 11, 45, 255],
201        [17, 12, 47, 255],
202        [18, 13, 49, 255],
203        [19, 13, 52, 255],
204        [20, 14, 54, 255],
205        [21, 14, 56, 255],
206        [22, 15, 59, 255],
207        [24, 15, 61, 255],
208        [25, 16, 63, 255],
209        [26, 16, 66, 255],
210        [28, 16, 68, 255],
211        [29, 17, 71, 255],
212        [30, 17, 73, 255],
213        [32, 17, 75, 255],
214        [33, 17, 78, 255],
215        [34, 17, 80, 255],
216        [36, 18, 83, 255],
217        [37, 18, 85, 255],
218        [39, 18, 88, 255],
219        [41, 17, 90, 255],
220        [42, 17, 92, 255],
221        [44, 17, 95, 255],
222        [45, 17, 97, 255],
223        [47, 17, 99, 255],
224        [49, 17, 101, 255],
225        [51, 16, 103, 255],
226        [52, 16, 105, 255],
227        [54, 16, 107, 255],
228        [56, 16, 108, 255],
229        [57, 15, 110, 255],
230        [59, 15, 112, 255],
231        [61, 15, 113, 255],
232        [63, 15, 114, 255],
233        [64, 15, 116, 255],
234        [66, 15, 117, 255],
235        [68, 15, 118, 255],
236        [69, 16, 119, 255],
237        [71, 16, 120, 255],
238        [73, 16, 120, 255],
239        [74, 16, 121, 255],
240        [76, 17, 122, 255],
241        [78, 17, 123, 255],
242        [79, 18, 123, 255],
243        [81, 18, 124, 255],
244        [82, 19, 124, 255],
245        [84, 19, 125, 255],
246        [86, 20, 125, 255],
247        [87, 21, 126, 255],
248        [89, 21, 126, 255],
249        [90, 22, 126, 255],
250        [92, 22, 127, 255],
251        [93, 23, 127, 255],
252        [95, 24, 127, 255],
253        [96, 24, 128, 255],
254        [98, 25, 128, 255],
255        [100, 26, 128, 255],
256        [101, 26, 128, 255],
257        [103, 27, 128, 255],
258        [104, 28, 129, 255],
259        [106, 28, 129, 255],
260        [107, 29, 129, 255],
261        [109, 29, 129, 255],
262        [110, 30, 129, 255],
263        [112, 31, 129, 255],
264        [114, 31, 129, 255],
265        [115, 32, 129, 255],
266        [117, 33, 129, 255],
267        [118, 33, 129, 255],
268        [120, 34, 129, 255],
269        [121, 34, 130, 255],
270        [123, 35, 130, 255],
271        [124, 35, 130, 255],
272        [126, 36, 130, 255],
273        [128, 37, 130, 255],
274        [129, 37, 129, 255],
275        [131, 38, 129, 255],
276        [132, 38, 129, 255],
277        [134, 39, 129, 255],
278        [136, 39, 129, 255],
279        [137, 40, 129, 255],
280        [139, 41, 129, 255],
281        [140, 41, 129, 255],
282        [142, 42, 129, 255],
283        [144, 42, 129, 255],
284        [145, 43, 129, 255],
285        [147, 43, 128, 255],
286        [148, 44, 128, 255],
287        [150, 44, 128, 255],
288        [152, 45, 128, 255],
289        [153, 45, 128, 255],
290        [155, 46, 127, 255],
291        [156, 46, 127, 255],
292        [158, 47, 127, 255],
293        [160, 47, 127, 255],
294        [161, 48, 126, 255],
295        [163, 48, 126, 255],
296        [165, 49, 126, 255],
297        [166, 49, 125, 255],
298        [168, 50, 125, 255],
299        [170, 51, 125, 255],
300        [171, 51, 124, 255],
301        [173, 52, 124, 255],
302        [174, 52, 123, 255],
303        [176, 53, 123, 255],
304        [178, 53, 123, 255],
305        [179, 54, 122, 255],
306        [181, 54, 122, 255],
307        [183, 55, 121, 255],
308        [184, 55, 121, 255],
309        [186, 56, 120, 255],
310        [188, 57, 120, 255],
311        [189, 57, 119, 255],
312        [191, 58, 119, 255],
313        [192, 58, 118, 255],
314        [194, 59, 117, 255],
315        [196, 60, 117, 255],
316        [197, 60, 116, 255],
317        [199, 61, 115, 255],
318        [200, 62, 115, 255],
319        [202, 62, 114, 255],
320        [204, 63, 113, 255],
321        [205, 64, 113, 255],
322        [207, 64, 112, 255],
323        [208, 65, 111, 255],
324        [210, 66, 111, 255],
325        [211, 67, 110, 255],
326        [213, 68, 109, 255],
327        [214, 69, 108, 255],
328        [216, 69, 108, 255],
329        [217, 70, 107, 255],
330        [219, 71, 106, 255],
331        [220, 72, 105, 255],
332        [222, 73, 104, 255],
333        [223, 74, 104, 255],
334        [224, 76, 103, 255],
335        [226, 77, 102, 255],
336        [227, 78, 101, 255],
337        [228, 79, 100, 255],
338        [229, 80, 100, 255],
339        [231, 82, 99, 255],
340        [232, 83, 98, 255],
341        [233, 84, 98, 255],
342        [234, 86, 97, 255],
343        [235, 87, 96, 255],
344        [236, 88, 96, 255],
345        [237, 90, 95, 255],
346        [238, 91, 94, 255],
347        [239, 93, 94, 255],
348        [240, 95, 94, 255],
349        [241, 96, 93, 255],
350        [242, 98, 93, 255],
351        [242, 100, 92, 255],
352        [243, 101, 92, 255],
353        [244, 103, 92, 255],
354        [244, 105, 92, 255],
355        [245, 107, 92, 255],
356        [246, 108, 92, 255],
357        [246, 110, 92, 255],
358        [247, 112, 92, 255],
359        [247, 114, 92, 255],
360        [248, 116, 92, 255],
361        [248, 118, 92, 255],
362        [249, 120, 93, 255],
363        [249, 121, 93, 255],
364        [249, 123, 93, 255],
365        [250, 125, 94, 255],
366        [250, 127, 94, 255],
367        [250, 129, 95, 255],
368        [251, 131, 95, 255],
369        [251, 133, 96, 255],
370        [251, 135, 97, 255],
371        [252, 137, 97, 255],
372        [252, 138, 98, 255],
373        [252, 140, 99, 255],
374        [252, 142, 100, 255],
375        [252, 144, 101, 255],
376        [253, 146, 102, 255],
377        [253, 148, 103, 255],
378        [253, 150, 104, 255],
379        [253, 152, 105, 255],
380        [253, 154, 106, 255],
381        [253, 155, 107, 255],
382        [254, 157, 108, 255],
383        [254, 159, 109, 255],
384        [254, 161, 110, 255],
385        [254, 163, 111, 255],
386        [254, 165, 113, 255],
387        [254, 167, 114, 255],
388        [254, 169, 115, 255],
389        [254, 170, 116, 255],
390        [254, 172, 118, 255],
391        [254, 174, 119, 255],
392        [254, 176, 120, 255],
393        [254, 178, 122, 255],
394        [254, 180, 123, 255],
395        [254, 182, 124, 255],
396        [254, 183, 126, 255],
397        [254, 185, 127, 255],
398        [254, 187, 129, 255],
399        [254, 189, 130, 255],
400        [254, 191, 132, 255],
401        [254, 193, 133, 255],
402        [254, 194, 135, 255],
403        [254, 196, 136, 255],
404        [254, 198, 138, 255],
405        [254, 200, 140, 255],
406        [254, 202, 141, 255],
407        [254, 204, 143, 255],
408        [254, 205, 144, 255],
409        [254, 207, 146, 255],
410        [254, 209, 148, 255],
411        [254, 211, 149, 255],
412        [254, 213, 151, 255],
413        [254, 215, 153, 255],
414        [254, 216, 154, 255],
415        [253, 218, 156, 255],
416        [253, 220, 158, 255],
417        [253, 222, 160, 255],
418        [253, 224, 161, 255],
419        [253, 226, 163, 255],
420        [253, 227, 165, 255],
421        [253, 229, 167, 255],
422        [253, 231, 169, 255],
423        [253, 233, 170, 255],
424        [253, 235, 172, 255],
425        [252, 236, 174, 255],
426        [252, 238, 176, 255],
427        [252, 240, 178, 255],
428        [252, 242, 180, 255],
429        [252, 244, 182, 255],
430        [252, 246, 184, 255],
431        [252, 247, 185, 255],
432        [252, 249, 187, 255],
433        [252, 251, 189, 255],
434        [252, 253, 191, 255],
435    ]
436}
437
438// ---------------------------------------------------------------------------
439// Inferno: exact 256-sample LUT sampled from matplotlib
440// ---------------------------------------------------------------------------
441
442/// Inferno colourmap : perceptually uniform. Black -> deep red -> orange -> light yellow.
443pub fn inferno_rgba() -> [[u8; 4]; 256] {
444    [
445        [0, 0, 4, 255],
446        [1, 0, 5, 255],
447        [1, 1, 6, 255],
448        [1, 1, 8, 255],
449        [2, 1, 10, 255],
450        [2, 2, 12, 255],
451        [2, 2, 14, 255],
452        [3, 2, 16, 255],
453        [4, 3, 18, 255],
454        [4, 3, 20, 255],
455        [5, 4, 23, 255],
456        [6, 4, 25, 255],
457        [7, 5, 27, 255],
458        [8, 5, 29, 255],
459        [9, 6, 31, 255],
460        [10, 7, 34, 255],
461        [11, 7, 36, 255],
462        [12, 8, 38, 255],
463        [13, 8, 41, 255],
464        [14, 9, 43, 255],
465        [16, 9, 45, 255],
466        [17, 10, 48, 255],
467        [18, 10, 50, 255],
468        [20, 11, 52, 255],
469        [21, 11, 55, 255],
470        [22, 11, 57, 255],
471        [24, 12, 60, 255],
472        [25, 12, 62, 255],
473        [27, 12, 65, 255],
474        [28, 12, 67, 255],
475        [30, 12, 69, 255],
476        [31, 12, 72, 255],
477        [33, 12, 74, 255],
478        [35, 12, 76, 255],
479        [36, 12, 79, 255],
480        [38, 12, 81, 255],
481        [40, 11, 83, 255],
482        [41, 11, 85, 255],
483        [43, 11, 87, 255],
484        [45, 11, 89, 255],
485        [47, 10, 91, 255],
486        [49, 10, 92, 255],
487        [50, 10, 94, 255],
488        [52, 10, 95, 255],
489        [54, 9, 97, 255],
490        [56, 9, 98, 255],
491        [57, 9, 99, 255],
492        [59, 9, 100, 255],
493        [61, 9, 101, 255],
494        [62, 9, 102, 255],
495        [64, 10, 103, 255],
496        [66, 10, 104, 255],
497        [68, 10, 104, 255],
498        [69, 10, 105, 255],
499        [71, 11, 106, 255],
500        [73, 11, 106, 255],
501        [74, 12, 107, 255],
502        [76, 12, 107, 255],
503        [77, 13, 108, 255],
504        [79, 13, 108, 255],
505        [81, 14, 108, 255],
506        [82, 14, 109, 255],
507        [84, 15, 109, 255],
508        [85, 15, 109, 255],
509        [87, 16, 110, 255],
510        [89, 16, 110, 255],
511        [90, 17, 110, 255],
512        [92, 18, 110, 255],
513        [93, 18, 110, 255],
514        [95, 19, 110, 255],
515        [97, 19, 110, 255],
516        [98, 20, 110, 255],
517        [100, 21, 110, 255],
518        [101, 21, 110, 255],
519        [103, 22, 110, 255],
520        [105, 22, 110, 255],
521        [106, 23, 110, 255],
522        [108, 24, 110, 255],
523        [109, 24, 110, 255],
524        [111, 25, 110, 255],
525        [113, 25, 110, 255],
526        [114, 26, 110, 255],
527        [116, 26, 110, 255],
528        [117, 27, 110, 255],
529        [119, 28, 109, 255],
530        [120, 28, 109, 255],
531        [122, 29, 109, 255],
532        [124, 29, 109, 255],
533        [125, 30, 109, 255],
534        [127, 30, 108, 255],
535        [128, 31, 108, 255],
536        [130, 32, 108, 255],
537        [132, 32, 107, 255],
538        [133, 33, 107, 255],
539        [135, 33, 107, 255],
540        [136, 34, 106, 255],
541        [138, 34, 106, 255],
542        [140, 35, 105, 255],
543        [141, 35, 105, 255],
544        [143, 36, 105, 255],
545        [144, 37, 104, 255],
546        [146, 37, 104, 255],
547        [147, 38, 103, 255],
548        [149, 38, 103, 255],
549        [151, 39, 102, 255],
550        [152, 39, 102, 255],
551        [154, 40, 101, 255],
552        [155, 41, 100, 255],
553        [157, 41, 100, 255],
554        [159, 42, 99, 255],
555        [160, 42, 99, 255],
556        [162, 43, 98, 255],
557        [163, 44, 97, 255],
558        [165, 44, 96, 255],
559        [166, 45, 96, 255],
560        [168, 46, 95, 255],
561        [169, 46, 94, 255],
562        [171, 47, 94, 255],
563        [173, 48, 93, 255],
564        [174, 48, 92, 255],
565        [176, 49, 91, 255],
566        [177, 50, 90, 255],
567        [179, 50, 90, 255],
568        [180, 51, 89, 255],
569        [182, 52, 88, 255],
570        [183, 53, 87, 255],
571        [185, 53, 86, 255],
572        [186, 54, 85, 255],
573        [188, 55, 84, 255],
574        [189, 56, 83, 255],
575        [191, 57, 82, 255],
576        [192, 58, 81, 255],
577        [193, 58, 80, 255],
578        [195, 59, 79, 255],
579        [196, 60, 78, 255],
580        [198, 61, 77, 255],
581        [199, 62, 76, 255],
582        [200, 63, 75, 255],
583        [202, 64, 74, 255],
584        [203, 65, 73, 255],
585        [204, 66, 72, 255],
586        [206, 67, 71, 255],
587        [207, 68, 70, 255],
588        [208, 69, 69, 255],
589        [210, 70, 68, 255],
590        [211, 71, 67, 255],
591        [212, 72, 66, 255],
592        [213, 74, 65, 255],
593        [215, 75, 63, 255],
594        [216, 76, 62, 255],
595        [217, 77, 61, 255],
596        [218, 78, 60, 255],
597        [219, 80, 59, 255],
598        [221, 81, 58, 255],
599        [222, 82, 56, 255],
600        [223, 83, 55, 255],
601        [224, 85, 54, 255],
602        [225, 86, 53, 255],
603        [226, 87, 52, 255],
604        [227, 89, 51, 255],
605        [228, 90, 49, 255],
606        [229, 92, 48, 255],
607        [230, 93, 47, 255],
608        [231, 94, 46, 255],
609        [232, 96, 45, 255],
610        [233, 97, 43, 255],
611        [234, 99, 42, 255],
612        [235, 100, 41, 255],
613        [235, 102, 40, 255],
614        [236, 103, 38, 255],
615        [237, 105, 37, 255],
616        [238, 106, 36, 255],
617        [239, 108, 35, 255],
618        [239, 110, 33, 255],
619        [240, 111, 32, 255],
620        [241, 113, 31, 255],
621        [241, 115, 29, 255],
622        [242, 116, 28, 255],
623        [243, 118, 27, 255],
624        [243, 120, 25, 255],
625        [244, 121, 24, 255],
626        [245, 123, 23, 255],
627        [245, 125, 21, 255],
628        [246, 126, 20, 255],
629        [246, 128, 19, 255],
630        [247, 130, 18, 255],
631        [247, 132, 16, 255],
632        [248, 133, 15, 255],
633        [248, 135, 14, 255],
634        [248, 137, 12, 255],
635        [249, 139, 11, 255],
636        [249, 140, 10, 255],
637        [249, 142, 9, 255],
638        [250, 144, 8, 255],
639        [250, 146, 7, 255],
640        [250, 148, 7, 255],
641        [251, 150, 6, 255],
642        [251, 151, 6, 255],
643        [251, 153, 6, 255],
644        [251, 155, 6, 255],
645        [251, 157, 7, 255],
646        [252, 159, 7, 255],
647        [252, 161, 8, 255],
648        [252, 163, 9, 255],
649        [252, 165, 10, 255],
650        [252, 166, 12, 255],
651        [252, 168, 13, 255],
652        [252, 170, 15, 255],
653        [252, 172, 17, 255],
654        [252, 174, 18, 255],
655        [252, 176, 20, 255],
656        [252, 178, 22, 255],
657        [252, 180, 24, 255],
658        [251, 182, 26, 255],
659        [251, 184, 29, 255],
660        [251, 186, 31, 255],
661        [251, 188, 33, 255],
662        [251, 190, 35, 255],
663        [250, 192, 38, 255],
664        [250, 194, 40, 255],
665        [250, 196, 42, 255],
666        [250, 198, 45, 255],
667        [249, 199, 47, 255],
668        [249, 201, 50, 255],
669        [249, 203, 53, 255],
670        [248, 205, 55, 255],
671        [248, 207, 58, 255],
672        [247, 209, 61, 255],
673        [247, 211, 64, 255],
674        [246, 213, 67, 255],
675        [246, 215, 70, 255],
676        [245, 217, 73, 255],
677        [245, 219, 76, 255],
678        [244, 221, 79, 255],
679        [244, 223, 83, 255],
680        [244, 225, 86, 255],
681        [243, 227, 90, 255],
682        [243, 229, 93, 255],
683        [242, 230, 97, 255],
684        [242, 232, 101, 255],
685        [242, 234, 105, 255],
686        [241, 236, 109, 255],
687        [241, 237, 113, 255],
688        [241, 239, 117, 255],
689        [241, 241, 121, 255],
690        [242, 242, 125, 255],
691        [242, 244, 130, 255],
692        [243, 245, 134, 255],
693        [243, 246, 138, 255],
694        [244, 248, 142, 255],
695        [245, 249, 146, 255],
696        [246, 250, 150, 255],
697        [248, 251, 154, 255],
698        [249, 252, 157, 255],
699        [250, 253, 161, 255],
700        [252, 255, 164, 255],
701    ]
702}
703
704// ---------------------------------------------------------------------------
705// Turbo: exact 256-sample LUT sampled from matplotlib
706// ---------------------------------------------------------------------------
707
708/// Turbo colourmap (Google 2019) : improved rainbow. Deep purple -> cyan -> green -> yellow -> red.
709pub fn turbo_rgba() -> [[u8; 4]; 256] {
710    [
711        [48, 18, 59, 255],
712        [50, 21, 67, 255],
713        [51, 24, 74, 255],
714        [52, 27, 81, 255],
715        [53, 30, 88, 255],
716        [54, 33, 95, 255],
717        [55, 36, 102, 255],
718        [56, 39, 109, 255],
719        [57, 42, 115, 255],
720        [58, 45, 121, 255],
721        [59, 47, 128, 255],
722        [60, 50, 134, 255],
723        [61, 53, 139, 255],
724        [62, 56, 145, 255],
725        [63, 59, 151, 255],
726        [63, 62, 156, 255],
727        [64, 64, 162, 255],
728        [65, 67, 167, 255],
729        [65, 70, 172, 255],
730        [66, 73, 177, 255],
731        [66, 75, 181, 255],
732        [67, 78, 186, 255],
733        [68, 81, 191, 255],
734        [68, 84, 195, 255],
735        [68, 86, 199, 255],
736        [69, 89, 203, 255],
737        [69, 92, 207, 255],
738        [69, 94, 211, 255],
739        [70, 97, 214, 255],
740        [70, 100, 218, 255],
741        [70, 102, 221, 255],
742        [70, 105, 224, 255],
743        [70, 107, 227, 255],
744        [71, 110, 230, 255],
745        [71, 113, 233, 255],
746        [71, 115, 235, 255],
747        [71, 118, 238, 255],
748        [71, 120, 240, 255],
749        [71, 123, 242, 255],
750        [70, 125, 244, 255],
751        [70, 128, 246, 255],
752        [70, 130, 248, 255],
753        [70, 133, 250, 255],
754        [70, 135, 251, 255],
755        [69, 138, 252, 255],
756        [69, 140, 253, 255],
757        [68, 143, 254, 255],
758        [67, 145, 254, 255],
759        [66, 148, 255, 255],
760        [65, 150, 255, 255],
761        [64, 153, 255, 255],
762        [62, 155, 254, 255],
763        [61, 158, 254, 255],
764        [59, 160, 253, 255],
765        [58, 163, 252, 255],
766        [56, 165, 251, 255],
767        [55, 168, 250, 255],
768        [53, 171, 248, 255],
769        [51, 173, 247, 255],
770        [49, 175, 245, 255],
771        [47, 178, 244, 255],
772        [46, 180, 242, 255],
773        [44, 183, 240, 255],
774        [42, 185, 238, 255],
775        [40, 188, 235, 255],
776        [39, 190, 233, 255],
777        [37, 192, 231, 255],
778        [35, 195, 228, 255],
779        [34, 197, 226, 255],
780        [32, 199, 223, 255],
781        [31, 201, 221, 255],
782        [30, 203, 218, 255],
783        [28, 205, 216, 255],
784        [27, 208, 213, 255],
785        [26, 210, 210, 255],
786        [26, 212, 208, 255],
787        [25, 213, 205, 255],
788        [24, 215, 202, 255],
789        [24, 217, 200, 255],
790        [24, 219, 197, 255],
791        [24, 221, 194, 255],
792        [24, 222, 192, 255],
793        [24, 224, 189, 255],
794        [25, 226, 187, 255],
795        [25, 227, 185, 255],
796        [26, 228, 182, 255],
797        [28, 230, 180, 255],
798        [29, 231, 178, 255],
799        [31, 233, 175, 255],
800        [32, 234, 172, 255],
801        [34, 235, 170, 255],
802        [37, 236, 167, 255],
803        [39, 238, 164, 255],
804        [42, 239, 161, 255],
805        [44, 240, 158, 255],
806        [47, 241, 155, 255],
807        [50, 242, 152, 255],
808        [53, 243, 148, 255],
809        [56, 244, 145, 255],
810        [60, 245, 142, 255],
811        [63, 246, 138, 255],
812        [67, 247, 135, 255],
813        [70, 248, 132, 255],
814        [74, 248, 128, 255],
815        [78, 249, 125, 255],
816        [82, 250, 122, 255],
817        [85, 250, 118, 255],
818        [89, 251, 115, 255],
819        [93, 252, 111, 255],
820        [97, 252, 108, 255],
821        [101, 253, 105, 255],
822        [105, 253, 102, 255],
823        [109, 254, 98, 255],
824        [113, 254, 95, 255],
825        [117, 254, 92, 255],
826        [121, 254, 89, 255],
827        [125, 255, 86, 255],
828        [128, 255, 83, 255],
829        [132, 255, 81, 255],
830        [136, 255, 78, 255],
831        [139, 255, 75, 255],
832        [143, 255, 73, 255],
833        [146, 255, 71, 255],
834        [150, 254, 68, 255],
835        [153, 254, 66, 255],
836        [156, 254, 64, 255],
837        [159, 253, 63, 255],
838        [161, 253, 61, 255],
839        [164, 252, 60, 255],
840        [167, 252, 58, 255],
841        [169, 251, 57, 255],
842        [172, 251, 56, 255],
843        [175, 250, 55, 255],
844        [177, 249, 54, 255],
845        [180, 248, 54, 255],
846        [183, 247, 53, 255],
847        [185, 246, 53, 255],
848        [188, 245, 52, 255],
849        [190, 244, 52, 255],
850        [193, 243, 52, 255],
851        [195, 241, 52, 255],
852        [198, 240, 52, 255],
853        [200, 239, 52, 255],
854        [203, 237, 52, 255],
855        [205, 236, 52, 255],
856        [208, 234, 52, 255],
857        [210, 233, 53, 255],
858        [212, 231, 53, 255],
859        [215, 229, 53, 255],
860        [217, 228, 54, 255],
861        [219, 226, 54, 255],
862        [221, 224, 55, 255],
863        [223, 223, 55, 255],
864        [225, 221, 55, 255],
865        [227, 219, 56, 255],
866        [229, 217, 56, 255],
867        [231, 215, 57, 255],
868        [233, 213, 57, 255],
869        [235, 211, 57, 255],
870        [236, 209, 58, 255],
871        [238, 207, 58, 255],
872        [239, 205, 58, 255],
873        [241, 203, 58, 255],
874        [242, 201, 58, 255],
875        [244, 199, 58, 255],
876        [245, 197, 58, 255],
877        [246, 195, 58, 255],
878        [247, 193, 58, 255],
879        [248, 190, 57, 255],
880        [249, 188, 57, 255],
881        [250, 186, 57, 255],
882        [251, 184, 56, 255],
883        [251, 182, 55, 255],
884        [252, 179, 54, 255],
885        [252, 177, 54, 255],
886        [253, 174, 53, 255],
887        [253, 172, 52, 255],
888        [254, 169, 51, 255],
889        [254, 167, 50, 255],
890        [254, 164, 49, 255],
891        [254, 161, 48, 255],
892        [254, 158, 47, 255],
893        [254, 155, 45, 255],
894        [254, 153, 44, 255],
895        [254, 150, 43, 255],
896        [254, 147, 42, 255],
897        [254, 144, 41, 255],
898        [253, 141, 39, 255],
899        [253, 138, 38, 255],
900        [252, 135, 37, 255],
901        [252, 132, 35, 255],
902        [251, 129, 34, 255],
903        [251, 126, 33, 255],
904        [250, 123, 31, 255],
905        [249, 120, 30, 255],
906        [249, 117, 29, 255],
907        [248, 114, 28, 255],
908        [247, 111, 26, 255],
909        [246, 108, 25, 255],
910        [245, 105, 24, 255],
911        [244, 102, 23, 255],
912        [243, 99, 21, 255],
913        [242, 96, 20, 255],
914        [241, 93, 19, 255],
915        [240, 91, 18, 255],
916        [239, 88, 17, 255],
917        [237, 85, 16, 255],
918        [236, 83, 15, 255],
919        [235, 80, 14, 255],
920        [234, 78, 13, 255],
921        [232, 75, 12, 255],
922        [231, 73, 12, 255],
923        [229, 71, 11, 255],
924        [228, 69, 10, 255],
925        [226, 67, 10, 255],
926        [225, 65, 9, 255],
927        [223, 63, 8, 255],
928        [221, 61, 8, 255],
929        [220, 59, 7, 255],
930        [218, 57, 7, 255],
931        [216, 55, 6, 255],
932        [214, 53, 6, 255],
933        [212, 51, 5, 255],
934        [210, 49, 5, 255],
935        [208, 47, 5, 255],
936        [206, 45, 4, 255],
937        [204, 43, 4, 255],
938        [202, 42, 4, 255],
939        [200, 40, 3, 255],
940        [197, 38, 3, 255],
941        [195, 37, 3, 255],
942        [193, 35, 2, 255],
943        [190, 33, 2, 255],
944        [188, 32, 2, 255],
945        [185, 30, 2, 255],
946        [183, 29, 2, 255],
947        [180, 27, 1, 255],
948        [178, 26, 1, 255],
949        [175, 24, 1, 255],
950        [172, 23, 1, 255],
951        [169, 22, 1, 255],
952        [167, 20, 1, 255],
953        [164, 19, 1, 255],
954        [161, 18, 1, 255],
955        [158, 16, 1, 255],
956        [155, 15, 1, 255],
957        [152, 14, 1, 255],
958        [149, 13, 1, 255],
959        [146, 11, 1, 255],
960        [142, 10, 1, 255],
961        [139, 9, 2, 255],
962        [136, 8, 2, 255],
963        [133, 7, 2, 255],
964        [129, 6, 2, 255],
965        [126, 5, 2, 255],
966        [122, 4, 3, 255],
967    ]
968}
969
970// ---------------------------------------------------------------------------
971// Jet: exact 256-sample LUT sampled from matplotlib
972// ---------------------------------------------------------------------------
973
974/// Jet colourmap : classic blue-cyan-green-yellow-red. Not perceptually uniform.
975pub fn jet_rgba() -> [[u8; 4]; 256] {
976    [
977        [0, 0, 128, 255],
978        [0, 0, 132, 255],
979        [0, 0, 137, 255],
980        [0, 0, 141, 255],
981        [0, 0, 146, 255],
982        [0, 0, 150, 255],
983        [0, 0, 155, 255],
984        [0, 0, 159, 255],
985        [0, 0, 164, 255],
986        [0, 0, 168, 255],
987        [0, 0, 173, 255],
988        [0, 0, 178, 255],
989        [0, 0, 182, 255],
990        [0, 0, 187, 255],
991        [0, 0, 191, 255],
992        [0, 0, 196, 255],
993        [0, 0, 200, 255],
994        [0, 0, 205, 255],
995        [0, 0, 209, 255],
996        [0, 0, 214, 255],
997        [0, 0, 218, 255],
998        [0, 0, 223, 255],
999        [0, 0, 227, 255],
1000        [0, 0, 232, 255],
1001        [0, 0, 237, 255],
1002        [0, 0, 241, 255],
1003        [0, 0, 246, 255],
1004        [0, 0, 250, 255],
1005        [0, 0, 255, 255],
1006        [0, 0, 255, 255],
1007        [0, 0, 255, 255],
1008        [0, 0, 255, 255],
1009        [0, 1, 255, 255],
1010        [0, 4, 255, 255],
1011        [0, 9, 255, 255],
1012        [0, 13, 255, 255],
1013        [0, 17, 255, 255],
1014        [0, 20, 255, 255],
1015        [0, 25, 255, 255],
1016        [0, 29, 255, 255],
1017        [0, 33, 255, 255],
1018        [0, 36, 255, 255],
1019        [0, 41, 255, 255],
1020        [0, 45, 255, 255],
1021        [0, 49, 255, 255],
1022        [0, 52, 255, 255],
1023        [0, 57, 255, 255],
1024        [0, 61, 255, 255],
1025        [0, 65, 255, 255],
1026        [0, 68, 255, 255],
1027        [0, 73, 255, 255],
1028        [0, 77, 255, 255],
1029        [0, 81, 255, 255],
1030        [0, 84, 255, 255],
1031        [0, 89, 255, 255],
1032        [0, 93, 255, 255],
1033        [0, 97, 255, 255],
1034        [0, 100, 255, 255],
1035        [0, 105, 255, 255],
1036        [0, 109, 255, 255],
1037        [0, 113, 255, 255],
1038        [0, 116, 255, 255],
1039        [0, 121, 255, 255],
1040        [0, 125, 255, 255],
1041        [0, 129, 255, 255],
1042        [0, 133, 255, 255],
1043        [0, 136, 255, 255],
1044        [0, 141, 255, 255],
1045        [0, 145, 255, 255],
1046        [0, 149, 255, 255],
1047        [0, 153, 255, 255],
1048        [0, 157, 255, 255],
1049        [0, 161, 255, 255],
1050        [0, 165, 255, 255],
1051        [0, 168, 255, 255],
1052        [0, 173, 255, 255],
1053        [0, 177, 255, 255],
1054        [0, 181, 255, 255],
1055        [0, 185, 255, 255],
1056        [0, 189, 255, 255],
1057        [0, 193, 255, 255],
1058        [0, 197, 255, 255],
1059        [0, 200, 255, 255],
1060        [0, 205, 255, 255],
1061        [0, 209, 255, 255],
1062        [0, 213, 255, 255],
1063        [0, 217, 255, 255],
1064        [0, 221, 254, 255],
1065        [0, 225, 251, 255],
1066        [0, 229, 248, 255],
1067        [2, 232, 244, 255],
1068        [6, 237, 241, 255],
1069        [9, 241, 238, 255],
1070        [12, 245, 235, 255],
1071        [15, 249, 231, 255],
1072        [19, 253, 228, 255],
1073        [22, 255, 225, 255],
1074        [25, 255, 222, 255],
1075        [28, 255, 219, 255],
1076        [31, 255, 215, 255],
1077        [35, 255, 212, 255],
1078        [38, 255, 209, 255],
1079        [41, 255, 206, 255],
1080        [44, 255, 202, 255],
1081        [48, 255, 199, 255],
1082        [51, 255, 196, 255],
1083        [54, 255, 193, 255],
1084        [57, 255, 190, 255],
1085        [60, 255, 186, 255],
1086        [64, 255, 183, 255],
1087        [67, 255, 180, 255],
1088        [70, 255, 177, 255],
1089        [73, 255, 173, 255],
1090        [77, 255, 170, 255],
1091        [80, 255, 167, 255],
1092        [83, 255, 164, 255],
1093        [86, 255, 160, 255],
1094        [90, 255, 157, 255],
1095        [93, 255, 154, 255],
1096        [96, 255, 151, 255],
1097        [99, 255, 148, 255],
1098        [102, 255, 144, 255],
1099        [106, 255, 141, 255],
1100        [109, 255, 138, 255],
1101        [112, 255, 135, 255],
1102        [115, 255, 131, 255],
1103        [119, 255, 128, 255],
1104        [122, 255, 125, 255],
1105        [125, 255, 122, 255],
1106        [128, 255, 119, 255],
1107        [131, 255, 115, 255],
1108        [135, 255, 112, 255],
1109        [138, 255, 109, 255],
1110        [141, 255, 106, 255],
1111        [144, 255, 102, 255],
1112        [148, 255, 99, 255],
1113        [151, 255, 96, 255],
1114        [154, 255, 93, 255],
1115        [157, 255, 90, 255],
1116        [160, 255, 86, 255],
1117        [164, 255, 83, 255],
1118        [167, 255, 80, 255],
1119        [170, 255, 77, 255],
1120        [173, 255, 73, 255],
1121        [177, 255, 70, 255],
1122        [180, 255, 67, 255],
1123        [183, 255, 64, 255],
1124        [186, 255, 60, 255],
1125        [190, 255, 57, 255],
1126        [193, 255, 54, 255],
1127        [196, 255, 51, 255],
1128        [199, 255, 48, 255],
1129        [202, 255, 44, 255],
1130        [206, 255, 41, 255],
1131        [209, 255, 38, 255],
1132        [212, 255, 35, 255],
1133        [215, 255, 31, 255],
1134        [219, 255, 28, 255],
1135        [222, 255, 25, 255],
1136        [225, 255, 22, 255],
1137        [228, 255, 19, 255],
1138        [231, 255, 15, 255],
1139        [235, 255, 12, 255],
1140        [238, 255, 9, 255],
1141        [241, 252, 6, 255],
1142        [244, 248, 2, 255],
1143        [248, 245, 0, 255],
1144        [251, 241, 0, 255],
1145        [254, 237, 0, 255],
1146        [255, 234, 0, 255],
1147        [255, 230, 0, 255],
1148        [255, 226, 0, 255],
1149        [255, 222, 0, 255],
1150        [255, 219, 0, 255],
1151        [255, 215, 0, 255],
1152        [255, 211, 0, 255],
1153        [255, 208, 0, 255],
1154        [255, 204, 0, 255],
1155        [255, 200, 0, 255],
1156        [255, 196, 0, 255],
1157        [255, 193, 0, 255],
1158        [255, 189, 0, 255],
1159        [255, 185, 0, 255],
1160        [255, 182, 0, 255],
1161        [255, 178, 0, 255],
1162        [255, 174, 0, 255],
1163        [255, 171, 0, 255],
1164        [255, 167, 0, 255],
1165        [255, 163, 0, 255],
1166        [255, 159, 0, 255],
1167        [255, 156, 0, 255],
1168        [255, 152, 0, 255],
1169        [255, 148, 0, 255],
1170        [255, 145, 0, 255],
1171        [255, 141, 0, 255],
1172        [255, 137, 0, 255],
1173        [255, 134, 0, 255],
1174        [255, 130, 0, 255],
1175        [255, 126, 0, 255],
1176        [255, 122, 0, 255],
1177        [255, 119, 0, 255],
1178        [255, 115, 0, 255],
1179        [255, 111, 0, 255],
1180        [255, 108, 0, 255],
1181        [255, 104, 0, 255],
1182        [255, 100, 0, 255],
1183        [255, 96, 0, 255],
1184        [255, 93, 0, 255],
1185        [255, 89, 0, 255],
1186        [255, 85, 0, 255],
1187        [255, 82, 0, 255],
1188        [255, 78, 0, 255],
1189        [255, 74, 0, 255],
1190        [255, 71, 0, 255],
1191        [255, 67, 0, 255],
1192        [255, 63, 0, 255],
1193        [255, 59, 0, 255],
1194        [255, 56, 0, 255],
1195        [255, 52, 0, 255],
1196        [255, 48, 0, 255],
1197        [255, 45, 0, 255],
1198        [255, 41, 0, 255],
1199        [255, 37, 0, 255],
1200        [255, 34, 0, 255],
1201        [255, 30, 0, 255],
1202        [255, 26, 0, 255],
1203        [255, 22, 0, 255],
1204        [255, 19, 0, 255],
1205        [250, 15, 0, 255],
1206        [246, 11, 0, 255],
1207        [241, 8, 0, 255],
1208        [237, 4, 0, 255],
1209        [232, 0, 0, 255],
1210        [228, 0, 0, 255],
1211        [223, 0, 0, 255],
1212        [218, 0, 0, 255],
1213        [214, 0, 0, 255],
1214        [209, 0, 0, 255],
1215        [205, 0, 0, 255],
1216        [200, 0, 0, 255],
1217        [196, 0, 0, 255],
1218        [191, 0, 0, 255],
1219        [187, 0, 0, 255],
1220        [182, 0, 0, 255],
1221        [178, 0, 0, 255],
1222        [173, 0, 0, 255],
1223        [168, 0, 0, 255],
1224        [164, 0, 0, 255],
1225        [159, 0, 0, 255],
1226        [155, 0, 0, 255],
1227        [150, 0, 0, 255],
1228        [146, 0, 0, 255],
1229        [141, 0, 0, 255],
1230        [137, 0, 0, 255],
1231        [132, 0, 0, 255],
1232        [128, 0, 0, 255],
1233    ]
1234}
1235
1236// ---------------------------------------------------------------------------
1237// RdBu (reversed): exact 256-sample LUT sampled from matplotlib
1238// ---------------------------------------------------------------------------
1239
1240/// RdBu diverging colourmap (red -> white -> blue, reversed so blue is at t=0).
1241/// Suitable for signed quantities (negative = blue, zero = white, positive = red).
1242pub fn rdbu_r_rgba() -> [[u8; 4]; 256] {
1243    [
1244        [5, 48, 97, 255],
1245        [6, 50, 100, 255],
1246        [7, 52, 103, 255],
1247        [8, 54, 106, 255],
1248        [9, 56, 109, 255],
1249        [10, 59, 112, 255],
1250        [12, 61, 115, 255],
1251        [13, 63, 118, 255],
1252        [14, 65, 121, 255],
1253        [15, 67, 123, 255],
1254        [16, 69, 126, 255],
1255        [17, 71, 129, 255],
1256        [18, 73, 132, 255],
1257        [19, 76, 135, 255],
1258        [20, 78, 138, 255],
1259        [21, 80, 141, 255],
1260        [23, 82, 144, 255],
1261        [24, 84, 147, 255],
1262        [25, 86, 150, 255],
1263        [26, 88, 153, 255],
1264        [27, 90, 156, 255],
1265        [28, 92, 159, 255],
1266        [29, 95, 162, 255],
1267        [30, 97, 165, 255],
1268        [31, 99, 168, 255],
1269        [32, 101, 171, 255],
1270        [34, 103, 172, 255],
1271        [35, 105, 173, 255],
1272        [36, 106, 174, 255],
1273        [38, 108, 175, 255],
1274        [39, 110, 176, 255],
1275        [40, 112, 177, 255],
1276        [42, 113, 178, 255],
1277        [43, 115, 179, 255],
1278        [44, 117, 180, 255],
1279        [46, 119, 181, 255],
1280        [47, 121, 181, 255],
1281        [48, 122, 182, 255],
1282        [50, 124, 183, 255],
1283        [51, 126, 184, 255],
1284        [52, 128, 185, 255],
1285        [54, 129, 186, 255],
1286        [55, 131, 187, 255],
1287        [56, 133, 188, 255],
1288        [58, 135, 189, 255],
1289        [59, 136, 190, 255],
1290        [60, 138, 190, 255],
1291        [62, 140, 191, 255],
1292        [63, 142, 192, 255],
1293        [64, 143, 193, 255],
1294        [66, 145, 194, 255],
1295        [67, 147, 195, 255],
1296        [70, 149, 196, 255],
1297        [73, 151, 197, 255],
1298        [76, 153, 198, 255],
1299        [79, 155, 199, 255],
1300        [82, 157, 200, 255],
1301        [86, 159, 201, 255],
1302        [89, 161, 202, 255],
1303        [92, 163, 203, 255],
1304        [95, 165, 205, 255],
1305        [98, 167, 206, 255],
1306        [101, 169, 207, 255],
1307        [104, 171, 208, 255],
1308        [107, 172, 209, 255],
1309        [110, 174, 210, 255],
1310        [113, 176, 211, 255],
1311        [117, 178, 212, 255],
1312        [120, 180, 213, 255],
1313        [123, 182, 214, 255],
1314        [126, 184, 215, 255],
1315        [129, 186, 216, 255],
1316        [132, 188, 217, 255],
1317        [135, 190, 218, 255],
1318        [138, 192, 219, 255],
1319        [141, 194, 220, 255],
1320        [144, 196, 221, 255],
1321        [147, 198, 222, 255],
1322        [150, 199, 223, 255],
1323        [152, 200, 224, 255],
1324        [155, 201, 224, 255],
1325        [157, 203, 225, 255],
1326        [160, 204, 226, 255],
1327        [162, 205, 227, 255],
1328        [165, 206, 227, 255],
1329        [167, 208, 228, 255],
1330        [169, 209, 229, 255],
1331        [172, 210, 229, 255],
1332        [174, 211, 230, 255],
1333        [177, 213, 231, 255],
1334        [179, 214, 232, 255],
1335        [182, 215, 232, 255],
1336        [184, 216, 233, 255],
1337        [187, 218, 234, 255],
1338        [189, 219, 234, 255],
1339        [192, 220, 235, 255],
1340        [194, 221, 236, 255],
1341        [197, 223, 236, 255],
1342        [199, 224, 237, 255],
1343        [202, 225, 238, 255],
1344        [204, 226, 239, 255],
1345        [207, 228, 239, 255],
1346        [209, 229, 240, 255],
1347        [210, 230, 240, 255],
1348        [212, 230, 241, 255],
1349        [213, 231, 241, 255],
1350        [215, 232, 241, 255],
1351        [216, 233, 241, 255],
1352        [218, 233, 242, 255],
1353        [219, 234, 242, 255],
1354        [221, 235, 242, 255],
1355        [222, 235, 242, 255],
1356        [224, 236, 243, 255],
1357        [225, 237, 243, 255],
1358        [227, 237, 243, 255],
1359        [228, 238, 244, 255],
1360        [230, 239, 244, 255],
1361        [231, 240, 244, 255],
1362        [233, 240, 244, 255],
1363        [234, 241, 245, 255],
1364        [236, 242, 245, 255],
1365        [237, 242, 245, 255],
1366        [239, 243, 245, 255],
1367        [240, 244, 246, 255],
1368        [242, 245, 246, 255],
1369        [243, 245, 246, 255],
1370        [245, 246, 247, 255],
1371        [246, 247, 247, 255],
1372        [247, 246, 246, 255],
1373        [247, 245, 244, 255],
1374        [248, 244, 242, 255],
1375        [248, 243, 240, 255],
1376        [248, 242, 239, 255],
1377        [248, 241, 237, 255],
1378        [249, 240, 235, 255],
1379        [249, 239, 233, 255],
1380        [249, 238, 231, 255],
1381        [249, 237, 229, 255],
1382        [249, 235, 227, 255],
1383        [250, 234, 225, 255],
1384        [250, 233, 223, 255],
1385        [250, 232, 222, 255],
1386        [250, 231, 220, 255],
1387        [251, 230, 218, 255],
1388        [251, 229, 216, 255],
1389        [251, 228, 214, 255],
1390        [251, 227, 212, 255],
1391        [252, 226, 210, 255],
1392        [252, 224, 208, 255],
1393        [252, 223, 207, 255],
1394        [252, 222, 205, 255],
1395        [253, 221, 203, 255],
1396        [253, 220, 201, 255],
1397        [253, 219, 199, 255],
1398        [253, 217, 196, 255],
1399        [252, 215, 194, 255],
1400        [252, 213, 191, 255],
1401        [252, 211, 188, 255],
1402        [251, 208, 185, 255],
1403        [251, 206, 183, 255],
1404        [251, 204, 180, 255],
1405        [250, 202, 177, 255],
1406        [250, 200, 175, 255],
1407        [249, 198, 172, 255],
1408        [249, 196, 169, 255],
1409        [249, 194, 167, 255],
1410        [248, 191, 164, 255],
1411        [248, 189, 161, 255],
1412        [248, 187, 158, 255],
1413        [247, 185, 156, 255],
1414        [247, 183, 153, 255],
1415        [247, 181, 150, 255],
1416        [246, 179, 148, 255],
1417        [246, 177, 145, 255],
1418        [246, 175, 142, 255],
1419        [245, 172, 139, 255],
1420        [245, 170, 137, 255],
1421        [245, 168, 134, 255],
1422        [244, 166, 131, 255],
1423        [243, 164, 129, 255],
1424        [242, 161, 127, 255],
1425        [241, 158, 125, 255],
1426        [240, 156, 123, 255],
1427        [239, 153, 121, 255],
1428        [238, 150, 119, 255],
1429        [236, 147, 116, 255],
1430        [235, 145, 114, 255],
1431        [234, 142, 112, 255],
1432        [233, 139, 110, 255],
1433        [232, 137, 108, 255],
1434        [230, 134, 106, 255],
1435        [229, 131, 104, 255],
1436        [228, 128, 102, 255],
1437        [227, 126, 100, 255],
1438        [226, 123, 98, 255],
1439        [225, 120, 96, 255],
1440        [223, 118, 94, 255],
1441        [222, 115, 92, 255],
1442        [221, 112, 89, 255],
1443        [220, 110, 87, 255],
1444        [219, 107, 85, 255],
1445        [218, 104, 83, 255],
1446        [216, 101, 81, 255],
1447        [215, 99, 79, 255],
1448        [214, 96, 77, 255],
1449        [213, 93, 76, 255],
1450        [211, 90, 74, 255],
1451        [210, 88, 73, 255],
1452        [208, 85, 72, 255],
1453        [207, 82, 70, 255],
1454        [206, 79, 69, 255],
1455        [204, 76, 68, 255],
1456        [203, 73, 66, 255],
1457        [201, 71, 65, 255],
1458        [200, 68, 64, 255],
1459        [198, 65, 62, 255],
1460        [197, 62, 61, 255],
1461        [196, 59, 60, 255],
1462        [194, 56, 58, 255],
1463        [193, 54, 57, 255],
1464        [191, 51, 56, 255],
1465        [190, 48, 54, 255],
1466        [189, 45, 53, 255],
1467        [187, 42, 52, 255],
1468        [186, 40, 50, 255],
1469        [184, 37, 49, 255],
1470        [183, 34, 48, 255],
1471        [182, 31, 46, 255],
1472        [180, 28, 45, 255],
1473        [179, 25, 44, 255],
1474        [177, 24, 43, 255],
1475        [174, 23, 42, 255],
1476        [171, 22, 42, 255],
1477        [168, 21, 41, 255],
1478        [165, 20, 41, 255],
1479        [162, 19, 40, 255],
1480        [159, 18, 40, 255],
1481        [156, 17, 39, 255],
1482        [153, 16, 39, 255],
1483        [150, 15, 39, 255],
1484        [147, 14, 38, 255],
1485        [144, 13, 38, 255],
1486        [141, 12, 37, 255],
1487        [138, 11, 37, 255],
1488        [135, 10, 36, 255],
1489        [132, 9, 36, 255],
1490        [129, 8, 35, 255],
1491        [127, 8, 35, 255],
1492        [124, 7, 34, 255],
1493        [121, 6, 34, 255],
1494        [118, 5, 33, 255],
1495        [115, 4, 33, 255],
1496        [112, 3, 32, 255],
1497        [109, 2, 32, 255],
1498        [106, 1, 31, 255],
1499        [103, 0, 31, 255],
1500    ]
1501}
1502
1503// ---------------------------------------------------------------------------
1504// Custom colourmap LUT generation
1505// ---------------------------------------------------------------------------
1506
1507/// Linearly interpolate between colour stops to produce a 256-sample LUT.
1508///
1509/// `stops` is a slice of `(position, rgba)` pairs where `position` is in `[0, 1]`.
1510/// Stops are sorted by position before interpolation.
1511/// The result is clamped: the first stop colour fills `t < stops[0].0` and the last
1512/// stop colour fills `t > stops.last().0`.
1513///
1514/// Returns a `[[u8; 4]; 256]` suitable for uploading to a 256x1 GPU texture.
1515pub fn lerp_colourmap_lut(stops: &[(f32, [u8; 4])]) -> [[u8; 4]; 256] {
1516    let mut lut = [[0u8; 4]; 256];
1517    if stops.is_empty() {
1518        return lut;
1519    }
1520    // Sort by position.
1521    let mut sorted: Vec<(f32, [u8; 4])> = stops.to_vec();
1522    sorted.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal));
1523
1524    for i in 0..256 {
1525        let t = i as f32 / 255.0;
1526
1527        // Find the surrounding stops.
1528        let first = sorted[0];
1529        let last = *sorted.last().unwrap();
1530
1531        if t <= first.0 {
1532            lut[i] = first.1;
1533            continue;
1534        }
1535        if t >= last.0 {
1536            lut[i] = last.1;
1537            continue;
1538        }
1539
1540        // Binary search for the lower stop.
1541        let pos = sorted.partition_point(|s| s.0 <= t);
1542        let lo = sorted[pos - 1];
1543        let hi = sorted[pos];
1544
1545        let range = hi.0 - lo.0;
1546        let frac = if range > 1.0e-7 {
1547            (t - lo.0) / range
1548        } else {
1549            0.0
1550        };
1551        lut[i] = [
1552            (lo.1[0] as f32 + (hi.1[0] as f32 - lo.1[0] as f32) * frac + 0.5) as u8,
1553            (lo.1[1] as f32 + (hi.1[1] as f32 - lo.1[1] as f32) * frac + 0.5) as u8,
1554            (lo.1[2] as f32 + (hi.1[2] as f32 - lo.1[2] as f32) * frac + 0.5) as u8,
1555            (lo.1[3] as f32 + (hi.1[3] as f32 - lo.1[3] as f32) * frac + 0.5) as u8,
1556        ];
1557    }
1558    lut
1559}
1560
1561/// Parse a ParaView XML colourmap file.
1562///
1563/// Supports the standard format:
1564/// ```xml
1565/// <ColourMaps>
1566///   <ColourMap name="MyMap" space="RGB">
1567///     <Point x="0.0" r="0.0" g="0.0" b="0.0" o="1.0"/>
1568///     <Point x="1.0" r="1.0" g="1.0" b="1.0" o="1.0"/>
1569///   </ColourMap>
1570/// </ColourMaps>
1571/// ```
1572///
1573/// Returns a list of `(name, stops)` pairs, where each stop is `(position_0_1, [r, g, b, a])`.
1574/// Uses simple string parsing without any XML library dependency.
1575pub fn parse_paraview_xml_colourmap(xml: &str) -> Vec<(String, Vec<(f32, [u8; 4])>)> {
1576    let mut result = Vec::new();
1577    let mut current_name: Option<String> = None;
1578    let mut current_stops: Vec<(f32, [u8; 4])> = Vec::new();
1579
1580    for line in xml.lines() {
1581        let trimmed = line.trim();
1582
1583        if trimmed.starts_with("<ColourMap") {
1584            // Extract name attribute.
1585            current_name = attr_value(trimmed, "name").map(|s| s.to_string());
1586            current_stops.clear();
1587        } else if trimmed.starts_with("</ColourMap>") {
1588            if let Some(name) = current_name.take() {
1589                if !current_stops.is_empty() {
1590                    result.push((name, current_stops.clone()));
1591                }
1592            }
1593            current_stops.clear();
1594        } else if trimmed.starts_with("<Point") {
1595            // Parse x, r, g, b, o attributes.
1596            if let (Some(x), Some(r), Some(g), Some(b)) = (
1597                attr_f32(trimmed, "x"),
1598                attr_f32(trimmed, "r"),
1599                attr_f32(trimmed, "g"),
1600                attr_f32(trimmed, "b"),
1601            ) {
1602                let a = attr_f32(trimmed, "o").unwrap_or(1.0);
1603                let stop = (
1604                    x,
1605                    [
1606                        (r.clamp(0.0, 1.0) * 255.0 + 0.5) as u8,
1607                        (g.clamp(0.0, 1.0) * 255.0 + 0.5) as u8,
1608                        (b.clamp(0.0, 1.0) * 255.0 + 0.5) as u8,
1609                        (a.clamp(0.0, 1.0) * 255.0 + 0.5) as u8,
1610                    ],
1611                );
1612                current_stops.push(stop);
1613            }
1614        }
1615    }
1616
1617    result
1618}
1619
1620/// Serialize a colourmap to the ParaView XML colourmap format.
1621pub fn export_paraview_xml_colourmap(name: &str, stops: &[(f32, [u8; 4])]) -> String {
1622    let mut out = String::new();
1623    out.push_str("<ColourMaps>\n");
1624    out.push_str(&format!("  <ColourMap name=\"{}\" space=\"RGB\">\n", name));
1625    for &(pos, rgba) in stops {
1626        let r = rgba[0] as f32 / 255.0;
1627        let g = rgba[1] as f32 / 255.0;
1628        let b = rgba[2] as f32 / 255.0;
1629        let o = rgba[3] as f32 / 255.0;
1630        out.push_str(&format!(
1631            "    <Point x=\"{:.6}\" r=\"{:.6}\" g=\"{:.6}\" b=\"{:.6}\" o=\"{:.6}\"/>\n",
1632            pos, r, g, b, o
1633        ));
1634    }
1635    out.push_str("  </ColourMap>\n");
1636    out.push_str("</ColourMaps>\n");
1637    out
1638}
1639
1640// ---------------------------------------------------------------------------
1641// XML parsing helpers
1642// ---------------------------------------------------------------------------
1643
1644/// Extract the string value of a named XML attribute from a tag line.
1645/// e.g. `attr_value(r#"<Point x="0.5"/>"#, "x")` returns `Some("0.5")`.
1646fn attr_value<'a>(tag: &'a str, name: &str) -> Option<&'a str> {
1647    let search = format!("{}=\"", name);
1648    let start = tag.find(search.as_str())? + search.len();
1649    let end = tag[start..].find('"')? + start;
1650    Some(&tag[start..end])
1651}
1652
1653fn attr_f32(tag: &str, name: &str) -> Option<f32> {
1654    attr_value(tag, name)?.parse().ok()
1655}
1656
1657/// Identifies a colourmap (LUT) uploaded to the GPU.
1658///
1659/// An append-only registry handle. The inner index is public because the
1660/// built-in colourmaps have stable indices a consumer can name directly; the
1661/// registry is never freed, so this stays a plain index.
1662#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1663pub struct ColourmapId(pub usize);