diff --git a/.gitignore b/.gitignore index ea8c4bf..0d533ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /target +imgs/* +*.mp4 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8201808 --- /dev/null +++ b/Makefile @@ -0,0 +1,3 @@ +default: + cargo r + ffmpeg -framerate 25 -i imgs/%d.png -crf 20 -pix_fmt yuv420p output.mp4 diff --git a/src/main.rs b/src/main.rs index c884596..32fb56a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,48 +2,61 @@ use image::{ImageBuffer, Rgb}; use rayon::prelude::*; // Image size. -const IMGW: u32 = 1000; -const IMGH: u32 = 1000; +const IMGW: u32 = 1024; +const IMGH: u32 = 1024; // Fractal settings. -const MAXITER: u32 = 600; +const MAXITER: u32 = IMGW; +const MAXITER_F64: f64 = MAXITER as f64; const ESCRAD: f64 = 2.4; -// Fractal bounds. -const XMIN: f64 = 2.0; -const XMAX: f64 = -2.0; -const YMIN: f64 = 2.0; -const YMAX: f64 = -2.0; - fn main() { let w = IMGW as f64; let h = IMGH as f64; - let pxs: Vec = (0..IMGH) - .into_par_iter() - .flat_map(|y| { - let fy = y as f64; - (0..IMGW) - .into_par_iter() - .flat_map(move |x| { - let cx = map_range(x as f64, 0.0, w, XMIN, XMAX); - let cy = map_range(fy, 0.0, h, YMIN, YMAX); - let c = num_complex::Complex::new(cx, cy); + // Fractal bounds. + let mut width: f64 = 2.0; // Initial frame width + let mut xmin: f64 = -1.0; + let mut ymin: f64 = -1.0; - // Compute color for each pixel. - col_map(esc_time(c)).to_vec() - }) - .collect::>() - }) - .collect(); + let target_x = -0.4638686756; + let target_y = 0.0723647; - // Create the image from the pixel buffer. - let img = ImageBuffer::, _>::from_raw(IMGW, IMGH, pxs).unwrap(); + let zoom_factor = 1.2; - img.save("h.png").unwrap(); - println!("Done."); + for i in 1..200 { + let pxs: Vec = (0..IMGH) + .into_par_iter() + .flat_map(|y| { + let fy = y as f64; + (0..IMGW) + .into_par_iter() + .flat_map(move |x| { + let cx = map_range(x as f64, 0.0, w, xmin, xmin + width); + let cy = map_range(fy, 0.0, h, ymin, ymin + width); + let c = num_complex::Complex::new(cx, cy); + + // Compute color for each pixel. + col_map(esc_time(c)).to_vec() + }) + .collect::>() + }) + .collect(); + + // Create the image from the pixel buffer. + let img = ImageBuffer::, _>::from_raw(IMGW, IMGH, pxs).unwrap(); + + img.save(format!("imgs/{i}.png")).unwrap(); + println!("#{i} done."); + + // Adjust bounds for the next zoom level + xmin = target_x - width / 2.0; + ymin = target_y - width / 2.0; + width /= zoom_factor; // Zoom in by reducing width + } } + // Maps a value from one range to another. fn map_range(val: f64, imin: f64, imax: f64, omin: f64, omax: f64) -> f64 { omin + (val - imin) * (omax - omin) / (imax - imin) @@ -66,8 +79,8 @@ fn col_map(iter: u32) -> [u8; 3] { if iter == MAXITER { [0, 0, 0] // Black for points that never escape. } else { - let t = iter as f64 / MAXITER as f64; - let c = (t * 700.0) as u8; + let t = iter as f64 / MAXITER_F64; + let c = (t * MAXITER_F64) as u8; [c, c, c] } }