diff options
23 files changed, 301 insertions, 276 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 26a68fd..5c9a622 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 2.2.0 + +* Bump minor version +* Rework row renderers as point renderers +* Support inverse fractals (toggle with left control) + # 2.1.1 * Update readme @@ -1,6 +1,6 @@ [package] name = "benoit" -version = "2.1.0" +version = "2.2.0" authors = ["Gabriel Bjørnager Jensen"] edition = "2021" description = "Mandelbrot renderer." diff --git a/source/benoit/benoit.rs b/source/benoit/benoit.rs index c384b5b..a366c61 100644 --- a/source/benoit/benoit.rs +++ b/source/benoit/benoit.rs @@ -32,24 +32,17 @@ pub mod palette; pub mod rendering; pub mod render; pub mod video; -pub mod width_height_ratio; -pub use width_height_ratio::*; - -pub struct Version<T> { - major: T, - minor: T, - patch: T, -} - -pub const VERSION: Version::<u32> = Version::<u32> { - major: 0x2, - minor: 0x1, - patch: 0x1, -}; +pub const VERSION: [u32; 0x3] = [ + 0x2, + 0x2, + 0x0, +]; pub const PRECISION: u32 = 0x80; +pub const BAILOUT: f32 = 256.0; + #[derive(Clone, Copy)] pub enum ImageFormat { Png, @@ -64,3 +57,11 @@ pub struct FeedbackInfo<'a> { next_centre_imag: &'a Float, next_zoom: &'a Float, } + +pub fn width_height_ratio(width: u32, height: u32) -> (f32, f32) { + return if width > height { + (1.0, height as f32 / width as f32) + } else { + (width as f32 / height as f32, 1.0) + }; +} diff --git a/source/benoit/benoit/app.rs b/source/benoit/benoit/app.rs index feac808..fa047f9 100644 --- a/source/benoit/benoit/app.rs +++ b/source/benoit/benoit/app.rs @@ -25,7 +25,7 @@ use crate::benoit::ImageFormat; use crate::benoit::fractal::Fractal; use crate::benoit::palette::Palette; use crate::benoit::rendering::Rendering; -use crate::benoit::render::{IteratorFunction, RowRenderer}; +use crate::benoit::render::{IteratorFunction, PointRenderer}; use crate::benoit::video::Video; extern crate rug; @@ -60,10 +60,12 @@ pub struct App { centre_imag: Float, zoom: Float, - multibrot_exponent: f32, - max_iter_count: u32, + inverse: bool, + + multibrot_exponent: f32, + palette: Palette, colour_range: f32, @@ -76,6 +78,6 @@ pub struct App { do_render: bool, do_textual_feedback: bool, - row_renderer: RowRenderer, + point_renderer: PointRenderer, iterator_function: IteratorFunction, } diff --git a/source/benoit/benoit/app/animate.rs b/source/benoit/benoit/app/animate.rs index 3d35bdb..9a6b4ba 100644 --- a/source/benoit/benoit/app/animate.rs +++ b/source/benoit/benoit/app/animate.rs @@ -79,7 +79,7 @@ impl App { let time_start = Instant::now(); - render(&mut iter_count_buffer[..], &mut square_dist_buffer[..], self.canvas_width, self.canvas_height, &self.centre_real, &self.centre_imag, &zoom, self.max_iter_count, self.row_renderer, self.iterator_function); + render(&mut iter_count_buffer[..], &mut square_dist_buffer[..], self.canvas_width, self.canvas_height, &self.centre_real, &self.centre_imag, &zoom, self.max_iter_count, self.inverse, self.point_renderer, self.iterator_function); let render_time = time_start.elapsed(); eprint!(" {:.3}ms, colouring...", render_time.as_micros() as f32 / 1000.0); diff --git a/source/benoit/benoit/app/handle_keys.rs b/source/benoit/benoit/app/handle_keys.rs index 0dc5b5a..3f9c0dd 100644 --- a/source/benoit/benoit/app/handle_keys.rs +++ b/source/benoit/benoit/app/handle_keys.rs @@ -25,7 +25,7 @@ use crate::benoit::{PRECISION}; use crate::benoit::app::App; use crate::benoit::fractal::Fractal; use crate::benoit::palette::Palette; -use crate::benoit::render::{IteratorFunction, RowRenderer}; +use crate::benoit::render::{IteratorFunction, PointRenderer}; use crate::benoit::rendering::Rendering; extern crate rug; @@ -44,10 +44,11 @@ impl App { Scancode::Escape => return true, Scancode::F1 => self.do_textual_feedback = !self.do_textual_feedback, Scancode::LAlt => (self.fractal, self.multibrot_exponent, self.iterator_function) = cycle_fractal(self.fractal, -0x1), + Scancode::LCtrl => self.inverse = toggle_inverse(self.inverse), Scancode::Left => self.palette = cycle_palette(self.palette, -0x1), Scancode::RAlt => (self.fractal, self.multibrot_exponent, self.iterator_function) = cycle_fractal(self.fractal, 0x1), Scancode::Right => self.palette = cycle_palette(self.palette, 0x1), - Scancode::Tab => (self.rendering, self.row_renderer) = toggle_julia(self.rendering), + Scancode::Tab => (self.rendering, self.point_renderer) = toggle_julia(self.rendering), Scancode::Z => eprintln!("c = {}{:+}i, {}x @ {} iter. (range.: {:.3})", &self.centre_real, &self.centre_imag, &self.zoom, self.max_iter_count, self.colour_range), _ => {}, } @@ -113,17 +114,28 @@ fn cycle_fractal(fractal: Fractal, distance: i8) -> (Fractal, f32, IteratorFunct return (fractal, exponent, iterator_function); } -fn toggle_julia(rendering: Rendering) -> (Rendering, RowRenderer) { +fn toggle_julia(rendering: Rendering) -> (Rendering, PointRenderer) { let rendering = rendering.cycle(); - let row_renderer = rendering.get_row_renderer(); + let point_renderer = rendering.get_point_renderer(); match rendering { Rendering::Julia => eprintln!("enabled the julia set"), Rendering::Normal => eprintln!("disabled the julia set"), }; - return (rendering, row_renderer); + return (rendering, point_renderer); +} + +fn toggle_inverse(inverse: bool) -> bool { + let inverse = !inverse; + + match inverse { + false => eprintln!("reverting fractal"), + true => eprintln!("inverting fractals"), + }; + + return inverse; } fn cycle_palette(palette: Palette, direction: i8) -> Palette { diff --git a/source/benoit/benoit/app/initialise.rs b/source/benoit/benoit/app/initialise.rs index 75535e8..f4b4f8e 100644 --- a/source/benoit/benoit/app/initialise.rs +++ b/source/benoit/benoit/app/initialise.rs @@ -74,10 +74,12 @@ impl App { centre_imag: configuration.centre_imag, zoom: configuration.zoom, - multibrot_exponent: 2.0, - max_iter_count: configuration.max_iter_count, + inverse: configuration.inverse, + + multibrot_exponent: configuration.fractal.get_exponent(), + palette: configuration.palette, colour_range: configuration.colour_range, @@ -90,7 +92,7 @@ impl App { do_render: true, do_textual_feedback: false, - row_renderer: configuration.rendering.get_row_renderer(), + point_renderer: configuration.rendering.get_point_renderer(), iterator_function: configuration.fractal.get_iterator(), }; } diff --git a/source/benoit/benoit/app/interactive.rs b/source/benoit/benoit/app/interactive.rs index e4ecd7c..a5cc51f 100644 --- a/source/benoit/benoit/app/interactive.rs +++ b/source/benoit/benoit/app/interactive.rs @@ -63,7 +63,7 @@ impl App { let time_start = Instant::now(); - render(&mut iter_count_buffer[..], &mut square_dist_buffer[..], self.canvas_width, self.canvas_height, &self.centre_real, &self.centre_imag, &self.zoom, self.max_iter_count, self.row_renderer, self.iterator_function); + render(&mut iter_count_buffer[..], &mut square_dist_buffer[..], self.canvas_width, self.canvas_height, &self.centre_real, &self.centre_imag, &self.zoom, self.max_iter_count, self.inverse, self.point_renderer, self.iterator_function); let render_time = time_start.elapsed(); eprintln!(" {:.3}ms", render_time.as_micros() as f32 / 1000.0); @@ -94,7 +94,7 @@ impl App { pub fn draw_feedback(&self, video: &mut Video, prev_centre_real: &Float, prev_centre_imag: &Float, prev_zoom: &Float) { let julia = match self.rendering { Rendering::Julia => true, - _ => false, + _ => false, }; if { @@ -135,15 +135,15 @@ impl App { println!("- \u{1B}[1mR\u{1B}[0m Decrease max. iteration count"); println!("- \u{1B}[1mF\u{1B}[0m Increase max. iteration count"); println!(); - println!("- \u{1B}[1mTab\u{1B}[0m Toggle Julia"); println!("- \u{1B}[1mLeft Alt\u{1B}[0m Cycle to previous fractal"); println!("- \u{1B}[1mRight Alt\u{1B}[0m Cycle to next fractal"); - println!(); - println!("- \u{1B}[1mUp\u{1B}[0m Increase colour range"); - println!("- \u{1B}[1mDown\u{1B}[0m Decrease colour range"); + println!("- \u{1B}[1mTab\u{1B}[0m Toggle Julia"); + println!("- \u{1B}[1mLeft Ctrl\u{1B}[0m Toggle inverse"); println!(); println!("- \u{1B}[1mLeft\u{1B}[0m Cycle to previous palette"); println!("- \u{1B}[1mRight\u{1B}[0m Cycle to next palette"); + println!("- \u{1B}[1mUp\u{1B}[0m Increase colour range"); + println!("- \u{1B}[1mDown\u{1B}[0m Decrease colour range"); println!(); println!("- \u{1B}[1mF1\u{1B}[0m Toggle textual feedback"); println!("- \u{1B}[1mZ\u{1B}[0m Print centre value (c)"); diff --git a/source/benoit/benoit/app/run.rs b/source/benoit/benoit/app/run.rs index b1ef578..cc8e3bb 100644 --- a/source/benoit/benoit/app/run.rs +++ b/source/benoit/benoit/app/run.rs @@ -30,7 +30,7 @@ impl App { #[must_use] pub fn run(&mut self) -> i32 { println!(); - println!("\u{1B}[1mBENO\u{CE}T\u{1B}[0m {:X}.{:X}.{:X}", VERSION.major, VERSION.minor, VERSION.patch); + println!("\u{1B}[1mBENO\u{CE}T\u{1B}[0m {:X}.{:X}.{:X}", VERSION[0x0], VERSION[0x1], VERSION[0x2]); println!("Copyright 2021, 2023 Gabriel Bj\u{F8}rnager Jensen."); println!(); println!("COCITAVIT\u{B7}ERCO\u{B7}FVIT"); diff --git a/source/benoit/benoit/app/still.rs b/source/benoit/benoit/app/still.rs index ff483b6..a5b6cc1 100644 --- a/source/benoit/benoit/app/still.rs +++ b/source/benoit/benoit/app/still.rs @@ -35,7 +35,7 @@ impl App { eprint!("rendering at {}{:+}i ({}x)...", self.centre_real.to_f32(), self.centre_imag.to_f32(), self.zoom.to_f32()); let time_start = Instant::now(); - render(&mut iter_count_buffer[..], &mut square_dist_buffer[..], self.canvas_width, self.canvas_height, &self.centre_real, &self.centre_imag, &self.zoom, self.max_iter_count, self.row_renderer, self.iterator_function); + render(&mut iter_count_buffer[..], &mut square_dist_buffer[..], self.canvas_width, self.canvas_height, &self.centre_real, &self.centre_imag, &self.zoom, self.max_iter_count, self.inverse, self.point_renderer, self.iterator_function); let render_time = time_start.elapsed(); eprint!(" {:.3}ms, colouring...", render_time.as_micros() as f32 / 1000.0); diff --git a/source/benoit/benoit/configuration.rs b/source/benoit/benoit/configuration.rs index ea6a841..2514ef8 100644 --- a/source/benoit/benoit/configuration.rs +++ b/source/benoit/benoit/configuration.rs @@ -51,6 +51,8 @@ pub struct Configuration { pub max_iter_count: u32, + pub inverse: bool, + pub palette: Palette, pub colour_range: f32, @@ -80,6 +82,8 @@ impl Configuration { max_iter_count: 0x100, + inverse: false, + palette: Palette::Fire, colour_range: 64.0, diff --git a/source/benoit/benoit/render.rs b/source/benoit/benoit/render.rs index b6c0ac8..45da9ee 100644 --- a/source/benoit/benoit/render.rs +++ b/source/benoit/benoit/render.rs @@ -26,18 +26,17 @@ use crate::benoit::render::render_data::RenderData; extern crate rug; use rug::Float; -use std::sync::Arc; pub mod colour; pub mod colour_data; pub mod iterate; pub mod render; pub mod render_data; -pub mod render_row; +pub mod render_point; pub use colour::*; pub use render::*; pub type IteratorFunction = fn(&mut Float, &mut Float, &Float, &Float); -pub type RowRenderer = fn(Arc<RenderData>, u32, IteratorFunction); +pub type PointRenderer = fn(&RenderData, u32, u32, IteratorFunction) -> (u32, f32); diff --git a/source/benoit/benoit/render/iterate/multibrot3.rs b/source/benoit/benoit/render/iterate/multibrot3.rs index 1de2e07..d0a7c2f 100644 --- a/source/benoit/benoit/render/iterate/multibrot3.rs +++ b/source/benoit/benoit/render/iterate/multibrot3.rs @@ -39,22 +39,22 @@ pub fn multibrot3(za: &mut Float, zb: &mut Float, ca: &Float, cb: &Float) { // <=> z_a = a^3-3ab^2 // z_b = 3(a^2)b-b^3 - let mut tmp0 = Float::with_val(PRECISION, &*zb * &*zb); // b^2 + let mut temporary0 = Float::with_val(PRECISION, &*zb * &*zb); // b^2 - let tmp1 = Float::with_val(PRECISION, &tmp0 * &*zb); // b^3 + let temporary1 = Float::with_val(PRECISION, &temporary0 * &*zb); // b^3 - tmp0 *= &*za; // ab^2 - tmp0 *= 0x3; // 3ab^2 + temporary0 *= &*za; // ab^2 + temporary0 *= 0x3; // 3ab^2 za.square_mut(); // a^2 *zb *= &*za; // (a^2)b *za *= &za_temporary; // a^3 - *za -= &tmp0; // a^3-3ab^2 + *za -= &temporary0; // a^3-3ab^2 *za += ca; // a^3-3ab^2+Re(c) - *zb *= 3.0; // 3(a^2)b - *zb -= &tmp1; // 3(a^2)b-b^3 - *zb += cb; // 3(a^2)b-b^3+Im(c) + *zb *= 3.0; // 3(a^2)b + *zb -= &temporary1; // 3(a^2)b-b^3 + *zb += cb; // 3(a^2)b-b^3+Im(c) } diff --git a/source/benoit/benoit/render/render.rs b/source/benoit/benoit/render/render.rs index 947bca7..1ff0931 100644 --- a/source/benoit/benoit/render/render.rs +++ b/source/benoit/benoit/render/render.rs @@ -21,7 +21,7 @@ If not, see <https://www.gnu.org/licenses/>. */ -use crate::benoit::render::{IteratorFunction, RowRenderer}; +use crate::benoit::render::{IteratorFunction, PointRenderer}; use crate::benoit::render::render_data::RenderData; extern crate rayon; @@ -29,12 +29,32 @@ extern crate rug; use rayon::prelude::*; use rug::Float; -use std::sync::Arc; -pub fn render(iter_count_buffer: &mut [u32], square_dist_buffer: &mut [f32], canvas_width: u32, canvas_height: u32, centre_real: &Float, centre_imag: &Float, zoom: &Float, max_iter_count: u32, row_renderer: RowRenderer, iterator: IteratorFunction) { - let data = Arc::new(RenderData::new(iter_count_buffer, square_dist_buffer, canvas_width, canvas_height, centre_real.clone(), centre_imag.clone(), zoom.clone(), max_iter_count)); +pub fn render(iter_count_buffer: &mut [u32], square_dist_buffer: &mut [f32], canvas_width: u32, canvas_height: u32, centre_real: &Float, centre_imag: &Float, zoom: &Float, max_iter_count: u32, inverse: bool, point_renderer: PointRenderer, iterator: IteratorFunction) { + let data = RenderData::new(iter_count_buffer, square_dist_buffer, canvas_width, canvas_height, centre_real.clone(), centre_imag.clone(), zoom.clone(), max_iter_count, inverse); - (0x0..canvas_height).into_par_iter().for_each(|row| { - row_renderer(data.clone(), row as u32, iterator); + let (canvas_size, overflow) = canvas_height.overflowing_mul(canvas_width); + if overflow { panic!("overflow when calculating canvas size") }; + + (0x0..canvas_size).into_par_iter().for_each(|index| { + render_point(&data, index as u32, point_renderer, iterator); }); } + +fn render_point(data: &RenderData, index: u32, point_renderer: PointRenderer, iterator: IteratorFunction) { + let (iter_count_buffer, square_dist_buffer) = data.output_buffers(); + + let (canvas_width, _) = data.canvas_size(); + + let x = index % canvas_width; + let y = index / canvas_width; + + let (iter_count, square_dist) = point_renderer(&data, x, y, iterator); + + // Sacrifice safety for speed by removing bounds- + // checking. + unsafe { + *iter_count_buffer.get_unchecked_mut( index as usize) = iter_count; + *square_dist_buffer.get_unchecked_mut(index as usize) = square_dist; + } +} diff --git a/source/benoit/benoit/render/render_data.rs b/source/benoit/benoit/render/render_data.rs index 765c0c0..a1d2fdd 100644 --- a/source/benoit/benoit/render/render_data.rs +++ b/source/benoit/benoit/render/render_data.rs @@ -21,7 +21,7 @@ If not, see <https://www.gnu.org/licenses/>. */ -use crate::benoit::width_height_ratio; +use crate::benoit::{PRECISION, width_height_ratio}; extern crate rug; @@ -32,12 +32,16 @@ pub struct RenderData { canvas_width: u32, canvas_height: u32, + canvas_size: usize, + centre_real: Float, centre_imag: Float, zoom: Float, max_iter_count: u32, + inverse: bool, + x_offset: f32, y_offset: f32, @@ -50,19 +54,23 @@ pub struct RenderData { impl RenderData { #[must_use] - pub fn new(iter_count_buffer: &mut [u32], square_dist_buffer: &mut [f32], canvas_width: u32, canvas_height: u32, centre_real: Float, centre_imag: Float, zoom: Float, max_iter_count: u32) -> RenderData { + pub fn new(iter_count_buffer: &mut [u32], square_dist_buffer: &mut [f32], canvas_width: u32, canvas_height: u32, centre_real: Float, centre_imag: Float, zoom: Float, max_iter_count: u32, inverse: bool) -> RenderData { let (width_ratio, height_ratio) = width_height_ratio(canvas_width, canvas_height); return RenderData { canvas_width: canvas_width, canvas_height: canvas_height, + canvas_size: canvas_height as usize * canvas_width as usize, + centre_real: centre_real, centre_imag: centre_imag, zoom: zoom, max_iter_count: max_iter_count, + inverse: inverse, + x_offset: canvas_width as f32 / -2.0, y_offset: canvas_height as f32 / -2.0, @@ -75,18 +83,32 @@ impl RenderData { } #[must_use] - pub fn input(&self) -> (u32, &Float, &Float, &Float, u32) { - return (self.canvas_width, &self.centre_real, &self.centre_imag, &self.zoom, self.max_iter_count); + pub fn inverse_factor(&self, a: &Float, b: &Float) -> Float { + return if self.inverse { + let mut inverse_factor = Float::with_val(PRECISION, a * a); + inverse_factor += b * b; + inverse_factor.recip_mut(); + + inverse_factor + } else { + Float::with_val(PRECISION, 0x1) + }; } #[must_use] - pub fn output_buffers(&self, row: u32) -> (&mut [u32], &mut [f32]) { - assert!(row < self.canvas_height); + pub fn canvas_size(&self) -> (u32, u32) { + return (self.canvas_width, self.canvas_height); + } - let offset = row as isize * self.canvas_width as isize; + #[must_use] + pub fn input(&self) -> (&Float, &Float, &Float, u32) { + return (&self.centre_real, &self.centre_imag, &self.zoom, self.max_iter_count); + } - let iter_count = unsafe { from_raw_parts_mut(self.iter_count_buffer.offset(offset), self.canvas_width as usize) }; - let square_dist = unsafe { from_raw_parts_mut(self.square_dist_buffer.offset(offset), self.canvas_width as usize) }; + #[must_use] + pub fn output_buffers(&self) -> (&mut [u32], &mut [f32]) { + let iter_count = unsafe { from_raw_parts_mut(self.iter_count_buffer, self.canvas_size as usize) }; + let square_dist = unsafe { from_raw_parts_mut(self.square_dist_buffer, self.canvas_size as usize) }; return (iter_count, square_dist); } diff --git a/source/benoit/benoit/render/render_row.rs b/source/benoit/benoit/render/render_point.rs index 7f9bf9a..7f9bf9a 100644 --- a/source/benoit/benoit/render/render_row.rs +++ b/source/benoit/benoit/render/render_point.rs diff --git a/source/benoit/benoit/render/render_point/julia.rs b/source/benoit/benoit/render/render_point/julia.rs new file mode 100644 index 0000000..fa7329c --- /dev/null +++ b/source/benoit/benoit/render/render_point/julia.rs @@ -0,0 +1,76 @@ +/* + 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::{BAILOUT, PRECISION}; +use crate::benoit::render::IteratorFunction; +use crate::benoit::render::render_data::RenderData; + +extern crate rug; + +use rug::{Assign, Float}; +use rug::float::Special; + +pub fn julia(data: &RenderData, x: u32, y: u32, iterator: IteratorFunction) -> (u32, f32) { + // For more information, see render_point::normal. + + let (centre_real, centre_imag, _zoom, max_iter_count) = data.input(); + + let (x_offset, y_offset, x_factor, y_factor) = data.consts(); + + let x_temporary = (x as f32 + x_offset) * x_factor; + let y_temporary = (y as f32 + y_offset) * y_factor; + + let ca = centre_real; + let cb = centre_imag; + + let mut za = Float::with_val(PRECISION, x_temporary); + let mut zb = Float::with_val(PRECISION, y_temporary); + + let inverse_factor = data.inverse_factor(&za, &zb); + + za *= &inverse_factor; + zb *= &inverse_factor; + + let mut za_prev = Float::with_val(PRECISION, Special::Nan); + let mut zb_prev = Float::with_val(PRECISION, Special::Nan); + + let mut iter_count: u32 = 0x1; + let mut square_dist = Float::with_val(PRECISION, Special::Nan); + while { + square_dist.assign(&za * &za + &zb * &zb); + + let periodic = za == za_prev && zb == zb_prev; + if periodic { iter_count = max_iter_count } + + square_dist <= BAILOUT && iter_count < max_iter_count + } { + za_prev.assign(&za); + zb_prev.assign(&zb); + + iterator(&mut za, &mut zb, ca, cb); + + iter_count += 0x1; + } + + return (iter_count, square_dist.to_f32()); +} diff --git a/source/benoit/benoit/render/render_point/normal.rs b/source/benoit/benoit/render/render_point/normal.rs new file mode 100644 index 0000000..8bf88f3 --- /dev/null +++ b/source/benoit/benoit/render/render_point/normal.rs @@ -0,0 +1,89 @@ +/* + 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::{BAILOUT, PRECISION}; +use crate::benoit::render::IteratorFunction; +use crate::benoit::render::render_data::RenderData; + +extern crate rug; + +use rug::{Assign, Float}; +use rug::float::Special; + +pub fn normal(data: &RenderData, x: u32, y: u32, iterator: IteratorFunction) -> (u32, f32) { + let (centre_real, centre_imag, zoom, max_iter_count) = data.input(); + + let (x_offset, y_offset, x_factor, y_factor) = data.consts(); + + let x_temporary = (x as f32 + x_offset) * x_factor; + let y_temporary = (y as f32 + y_offset) * y_factor; + + let ca = { + let mut ca = Float::with_val(PRECISION, x_temporary / zoom); + ca += centre_real; + + ca + }; + + let cb = { + let mut cb = Float::with_val(PRECISION, y_temporary / zoom); + cb -= centre_imag; + + cb + }; + + let inverse_factor = data.inverse_factor(&ca, &cb); + + let ca = ca * &inverse_factor; + let cb = cb * &inverse_factor; + + let mut za = ca.clone(); + let mut zb = cb.clone(); + + let mut za_prev = Float::with_val(PRECISION, Special::Nan); + let mut zb_prev = Float::with_val(PRECISION, Special::Nan); + + let mut iter_count: u32 = 0x1; + let mut square_dist = Float::with_val(PRECISION, Special::Nan); + while { + square_dist.assign(&za * &za + &zb * &zb); + // Having a larger escape radius gives better + // results with regard to smoothing. + + // Check if the value is periodic, i.e. its + // sequence repeats. + let periodic = za == za_prev && zb == zb_prev; + if periodic { iter_count = max_iter_count } + + square_dist <= BAILOUT && iter_count < max_iter_count + } { + za_prev.assign(&za); + zb_prev.assign(&zb); + + iterator(&mut za, &mut zb, &ca, &cb); + + iter_count += 0x1; + } + + return (iter_count, square_dist.to_f32()); +} diff --git a/source/benoit/benoit/render/render_row/julia.rs b/source/benoit/benoit/render/render_row/julia.rs deleted file mode 100644 index 9202a19..0000000 --- a/source/benoit/benoit/render/render_row/julia.rs +++ /dev/null @@ -1,84 +0,0 @@ -/* - 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::render::IteratorFunction; -use crate::benoit::render::render_data::RenderData; - -extern crate rug; - -use rug::{Assign, Float}; -use rug::float::Special; -use std::sync::Arc; - -pub fn julia(data: Arc<RenderData>, y: u32, iterator: IteratorFunction) { - let (iter_count_buffer, square_dist_buffer) = data.output_buffers(y); - - let (canvas_width, centre_real, centre_imag, _zoom, max_iter_count) = data.input(); - - let (x_offset, y_offset, x_factor, y_factor) = data.consts(); - - for x in 0x0..canvas_width { - // For more information, see render_row::normal. - - let x_temporary = (x as f32 + x_offset) * x_factor; - let y_temporary = (y as f32 + y_offset) * y_factor; - - let ca = centre_real; - let cb = centre_imag; - - // 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 = Float::with_val(PRECISION, x_temporary); - let mut zb = Float::with_val(PRECISION, y_temporary); - - let mut za_prev = Float::with_val(PRECISION, Special::Nan); - let mut zb_prev = Float::with_val(PRECISION, Special::Nan); - - let mut iter_count: u32 = 0x1; - let mut square_dist; - while { - square_dist = Float::with_val(PRECISION, &za * &za + &zb * &zb).to_f32(); - - let periodic = za == za_prev && zb == zb_prev; - if periodic { iter_count = max_iter_count } - - square_dist <= 256.0 && iter_count < max_iter_count - } { - za_prev.assign(&za); - zb_prev.assign(&zb); - - iterator(&mut za, &mut zb, ca, cb); - - iter_count += 0x1; - } - - unsafe { - *iter_count_buffer.get_unchecked_mut( x as usize) = iter_count; - *square_dist_buffer.get_unchecked_mut(x as usize) = square_dist; - } - } -} diff --git a/source/benoit/benoit/render/render_row/normal.rs b/source/benoit/benoit/render/render_row/normal.rs deleted file mode 100644 index 6e310d7..0000000 --- a/source/benoit/benoit/render/render_row/normal.rs +++ /dev/null @@ -1,94 +0,0 @@ -/* - 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::render::IteratorFunction; -use crate::benoit::render::render_data::RenderData; - -extern crate rug; - -use rug::{Assign, Float}; -use rug::float::Special; -use std::sync::Arc; - -pub fn normal(data: Arc<RenderData>, y: u32, iterator: IteratorFunction) { - let (iter_count_buffer, square_dist_buffer) = data.output_buffers(y); - - let (canvas_width, centre_real, centre_imag, zoom, max_iter_count) = data.input(); - - let (x_offset, y_offset, x_factor, y_factor) = data.consts(); - - for x in 0x0..canvas_width { - let x_temporary = (x as f32 + x_offset) * x_factor; - let y_temporary = (y as f32 + y_offset) * y_factor; - - let ca = { - let mut ca = Float::with_val(PRECISION, x_temporary / zoom); - ca += centre_real; - - ca - }; - - let cb = { - let mut cb = Float::with_val(PRECISION, y_temporary / zoom); - cb -= centre_imag; - - cb - }; - - let mut za = ca.clone(); - let mut zb = cb.clone(); - - let mut za_prev = Float::with_val(PRECISION, Special::Nan); - let mut zb_prev = Float::with_val(PRECISION, Special::Nan); - - let mut iter_count: u32 = 0x1; - let mut square_dist; - while { - square_dist = Float::with_val(PRECISION, &za * &za + &zb * &zb).to_f32(); - // Having a larger escape radius gives better - // results with regard to smoothing. - - // Check if the value is periodic, i.e. its - // sequence repeats. - let periodic = za == za_prev && zb == zb_prev; - if periodic { iter_count = max_iter_count } - - square_dist <= 256.0 && iter_count < max_iter_count - } { - za_prev.assign(&za); - zb_prev.assign(&zb); - - iterator(&mut za, &mut zb, &ca, &cb); - - iter_count += 0x1; - } - - // Sacrifice safety for speed by removing bounds- - // checking. - unsafe { - *iter_count_buffer.get_unchecked_mut( x as usize) = iter_count; - *square_dist_buffer.get_unchecked_mut(x as usize) = square_dist; - } - } -} diff --git a/source/benoit/benoit/rendering.rs b/source/benoit/benoit/rendering.rs index 125798f..923c01f 100644 --- a/source/benoit/benoit/rendering.rs +++ b/source/benoit/benoit/rendering.rs @@ -21,8 +21,8 @@ If not, see <https://www.gnu.org/licenses/>. */ -use crate::benoit::render::RowRenderer; -use crate::benoit::render::render_row; +use crate::benoit::render::PointRenderer; +use crate::benoit::render::render_point; use std::mem::transmute; @@ -33,10 +33,10 @@ pub enum Rendering { } impl Rendering { - pub fn get_row_renderer(self) -> RowRenderer { + pub fn get_point_renderer(self) -> PointRenderer { return match self { - Rendering::Julia => render_row::julia, - Rendering::Normal => render_row::normal, + Rendering::Julia => render_point::julia, + Rendering::Normal => render_point::normal, }; } diff --git a/source/benoit/benoit/video/initialise.rs b/source/benoit/benoit/video/initialise.rs index dcd92f7..8719b4e 100644 --- a/source/benoit/benoit/video/initialise.rs +++ b/source/benoit/benoit/video/initialise.rs @@ -34,7 +34,7 @@ impl Video { let sdl = sdl2::init().expect("unable to initialise sdl2"); let sdl_video = sdl.video().expect("unable to initialise video"); - let window_title = format!("BENO\u{CE}T {:X}.{:X}.{:X}", VERSION.major, VERSION.minor, VERSION.patch); + let window_title = format!("BENO\u{CE}T {:X}.{:X}.{:X}", VERSION[0x0], VERSION[0x1], VERSION[0x2]); let mut window_builder = sdl_video.window(window_title.as_str(), canvas_width * scale, canvas_height * scale); window_builder.borderless(); diff --git a/source/benoit/benoit/width_height_ratio.rs b/source/benoit/benoit/width_height_ratio.rs deleted file mode 100644 index c4afe91..0000000 --- a/source/benoit/benoit/width_height_ratio.rs +++ /dev/null @@ -1,30 +0,0 @@ -/* - 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 fn width_height_ratio(width: u32, height: u32) -> (f32, f32) { - return if width > height { - (1.0, height as f32 / width as f32) - } else { - (width as f32 / height as f32, 1.0) - }; -} |