diff --git a/Cargo.lock b/Cargo.lock index b84ed65..a4c4aee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2414,6 +2414,14 @@ dependencies = [ "utils", ] +[[package]] +name = "subtitled16" +version = "0.1.0" +dependencies = [ + "nannou", + "utils", +] + [[package]] name = "subtitled2" version = "0.1.0" diff --git a/crates/subtitled16/Cargo.toml b/crates/subtitled16/Cargo.toml new file mode 100644 index 0000000..3f6904b --- /dev/null +++ b/crates/subtitled16/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "subtitled16" +version = "0.1.0" +edition = "2018" + +[dependencies] +nannou = "0.17" +utils = { path = "../utils" } diff --git a/crates/subtitled16/src/main.rs b/crates/subtitled16/src/main.rs new file mode 100644 index 0000000..54d8c69 --- /dev/null +++ b/crates/subtitled16/src/main.rs @@ -0,0 +1,108 @@ +use std::time::Duration; + +use nannou::prelude::*; + +const R: f32 = 2.0; + +fn main() { + nannou::app(model).update(update).simple_window(view).run(); +} + +#[derive(Clone)] +struct Point { + pos: IVec2, + color: f32, +} + +impl Point { + fn new(pos: IVec2, color: f32) -> Self { + Self { pos, color } + } +} + +fn neighbors(point: IVec2) -> Vec { + let mut cube = vec![]; + let p = [-1, 0, 1]; + for &x in &p { + for &y in &p { + if (x, y) != (0, 0) { + cube.push(ivec2(x, y) + point); + } + } + } + cube +} + +struct Model { + points: Vec, + visits: Vec, +} + +fn model(_app: &App) -> Model { + Model { + visits: vec![Point::new(IVec2::ZERO, random_range(0.0, 360.0))], + points: vec![], + } +} + +fn update(app: &App, model: &mut Model, _update: Update) { + for _ in 0..20 { + run(app, model) + } +} +fn run(app: &App, model: &mut Model) { + let _t = app.elapsed_frames() as f32 / 60.0; + + // take a random out of the visits list + let point = model.visits.remove(random_range(0, model.visits.len())); + // visit it and all it's neighbors + let neighbors = neighbors(point.pos) + .into_iter() + .filter(|p| { + model.visits.iter().find(|point| point.pos == *p).is_none() + && model.points.iter().find(|point| point.pos == *p).is_none() + }) + .collect::>(); + for n in neighbors { + model + .visits + // NOTE: this is where the randomization of the color happens + .push(Point::new(n, point.color + random_range(-10.0, 10.0))) + } + // move it to visited points + model.points.push(point); +} + +fn view(app: &App, model: &Model, frame: Frame) { + let _t = frame.nth() as f32 / 60.0; + + let draw = app.draw(); + draw.background().color(SNOW); + + for walker in &model.visits { + let h = walker.color / 360.0; + draw.ellipse() + .xy(walker.pos.as_f32() * R * 2.0) + .radius(R) + .color(hsl(h.fract(), 0.5, 0.7)); + } + for walker in &model.points { + let h = walker.color / 360.0; + let p = walker.pos.as_f32() * R; + draw.quad() + .points( + p + R * vec2(1., 1.), + p + R * vec2(1., -1.), + p + R * vec2(-1., -1.), + p + R * vec2(-1., 1.), + ) + .xy(p) + .color(hsl(h.fract(), 0.5, 0.5)); + } + + // cause otherwise it goes too fast when recording and it can't save the frames in time lmao + std::thread::sleep(Duration::from_millis(5)); + + draw.to_frame(app, &frame).unwrap(); + utils::record::record(app, &frame); +} diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index b9b06fa..0785886 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -46,3 +46,6 @@ impl Tup2Extension for (f32, f32) { pub fn vec2_range(min: f32, max: f32) -> Vec2 { vec2(random_range(min, max), random_range(min, max)) } +pub fn ivec2_range(min: i32, max: i32) -> IVec2 { + ivec2(random_range(min, max), random_range(min, max)) +}