Compare commits
No commits in common. "b21d7d56b31e19ab8a19b4029107e044d3db8e5b" and "e7b0735bcf76aabbb2023158230ee10b412b868d" have entirely different histories.
b21d7d56b3
...
e7b0735bcf
|
@ -2348,22 +2348,6 @@ dependencies = [
|
||||||
"utils",
|
"utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "subtitled10"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"nannou",
|
|
||||||
"utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "subtitled11"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"nannou",
|
|
||||||
"utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtitled2"
|
name = "subtitled2"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -2404,30 +2388,6 @@ dependencies = [
|
||||||
"utils",
|
"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]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.74"
|
version = "1.0.74"
|
||||||
|
|
|
@ -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,159 +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
|
|
||||||
100.0 * vec2(v.x, v.z)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
// make all pairs of points
|
|
||||||
let p = p
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.flat_map(|(i, a)| p[i + 1..].iter().map(move |b| (a, b)));
|
|
||||||
for (&a, &b) in p {
|
|
||||||
draw.line().points(a, b).color(BLACK);
|
|
||||||
}
|
|
||||||
|
|
||||||
draw.to_frame(app, &frame).unwrap();
|
|
||||||
utils::record::record(app, &frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Automata {
|
|
||||||
points: Vec<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],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -34,7 +34,7 @@ fn view(app: &App, _model: &Model, frame: Frame) {
|
||||||
|
|
||||||
let draw = app.draw();
|
let draw = app.draw();
|
||||||
|
|
||||||
if frame.nth() == 0 {
|
if frame.nth() == 1 {
|
||||||
draw.background().color(BG);
|
draw.background().color(BG);
|
||||||
} else {
|
} else {
|
||||||
let win = app.window_rect();
|
let win = app.window_rect();
|
||||||
|
|
|
@ -9,25 +9,17 @@ fn main() {
|
||||||
|
|
||||||
struct Model {
|
struct Model {
|
||||||
shape: Shapes,
|
shape: Shapes,
|
||||||
count: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn model(_app: &App) -> Model {
|
fn model(_app: &App) -> Model {
|
||||||
Model {
|
Model {
|
||||||
shape: Shapes::new(0),
|
shape: Shapes::new(),
|
||||||
count: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(app: &App, model: &mut Model, _update: Update) {
|
fn update(app: &App, model: &mut Model, _update: Update) {
|
||||||
if app.elapsed_frames() % 60 == 0 && app.elapsed_frames() > 1 {
|
if app.elapsed_frames() % 60 == 0 {
|
||||||
if model.count >= 20 {
|
model.shape = Shapes::new();
|
||||||
std::process::exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
model.shape = Shapes::new(random_range(1, 7));
|
|
||||||
|
|
||||||
model.count += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +29,7 @@ fn view(app: &App, model: &Model, frame: Frame) {
|
||||||
let draw = app.draw();
|
let draw = app.draw();
|
||||||
if frame.nth() == 0 {
|
if frame.nth() == 0 {
|
||||||
draw.background().color(BLACK);
|
draw.background().color(BLACK);
|
||||||
} else if frame.nth() % 60 > 30 {
|
} else if frame.nth() % 60 > 40 {
|
||||||
let win = app.window_rect();
|
let win = app.window_rect();
|
||||||
draw.rect().wh(win.wh()).color(srgba(0.0, 0.0, 0.0, 0.2));
|
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>);
|
pub struct Shapes(Vec<Shape>);
|
||||||
impl Shapes {
|
impl Shapes {
|
||||||
pub fn draw(&self, draw: Draw) {
|
pub fn draw(&self, draw: Draw) {
|
||||||
let w = 1.0;
|
|
||||||
|
|
||||||
for shape in &self.0 {
|
for shape in &self.0 {
|
||||||
match shape {
|
match shape {
|
||||||
&Shape::Triangle {
|
Shape::Triangle { center, radius } => {
|
||||||
center,
|
|
||||||
radius,
|
|
||||||
rotation,
|
|
||||||
} => {
|
|
||||||
let points = vec![vec2(0., 1.), vec2(0.866, -0.5), vec2(-0.866, -0.5)]
|
let points = vec![vec2(0., 1.), vec2(0.866, -0.5), vec2(-0.866, -0.5)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|v| {
|
.map(|v| v * *radius + *center)
|
||||||
vec2(
|
|
||||||
v.x * rotation.cos() - v.y * rotation.sin(),
|
|
||||||
v.x * rotation.sin() + v.y * rotation.cos(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map(|v| v * radius + center)
|
|
||||||
.collect::<Vec<_>>();
|
.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()
|
draw.ellipse()
|
||||||
.radius(*radius)
|
.radius(*radius)
|
||||||
.no_fill()
|
.no_fill()
|
||||||
.stroke_weight(w)
|
.stroke_weight(3.)
|
||||||
.xy(*center)
|
.xy(*center)
|
||||||
.stroke_color(PINK);
|
.stroke_color(PINK);
|
||||||
}
|
}
|
||||||
&Shape::Line {
|
Shape::Line { center, radius } => {}
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(children: usize) -> Self {
|
pub fn new() -> Self {
|
||||||
let root = Shape::random(Vec2::ZERO, 100.0);
|
let root = Shape::random(Vec2::ZERO, 100.0);
|
||||||
|
|
||||||
let mut vec = vec![];
|
let mut vec = vec![];
|
||||||
|
|
||||||
for _ in 0..children {
|
for _ in 0..3 {
|
||||||
let (c, r) = root.get_random_point_distance();
|
let (c, r) = root.get_random_point_distance();
|
||||||
let s = Shape::random(c, r);
|
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 {
|
for _ in 0..children {
|
||||||
let (c, r) = s.get_random_point_distance();
|
let (c, r) = s.get_random_point_distance();
|
||||||
let s = Shape::random(c, r);
|
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);
|
vec.push(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,144 +49,58 @@ impl Shapes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! sh {
|
pub enum Shape {
|
||||||
( $($id:ident),* ) => {
|
Triangle { center: Vec2, radius: f32 },
|
||||||
pub enum Shape {
|
Circle { center: Vec2, radius: f32 },
|
||||||
$(
|
Line { center: Vec2, radius: f32 },
|
||||||
$id { center: Vec2, radius: f32, rotation: 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 {
|
impl Shape {
|
||||||
fn random(center: Vec2, radius: f32) -> Self {
|
fn random(center: Vec2, radius: f32) -> Self {
|
||||||
match random_range(0, 5) {
|
match random_range(0, 3) {
|
||||||
0 => Self::tri(center, radius, random_tri_rot()),
|
0 => Self::tri(center, radius),
|
||||||
1 => Self::line(center, radius, random_line_rot()),
|
1 => Self::line(center, radius),
|
||||||
2 if center.distance(Vec2::ZERO) > 0.01 => Self::long_line(center, radius, 0.0),
|
_ => Self::circ(center, radius),
|
||||||
3 => Self::square(center, radius, random_sq_rot()),
|
|
||||||
_ => Self::circ(center, radius, 0.0),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tri(center: Vec2, radius: f32, rotation: f32) -> Self {
|
fn tri(center: Vec2, radius: f32) -> Self {
|
||||||
Self::Triangle {
|
Self::Triangle { center, radius }
|
||||||
center,
|
|
||||||
radius,
|
|
||||||
rotation,
|
|
||||||
}
|
}
|
||||||
|
fn circ(center: Vec2, radius: f32) -> Self {
|
||||||
|
Self::Circle { center, radius }
|
||||||
}
|
}
|
||||||
fn circ(center: Vec2, radius: f32, rotation: f32) -> Self {
|
fn line(center: Vec2, radius: f32) -> Self {
|
||||||
Self::Circle {
|
Self::Line { center, radius }
|
||||||
center,
|
|
||||||
radius,
|
|
||||||
rotation,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 get_random_point_distance(&self) -> (Vec2, f32) {
|
fn get_random_point_distance(&self) -> (Vec2, f32) {
|
||||||
match self {
|
match self {
|
||||||
&Shape::Triangle {
|
Shape::Triangle { center, radius } => {
|
||||||
center,
|
|
||||||
radius,
|
|
||||||
rotation,
|
|
||||||
} => {
|
|
||||||
let points = vec![vec2(0., 1.), vec2(0.866, -0.5), vec2(-0.866, -0.5)]
|
let points = vec![vec2(0., 1.), vec2(0.866, -0.5), vec2(-0.866, -0.5)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|v| {
|
.map(|v| v * *radius + *center)
|
||||||
vec2(
|
|
||||||
v.x * rotation.cos() - v.y * rotation.sin(),
|
|
||||||
v.x * rotation.sin() + v.y * rotation.cos(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map(|v| v * radius + center)
|
|
||||||
.collect::<Vec<_>>();
|
.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)
|
(points[random_range(0, points.len())], radius / denom)
|
||||||
}
|
}
|
||||||
&Shape::Circle { center, radius, .. } => {
|
Shape::Circle { center, radius } => {
|
||||||
let point = match random_range(0, 4) {
|
let point = match random_range(0, 4) {
|
||||||
0 => center + Vec2::X * radius,
|
0 => *center + Vec2::X * *radius,
|
||||||
1 => center - Vec2::X * radius,
|
1 => *center - Vec2::X * *radius,
|
||||||
2 => center + Vec2::Y * radius,
|
2 => *center + Vec2::Y * *radius,
|
||||||
_ => 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)
|
(point, radius / denom)
|
||||||
}
|
}
|
||||||
&Shape::Line { center, radius, .. } => {
|
Shape::Line { center, radius } => {
|
||||||
let point = match random_range(0, 2) {
|
let point = todo!("one of the two vertices");
|
||||||
0 => center - center.normalize() * radius,
|
|
||||||
_ => center + center.normalize() * radius,
|
|
||||||
};
|
|
||||||
|
|
||||||
let denom = random_range(1.0, 4.0).floor();
|
let denom = random_range(1.0, 5.0).floor();
|
||||||
(point, radius / denom)
|
(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 nannou::prelude::*;
|
||||||
use utils::*;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
nannou::app(model).update(update).simple_window(view).run();
|
nannou::app(model).update(update).simple_window(view).run();
|
||||||
|
@ -11,18 +10,13 @@ fn model(_app: &App) -> Model {
|
||||||
Model {}
|
Model {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(app: &App, _model: &mut Model, _update: Update) {
|
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) {
|
fn view(app: &App, _model: &Model, frame: Frame) {
|
||||||
let _t = frame.nth() as f32 / 60.0;
|
let _t = frame.nth() as f32 / 60.0;
|
||||||
|
|
||||||
let draw = app.draw();
|
let draw = app.draw();
|
||||||
draw.background().color(PLUM);
|
draw.background().color(PLUM);
|
||||||
|
|
||||||
draw.ellipse().color(STEELBLUE);
|
draw.ellipse().color(STEELBLUE);
|
||||||
|
|
||||||
draw.to_frame(app, &frame).unwrap();
|
draw.to_frame(app, &frame).unwrap();
|
||||||
utils::record::record(app, &frame);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
use nannou::{color::IntoLinSrgba, draw::properties::ColorScalar, prelude::*};
|
|
||||||
|
|
||||||
/// 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,7 +1,5 @@
|
||||||
pub mod color;
|
pub mod color;
|
||||||
pub mod drawing;
|
|
||||||
pub mod record;
|
pub mod record;
|
||||||
pub mod sequences;
|
|
||||||
|
|
||||||
use nannou::prelude::*;
|
use nannou::prelude::*;
|
||||||
|
|
||||||
|
@ -16,29 +14,9 @@ pub fn map_cos(v: f32, out_min: f32, out_max: f32) -> f32 {
|
||||||
|
|
||||||
pub trait Vec2Extension {
|
pub trait Vec2Extension {
|
||||||
fn atan2(self) -> f32;
|
fn atan2(self) -> f32;
|
||||||
fn yy(self) -> Self;
|
|
||||||
fn yx(self) -> Self;
|
|
||||||
fn xx(self) -> Self;
|
|
||||||
}
|
}
|
||||||
impl Vec2Extension for Vec2 {
|
impl Vec2Extension for Vec2 {
|
||||||
fn atan2(self) -> f32 {
|
fn atan2(self) -> f32 {
|
||||||
self.x.atan2(self.y)
|
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ pub fn record(app: &App, frame: &Frame) {
|
||||||
// Capture all frames to a directory called `/<path_to_nannou>/nannou/simple_capture`.
|
// Capture all frames to a directory called `/<path_to_nannou>/nannou/simple_capture`.
|
||||||
.join("recordings")
|
.join("recordings")
|
||||||
.join(app.exe_name().unwrap())
|
.join(app.exe_name().unwrap())
|
||||||
.join("frames")
|
|
||||||
// Name each file after the number of the frame.
|
// Name each file after the number of the frame.
|
||||||
.join(format!("{:03}", frame.nth()))
|
.join(format!("{:03}", frame.nth()))
|
||||||
// The extension will be PNG. We also support tiff, bmp, gif, jpeg, webp and some others.
|
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,9 +7,8 @@ if [[ -z $1 ]]; then
|
||||||
echo "example:"
|
echo "example:"
|
||||||
echo -e "\t$0 packagename"
|
echo -e "\t$0 packagename"
|
||||||
else
|
else
|
||||||
rm -rf "recordings/$1/frames"
|
rm -rf "recordings/$1"
|
||||||
cargo run --release --package $1 -- -record
|
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/%03d.png" -pix_fmt yuv420p "recordings/$1.mp4"
|
||||||
ffmpeg -framerate 60 -i "recordings/$1/frames/%03d.png" -pix_fmt yuv420p "recordings/$1/videos/$filename"
|
|
||||||
echo "done"
|
echo "done"
|
||||||
fi
|
fi
|
||||||
|
|
Loading…
Reference in New Issue