1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
use async_std::{fs::File, io, prelude::*, task, io::BufWriter};
fn lerp(fraction: f64, from: f64, to: f64) -> f64 {
from + fraction * (to - from)
}
fn compute_pixel(re: f64, im: f64) -> u32 {
let mut a = re;
let mut b = im;
let mut a2 = a * a;
let mut b2 = b * b;
let mut niters = 0;
while a2 + b2 < 4.0 {
b = 2.0 * a * b + im;
a = a2 - b2 + re;
a2 = a * a;
b2 = b * b;
niters += 1;
if niters >= 10240 { break; }
}
niters
}
async fn compute_row(im: f64, re_min: f64, re_max: f64, width: usize) -> Vec<u32> {
let mut row = Vec::new();
row.resize(width, 0);
for i in 0..width {
row[i] = compute_pixel(lerp((i as f64) / (width as f64), re_min, re_max), im);
}
row
}
async fn write_image(fname: &str, rows: &Vec<Vec<u32>>) -> io::Result<()> {
let width = rows[0].len();
let height = rows.len();
let maxval = rows.iter().map(|row| row.iter().max().unwrap()).max().unwrap();
let mut out_vec: Vec<u8> = Vec::new();
let mut writer = BufWriter::new(&mut out_vec);
write!(writer, "P2\n{} {}\n{}\n", width, height, maxval).await?;
for row in rows {
for item in row {
write!(writer, "{} ", item).await?;
}
writeln!(writer).await?;
}
let mut file = File::create(fname).await?;
file.write(&out_vec).await?;
file.flush().await?;
Ok(())
}
async fn compute_brot(fname: &str, width: usize, height: usize, left_top: (f64, f64), right_bottom: (f64, f64)) -> io::Result<()> {
println!("Spawning...");
let mut join_handles = Vec::with_capacity(height);
for i in 0..height {
let im = lerp(i as f64 / height as f64, left_top.1, right_bottom.1);
// Note: spawn to not run within the same thread
join_handles.push(task::spawn(compute_row(im, left_top.0, right_bottom.0, width)));
}
println!("Awaiting...");
let mut rows = Vec::with_capacity(height);
for jh in join_handles {
rows.push(jh.await);
}
println!("Writing...");
write_image(fname, &rows).await
}
fn main() -> io::Result<()> {
// Note: the following does not work:
// task::block_on(task::spawn(compute_brot("out.ppm", 1920, 1080, (-1.5, 1.0), (1.0, -1.0))))
// You get a scary large futures error about Send.
task::block_on(async {
let width = 1920;
let height = 1080;
let left = -1.8;
let right = 1.5;
let height_im = height as f64 / width as f64 * (right - left);
let top = height_im / 2.0;
let bottom = -height_im / 2.0;
compute_brot("out.ppm", width, height, (left, top), (right, bottom)).await
})
}
// vim: set sw=4 ts=4 et:
|