1use std::collections::HashMap;
4
5use glam::Vec3;
6
7#[derive(Debug, Clone)]
9pub struct ColorMap {
10 pub name: String,
12 pub colors: Vec<Vec3>,
14}
15
16impl ColorMap {
17 pub fn new(name: impl Into<String>, colors: Vec<Vec3>) -> Self {
19 Self {
20 name: name.into(),
21 colors,
22 }
23 }
24
25 #[must_use]
27 pub fn sample(&self, t: f32) -> Vec3 {
28 let t = t.clamp(0.0, 1.0);
29
30 if self.colors.is_empty() {
31 return Vec3::ZERO;
32 }
33
34 if self.colors.len() == 1 {
35 return self.colors[0];
36 }
37
38 let n = self.colors.len() - 1;
39 let idx = (t * n as f32).floor() as usize;
40 let idx = idx.min(n - 1);
41 let frac = t * n as f32 - idx as f32;
42
43 self.colors[idx].lerp(self.colors[idx + 1], frac)
44 }
45}
46
47#[derive(Default)]
49pub struct ColorMapRegistry {
50 color_maps: HashMap<String, ColorMap>,
51}
52
53impl ColorMapRegistry {
54 #[must_use]
56 pub fn new() -> Self {
57 let mut registry = Self::default();
58 registry.register_defaults();
59 registry
60 }
61
62 #[allow(clippy::approx_constant)] fn register_defaults(&mut self) {
64 self.register(ColorMap::new(
66 "viridis",
67 vec![
68 Vec3::new(0.267, 0.004, 0.329),
69 Vec3::new(0.282, 0.140, 0.457),
70 Vec3::new(0.253, 0.265, 0.529),
71 Vec3::new(0.206, 0.371, 0.553),
72 Vec3::new(0.163, 0.471, 0.558),
73 Vec3::new(0.127, 0.566, 0.550),
74 Vec3::new(0.134, 0.658, 0.517),
75 Vec3::new(0.266, 0.749, 0.440),
76 Vec3::new(0.477, 0.821, 0.318),
77 Vec3::new(0.741, 0.873, 0.150),
78 Vec3::new(0.993, 0.906, 0.144),
79 ],
80 ));
81
82 self.register(ColorMap::new(
84 "blues",
85 vec![
86 Vec3::new(0.969, 0.984, 1.000),
87 Vec3::new(0.871, 0.922, 0.969),
88 Vec3::new(0.776, 0.859, 0.937),
89 Vec3::new(0.620, 0.792, 0.882),
90 Vec3::new(0.419, 0.682, 0.839),
91 Vec3::new(0.259, 0.573, 0.776),
92 Vec3::new(0.129, 0.443, 0.710),
93 Vec3::new(0.031, 0.318, 0.612),
94 Vec3::new(0.031, 0.188, 0.420),
95 ],
96 ));
97
98 self.register(ColorMap::new(
100 "reds",
101 vec![
102 Vec3::new(1.000, 0.961, 0.941),
103 Vec3::new(0.996, 0.878, 0.824),
104 Vec3::new(0.988, 0.733, 0.631),
105 Vec3::new(0.988, 0.573, 0.447),
106 Vec3::new(0.984, 0.416, 0.290),
107 Vec3::new(0.937, 0.231, 0.173),
108 Vec3::new(0.796, 0.094, 0.114),
109 Vec3::new(0.647, 0.059, 0.082),
110 Vec3::new(0.404, 0.000, 0.051),
111 ],
112 ));
113
114 self.register(ColorMap::new(
116 "coolwarm",
117 vec![
118 Vec3::new(0.230, 0.299, 0.754),
119 Vec3::new(0.552, 0.690, 0.996),
120 Vec3::new(0.866, 0.866, 0.866),
121 Vec3::new(0.956, 0.604, 0.486),
122 Vec3::new(0.706, 0.016, 0.150),
123 ],
124 ));
125
126 self.register(ColorMap::new(
128 "rainbow",
129 vec![
130 Vec3::new(0.5, 0.0, 1.0),
131 Vec3::new(0.0, 0.0, 1.0),
132 Vec3::new(0.0, 1.0, 1.0),
133 Vec3::new(0.0, 1.0, 0.0),
134 Vec3::new(1.0, 1.0, 0.0),
135 Vec3::new(1.0, 0.0, 0.0),
136 ],
137 ));
138 }
139
140 pub fn register(&mut self, color_map: ColorMap) {
142 self.color_maps.insert(color_map.name.clone(), color_map);
143 }
144
145 #[must_use]
147 pub fn get(&self, name: &str) -> Option<&ColorMap> {
148 self.color_maps.get(name)
149 }
150
151 pub fn names(&self) -> impl Iterator<Item = &str> {
153 self.color_maps.keys().map(std::string::String::as_str)
154 }
155}