experimental SVG-based video rendering engine made for music videos. React to MIDI or arbitrary signals from your DAW through "probe" VSTs
at main 2.9 kB view raw
1use itertools::Itertools; 2use measure_time::debug_time; 3 4use crate::{Fill, Object, Shape}; 5 6use super::{ 7 CSSRenderable, SVGAttributesRenderable, renderable::SVGRenderable, svg, 8}; 9 10impl SVGRenderable for Object { 11 fn render_to_svg( 12 &self, 13 colormap: crate::ColorMapping, 14 cell_size: usize, 15 object_sizes: crate::graphics::objects::ObjectSizes, 16 id: &str, 17 ) -> anyhow::Result<svg::Node> { 18 debug_time!("render_to_svg/colored_object"); 19 20 let plain_obj = match &self.shape { 21 Shape::RawSVG { .. } => self.render_raw_svg(&colormap), 22 _ => self.shape.render_to_svg( 23 colormap.clone(), 24 cell_size, 25 object_sizes, 26 id, 27 )?, 28 }; 29 30 let mut css = self 31 .fill 32 .render_to_css(&colormap.clone(), !self.shape.fillable()); 33 34 let object_svg = if !self.transformations.is_empty() 35 || !self.filters.is_empty() 36 { 37 // transform-box is not supported by resvg yet 38 // css += "transform-box: fill-box; transform-origin: 50% 50%;"; 39 40 let (center_x, center_y) = 41 self.shape.region().center_coords(cell_size); 42 43 css += &format!("transform-origin: {center_x}px {center_y}px;"); 44 45 css += self 46 .filters 47 .iter() 48 .map(|f| f.render_to_css_filled(&colormap)) 49 .join(" ") 50 .as_ref(); 51 52 svg::tag("g") 53 .dataset("object", id) 54 .with_attributes(self.transformations.render_to_svg_attributes( 55 colormap, 56 cell_size, 57 object_sizes, 58 id, 59 )?) 60 .wrapping(vec![plain_obj]) 61 .attr("style", &css) 62 .into() 63 } else { 64 match plain_obj { 65 svg::Node::Element(el) => el.attr("style", &css).into(), 66 _ => plain_obj, 67 } 68 }; 69 70 if let Some(region) = &self.clip_to { 71 Ok(svg::tag("g") 72 .attr("clip-path", region.clip_path_id()) 73 .child(object_svg) 74 .into()) 75 } else { 76 Ok(object_svg) 77 } 78 } 79} 80 81impl Object { 82 fn render_raw_svg(&self, colormap: &crate::ColorMapping) -> svg::Node { 83 if let Shape::RawSVG { content, color } = &self.shape { 84 let filled_svg = match &self.fill { 85 Some(Fill::Solid(fill_color)) => { 86 content.replace(color, &fill_color.render(colormap)) 87 } 88 _ => content.clone(), 89 }; 90 91 svg::Node::SVG(filled_svg) 92 } else { 93 panic!("Called render_raw_svg on a non-RawSVG shape"); 94 } 95 } 96}