diff --git a/src/canvas.rs b/src/canvas.rs index 7678287..4aed98f 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -43,6 +43,7 @@ impl Canvas { objects: HashMap::new(), name: name.to_string(), _render_cache: None, + hidden: false, }) .collect(), ..Self::default_settings() @@ -233,6 +234,7 @@ impl Canvas { name: name.to_string(), objects, _render_cache: None, + hidden: false, } } @@ -267,6 +269,7 @@ impl Canvas { name: layer_name.to_owned(), objects, _render_cache: None, + hidden: false, } } @@ -512,7 +515,7 @@ impl Canvas { ) } - pub fn render(&mut self, layers: &Vec<&str>, render_background: bool) -> Result { + pub fn render(&mut self, render_background: bool) -> Result { let background_color = self.background.unwrap_or_default(); let mut svg = svg::Document::new(); if render_background { @@ -525,12 +528,7 @@ impl Canvas { .set("fill", background_color.render(&self.colormap)), ); } - for layer in self - .layers - .iter_mut() - .filter(|layer| layers.contains(&"*") || layers.contains(&layer.name.as_str())) - .rev() - { + for layer in self.layers.iter_mut().filter(|layer| !layer.hidden).rev() { svg = svg.add(layer.render(self.colormap.clone(), self.cell_size, layer.object_sizes)); } diff --git a/src/layer.rs b/src/layer.rs index a41e17b..e303a50 100644 --- a/src/layer.rs +++ b/src/layer.rs @@ -1,4 +1,4 @@ -use crate::{ColorMapping, ColoredObject, Fill, Filter, ObjectSizes, Region}; +use crate::{ColorMapping, ColoredObject, Fill, Filter, ObjectSizes, Region, Toggleable}; use std::{collections::HashMap, fmt::Display}; #[derive(Debug, Clone, Default)] @@ -7,6 +7,7 @@ pub struct Layer { pub object_sizes: ObjectSizes, pub objects: HashMap, pub name: String, + pub hidden: bool, pub _render_cache: Option, } @@ -17,9 +18,22 @@ impl Layer { objects: HashMap::new(), name: name.to_string(), _render_cache: None, + hidden: false, } } + pub fn hide(&mut self) { + self.hidden = true; + } + + pub fn show(&mut self) { + self.hidden = false; + } + + pub fn toggle(&mut self) { + self.hidden.toggle(); + } + pub fn object(&mut self, name: &str) -> &mut ColoredObject { self.objects.get_mut(name).unwrap() } diff --git a/src/lib.rs b/src/lib.rs index 58854f4..d1ed0f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -190,5 +190,15 @@ impl<'a, C> Context<'a, C> { } } +trait Toggleable { + fn toggle(&mut self); +} + +impl Toggleable for bool { + fn toggle(&mut self) { + *self = !*self; + } +} + #[allow(unused)] fn main() {} diff --git a/src/main.rs b/src/main.rs index 4e6fadc..b1826be 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ pub fn run(args: cli::Args) -> Result<()> { if args.cmd_image && !args.cmd_video { canvas = examples::dna_analysis_machine(); - let rendered = canvas.render(&vec!["*"], true)?; + let rendered = canvas.render(true)?; if args.arg_file.ends_with(".svg") { std::fs::write(args.arg_file, rendered).unwrap(); } else { diff --git a/src/objects.rs b/src/objects.rs index 8c94565..0c4cdb1 100644 --- a/src/objects.rs +++ b/src/objects.rs @@ -62,11 +62,15 @@ impl ColoredObject { colormap: &ColorMapping, id: &str, ) -> svg::node::element::Group { - let group = self.object.render(cell_size, object_sizes, id); + let mut group = self.object.render(cell_size, object_sizes, id); - let rendered_transforms = self + match self .transformations - .render_attribute(colormap, !self.object.fillable()); + .render_attribute(colormap, !self.object.fillable()) + { + (key, _) if key.is_empty() => (), + (key, value) => group = group.set(key, value), + } let mut css = String::new(); if !matches!(self.object, Object::RawSVG(..)) { @@ -81,9 +85,7 @@ impl ColoredObject { .join(" ") .as_ref(); - group - .set("style", css) - .set(rendered_transforms.0, rendered_transforms.1) + group.set("style", css) } } @@ -177,9 +179,8 @@ impl RenderAttribute for Vec { fn render_fill_attribute(&self, colormap: &ColorMapping) -> (String, String) { ( self.first() - .unwrap() - .render_fill_attribute(colormap) - .0 + .map(|v| v.render_fill_attribute(colormap).0) + .unwrap_or_default() .clone(), self.iter() .map(|v| v.render_fill_attribute(colormap).1.clone()) @@ -190,9 +191,8 @@ impl RenderAttribute for Vec { fn render_stroke_attribute(&self, colormap: &ColorMapping) -> (String, String) { ( self.first() - .unwrap() - .render_stroke_attribute(colormap) - .0 + .map(|v| v.render_stroke_attribute(colormap).0) + .unwrap_or_default() .clone(), self.iter() .map(|v| v.render_stroke_attribute(colormap).1.clone()) diff --git a/src/video.rs b/src/video.rs index 6dcaa50..3eabd2c 100644 --- a/src/video.rs +++ b/src/video.rs @@ -18,7 +18,8 @@ use crate::{ preview, sync::SyncData, ui::{self, setup_progress_bar, Log as _}, - Canvas, ColoredObject, Context, MidiSynchronizer, MusicalDurationUnit, Syncable, + Canvas, ColoredObject, Context, LayerAnimationUpdateFunction, MidiSynchronizer, + MusicalDurationUnit, Syncable, }; pub type BeatNumber = usize; @@ -449,6 +450,23 @@ impl Video { Self { commands, ..self } } + pub fn bind_amplitude( + self, + layer: &'static str, + stem: &'static str, + update: &'static LayerAnimationUpdateFunction, + ) -> Self { + self.with_hook(Hook { + when: Box::new(move |_, _, _, _| true), + render_function: Box::new(move |canvas, context| { + let amplitude = context.stem(stem).amplitude_relative(); + update(amplitude, canvas.layer(layer), context.ms)?; + canvas.layer(layer).flush(); + Ok(()) + }), + }) + } + pub fn total_frames(&self) -> usize { self.fps * (self.duration_ms() + self.start_rendering_at) / 1000 } @@ -470,7 +488,7 @@ impl Video { let mut rendered_frames: HashMap = HashMap::new(); let progress_bar = self.setup_progress_bar(); - for (frame, _, ms) in self.render_frames(&progress_bar, vec!["*"], true)? { + for (frame, _, ms) in self.render_frames(&progress_bar, true)? { rendered_frames.insert(ms, frame); } @@ -493,7 +511,7 @@ impl Video { workers_count: usize, preview_only: bool, ) -> Result<()> { - self.render_composition(output_file, vec!["*"], true, workers_count, preview_only) + self.render(output_file, true, workers_count, preview_only) } pub fn render_layers_in(&self, output_directory: String, workers_count: usize) -> Result<()> { @@ -503,9 +521,8 @@ impl Video { .iter() .map(|l| vec![l.name.as_str()]) { - self.render_composition( + self.render( format!("{}/{}.mov", output_directory, composition.join("+")), - composition, false, workers_count, false, @@ -518,7 +535,6 @@ impl Video { pub fn render_frames( &self, progress_bar: &ProgressBar, - composition: Vec<&str>, render_background: bool, ) -> Result> { let mut context = Context { @@ -611,7 +627,7 @@ impl Video { } if context.frame != previous_rendered_frame { - let rendered = canvas.render(&composition, render_background)?; + let rendered = canvas.render(render_background)?; previous_rendered_beat = context.beat; previous_rendered_frame = context.frame; @@ -627,10 +643,9 @@ impl Video { ui::setup_progress_bar(self.total_frames() as u64, "Rendering") } - pub fn render_composition( + pub fn render( &self, output_file: String, - composition: Vec<&str>, render_background: bool, workers_count: usize, _preview_only: bool, @@ -651,9 +666,7 @@ impl Video { self.progress_bar.set_prefix("Rendering"); self.progress_bar.set_message(""); - for (frame, no, ms) in - self.render_frames(&self.progress_bar, composition, render_background)? - { + for (frame, no, ms) in self.render_frames(&self.progress_bar, render_background)? { frames_to_write.push((frame, no, ms)); } @@ -697,7 +710,8 @@ impl Video { frames_output_directory, aspect_ratio, resolution, - ).unwrap(); + ) + .unwrap(); progress_bar.inc(1); } }) diff --git a/src/web.rs b/src/web.rs index 86ed0e2..56c4cff 100644 --- a/src/web.rs +++ b/src/web.rs @@ -65,13 +65,13 @@ pub fn map_to_midi_controller() {} #[wasm_bindgen] pub fn render_canvas_into(selector: String) -> () { - let svgstring = canvas().render(&vec!["*"], false).unwrap_throw(); + let svgstring = canvas().render(false).unwrap_throw(); append_new_div_inside(svgstring, selector) } #[wasm_bindgen] pub fn render_canvas_at(selector: String) -> () { - let svgstring = canvas().render(&vec!["*"], false).unwrap_throw(); + let svgstring = canvas().render(false).unwrap_throw(); replace_content_with(svgstring, selector) } @@ -135,15 +135,9 @@ impl From<(MidiEvent, MidiEventData)> for MidiMessage { } #[wasm_bindgen] -pub fn render_canvas(layers_pattern: Option, render_background: Option) -> () { +pub fn render_canvas(render_background: Option) -> () { canvas() - .render( - &match layers_pattern { - Some(ref pattern) => vec![pattern], - None => vec!["*"], - }, - render_background.unwrap_or(false), - ) + .render(render_background.unwrap_or(false)) .unwrap_throw(); } @@ -214,7 +208,7 @@ pub struct LayerWeb { #[wasm_bindgen] impl LayerWeb { pub fn render(&self) -> String { - canvas().render(&vec![&self.name], false).unwrap_throw() + canvas().render(false).unwrap_throw() } pub fn render_into(&self, selector: String) -> () {