use crate::brush::bundle::Brush;
use crate::brush::portable::PortableBrush;
include!(concat!(env!("OUT_DIR"), "/builtin_brushes_gen.rs"));
pub fn all() -> Vec<Brush> {
let registry = crate::brush::registry();
BUILTIN_BRUSHES_YAML
.iter()
.map(|(filename, yaml)| {
let portable: PortableBrush = serde_yaml_ng::from_str(yaml)
.unwrap_or_else(|e| panic!("invalid built-in brush '{filename}': {e}"));
portable
.into_brush(registry)
.unwrap_or_else(|e| panic!("invalid built-in brush '{filename}': {e}"))
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builtin_brushes_compile() {
for brush in all() {
let result = crate::brush::compile_graph(&brush.metadata.graph);
assert!(
result.is_ok(),
"brush '{}' failed to compile: {:?}",
brush.metadata.name,
result.err(),
);
}
}
#[test]
fn builtin_brushes_round_trip() {
for brush in all() {
let name = brush.metadata.name.clone();
let bytes = brush.to_bytes().unwrap();
let loaded = Brush::from_bytes(&bytes).unwrap();
assert_eq!(loaded.metadata.name, name);
}
}
#[test]
fn builtin_brushes_no_overlapping_nodes() {
for brush in all() {
let layout = brush.metadata.graph.auto_layout();
let positions: Vec<[i32; 2]> = layout
.values()
.map(|p| [p[0] as i32, p[1] as i32])
.collect();
for (i, a) in positions.iter().enumerate() {
for b in &positions[i + 1..] {
assert_ne!(
a, b,
"brush '{}' has overlapping nodes at {:?}",
brush.metadata.name, a,
);
}
}
}
}
#[test]
fn builtin_brushes_unique_names() {
let brushes = all();
let mut names: Vec<_> = brushes.iter().map(|b| b.metadata.name.clone()).collect();
names.sort();
names.dedup();
assert_eq!(names.len(), brushes.len(), "duplicate brush names");
}
#[test]
fn liquify_brush_has_tight_spacing() {
let brush = all()
.into_iter()
.find(|b| b.metadata.name == "Liquify")
.expect("Liquify built-in must exist");
let pen = brush
.metadata
.graph
.nodes()
.values()
.find(|n| n.type_id == crate::brush::nodes::pen_input::TYPE_ID)
.expect("liquify brush has a pen_input node");
let spacing = pen
.ports
.iter()
.find(|p| p.name == "spacing")
.expect("pen_input has a spacing port");
assert!(
spacing.default <= 0.05,
"liquify spacing default is {}, expected <= 5% for smooth warps",
spacing.default
);
}
}