feat: pure software generation of mandelbrot

This commit is contained in:
Rekai Nyangadzayi Musuka 2020-11-26 12:58:14 -06:00
parent e8e31ad5b1
commit 8a2a5bd108
2 changed files with 44 additions and 38 deletions

View File

@ -6,10 +6,10 @@ fn main() {
// Mandelbrot::escape_time_image(); // Mandelbrot::escape_time_image();
App::build() App::build()
.add_plugins(DefaultPlugins) .add_plugins(DefaultPlugins)
.add_startup_system(startup.system())
.add_resource(SpriteScale::default()) .add_resource(SpriteScale::default())
.add_startup_system(png_startup.system())
.add_system(mandelbrot_render_system.system()) .add_system(mandelbrot_render_system.system())
.add_system(mandelbrot_input_scale_system.system()) .add_system(transform_mandelbrot_system.system())
.run(); .run();
} }
@ -31,7 +31,7 @@ impl Default for SpriteScale {
} }
} }
fn mandelbrot_input_scale_system( fn transform_mandelbrot_system(
input: Res<Input<KeyCode>>, input: Res<Input<KeyCode>>,
mut scale: ResMut<SpriteScale>, mut scale: ResMut<SpriteScale>,
// camera: Res<Camera>, // camera: Res<Camera>,
@ -52,9 +52,6 @@ fn mandelbrot_input_scale_system(
} }
} }
const X_BOUNDS: (f64, f64) = (-2.5, 1.0);
const Y_BOUNDS: (f64, f64) = (-1.0, 1.0);
fn mandelbrot_render_system( fn mandelbrot_render_system(
materials: Res<Assets<ColorMaterial>>, materials: Res<Assets<ColorMaterial>>,
mut textures: ResMut<Assets<Texture>>, mut textures: ResMut<Assets<Texture>>,
@ -75,21 +72,31 @@ fn mandelbrot_render_system(
((-1.0 * z) - v, (1.0 * z) - v), ((-1.0 * z) - v, (1.0 * z) - v),
); );
let diff = Instant::now() - start; let diff = Instant::now() - start;
println!(
dbg!(z); "Frametime: {:?} Framerate: {:.2}",
dbg!(diff); diff,
1.0 / diff.as_secs_f32()
);
} }
} }
} }
} }
} }
fn png_startup( fn startup(
mut commands: Commands, mut commands: Commands,
asset_server: Res<AssetServer>, mut textures: ResMut<Assets<Texture>>,
mut materials: ResMut<Assets<ColorMaterial>>, mut materials: ResMut<Assets<ColorMaterial>>,
) { ) {
let texture_handle = asset_server.load("test.png"); let img_size = Vec2::new(Mandelbrot::width() as f32, Mandelbrot::height() as f32);
let img_buf = Mandelbrot::new().generate_image();
let texture_handle = textures.add(Texture::new(
img_size,
img_buf,
TextureFormat::Rgba8UnormSrgb,
));
commands commands
.spawn(Camera2dComponents::default()) .spawn(Camera2dComponents::default())
.spawn(SpriteComponents { .spawn(SpriteComponents {
@ -98,10 +105,3 @@ fn png_startup(
}) })
.with(Mandelbrot::new()); .with(Mandelbrot::new());
} }
fn fractal_startup(mut commands: Commands) {
commands
.spawn(Camera2dComponents::default())
.spawn(SpriteComponents::default())
.with(Mandelbrot::new());
}

View File

@ -3,8 +3,6 @@ use num_complex::Complex;
use rayon::prelude::*; use rayon::prelude::*;
const MAX_ITERATIONS: u16 = 256; const MAX_ITERATIONS: u16 = 256;
const IMG_WIDTH: usize = 1280;
const IMG_HEIGHT: usize = 720;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Mandelbrot { pub struct Mandelbrot {
@ -18,18 +16,29 @@ enum Colour {
} }
impl Mandelbrot { impl Mandelbrot {
const IMG_WIDTH: usize = 1280;
const IMG_HEIGHT: usize = 720;
pub fn new() -> Self { pub fn new() -> Self {
Mandelbrot { Mandelbrot {
iterations: vec![0; IMG_WIDTH * IMG_HEIGHT], iterations: vec![0; Self::IMG_WIDTH * Self::IMG_HEIGHT],
} }
} }
pub fn width() -> usize {
Self::IMG_WIDTH
}
pub fn height() -> usize {
Self::IMG_HEIGHT
}
pub fn generate_image(&mut self) -> Vec<u8> { pub fn generate_image(&mut self) -> Vec<u8> {
// Create the image // Create the image
// Pixel Format can be Rgba8UnormSrgb // Pixel Format can be Rgba8UnormSrgb
self.escape_time(); self.escape_time();
let mut texture_buffer = vec![0; (IMG_WIDTH * IMG_HEIGHT) * 4]; let mut texture_buffer = vec![0; (Self::IMG_WIDTH * Self::IMG_HEIGHT) * 4];
for i in 0..texture_buffer.len() { for i in 0..texture_buffer.len() {
if i % 4 == 0 { if i % 4 == 0 {
@ -61,13 +70,13 @@ impl Mandelbrot {
} }
pub fn generate_scaled_image(&mut self, x_bounds: (f64, f64), y_bounds: (f64, f64)) -> Vec<u8> { pub fn generate_scaled_image(&mut self, x_bounds: (f64, f64), y_bounds: (f64, f64)) -> Vec<u8> {
let mut texture_buffer = vec![0; (IMG_WIDTH * IMG_HEIGHT) * 4]; let mut texture_buffer = vec![0; (Self::IMG_WIDTH * Self::IMG_HEIGHT) * 4];
self.iterations self.iterations
.par_iter_mut() .par_iter_mut()
.enumerate() .enumerate()
.for_each(|(i, value)| { .for_each(|(i, value)| {
let px = i % IMG_WIDTH; let px = i % Self::IMG_WIDTH;
let py = i / IMG_WIDTH; let py = i / Self::IMG_WIDTH;
let c = Self::coords_to_complex(px, py, x_bounds, y_bounds); let c = Self::coords_to_complex(px, py, x_bounds, y_bounds);
@ -108,8 +117,8 @@ impl Mandelbrot {
.par_iter_mut() .par_iter_mut()
.enumerate() .enumerate()
.for_each(|(i, value)| { .for_each(|(i, value)| {
let px = i % IMG_WIDTH; let px = i % Self::IMG_WIDTH;
let py = i / IMG_WIDTH; let py = i / Self::IMG_WIDTH;
let c = Self::coords_to_complex(px, py, (-2.5, 1.0), (-1.0, 1.0)); let c = Self::coords_to_complex(px, py, (-2.5, 1.0), (-1.0, 1.0));
@ -118,18 +127,15 @@ impl Mandelbrot {
} }
pub fn escape_time_image() { pub fn escape_time_image() {
const IMG_WIDTH: usize = 1280; let mut img: RgbImage = ImageBuffer::new(Self::IMG_WIDTH as u32, Self::IMG_HEIGHT as u32);
const IMG_HEIGHT: usize = 720; let mut mandelbrot: Vec<u16> = vec![0; Self::IMG_HEIGHT * Self::IMG_WIDTH];
let mut img: RgbImage = ImageBuffer::new(IMG_WIDTH as u32, IMG_HEIGHT as u32);
let mut mandelbrot: Vec<u16> = vec![0; IMG_HEIGHT * IMG_WIDTH];
mandelbrot mandelbrot
.par_iter_mut() .par_iter_mut()
.enumerate() .enumerate()
.for_each(|(i, value)| { .for_each(|(i, value)| {
let px = i % IMG_WIDTH; let px = i % Self::IMG_WIDTH;
let py = i / IMG_WIDTH; let py = i / Self::IMG_WIDTH;
let c = Self::coords_to_complex(px, py, (-2.5, 1.0), (-1.0, 1.0)); let c = Self::coords_to_complex(px, py, (-2.5, 1.0), (-1.0, 1.0));
@ -137,7 +143,7 @@ impl Mandelbrot {
}); });
for (px, py, pixel) in img.enumerate_pixels_mut() { for (px, py, pixel) in img.enumerate_pixels_mut() {
let i = px as usize + IMG_WIDTH * py as usize; let i = px as usize + Self::IMG_WIDTH * py as usize;
let num_iterations = mandelbrot[i]; let num_iterations = mandelbrot[i];
match Self::find_colour(num_iterations) { match Self::find_colour(num_iterations) {
@ -193,13 +199,13 @@ impl Mandelbrot {
// const X_MIN: f64 = -2.5; // const X_MIN: f64 = -2.5;
// const X_MAX: f64 = 1.0; // const X_MAX: f64 = 1.0;
x_bounds.0 + ((x_bounds.1 - x_bounds.0) * (px as f64 - 0.0)) / IMG_WIDTH as f64 - 0.0 x_bounds.0 + ((x_bounds.1 - x_bounds.0) * (px as f64 - 0.0)) / Self::IMG_WIDTH as f64 - 0.0
} }
fn scale_height(py: usize, y_bounds: (f64, f64)) -> f64 { fn scale_height(py: usize, y_bounds: (f64, f64)) -> f64 {
// const Y_MIN: f64 = -1.0; // const Y_MIN: f64 = -1.0;
// const Y_MAX: f64 = 1.0; // const Y_MAX: f64 = 1.0;
y_bounds.0 + ((y_bounds.1 - y_bounds.0) * (py as f64 - 0.0)) / IMG_HEIGHT as f64 - 0.0 y_bounds.0 + ((y_bounds.1 - y_bounds.0) * (py as f64 - 0.0)) / Self::IMG_HEIGHT as f64 - 0.0
} }
} }