add 22, 23, 24,

main
annieversary 2021-10-20 18:52:16 +01:00
parent 5e0d3b3ca0
commit 92214054f9
10 changed files with 409 additions and 0 deletions

24
Cargo.lock generated
View File

@ -2470,6 +2470,30 @@ dependencies = [
"utils",
]
[[package]]
name = "subtitled22"
version = "0.1.0"
dependencies = [
"nannou",
"utils",
]
[[package]]
name = "subtitled23"
version = "0.1.0"
dependencies = [
"nannou",
"utils",
]
[[package]]
name = "subtitled24"
version = "0.1.0"
dependencies = [
"nannou",
"utils",
]
[[package]]
name = "subtitled3"
version = "0.1.0"

View File

@ -0,0 +1,8 @@
[package]
name = "subtitled22"
version = "0.1.0"
edition = "2018"
[dependencies]
nannou = "0.17"
utils = { path = "../utils" }

View File

@ -0,0 +1,99 @@
use nannou::prelude::*;
use utils::{drawing::draw_soft_bg, *};
fn main() {
nannou::app(model).update(update).simple_window(view).run();
}
enum Type {
Square,
Circle,
}
struct Shape {
size: f32,
r: f32,
color: f32,
t: Type,
}
struct Model {
shapes: Vec<Shape>,
}
fn model(_app: &App) -> Model {
Model {
shapes: (0..1000)
.map(|_| {
let size = random_range(7.0, 18.0);
let r = random_range(100.0, 300.0);
let color = (random_range(0.0, 80.0) / 360.0).fract();
let t = if random::<f32>() > 0.3 {
Type::Circle
} else {
Type::Square
};
Shape { size, r, color, t }
})
.collect(),
}
}
fn update(app: &App, _model: &mut Model, _update: Update) {
let _t = app.elapsed_frames() as f32 / 60.0;
}
fn view(app: &App, model: &Model, frame: Frame) {
let t = frame.nth() as f32 / 60.0;
let draw = app.draw();
draw_soft_bg(&draw, &app, SNOW, 1.03);
let count = model.shapes.len() as f32;
for (i, shape) in model.shapes.iter().enumerate() {
let angle = 360.0 * i as f32 / count;
let angle = angle + t * map_sin(angle.powi(4), 0.2, 0.7);
let r = shape.r * map_sin(t + i as f32, 0.5, 1.3);
let size = shape.size * map_sin(0.004 * t + 2.0 * i as f32, 0.5, 1.5);
match shape.t {
Type::Circle => {
let color = (shape.color + 0.01 * t + angle * 0.0001).fract();
let color = hsl(color, map_sin(i.pow(3) as f32, 0.4, 0.7), 0.5);
let p = r * angle.sin_cos().to_vec2();
draw.ellipse().radius(size).xy(p).color(color);
}
Type::Square => {
let p = r * (-angle).sin_cos().to_vec2();
let rotation = t + i as f32;
let points = vec![
vec2(1.0, 1.0),
vec2(-1.0, 1.0),
vec2(-1.0, -1.0),
vec2(1.0, -1.0),
]
.into_iter()
.map(|v| {
vec2(
v.x * rotation.cos() - v.y * rotation.sin(),
v.x * rotation.sin() + v.y * rotation.cos(),
)
})
.map(|v| v * size + p)
.collect::<Vec<_>>();
draw.polyline()
.stroke_weight(1.5)
.points_closed(points)
.color(SNOW);
}
};
}
draw.to_frame(app, &frame).unwrap();
utils::record::record(app, &frame);
}

View File

@ -0,0 +1,8 @@
[package]
name = "subtitled23"
version = "0.1.0"
edition = "2018"
[dependencies]
nannou = "0.17"
utils = { path = "../utils" }

View File

@ -0,0 +1,68 @@
use nannou::prelude::*;
use utils::*;
fn main() {
nannou::app(model).update(update).simple_window(view).run();
}
struct Model {
points: Vec<Vec2>,
base_hue: f32,
}
fn model(_app: &App) -> Model {
Model {
base_hue: random_range(0., 360.0),
points: vec![Vec2::splat(0.1); 10000],
}
}
fn advance(point: Vec2, t: f32) -> Vec2 {
// pick a random point
let count = ((t * 0.125).trunc() as usize % 5) + 3;
let points = (0..count)
.map(|i| (TAU * i as f32 / count as f32).sin_cos().to_vec2())
.collect::<Vec<_>>();
let random = points[random_range(0, count)];
(random + point) * map_cos(t * PI * 0.25, 0.1, 1.0).powf(1.5)
}
fn update(app: &App, model: &mut Model, _update: Update) {
let t = app.elapsed_frames() as f32 / 60.0;
// advance all points in list
let mut last = model.points.last().unwrap().clone();
for v in &mut model.points {
last = advance(last, t);
*v = last;
}
// move base_hue
model.base_hue += 0.5;
}
fn view(app: &App, model: &Model, frame: Frame) {
let _t = frame.nth() as f32 / 60.0;
let draw = app.draw();
if frame.nth() == 0 {
draw.background().color(BLACK);
} else {
let win = app.window_rect();
draw.rect().wh(win.wh()).color(srgba(0., 0.0, 0.0, 0.02));
}
for &p in &model.points {
let h = random_range(model.base_hue, model.base_hue + 60.0) / 360.0;
draw.ellipse()
.radius(0.2)
.xy(150.0 * p)
.color(hsla(h.fract(), 1.0, 0.5, 0.1));
}
draw.to_frame(app, &frame).unwrap();
utils::record::record(app, &frame);
}

