feat: pure software generation of mandelbrot
This commit is contained in:
parent
e8e31ad5b1
commit
8a2a5bd108
38
src/main.rs
38
src/main.rs
|
@ -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());
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue