diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/benoit/benoit.rs | 8 | ||||
-rw-r--r-- | source/benoit/benoit/application.rs | 2 | ||||
-rw-r--r-- | source/benoit/benoit/application/animate.rs | 10 | ||||
-rw-r--r-- | source/benoit/benoit/application/colour.rs | 29 | ||||
-rw-r--r-- | source/benoit/benoit/application/draw.rs | 5 | ||||
-rw-r--r-- | source/benoit/benoit/application/get_iterator_function.rs | 2 | ||||
-rw-r--r-- | source/benoit/benoit/application/handle_keys.rs | 17 | ||||
-rw-r--r-- | source/benoit/benoit/application/loop.rs | 33 | ||||
-rw-r--r-- | source/benoit/benoit/application/render.rs | 6 | ||||
-rw-r--r-- | source/benoit/benoit/application/render_row.rs | 30 | ||||
-rw-r--r-- | source/benoit/benoit/application/run.rs | 9 | ||||
-rw-r--r-- | source/benoit/benoit/configuration.rs | 2 | ||||
-rw-r--r-- | source/benoit/benoit/configuration/default.rs | 5 | ||||
-rw-r--r-- | source/benoit/benoit/configuration/load.rs | 3 | ||||
-rw-r--r-- | source/benoit/benoit/fractal.rs | 31 | ||||
-rw-r--r-- | source/benoit/benoit/fractal/get_name.rs | 34 | ||||
-rw-r--r-- | source/benoit/benoit/render_data.rs | 5 | ||||
-rw-r--r-- | source/benoit/benoit/render_data/new.rs | 8 | ||||
-rw-r--r-- | source/benoit/benoit/render_data/slice.rs | 7 |
19 files changed, 168 insertions, 78 deletions
diff --git a/source/benoit/benoit.rs b/source/benoit/benoit.rs index dfb4856..b301f36 100644 --- a/source/benoit/benoit.rs +++ b/source/benoit/benoit.rs @@ -23,15 +23,9 @@ pub mod application; pub mod configuration; +pub mod fractal; pub mod iteration; pub mod render_data; pub mod video; pub const PRECISION: u32 = 0x80; - -#[derive(Clone, Copy)] -pub enum Fractal { - BurningShip, - Mandelbrot, - Tricorn, -} diff --git a/source/benoit/benoit/application.rs b/source/benoit/benoit/application.rs index 07f3815..be3d0fb 100644 --- a/source/benoit/benoit/application.rs +++ b/source/benoit/benoit/application.rs @@ -21,7 +21,7 @@ If not, see <https://www.gnu.org/licenses/>. */ -use crate::benoit::Fractal; +use crate::benoit::fractal::Fractal; use crate::benoit::iteration::IteratorFunction; use crate::benoit::video::Video; diff --git a/source/benoit/benoit/application/animate.rs b/source/benoit/benoit/application/animate.rs index 65b4aeb..48677f3 100644 --- a/source/benoit/benoit/application/animate.rs +++ b/source/benoit/benoit/application/animate.rs @@ -34,7 +34,7 @@ use std::ops::MulAssign; impl Application { pub fn animate(&self) -> i32 { // zoom_start: - let mut zoom = Float::with_val(PRECISION, 1.0 / 2.0); + let mut zoom = Float::with_val(PRECISION, 1.0 / 4.0); let zoom_stop = Float::with_val(PRECISION, &self.zoom); @@ -70,13 +70,15 @@ impl Application { let canvas_size = self.canvas_height as usize * self.canvas_width as usize; - let mut data: Vec::<u32> = vec![0x0; canvas_size]; + let mut iteration_count_buffer: Vec::<u32> = vec![0x0; canvas_size]; + let mut square_distance_buffer: Vec::<f32> = vec![0.0; canvas_size]; + let mut image: Vec::<u8> = vec![0x0; canvas_size * 0x3]; for frame in 0x0..self.frame_count { eprint!("{frame:010}: "); - self.render(&mut data[..], &self.center_real, &self.center_imaginary, &zoom, self.maximum_iteration_count); - self.colour(&mut image[..], &data[..]); + self.render(&mut iteration_count_buffer[..], &mut square_distance_buffer[..], &self.center_real, &self.center_imaginary, &zoom, self.maximum_iteration_count); + self.colour(&mut image[..], &mut iteration_count_buffer[..], &mut square_distance_buffer[..]); self.dump(format!("{}/frame{frame:010}.webp", self.dump_path), &image, self.canvas_width, self.canvas_height); diff --git a/source/benoit/benoit/application/colour.rs b/source/benoit/benoit/application/colour.rs index c9cf507..701d49f 100644 --- a/source/benoit/benoit/application/colour.rs +++ b/source/benoit/benoit/application/colour.rs @@ -24,30 +24,33 @@ use crate::benoit::application::Application; impl Application { - pub fn colour(&self, buffer: &mut [u8], data: &[u32]) { + pub fn colour(&self, buffer: &mut [u8], iteration_count_buffer: &[u32], square_distance_buffer: &[f32]) { let canvas_size = self.canvas_height * self.canvas_width; + for pixel in 0x0..canvas_size { - let iteration_count = data[pixel as usize]; + let iteration_count = iteration_count_buffer[pixel as usize]; + + let (red, green, blue) = if iteration_count != self.maximum_iteration_count { + let distance = square_distance_buffer[pixel as usize].sqrt(); - let factor = { - let factor = iteration_count as f32 / 64.0 % 1.0; + let mut factor = (iteration_count as f32 + 1.0 - distance.log2().log2()) / 16.0 % 1.0; - (if factor >= 1.0 / 2.0 { + factor %= 1.0; + + factor = (if factor >= 1.0 / 2.0 { 1.0 - factor } else { factor - }) * 2.0 - }; + }) * 2.0; - let value: u8 = if iteration_count != self.maximum_iteration_count { - (factor * 255.0).round() as u8 + (factor * factor, factor * factor, factor) } else { - 0x0 + (0.0, 0.0, 0.0) }; - let red = value; - let green = value; - let blue = value; + let red = (red * 255.0).round() as u8; + let green = (green * 255.0).round() as u8; + let blue = (blue * 255.0).round() as u8; buffer[pixel as usize * 0x3] = red; buffer[pixel as usize * 0x3 + 0x1] = green; diff --git a/source/benoit/benoit/application/draw.rs b/source/benoit/benoit/application/draw.rs index 715b3da..6b1300b 100644 --- a/source/benoit/benoit/application/draw.rs +++ b/source/benoit/benoit/application/draw.rs @@ -29,12 +29,9 @@ use sdl2::pixels::Color; use sdl2::rect::Rect; impl Application { - pub fn draw(&mut self, data: &mut [u32], image: &mut [u8]) { + pub fn draw(&mut self, image: &[u8]) { let canvas_size = self.canvas_height * self.canvas_width; - self.render(&mut data[..], &self.center_real, &self.center_imaginary, &self.zoom, self.maximum_iteration_count); - self.colour(&mut image[..], &data[..]); - for pixel in 0x0..canvas_size { let y = pixel as u32 / self.canvas_width; let x = pixel as u32 - y * self.canvas_width; diff --git a/source/benoit/benoit/application/get_iterator_function.rs b/source/benoit/benoit/application/get_iterator_function.rs index b2375a0..1ca2cb7 100644 --- a/source/benoit/benoit/application/get_iterator_function.rs +++ b/source/benoit/benoit/application/get_iterator_function.rs @@ -21,7 +21,7 @@ If not, see <https://www.gnu.org/licenses/>. */ -use crate::benoit::Fractal; +use crate::benoit::fractal::Fractal; use crate::benoit::application::Application; use crate::benoit::iteration::*; diff --git a/source/benoit/benoit/application/handle_keys.rs b/source/benoit/benoit/application/handle_keys.rs index 67e32cd..659a584 100644 --- a/source/benoit/benoit/application/handle_keys.rs +++ b/source/benoit/benoit/application/handle_keys.rs @@ -23,6 +23,8 @@ use crate::benoit::PRECISION; use crate::benoit::application::Application; +use crate::benoit::fractal::Fractal; +use crate::benoit::iteration::IteratorFunction; extern crate rug; extern crate sdl2; @@ -30,11 +32,26 @@ extern crate sdl2; use rug::Float; use sdl2::keyboard::Scancode; +fn cycle_fractal(fractal: Fractal) -> (Fractal, IteratorFunction) { + let fractal = match fractal { + Fractal::BurningShip => Fractal::Mandelbrot, + Fractal::Mandelbrot => Fractal::Tricorn, + Fractal::Tricorn => Fractal::BurningShip, + }; + + let iterator_function = Application::get_iterator_function(fractal); + + eprintln!("rendering the {}", fractal.get_name()); + + return (fractal, iterator_function); +} + impl Application { pub fn handle_keys(&mut self, scan_code: Scancode) -> bool { match scan_code { Scancode::Escape => return true, Scancode::C => self.do_draw = true, + Scancode::Tab => (self.fractal, self.iterator_function) = cycle_fractal(self.fractal), Scancode::X => self.do_dump = true, Scancode::Z => eprintln!("c = {}{:+}i -- {}x @ {} iter.", &self.center_real, &self.center_imaginary, &self.zoom, self.maximum_iteration_count), _ => {}, diff --git a/source/benoit/benoit/application/loop.rs b/source/benoit/benoit/application/loop.rs index 8261970..f6747e7 100644 --- a/source/benoit/benoit/application/loop.rs +++ b/source/benoit/benoit/application/loop.rs @@ -29,34 +29,41 @@ impl Application { pub fn r#loop(&mut self) -> i32 { eprintln!(); eprintln!("Controls:"); - eprintln!("- W Translate up"); - eprintln!("- A Translate left"); - eprintln!("- S Translate down"); - eprintln!("- D Translate right"); + eprintln!("- W Translate up"); + eprintln!("- A Translate left"); + eprintln!("- S Translate down"); + eprintln!("- D Translate right"); eprintln!(); - eprintln!("- Q Zoom out"); - eprintln!("- E Zoom in"); + eprintln!("- Q Zoom out"); + eprintln!("- E Zoom in"); eprintln!(); - eprintln!("- R Decrease max. iteration count"); - eprintln!("- F Increase max. iteration count"); + eprintln!("- R Decrease max. iteration count"); + eprintln!("- F Increase max. iteration count"); eprintln!(); - eprintln!("- Z Print centre value (c)"); - eprintln!("- X Dump frame"); - eprintln!("- C Render frame"); + eprintln!("- Tab Cycle between fractals"); + eprintln!(); + eprintln!("- Z Print centre value (c)"); + eprintln!("- X Dump frame"); + eprintln!("- C Render frame"); eprintln!(); let mut event_pump = self.video.as_mut().unwrap().sdl.event_pump().expect("unable to get event pump"); let canvas_size = self.canvas_height as usize * self.canvas_width as usize; - let mut data: Vec::<u32> = vec![0x0; canvas_size]; + let mut iteration_count_buffer: Vec::<u32> = vec![0x0; canvas_size]; + let mut square_distance_buffer: Vec::<f32> = vec![0.0; canvas_size]; + let mut image: Vec::<u8> = vec![0x0; canvas_size * 0x3]; loop { if self.poll_events(&mut event_pump) { break } if self.do_draw { - self.draw(data.as_mut_slice(), image.as_mut_slice()); + self.render(&mut iteration_count_buffer[..], &mut square_distance_buffer[..], &self.center_real, &self.center_imaginary, &self.zoom, self.maximum_iteration_count); + self.colour(&mut image[..], &iteration_count_buffer[..], &square_distance_buffer[..]); + + self.draw(&image[..]); self.do_draw = false; } diff --git a/source/benoit/benoit/application/render.rs b/source/benoit/benoit/application/render.rs index e06b168..17ccc88 100644 --- a/source/benoit/benoit/application/render.rs +++ b/source/benoit/benoit/application/render.rs @@ -33,16 +33,16 @@ use std::sync::Arc; use std::time::Instant; impl Application { - pub fn render(&self, buffer: &mut [u32], center_real: &Float, center_imaginary: &Float, zoom: &Float, maximum_iteration_count: u32) { + pub fn render(&self, iteration_count_buffer: &mut [u32], square_distance_buffer: &mut [f32], center_real: &Float, center_imaginary: &Float, zoom: &Float, maximum_iteration_count: u32) { eprint!("rendering..."); let time_start = Instant::now(); let iterator = self.iterator_function; - let data = Arc::new(RenderData::new(buffer, self.canvas_width, self.canvas_height, center_real.clone(), center_imaginary.clone(), zoom.clone(), maximum_iteration_count)); + let data = Arc::new(RenderData::new(iteration_count_buffer, square_distance_buffer, self.canvas_width, self.canvas_height, center_real.clone(), center_imaginary.clone(), zoom.clone(), maximum_iteration_count)); - (0x0..self.canvas_height).into_par_iter().for_each_with(data, |data, row| { + (0x0..self.canvas_height).into_par_iter().for_each(|row| { Application::render_row(data.clone(), row, iterator); }); diff --git a/source/benoit/benoit/application/render_row.rs b/source/benoit/benoit/application/render_row.rs index 20fabdb..23946ec 100644 --- a/source/benoit/benoit/application/render_row.rs +++ b/source/benoit/benoit/application/render_row.rs @@ -32,12 +32,12 @@ use rug::Float; use std::sync::Arc; impl Application { - pub fn render_row(task: Arc<RenderData>, y: u32, iterator: IteratorFunction) { - let buffer = unsafe { task.slice(y) }; + pub fn render_row(data: Arc<RenderData>, y: u32, iterator: IteratorFunction) { + let (iteration_count_buffer, square_distance_buffer) = unsafe { data.slice(y) }; - for x in 0x0..task.canvas_width { - let canvas_width = Float::with_val(PRECISION, task.canvas_width); - let canvas_height = Float::with_val(PRECISION, task.canvas_height); + for x in 0x0..data.canvas_width { + let canvas_width = Float::with_val(PRECISION, data.canvas_width); + let canvas_height = Float::with_val(PRECISION, data.canvas_height); let x_float = Float::with_val(PRECISION, x); let y_float = Float::with_val(PRECISION, y); @@ -48,8 +48,8 @@ impl Application { let mut ca = Float::with_val(PRECISION, &x_float - &tmp0); ca *= 4.0; ca /= &canvas_width; - ca /= &task.zoom; - ca += &task.real; + ca /= &data.zoom; + ca += &data.real; ca }; @@ -60,8 +60,8 @@ impl Application { let mut cb = Float::with_val(PRECISION, &y_float - &tmp0); cb *= 4.0; cb /= &canvas_height; - cb /= &task.zoom; - cb += &task.imaginary; + cb /= &data.zoom; + cb += &data.imaginary; cb }; @@ -70,16 +70,22 @@ impl Application { let mut zb = Float::with_val(PRECISION, &cb); let mut iteration_count: u32 = 0x0; + let mut square_distance; while { - let square_distance = Float::with_val(PRECISION, &za * &za + &zb * &zb); - square_distance <= 4.0 && iteration_count < task.maximum_iteration_count + square_distance = Float::with_val(PRECISION, &za * &za + &zb * &zb).to_f32(); + // Having a larger escape radius gives better + // results with regard to smoothing. + square_distance <= 256.0 && iteration_count < data.maximum_iteration_count } { iterator(&mut za, &mut zb, &ca, &cb); iteration_count += 0x1; } - unsafe { *buffer.get_unchecked_mut(x as usize) = iteration_count } + unsafe { + *iteration_count_buffer.get_unchecked_mut(x as usize) = iteration_count; + *square_distance_buffer.get_unchecked_mut(x as usize) = square_distance; + } } } } diff --git a/source/benoit/benoit/application/run.rs b/source/benoit/benoit/application/run.rs index 7b91c22..e8ee4e3 100644 --- a/source/benoit/benoit/application/run.rs +++ b/source/benoit/benoit/application/run.rs @@ -21,20 +21,13 @@ If not, see <https://www.gnu.org/licenses/>. */ -use crate::benoit::Fractal; use crate::benoit::application::Application; extern crate sdl2; impl Application { pub fn run(&mut self) -> i32 { - let fractal_name = match self.fractal { - Fractal::BurningShip => "burning ship", - Fractal::Mandelbrot => "mandelbrot set", - Fractal::Tricorn => "tricorn", - }; - - eprintln!("rendering the {fractal_name}"); + eprintln!("rendering the {}", self.fractal.get_name()); return match self.interactive { true => self.r#loop(), diff --git a/source/benoit/benoit/configuration.rs b/source/benoit/benoit/configuration.rs index b330089..455107f 100644 --- a/source/benoit/benoit/configuration.rs +++ b/source/benoit/benoit/configuration.rs @@ -21,7 +21,7 @@ If not, see <https://www.gnu.org/licenses/>. */ -use crate::benoit::Fractal; +use crate::benoit::fractal::Fractal; extern crate rug; diff --git a/source/benoit/benoit/configuration/default.rs b/source/benoit/benoit/configuration/default.rs index 19fc5fb..5442a99 100644 --- a/source/benoit/benoit/configuration/default.rs +++ b/source/benoit/benoit/configuration/default.rs @@ -21,8 +21,9 @@ If not, see <https://www.gnu.org/licenses/>. */ -use crate::benoit::{Fractal, PRECISION}; +use crate::benoit::PRECISION; use crate::benoit::configuration::Configuration; +use crate::benoit::fractal::Fractal; extern crate rug; @@ -42,7 +43,7 @@ impl Configuration { center_real: Float::with_val(PRECISION, 0.0), center_imaginary: Float::with_val(PRECISION, 0.0), - zoom: Float::with_val(PRECISION, 1.0), + zoom: Float::with_val(PRECISION, 1.0 / 4.0), maximum_iteration_count: 0x100, dump_path: "./render/".to_string(), diff --git a/source/benoit/benoit/configuration/load.rs b/source/benoit/benoit/configuration/load.rs index 6d39c13..4f5f557 100644 --- a/source/benoit/benoit/configuration/load.rs +++ b/source/benoit/benoit/configuration/load.rs @@ -21,8 +21,9 @@ If not, see <https://www.gnu.org/licenses/>. */ -use crate::benoit::{Fractal, PRECISION}; +use crate::benoit::PRECISION; use crate::benoit::configuration::Configuration; +use crate::benoit::fractal::Fractal; extern crate rug; extern crate toml; diff --git a/source/benoit/benoit/fractal.rs b/source/benoit/benoit/fractal.rs new file mode 100644 index 0000000..1c7c08d --- /dev/null +++ b/source/benoit/benoit/fractal.rs @@ -0,0 +1,31 @@ +/* + Copyright 2021, 2023 Gabriel Bjørnager Jensen. + + This file is part of Benoit. + + Benoit is free software: you can redistribute it + and/or modify it under the terms of the GNU + Affero General Public License as published by + the Free Software Foundation, either version 3 + of the License, or (at your option) any later + version. + + Benoit is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without + even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU + Affero General Public License along with Benoit. + If not, see <https://www.gnu.org/licenses/>. +*/ + +pub mod get_name; + +#[derive(Clone, Copy)] +pub enum Fractal { + BurningShip, + Mandelbrot, + Tricorn, +} diff --git a/source/benoit/benoit/fractal/get_name.rs b/source/benoit/benoit/fractal/get_name.rs new file mode 100644 index 0000000..cdbadb1 --- /dev/null +++ b/source/benoit/benoit/fractal/get_name.rs @@ -0,0 +1,34 @@ +/* + Copyright 2021, 2023 Gabriel Bjørnager Jensen. + + This file is part of Benoit. + + Benoit is free software: you can redistribute it + and/or modify it under the terms of the GNU + Affero General Public License as published by + the Free Software Foundation, either version 3 + of the License, or (at your option) any later + version. + + Benoit is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without + even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU + Affero General Public License along with Benoit. + If not, see <https://www.gnu.org/licenses/>. +*/ + +use crate::benoit::fractal::Fractal; + +impl Fractal { + pub fn get_name(self) -> &'static str { + return match self { + Fractal::BurningShip => "burning ship", + Fractal::Mandelbrot => "mandelbrot set", + Fractal::Tricorn => "tricorn", + }; + } +} diff --git a/source/benoit/benoit/render_data.rs b/source/benoit/benoit/render_data.rs index 602521e..a849cfd 100644 --- a/source/benoit/benoit/render_data.rs +++ b/source/benoit/benoit/render_data.rs @@ -26,8 +26,8 @@ extern crate rug; use rug::Float; pub mod new; -pub mod slice; pub mod send; +pub mod slice; pub mod sync; pub struct RenderData { @@ -40,5 +40,6 @@ pub struct RenderData { pub maximum_iteration_count: u32, - buffer: *mut u32, + iteration_count_buffer: *mut u32, + square_distance_buffer: *mut f32, } diff --git a/source/benoit/benoit/render_data/new.rs b/source/benoit/benoit/render_data/new.rs index fb45390..6e801a0 100644 --- a/source/benoit/benoit/render_data/new.rs +++ b/source/benoit/benoit/render_data/new.rs @@ -28,8 +28,9 @@ extern crate rug; use rug::Float; impl RenderData { - pub fn new(buffer: &mut [u32], canvas_width: u32, canvas_height: u32, real: Float, imaginary: Float, zoom: Float, maximum_iteration_count: u32) -> RenderData { - let buffer_pointer = buffer.as_mut_ptr(); + pub fn new(iteration_count_buffer: &mut [u32], square_distance_buffer: &mut [f32], canvas_width: u32, canvas_height: u32, real: Float, imaginary: Float, zoom: Float, maximum_iteration_count: u32) -> RenderData { + let iteration_count_buffer_pointer = iteration_count_buffer.as_mut_ptr(); + let square_distance_buffer_pointer = square_distance_buffer.as_mut_ptr(); return RenderData { canvas_width: canvas_width, @@ -41,7 +42,8 @@ impl RenderData { maximum_iteration_count: maximum_iteration_count, - buffer: buffer_pointer, + iteration_count_buffer: iteration_count_buffer_pointer, + square_distance_buffer: square_distance_buffer_pointer, }; } } diff --git a/source/benoit/benoit/render_data/slice.rs b/source/benoit/benoit/render_data/slice.rs index 6783aae..4f6b486 100644 --- a/source/benoit/benoit/render_data/slice.rs +++ b/source/benoit/benoit/render_data/slice.rs @@ -26,10 +26,11 @@ use crate::benoit::render_data::RenderData; use std::slice::from_raw_parts_mut; impl RenderData { - pub unsafe fn slice(&self, row: u32) -> &mut [u32] { + pub unsafe fn slice(&self, row: u32) -> (&mut [u32], &mut [f32]) { let offset = row as isize * self.canvas_width as isize; - let slice = from_raw_parts_mut(self.buffer.offset(offset), self.canvas_width as usize); + let iteration_count = from_raw_parts_mut(self.iteration_count_buffer.offset(offset), self.canvas_width as usize); + let distance = from_raw_parts_mut(self.square_distance_buffer.offset(offset), self.canvas_width as usize); - return slice; + return (iteration_count, distance); } } |