Compare commits
No commits in common. "main" and "e7b0735bcf76aabbb2023158230ee10b412b868d" have entirely different histories.
main
...
e7b0735bcf
|
@ -236,7 +236,7 @@ dependencies = [
|
|||
"daggy 0.5.0",
|
||||
"fnv",
|
||||
"instant",
|
||||
"num 0.3.1",
|
||||
"num",
|
||||
"pistoncore-input",
|
||||
"rusttype 0.8.3",
|
||||
]
|
||||
|
@ -1075,7 +1075,7 @@ dependencies = [
|
|||
"gif",
|
||||
"jpeg-decoder",
|
||||
"num-iter",
|
||||
"num-rational 0.3.2",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
"png",
|
||||
"scoped_threadpool",
|
||||
|
@ -1188,12 +1188,6 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
|
||||
|
||||
[[package]]
|
||||
name = "line_drawing"
|
||||
version = "0.7.0"
|
||||
|
@ -1587,25 +1581,11 @@ version = "0.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f"
|
||||
dependencies = [
|
||||
"num-bigint 0.3.2",
|
||||
"num-complex 0.3.1",
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational 0.3.2",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
|
||||
dependencies = [
|
||||
"num-bigint 0.4.2",
|
||||
"num-complex 0.4.0",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational 0.4.0",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
|
@ -1620,17 +1600,6 @@ dependencies = [
|
|||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74e768dff5fb39a41b3bcd30bb25cf989706c90d028d1ad71971987aa309d535"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.3.1"
|
||||
|
@ -1640,15 +1609,6 @@ dependencies = [
|
|||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.44"
|
||||
|
@ -1677,19 +1637,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-bigint 0.3.2",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-bigint 0.4.2",
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
@ -1701,7 +1649,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2080,16 +2027,6 @@ dependencies = [
|
|||
"getrandom 0.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_distr"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "051b398806e42b9cd04ad9ec8f81e355d0a382c543ac6672c62f5a5b452ef142"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"rand 0.8.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
|
@ -2411,87 +2348,6 @@ dependencies = [
|
|||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled10"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled11"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled12"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"rand_distr",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled13"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled14"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled15"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled16"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled17"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled18"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled19"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled2"
|
||||
version = "0.1.0"
|
||||
|
@ -2500,55 +2356,6 @@ dependencies = [
|
|||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled20"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled21"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"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 = "subtitled25"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"num 0.4.0",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled3"
|
||||
version = "0.1.0"
|
||||
|
@ -2581,30 +2388,6 @@ dependencies = [
|
|||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled7"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled8"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled9"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.74"
|
||||
|
|
|
@ -3,3 +3,7 @@
|
|||
this is a bunch of nannou projects
|
||||
|
||||
i'll add a list with pictures here soon
|
||||
|
||||
you'll notice that the numbers i've put on fedi and the ones here are different :)
|
||||
|
||||
also don't criticize my code pls i'm sensitive and i Will cry
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.0 MiB |
Binary file not shown.
Before Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.4 KiB |
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled10"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,171 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
use utils::*;
|
||||
|
||||
fn main() {
|
||||
nannou::app(model).update(update).simple_window(view).run();
|
||||
}
|
||||
|
||||
// http://paulbourke.net/fractals/clifford/
|
||||
// http://paulbourke.net/fractals/peterdejong/
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum Attractor {
|
||||
Clifford,
|
||||
DeJong,
|
||||
}
|
||||
|
||||
impl Attractor {
|
||||
fn random() -> Self {
|
||||
match random_range(0, 2) {
|
||||
0 => Self::Clifford,
|
||||
_ => Self::DeJong,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct Params {
|
||||
a: f32,
|
||||
b: f32,
|
||||
c: f32,
|
||||
d: f32,
|
||||
attractor: Attractor,
|
||||
}
|
||||
struct Model {
|
||||
points: Vec<Vec2>,
|
||||
base_hue: f32,
|
||||
|
||||
/// params for the attractor
|
||||
params: Params,
|
||||
|
||||
// modulation values for each param
|
||||
a_mul: f32,
|
||||
a_add: f32,
|
||||
b_mul: f32,
|
||||
b_add: f32,
|
||||
c_mul: f32,
|
||||
c_add: f32,
|
||||
d_mul: f32,
|
||||
d_add: f32,
|
||||
|
||||
// max range for each param
|
||||
// this would be a const, but acos isn't a const fn
|
||||
min_a: f32,
|
||||
max_a: f32,
|
||||
min_b: f32,
|
||||
max_b: f32,
|
||||
min_c: f32,
|
||||
max_c: f32,
|
||||
min_d: f32,
|
||||
max_d: f32,
|
||||
}
|
||||
|
||||
fn model(_app: &App) -> Model {
|
||||
Model {
|
||||
params: Params {
|
||||
a: 0.0,
|
||||
b: 0.0,
|
||||
c: 0.0,
|
||||
d: 0.0,
|
||||
attractor: Attractor::random(),
|
||||
},
|
||||
|
||||
a_mul: random_range(0.3, 1.0) * random_range(-1.0, 1.0).signum(),
|
||||
b_mul: random_range(0.3, 1.0) * random_range(-1.0, 1.0).signum(),
|
||||
c_mul: random_range(0.3, 1.0) * random_range(-1.0, 1.0).signum(),
|
||||
d_mul: random_range(0.3, 1.0) * random_range(-1.0, 1.0).signum(),
|
||||
|
||||
a_add: random_range(0.3, 2.0),
|
||||
b_add: random_range(0.3, 2.0),
|
||||
c_add: random_range(0.3, 2.0),
|
||||
d_add: random_range(0.3, 2.0),
|
||||
|
||||
// magic numbers from here:
|
||||
// http://paulbourke.net/fractals/clifford/paul_richards/main.cpp
|
||||
min_a: f32::acos(1.6 / 2.0),
|
||||
max_a: f32::acos(1.3 / 2.0),
|
||||
min_b: f32::acos(-0.6 / 2.0),
|
||||
max_b: f32::acos(1.7 / 2.0),
|
||||
min_c: f32::acos(-1.2 / 2.0),
|
||||
max_c: f32::acos(0.5 / 2.0),
|
||||
min_d: f32::acos(1.6 / 2.0),
|
||||
max_d: f32::acos(1.4 / 2.0),
|
||||
|
||||
base_hue: random_range(0., 360.0),
|
||||
points: vec![Vec2::splat(0.1); 10000],
|
||||
}
|
||||
}
|
||||
|
||||
fn advance(
|
||||
Params {
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
d,
|
||||
attractor,
|
||||
}: Params,
|
||||
point: Vec2,
|
||||
) -> Vec2 {
|
||||
let x = point.x;
|
||||
let y = point.y;
|
||||
|
||||
// clifford attractor
|
||||
// xn+1 = sin(a yn) + c cos(a xn)
|
||||
// yn+1 = sin(b xn) + d cos(b yn)
|
||||
|
||||
// de Jong
|
||||
// xn+1 = sin(a yn) - cos(b xn)
|
||||
// yn+1 = sin(c xn) - cos(d yn)
|
||||
|
||||
match attractor {
|
||||
Attractor::Clifford => vec2(
|
||||
(a * y).sin() + (a * x).cos() * c,
|
||||
(b * x).sin() + (b * y).cos() * d,
|
||||
),
|
||||
Attractor::DeJong => vec2((a * y).sin() - (b * x).cos(), (c * x).sin() - (d * y).cos()),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(app: &App, model: &mut Model, _update: Update) {
|
||||
let t = app.elapsed_frames() as f32 / 60.0;
|
||||
|
||||
// modulate params
|
||||
model.params.a = map_sin(t * model.a_mul + model.a_add, model.min_a, model.max_a);
|
||||
model.params.b = map_sin(t * model.b_mul + model.b_add, model.min_b, model.max_b);
|
||||
model.params.c = map_sin(t * model.c_mul + model.c_add, model.min_c, model.max_c);
|
||||
model.params.d = map_sin(t * model.d_mul + model.d_add, model.min_d, model.max_d);
|
||||
|
||||
// advance all points in list
|
||||
let mut last = model.points.last().unwrap().clone();
|
||||
for v in &mut model.points {
|
||||
last = advance(model.params, last);
|
||||
*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);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled11"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,163 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
|
||||
fn main() {
|
||||
nannou::app(model).update(update).simple_window(view).run();
|
||||
}
|
||||
|
||||
struct Model {
|
||||
automata: Automata,
|
||||
row: usize,
|
||||
cube: Vec<Vec4>,
|
||||
}
|
||||
|
||||
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
|
||||
50.0 * vec2(v.x + v.y, v.z + v.w)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (i, (&a, &b)) in p
|
||||
.iter()
|
||||
.enumerate()
|
||||
// make all pairs of points
|
||||
.flat_map(|(i, a)| p[i + 1..].iter().map(move |b| (a, b)))
|
||||
.enumerate()
|
||||
{
|
||||
if i % 2 != 0 {
|
||||
draw.line().points(a, b).color(BLACK);
|
||||
}
|
||||
}
|
||||
|
||||
draw.to_frame(app, &frame).unwrap();
|
||||
utils::record::record(app, &frame);
|
||||
}
|
||||
|
||||
struct Automata {
|
||||
points: Vec<bool>,
|
||||
rule: Vec<bool>,
|
||||
}
|
||||
|
||||
impl Automata {
|
||||
fn new() -> Self {
|
||||
let points = (0..200).map(|_| random::<bool>()).collect();
|
||||
let rule = (0..8).map(|_| random::<bool>()).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],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled12"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
rand_distr = "0.4.1"
|
||||
utils = { path = "../utils" }
|
|
@ -1,67 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
use nannou::rand::prelude::*;
|
||||
use rand_distr::Normal;
|
||||
use utils::*;
|
||||
|
||||
fn main() {
|
||||
nannou::app(model).update(update).simple_window(view).run();
|
||||
}
|
||||
|
||||
struct Model {
|
||||
lines: Vec<Vec<Vec2>>,
|
||||
}
|
||||
|
||||
fn lines(max_width: f32) -> Vec<Vec<Vec2>> {
|
||||
let normal = Normal::new(0.0, 0.2).unwrap();
|
||||
|
||||
(0..20)
|
||||
.map(|_| {
|
||||
let mut line = vec![Vec2::Y];
|
||||
|
||||
// generate the y coordinates for all points
|
||||
let n = random_range(4, 12);
|
||||
let mut ys = (0..n).map(|_| random_range(-1.0, 1.0)).collect::<Vec<_>>();
|
||||
ys.sort_by(|a, b| b.partial_cmp(a).unwrap());
|
||||
|
||||
// make the actual points and add them to the vec
|
||||
for y in ys {
|
||||
let w = map_range(1.0 - y.abs(), 0.0, 1.0, 0.01, max_width);
|
||||
let x = nannou::rand::thread_rng().sample::<f32, _>(normal) * w;
|
||||
line.push(vec2(x, y));
|
||||
}
|
||||
|
||||
line.push(-Vec2::Y);
|
||||
|
||||
line
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn model(_app: &App) -> Model {
|
||||
Model { lines: lines(0.0) }
|
||||
}
|
||||
|
||||
fn update(app: &App, model: &mut Model, _update: Update) {
|
||||
let t = app.elapsed_frames() as f32 / 60.0;
|
||||
|
||||
if app.elapsed_frames() % 2 == 0 {
|
||||
model.lines = lines(map_sin(t, 0.1, 1.0));
|
||||
}
|
||||
}
|
||||
|
||||
fn view(app: &App, model: &Model, frame: Frame) {
|
||||
let _t = frame.nth() as f32 / 60.0;
|
||||
|
||||
let draw = app.draw();
|
||||
draw.background().color(BLACK);
|
||||
|
||||
for line in &model.lines {
|
||||
draw.polyline()
|
||||
.stroke_weight(1.0)
|
||||
.points(line.iter().map(|v| *v * 300.0))
|
||||
.color(PINK);
|
||||
}
|
||||
|
||||
draw.to_frame(app, &frame).unwrap();
|
||||
utils::record::record(app, &frame);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled13"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,94 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
use utils::*;
|
||||
|
||||
fn main() {
|
||||
nannou::app(model).update(update).simple_window(view).run();
|
||||
}
|
||||
|
||||
struct Model {
|
||||
walkers: Vec<Vec2>,
|
||||
clustered: Vec<Vec2>,
|
||||
}
|
||||
|
||||
fn model(_app: &App) -> Model {
|
||||
Model {
|
||||
walkers: (0..5000).map(|_| vec2_range(-1.0, 1.0) * 300.0).collect(),
|
||||
clustered: vec![Vec2::ZERO],
|
||||
}
|
||||
}
|
||||
|
||||
fn update(app: &App, model: &mut Model, _update: Update) {
|
||||
let _t = app.elapsed_frames() as f32 / 60.0;
|
||||
|
||||
// sort them by x to be a bit more efficient with the collision detection
|
||||
model
|
||||
.clustered
|
||||
.sort_by(|a, b| a.x.partial_cmp(&b.x).unwrap());
|
||||
let clusters = model.clustered.clone();
|
||||
|
||||
let mut to_remove = vec![];
|
||||
for (i, p) in &mut model.walkers.iter_mut().enumerate() {
|
||||
*p += vec2_range(-1.0, 1.0) * 3.5 + 0.5 * vec2(p.y, -p.x).normalize();
|
||||
|
||||
const RAD: f32 = 6.0;
|
||||
for &c in &clusters {
|
||||
// skip the ones outside the x range
|
||||
if c.x < p.x - RAD {
|
||||
continue;
|
||||
}
|
||||
if c.x > p.x + RAD {
|
||||
break;
|
||||
}
|
||||
|
||||
// if it's colliding, make it be a clustered point
|
||||
if p.distance_squared(c) < RAD * RAD {
|
||||
model.clustered.push(*p);
|
||||
to_remove.push(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove the ones that have become clustered
|
||||
// backwards cause otherwise you shift the indexes
|
||||
for i in to_remove.into_iter().rev() {
|
||||
model.walkers.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
fn view(app: &App, model: &Model, frame: Frame) {
|
||||
let t = frame.nth() as f32 / 60.0;
|
||||
|
||||
let draw = app.draw();
|
||||
|
||||
drawing::draw_soft_bg(&draw, app, SNOW, 1.0);
|
||||
|
||||
for &p in &model.clustered {
|
||||
let v = map_sin(t + (p.x.powi(2) + p.y.powi(2) + t) * 0.00003, -20.0, 20.0);
|
||||
let h = (100.0 + v) / 360.0;
|
||||
draw.ellipse().xy(p).radius(4.0).color(hsl(h, 0.5, 0.5));
|
||||
}
|
||||
|
||||
for &p in &model.walkers {
|
||||
draw.ellipse().xy(p).radius(0.0).color(BLACK);
|
||||
}
|
||||
// use nannou::rand::seq::SliceRandom;
|
||||
// let mut rng = nannou::rand::thread_rng();
|
||||
// let n = (frame.nth() as f32 * 0.7) as usize;
|
||||
// for _ in 0..n {
|
||||
// let a = model.clustered.choose(&mut rng);
|
||||
// let b = model.clustered.choose(&mut rng);
|
||||
// if let (Some(&a), Some(&b)) = (a, b) {
|
||||
// let v = map_sin(t * 2.0 + a.x * a.y, -20.0, 20.0);
|
||||
// let h = (100.0 + v) / 360.0;
|
||||
|
||||
// draw.line()
|
||||
// .stroke_weight(3.0)
|
||||
// .points(a, b)
|
||||
// .color(hsla(h, 0.5, 0.5, 0.04));
|
||||
// }
|
||||
// }
|
||||
|
||||
draw.to_frame(app, &frame).unwrap();
|
||||
utils::record::record(app, &frame);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled14"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,152 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
// use utils::*;
|
||||
|
||||
// from https://fabiensanglard.net/doom_fire_psx/
|
||||
|
||||
fn main() {
|
||||
nannou::app(model).update(update).simple_window(view).run();
|
||||
}
|
||||
|
||||
struct Model {
|
||||
fire: Vec<Vec<f32>>,
|
||||
colors: Vec<Rgb8>,
|
||||
uwu: wgpu::Texture,
|
||||
}
|
||||
|
||||
const WIDTH: usize = 400;
|
||||
const HEIGHT: usize = 300;
|
||||
const BALL_SIZE: f32 = 3.0;
|
||||
|
||||
fn model(app: &App) -> Model {
|
||||
let fire = vec![vec![0.0; WIDTH]; HEIGHT];
|
||||
|
||||
let colors = vec![
|
||||
(0x07, 0x07, 0x07),
|
||||
(0x1F, 0x07, 0x07),
|
||||
(0x2F, 0x0F, 0x07),
|
||||
(0x47, 0x0F, 0x07),
|
||||
(0x57, 0x17, 0x07),
|
||||
(0x67, 0x1F, 0x07),
|
||||
(0x77, 0x1F, 0x07),
|
||||
(0x8F, 0x27, 0x07),
|
||||
(0x9F, 0x2F, 0x07),
|
||||
(0xAF, 0x3F, 0x07),
|
||||
(0xBF, 0x47, 0x07),
|
||||
(0xC7, 0x47, 0x07),
|
||||
(0xDF, 0x4F, 0x07),
|
||||
(0xDF, 0x57, 0x07),
|
||||
(0xDF, 0x57, 0x07),
|
||||
(0xD7, 0x5F, 0x07),
|
||||
(0xD7, 0x5F, 0x07),
|
||||
(0xD7, 0x67, 0x0F),
|
||||
(0xCF, 0x6F, 0x0F),
|
||||
(0xCF, 0x77, 0x0F),
|
||||
(0xCF, 0x7F, 0x0F),
|
||||
(0xCF, 0x87, 0x17),
|
||||
(0xC7, 0x87, 0x17),
|
||||
(0xC7, 0x8F, 0x17),
|
||||
(0xC7, 0x97, 0x1F),
|
||||
(0xBF, 0x9F, 0x1F),
|
||||
(0xBF, 0x9F, 0x1F),
|
||||
(0xBF, 0xA7, 0x27),
|
||||
(0xBF, 0xA7, 0x27),
|
||||
(0xBF, 0xAF, 0x2F),
|
||||
(0xB7, 0xAF, 0x2F),
|
||||
(0xB7, 0xB7, 0x2F),
|
||||
(0xB7, 0xB7, 0x37),
|
||||
(0xCF, 0xCF, 0x6F),
|
||||
(0xDF, 0xDF, 0x9F),
|
||||
(0xEF, 0xEF, 0xC7),
|
||||
(0xFF, 0xFF, 0xFF),
|
||||
]
|
||||
.into_iter()
|
||||
.map(|c| c.into())
|
||||
.collect();
|
||||
|
||||
let assets = app.assets_path().unwrap();
|
||||
let img_path = assets.join("images").join("blahaj.png");
|
||||
let uwu = wgpu::Texture::from_path(app, img_path).unwrap();
|
||||
|
||||
let mut model = Model { fire, colors, uwu };
|
||||
|
||||
// presimulate fire
|
||||
for _ in 0..400 {
|
||||
advance(app, &mut model);
|
||||
}
|
||||
|
||||
model
|
||||
}
|
||||
|
||||
fn update(app: &App, model: &mut Model, _update: Update) {
|
||||
let _t = app.elapsed_frames() as f32 / 60.0;
|
||||
|
||||
advance(app, model);
|
||||
}
|
||||
|
||||
fn advance(app: &App, model: &mut Model) {
|
||||
let (w, h) = app.window_rect().w_h();
|
||||
|
||||
let cols = (w / BALL_SIZE) as usize;
|
||||
let rows = (h / BALL_SIZE) as usize - 50;
|
||||
|
||||
if app.elapsed_frames() > 200 {
|
||||
for i in 0..cols {
|
||||
model.fire[rows][i] = 0.0;
|
||||
}
|
||||
} else {
|
||||
for i in 0..cols {
|
||||
model.fire[rows][i] = 36.0;
|
||||
}
|
||||
}
|
||||
|
||||
for x in 0..cols {
|
||||
for y in 0..rows {
|
||||
let disp = random_range(0, 2);
|
||||
model.fire[y][(x + disp) % cols] = model.fire[y + 1][x] - random_range(0., 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn view(app: &App, model: &Model, frame: Frame) {
|
||||
let _t = frame.nth() as f32 / 60.0;
|
||||
|
||||
let draw = app.draw();
|
||||
draw.background().color(BLACK);
|
||||
|
||||
draw.texture(&model.uwu)
|
||||
.w_h(400.0, 282.6)
|
||||
.y((-200.0 + frame.nth() as f32).min(0.0));
|
||||
|
||||
let (l, top, w, h) = app.window_rect().l_t_w_h();
|
||||
|
||||
let cols = w / BALL_SIZE;
|
||||
let rows = h / BALL_SIZE;
|
||||
|
||||
for (i, row) in model.fire.iter().enumerate() {
|
||||
for (j, c) in row.iter().enumerate() {
|
||||
let col_index = c.max(0.0).trunc() as usize % model.colors.len();
|
||||
|
||||
if i as f32 <= rows && j as f32 <= cols && col_index != 0 {
|
||||
let x = l + j as f32 * BALL_SIZE;
|
||||
let y = top - i as f32 * BALL_SIZE;
|
||||
let p = vec2(x, y);
|
||||
let r = BALL_SIZE;
|
||||
// * map_range(i as f32, 0 as f32, rows, 0., 1.0)
|
||||
// * random_range(0.9, 1.1);
|
||||
|
||||
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(model.colors[col_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
draw.to_frame(app, &frame).unwrap();
|
||||
utils::record::record(app, &frame);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled15"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
Binary file not shown.
|
@ -1,13 +0,0 @@
|
|||
// NOTE: This shader requires being manually compiled to SPIR-V in order to
|
||||
// avoid having downstream users require building shaderc and compiling the
|
||||
// shader themselves. If you update this shader, be sure to also re-compile it
|
||||
// and update `frag.spv`. You can do so using `glslangValidator` with the
|
||||
// following command: `glslangValidator -V shader.frag`
|
||||
|
||||
#version 450
|
||||
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
void main() {
|
||||
f_color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
// NOTE: This shader requires being manually compiled to SPIR-V in order to
|
||||
// avoid having downstream users require building shaderc and compiling the
|
||||
// shader themselves. If you update this shader, be sure to also re-compile it
|
||||
// and update `vert.spv`. You can do so using `glslangValidator` with the
|
||||
// following command: `glslangValidator -V shader.vert`
|
||||
|
||||
#version 450
|
||||
|
||||
// maybe change for this https://github.com/castor-software/rethread/blob/69a5746b02c260982a812c52da15ee364bc047e8/code/software-evolution/drift_vis/src/shaders/blur.vert
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
}
|
Binary file not shown.
|
@ -1,127 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
|
||||
struct Model {
|
||||
bind_group: wgpu::BindGroup,
|
||||
render_pipeline: wgpu::RenderPipeline,
|
||||
vertex_buffer1: wgpu::Buffer,
|
||||
vertex_buffer2: wgpu::Buffer,
|
||||
}
|
||||
|
||||
// The vertex type that we will use to represent a point on our triangle.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
struct Vertex {
|
||||
position: [f32; 2],
|
||||
}
|
||||
|
||||
// The vertices that make up our triangle.
|
||||
const VERTICES1: [Vertex; 3] = [
|
||||
Vertex {
|
||||
position: [-1.0, -1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [1.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-1.0, 1.0],
|
||||
},
|
||||
];
|
||||
const VERTICES2: [Vertex; 3] = [
|
||||
Vertex {
|
||||
position: [1.0, -1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [1.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-1.0, -1.0],
|
||||
},
|
||||
];
|
||||
|
||||
fn main() {
|
||||
nannou::app(model).run();
|
||||
}
|
||||
|
||||
fn model(app: &App) -> Model {
|
||||
let w_id = app.new_window().size(512, 512).view(view).build().unwrap();
|
||||
|
||||
// The gpu device associated with the window's swapchain
|
||||
let window = app.window(w_id).unwrap();
|
||||
let device = window.swap_chain_device();
|
||||
let format = Frame::TEXTURE_FORMAT;
|
||||
let sample_count = window.msaa_samples();
|
||||
|
||||
// Load shader modules.
|
||||
let vs_mod = wgpu::shader_from_spirv_bytes(device, include_bytes!("../shaders/vert.spv"));
|
||||
let fs_mod = wgpu::shader_from_spirv_bytes(device, include_bytes!("../shaders/frag.spv"));
|
||||
|
||||
// Create the vertex buffer.
|
||||
let usage = wgpu::BufferUsage::VERTEX;
|
||||
let vertices_bytes = vertices_as_bytes(&VERTICES1[..]);
|
||||
let vertex_buffer1 = device.create_buffer_init(&BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: vertices_bytes,
|
||||
usage,
|
||||
});
|
||||
let vertices_bytes = vertices_as_bytes(&VERTICES2[..]);
|
||||
let vertex_buffer2 = device.create_buffer_init(&BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: vertices_bytes,
|
||||
usage,
|
||||
});
|
||||
|
||||
// Create the render pipeline.
|
||||
let bind_group_layout = wgpu::BindGroupLayoutBuilder::new().build(device);
|
||||
let bind_group = wgpu::BindGroupBuilder::new().build(device, &bind_group_layout);
|
||||
let pipeline_layout = wgpu::create_pipeline_layout(device, None, &[&bind_group_layout], &[]);
|
||||
let render_pipeline = wgpu::RenderPipelineBuilder::from_layout(&pipeline_layout, &vs_mod)
|
||||
.fragment_shader(&fs_mod)
|
||||
.color_format(format)
|
||||
.add_vertex_buffer::<Vertex>(&wgpu::vertex_attr_array![0 => Float32x2])
|
||||
.sample_count(sample_count)
|
||||
.build(device);
|
||||
|
||||
Model {
|
||||
bind_group,
|
||||
vertex_buffer1,
|
||||
vertex_buffer2,
|
||||
render_pipeline,
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the state of your `Model` into the given `Frame` here.
|
||||
fn view(_app: &App, model: &Model, frame: Frame) {
|
||||
// Using this we will encode commands that will be submitted to the GPU.
|
||||
let mut encoder = frame.command_encoder();
|
||||
|
||||
// The render pass can be thought of a single large command consisting of sub commands. Here we
|
||||
// begin a render pass that outputs to the frame's texture. Then we add sub-commands for
|
||||
// setting the bind group, render pipeline, vertex buffers and then finally drawing.
|
||||
let mut render_pass = wgpu::RenderPassBuilder::new()
|
||||
.color_attachment(frame.texture_view(), |color| color)
|
||||
.begin(&mut encoder);
|
||||
render_pass.set_bind_group(0, &model.bind_group, &[]);
|
||||
render_pass.set_pipeline(&model.render_pipeline);
|
||||
render_pass.set_vertex_buffer(0, model.vertex_buffer1.slice(..));
|
||||
|
||||
// We want to draw the whole range of vertices, and we're only drawing one instance of them.
|
||||
let vertex_range = 0..VERTICES1.len() as u32;
|
||||
let instance_range = 0..1;
|
||||
render_pass.draw(vertex_range, instance_range);
|
||||
|
||||
render_pass.set_bind_group(0, &model.bind_group, &[]);
|
||||
render_pass.set_pipeline(&model.render_pipeline);
|
||||
render_pass.set_vertex_buffer(0, model.vertex_buffer2.slice(..));
|
||||
|
||||
// We want to draw the whole range of vertices, and we're only drawing one instance of them.
|
||||
let vertex_range = 0..VERTICES2.len() as u32;
|
||||
let instance_range = 0..1;
|
||||
render_pass.draw(vertex_range, instance_range);
|
||||
|
||||
// Now we're done! The commands we added will be submitted after `view` completes.
|
||||
}
|
||||
|
||||
// See the `nannou::wgpu::bytes` documentation for why this is necessary.
|
||||
fn vertices_as_bytes(data: &[Vertex]) -> &[u8] {
|
||||
unsafe { wgpu::bytes::from_slice(data) }
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled16"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,112 +0,0 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use nannou::prelude::*;
|
||||
|
||||
// https://sighack.com/post/flood-fill-art-using-random-walks
|
||||
|
||||
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<IVec2> {
|
||||
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<Point>,
|
||||
visits: Vec<Point>,
|
||||
}
|
||||
|
||||
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..50 {
|
||||
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::<Vec<_>>();
|
||||
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));
|
||||
}
|
||||
|
||||
if frame.nth() < 50 {
|
||||
// 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);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled17"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,54 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
use utils::{curves::*, drawing::draw_soft_bg, *};
|
||||
|
||||
const POINTS: usize = 10;
|
||||
const SIZE: f32 = 300.0;
|
||||
|
||||
fn main() {
|
||||
nannou::app(model).update(update).simple_window(view).run();
|
||||
}
|
||||
|
||||
struct Model {
|
||||
curves: Vec<Chaikin>,
|
||||
}
|
||||
|
||||
fn model(_app: &App) -> Model {
|
||||
let curves = (0..10)
|
||||
.map(|_| {
|
||||
Chaikin::new(
|
||||
(0..POINTS)
|
||||
.map(|_| vec2_range(-1., 1.) * SIZE)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Model { curves }
|
||||
}
|
||||
|
||||
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, 0.01);
|
||||
|
||||
for (i, curve) in model.curves.iter().enumerate() {
|
||||
let div = map_sin(t * 0.7 + (2 * i) as f32, 0.15, 0.35);
|
||||
let h = map_sin(t * 0.3 + i as f32, 0., 1.);
|
||||
|
||||
draw.polyline().stroke_weight(1.5).points_colored(
|
||||
curve
|
||||
.points(div, 10)
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, p)| (p, hsla((h + i as f32 / 10000.0).fract(), 0.5, 0.5, 0.5))),
|
||||
);
|
||||
}
|
||||
|
||||
draw.to_frame(app, &frame).unwrap();
|
||||
utils::record::record(app, &frame);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled18"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,52 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
use utils::{drawing::draw_soft_bg, *};
|
||||
|
||||
fn main() {
|
||||
nannou::app(model).update(update).simple_window(view).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();
|
||||
draw_soft_bg(&draw, app, BLACK, 1.0);
|
||||
|
||||
let count = 10;
|
||||
for a in 0..360 {
|
||||
for i in 1..=count {
|
||||
let a = a as f32;
|
||||
let fi = i as f32;
|
||||
|
||||
let r = 1500.0 * (t + 0.01 * a + fi).cos();
|
||||
let r = r.powf(0.9 * fi / count as f32);
|
||||
// alternate directions of spin for each layer
|
||||
let s = if i % 2 == 0 { 1.0 } else { -1.0 } * map_sin(a * fi * fi, 0.1, 1.0);
|
||||
|
||||
let p = r * (s * t + fi + a).sin_cos().to_vec2();
|
||||
|
||||
// jitter
|
||||
let p = p + map_sin(t * 0.3 + TAU * 0.75, 0., 7.0) * vec2_circ();
|
||||
let sat = map_sin(t * 0.3 + TAU * 0.75, 0.4, 0.9);
|
||||
|
||||
let r = map_range(r, 0., 500.0, 0.5, 13.0).sqrt();
|
||||
|
||||
draw.ellipse()
|
||||
.radius(r)
|
||||
.xy(p)
|
||||
.color(hsl(a / 360.0, sat, 0.5));
|
||||
}
|
||||
}
|
||||
|
||||
draw.to_frame(app, &frame).unwrap();
|
||||
utils::record::record(app, &frame);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled19"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,66 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
use utils::{drawing::draw_soft_bg, *};
|
||||
|
||||
fn main() {
|
||||
nannou::app(model).update(update).simple_window(view).run();
|
||||
}
|
||||
|
||||
struct Walker {
|
||||
pos: Vec2,
|
||||
vel: Vec2,
|
||||
color: f32,
|
||||
}
|
||||
|
||||
struct Model {
|
||||
walkers: Vec<Walker>,
|
||||
}
|
||||
|
||||
fn model(_app: &App) -> Model {
|
||||
Model {
|
||||
walkers: (0..100)
|
||||
.map(|_| Walker {
|
||||
pos: Vec2::ZERO,
|
||||
vel: Vec2::ZERO,
|
||||
color: random_range(0.0, 1.0),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(app: &App, model: &mut Model, _update: Update) {
|
||||
let _t = app.elapsed_frames() as f32 / 60.0;
|
||||
|
||||
for walker in &mut model.walkers {
|
||||
walker.vel += vec2_range(-2.0, 1.0);
|
||||
walker.vel = walker.vel.normalize();
|
||||
|
||||
walker.pos += walker.vel;
|
||||
|
||||
// wrap around the box
|
||||
const SIZE: f32 = 100.0;
|
||||
if walker.pos.x.abs() > SIZE {
|
||||
walker.pos.x = -walker.pos.x;
|
||||
}
|
||||
if walker.pos.y.abs() > SIZE {
|
||||
walker.pos.y = -walker.pos.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, 0.01);
|
||||
|
||||
for walker in &model.walkers {
|
||||
let h = (t * 10.0 + walker.color * 50.0) / 360.0;
|
||||
draw.ellipse()
|
||||
.xy(walker.pos)
|
||||
.radius(1.0)
|
||||
.color(hsl(h.fract(), 0.7, 0.5));
|
||||
}
|
||||
|
||||
draw.to_frame(app, &frame).unwrap();
|
||||
utils::record::record(app, &frame);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled20"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,60 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
use utils::*;
|
||||
|
||||
// based on https://nbickford.wordpress.com/2011/04/03/the-minsky-circle-algorithm/
|
||||
|
||||
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 {
|
||||
points: (0..1000).map(|_| Vec2::ONE * 6.0).collect(),
|
||||
base_hue: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
fn advance(mut point: Vec2, t: f32) -> Vec2 {
|
||||
let d = map_sin(t * 1.1, 0.01, 0.12);
|
||||
let e = (t.sqrt() * 0.01 + 0.3).min(1.1);
|
||||
point.x -= (point.y * d).floor();
|
||||
point.y += (point.x * e).floor();
|
||||
point
|
||||
}
|
||||
|
||||
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 += random::<f32>();
|
||||
}
|
||||
|
||||
fn view(app: &App, model: &Model, frame: Frame) {
|
||||
let t = frame.nth() as f32 / 60.0;
|
||||
|
||||
let draw = app.draw();
|
||||
drawing::draw_soft_bg(&draw, app, BLACK, 0.01);
|
||||
|
||||
for &p in &model.points {
|
||||
let h = random_range(model.base_hue, model.base_hue + 60.0) / 360.0;
|
||||
draw.ellipse()
|
||||
.radius(map_sin(p.x.powi(3) + p.y.powi(7) + t * 0.1, 1.0, 3.0))
|
||||
.xy(p * 7.0)
|
||||
.color(hsla(h.fract(), 1.0, 0.5, 0.1));
|
||||
}
|
||||
|
||||
draw.to_frame(app, &frame).unwrap();
|
||||
utils::record::record(app, &frame);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled21"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,90 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
|
||||
fn main() {
|
||||
nannou::app(model)
|
||||
.update(update)
|
||||
.simple_window(view)
|
||||
.size(800, 800)
|
||||
.run();
|
||||
}
|
||||
|
||||
struct Model {}
|
||||
|
||||
const BALL_SIZE: f32 = 3.0;
|
||||
|
||||
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 shader(i: usize, j: usize, w: usize, h: usize, t: f32) -> Rgb {
|
||||
let x = i as f32 / w as f32;
|
||||
let y = j as f32 / h as f32;
|
||||
let pos = vec2(x, y);
|
||||
|
||||
creation(pos, t)
|
||||
}
|
||||
|
||||
// https://www.shadertoy.com/view/XsXXDn
|
||||
fn creation(pos: Vec2, t: f32) -> Rgb {
|
||||
let mut l = t;
|
||||
let mut z = t;
|
||||
let mut c = [0.0; 3];
|
||||
|
||||
for i in 0..3 {
|
||||
let mut uv = pos;
|
||||
let mut p = pos;
|
||||
|
||||
p -= Vec2::splat(0.5);
|
||||
z += 0.07;
|
||||
l = p.length();
|
||||
uv += p / l * (z.sin() + 1.) * abs((l * 9. - z * 2.).sin());
|
||||
c[i] = 0.01 / ((vec2(uv.x.fract(), uv.y.fract()) - Vec2::splat(0.5)).abs()).length();
|
||||
}
|
||||
|
||||
srgb(c[0] / l, c[1] / l, c[2] / l)
|
||||
}
|
||||
|
||||
fn view(app: &App, _model: &Model, frame: Frame) {
|
||||
let t = frame.nth() as f32 / 120.0;
|
||||
|
||||
let draw = app.draw();
|
||||
draw.background().color(BLACK);
|
||||
|
||||
let (l, top, w, h) = app.window_rect().l_t_w_h();
|
||||
|
||||
let cols = (w / BALL_SIZE) as usize;
|
||||
let rows = (h / BALL_SIZE) as usize;
|
||||
|
||||
for i in 0..cols {
|
||||
for j in 0..rows {
|
||||
let x = l + j as f32 * BALL_SIZE;
|
||||
let y = top - i as f32 * BALL_SIZE;
|
||||
let p = vec2(x, y)
|
||||
+ (t * 0.4).min(5.0)
|
||||
* 10.0
|
||||
* vec2(
|
||||
(t * 0.7 + (i * j) as f32).sin(),
|
||||
(t * 0.9 + (2 * i * j) as f32).cos(),
|
||||
);
|
||||
|
||||
let color = shader(i, j, cols, rows, t);
|
||||
|
||||
draw.quad()
|
||||
.points(
|
||||
p + BALL_SIZE * vec2(1., 1.),
|
||||
p + BALL_SIZE * vec2(1., -1.),
|
||||
p + BALL_SIZE * vec2(-1., -1.),
|
||||
p + BALL_SIZE * vec2(-1., 1.),
|
||||
)
|
||||
.xy(p)
|
||||
.color(color);
|
||||
}
|
||||
}
|
||||
|
||||
draw.to_frame(app, &frame).unwrap();
|
||||
utils::record::record(app, &frame);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled22"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,99 +0,0 @@
|
|||
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);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled23"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,69 +0,0 @@
|
|||
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 mut points = (0..count)
|
||||
.map(|i| (TAU * i as f32 / count as f32).sin_cos().to_vec2())
|
||||
.collect::<Vec<_>>();
|
||||
points.push(Vec2::ZERO);
|
||||
|
||||
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);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled24"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,67 +0,0 @@
|
|||
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);
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled25"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
num = "0.4.0"
|
||||
utils = { path = "../utils" }
|
|
@ -1,50 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
use num::complex::*;
|
||||
use utils::*;
|
||||
|
||||
fn main() {
|
||||
nannou::app(model)
|
||||
.update(update)
|
||||
.simple_window(view)
|
||||
.size(800, 800)
|
||||
.run();
|
||||
}
|
||||
|
||||
struct Model {}
|
||||
|
||||
const BALL_SIZE: f32 = 3.0;
|
||||
|
||||
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 shader(i: usize, j: usize, w: usize, h: usize, t: f32) -> Hsl {
|
||||
let x = (i as f32 / w as f32) - 0.5;
|
||||
let y = (j as f32 / h as f32) - 0.5;
|
||||
let x = x * 7.0;
|
||||
let y = y * 7.0;
|
||||
let mut v = Complex::new(y, x);
|
||||
|
||||
let a = map_sin(t * 0.5, 0.0, TAU);
|
||||
let c = Complex::from_polar(0.7885, a);
|
||||
|
||||
let iters = map_sin(t * 0.1, 10.0, 100.0);
|
||||
|
||||
for i in 0..(iters as usize) {
|
||||
v = v.powi(2) + c;
|
||||
|
||||
if v.norm() > 10.0 {
|
||||
return hsl(i as f32 / iters, 0.5, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
hsl(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
||||
fn view(app: &App, _model: &Model, frame: Frame) {
|
||||
utils::shaders::run(app, frame, BALL_SIZE, shader, vec2)
|
||||
}
|
|
@ -34,7 +34,7 @@ fn view(app: &App, _model: &Model, frame: Frame) {
|
|||
|
||||
let draw = app.draw();
|
||||
|
||||
if frame.nth() == 0 {
|
||||
if frame.nth() == 1 {
|
||||
draw.background().color(BG);
|
||||
} else {
|
||||
let win = app.window_rect();
|
||||
|
|
|
@ -9,25 +9,17 @@ fn main() {
|
|||
|
||||
struct Model {
|
||||
shape: Shapes,
|
||||
count: usize,
|
||||
}
|
||||
|
||||
fn model(_app: &App) -> Model {
|
||||
Model {
|
||||
shape: Shapes::new(0),
|
||||
count: 0,
|
||||
shape: Shapes::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(app: &App, model: &mut Model, _update: Update) {
|
||||
if app.elapsed_frames() % 60 == 0 && app.elapsed_frames() > 1 {
|
||||
if model.count >= 20 {
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
model.shape = Shapes::new(random_range(1, 7));
|
||||
|
||||
model.count += 1;
|
||||
if app.elapsed_frames() % 60 == 0 {
|
||||
model.shape = Shapes::new();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,7 +29,7 @@ fn view(app: &App, model: &Model, frame: Frame) {
|
|||
let draw = app.draw();
|
||||
if frame.nth() == 0 {
|
||||
draw.background().color(BLACK);
|
||||
} else if frame.nth() % 60 > 30 {
|
||||
} else if frame.nth() % 60 > 40 {
|
||||
let win = app.window_rect();
|
||||
draw.rect().wh(win.wh()).color(srgba(0.0, 0.0, 0.0, 0.2));
|
||||
}
|
||||
|
|
|
@ -3,115 +3,41 @@ use nannou::prelude::*;
|
|||
pub struct Shapes(Vec<Shape>);
|
||||
impl Shapes {
|
||||
pub fn draw(&self, draw: Draw) {
|
||||
let w = 1.0;
|
||||
|
||||
for shape in &self.0 {
|
||||
match shape {
|
||||
&Shape::Triangle {
|
||||
center,
|
||||
radius,
|
||||
rotation,
|
||||
} => {
|
||||
Shape::Triangle { center, radius } => {
|
||||
let points = vec![vec2(0., 1.), vec2(0.866, -0.5), vec2(-0.866, -0.5)]
|
||||
.into_iter()
|
||||
.map(|v| {
|
||||
vec2(
|
||||
v.x * rotation.cos() - v.y * rotation.sin(),
|
||||
v.x * rotation.sin() + v.y * rotation.cos(),
|
||||
)
|
||||
})
|
||||
.map(|v| v * radius + center)
|
||||
.map(|v| v * *radius + *center)
|
||||
.collect::<Vec<_>>();
|
||||
draw.polyline().weight(w).points_closed(points).color(PINK);
|
||||
draw.polyline().weight(3.).points_closed(points).color(PINK);
|
||||
}
|
||||
Shape::Circle { center, radius, .. } => {
|
||||
Shape::Circle { center, radius } => {
|
||||
draw.ellipse()
|
||||
.radius(*radius)
|
||||
.no_fill()
|
||||
.stroke_weight(w)
|
||||
.stroke_weight(3.)
|
||||
.xy(*center)
|
||||
.stroke_color(PINK);
|
||||
}
|
||||
&Shape::Line {
|
||||
center,
|
||||
radius,
|
||||
rotation,
|
||||
} => {
|
||||
let points = vec![vec2(-1.0, 0.), vec2(1.0, 0.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 * radius + center)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
draw.line()
|
||||
.stroke_weight(w)
|
||||
.start(points[0])
|
||||
.end(points[1])
|
||||
.color(PINK);
|
||||
}
|
||||
Shape::LongLine { center, radius, .. } => {
|
||||
draw.line()
|
||||
.stroke_weight(w)
|
||||
.start(Vec2::ZERO)
|
||||
.end(*center + center.normalize() * *radius)
|
||||
.color(PINK);
|
||||
}
|
||||
&Shape::Square {
|
||||
center,
|
||||
radius,
|
||||
rotation,
|
||||
} => {
|
||||
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 * radius + center)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
draw.polyline()
|
||||
.stroke_weight(w)
|
||||
.points_closed(points)
|
||||
.color(PINK);
|
||||
}
|
||||
Shape::Line { center, radius } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(children: usize) -> Self {
|
||||
pub fn new() -> Self {
|
||||
let root = Shape::random(Vec2::ZERO, 100.0);
|
||||
|
||||
let mut vec = vec![];
|
||||
|
||||
for _ in 0..children {
|
||||
for _ in 0..3 {
|
||||
let (c, r) = root.get_random_point_distance();
|
||||
let s = Shape::random(c, r);
|
||||
|
||||
let children = random_range(0, 5.min(children + 2));
|
||||
let children = random_range(0, 3);
|
||||
for _ in 0..children {
|
||||
let (c, r) = s.get_random_point_distance();
|
||||
let s = Shape::random(c, r);
|
||||
|
||||
let children = random_range(0, 3.min(children + 1));
|
||||
for _ in 0..children {
|
||||
let (c, r) = s.get_random_point_distance();
|
||||
let s = Shape::random(c, r);
|
||||
vec.push(s);
|
||||
}
|
||||
|
||||
vec.push(s);
|
||||
}
|
||||
|
||||
|
@ -123,144 +49,58 @@ impl Shapes {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! sh {
|
||||
( $($id:ident),* ) => {
|
||||
pub enum Shape {
|
||||
$(
|
||||
$id { center: Vec2, radius: f32, rotation: f32 },
|
||||
)*
|
||||
}
|
||||
};
|
||||
pub enum Shape {
|
||||
Triangle { center: Vec2, radius: f32 },
|
||||
Circle { center: Vec2, radius: f32 },
|
||||
Line { center: Vec2, radius: f32 },
|
||||
}
|
||||
|
||||
sh!(Triangle, Circle, Line, LongLine, Square);
|
||||
|
||||
fn random_sq_rot() -> f32 {
|
||||
[0.0, PI / 4.0][random_range(0, 2)]
|
||||
}
|
||||
fn random_tri_rot() -> f32 {
|
||||
[0.0, PI / 3.0][random_range(0, 2)]
|
||||
}
|
||||
fn random_line_rot() -> f32 {
|
||||
[0.0, PI / 3.0, PI / 2.0, PI / 4.0, PI][random_range(0, 4)]
|
||||
}
|
||||
|
||||
impl Shape {
|
||||
fn random(center: Vec2, radius: f32) -> Self {
|
||||
match random_range(0, 5) {
|
||||
0 => Self::tri(center, radius, random_tri_rot()),
|
||||
1 => Self::line(center, radius, random_line_rot()),
|
||||
2 if center.distance(Vec2::ZERO) > 0.01 => Self::long_line(center, radius, 0.0),
|
||||
3 => Self::square(center, radius, random_sq_rot()),
|
||||
_ => Self::circ(center, radius, 0.0),
|
||||
match random_range(0, 3) {
|
||||
0 => Self::tri(center, radius),
|
||||
1 => Self::line(center, radius),
|
||||
_ => Self::circ(center, radius),
|
||||
}
|
||||
}
|
||||
|
||||
fn tri(center: Vec2, radius: f32, rotation: f32) -> Self {
|
||||
Self::Triangle {
|
||||
center,
|
||||
radius,
|
||||
rotation,
|
||||
}
|
||||
fn tri(center: Vec2, radius: f32) -> Self {
|
||||
Self::Triangle { center, radius }
|
||||
}
|
||||
fn circ(center: Vec2, radius: f32, rotation: f32) -> Self {
|
||||
Self::Circle {
|
||||
center,
|
||||
radius,
|
||||
rotation,
|
||||
}
|
||||
fn circ(center: Vec2, radius: f32) -> Self {
|
||||
Self::Circle { center, radius }
|
||||
}
|
||||
fn line(center: Vec2, radius: f32, rotation: f32) -> Self {
|
||||
Self::Line {
|
||||
center,
|
||||
radius,
|
||||
rotation,
|
||||
}
|
||||
}
|
||||
fn long_line(center: Vec2, radius: f32, rotation: f32) -> Self {
|
||||
Self::LongLine {
|
||||
center,
|
||||
radius,
|
||||
rotation,
|
||||
}
|
||||
}
|
||||
fn square(center: Vec2, radius: f32, rotation: f32) -> Self {
|
||||
Self::Square {
|
||||
center,
|
||||
radius,
|
||||
rotation,
|
||||
}
|
||||
fn line(center: Vec2, radius: f32) -> Self {
|
||||
Self::Line { center, radius }
|
||||
}
|
||||
|
||||
fn get_random_point_distance(&self) -> (Vec2, f32) {
|
||||
match self {
|
||||
&Shape::Triangle {
|
||||
center,
|
||||
radius,
|
||||
rotation,
|
||||
} => {
|
||||
Shape::Triangle { center, radius } => {
|
||||
let points = vec![vec2(0., 1.), vec2(0.866, -0.5), vec2(-0.866, -0.5)]
|
||||
.into_iter()
|
||||
.map(|v| {
|
||||
vec2(
|
||||
v.x * rotation.cos() - v.y * rotation.sin(),
|
||||
v.x * rotation.sin() + v.y * rotation.cos(),
|
||||
)
|
||||
})
|
||||
.map(|v| v * radius + center)
|
||||
.map(|v| v * *radius + *center)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let denom = random_range(1.0, 4.0).floor();
|
||||
let denom = random_range(1.0, 5.0).floor();
|
||||
(points[random_range(0, points.len())], radius / denom)
|
||||
}
|
||||
&Shape::Circle { center, radius, .. } => {
|
||||
Shape::Circle { center, radius } => {
|
||||
let point = match random_range(0, 4) {
|
||||
0 => center + Vec2::X * radius,
|
||||
1 => center - Vec2::X * radius,
|
||||
2 => center + Vec2::Y * radius,
|
||||
_ => center - Vec2::Y * radius,
|
||||
0 => *center + Vec2::X * *radius,
|
||||
1 => *center - Vec2::X * *radius,
|
||||
2 => *center + Vec2::Y * *radius,
|
||||
_ => *center - Vec2::Y * *radius,
|
||||
};
|
||||
|
||||
let denom = random_range(1.0, 4.0).floor();
|
||||
let denom = random_range(1.0, 5.0).floor();
|
||||
(point, radius / denom)
|
||||
}
|
||||
&Shape::Line { center, radius, .. } => {
|
||||
let point = match random_range(0, 2) {
|
||||
0 => center - center.normalize() * radius,
|
||||
_ => center + center.normalize() * radius,
|
||||
};
|
||||
Shape::Line { center, radius } => {
|
||||
let point = todo!("one of the two vertices");
|
||||
|
||||
let denom = random_range(1.0, 4.0).floor();
|
||||
let denom = random_range(1.0, 5.0).floor();
|
||||
(point, radius / denom)
|
||||
}
|
||||
&Shape::LongLine { center, radius, .. } => {
|
||||
let denom = random_range(1.0, 4.0).floor();
|
||||
(center + center.normalize() * radius, radius / denom)
|
||||
}
|
||||
&Shape::Square {
|
||||
center,
|
||||
radius,
|
||||
rotation,
|
||||
} => {
|
||||
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 * radius + center)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let denom = random_range(1.0, 4.0).floor();
|
||||
(points[random_range(0, 4)], radius / denom)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled7"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,151 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
use std::collections::VecDeque;
|
||||
use utils::*;
|
||||
|
||||
fn main() {
|
||||
nannou::app(model).update(update).simple_window(view).run();
|
||||
}
|
||||
|
||||
struct Model {
|
||||
points: VecDeque<(Vec2, (f32, f32))>,
|
||||
}
|
||||
|
||||
const GOLDEN: f32 = 0.618033988;
|
||||
|
||||
fn point(i: usize) -> Vec2 {
|
||||
let theta = i as f32 * TAU * GOLDEN;
|
||||
let r = theta.sqrt();
|
||||
let x = r * theta.cos();
|
||||
let y = r * theta.sin();
|
||||
vec2(x, y)
|
||||
}
|
||||
|
||||
fn color() -> (f32, f32) {
|
||||
(
|
||||
random_range(345.0, 355.0) / 360.0,
|
||||
random_range(75.0, 93.0) / 100.0,
|
||||
)
|
||||
}
|
||||
|
||||
fn model(_app: &App) -> Model {
|
||||
Model {
|
||||
points: (0..2000).map(point).map(|a| (a * 10.0, color())).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn circ(p: Vec2, center: Vec2, r: f32) -> f32 {
|
||||
(p - center).length() - r
|
||||
}
|
||||
|
||||
fn spinny_circles(p: Vec2, t: f32) -> f32 {
|
||||
let mut c = vec![(Vec2::ZERO, 1.0)];
|
||||
|
||||
let mut ext = (0..7)
|
||||
.map(|i| {
|
||||
let v: Vec2 = (t + TAU * i as f32 / 7.0).sin_cos().into();
|
||||
(v * 100.0, 10.0)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
c.append(&mut ext);
|
||||
let mut ext = (0..7)
|
||||
.map(|i| {
|
||||
let v: Vec2 = (-t + TAU * i as f32 / 7.0).sin_cos().into();
|
||||
(v * 250.0, 10.0)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
c.append(&mut ext);
|
||||
|
||||
c.iter()
|
||||
.fold(f32::MAX, |acc, &(c, r)| acc.min(circ(p, c, r)))
|
||||
}
|
||||
|
||||
fn segment(p: Vec2, a: Vec2, b: Vec2) -> f32 {
|
||||
let pa = p - a;
|
||||
let ba = b - a;
|
||||
let h = (pa.dot(ba) / ba.length_squared()).clamp(0.0, 1.0);
|
||||
return (pa - ba * h).length();
|
||||
}
|
||||
fn pentagram(p: Vec2, center: Vec2, t: f32) -> f32 {
|
||||
let points = (0..5)
|
||||
.map(|i| {
|
||||
let v: Vec2 = (-t + TAU * i as f32 / 5.0).sin_cos().into();
|
||||
v * 100.0 - center
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
(0..5)
|
||||
.map(|i| (points[i], points[(i + 2) % 5]))
|
||||
.fold(f32::MAX, |acc, (a, b)| acc.min(segment(p, a, b)))
|
||||
}
|
||||
fn pentagrams(p: Vec2, t: f32) -> f32 {
|
||||
(0..5)
|
||||
.map(|i| {
|
||||
let v: Vec2 = (t / 10.0 + TAU * i as f32 / 5.0).sin_cos().into();
|
||||
let v = v * 330.0;
|
||||
pentagram(p, v, t)
|
||||
})
|
||||
.fold(f32::MAX, |acc, a| acc.min(a))
|
||||
}
|
||||
|
||||
fn f(p: Vec2, t: f32) -> f32 {
|
||||
spinny_circles(p, t).min(pentagrams(p, t))
|
||||
}
|
||||
|
||||
fn norm_f(p: Vec2, t: f32) -> Vec2 {
|
||||
const H: f32 = 0.0001;
|
||||
let k = vec2(1.0, -1.0);
|
||||
return (k * f(p + k * H, t)
|
||||
+ k.yy() * f(p + k.yy() * H, t)
|
||||
+ k.yx() * f(p + k.yx() * H, t)
|
||||
+ k.xx() * f(p + k.xx() * H, t))
|
||||
.normalize();
|
||||
}
|
||||
|
||||
fn update(app: &App, model: &mut Model, _update: Update) {
|
||||
let t = app.elapsed_frames() as f32 / 120.0;
|
||||
for (p, _) in &mut model.points {
|
||||
*p -= norm_f(*p, t) * f(*p, t).signum();
|
||||
}
|
||||
|
||||
if app.elapsed_frames() > 20 {
|
||||
for _ in 0..10 {
|
||||
model
|
||||
.points
|
||||
.push_back((6.0 * point(random_range(0, 1000)), color()));
|
||||
}
|
||||
}
|
||||
|
||||
// remove a bunch of them every once in a while
|
||||
// since we're already not running real time, who cares if we pause for a bit rigth?
|
||||
if app.elapsed_frames() % 200 == 0 {
|
||||
// drain_filter but i'm too lazy for nightly
|
||||
let mut i = 0;
|
||||
while i < model.points.len() {
|
||||
if f(model.points[i].0, t) < 0.0 {
|
||||
model.points.remove(i);
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn view(app: &App, model: &Model, frame: Frame) {
|
||||
let _t = frame.nth() as f32 / 120.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.005));
|
||||
}
|
||||
|
||||
for &(p, (h, l)) in &model.points {
|
||||
draw.ellipse().color(hsl(h, 1.0, l)).xy(p).radius(1.0);
|
||||
}
|
||||
|
||||
draw.to_frame(app, &frame).unwrap();
|
||||
|
||||
utils::record::record(app, &frame);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled8"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,133 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
use utils::*;
|
||||
|
||||
fn main() {
|
||||
nannou::app(model).update(update).simple_window(view).run();
|
||||
}
|
||||
|
||||
const POINTS: usize = 10;
|
||||
const NUM: usize = 200;
|
||||
|
||||
struct Model {
|
||||
points: Vec<Vec2>,
|
||||
offsets: Vec<Vec2>,
|
||||
|
||||
bg: Vec<(Vec2, f32)>,
|
||||
}
|
||||
impl Model {
|
||||
fn points(&self) -> Vec<Vec2> {
|
||||
self.points
|
||||
.windows(2)
|
||||
.flat_map(|p| {
|
||||
let a = p[0];
|
||||
let b = p[1];
|
||||
(0..NUM).map(move |i| {
|
||||
let i = i as f32 / NUM as f32;
|
||||
(1.0 - i) * a + i * b
|
||||
})
|
||||
})
|
||||
.zip(self.offsets.iter())
|
||||
.map(|(a, &b)| a + b)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn model(_app: &App) -> Model {
|
||||
let points = (0..POINTS)
|
||||
.map(|_| vec2(random_range(-1., 1.), random_range(-1., 1.)) * 200.0)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let offsets = vec![Vec2::ZERO; NUM * POINTS];
|
||||
|
||||
let bg = sequences::Halton::points(2.0, 3.0)
|
||||
.take(10000)
|
||||
.map(|v| (v - Vec2::splat(0.5)) * 1100.0)
|
||||
.filter(|v| v.x.abs() > 220.0 || v.y.abs() > 220.0)
|
||||
.map(|v| (v, 0.5))
|
||||
.collect();
|
||||
|
||||
Model {
|
||||
points,
|
||||
offsets,
|
||||
bg,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(app: &App, model: &mut Model, _update: Update) {
|
||||
let t = app.elapsed_frames() as f32 / 60.0;
|
||||
|
||||
for p in &mut model.offsets {
|
||||
*p *= 0.95;
|
||||
*p += 0.3 * vec2(random_range(-1.0, 1.0), random_range(-1.0, 1.0));
|
||||
}
|
||||
|
||||
for (i, p) in model.points.iter_mut().enumerate() {
|
||||
let a = i as f32 * 0.1;
|
||||
p.x = (t * a + i as f32).sin();
|
||||
p.y = (t * 1.3 * a + i as f32).cos();
|
||||
*p *= 200.0;
|
||||
}
|
||||
|
||||
for (i, p) in model.bg.iter_mut().enumerate() {
|
||||
p.1 = (t * 2.0 + i as f32).sin() + 1.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);
|
||||
} else {
|
||||
// we only want fading on the inner box,
|
||||
// outside of it we want a hard reset
|
||||
|
||||
let win = app.window_rect();
|
||||
draw.rect()
|
||||
.wh(win.wh())
|
||||
.color(srgba(1.0, 250.0 / 255.0, 250.0 / 255.0, 0.001));
|
||||
|
||||
draw.quad()
|
||||
.points(
|
||||
vec2(220.0, -1000.0),
|
||||
vec2(220.0, 1000.0),
|
||||
vec2(1000.0, 1000.0),
|
||||
vec2(1000.0, -1000.0),
|
||||
)
|
||||
.color(SNOW);
|
||||
draw.quad()
|
||||
.points(
|
||||
vec2(-220.0, -1000.0),
|
||||
vec2(-220.0, 1000.0),
|
||||
vec2(-1000.0, 1000.0),
|
||||
vec2(-1000.0, -1000.0),
|
||||
)
|
||||
.color(SNOW);
|
||||
draw.quad()
|
||||
.points(
|
||||
vec2(-1000.0, 220.0),
|
||||
vec2(-1000.0, 1000.0),
|
||||
vec2(1000.0, 1000.0),
|
||||
vec2(1000.0, 220.0),
|
||||
)
|
||||
.color(SNOW);
|
||||
draw.quad()
|
||||
.points(
|
||||
vec2(-1000.0, -220.0),
|
||||
vec2(-1000.0, -1000.0),
|
||||
vec2(1000.0, -1000.0),
|
||||
vec2(1000.0, -220.0),
|
||||
)
|
||||
.color(SNOW);
|
||||
}
|
||||
|
||||
draw.polyline().points(model.points()).color(BLACK);
|
||||
|
||||
for &(p, r) in &model.bg {
|
||||
draw.ellipse().xy(p).radius(r).color(BLACK);
|
||||
}
|
||||
|
||||
draw.to_frame(app, &frame).unwrap();
|
||||
utils::record::record(app, &frame);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "subtitled9"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -1,82 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
use utils::*;
|
||||
|
||||
fn main() {
|
||||
nannou::app(model).update(update).simple_window(view).run();
|
||||
}
|
||||
|
||||
struct Model {}
|
||||
|
||||
fn model(_app: &App) -> Model {
|
||||
Model {}
|
||||
}
|
||||
|
||||
fn update(_app: &App, _model: &mut Model, _update: Update) {}
|
||||
|
||||
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);
|
||||
} else {
|
||||
// we only want fading on the inner box,
|
||||
// outside of it we want a hard reset
|
||||
|
||||
let win = app.window_rect();
|
||||
draw.rect()
|
||||
.wh(win.wh())
|
||||
.color(srgba(1.0, 250.0 / 255.0, 250.0 / 255.0, 0.01));
|
||||
}
|
||||
|
||||
// okay so this is a bit of a hack
|
||||
// we draw the ones inside and outside the box in two separate passes
|
||||
// on the first one, we draw the ones inside the box, with a box of size 220
|
||||
// then we draw the blank stuff outside of a 200 box
|
||||
// then we draw the points outside the 200 box
|
||||
|
||||
// this is cause otherwise either the colored lines go outside the box,
|
||||
// or the colored lines finish too early
|
||||
// this works and it's still real time so
|
||||
// don't judge me uwu
|
||||
|
||||
// inner draw
|
||||
for i in 0..50 {
|
||||
let r = 1.5;
|
||||
let r2 = r * (50 + i) as f32 / 50.0;
|
||||
let v = vec2((t * r + i as f32).sin(), (t * r2 + (2 * i) as f32).sin()) * 300.0;
|
||||
|
||||
// while inside the box, draw a line to the last point
|
||||
if v.x.abs() < 220.0 && v.y.abs() < 220.0 {
|
||||
let t = t - 1.0 / 60.0;
|
||||
let v_prev = vec2((t * r + i as f32).sin(), (t * r2 + (2 * i) as f32).sin()) * 300.0;
|
||||
|
||||
let h_prev = map_sin((v_prev.x + v_prev.y) / 400.0 + i as f32, 0.0, 1.0);
|
||||
|
||||
draw.line()
|
||||
.stroke_weight(4.0)
|
||||
.points(v, v_prev)
|
||||
.color(hsl(h_prev, 0.5, 0.5));
|
||||
|
||||
let h = map_sin((v.x + v.y) / 400.0 + i as f32, 0.0, 1.0);
|
||||
draw.ellipse().radius(2.0).xy(v).color(hsl(h, 0.5, 0.5));
|
||||
}
|
||||
}
|
||||
|
||||
// draw exterior
|
||||
drawing::draw_exterior(&draw, 200.0, SNOW);
|
||||
|
||||
// outer draw
|
||||
for i in 0..50 {
|
||||
let r = 1.5;
|
||||
let r2 = r * (50 + i) as f32 / 50.0;
|
||||
let v = vec2((t * r + i as f32).sin(), (t * r2 + (2 * i) as f32).sin()) * 300.0;
|
||||
|
||||
if v.x.abs() > 201.0 || v.y.abs() > 201.0 {
|
||||
draw.ellipse().radius(2.0).xy(v).color(BLACK);
|
||||
}
|
||||
}
|
||||
|
||||
draw.to_frame(app, &frame).unwrap();
|
||||
utils::record::record(app, &frame);
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
use nannou::prelude::*;
|
||||
use utils::*;
|
||||
|
||||
fn main() {
|
||||
nannou::app(model).update(update).simple_window(view).run();
|
||||
|
@ -11,18 +10,13 @@ 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 update(_app: &App, _model: &mut Model, _update: Update) {}
|
||||
|
||||
fn view(app: &App, _model: &Model, frame: Frame) {
|
||||
let _t = frame.nth() as f32 / 60.0;
|
||||
|
||||
let draw = app.draw();
|
||||
draw.background().color(PLUM);
|
||||
|
||||
draw.ellipse().color(STEELBLUE);
|
||||
|
||||
draw.to_frame(app, &frame).unwrap();
|
||||
utils::record::record(app, &frame);
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
|
||||
pub struct Chaikin {
|
||||
pub points: Vec<Vec2>,
|
||||
}
|
||||
impl Chaikin {
|
||||
pub fn new(points: Vec<Vec2>) -> Self {
|
||||
Self { points }
|
||||
}
|
||||
|
||||
pub fn points(&self, div: f32, n: usize) -> Vec<Vec2> {
|
||||
let mut points = self.points.clone();
|
||||
for _ in 0..n {
|
||||
let first = *points.first().unwrap();
|
||||
let last = *points.last().unwrap();
|
||||
points = points
|
||||
.windows(2)
|
||||
.flat_map(|p| {
|
||||
let a = p[0];
|
||||
let b = p[1];
|
||||
|
||||
[a + div * (b - a), a + (1.0 - div) * (b - a)]
|
||||
})
|
||||
.collect();
|
||||
|
||||
points.insert(0, first);
|
||||
points.push(last);
|
||||
}
|
||||
points
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
use nannou::{color::IntoLinSrgba, draw::properties::ColorScalar, prelude::*};
|
||||
|
||||
pub fn draw_soft_bg(draw: &Draw, app: &App, color: impl IntoLinSrgba<ColorScalar>, alpha: f32) {
|
||||
if app.elapsed_frames() <= 1 {
|
||||
draw.background().color(color);
|
||||
} else {
|
||||
let mut color = color.into_lin_srgba();
|
||||
color.alpha = alpha;
|
||||
|
||||
let win = app.window_rect();
|
||||
draw.rect().wh(win.wh()).color(color);
|
||||
}
|
||||
}
|
||||
|
||||
/// Draws the opposite of a box
|
||||
pub fn draw_exterior(draw: &Draw, size: f32, color: impl IntoLinSrgba<ColorScalar> + Clone) {
|
||||
draw.quad()
|
||||
.points(
|
||||
vec2(size, -1000.0),
|
||||
vec2(size, 1000.0),
|
||||
vec2(1000.0, 1000.0),
|
||||
vec2(1000.0, -1000.0),
|
||||
)
|
||||
.color(color.clone());
|
||||
draw.quad()
|
||||
.points(
|
||||
vec2(-size, -1000.0),
|
||||
vec2(-size, 1000.0),
|
||||
vec2(-1000.0, 1000.0),
|
||||
vec2(-1000.0, -1000.0),
|
||||
)
|
||||
.color(color.clone());
|
||||
draw.quad()
|
||||
.points(
|
||||
vec2(-1000.0, size),
|
||||
vec2(-1000.0, 1000.0),
|
||||
vec2(1000.0, 1000.0),
|
||||
vec2(1000.0, size),
|
||||
)
|
||||
.color(color.clone());
|
||||
draw.quad()
|
||||
.points(
|
||||
vec2(-1000.0, -size),
|
||||
vec2(-1000.0, -1000.0),
|
||||
vec2(1000.0, -1000.0),
|
||||
vec2(1000.0, -size),
|
||||
)
|
||||
.color(color);
|
||||
}
|
|
@ -1,11 +1,5 @@
|
|||
pub mod color;
|
||||
pub mod curves;
|
||||
pub mod drawing;
|
||||
pub mod lsystems;
|
||||
pub mod record;
|
||||
pub mod sequences;
|
||||
pub mod shaders;
|
||||
pub mod turtle;
|
||||
|
||||
use nannou::prelude::*;
|
||||
|
||||
|
@ -20,40 +14,9 @@ pub fn map_cos(v: f32, out_min: f32, out_max: f32) -> f32 {
|
|||
|
||||
pub trait Vec2Extension {
|
||||
fn atan2(self) -> f32;
|
||||
fn yy(self) -> Self;
|
||||
fn yx(self) -> Self;
|
||||
fn xx(self) -> Self;
|
||||
}
|
||||
impl Vec2Extension for Vec2 {
|
||||
fn atan2(self) -> f32 {
|
||||
self.x.atan2(self.y)
|
||||
}
|
||||
fn yy(self) -> Self {
|
||||
vec2(self.y, self.y)
|
||||
}
|
||||
fn yx(self) -> Self {
|
||||
vec2(self.y, self.x)
|
||||
}
|
||||
fn xx(self) -> Self {
|
||||
vec2(self.x, self.x)
|
||||
}
|
||||
}
|
||||
pub trait Tup2Extension {
|
||||
fn to_vec2(self) -> Vec2;
|
||||
}
|
||||
impl Tup2Extension for (f32, f32) {
|
||||
fn to_vec2(self) -> Vec2 {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
/// returns a random vector in the unit circle
|
||||
pub fn vec2_circ() -> Vec2 {
|
||||
random_range(0., TAU).sin_cos().into()
|
||||
}
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
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));
|
||||
}
|
||||
}
|
|
@ -18,7 +18,6 @@ pub fn record(app: &App, frame: &Frame) {
|
|||
// Capture all frames to a directory called `/<path_to_nannou>/nannou/simple_capture`.
|
||||
.join("recordings")
|
||||
.join(app.exe_name().unwrap())
|
||||
.join("frames")
|
||||
// Name each file after the number of the frame.
|
||||
.join(format!("{:03}", frame.nth()))
|
||||
// The extension will be PNG. We also support tiff, bmp, gif, jpeg, webp and some others.
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
|
||||
pub struct Halton {
|
||||
i: usize,
|
||||
base: f32,
|
||||
}
|
||||
|
||||
impl Halton {
|
||||
pub fn new(base: f32) -> Self {
|
||||
Self { i: 0, base }
|
||||
}
|
||||
|
||||
pub fn points(base1: f32, base2: f32) -> impl Iterator<Item = Vec2> {
|
||||
Self::new(base1)
|
||||
.zip(Self::new(base2))
|
||||
.map(crate::Tup2Extension::to_vec2)
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Halton {
|
||||
type Item = f32;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut f = 1.0;
|
||||
let mut r = 0.0;
|
||||
let mut index = self.i as f32;
|
||||
|
||||
while index > 0.0 {
|
||||
f /= self.base;
|
||||
r += f * (index % self.base);
|
||||
index = (index / self.base).floor();
|
||||
}
|
||||
self.i += 1;
|
||||
Some(r)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VanDerCorput {
|
||||
i: usize,
|
||||
base: f32,
|
||||
}
|
||||
impl VanDerCorput {
|
||||
pub fn new(base: f32) -> Self {
|
||||
Self { i: 0, base }
|
||||
}
|
||||
pub fn points(base1: f32, base2: f32) -> impl Iterator<Item = Vec2> {
|
||||
Self::new(base1)
|
||||
.zip(Self::new(base2))
|
||||
.map(crate::Tup2Extension::to_vec2)
|
||||
}
|
||||
}
|
||||
impl Iterator for VanDerCorput {
|
||||
type Item = f32;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut q = 0.0;
|
||||
let mut bk = 1.0 / self.base;
|
||||
let mut i = self.i as f32;
|
||||
|
||||
while i > 0.0 {
|
||||
q += (i % self.base) * bk;
|
||||
i /= self.base;
|
||||
bk /= self.base;
|
||||
}
|
||||
|
||||
Some(q)
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
use nannou::prelude::*;
|
||||
|
||||
pub fn run<S, T>(app: &App, frame: Frame, ball_size: f32, shader: S, tile_movement: T)
|
||||
where
|
||||
S: Fn(usize, usize, usize, usize, f32) -> Hsl,
|
||||
T: Fn(f32, f32) -> Vec2,
|
||||
{
|
||||
let t = frame.nth() as f32 / 120.0;
|
||||
|
||||
let draw = app.draw();
|
||||
draw.background().color(BLACK);
|
||||
|
||||
let (l, top, w, h) = app.window_rect().l_t_w_h();
|
||||
|
||||
let cols = (w / ball_size) as usize;
|
||||
let rows = (h / ball_size) as usize;
|
||||
|
||||
for i in 0..cols {
|
||||
for j in 0..rows {
|
||||
let x = l + j as f32 * ball_size;
|
||||
let y = top - i as f32 * ball_size;
|
||||
let p = tile_movement(x, y);
|
||||
|
||||
let color = shader(i, j, cols, rows, t);
|
||||
|
||||
draw.quad()
|
||||
.points(
|
||||
p + ball_size * vec2(1., 1.),
|
||||
p + ball_size * vec2(1., -1.),
|
||||
p + ball_size * vec2(-1., -1.),
|
||||
p + ball_size * vec2(-1., 1.),
|
||||
)
|
||||
.xy(p)
|
||||
.color(color);
|
||||
}
|
||||
}
|
||||
|
||||
draw.to_frame(app, &frame).unwrap();
|
||||
super::record::record(app, &frame);
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,10 +7,8 @@ if [[ -z $1 ]]; then
|
|||
echo "example:"
|
||||
echo -e "\t$0 packagename"
|
||||
else
|
||||
rm -rf "recordings/$1/frames"
|
||||
mkdir -p "recordings/$1/videos"
|
||||
rm -rf "recordings/$1"
|
||||
cargo run --release --package $1 -- -record
|
||||
filename="video$(( $(find recordings/$1/videos -type f -exec basename -s .mp4 {} \; | sed 's/^video//' | sort -n | tail -n1) + 1)).mp4"
|
||||
ffmpeg -framerate 60 -i "recordings/$1/frames/%03d.png" -pix_fmt yuv420p "recordings/$1/videos/$filename"
|
||||
ffmpeg -framerate 60 -i "recordings/$1/%03d.png" -pix_fmt yuv420p "recordings/$1.mp4"
|
||||
echo "done"
|
||||
fi
|
||||
|
|
Loading…
Reference in New Issue