diff options
-rw-r--r-- | CHANGELOG.md | 6 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | source/benoit/benoit/application.rs | 22 | ||||
-rw-r--r-- | source/benoit/benoit/application/animate.rs | 4 | ||||
-rw-r--r-- | source/benoit/benoit/application/draw.rs | 11 | ||||
-rw-r--r-- | source/benoit/benoit/application/get_row_renderer.rs | 34 | ||||
-rw-r--r-- | source/benoit/benoit/application/handle_keys.rs | 38 | ||||
-rw-r--r-- | source/benoit/benoit/application/initialise.rs | 8 | ||||
-rw-r--r-- | source/benoit/benoit/application/loop.rs | 25 | ||||
-rw-r--r-- | source/benoit/benoit/application/render.rs | 9 | ||||
-rw-r--r-- | source/benoit/benoit/application/render_row_julia.rs | 92 | ||||
-rw-r--r-- | source/benoit/benoit/application/render_row_normal.rs (renamed from source/benoit/benoit/application/render_row.rs) | 2 | ||||
-rw-r--r-- | source/benoit/benoit/configuration.rs | 5 | ||||
-rw-r--r-- | source/benoit/benoit/configuration/default.rs | 7 | ||||
-rw-r--r-- | source/benoit/benoit/configuration/load.rs | 6 |
15 files changed, 226 insertions, 45 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e503d8..f7cd193 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 27 + +* Bring back Julia sets (using row renderers) +* Update controls (decrease sensitivity of zooms) +* Scale by default + # 26 * Update colouring for small iteration counts @@ -1,6 +1,6 @@ [package] name = "benoit" -version = "0.30.0" +version = "0.31.0" authors = ["Gabriel Bjørnager Jensen"] edition = "2021" description = "Mandelbrot renderer." diff --git a/source/benoit/benoit/application.rs b/source/benoit/benoit/application.rs index be3d0fb..1830721 100644 --- a/source/benoit/benoit/application.rs +++ b/source/benoit/benoit/application.rs @@ -23,37 +23,50 @@ use crate::benoit::fractal::Fractal; use crate::benoit::iteration::IteratorFunction; +use crate::benoit::render_data::RenderData; use crate::benoit::video::Video; extern crate rug; use rug::Float; +use std::sync::Arc; pub mod animate; pub mod colour; pub mod draw; pub mod dump; pub mod get_iterator_function; +pub mod get_row_renderer; pub mod handle_keys; pub mod initialise; pub mod r#loop; pub mod poll_events; -pub mod render_row; +pub mod render_row_julia; +pub mod render_row_normal; pub mod render; pub mod run; +pub type RowRenderer = fn(Arc<RenderData>, u32, IteratorFunction); + +pub struct PreviousPosition { + real: Float, + imaginary: Float, + zoom: Float, +} + pub struct Application { thread_count: u32, fractal: Fractal, + julia: bool, canvas_width: u32, canvas_height: u32, scale: u32, frame_count: u32, - center_real: Float, - center_imaginary: Float, + centre_real: Float, + centre_imaginary: Float, zoom: Float, maximum_iteration_count: u32, @@ -62,8 +75,9 @@ pub struct Application { video: Option<Video>, interactive: bool, - do_draw: bool, + do_render: bool, do_dump: bool, + row_renderer: RowRenderer, iterator_function: IteratorFunction, } diff --git a/source/benoit/benoit/application/animate.rs b/source/benoit/benoit/application/animate.rs index 48677f3..3c9aaab 100644 --- a/source/benoit/benoit/application/animate.rs +++ b/source/benoit/benoit/application/animate.rs @@ -66,7 +66,7 @@ impl Application { factor }; - eprintln!("animating {} frames at {}{:+}i to {:.3} (fac.: {:.3})", self.frame_count, self.center_real.to_f64(), self.center_imaginary.to_f64(), zoom_stop.to_f64(), zoom_factor.to_f64()); + eprintln!("animating {} frames at {}{:+}i to {:.3} (fac.: {:.3})", self.frame_count, self.centre_real.to_f64(), self.centre_imaginary.to_f64(), zoom_stop.to_f64(), zoom_factor.to_f64()); let canvas_size = self.canvas_height as usize * self.canvas_width as usize; @@ -77,7 +77,7 @@ impl Application { for frame in 0x0..self.frame_count { eprint!("{frame:010}: "); - self.render(&mut iteration_count_buffer[..], &mut square_distance_buffer[..], &self.center_real, &self.center_imaginary, &zoom, self.maximum_iteration_count); + self.render(&mut iteration_count_buffer[..], &mut square_distance_buffer[..], &self.centre_real, &self.centre_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/draw.rs b/source/benoit/benoit/application/draw.rs index 6b1300b..ae936ba 100644 --- a/source/benoit/benoit/application/draw.rs +++ b/source/benoit/benoit/application/draw.rs @@ -21,15 +21,18 @@ If not, see <https://www.gnu.org/licenses/>. */ -use crate::benoit::application::Application; +use crate::benoit::PRECISION; +use crate::benoit::application::{Application, PreviousPosition}; +extern crate rug; extern crate sdl2; +use rug::Float; use sdl2::pixels::Color; use sdl2::rect::Rect; impl Application { - pub fn draw(&mut self, image: &[u8]) { + pub fn draw(&mut self, image: &[u8], previous_position: &PreviousPosition) { let canvas_size = self.canvas_height * self.canvas_width; for pixel in 0x0..canvas_size { @@ -44,14 +47,14 @@ impl Application { Color::RGB(red, green, blue) }; - self.video.as_mut().unwrap().canvas.set_draw_color(colour); - let rectangle = Rect::new( (x * self.scale) as i32, (y * self.scale) as i32, self.scale, self.scale ); + + self.video.as_mut().unwrap().canvas.set_draw_color(colour); self.video.as_mut().unwrap().canvas.fill_rects(&[rectangle]).unwrap(); } diff --git a/source/benoit/benoit/application/get_row_renderer.rs b/source/benoit/benoit/application/get_row_renderer.rs new file mode 100644 index 0000000..d8c349a --- /dev/null +++ b/source/benoit/benoit/application/get_row_renderer.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::application::Application; +use crate::benoit::application::RowRenderer; + +impl Application { + pub fn get_row_renderer(julia: bool) -> RowRenderer { + return match julia { + false => Application::render_row_normal, + true => Application::render_row_julia, + }; + } +} diff --git a/source/benoit/benoit/application/handle_keys.rs b/source/benoit/benoit/application/handle_keys.rs index 659a584..4b2c09c 100644 --- a/source/benoit/benoit/application/handle_keys.rs +++ b/source/benoit/benoit/application/handle_keys.rs @@ -22,7 +22,7 @@ */ use crate::benoit::PRECISION; -use crate::benoit::application::Application; +use crate::benoit::application::{Application, RowRenderer}; use crate::benoit::fractal::Fractal; use crate::benoit::iteration::IteratorFunction; @@ -46,40 +46,54 @@ fn cycle_fractal(fractal: Fractal) -> (Fractal, IteratorFunction) { return (fractal, iterator_function); } +fn toggle_julia(julia: bool) -> (bool, RowRenderer) { + let julia = !julia; + + let row_renderer = Application::get_row_renderer(julia); + + match julia { + false => eprintln!("enabled the julia set"), + true => eprintln!("disabled the julia set"), + }; + + return (julia, row_renderer); +} + impl Application { pub fn handle_keys(&mut self, scan_code: Scancode) -> bool { match scan_code { + Scancode::LAlt => (self.fractal, self.iterator_function) = cycle_fractal(self.fractal), Scancode::Escape => return true, - Scancode::C => self.do_draw = true, - Scancode::Tab => (self.fractal, self.iterator_function) = cycle_fractal(self.fractal), + Scancode::C => self.do_render = true, + Scancode::Tab => (self.julia, self.row_renderer) = toggle_julia(self.julia), 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), + Scancode::Z => eprintln!("c = {}{:+}i -- {}x @ {} iter.", &self.centre_real, &self.centre_imaginary, &self.zoom, self.maximum_iteration_count), _ => {}, } match scan_code { - Scancode::E => self.zoom *= 4.0, - Scancode::Q => self.zoom /= 4.0, + Scancode::E => self.zoom *= 2.0, + Scancode::Q => self.zoom /= 2.0, _ => {}, }; let translate_ammount = { - let mut ammount = Float::with_val(PRECISION, 1.0); - ammount /= 4.0; + let mut ammount = Float::with_val(PRECISION, 4.0); + ammount /= 16.0; ammount /= &self.zoom; ammount }; match scan_code { - Scancode::A => self.center_real -= &translate_ammount, - Scancode::D => self.center_real += &translate_ammount, + Scancode::A => self.centre_real -= &translate_ammount, + Scancode::D => self.centre_real += &translate_ammount, _ => {}, }; match scan_code { - Scancode::S => self.center_imaginary += &translate_ammount, - Scancode::W => self.center_imaginary -= &translate_ammount, + Scancode::S => self.centre_imaginary += &translate_ammount, + Scancode::W => self.centre_imaginary -= &translate_ammount, _ => {}, }; diff --git a/source/benoit/benoit/application/initialise.rs b/source/benoit/benoit/application/initialise.rs index 97ac4a4..e46347c 100644 --- a/source/benoit/benoit/application/initialise.rs +++ b/source/benoit/benoit/application/initialise.rs @@ -65,14 +65,15 @@ impl Application { thread_count: thread_count, fractal: configuration.fractal, + julia: configuration.julia, canvas_width: configuration.canvas_width, canvas_height: configuration.canvas_height, scale: configuration.scale, frame_count: configuration.frame_count, - center_real: Float::with_val(PRECISION, configuration.center_real), - center_imaginary: Float::with_val(PRECISION, configuration.center_imaginary), + centre_real: Float::with_val(PRECISION, configuration.centre_real), + centre_imaginary: Float::with_val(PRECISION, configuration.centre_imaginary), zoom: Float::with_val(PRECISION, configuration.zoom), maximum_iteration_count: configuration.maximum_iteration_count, @@ -81,9 +82,10 @@ impl Application { video: video, interactive: configuration.interactive, - do_draw: true, + do_render: true, do_dump: false, + row_renderer: Application::get_row_renderer( configuration.julia), iterator_function: Application::get_iterator_function(configuration.fractal), }; } diff --git a/source/benoit/benoit/application/loop.rs b/source/benoit/benoit/application/loop.rs index f6747e7..2621556 100644 --- a/source/benoit/benoit/application/loop.rs +++ b/source/benoit/benoit/application/loop.rs @@ -21,7 +21,7 @@ If not, see <https://www.gnu.org/licenses/>. */ -use crate::benoit::application::Application; +use crate::benoit::application::{Application, PreviousPosition}; extern crate sdl2; @@ -40,7 +40,8 @@ impl Application { eprintln!("- R Decrease max. iteration count"); eprintln!("- F Increase max. iteration count"); eprintln!(); - eprintln!("- Tab Cycle between fractals"); + eprintln!("- Tab Toggle Julia"); + eprintln!("- Alt Cycle between fractals"); eprintln!(); eprintln!("- Z Print centre value (c)"); eprintln!("- X Dump frame"); @@ -56,18 +57,30 @@ impl Application { let mut image: Vec::<u8> = vec![0x0; canvas_size * 0x3]; + let mut previous_position = PreviousPosition { + real: self.centre_real.clone(), + imaginary: self.centre_imaginary.clone(), + zoom: self.zoom.clone(), + }; + loop { if self.poll_events(&mut event_pump) { break } - if self.do_draw { - self.render(&mut iteration_count_buffer[..], &mut square_distance_buffer[..], &self.center_real, &self.center_imaginary, &self.zoom, self.maximum_iteration_count); + if self.do_render { + self.render(&mut iteration_count_buffer[..], &mut square_distance_buffer[..], &self.centre_real, &self.centre_imaginary, &self.zoom, self.maximum_iteration_count); self.colour(&mut image[..], &iteration_count_buffer[..], &square_distance_buffer[..]); - self.draw(&image[..]); + previous_position = PreviousPosition { + real: self.centre_real.clone(), + imaginary: self.centre_imaginary.clone(), + zoom: self.zoom.clone(), + }; - self.do_draw = false; + self.do_render = false; } + self.draw(&image[..], &previous_position); + if self.do_dump { let path = format!("{}/image.webp", self.dump_path); diff --git a/source/benoit/benoit/application/render.rs b/source/benoit/benoit/application/render.rs index 17ccc88..3063d6f 100644 --- a/source/benoit/benoit/application/render.rs +++ b/source/benoit/benoit/application/render.rs @@ -33,17 +33,18 @@ use std::sync::Arc; use std::time::Instant; impl Application { - 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) { + pub fn render(&self, iteration_count_buffer: &mut [u32], square_distance_buffer: &mut [f32], centre_real: &Float, centre_imaginary: &Float, zoom: &Float, maximum_iteration_count: u32) { eprint!("rendering..."); let time_start = Instant::now(); - let iterator = self.iterator_function; + let row_renderer = self.row_renderer; + let iterator = self.iterator_function; - 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)); + let data = Arc::new(RenderData::new(iteration_count_buffer, square_distance_buffer, self.canvas_width, self.canvas_height, centre_real.clone(), centre_imaginary.clone(), zoom.clone(), maximum_iteration_count)); (0x0..self.canvas_height).into_par_iter().for_each(|row| { - Application::render_row(data.clone(), row, iterator); + row_renderer(data.clone(), row, iterator); }); let duration = time_start.elapsed(); diff --git a/source/benoit/benoit/application/render_row_julia.rs b/source/benoit/benoit/application/render_row_julia.rs new file mode 100644 index 0000000..ba46afa --- /dev/null +++ b/source/benoit/benoit/application/render_row_julia.rs @@ -0,0 +1,92 @@ +/* + 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::PRECISION; +use crate::benoit::application::Application; +use crate::benoit::iteration::IteratorFunction; +use crate::benoit::render_data::RenderData; + +extern crate rug; + +use rug::Float; +use std::sync::Arc; + +impl Application { + pub fn render_row_julia(data: Arc<RenderData>, y: u32, iterator: IteratorFunction) { + let (iteration_count_buffer, square_distance_buffer) = unsafe { data.slice(y) }; + + 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); + + // For more information, see render_row_normal. + + let ca = &data.real; + let cb = &data.imaginary; + + // When rendering the Julia fractals, the value of + // (c) remains constant throughout the entire + // canvas. The value of (z) - however - takes the + // position-determined value that (c) would've had. + + let mut za = { + let tmp0 = Float::with_val(PRECISION, &canvas_width / 2.0); + + let mut za = Float::with_val(PRECISION, &x_float - &tmp0); + za *= 4.0; + za /= &canvas_width; + + za + }; + + let mut zb = { + let tmp0 = Float::with_val(PRECISION, &canvas_height / 2.0); + + let mut zb = Float::with_val(PRECISION, &y_float - &tmp0); + zb *= 4.0; + zb /= &canvas_height; + + zb + }; + + let mut iteration_count: u32 = 0x0; + let mut square_distance; + while { + square_distance = Float::with_val(PRECISION, &za * &za + &zb * &zb).to_f32(); + square_distance <= 256.0 && iteration_count < data.maximum_iteration_count + } { + iterator(&mut za, &mut zb, ca, cb); + + iteration_count += 0x1; + } + + 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/render_row.rs b/source/benoit/benoit/application/render_row_normal.rs index 23946ec..570f9d4 100644 --- a/source/benoit/benoit/application/render_row.rs +++ b/source/benoit/benoit/application/render_row_normal.rs @@ -32,7 +32,7 @@ use rug::Float; use std::sync::Arc; impl Application { - pub fn render_row(data: Arc<RenderData>, y: u32, iterator: IteratorFunction) { + pub fn render_row_normal(data: Arc<RenderData>, y: u32, iterator: IteratorFunction) { let (iteration_count_buffer, square_distance_buffer) = unsafe { data.slice(y) }; for x in 0x0..data.canvas_width { diff --git a/source/benoit/benoit/configuration.rs b/source/benoit/benoit/configuration.rs index 455107f..730835a 100644 --- a/source/benoit/benoit/configuration.rs +++ b/source/benoit/benoit/configuration.rs @@ -34,14 +34,15 @@ pub struct Configuration { pub thread_count: u32, pub fractal: Fractal, + pub julia: bool, pub canvas_width: u32, pub canvas_height: u32, pub scale: u32, pub frame_count: u32, - pub center_real: Float, - pub center_imaginary: Float, + pub centre_real: Float, + pub centre_imaginary: Float, pub zoom: Float, pub maximum_iteration_count: u32, diff --git a/source/benoit/benoit/configuration/default.rs b/source/benoit/benoit/configuration/default.rs index b8649b5..c992951 100644 --- a/source/benoit/benoit/configuration/default.rs +++ b/source/benoit/benoit/configuration/default.rs @@ -35,14 +35,15 @@ impl Configuration { thread_count: 0x0, fractal: Fractal::Mandelbrot, + julia: false, canvas_width: 0x100, canvas_height: 0x100, - scale: 0x1, + scale: 0x2, frame_count: 0x10, - center_real: Float::with_val(PRECISION, 0.0), - center_imaginary: Float::with_val(PRECISION, 0.0), + centre_real: Float::with_val(PRECISION, 0.0), + centre_imaginary: Float::with_val(PRECISION, 0.0), zoom: Float::with_val(PRECISION, 1.0), maximum_iteration_count: 0x100, diff --git a/source/benoit/benoit/configuration/load.rs b/source/benoit/benoit/configuration/load.rs index 4f5f557..a4ac83c 100644 --- a/source/benoit/benoit/configuration/load.rs +++ b/source/benoit/benoit/configuration/load.rs @@ -83,7 +83,7 @@ impl Configuration { }; }; - get_integer(&mut configuration.thread_count, &configuration_table, "thread_count"); + get_integer(&mut configuration.thread_count, &configuration_table, "thread_count"); configuration.fractal = if let Some(name) = get_string(&configuration_table, "fractal") { match name.as_str() { @@ -101,8 +101,8 @@ impl Configuration { get_integer(&mut configuration.scale, &configuration_table, "scale"); get_integer(&mut configuration.frame_count, &configuration_table, "frame_count"); - get_float( &mut configuration.center_real, &configuration_table, "real"); - get_float( &mut configuration.center_imaginary, &configuration_table, "imaginary"); + get_float( &mut configuration.centre_real, &configuration_table, "real"); + get_float( &mut configuration.centre_imaginary, &configuration_table, "imaginary"); get_float( &mut configuration.zoom, &configuration_table, "zoom"); get_integer(&mut configuration.maximum_iteration_count, &configuration_table, "maximum_iteration_count"); |