This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

🚸 General API improvements

+108 -41
+12 -3
examples/dna-analysis-machine/src/main.rs
··· 1 1 use itertools::Itertools; 2 - use rand::{SeedableRng, Rng}; 2 + use rand::{Rng, SeedableRng}; 3 3 use shapemaker::*; 4 4 5 5 fn artwork() -> Canvas { ··· 29 29 Region::from_bottomleft(draw_in.bottomleft().translated(2, -1), (3, 3)) 30 30 .unwrap(); 31 31 32 - canvas.n_random_curves_within(&mut rng, &strands_in, 30, "strands"); 32 + let strands = 33 + canvas.n_random_curves_within(&mut rng, &strands_in, 30, "strands"); 34 + 35 + canvas.add_layer(strands); 33 36 34 - for (i, (_key, obj)) in canvas.layer("strands").objects.iter_mut().sorted_by_key(|(k, _)| *k).enumerate() { 37 + for (i, (_key, obj)) in canvas 38 + .layer("strands") 39 + .objects 40 + .iter_mut() 41 + .sorted_by_key(|(k, _)| *k) 42 + .enumerate() 43 + { 35 44 obj.recolor(if i % 2 == 0 { Cyan } else { Pink }); 36 45 obj.filter(Filter::glow(4.0)); 37 46 }
+46 -16
examples/schedule-hell/src/main.rs
··· 104 104 Ok(()) 105 105 }) 106 106 .on_note("bass", &|canvas, ctx| { 107 - let new_layer = canvas.random_layer_within( 107 + let pitch = ctx 108 + .notes_of_stem("bass") 109 + .find(|note| note.is_on()) 110 + .map(|note| note.pitch); 111 + 112 + let area = (2, 2); 113 + ctx.extra.bass_pattern_at = match pitch { 114 + Some(32 | 33 | 34) => { 115 + canvas.world_region.starting_from_topleft(area) 116 + } 117 + Some(39) => canvas.world_region.starting_from_topright(area), 118 + Some(35) => canvas.world_region.starting_from_bottomleft(area), 119 + Some(42 | 41) => { 120 + canvas.world_region.starting_from_bottomright(area) 121 + } 122 + _ => canvas.world_region.starting_from_bottomleft(area), 123 + } 124 + .unwrap(); 125 + 126 + let mut bass = canvas.random_layer_within( 108 127 &mut ctx.extra.rng, 109 128 "bass", 110 129 &ctx.extra.bass_pattern_at, 111 130 ); 112 - new_layer.paint_all_objects(Fill::Solid(Color::White)); 131 + 132 + bass.paint_all_objects(Fill::Solid(Color::White)); 133 + canvas.add_or_replace_layer(bass); 134 + 113 135 Ok(()) 114 136 }) 115 137 .on_note("powerful clap hit, clap, perclap", &|canvas, ctx| { 116 - let new_layer = canvas.random_layer_within( 138 + let mut claps = canvas.random_layer_within( 117 139 &mut ctx.extra.rng, 118 140 "claps", 119 141 &ctx.extra.bass_pattern_at.translated(2, 0), 120 142 ); 121 - new_layer.paint_all_objects(Fill::Solid(Color::Red)); 143 + claps.paint_all_objects(Fill::Solid(Color::Red)); 144 + canvas.add_or_replace_layer(claps); 122 145 Ok(()) 123 146 }) 124 147 .on_note( 125 148 "rimshot, glitchy percs, hitting percs, glitchy percs", 126 149 &|canvas, ctx| { 127 - let new_layer = canvas.random_layer_within( 150 + let mut foley = canvas.random_layer_within( 128 151 &mut ctx.extra.rng, 129 152 "percs", 130 153 &ctx.extra.bass_pattern_at.translated(2, 0), 131 154 ); 132 - new_layer.paint_all_objects(Fill::Translucent(Color::Red, 0.5)); 155 + foley.paint_all_objects(Fill::Translucent(Color::Red, 0.5)); 156 + canvas.add_or_replace_layer(foley); 133 157 Ok(()) 134 158 }, 135 159 ) 136 160 .on_note("qanda", &|canvas, ctx| { 137 161 let canvas_line_width = canvas.object_sizes.default_line_width; 138 - let new_layer = canvas.random_curves_within( 162 + let mut qanda = canvas.random_curves_within( 139 163 &mut ctx.extra.rng, 140 164 "qanda", 141 165 &ctx.extra.bass_pattern_at.translated(-1, -1).enlarged(1, 1), 142 166 3..=5, 143 167 ); 144 - new_layer.paint_all_objects(Fill::Solid(Color::Orange)); 145 - new_layer.object_sizes.default_line_width = 168 + qanda.paint_all_objects(Fill::Solid(Color::Orange)); 169 + qanda.object_sizes.default_line_width = 146 170 canvas_line_width * 4.0 * ctx.stem("qanda").velocity_relative(); 171 + 172 + canvas.add_or_replace_layer(qanda); 147 173 Ok(()) 148 174 }) 149 175 .on_note("brokenup", &|canvas, ctx| { 150 176 let canvas_line_width = canvas.object_sizes.default_line_width; 151 - let new_layer = canvas.random_curves_within( 177 + let mut brokenup = canvas.random_curves_within( 152 178 &mut ctx.extra.rng, 153 179 "brokenup", 154 180 &ctx.extra.bass_pattern_at.translated(0, -2), 155 181 3..=5, 156 182 ); 157 - new_layer.paint_all_objects(Fill::Solid(Color::Yellow)); 158 - new_layer.object_sizes.default_line_width = canvas_line_width 183 + brokenup.paint_all_objects(Fill::Solid(Color::Yellow)); 184 + brokenup.object_sizes.default_line_width = canvas_line_width 159 185 * 4.0 160 186 * ctx.stem("brokenup").velocity_relative(); 187 + 188 + canvas.add_or_replace_layer(brokenup); 161 189 Ok(()) 162 190 }) 163 191 .on_note("goup", &|canvas, ctx| { 164 192 let canvas_line_width = canvas.object_sizes.default_line_width; 165 - let new_layer = canvas.random_curves_within( 193 + let mut goup = canvas.random_curves_within( 166 194 &mut ctx.extra.rng, 167 195 "goup", 168 196 &ctx.extra.bass_pattern_at.translated(0, 2), 169 197 3..=5, 170 198 ); 171 - new_layer.paint_all_objects(Fill::Solid(Color::Green)); 172 - new_layer.object_sizes.default_line_width = 199 + goup.paint_all_objects(Fill::Solid(Color::Green)); 200 + goup.object_sizes.default_line_width = 173 201 canvas_line_width * 4.0 * ctx.stem("goup").velocity_relative(); 202 + 203 + canvas.add_or_replace_layer(goup); 174 204 Ok(()) 175 205 }) 176 206 .on_note("ch", &|canvas, ctx| { ··· 210 240 "credits text", 211 241 Object::Text( 212 242 world.start.translated(2, 2), 213 - "by ewen-lbh".into(), 243 + "Postamble / Schedule Hell".into(), 214 244 12.0, 215 245 ) 216 246 .colored(Color::White),
+27 -7
src/geometry/region.rs
··· 209 209 ) 210 210 } 211 211 212 + pub fn starting_from_topleft(&self, size: (usize, usize)) -> Result<Self> { 213 + Self::from_topleft(self.start, size) 214 + } 215 + 212 216 pub fn from_bottomleft(origin: Point, size: (usize, usize)) -> Result<Self> { 213 217 Self::from_topleft(origin.translated(0, -(size.1 as i32 - 1)), size) 214 218 } 215 219 220 + pub fn starting_from_bottomleft(&self, size: (usize, usize)) -> Result<Self> { 221 + Self::from_bottomleft(self.bottomleft(), size) 222 + } 223 + 216 224 pub fn from_bottomright(origin: Point, size: (usize, usize)) -> Result<Self> { 217 225 Self::from_points( 218 - origin.translated_by(Point::from(size).translated(-1, -1)), 226 + origin.translated(-(size.0 as i32 - 1), -(size.1 as i32 - 1)), 219 227 origin, 220 228 ) 229 + } 230 + 231 + pub fn starting_from_bottomright( 232 + &self, 233 + size: (usize, usize), 234 + ) -> Result<Self> { 235 + Self::from_bottomright(self.bottomright(), size) 221 236 } 222 237 223 238 pub fn from_topright(origin: Point, size: (usize, usize)) -> Result<Self> { 224 239 Self::from_topleft(origin.translated(-(size.0 as i32 - 1), 0), size) 225 240 } 226 241 242 + pub fn starting_from_topright(&self, size: (usize, usize)) -> Result<Self> { 243 + Self::from_topright(self.topright(), size) 244 + } 245 + 227 246 pub fn from_center_and_size( 228 247 center: Point, 229 248 size: (usize, usize), ··· 270 289 } 271 290 272 291 /// adds dx and dy to the end of the region (dx and dy are _not_ multiplicative but **additive** factors) 273 - pub fn enlarged(&self, dx: i32, dy: i32) -> Self { 292 + pub fn enlarged(&self, add_x: i32, add_y: i32) -> Self { 274 293 let resulting = Self { 275 294 start: self.start, 276 295 end: ( 277 - (self.end.0 as i32 + dx) as usize, 278 - (self.end.1 as i32 + dy) as usize, 296 + (self.end.0 as i32 + add_x) as usize, 297 + (self.end.1 as i32 + add_y) as usize, 279 298 ) 280 299 .into(), 281 300 }; ··· 283 302 if resulting.ensure_valid().is_err() { 284 303 let bt = Backtrace::new(); 285 304 println!( 286 - "WARN: Did not enlarge region {self} with ({dx}, {dy}), it would result in a non-valid region\n{bt:?}" 305 + "WARN: Did not enlarge region {self} with ({add_x}, {add_y}), it would result in a non-valid region\n{bt:?}" 287 306 ); 288 307 return *self; 289 308 } ··· 292 311 } 293 312 294 313 /// resized is like enlarged, but transforms from the center, by first translating the region by (-dx, -dy) 295 - pub fn resized(&self, dx: i32, dy: i32) -> Self { 296 - self.translated(-dx / 2, -dy / 2).enlarged(dx, dy) 314 + pub fn resized(&self, add_x: i32, add_y: i32) -> Self { 315 + self.translated(-add_x / 2, -add_y / 2) 316 + .enlarged(add_x, add_y) 297 317 } 298 318 299 319 pub fn x_range(&self) -> std::ops::RangeInclusive<usize> {
+1 -1
src/graphics/canvas.rs
··· 180 180 assert!(new_order.iter().all(|name| self.layer_exists(name))); 181 181 182 182 self.layers.sort_by_key(|o| { 183 - new_order.iter().position(|&n| n == o.name).unwrap_or( 183 + new_order.iter().position(|n| *n == o.name).unwrap_or( 184 184 current_order.iter().position(|n| *n == o.name).unwrap(), 185 185 ) 186 186 });
+2 -2
src/graphics/layer.rs
··· 156 156 layer.add_anon(self); 157 157 } 158 158 159 - pub fn add_named_to(self, name: impl Display, layer: &mut Layer) { 160 - layer.add(name, self); 159 + pub fn set_in(self, layer: &mut Layer, name: impl Display) { 160 + layer.set(name, self); 161 161 } 162 162 }
+11 -11
src/random/canvas.rs
··· 3 3 use std::collections::HashMap; 4 4 5 5 impl Canvas { 6 - pub fn random_layer(&mut self, rng: &mut impl Rng, name: &str) -> &mut Layer { 6 + pub fn random_layer(&mut self, rng: &mut impl Rng, name: &str) -> Layer { 7 7 self.random_layer_within(rng, name, &self.world_region.clone()) 8 8 } 9 9 ··· 30 30 region: &Region, 31 31 count: usize, 32 32 layer_name: &str, 33 - ) -> &mut Layer { 33 + ) -> Layer { 34 34 let mut objects: HashMap<String, ColoredObject> = HashMap::new(); 35 35 for i in 0..count { 36 36 let object = Object::random_curve_within( ··· 50 50 )), 51 51 ); 52 52 } 53 - let layer = Layer { 53 + 54 + Layer { 54 55 object_sizes: self.object_sizes, 55 56 name: layer_name.to_owned(), 56 57 objects, 57 58 _render_cache: None, 58 59 hidden: false, 59 - }; 60 - self.add_layer(layer) 60 + } 61 61 } 62 62 63 63 pub fn random_curves_within( ··· 66 66 layer_name: &str, 67 67 region: &Region, 68 68 object_counts: impl SampleRange<usize>, 69 - ) -> &mut Layer { 69 + ) -> Layer { 70 70 let number_of_objects = rng.random_range(object_counts); 71 71 self.n_random_curves_within(rng, region, number_of_objects, layer_name) 72 72 } ··· 76 76 rng: &mut impl Rng, 77 77 name: &str, 78 78 region: &Region, 79 - ) -> &mut Layer { 79 + ) -> Layer { 80 80 let mut objects: HashMap<String, ColoredObject> = HashMap::new(); 81 81 let number_of_objects = 82 82 rng.random_range(self.objects_count_range.clone()); ··· 97 97 }), 98 98 ); 99 99 } 100 - let layer = Layer { 100 + 101 + Layer { 101 102 object_sizes: self.object_sizes, 102 103 name: name.to_string(), 103 104 objects, 104 105 _render_cache: None, 105 106 hidden: false, 106 - }; 107 - self.add_layer(layer) 107 + } 108 108 } 109 109 110 110 pub fn random_linelikes( 111 111 &mut self, 112 112 rng: &mut impl Rng, 113 113 layer_name: &str, 114 - ) -> &mut Layer { 114 + ) -> Layer { 115 115 self.random_curves_within( 116 116 rng, 117 117 layer_name,
+9 -1
src/video/context.rs
··· 1 1 use super::animation::{AnimationUpdateFunction, LayerAnimationUpdateFunction}; 2 2 use super::engine::{LaterHook, LaterRenderFunction}; 3 3 use super::Animation; 4 - use crate::synchronization::audio::StemAtInstant; 4 + use crate::synchronization::audio::{Note, StemAtInstant}; 5 5 use crate::synchronization::sync::SyncData; 6 6 use itertools::Itertools; 7 7 use nanoid::nanoid; ··· 50 50 duration: stems[name].duration_ms, 51 51 notes: stems[name].notes.get(&self.ms).cloned().unwrap_or(vec![]), 52 52 } 53 + } 54 + 55 + pub fn notes_of_stem(&self, name: &str) -> impl Iterator<Item = Note> + '_ { 56 + let stem = &self.syncdata.stems[name]; 57 + stem.notes 58 + .get(&self.ms) 59 + .into_iter() 60 + .flat_map(|notes| notes.iter().cloned()) 53 61 } 54 62 55 63 pub fn dump_syncdata(&self, to: PathBuf) -> anyhow::Result<()> {