Skip to content

Instantly share code, notes, and snippets.

@fitzgen
Created December 24, 2018 04:13
Show Gist options
  • Save fitzgen/8f13bd45889d4cb1e003694d3505d2f2 to your computer and use it in GitHub Desktop.
Save fitzgen/8f13bd45889d4cb1e003694d3505d2f2 to your computer and use it in GitHub Desktop.
use nannou::noise::{NoiseModule, Seedable};
use nannou::prelude::*;
const WIDTH: u32 = 400;
const NOISE_FACTOR: f32 = 0.75;
const SEGMENT_LENGTH: u32 = 20;
const LINE_MARGIN: u32 = 8;
const LINE_NOISE_RANGE: f32 = LINE_MARGIN as f32 / 3.0;
fn main() {
nannou::run(model, event, view);
}
struct Line {
points: Vec<Vector2>,
}
impl Line {
fn draw(&self, noise: &nannou::noise::Perlin, draw: &nannou::app::Draw) {
for win in self.points.windows(2) {
hand_drawn_line(win[0], win[1], &noise, &draw);
}
}
}
struct Model {
lines: Vec<Line>,
}
fn model(app: &App) -> Model {
app.main_window()
.set_inner_size_pixels(WIDTH + WIDTH / 2, WIDTH + WIDTH / 2);
// Create the initial, center line.
let points: Vec<_> = (0..WIDTH / SEGMENT_LENGTH)
.map(|y| {
vec2(
0.0,
map_range(
y,
0,
WIDTH / SEGMENT_LENGTH,
-(WIDTH as f32 / 2.0),
WIDTH as f32 / 2.0,
),
)
})
.collect();
let line = Line { points };
let mut lines = vec![line];
// Add lines to the right.
for _ in 0..(WIDTH / LINE_MARGIN / 2) {
let reference = lines.last().unwrap();
let points: Vec<_> = reference
.points
.iter()
.map(|p| {
vec2(
LINE_MARGIN as f32 + random_range(-LINE_NOISE_RANGE, LINE_NOISE_RANGE) + p.x,
p.y + random_range(-LINE_NOISE_RANGE, LINE_NOISE_RANGE),
)
})
.collect();
let line = Line { points };
lines.push(line);
}
// Add lines to the left.
for i in 0..(WIDTH / LINE_MARGIN / 2) {
let reference = if i == 0 {
&lines[0]
} else {
lines.last().unwrap()
};
let points: Vec<_> = reference
.points
.iter()
.map(|p| {
vec2(
p.x - (LINE_MARGIN as f32) + random_range(-LINE_NOISE_RANGE, LINE_NOISE_RANGE),
p.y + random_range(-LINE_NOISE_RANGE, LINE_NOISE_RANGE),
)
})
.collect();
let line = Line { points };
lines.push(line);
}
Model { lines }
}
fn event(_app: &App, model: Model, _event: Event) -> Model {
model
}
fn hand_drawn_line(
from: Vector2,
to: Vector2,
noise: &nannou::noise::Perlin,
draw: &nannou::app::Draw,
) {
let mut from = from;
loop {
let delta = to - from;
if delta.magnitude().abs() < 1.0 {
draw.line().start(from).end(to);
return;
}
let epsilon = delta.normalize();
let normal = vec2(epsilon.y, -epsilon.x);
let noise = noise.get([from.x, from.y]);
assert!(-1.0 <= noise && noise <= 1.0, "noise = {}", noise);
let noise = normal * noise;
let next = from + (epsilon * (1.0 - NOISE_FACTOR)) + (noise * NOISE_FACTOR);
draw.line().start(from).end(next).half_thickness(0.75);
from = next;
}
}
fn view(app: &App, model: &Model, frame: Frame) -> Frame {
let draw = app.draw();
draw.background().color(BLACK);
let noise = nannou::noise::Perlin::new();
let noise = noise.set_seed((app.time * 1000.0) as usize);
for line in &model.lines {
line.draw(&noise, &draw);
}
draw.to_frame(app, &frame).unwrap();
frame
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment