From 3d0f2acea3d1ceda5aa8162f93bc05401d89323b Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Mon, 29 Mar 2021 20:22:26 -0500 Subject: [PATCH] fix: refactor parts of mandelbrot.rs --- src/lib.rs | 1 + src/main.rs | 18 +++++---- src/mandelbrot.rs | 98 ++++++++++++++++++++++++++++++----------------- 3 files changed, 73 insertions(+), 44 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bd0631c..9f0a770 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ +pub use crate::mandelbrot::Bounds; pub use crate::mandelbrot::Mandelbrot; mod mandelbrot; diff --git a/src/main.rs b/src/main.rs index d4d9987..2069a27 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ use bevy::{prelude::*, render::texture::TextureFormat}; -use mandelbrot::Mandelbrot; +use mandelbrot::{Bounds, Mandelbrot}; use std::time::Instant; fn main() { @@ -88,14 +88,16 @@ fn mandelbrot_render_system( let z = scale.zoom; let h = scale.horizontal; let v = scale.vertical; - let iters = scale.iterations; + let limit = scale.iterations; + + let x = ((-2.5 * z) + h, (1.0 * z) + h); + let y = ((-1.0 * z) - v, (1.0 * z) - v); + let bounds = Bounds::new(x, y); let start = Instant::now(); - texture.data.copy_from_slice(fractal.generate_scaled_image( - ((-2.5 * z) + h, (1.0 * z) + h), - ((-1.0 * z) - v, (1.0 * z) - v), - iters, - )); + texture + .data + .copy_from_slice(fractal.scaled_image(bounds, limit)); let _diff = Instant::now() - start; } } @@ -109,7 +111,7 @@ fn startup( mut materials: ResMut>, ) { let img_size = Vec2::new(Mandelbrot::width() as f32, Mandelbrot::height() as f32); - let img_buf = Mandelbrot::new().generate_image().to_vec(); + let img_buf = Mandelbrot::new().image().to_vec(); let texture_handle = textures.add(Texture::new( img_size, diff --git a/src/mandelbrot.rs b/src/mandelbrot.rs index 0dfe95f..17019d1 100644 --- a/src/mandelbrot.rs +++ b/src/mandelbrot.rs @@ -1,7 +1,43 @@ use num_complex::Complex; use rayon::prelude::*; -const MAX_ITERATIONS: u16 = 512; +pub struct Coordinate(usize, usize); + +impl Coordinate { + pub fn new(x: usize, y: usize) -> Self { + Self(x, y) + } + + pub fn x(&self) -> usize { + self.0 + } + + pub fn y(&self) -> usize { + self.1 + } +} + +#[derive(Debug, Clone, Copy)] +pub struct Bounds { + x: (f64, f64), + y: (f64, f64), +} + +impl Bounds { + pub const fn new(x: (f64, f64), y: (f64, f64)) -> Self { + Self { x, y } + } + pub fn x(&self) -> (f64, f64) { + self.x + } + + pub fn y(&self) -> (f64, f64) { + self.y + } +} + +const DEFAULT_MAX_ITERATIONS: u32 = 64; +const DEFAULT_BOUNDS: Bounds = Bounds::new((-2.5, 1.0), (-1.0, 1.0)); #[derive(Debug, Clone)] pub struct Mandelbrot { @@ -26,33 +62,32 @@ impl Mandelbrot { Self::IMG_HEIGHT } - pub fn generate_image(&mut self) -> &[u8] { + pub fn image(&mut self) -> &[u8] { + let max_iters = DEFAULT_MAX_ITERATIONS as f64; + self.texture_buffer .par_chunks_mut(4) .enumerate() .for_each(|(i, buf)| { - let iters = Self::new_escape_time(i, (-2.5, 1.0), (-1.0, 1.0), 64); - let normalized_iters = iters / MAX_ITERATIONS as f64; - let h = 0.5 + (10.0 * normalized_iters); - buf.copy_from_slice(&Self::hsv_to_rgb(h, 0.6, 1.0)); + let iters = Self::escape_time(i, DEFAULT_BOUNDS, DEFAULT_MAX_ITERATIONS); + let normalized_iters = iters / max_iters; + + let h = normalized_iters * 350.0; + let v = if iters == max_iters { 0.0 } else { 1.0 }; + buf.copy_from_slice(&Self::hsv_to_rgb(h, 1.0, v)); }); &self.texture_buffer } - pub fn generate_scaled_image( - &mut self, - x_bounds: (f64, f64), - y_bounds: (f64, f64), - max_iterations: u32, - ) -> &[u8] { + pub fn scaled_image(&mut self, bounds: Bounds, max_iterations: u32) -> &[u8] { self.texture_buffer .par_chunks_mut(4) .enumerate() .for_each(|(i, buf)| { let max_iters = max_iterations as f64; - let iters = Self::new_escape_time(i, x_bounds, y_bounds, max_iterations); + let iters = Self::escape_time(i, bounds, max_iterations); let normalized_iters = iters / max_iters; let h = normalized_iters * 350.0; @@ -63,17 +98,11 @@ impl Mandelbrot { &self.texture_buffer } - fn new_escape_time( - i: usize, - x_bounds: (f64, f64), - y_bounds: (f64, f64), - max_iterations: u32, - ) -> f64 { - let px = i % Self::IMG_WIDTH; - let py = i / Self::IMG_WIDTH; - let c = Self::coords_to_complex(px, py, x_bounds, y_bounds); + fn escape_time(i: usize, bounds: Bounds, max_iterations: u32) -> f64 { + let point = Coordinate::new(i % Self::IMG_WIDTH, i / Self::IMG_WIDTH); + let c = Self::coords_to_complex(point, bounds); - Self::new_calc_num_iters(c, max_iterations) + Self::count_iterations(c, max_iterations) } #[inline] @@ -108,7 +137,7 @@ impl Mandelbrot { [r, g, b, a] } - fn new_calc_num_iters(c: Complex, max_iterations: u32) -> f64 { + fn count_iterations(c: Complex, max_iterations: u32) -> f64 { let mut z: Complex = Complex::new(0.0, 0.0); let mut num_iters: u32 = 0; @@ -132,29 +161,26 @@ impl Mandelbrot { } } - fn coords_to_complex( - px: usize, - py: usize, - x_bounds: (f64, f64), - y_bounds: (f64, f64), - ) -> Complex { + fn coords_to_complex(point: Coordinate, bounds: Bounds) -> Complex { Complex::new( - Self::scale_width(px, x_bounds), - Self::scale_height(py, y_bounds), + Self::scale_width(point.x(), bounds.x()), + Self::scale_height(point.y(), bounds.y()), ) } - fn scale_width(px: usize, x_bounds: (f64, f64)) -> f64 { + #[inline] + fn scale_width(x: usize, bounds: (f64, f64)) -> f64 { // const X_MIN: f64 = -2.5; // const X_MAX: f64 = 1.0; - x_bounds.0 + ((x_bounds.1 - x_bounds.0) * (px as f64 - 0.0)) / Self::IMG_WIDTH as f64 - 0.0 + bounds.0 + ((bounds.1 - bounds.0) * (x as f64 - 0.0)) / Self::IMG_WIDTH as f64 - 0.0 } - fn scale_height(py: usize, y_bounds: (f64, f64)) -> f64 { + #[inline] + fn scale_height(y: usize, bounds: (f64, f64)) -> f64 { // const Y_MIN: f64 = -1.0; // const Y_MAX: f64 = 1.0; - y_bounds.0 + ((y_bounds.1 - y_bounds.0) * (py as f64 - 0.0)) / Self::IMG_HEIGHT as f64 - 0.0 + bounds.0 + ((bounds.1 - bounds.0) * (y as f64 - 0.0)) / Self::IMG_HEIGHT as f64 - 0.0 } }