summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md9
-rw-r--r--Cargo.toml3
-rw-r--r--source/benoit/benoit.rs9
-rw-r--r--source/benoit/benoit/app.rs5
-rw-r--r--source/benoit/benoit/app/configure.rs3
-rw-r--r--source/benoit/benoit/app/draw_feedback.rs48
-rw-r--r--source/benoit/benoit/app/handle_keys.rs31
-rw-r--r--source/benoit/benoit/app/print_controls.rs64
-rw-r--r--source/benoit/benoit/app/render.rs (renamed from source/benoit/benoit/renderer/render_point.rs)26
-rw-r--r--source/benoit/benoit/app/run.rs78
-rw-r--r--source/benoit/benoit/colour_data.rs45
-rw-r--r--source/benoit/benoit/configuration.rs49
-rw-r--r--source/benoit/benoit/configuration/default.rs62
-rw-r--r--source/benoit/benoit/configuration/load.rs9
-rw-r--r--source/benoit/benoit/fractal.rs51
-rw-r--r--source/benoit/benoit/image.rs4
-rw-r--r--source/benoit/benoit/image/colour.rs27
-rw-r--r--source/benoit/benoit/palette.rs64
-rw-r--r--source/benoit/benoit/palette/data.rs77
-rw-r--r--source/benoit/benoit/render.rs20
-rw-r--r--source/benoit/benoit/render/allocate.rs6
-rw-r--r--source/benoit/benoit/render/render.rs84
-rw-r--r--source/benoit/benoit/render_data.rs85
-rw-r--r--source/benoit/benoit/renderer.rs55
-rw-r--r--source/benoit/benoit/renderer/render_point/julia.rs84
-rw-r--r--source/benoit/benoit/renderer/render_point/normal.rs89
-rw-r--r--source/benoit/benoit/script.rs2
-rw-r--r--source/benoit/benoit/script/animate.rs1
-rw-r--r--source/benoit/benoit/script/configure.rs3
-rw-r--r--source/benoit/benoit/script/dump.rs3
-rw-r--r--source/benoit/benoit/script/still.rs1
-rw-r--r--source/benoit/benoit/video/initialise.rs2
-rw-r--r--source/benoit/main.rs9
33 files changed, 527 insertions, 581 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0c77393..99e632d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,12 @@
+# 2.4.1
+
+* Remove renderers in favour of the fractal type
+* Fix default configuration
+* Update rendering
+* Greatly improve safety
+* Remove ctor as dependency
+* Modulise and clean up code
+
# 2.4.0
* Clean up and restructure code
diff --git a/Cargo.toml b/Cargo.toml
index 305156b..fbe0085 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "benoit"
-version = "2.4.0"
+version = "2.4.1"
authors = ["Gabriel Bjørnager Jensen"]
edition = "2021"
description = "Mandelbrot renderer."
@@ -16,7 +16,6 @@ codegen-units = 1
lto = "fat"
[dependencies]
-ctor = "0.2.5"
enum-iterator = "1.4.1"
png = "0.17.10"
rayon = "1.8.0"
diff --git a/source/benoit/benoit.rs b/source/benoit/benoit.rs
index 86fa5d0..7d3a165 100644
--- a/source/benoit/benoit.rs
+++ b/source/benoit/benoit.rs
@@ -30,19 +30,18 @@ pub mod fractal;
pub mod palette;
pub mod render;
pub mod render_data;
-pub mod renderer;
pub mod script;
pub mod video;
-pub const VERSION: [u32; 0x3] = [
+pub const VERSION: (u32, u32, u32) = (
0x2, // Major
0x4, // Minor
- 0x0, // Patch
-];
+ 0x1, // Patch
+);
pub const PRECISION: u32 = 0x80;
-pub const BAILOUT: f32 = 256.0;
+pub const BAILOUT_DISTANCE: f32 = 256.0;
pub fn width_height_ratio(width: u32, height: u32) -> (f32, f32) {
return if width > height {
diff --git a/source/benoit/benoit/app.rs b/source/benoit/benoit/app.rs
index 3eb54d0..61446be 100644
--- a/source/benoit/benoit/app.rs
+++ b/source/benoit/benoit/app.rs
@@ -24,22 +24,23 @@
use crate::benoit::complex::Complex;
use crate::benoit::fractal::Fractal;
use crate::benoit::palette::Palette;
-use crate::benoit::renderer::Renderer;
extern crate rug;
use rug::Float;
pub mod configure;
+pub mod draw_feedback;
pub mod drop;
pub mod handle_keys;
pub mod poll_events;
+pub mod print_controls;
+pub mod render;
pub mod run;
pub struct App {
// Configuration:
fractal: Fractal,
- renderer: Renderer,
canvas_width: u32,
canvas_height: u32,
diff --git a/source/benoit/benoit/app/configure.rs b/source/benoit/benoit/app/configure.rs
index 64db009..1af3d60 100644
--- a/source/benoit/benoit/app/configure.rs
+++ b/source/benoit/benoit/app/configure.rs
@@ -29,8 +29,7 @@ impl App {
#[must_use]
pub fn configure(configuration: Configuration) -> App {
return App {
- fractal: configuration.fractal,
- renderer: configuration.renderer,
+ fractal: configuration.fractal,
canvas_width: configuration.canvas_width,
canvas_height: configuration.canvas_height,
diff --git a/source/benoit/benoit/app/draw_feedback.rs b/source/benoit/benoit/app/draw_feedback.rs
new file mode 100644
index 0000000..e21b343
--- /dev/null
+++ b/source/benoit/benoit/app/draw_feedback.rs
@@ -0,0 +1,48 @@
+/*
+ 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::app::App;
+use crate::benoit::complex::Complex;
+use crate::benoit::video::Video;
+
+extern crate rug;
+
+use rug::Float;
+
+impl App {
+ pub(super) fn draw_feedback(&self, video: &mut Video, prev_centre: &Complex, prev_zoom: &Float) {
+ if {
+ // Don't draw translation feedback if rendering a
+ // Julia set or if we haven't done any viewport
+ // translations.
+
+ &self.centre.real != &prev_centre.real
+ || &self.centre.imag != &prev_centre.imag
+ || &self.zoom != prev_zoom
+ }{
+ video.draw_translation_feedback(self.canvas_width, self.canvas_height, self.scale, prev_centre, prev_zoom, &self.centre, &self.zoom);
+ }
+
+ if self.do_textual_feedback { video.draw_textual_feedback(&self.centre, &self.zoom, self.max_iter_count) };
+ }
+} \ No newline at end of file
diff --git a/source/benoit/benoit/app/handle_keys.rs b/source/benoit/benoit/app/handle_keys.rs
index b0fdcb9..5b27897 100644
--- a/source/benoit/benoit/app/handle_keys.rs
+++ b/source/benoit/benoit/app/handle_keys.rs
@@ -24,7 +24,6 @@
use crate::benoit::PRECISION;
use crate::benoit::app::App;
use crate::benoit::configuration::Configuration;
-use crate::benoit::renderer::Renderer;
extern crate rug;
extern crate sdl2;
@@ -123,15 +122,6 @@ impl App {
eprintln!("renderer the {}", self.fractal.kind().name());
}
- fn toggle_julia(&mut self) {
- self.renderer.toggle();
-
- match self.renderer {
- Renderer::Julia => eprintln!("enabled the julia set"),
- Renderer::Normal => eprintln!("disabled the julia set"),
- };
- }
-
fn toggle_inverse(&mut self) {
let inverse = !self.fractal.inverse();
@@ -143,6 +133,17 @@ impl App {
self.fractal.set_inverse(inverse);
}
+ fn toggle_julia(&mut self) {
+ let julia = !self.fractal.julia();
+
+ match julia {
+ false => eprintln!("disabled the julia set"),
+ true => eprintln!("enabled the julia set"),
+ };
+
+ self.fractal.set_julia(julia);
+ }
+
fn cycle_palette(&mut self, direction: i8) {
let palette = self.palette.cycle(direction);
@@ -152,12 +153,12 @@ impl App {
}
fn reset_viewport(&mut self) {
- self.centre.real.assign(Configuration::DEFAULT_CENTRE_REAL);
- self.centre.imag.assign(Configuration::DEFAULT_CENTRE_IMAG);
+ self.centre.real.assign(Configuration::DEFAULT_CENTRE.0);
+ self.centre.imag.assign(Configuration::DEFAULT_CENTRE.1);
self.zoom.assign( Configuration::DEFAULT_ZOOM);
- self.extra.real.assign(Configuration::DEFAULT_EXTRA_REAL);
- self.extra.imag.assign(Configuration::DEFAULT_EXTRA_IMAG);
+ self.extra.real.assign(Configuration::DEFAULT_EXTRA.0);
+ self.extra.imag.assign(Configuration::DEFAULT_EXTRA.1);
self.max_iter_count = Configuration::DEFAULT_MAX_ITER_COUNT;
@@ -165,7 +166,7 @@ impl App {
}
fn dump_info(&self) {
- eprintln!("info dump: the {}", self.fractal.kind().name());
+ eprintln!("info dump: the {}", self.fractal.name());
eprintln!(" c = {}{:+}i ({}x)", &self.centre.real, &self.centre.imag, &self.zoom);
eprintln!(" w = {}{:+}i", &self.extra.real, &self.extra.imag);
eprintln!(" max. iter.: {}, col. range: {}", self.max_iter_count, self.colour_range);
diff --git a/source/benoit/benoit/app/print_controls.rs b/source/benoit/benoit/app/print_controls.rs
new file mode 100644
index 0000000..936d286
--- /dev/null
+++ b/source/benoit/benoit/app/print_controls.rs
@@ -0,0 +1,64 @@
+/*
+ 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::app::App;
+
+impl App {
+ pub(super) fn print_controls(&self) {
+ println!("Controls:");
+ println!("- \u{1B}[1mW\u{1B}[0m Translate +Im");
+ println!("- \u{1B}[1mA\u{1B}[0m Translate -Re");
+ println!("- \u{1B}[1mS\u{1B}[0m Translate -Im");
+ println!("- \u{1B}[1mD\u{1B}[0m Translate +Re");
+ println!();
+ println!("- \u{1B}[1mQ\u{1B}[0m Zoom out");
+ println!("- \u{1B}[1mE\u{1B}[0m Zoom in");
+ println!();
+ 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}[1mLEFT ALT\u{1B}[0m Cycle to previous fractal");
+ println!("- \u{1B}[1mRIGHT ALT\u{1B}[0m Cycle to next fractal");
+ 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)");
+ println!();
+ println!("- \u{1B}[1mC\u{1B}[0m Render frame");
+ println!();
+ println!("Controls (holding \u{1B}[1mSHIFT\u{1B}[0m):");
+ println!("- \u{1B}[1mW\u{1B}[0m Perturbate/translate +Im");
+ println!("- \u{1B}[1mA\u{1B}[0m Perturbate/translate -Re");
+ println!("- \u{1B}[1mS\u{1B}[0m Perturbate/translate -Im");
+ println!("- \u{1B}[1mD\u{1B}[0m Perturbate/translate +Re");
+ println!();
+ println!("- \u{1B}[1mC\u{1B}[0m Render frame");
+ println!();
+ }
+} \ No newline at end of file
diff --git a/source/benoit/benoit/renderer/render_point.rs b/source/benoit/benoit/app/render.rs
index 7f9bf9a..7f4b132 100644
--- a/source/benoit/benoit/renderer/render_point.rs
+++ b/source/benoit/benoit/app/render.rs
@@ -21,8 +21,26 @@
If not, see <https://www.gnu.org/licenses/>.
*/
-pub mod julia;
-pub mod normal;
+use crate::benoit::app::App;
+use crate::benoit::render::Render;
+use std::time::Instant;
-pub use julia::*;
-pub use normal::*;
+impl App {
+ pub(super) fn render(&self, render: &mut Render) {
+ eprint!("rendering...");
+
+ let time_start = Instant::now();
+
+ render.render(
+ self.fractal,
+ &self.centre,
+ &self.zoom,
+ &self.extra,
+ self.max_iter_count,
+ );
+
+ let render_time = time_start.elapsed();
+
+ eprintln!(" {:.3}ms", render_time.as_micros() as f32 / 1000.0);
+ }
+} \ No newline at end of file
diff --git a/source/benoit/benoit/app/run.rs b/source/benoit/benoit/app/run.rs
index cefe5f7..b4f8fb4 100644
--- a/source/benoit/benoit/app/run.rs
+++ b/source/benoit/benoit/app/run.rs
@@ -22,14 +22,13 @@
*/
use crate::benoit::app::App;
-use crate::benoit::complex::Complex;
use crate::benoit::image::Image;
use crate::benoit::render::Render;
use crate::benoit::video::Video;
extern crate rug;
-use rug::{Assign, Float};
+use rug::Assign;
use std::time::Instant;
impl App {
@@ -37,7 +36,7 @@ impl App {
pub fn run(mut self) -> i32 {
let mut video = Video::initialise(self.canvas_width, self.canvas_height, self.scale);
- App::print_controls();
+ self.print_controls();
let mut event_pump = video.sdl.event_pump().expect("unable to get event pump");
@@ -74,77 +73,4 @@ impl App {
return 0x0;
}
-
- fn render(&self, render: &mut Render) {
- eprint!("rendering...");
-
- let time_start = Instant::now();
-
- render.render(
- self.fractal,
- self.renderer,
- &self.centre,
- &self.zoom,
- &self.extra,
- self.max_iter_count,
- );
-
- let render_time = time_start.elapsed();
-
- eprintln!(" {:.3}ms", render_time.as_micros() as f32 / 1000.0);
- }
-
- fn draw_feedback(&self, video: &mut Video, prev_centre: &Complex, prev_zoom: &Float) {
- if {
- // Don't draw translation feedback if rendering a
- // Julia set or if we haven't done any viewport
- // translations.
-
- &self.centre.real != &prev_centre.real
- || &self.centre.imag != &prev_centre.imag
- || &self.zoom != prev_zoom
- }{
- video.draw_translation_feedback(self.canvas_width, self.canvas_height, self.scale, prev_centre, prev_zoom, &self.centre, &self.zoom);
- }
-
- if self.do_textual_feedback { video.draw_textual_feedback(&self.centre, &self.zoom, self.max_iter_count) };
- }
-
- fn print_controls() {
- println!("Controls:");
- println!("- \u{1B}[1mW\u{1B}[0m Translate +Im");
- println!("- \u{1B}[1mA\u{1B}[0m Translate -Re");
- println!("- \u{1B}[1mS\u{1B}[0m Translate -Im");
- println!("- \u{1B}[1mD\u{1B}[0m Translate +Re");
- println!();
- println!("- \u{1B}[1mQ\u{1B}[0m Zoom out");
- println!("- \u{1B}[1mE\u{1B}[0m Zoom in");
- println!();
- 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}[1mLEFT ALT\u{1B}[0m Cycle to previous fractal");
- println!("- \u{1B}[1mRIGHT ALT\u{1B}[0m Cycle to next fractal");
- 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)");
- println!();
- println!("- \u{1B}[1mC\u{1B}[0m Render frame");
- println!();
- println!("Controls (holding \u{1B}[1mSHIFT\u{1B}[0m):");
- println!("- \u{1B}[1mW\u{1B}[0m Perturbate/translate +Im");
- println!("- \u{1B}[1mA\u{1B}[0m Perturbate/translate -Re");
- println!("- \u{1B}[1mS\u{1B}[0m Perturbate/translate -Im");
- println!("- \u{1B}[1mD\u{1B}[0m Perturbate/translate +Re");
- println!();
- println!("- \u{1B}[1mC\u{1B}[0m Render frame");
- println!();
- }
} \ No newline at end of file
diff --git a/source/benoit/benoit/colour_data.rs b/source/benoit/benoit/colour_data.rs
index 6e994fb..4ea3852 100644
--- a/source/benoit/benoit/colour_data.rs
+++ b/source/benoit/benoit/colour_data.rs
@@ -24,63 +24,46 @@
use crate::benoit::image::Image;
use crate::benoit::palette::PaletteData;
-use std::slice::{from_raw_parts, from_raw_parts_mut};
+use std::mem::size_of;
+use std::num::NonZeroUsize;
+use std::ptr::addr_of;
pub struct ColourData {
- canvas_size: usize,
-
exponent: f32,
max_iter_count: u32,
colour_range: f32,
palette_data: &'static PaletteData,
- iter_count_buffer: *const u32,
- square_dist_buffer: *const f32,
-
- image: *mut (u8, u8, u8),
+ image: NonZeroUsize,
}
impl ColourData {
#[must_use]
pub fn new(
- image: &mut Image,
- canvas_width: u32,
- canvas_height: u32,
- exponent: f32,
- max_iter_count: u32,
- colour_range: f32,
- palette_data: &'static PaletteData,
- iter_count_buffer: &[u32],
- square_dist_buffer: &[f32],
+ image: &Image,
+ exponent: f32,
+ max_iter_count: u32,
+ colour_range: f32,
+ palette_data: &'static PaletteData,
) -> ColourData {
return ColourData {
- canvas_size: canvas_height as usize * canvas_width as usize,
-
exponent: exponent,
max_iter_count: max_iter_count,
colour_range: colour_range,
palette_data: palette_data,
- iter_count_buffer: iter_count_buffer.as_ptr(),
- square_dist_buffer: square_dist_buffer.as_ptr(),
-
- image: image.mut_data().as_mut_ptr(),
+ image: NonZeroUsize::new(image.data().as_ptr() as usize).unwrap(),
};
}
#[must_use]
- pub fn input_buffers(&self) -> (&[u32], &[f32]) {
- let iter_count = unsafe { from_raw_parts(self.iter_count_buffer, self.canvas_size) };
- let dist = unsafe { from_raw_parts(self.square_dist_buffer, self.canvas_size) };
+ pub fn index(&self, element: &(u8, u8, u8)) -> usize {
+ let element_addr = addr_of!(*element) as usize;
- return (iter_count, dist);
- }
-
- #[must_use]
- pub unsafe fn image<'a>(&'a self) -> &'a mut [(u8, u8, u8)] {
- return from_raw_parts_mut(self.image, self.canvas_size);
+ let index = (element_addr - self.image.get()) / size_of::<(u8, u8, u8)>();
+ return index;
}
#[must_use]
diff --git a/source/benoit/benoit/configuration.rs b/source/benoit/benoit/configuration.rs
index 2975430..104ba41 100644
--- a/source/benoit/benoit/configuration.rs
+++ b/source/benoit/benoit/configuration.rs
@@ -21,23 +21,21 @@
If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::benoit::{PRECISION};
use crate::benoit::fractal::{Fractal, FractalKind};
use crate::benoit::image::ImageFormat;
use crate::benoit::palette::Palette;
-use crate::benoit::renderer::Renderer;
extern crate rug;
use rug::Float;
+pub mod default;
pub mod load;
pub struct Configuration {
pub thread_count: u32,
- pub fractal: Fractal,
- pub renderer: Renderer,
+ pub fractal: Fractal,
pub canvas_width: u32,
pub canvas_height: u32,
@@ -62,43 +60,14 @@ pub struct Configuration {
}
impl Configuration {
- pub const DEFAULT_CENTRE_REAL: f64 = 0.0;
- pub const DEFAULT_CENTRE_IMAG: f64 = 0.0;
- pub const DEFAULT_EXTRA_REAL: f64 = 0.0;
- pub const DEFAULT_EXTRA_IMAG: f64 = 0.0;
- pub const DEFAULT_ZOOM: f64 = 1.0;
+ pub const DEFAULT_FRACTAL: Fractal = Fractal::new(FractalKind::Mandelbrot, false, false);
- pub const DEFAULT_MAX_ITER_COUNT: u32 = 0x100;
- pub const DEFAULT_COLOUR_RANGE: f32 = 64.0;
-
- #[must_use]
- pub fn default() -> Configuration {
- return Configuration {
- thread_count: 0x0,
-
- fractal: Fractal::new(FractalKind::Multibrot3, false),
- renderer: Renderer::Normal,
-
- canvas_width: 0x100,
- canvas_height: 0xC0,
- scale: 0x2,
- frame_start: 0x10,
- frame_stop: 0x10,
+ pub const DEFAULT_CENTRE: (f64, f64) = (0.0, 0.0);
+ pub const DEFAULT_EXTRA: (f64, f64) = (0.0, 0.0);
+ pub const DEFAULT_ZOOM: f64 = 1.0;
- centre_real: Float::with_val(PRECISION, Self::DEFAULT_CENTRE_REAL),
- centre_imag: Float::with_val(PRECISION, Self::DEFAULT_CENTRE_IMAG),
- zoom: Float::with_val(PRECISION, Self::DEFAULT_ZOOM),
-
- extra_real: Float::with_val(PRECISION, Self::DEFAULT_EXTRA_REAL),
- extra_imag: Float::with_val(PRECISION, Self::DEFAULT_EXTRA_IMAG),
-
- max_iter_count: Self::DEFAULT_MAX_ITER_COUNT,
-
- palette: Palette::Fire,
- colour_range: Self::DEFAULT_COLOUR_RANGE,
+ pub const DEFAULT_MAX_ITER_COUNT: u32 = 0x100;
- dump_path: "./render".to_string(),
- image_format: ImageFormat::Png,
- };
- }
+ pub const DEFAULT_PALETTE: Palette = Palette::Fire;
+ pub const DEFAULT_COLOUR_RANGE: f32 = 64.0;
}
diff --git a/source/benoit/benoit/configuration/default.rs b/source/benoit/benoit/configuration/default.rs
new file mode 100644
index 0000000..24d28b1
--- /dev/null
+++ b/source/benoit/benoit/configuration/default.rs
@@ -0,0 +1,62 @@
+/*
+ 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::configuration::Configuration;
+use crate::benoit::image::ImageFormat;
+
+extern crate rug;
+
+use rug::Float;
+
+impl Configuration {
+ #[must_use]
+ pub fn default() -> Configuration {
+ return Configuration {
+ thread_count: 0x0, // Automatic if null.
+
+ fractal: Self::DEFAULT_FRACTAL,
+
+ canvas_width: 0x100,
+ canvas_height: 0xC0,
+ scale: 0x2,
+ frame_start: 0x0,
+ frame_stop: 0x0,
+
+ centre_real: Float::with_val(PRECISION, Self::DEFAULT_CENTRE.0),
+ centre_imag: Float::with_val(PRECISION, Self::DEFAULT_CENTRE.1),
+ zoom: Float::with_val(PRECISION, Self::DEFAULT_ZOOM),
+
+ extra_real: Float::with_val(PRECISION, Self::DEFAULT_EXTRA.0),
+ extra_imag: Float::with_val(PRECISION, Self::DEFAULT_EXTRA.1),
+
+ max_iter_count: Self::DEFAULT_MAX_ITER_COUNT,
+
+ palette: Self::DEFAULT_PALETTE,
+ colour_range: Self::DEFAULT_COLOUR_RANGE,
+
+ dump_path: "./render".to_string(),
+ image_format: ImageFormat::Png,
+ };
+ }
+}
diff --git a/source/benoit/benoit/configuration/load.rs b/source/benoit/benoit/configuration/load.rs
index 6229e58..c03e299 100644
--- a/source/benoit/benoit/configuration/load.rs
+++ b/source/benoit/benoit/configuration/load.rs
@@ -26,7 +26,6 @@ use crate::benoit::configuration::Configuration;
use crate::benoit::fractal::FractalKind;
use crate::benoit::image::ImageFormat;
use crate::benoit::palette::Palette;
-use crate::benoit::renderer::Renderer;
extern crate rug;
extern crate toml;
@@ -52,14 +51,6 @@ impl Configuration {
get_integer(&mut configuration.thread_count, &configuration_table, "thread_count");
- if let Some(name) = get_string(&configuration_table, "renderer") {
- configuration.renderer = match name.as_str() {
- "julia" => Renderer::Julia,
- "normal" => Renderer::Normal,
- name => panic!("invalid renderer method \"{name}\""),
- };
- }
-
if let Some(name) = get_string(&configuration_table, "fractal") {
configuration.fractal.set_kind(match name.as_str() {
"burningship" => FractalKind::BurningShip,
diff --git a/source/benoit/benoit/fractal.rs b/source/benoit/benoit/fractal.rs
index 1496450..7630571 100644
--- a/source/benoit/benoit/fractal.rs
+++ b/source/benoit/benoit/fractal.rs
@@ -31,31 +31,51 @@ mod iterate;
pub struct Fractal {
kind: FractalKind,
inverse: bool,
+ julia: bool,
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum FractalKind {
- BurningShip,
+ // Sorted according to exponent.
Mandelbrot,
+ BurningShip,
+ Tricorn,
Multibrot3,
Multibrot4,
- Tricorn,
}
pub type IteratorFunction = fn(&mut Complex, &Complex);
impl Fractal {
#[must_use]
- pub const fn new(kind: FractalKind, inverse: bool) -> Self {
+ pub const fn new(kind: FractalKind, inverse: bool, julia: bool) -> Self {
let fractal = Fractal {
kind: kind,
inverse: inverse,
+ julia: julia,
};
return fractal;
}
+ pub fn name(&self) -> String {
+ let kind = self.kind.name();
+
+ let extra = if self.inverse && !self.julia {
+ "inverse"
+ } else if !self.inverse && self.julia {
+ "julia"
+ } else if self.inverse && self.julia {
+ "inverse julia"
+ } else {
+ "normal"
+ };
+
+ let name = format!("{kind} ({extra})");
+ return name;
+ }
+
#[must_use]
pub fn kind(&self) -> FractalKind {
return self.kind;
@@ -67,6 +87,11 @@ impl Fractal {
}
#[must_use]
+ pub fn julia(&self) -> bool {
+ return self.julia;
+ }
+
+ #[must_use]
pub fn exponent(&self) -> f32 {
return match self.kind {
FractalKind::BurningShip => 2.0,
@@ -96,34 +121,40 @@ impl Fractal {
self.inverse = inverse;
}
+ pub fn set_julia(&mut self, julia: bool) {
+ self.julia = julia;
+ }
+
pub fn cycle(&mut self, direction: i8) {
// Not important.
debug_assert!(direction != 0x0);
let raw = self.kind as i8 + direction;
- let raw: u8 = if raw < 0x0 {
+
+ let new: FractalKind = if raw < 0x0 {
FractalKind::MAX
} else if raw > FractalKind::MAX as i8 {
- 0x0
+ FractalKind::MIN
} else {
- raw as u8
+ unsafe { transmute(raw) }
};
- let new: FractalKind = unsafe { transmute(raw) };
+ let new: FractalKind = unsafe { transmute(new) };
self.kind = new;
}
}
impl FractalKind {
- const MAX: u8 = FractalKind::Tricorn as u8;
+ const MIN: FractalKind = FractalKind::Mandelbrot;
+ const MAX: FractalKind = FractalKind::Multibrot4;
pub fn name(self) -> &'static str {
return match self {
FractalKind::BurningShip => "burning ship",
FractalKind::Mandelbrot => "mandelbrot set",
- FractalKind::Multibrot3 => "multibrot (d=3) set",
- FractalKind::Multibrot4 => "multibrot (d=4) set",
+ FractalKind::Multibrot3 => "multibrot3 set",
+ FractalKind::Multibrot4 => "multibrot4 set",
FractalKind::Tricorn => "tricorn",
};
}
diff --git a/source/benoit/benoit/image.rs b/source/benoit/benoit/image.rs
index a140a01..dffacb0 100644
--- a/source/benoit/benoit/image.rs
+++ b/source/benoit/benoit/image.rs
@@ -48,8 +48,8 @@ impl Image {
}
#[must_use]
- pub fn mut_data<'a>(&'a mut self) -> &'a mut [(u8, u8, u8)] {
- return &mut self.data[..];
+ pub fn data<'a>(&'a self) -> &'a [(u8, u8, u8)] {
+ return &self.data[..];
}
#[must_use]
diff --git a/source/benoit/benoit/image/colour.rs b/source/benoit/benoit/image/colour.rs
index 18085dd..3eefd09 100644
--- a/source/benoit/benoit/image/colour.rs
+++ b/source/benoit/benoit/image/colour.rs
@@ -36,40 +36,27 @@ impl Image {
let (fractal, max_iter_count) = render.info().expect("cannot colour before render");
- let (iter_count_buffer, square_dist_buffer) = render.data();
-
let data = ColourData::new(
self,
- self.width,
- self.height,
fractal.exponent(),
max_iter_count.min(new_max_iter_count),
colour_range,
palette.data(),
- &iter_count_buffer,
- &square_dist_buffer,
);
- let canvas_size = self.height as usize * self.width as usize;
-
- (0x0..canvas_size).into_par_iter().for_each(|index| {
- colour_point(&data, index as usize);
+ self.data.par_iter_mut().for_each(|point| {
+ let index = data.index(point);
+ let (iter_count, dist) = render[index];
+ *point = colour_point(&data, iter_count, dist);
});
}
}
-fn colour_point(data: &ColourData, index: usize) {
- let (iter_count_buffer, square_dist_buffer) = data.input_buffers();
-
- let image = unsafe { data.image() };
-
+fn colour_point(data: &ColourData, iter_count: u32, dist: f32) -> (u8, u8, u8) {
let (exponent, max_iter_count, colour_range, palette_data) = data.consts();
- let iter_count = iter_count_buffer[ index];
- let distance = square_dist_buffer[index].sqrt();
-
let (red, green, blue) = if iter_count < max_iter_count {
- let factor = (iter_count as f32 + 1.0 - distance.ln().log(exponent)) / colour_range;
+ let factor = (iter_count as f32 + 1.0 - dist.ln().log(exponent)) / colour_range;
let index = (factor * PALETTE_DATA_LENGTH as f32).round() as usize % PALETTE_DATA_LENGTH;
palette_data[index]
@@ -81,5 +68,5 @@ fn colour_point(data: &ColourData, index: usize) {
let green = (green * 255.0).round() as u8;
let blue = (blue * 255.0).round() as u8;
- image[index] = (red, green, blue);
+ return (red, green, blue);
}
diff --git a/source/benoit/benoit/palette.rs b/source/benoit/benoit/palette.rs
index b697af7..c5157f6 100644
--- a/source/benoit/benoit/palette.rs
+++ b/source/benoit/benoit/palette.rs
@@ -21,29 +21,34 @@
If not, see <https://www.gnu.org/licenses/>.
*/
-extern crate ctor;
extern crate enum_iterator;
-use ctor::ctor;
-use enum_iterator::{all, Sequence};
+use enum_iterator::Sequence;
use std::mem::transmute;
+mod data;
mod paint;
+pub use data::fill_palettes;
+
+pub const PALETTE_DATA_LENGTH: usize = 0x1000;
+pub type PaletteData = [(f32, f32, f32); PALETTE_DATA_LENGTH];
+
#[derive(Clone, Copy, Sequence)]
#[repr(u8)]
pub enum Palette {
+ // Sorted according to date of addition.
Ancient,
Fire,
Greyscale,
+ Sapphire,
Hsv,
Lch,
- Sapphire,
}
impl Palette {
const MIN: Self = Palette::Ancient;
- const MAX: Self = Palette::Sapphire;
+ const MAX: Self = Palette::Lch;
#[must_use]
pub fn name(self) -> &'static str {
@@ -59,7 +64,8 @@ impl Palette {
#[must_use]
pub fn data(self) -> &'static PaletteData {
- return &*self.mut_data();
+ // This is safe as we return it as immutable.
+ return unsafe { &*self.mut_data() };
}
#[must_use]
@@ -88,50 +94,4 @@ impl Palette {
Palette::Sapphire => paint::sapphire,
};
}
-
- #[must_use]
- fn mut_data(self) -> &'static mut PaletteData {
- return unsafe { match self {
- Palette::Ancient => &mut DATA_ANCIENT,
- Palette::Fire => &mut DATA_FIRE,
- Palette::Greyscale => &mut DATA_GREYSCALE,
- Palette::Hsv => &mut DATA_HSV,
- Palette::Lch => &mut DATA_LCH,
- Palette::Sapphire => &mut DATA_SAPPHIRE,
- } };
- }
-}
-
-// We would like to precalculate the palettes at
-// compile-time, but Rust does not support
-// floating-point arithmetic there.
-
-pub const PALETTE_DATA_LENGTH: usize = 0x1000;
-pub type PaletteData = [(f32, f32, f32); PALETTE_DATA_LENGTH];
-
-const fn default_palette_data() -> PaletteData {
- return [(0.0, 0.0, 0.0); PALETTE_DATA_LENGTH];
-}
-
-static mut DATA_ANCIENT: PaletteData = default_palette_data();
-static mut DATA_FIRE: PaletteData = default_palette_data();
-static mut DATA_GREYSCALE: PaletteData = default_palette_data();
-static mut DATA_HSV: PaletteData = default_palette_data();
-static mut DATA_LCH: PaletteData = default_palette_data();
-static mut DATA_SAPPHIRE: PaletteData = default_palette_data();
-
-#[ctor]
-fn calculate_palettes() {
- for palette in all::<Palette>() {
- let data = palette.mut_data();
- let function = palette.function();
-
- for index in 0x0..PALETTE_DATA_LENGTH {
- let factor = index as f32 / PALETTE_DATA_LENGTH as f32;
-
- let (red, green, blue) = function(factor);
-
- data[index as usize] = (red, green, blue);
- }
- }
}
diff --git a/source/benoit/benoit/palette/data.rs b/source/benoit/benoit/palette/data.rs
new file mode 100644
index 0000000..28bfba4
--- /dev/null
+++ b/source/benoit/benoit/palette/data.rs
@@ -0,0 +1,77 @@
+/*
+ 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::palette::{Palette, PALETTE_DATA_LENGTH, PaletteData};
+
+use enum_iterator::all;
+
+impl Palette {
+ #[must_use]
+ pub(super) unsafe fn mut_data(self) -> &'static mut PaletteData {
+ return unsafe { match self {
+ Palette::Ancient => &mut DATA_ANCIENT,
+ Palette::Fire => &mut DATA_FIRE,
+ Palette::Greyscale => &mut DATA_GREYSCALE,
+ Palette::Hsv => &mut DATA_HSV,
+ Palette::Lch => &mut DATA_LCH,
+ Palette::Sapphire => &mut DATA_SAPPHIRE,
+ } };
+ }
+}
+
+const fn default_palette_data() -> PaletteData {
+ return [(0.0, 0.0, 0.0); PALETTE_DATA_LENGTH];
+}
+
+static mut DATA_ANCIENT: PaletteData = default_palette_data();
+static mut DATA_FIRE: PaletteData = default_palette_data();
+static mut DATA_GREYSCALE: PaletteData = default_palette_data();
+static mut DATA_HSV: PaletteData = default_palette_data();
+static mut DATA_LCH: PaletteData = default_palette_data();
+static mut DATA_SAPPHIRE: PaletteData = default_palette_data();
+
+pub unsafe fn fill_palettes() {
+ use std::time::Instant;
+
+ // We would like to precalculate the palettes at
+ // compile-time, but Rust does not allow
+ // const floating-point arithmetic.
+
+ eprint!("filling palettes...");
+ let time = Instant::now();
+
+ for palette in all::<Palette>() {
+ let data = palette.mut_data();
+ let function = palette.function();
+
+ for index in 0x0..PALETTE_DATA_LENGTH {
+ let factor = index as f32 / PALETTE_DATA_LENGTH as f32;
+
+ let (red, green, blue) = function(factor);
+
+ data[index as usize] = (red, green, blue);
+ }
+ }
+
+ eprintln!(" {:.3}ms", time.elapsed().as_micros() as f32 / 1000.0);
+}
diff --git a/source/benoit/benoit/render.rs b/source/benoit/benoit/render.rs
index 6e2b6ef..0141f52 100644
--- a/source/benoit/benoit/render.rs
+++ b/source/benoit/benoit/render.rs
@@ -26,14 +26,15 @@ use crate::benoit::fractal::Fractal;
pub mod allocate;
pub mod render;
+use std::ops::{Index, IndexMut};
+
pub struct Render {
canvas_width: u32,
canvas_height: u32,
info: Option<(Fractal, u32)>,
- iter_count_buffer: Vec::<u32>,
- square_dist_buffer: Vec::<f32>,
+ data: Vec::<(u32, f32)>,
}
impl Render {
@@ -46,9 +47,18 @@ impl Render {
pub fn info(&self) -> Option<(Fractal, u32)> {
return self.info.clone();
}
+}
- #[must_use]
- pub fn data<'a>(&'a self) -> (&'a Vec::<u32>, &'a Vec::<f32>) {
- return (&self.iter_count_buffer, &self.square_dist_buffer);
+impl Index<usize> for Render {
+ type Output = (u32, f32);
+
+ fn index<'a>(&'a self, index: usize) -> &'a Self::Output {
+ return &self.data[index];
+ }
+}
+
+impl IndexMut<usize> for Render {
+ fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut Self::Output {
+ return &mut self.data[index];
}
}
diff --git a/source/benoit/benoit/render/allocate.rs b/source/benoit/benoit/render/allocate.rs
index e76f540..4228914 100644
--- a/source/benoit/benoit/render/allocate.rs
+++ b/source/benoit/benoit/render/allocate.rs
@@ -32,8 +32,7 @@ impl Render {
canvas_size as usize
};
- let iter_count_buffer: Vec::<u32> = vec![0x0; canvas_size];
- let square_dist_buffer: Vec::<f32> = vec![0.0; canvas_size];
+ let data: Vec<(u32, f32)> = vec![(0x0, 0.0); canvas_size];
return Render {
canvas_width: canvas_width,
@@ -41,8 +40,7 @@ impl Render {
info: None,
- iter_count_buffer: iter_count_buffer,
- square_dist_buffer: square_dist_buffer,
+ data: data,
};
}
}
diff --git a/source/benoit/benoit/render/render.rs b/source/benoit/benoit/render/render.rs
index 731f347..7ce1a3e 100644
--- a/source/benoit/benoit/render/render.rs
+++ b/source/benoit/benoit/render/render.rs
@@ -21,33 +21,32 @@
If not, see <https://www.gnu.org/licenses/>.
*/
+use crate::benoit::{BAILOUT_DISTANCE, PRECISION};
use crate::benoit::complex::Complex;
use crate::benoit::fractal::{Fractal, IteratorFunction};
use crate::benoit::render::Render;
use crate::benoit::render_data::RenderData;
-use crate::benoit::renderer::{PointRenderer, Renderer};
extern crate rayon;
extern crate rug;
use rayon::prelude::*;
-use rug::Float;
+use rug::{Assign, Float};
+use rug::float::Special;
impl Render {
pub fn render(
&mut self,
- fractal: Fractal,
- renderer: Renderer,
- centre: &Complex,
- zoom: &Float,
- extra: &Complex,
- max_iter_count: u32,
+ fractal: Fractal,
+ centre: &Complex,
+ zoom: &Float,
+ extra: &Complex,
+ max_iter_count: u32,
) {
assert!(max_iter_count > 0x0);
let data = RenderData::new(
- &mut self.iter_count_buffer[..],
- &mut self.square_dist_buffer[..],
+ &mut self.data[..],
self.canvas_width,
self.canvas_height,
centre.clone(),
@@ -55,31 +54,68 @@ impl Render {
zoom.clone(),
max_iter_count,
fractal.inverse(),
+ fractal.julia(),
);
- let canvas_size = self.canvas_height as usize * self.canvas_width as usize;
+ let iterator = fractal.iterator();
- let point_renderer = renderer.point_renderer();
- let iterator = fractal.iterator();
-
- (0x0..canvas_size).into_par_iter().for_each(|index| {
- render_point(&data, index as usize, point_renderer, iterator);
+ self.data.par_iter_mut().for_each(|point| {
+ let (x, y) = data.coordinate(point);
+ *point = render_point(&data, x, y, iterator);
});
self.info = Some((fractal, max_iter_count));
}
}
-fn render_point(data: &RenderData, index: usize, point_renderer: PointRenderer, iterator: IteratorFunction) {
- let (iter_count_buffer, square_dist_buffer) = unsafe { data.output_buffers() };
+fn render_point(data: &RenderData, x: u32, y: u32, iterator: IteratorFunction) -> (u32, f32) {
+ let (centre, 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 mut z = {
+ let mut a = Float::with_val(PRECISION, x_temporary / zoom);
+ a += &centre.real;
+
+ let mut b = Float::with_val(PRECISION, y_temporary / zoom);
+ b -= &centre.imag;
+
+ Complex {real: a, imag: b}
+ };
- let (canvas_width, _) = data.canvas_size();
+ z = data.factor_inverse(z);
+ let (mut z, c) = data.setup_julia(z);
- let x = (index % canvas_width as usize) as u32;
- let y = (index / canvas_width as usize) as u32;
+ let mut z_prev = Complex {
+ real: Float::with_val(PRECISION, Special::Nan),
+ imag: Float::with_val(PRECISION, Special::Nan),
+ };
- let (iter_count, square_dist) = point_renderer(&data, x, y, iterator);
+ let mut iter_count: u32 = 0x1;
+ let mut square_dist = Float::with_val(PRECISION, Special::Nan);
+ while {
+ square_dist.assign(&z.real * &z.real + &z.imag * &z.imag);
+ // 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 = z.real == z_prev.real && z.imag == z_prev.imag;
+ if periodic { iter_count = max_iter_count }
+
+ square_dist <= BAILOUT_DISTANCE && iter_count < max_iter_count
+ } {
+ z_prev.assign(&z);
+
+ iterator(&mut z, &c);
+
+ z = data.perturbate(z);
+
+ iter_count += 0x1;
+ }
- iter_count_buffer[ index as usize] = iter_count;
- square_dist_buffer[index as usize] = square_dist;
+ return (iter_count, square_dist.to_f32());
}
diff --git a/source/benoit/benoit/render_data.rs b/source/benoit/benoit/render_data.rs
index 0dda5d9..4f6eaa9 100644
--- a/source/benoit/benoit/render_data.rs
+++ b/source/benoit/benoit/render_data.rs
@@ -27,13 +27,12 @@ use crate::benoit::complex::Complex;
extern crate rug;
use rug::Float;
-use std::slice::from_raw_parts_mut;
+use std::mem::size_of;
+use std::num::NonZeroUsize;
+use std::ptr::addr_of;
pub struct RenderData {
- canvas_width: u32,
- canvas_height: u32,
-
- canvas_size: usize,
+ canvas_width: u32,
centre: Complex,
extra: Complex,
@@ -42,6 +41,7 @@ pub struct RenderData {
max_iter_count: u32,
inverse: bool,
+ julia: bool,
x_offset: f32,
y_offset: f32,
@@ -49,15 +49,13 @@ pub struct RenderData {
x_factor: f32,
y_factor: f32,
- iter_count_buffer: *mut u32,
- square_dist_buffer: *mut f32,
+ buffer: NonZeroUsize,
}
impl RenderData {
#[must_use]
pub fn new(
- iter_count_buffer: &mut [u32],
- square_dist_buffer: &mut [f32],
+ buffer: &[(u32, f32)],
canvas_width: u32,
canvas_height: u32,
centre: Complex,
@@ -65,14 +63,12 @@ impl RenderData {
zoom: Float,
max_iter_count: u32,
inverse: bool,
+ julia: 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,
+ canvas_width: canvas_width,
centre: centre,
extra: extra,
@@ -81,6 +77,7 @@ impl RenderData {
max_iter_count: max_iter_count,
inverse: inverse,
+ julia: julia,
x_offset: canvas_width as f32 / -2.0,
y_offset: canvas_height as f32 / -2.0,
@@ -88,49 +85,63 @@ impl RenderData {
x_factor: 4.0 / canvas_width as f32 * width_ratio,
y_factor: 4.0 / canvas_height as f32 * height_ratio,
- iter_count_buffer: iter_count_buffer.as_mut_ptr(),
- square_dist_buffer: square_dist_buffer.as_mut_ptr(),
+ buffer: NonZeroUsize::new(buffer.as_ptr() as usize).unwrap(),
};
}
#[must_use]
- pub fn canvas_size(&self) -> (u32, u32) {
- return (self.canvas_width, self.canvas_height);
+ pub fn input(&self) -> (&Complex, &Float, u32) {
+ return (&self.centre, &self.zoom, self.max_iter_count);
}
#[must_use]
- pub fn input(&self) -> (&Complex, &Complex, &Float, u32) {
- return (&self.centre, &self.extra, &self.zoom, self.max_iter_count);
+ pub fn consts(&self) -> (f32, f32, f32, f32) {
+ return (self.x_offset, self.y_offset, self.x_factor, self.y_factor);
}
#[must_use]
- pub unsafe fn output_buffers<'a>(&'a self) -> (&'a mut [u32], &'a mut [f32]) {
- // All reads and writes to these buffer are unsafe
- // AND UB if the same indices are used from
- // multiple threads.
+ pub fn coordinate(&self, element: &(u32, f32)) -> (u32, u32) {
+ let element_addr = addr_of!(*element) as usize;
- let iter_count = from_raw_parts_mut(self.iter_count_buffer, self.canvas_size as usize);
- let square_dist = from_raw_parts_mut(self.square_dist_buffer, self.canvas_size as usize);
+ let index = (element_addr - self.buffer.get()) / size_of::<(u32, f32)>();
- return (iter_count, square_dist);
+ let x = (index % self.canvas_width as usize) as u32;
+ let y = (index / self.canvas_width as usize) as u32;
+ return (x, y);
}
#[must_use]
- pub fn consts(&self) -> (f32, f32, f32, f32) {
- return (self.x_offset, self.y_offset, self.x_factor, self.y_factor);
+ pub fn factor_inverse(&self, mut z: Complex) -> Complex {
+ if self.inverse {
+ let mut factor_inverse = Float::with_val(PRECISION, &z.real * &z.real);
+ factor_inverse += &z.imag * &z.imag;
+ factor_inverse.recip_mut();
+
+ z.real *= &factor_inverse;
+ z.imag *= factor_inverse;
+ }
+
+ return z;
}
#[must_use]
- pub fn inverse_factor(&self, val: &Complex) -> Float {
- return if self.inverse {
- let mut inverse_factor = Float::with_val(PRECISION, &val.real * &val.real);
- inverse_factor += &val.imag * &val.imag;
- inverse_factor.recip_mut();
-
- inverse_factor
- } else {
- Float::with_val(PRECISION, 0x1)
+ pub fn setup_julia(&self, z: Complex) -> (Complex, Complex) {
+ let c = match self.julia {
+ false => z.clone(),
+ true => self.extra.clone(),
};
+
+ return (z, c);
+ }
+
+ #[must_use]
+ pub fn perturbate(&self, mut z: Complex) -> Complex {
+ if !self.julia {
+ z.real += &self.extra.real;
+ z.imag += &self.extra.imag;
+ }
+
+ return z;
}
}
diff --git a/source/benoit/benoit/renderer.rs b/source/benoit/benoit/renderer.rs
deleted file mode 100644
index 0c02509..0000000
--- a/source/benoit/benoit/renderer.rs
+++ /dev/null
@@ -1,55 +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::fractal::IteratorFunction;
-use crate::benoit::render_data::RenderData;
-
-use std::mem::transmute;
-
-mod render_point;
-
-#[derive(Clone, Copy)]
-#[repr(u8)]
-pub enum Renderer {
- Julia,
- Normal,
-}
-
-pub type PointRenderer = fn(&RenderData, u32, u32, IteratorFunction) -> (u32, f32);
-
-impl Renderer {
- #[must_use]
- pub fn point_renderer(self) -> PointRenderer {
- return match self {
- Renderer::Julia => render_point::julia,
- Renderer::Normal => render_point::normal,
- };
- }
-
- pub fn toggle(&mut self) {
- let raw = !(*self as u8) & 0b00000001;
- let new: Self = unsafe { transmute(raw) };
-
- *self = new;
- }
-}
diff --git a/source/benoit/benoit/renderer/render_point/julia.rs b/source/benoit/benoit/renderer/render_point/julia.rs
deleted file mode 100644
index 06a478c..0000000
--- a/source/benoit/benoit/renderer/render_point/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::{BAILOUT, PRECISION};
-use crate::benoit::complex::Complex;
-use crate::benoit::fractal::IteratorFunction;
-use crate::benoit::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, extra, 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 c = extra;
-
- let mut z = {
- let mut a = Float::with_val(PRECISION, x_temporary / zoom);
- a += &centre.real;
-
- let mut b = Float::with_val(PRECISION, y_temporary / zoom);
- b -= &centre.imag;
-
- Complex {real: a, imag: b}
- };
-
- let inverse_factor = data.inverse_factor(&z);
-
- z.real *= &inverse_factor;
- z.imag *= &inverse_factor;
-
- let mut z_prev = Complex {
- real: Float::with_val(PRECISION, Special::Nan),
- imag: 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(&z.real * &z.real + &z.imag * &z.imag);
-
- let periodic = z.real == z_prev.real && z.imag == z_prev.imag;
- if periodic { iter_count = max_iter_count }
-
- square_dist <= BAILOUT && iter_count < max_iter_count
- } {
- z_prev.assign(&z);
-
- iterator(&mut z, c);
-
- iter_count += 0x1;
- }
-
- return (iter_count, square_dist.to_f32());
-}
diff --git a/source/benoit/benoit/renderer/render_point/normal.rs b/source/benoit/benoit/renderer/render_point/normal.rs
deleted file mode 100644
index e9f848f..0000000
--- a/source/benoit/benoit/renderer/render_point/normal.rs
+++ /dev/null
@@ -1,89 +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::{BAILOUT, PRECISION};
-use crate::benoit::complex::Complex;
-use crate::benoit::fractal::IteratorFunction;
-use crate::benoit::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, extra, 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 mut z = {
- let mut a = Float::with_val(PRECISION, x_temporary / zoom);
- a += &centre.real;
-
- let mut b = Float::with_val(PRECISION, y_temporary / zoom);
- b -= &centre.imag;
-
- Complex {real: a, imag: b}
- };
-
- let inverse_factor = data.inverse_factor(&z);
-
- z.real *= &inverse_factor;
- z.imag *= &inverse_factor;
-
- let c = z.clone();
-
- let mut z_prev = Complex {
- real: Float::with_val(PRECISION, Special::Nan),
- imag: 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(&z.real * &z.real + &z.imag * &z.imag);
- // 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 = z.real == z_prev.real && z.imag == z_prev.imag;
- if periodic { iter_count = max_iter_count }
-
- square_dist <= BAILOUT && iter_count < max_iter_count
- } {
- z_prev.assign(&z);
-
- iterator(&mut z, &c);
-
- z.real += &extra.real;
- z.imag -= &extra.imag;
-
- iter_count += 0x1;
- }
-
- return (iter_count, square_dist.to_f32());
-}
diff --git a/source/benoit/benoit/script.rs b/source/benoit/benoit/script.rs
index 4337944..6403bef 100644
--- a/source/benoit/benoit/script.rs
+++ b/source/benoit/benoit/script.rs
@@ -25,7 +25,6 @@ use crate::benoit::complex::Complex;
use crate::benoit::fractal::Fractal;
use crate::benoit::image::ImageFormat;
use crate::benoit::palette::Palette;
-use crate::benoit::renderer::Renderer;
extern crate rug;
@@ -40,7 +39,6 @@ pub mod still;
pub struct Script {
// Configuration:
fractal: Fractal,
- renderer: Renderer,
canvas_width: u32,
canvas_height: u32,
diff --git a/source/benoit/benoit/script/animate.rs b/source/benoit/benoit/script/animate.rs
index 65bbe90..48fea58 100644
--- a/source/benoit/benoit/script/animate.rs
+++ b/source/benoit/benoit/script/animate.rs
@@ -65,7 +65,6 @@ impl Script {
frame_name.as_str(),
&mut image,
&mut render,
- self.renderer,
self.fractal,
self.palette,
&self.centre,
diff --git a/source/benoit/benoit/script/configure.rs b/source/benoit/benoit/script/configure.rs
index acb6071..9966199 100644
--- a/source/benoit/benoit/script/configure.rs
+++ b/source/benoit/benoit/script/configure.rs
@@ -29,8 +29,7 @@ impl Script {
#[must_use]
pub fn configure(configuration: Configuration) -> Script {
return Script {
- fractal: configuration.fractal,
- renderer: configuration.renderer,
+ fractal: configuration.fractal,
canvas_width: configuration.canvas_width,
canvas_height: configuration.canvas_height,
diff --git a/source/benoit/benoit/script/dump.rs b/source/benoit/benoit/script/dump.rs
index d77b597..d8c23f2 100644
--- a/source/benoit/benoit/script/dump.rs
+++ b/source/benoit/benoit/script/dump.rs
@@ -26,7 +26,6 @@ use crate::benoit::fractal::Fractal;
use crate::benoit::image::{Image, ImageFormat};
use crate::benoit::palette::Palette;
use crate::benoit::render::Render;
-use crate::benoit::renderer::Renderer;
use crate::benoit::script::Script;
extern crate rug;
@@ -40,7 +39,6 @@ impl Script {
name: &str,
image: &mut Image,
render: &mut Render,
- renderer: Renderer,
fractal: Fractal,
palette: Palette,
centre: &Complex,
@@ -56,7 +54,6 @@ impl Script {
render.render(
fractal,
- renderer,
centre,
zoom,
extra,
diff --git a/source/benoit/benoit/script/still.rs b/source/benoit/benoit/script/still.rs
index 73ebcf8..b93dc11 100644
--- a/source/benoit/benoit/script/still.rs
+++ b/source/benoit/benoit/script/still.rs
@@ -38,7 +38,6 @@ impl Script {
FRAME_NAME,
&mut image,
&mut render,
- self.renderer,
self.fractal,
self.palette,
&self.centre,
diff --git a/source/benoit/benoit/video/initialise.rs b/source/benoit/benoit/video/initialise.rs
index 76668bd..64a0608 100644
--- a/source/benoit/benoit/video/initialise.rs
+++ b/source/benoit/benoit/video/initialise.rs
@@ -35,7 +35,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[0x0], VERSION[0x1], VERSION[0x2]);
+ let window_title = format!("BENO\u{CE}T {:X}.{:X}.{:X}", VERSION.0, VERSION.1, VERSION.2);
let mut window_builder = sdl_video.window(window_title.as_str(), canvas_width * scale, canvas_height * scale);
window_builder.position_centered();
diff --git a/source/benoit/main.rs b/source/benoit/main.rs
index 9e8e572..4263ff4 100644
--- a/source/benoit/main.rs
+++ b/source/benoit/main.rs
@@ -26,6 +26,7 @@ mod benoit;
use crate::benoit::VERSION;
use crate::benoit::app::App;
use crate::benoit::configuration::Configuration;
+use crate::benoit::palette::fill_palettes;
use crate::benoit::script::Script;
extern crate rayon;
@@ -37,12 +38,14 @@ use std::thread::available_parallelism;
fn main() {
println!();
- println!("\u{1B}[1mBENO\u{CE}T\u{1B}[0m {:X}.{:X}.{:X}", VERSION[0x0], VERSION[0x1], VERSION[0x2]);
+ println!("\u{1B}[1mBENO\u{CE}T\u{1B}[0m {:X}.{:X}.{:X}", VERSION.0, VERSION.1, VERSION.2);
println!("Copyright 2021, 2023 Gabriel Bj\u{F8}rnager Jensen.");
println!();
println!("Le p\u{E8}re cogita et c'est pourquoi il fut.");
println!();
+ unsafe { fill_palettes() };
+
let mut arguments = args();
let (mut configuration, interative) = match arguments.nth(0x1) {
@@ -63,12 +66,12 @@ fn main() {
ThreadPoolBuilder::new().num_threads(configuration.thread_count as usize).build_global().unwrap();
let code = if interative {
- eprintln!("running iteractive mode");
+ eprintln!("running in iteractive mode");
let app = App::configure(configuration);
app.run()
} else {
- eprintln!("running script mode");
+ eprintln!("running in script mode");
let script = Script::configure(configuration);
script.run()