use crate::ramp::{Spread, texels};
use std::env;
use std::fmt::Write as _;
use std::fs;
use std::path::{Path, PathBuf};
pub(crate) fn generate() {
let manifest = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let catalog = fs::read_to_string(manifest.join("colormaps/catalog.txt")).unwrap();
let mut entries = String::new();
let mut consts = String::new();
let mut names = Vec::new();
for (index, line) in catalog.lines().filter(|l| !l.trim().is_empty()).enumerate() {
let (head, hex) = line.split_once('|').expect("name kind label|colors");
let mut words = head.splitn(3, ' ');
let (name, kind, label) = (words.next().unwrap(), words.next().unwrap(), words.next().unwrap());
let colors: Vec<[u8; 3]> = hex
.as_bytes()
.as_chunks::<6>()
.0
.iter()
.map(|digits| {
let byte =
|at: usize| u8::from_str_radix(std::str::from_utf8(&digits[at..at + 2]).unwrap(), 16).unwrap();
[byte(0), byte(2), byte(4)]
})
.collect();
let (kind, spread) = match kind {
"sequential" | "multihue" => ("Sequential", Spread::Continuous),
"diverging" => ("Diverging", Spread::Continuous),
"cyclic" => ("Cyclic", Spread::Cyclic),
"categorical" => ("Categorical", Spread::Categorical),
other => panic!("unknown colormap kind {other}"),
};
let stops: Vec<_> =
colors.iter().map(|c| (None, [c[0], c[1], c[2], 255].map(|b| f32::from(b) / 255.0))).collect();
let texels: Vec<String> = texels(spread, &stops).iter().map(|t| format!("{t:?}")).collect();
writeln!(
entries,
" Entry {{ name: {name:?}, label: {label:?}, kind: ColormapKind::{kind}, count: {}, texels: [{}] }},",
colors.len(),
texels.join(", ")
)
.unwrap();
let doc = format!("/// {label}, a {} colormap.", kind.to_lowercase());
writeln!(
consts,
" {doc}\n pub const {}: Colormap = Colormap(Map::Catalog({index}));",
name.to_uppercase()
)
.unwrap();
names.push(format!("{name:?}"));
}
let count = names.len();
let rust = format!(
"// Generated by build/colormaps.rs from colormaps/catalog.txt. Do not edit.\n\n\
static CATALOG: [Entry; {count}] = [\n{entries}];\n\n\
#[allow(clippy::doc_markdown, reason = \"the docs name colormaps by their labels\")]\n\
impl Colormap {{\n{consts}\n /// The names of every colormap in the catalog.\n pub const NAMES: [&'static str; {count}] = [{}];\n}}\n",
names.join(", ")
);
let out = PathBuf::from(env::var("OUT_DIR").unwrap());
fs::write(out.join("colormaps.rs"), rust).unwrap();
println!("cargo::rerun-if-changed={}", Path::new("colormaps").display());
}