From b21d7d56b31e19ab8a19b4029107e044d3db8e5b Mon Sep 17 00:00:00 2001 From: annieversary Date: Sat, 28 Aug 2021 00:21:10 +0200 Subject: [PATCH] subtitled #11 --- Cargo.lock | 8 ++ crates/subtitled11/Cargo.toml | 8 ++ crates/subtitled11/src/main.rs | 159 +++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 crates/subtitled11/Cargo.toml create mode 100644 crates/subtitled11/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index cb5844d..e60337e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2356,6 +2356,14 @@ dependencies = [ "utils", ] +[[package]] +name = "subtitled11" +version = "0.1.0" +dependencies = [ + "nannou", + "utils", +] + [[package]] name = "subtitled2" version = "0.1.0" diff --git a/crates/subtitled11/Cargo.toml b/crates/subtitled11/Cargo.toml new file mode 100644 index 0000000..e27036b --- /dev/null +++ b/crates/subtitled11/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "subtitled11" +version = "0.1.0" +edition = "2018" + +[dependencies] +nannou = "0.17" +utils = { path = "../utils" } diff --git a/crates/subtitled11/src/main.rs b/crates/subtitled11/src/main.rs new file mode 100644 index 0000000..41d19e7 --- /dev/null +++ b/crates/subtitled11/src/main.rs @@ -0,0 +1,159 @@ +use nannou::prelude::*; + +fn main() { + nannou::app(model).update(update).simple_window(view).run(); +} + +struct Model { + automata: Automata, + row: usize, + cube: Vec, +} + +fn model(_app: &App) -> Model { + // generate all the points in the cube + let mut cube = vec![]; + let p = [-1.0, 1.0]; + for &x in &p { + for &y in &p { + for &z in &p { + for &w in &p { + cube.push(vec4(x, y, z, w)); + } + } + } + } + + Model { + automata: Automata::new(), + row: 0, + cube, + } +} + +fn update(app: &App, model: &mut Model, _update: Update) { + let _t = app.elapsed_frames() as f32 / 60.0; + + if app.elapsed_frames() % 10 == 0 { + model.automata.advance(); + model.row += 1; + } +} + +fn rot(angle: f32) -> Mat4 { + // 4d rotations https://math.stackexchange.com/questions/1402362/rotation-in-4d + let m = mat4( + vec4(angle.cos(), angle.sin(), 0.0, 0.0), + vec4(-angle.sin(), angle.cos(), 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(0.0, 0.0, 0.0, 1.0), + ) * mat4( + vec4(1.0, 0.0, 0.0, 0.0), + vec4(0.0, angle.cos(), angle.sin(), 0.0), + vec4(0.0, -angle.sin(), angle.cos(), 0.0), + vec4(0.0, 0.0, 0.0, 1.0), + ); + let angle = -angle * 2.0; + m * mat4( + vec4(1.0, 0.0, 0.0, 0.0), + vec4(0.0, 1.0, 0.0, 0.0), + vec4(0.0, 0.0, angle.cos(), angle.sin()), + vec4(0.0, 0.0, -angle.sin(), angle.cos()), + ) +} + +fn view(app: &App, model: &Model, frame: Frame) { + let t = frame.nth() as f32 / 60.0; + + // background + + let draw = app.draw(); + if frame.nth() == 0 { + draw.background().color(SNOW); + } else { + let win = app.window_rect(); + draw.rect() + .wh(win.wh()) + .color(srgba(1.0, 250.0 / 255.0, 250.0 / 255.0, 0.01)); + } + + // draw automata + + let (l, top, w, h) = app.window_rect().l_t_w_h(); + + const BALL_SIZE: f32 = 6.0; + let cols = w / BALL_SIZE; + let rows = h / BALL_SIZE; + + for (i, &b) in model.automata.points.iter().enumerate() { + if b && i as f32 <= cols { + let x = l + (i as f32 % cols) * BALL_SIZE; + let y = top - (model.row as f32 % rows) * BALL_SIZE; + let p = vec2(x, y); + let h = model.row as f32 / 360.0; + draw.ellipse() + .radius(BALL_SIZE / 2.0) + .xy(p) + .color(hsl(h.fract(), 0.5, 0.5)); + } + } + + // draw center square + draw.rect().w_h(400.0, 400.0).color(SNOW); + + // draw 4d cube + let p: Vec<_> = model + .cube + .iter() + .map(|&v| { + // rotate + let v = rot(t) * v; + // project onto xz plane cause it's the coolest one + 100.0 * vec2(v.x, v.z) + }) + .collect::>(); + // make all pairs of points + let p = p + .iter() + .enumerate() + .flat_map(|(i, a)| p[i + 1..].iter().map(move |b| (a, b))); + for (&a, &b) in p { + draw.line().points(a, b).color(BLACK); + } + + draw.to_frame(app, &frame).unwrap(); + utils::record::record(app, &frame); +} + +struct Automata { + points: Vec, + rule: Vec, +} + +impl Automata { + fn new() -> Self { + let points = (0..200).map(|_| random::()).collect(); + let rule = (0..8).map(|_| random::()).collect(); + + Self { points, rule } + } + + fn advance(&mut self) { + for i in 0..self.points.len() { + let i1 = (i + 1) % self.points.len(); + let im1 = if i == 0 { self.points.len() - 1 } else { i - 1 }; + let v = (self.points[im1], self.points[i], self.points[i1]); + + self.points[i] = match v { + (false, false, false) => self.rule[0], + (false, false, true) => self.rule[1], + (false, true, false) => self.rule[2], + (false, true, true) => self.rule[3], + (true, false, false) => self.rule[4], + (true, false, true) => self.rule[5], + (true, true, false) => self.rule[6], + (true, true, true) => self.rule[7], + } + } + } +}