experimental SVG-based video rendering engine made for music videos. React to MIDI or arbitrary signals from your DAW through "probe" VSTs
at main 3.3 kB view raw
1use super::svg; 2use crate::{ColorMapping, graphics::objects::ObjectSizes}; 3use anyhow::Result; 4use itertools::Itertools; 5use std::collections::HashMap; 6 7/// Struct can be rendered as a SVG element 8pub trait SVGRenderable { 9 fn render_to_svg( 10 &self, 11 colormap: ColorMapping, 12 cell_size: usize, 13 object_sizes: ObjectSizes, 14 id: &str, 15 ) -> Result<svg::Node>; 16} 17 18/// Struct can be rendered as attributes of a SVG element 19pub trait SVGAttributesRenderable { 20 /// When merging multiple SVGAttributesRenderable, this string is used to join multiple values for the same key 21 const MULTIPLE_VALUES_JOIN_BY: &'static str = ", "; 22 23 fn render_to_svg_attributes( 24 &self, 25 colormap: ColorMapping, 26 cell_size: usize, 27 object_sizes: ObjectSizes, 28 id: &str, 29 ) -> Result<HashMap<String, String>>; 30} 31 32/// Struct can be rendered as a CSS ruleset (e.g. no selectors) 33pub trait CSSRenderable { 34 fn render_to_css_filled(&self, colormap: &ColorMapping) -> String; 35 fn render_to_css_stroked(&self, colormap: &ColorMapping) -> String; 36 fn render_to_css( 37 &self, 38 colormap: &ColorMapping, 39 fill_as_stroke_color: bool, 40 ) -> String { 41 if fill_as_stroke_color { 42 self.render_to_css_stroked(colormap) 43 } else { 44 self.render_to_css_filled(colormap) 45 } 46 } 47} 48 49impl<T: CSSRenderable, V: Clone + IntoIterator<Item = T>> CSSRenderable for V { 50 fn render_to_css_filled(&self, colormap: &ColorMapping) -> String { 51 self.clone() 52 .into_iter() 53 .map(|v| v.render_to_css_filled(colormap)) 54 .join("\n") 55 } 56 57 fn render_to_css_stroked(&self, colormap: &ColorMapping) -> String { 58 self.clone() 59 .into_iter() 60 .map(|v| v.render_to_css_stroked(colormap)) 61 .join("\n") 62 } 63} 64 65// We get the Option<T> implementation for free since Option<T> implements IntoIterator, and it works: 66// None => empty iterator => empty hashmap, 67// Some(T) => iterator with one element => one hashmap, no merging. 68// I love Rust <3. 69 70impl<T, V> SVGAttributesRenderable for V 71where 72 T: SVGAttributesRenderable, 73 V: Clone + IntoIterator<Item = T>, 74{ 75 fn render_to_svg_attributes( 76 &self, 77 colormap: ColorMapping, 78 cell_size: usize, 79 object_sizes: ObjectSizes, 80 id: &str, 81 ) -> Result<HashMap<String, String>> { 82 let mut attrs = HashMap::<String, String>::new(); 83 for attrmap in self.clone().into_iter().map(|v| { 84 v.render_to_svg_attributes( 85 colormap.clone(), 86 cell_size, 87 object_sizes, 88 id, 89 ) 90 .unwrap() 91 }) { 92 for (key, value) in attrmap { 93 if attrs.contains_key(&key) { 94 attrs.insert( 95 key.clone(), 96 format!( 97 "{}{}{}", 98 attrs[&key], 99 T::MULTIPLE_VALUES_JOIN_BY, 100 value 101 ), 102 ); 103 } else { 104 attrs.insert(key, value); 105 } 106 } 107 } 108 Ok(attrs) 109 } 110}