this repo has no description
3
fork

Configure Feed

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

🚧 Continue schedule hell clip

authored by

Gwenn Le Bihan and committed by
Ewen Le Bihan
80382dce e3f6aa61

+165 -22
+70 -2
src/canvas.rs
··· 15 15 pub end: (usize, usize), 16 16 } 17 17 18 + impl From<((usize, usize), (usize, usize))> for Region { 19 + fn from(value: ((usize, usize), (usize, usize))) -> Self { 20 + Region { 21 + start: value.0, 22 + end: value.1, 23 + } 24 + } 25 + } 26 + 27 + impl From<(&Anchor, &Anchor)> for Region { 28 + fn from(value: (&Anchor, &Anchor)) -> Self { 29 + Region { 30 + start: (value.0 .0 as usize, value.0 .1 as usize), 31 + end: (value.1 .0 as usize, value.1 .1 as usize), 32 + } 33 + } 34 + } 35 + 36 + impl From<(&CenterAnchor, &CenterAnchor)> for Region { 37 + fn from(value: (&CenterAnchor, &CenterAnchor)) -> Self { 38 + Region { 39 + start: (value.0 .0 as usize, value.0 .1 as usize), 40 + end: (value.1 .0 as usize, value.1 .1 as usize), 41 + } 42 + } 43 + } 44 + 18 45 impl std::ops::Sub for Region { 19 46 type Output = (i32, i32); 20 47 ··· 43 70 }; 44 71 region.ensure_valid(); 45 72 region 73 + } 74 + 75 + pub fn max<'a>(&'a self, other: &'a Region) -> &'a Region { 76 + if self.within(other) { 77 + other 78 + } else { 79 + self 80 + } 46 81 } 47 82 48 83 pub fn from_origin(end: (usize, usize)) -> Self { ··· 270 305 self.random_object_within(&self.world_region) 271 306 } 272 307 273 - pub fn replace_or_create_layer(&mut self, name: &'static str, layer: Layer) { 274 - if let Some(existing_layer) = self.layer(name) { 308 + pub fn replace_or_create_layer(&mut self, layer: Layer) { 309 + if let Some(existing_layer) = self.layer(&layer.name) { 275 310 existing_layer.replace(layer); 276 311 } else { 277 312 self.layers.push(layer); ··· 590 625 anchor.translate(dx, dy) 591 626 } 592 627 Object::BigCircle(center) => center.translate(dx, dy), 628 + Object::RawSVG(_) => { 629 + unimplemented!() 630 + } 631 + } 632 + } 633 + 634 + pub fn translate_with(&mut self, delta: (i32, i32)) { 635 + self.translate(delta.0, delta.1) 636 + } 637 + 638 + pub fn region(&self) -> Region { 639 + match self { 640 + Object::Polygon(start, lines) => { 641 + let mut region: Region = (start, start).into(); 642 + for line in lines { 643 + match line { 644 + LineSegment::InwardCurve(anchor) 645 + | LineSegment::OutwardCurve(anchor) 646 + | LineSegment::Straight(anchor) => { 647 + region = *region.max(&(start, anchor).into()) 648 + } 649 + } 650 + } 651 + region 652 + } 653 + Object::Line(start, end) 654 + | Object::CurveInward(start, end) 655 + | Object::CurveOutward(start, end) 656 + | Object::Rectangle(start, end) => (start, end).into(), 657 + Object::Text(anchor, _) | Object::Dot(anchor) | Object::SmallCircle(anchor) => { 658 + (anchor, anchor).into() 659 + } 660 + Object::BigCircle(center) => (center, center).into(), // FIXME will be wrong lmao, 593 661 Object::RawSVG(_) => { 594 662 unimplemented!() 595 663 }
+9 -1
src/layer.rs
··· 70 70 let mut layer_group = svg::node::element::Group::new() 71 71 .set("class", "layer") 72 72 .set("data-layer", self.name.clone()); 73 - for (_id, (object, maybe_fill)) in &self.objects { 73 + for (id, (object, maybe_fill)) in &self.objects { 74 74 let mut group = svg::node::element::Group::new(); 75 + group = group.set("data-object", id.clone()); 75 76 match object { 76 77 Object::RawSVG(svg) => { 77 78 // eprintln!("render: raw_svg [{}]", id); ··· 306 307 // TODO 307 308 Some(Fill::Solid(color)) => { 308 309 format!("fill: {};", color.to_string(&colormap)) 310 + } 311 + Some(Fill::Translucent(color, opacity)) => { 312 + format!( 313 + "fill: {}; opacity: {};", 314 + color.to_string(&colormap), 315 + opacity 316 + ) 309 317 } 310 318 _ => format!( 311 319 "fill: none; stroke: {}; stroke-width: {}px;",
+6 -6
src/lib.rs
··· 35 35 /// Arguments: canvas, context, previous rendered beat, previous rendered frame 36 36 pub type HookCondition<C> = dyn Fn(&Canvas, &Context<C>, usize, usize) -> bool; 37 37 38 - pub type LaterRenderFunction<C> = dyn Fn(&mut Canvas, &Context<C>); 38 + pub type LaterRenderFunction = dyn Fn(&mut Canvas); 39 39 40 40 /// Arguments: canvas, context, previous rendered beat 41 41 pub type LaterHookCondition<C> = dyn Fn(&Canvas, &Context<C>, usize) -> bool; ··· 61 61 62 62 pub struct LaterHook<C> { 63 63 pub when: Box<LaterHookCondition<C>>, 64 - pub render_function: Box<LaterRenderFunction<C>>, 64 + pub render_function: Box<LaterRenderFunction>, 65 65 } 66 66 67 67 impl<C> std::fmt::Debug for Hook<C> { ··· 162 162 } 163 163 } 164 164 165 - pub fn later_frames(&mut self, delay: usize, render_function: &'static LaterRenderFunction<C>) { 165 + pub fn later_frames(&mut self, delay: usize, render_function: &'static LaterRenderFunction) { 166 166 let current_frame = self.frame; 167 167 168 168 self.later_hooks.insert( ··· 176 176 ); 177 177 } 178 178 179 - pub fn later_ms(&mut self, delay: usize, render_function: &'static LaterRenderFunction<C>) { 179 + pub fn later_ms(&mut self, delay: usize, render_function: &'static LaterRenderFunction) { 180 180 let current_ms = self.ms; 181 181 182 182 self.later_hooks.insert( ··· 188 188 ); 189 189 } 190 190 191 - pub fn later_beats(&mut self, delay: f32, render_function: &'static LaterRenderFunction<C>) { 191 + pub fn later_beats(&mut self, delay: f32, render_function: &'static LaterRenderFunction) { 192 192 let current_beat = self.beat; 193 193 194 194 self.later_hooks.insert( ··· 733 733 734 734 for (i, hook) in context.later_hooks.iter().enumerate() { 735 735 if (hook.when)(&canvas, &context, previous_rendered_beat) { 736 - (hook.render_function)(&mut canvas, &context); 736 + (hook.render_function)(&mut canvas); 737 737 later_hooks_to_delete.push(i); 738 738 } 739 739 }
+80 -13
src/main.rs
··· 1 - use shapemaker::{Canvas, Color, Fill, Layer, Object, Region, Video}; 1 + use shapemaker::{Anchor, Canvas, CenterAnchor, Color, Fill, Layer, Object, Region, Video}; 2 2 mod cli; 3 3 pub use cli::{canvas_from_cli, cli_args}; 4 4 ··· 33 33 first_kick_happened: false, 34 34 }; 35 35 canvas.set_background(Color::Black); 36 + 37 + let mut kicks = Layer::new("anchor kick"); 38 + 39 + let fill = Some(Fill::Translucent(Color::White, 0.0)); 40 + let circle_at = |x: usize, y: usize| Object::SmallCircle(Anchor(x as i32, y as i32)); 41 + 42 + let (end_x, end_y) = { 43 + let (x, y) = canvas.world_region.end; 44 + (x - 2, y - 2) 45 + }; 46 + kicks.add_object("top left", circle_at(1, 1), fill); 47 + kicks.add_object("top right", circle_at(end_x, 1), fill); 48 + kicks.add_object("bottom left", circle_at(1, end_y), fill); 49 + kicks.add_object("bottom right", circle_at(end_x, end_y), fill); 50 + canvas.replace_or_create_layer(kicks); 36 51 }) 37 52 .sync_audio_with(&args.flag_sync_with.unwrap()) 38 - .on_note("anchor kick", &|_, ctx| { 53 + .on_note("anchor kick", &|canvas, ctx| { 39 54 // ctx.extra.bass_pattern_at = region_cycle(&canvas.world_region, None); 40 - ctx.extra.first_kick_happened = true; 55 + canvas 56 + .layer("anchor kick") 57 + .unwrap() 58 + .paint_all_objects(Fill::Translucent(Color::White, 1.0)); 59 + 60 + canvas.layer("anchor kick").unwrap().flush(); 61 + 62 + ctx.later_ms(200, &fade_out_kick_circles) 41 63 }) 42 64 .on_note("bass", &|canvas, ctx| { 43 65 let mut new_layer = canvas.random_layer_within("bass", &ctx.extra.bass_pattern_at); 44 66 new_layer.paint_all_objects(Fill::Solid(Color::White)); 45 - canvas.replace_or_create_layer("bass", new_layer); 67 + canvas.replace_or_create_layer(new_layer); 46 68 }) 47 69 .on_note("powerful clap hit, clap, perclap", &|canvas, ctx| { 48 70 let mut new_layer = 49 71 canvas.random_layer_within("claps", &ctx.extra.bass_pattern_at.translated(2, 0)); 50 72 new_layer.paint_all_objects(Fill::Solid(Color::Red)); 51 - canvas.replace_or_create_layer("claps", new_layer) 73 + canvas.replace_or_create_layer(new_layer) 52 74 }) 53 75 .on_note("qanda", &|canvas, ctx| { 54 - if ctx.stem("qanda").amplitude_relative() < 0.7 { 55 - return; 56 - } 57 - 58 76 let mut new_layer = 59 77 canvas.random_layer_within("qanda", &ctx.extra.bass_pattern_at.translated(-2, 0)); 60 78 new_layer.paint_all_objects(Fill::Solid(Color::Orange)); 61 - canvas.replace_or_create_layer("qanda", new_layer) 79 + canvas.replace_or_create_layer(new_layer) 62 80 }) 63 81 .on_note("brokenup", &|canvas, ctx| { 64 82 let mut new_layer = canvas 65 83 .random_layer_within("brokenup", &ctx.extra.bass_pattern_at.translated(0, -2)); 66 84 new_layer.paint_all_objects(Fill::Solid(Color::Yellow)); 67 - canvas.replace_or_create_layer("brokenup", new_layer); 85 + canvas.replace_or_create_layer(new_layer); 68 86 }) 69 87 .on_note("goup", &|canvas, ctx| { 70 88 let mut new_layer = 71 89 canvas.random_layer_within("goup", &ctx.extra.bass_pattern_at.translated(0, 2)); 72 - new_layer.paint_all_objects(Fill::Solid(Color::Yellow)); 73 - canvas.replace_or_create_layer("goup", new_layer); 90 + new_layer.paint_all_objects(Fill::Solid(Color::Green)); 91 + canvas.replace_or_create_layer(new_layer); 92 + }) 93 + .on_note("ch", &|canvas, _| { 94 + let world = canvas.world_region.clone(); 95 + let layer = canvas.layer("ch").unwrap(); 96 + let (obj, _) = layer.objects.get_mut("dot").unwrap(); 97 + obj.translate_with(hat_region_cycle(&world, &obj.region())); 98 + layer.flush(); 99 + }) 100 + .on_note("flavor kick", &|canvas, _| { 101 + let mut new_layer = canvas.random_layer_within( 102 + "flavor kick", 103 + &Region::from_origin_and_size((14, 0), (1, 1)), 104 + ); 105 + new_layer.paint_all_objects(Fill::Solid(Color::White)); 106 + canvas.replace_or_create_layer(new_layer); 107 + }) 108 + .on_note("rimshot, glitchy percs", &|canvas, ctx| { 109 + let mut new_layer = 110 + canvas.random_layer_within("percs", &ctx.extra.bass_pattern_at.translated(2, 1)); 111 + new_layer.paint_all_objects(Fill::Translucent(Color::Red, 0.5)); 112 + canvas.replace_or_create_layer(new_layer); 74 113 }) 75 114 .when_remaining(10, &|canvas, _| { 76 115 canvas.root().add_object( ··· 91 130 } 92 131 } 93 132 133 + fn fade_out_kick_circles(canvas: &mut Canvas) { 134 + canvas 135 + .layer("anchor kick") 136 + .unwrap() 137 + .paint_all_objects(Fill::Translucent(Color::White, 0.0)); 138 + 139 + canvas.layer("anchor kick").unwrap().flush(); 140 + } 141 + 94 142 fn update_stem_position( 95 143 ctx: &mut shapemaker::Context<State>, 96 144 canvas: &mut Canvas, ··· 140 188 } 141 189 142 190 region_cycle_with_offset(world, current, offset - 1) 191 + } 192 + 193 + fn hat_region_cycle(world: &Region, current: &Region) -> (i32, i32) { 194 + let (end_x, end_y) = { 195 + let (x, y) = world.end; 196 + (x - 1, y - 1) 197 + }; 198 + 199 + match current.start { 200 + // top row 201 + (x, 0) if x <= end_x => (1, 0), 202 + // right column 203 + (x, y) if x == end_x && y <= end_y => (0, 1), 204 + // bottom row 205 + (x, y) if y == end_y && x > 0 => (-1, 0), 206 + // left column 207 + (0, y) if y > 0 => (0, -1), 208 + _ => unreachable!(), 209 + } 143 210 } 144 211 145 212 fn region_cycle(world: &Region, current: Option<&Region>) -> Region {