View File

@ -0,0 +1,8 @@
[package]
name = "subtitled24"
version = "0.1.0"
edition = "2018"
[dependencies]
nannou = "0.17"
utils = { path = "../utils" }

View File

@ -0,0 +1,67 @@
use std::time::Duration;
use nannou::prelude::*;
use utils::{
lsystems::LSystem,
turtle::{Turtle, TurtleAlphabet},
};
fn main() {
nannou::app(model)
.update(update)
.simple_window(view)
.size(600, 520)
.run();
}
struct Model {}
fn model(_app: &App) -> Model {
Model {}
}
fn update(app: &App, _model: &mut Model, _update: Update) {
let _t = app.elapsed_frames() as f32 / 60.0;
}
fn view(app: &App, _model: &Model, frame: Frame) {
let t = frame.nth() as f32 / 60.0;
let draw = app.draw();
if frame.nth() == 0 {
draw.background().color(SNOW);
}
if frame.nth() % 60 == 0 {
let iters = t.trunc() as usize % 10;
use TurtleAlphabet::*;
let mut sys = LSystem::new(
vec![Line, Right, Right, Line, Right, Right, Line],
Box::new(|i| match i {
Line => vec![
Line, Right, Right, Line, Right, Right, Line, Right, Right, Move,
],
Move => vec![Move, Move],
a @ _ => vec![a],
}),
);
let h = app.window_rect().h() / 2.0;
let w = app.window_rect().w() / 2.0;
let mut turtle = Turtle::new(vec2(-w, -h), 2.85 * w * 0.5.powi(iters as i32), TAU / 3.0);
turtle.rotation = -PI / 4.0;
let a = sys.nth(iters);
turtle.advance_many(&draw, &a);
// turtle.advance(&draw, TurtleAlphabet::Line);
// turtle.advance(&draw, TurtleAlphabet::Right);
// turtle.advance(&draw, TurtleAlphabet::Line);
}
// 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);
}

View File

@ -1,8 +1,10 @@
pub mod color;
pub mod curves;
pub mod drawing;
pub mod lsystems;
pub mod record;
pub mod sequences;
pub mod turtle;
use nannou::prelude::*;

View File

@ -0,0 +1,66 @@
use std::collections::HashMap;
pub struct LSystem<Alphabet: Clone> {
axiom: Vec<Alphabet>,
rule: Box<dyn FnMut(Alphabet) -> Vec<Alphabet>>,
memo: HashMap<usize, Vec<Alphabet>>,
}
impl<Alphabet: Clone> LSystem<Alphabet> {
pub fn new(axiom: Vec<Alphabet>, rule: Box<dyn FnMut(Alphabet) -> Vec<Alphabet>>) -> Self {
Self {
axiom,
rule,
memo: Default::default(),
}
}
pub fn nth(&mut self, i: usize) -> Vec<Alphabet> {
if i == 0 {
return self.axiom.clone();
}
if let Some(a) = self.memo.get(&i) {
return a.clone();
}
let last = self.nth(i - 1);
let mut res = Vec::new();
for letter in last {
res.extend((self.rule)(letter).into_iter());
}
self.memo.insert(i, res.clone());
res
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lsystems() {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Test {
A,
B,
}
use Test::*;
let mut sys = LSystem::new(
vec![A],
Box::new(|i| match i {
A => vec![A, B],
B => vec![A],
}),
);
assert_eq!(vec![A], sys.nth(0));
assert_eq!(vec![A, B], sys.nth(1));
assert_eq!(vec![A, B, A], sys.nth(2));
assert_eq!(vec![A, B, A, A, B], sys.nth(3));
assert_eq!(vec![A, B, A, A, B, A, B, A], sys.nth(4));
}
}

View File

@ -0,0 +1,59 @@
use nannou::prelude::*;
#[derive(Clone, Copy, Debug)]
pub enum TurtleAlphabet {
Line,
Move,
Right,
Left,
Push,
Pop,
}
pub struct Turtle {
position: Vec2,
pub rotation: f32,
len: f32,
theta: f32,
stack: Vec<(Vec2, f32)>,
}
impl Turtle {
pub fn new(position: Vec2, len: f32, theta: f32) -> Self {
Self {
position,
rotation: 0.0,
len,
theta,
stack: Default::default(),
}
}
pub fn advance(&mut self, draw: &Draw, l: TurtleAlphabet) {
match l {
TurtleAlphabet::Line | TurtleAlphabet::Move => {
let next = self.position + Vec2::ONE.rotate(self.rotation) * self.len;
draw.line().points(self.position, next);
self.position = next;
}
// TurtleAlphabet::Move => {
// self.position += Vec2::ONE.rotate(self.rotation) * self.len;
// }
TurtleAlphabet::Right => self.rotation = (self.rotation - self.theta).rem_euclid(TAU),
TurtleAlphabet::Left => self.rotation = (self.rotation + self.theta).rem_euclid(TAU),
TurtleAlphabet::Push => self.stack.push((self.position, self.rotation)),
TurtleAlphabet::Pop => {
if let Some((a, b)) = self.stack.pop() {
self.position = a;
self.rotation = b;
}
}
}
}
pub fn advance_many(&mut self, draw: &Draw, l: &[TurtleAlphabet]) {
for &l in l {
self.advance(draw, l)
}
}
}