summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/benoit/benoit.rs33
-rw-r--r--source/benoit/benoit/app.rs (renamed from source/benoit/benoit/application.rs)15
-rw-r--r--source/benoit/benoit/app/animate.rs120
-rw-r--r--source/benoit/benoit/app/colour.rs40
-rw-r--r--source/benoit/benoit/app/colour_row.rs (renamed from source/benoit/benoit/application/colour.rs)80
-rw-r--r--source/benoit/benoit/app/drop.rs (renamed from source/benoit/benoit/render_data/send.rs)9
-rw-r--r--source/benoit/benoit/app/dump.rs (renamed from source/benoit/benoit/application/dump.rs)4
-rw-r--r--source/benoit/benoit/app/get_iterator_function.rs (renamed from source/benoit/benoit/application/get_iterator_function.rs)4
-rw-r--r--source/benoit/benoit/app/get_row_renderer.rs (renamed from source/benoit/benoit/application/get_row_renderer.rs)10
-rw-r--r--source/benoit/benoit/app/handle_keys.rs (renamed from source/benoit/benoit/application/handle_keys.rs)66
-rw-r--r--source/benoit/benoit/app/initialise.rs (renamed from source/benoit/benoit/application/initialise.rs)16
-rw-r--r--source/benoit/benoit/app/loop.rs126
-rw-r--r--source/benoit/benoit/app/poll_events.rs (renamed from source/benoit/benoit/application/poll_events.rs)4
-rw-r--r--source/benoit/benoit/app/render.rs (renamed from source/benoit/benoit/application/render.rs)17
-rw-r--r--source/benoit/benoit/app/render_row_julia.rs (renamed from source/benoit/benoit/application/render_row_julia.rs)19
-rw-r--r--source/benoit/benoit/app/render_row_normal.rs (renamed from source/benoit/benoit/application/render_row_normal.rs)21
-rw-r--r--source/benoit/benoit/app/run.rs (renamed from source/benoit/benoit/application/run.rs)8
-rw-r--r--source/benoit/benoit/application/animate.rs90
-rw-r--r--source/benoit/benoit/application/loop.rs96
-rw-r--r--source/benoit/benoit/configuration.rs2
-rw-r--r--source/benoit/benoit/configuration/default.rs2
-rw-r--r--source/benoit/benoit/configuration/load.rs28
-rw-r--r--source/benoit/benoit/iteration/iterate_burning_ship.rs2
-rw-r--r--source/benoit/benoit/iteration/iterate_mandelbrot.rs4
-rw-r--r--source/benoit/benoit/iteration/iterate_tricorn.rs4
-rw-r--r--source/benoit/benoit/task.rs (renamed from source/benoit/benoit/render_data/sync.rs)5
-rw-r--r--source/benoit/benoit/task/colour_data.rs40
-rw-r--r--source/benoit/benoit/task/colour_data/new.rs40
-rw-r--r--source/benoit/benoit/task/colour_data/slice.rs41
-rw-r--r--source/benoit/benoit/task/render_data.rs (renamed from source/benoit/benoit/render_data.rs)5
-rw-r--r--source/benoit/benoit/task/render_data/new.rs (renamed from source/benoit/benoit/render_data/new.rs)9
-rw-r--r--source/benoit/benoit/task/render_data/slice.rs (renamed from source/benoit/benoit/render_data/slice.rs)7
-rw-r--r--source/benoit/benoit/video.rs9
-rw-r--r--source/benoit/benoit/video/draw.rs (renamed from source/benoit/benoit/application/draw.rs)58
-rw-r--r--source/benoit/benoit/video/initialise.rs7
-rw-r--r--source/benoit/benoit/video/sync.rs46
-rw-r--r--source/benoit/main.rs8
37 files changed, 712 insertions, 383 deletions
diff --git a/source/benoit/benoit.rs b/source/benoit/benoit.rs
index 2812e52..e4a7a8f 100644
--- a/source/benoit/benoit.rs
+++ b/source/benoit/benoit.rs
@@ -12,8 +12,8 @@
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
+ even the implied warranty of MERCHANTABIL ITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See theGNU
Affero General Public License for more details.
You should have received a copy of the GNU
@@ -21,13 +21,36 @@
If not, see <https://www.gnu.org/licenses/>.
*/
-pub mod application;
+extern crate rug;
+
+use rug::Float;
+
+pub mod app;
pub mod configuration;
pub mod fractal;
pub mod iteration;
-pub mod render_data;
+pub mod task;
pub mod video;
-pub const VERSION: u32 = 0x23;
+pub struct Version<T> {
+ major: T,
+ minor: T,
+ patch: T,
+}
+
+pub const VERSION: Version::<u32> = Version::<u32> {
+ major: 0x1,
+ minor: 0x0,
+ patch: 0x0,
+};
pub const PRECISION: u32 = 0x80;
+
+pub struct FeedbackInfo<'a> {
+ prev_centre_real: &'a Float,
+ prev_centre_imag: &'a Float,
+ prev_zoom: &'a Float,
+ next_centre_real: &'a Float,
+ next_centre_imag: &'a Float,
+ next_zoom: &'a Float,
+}
diff --git a/source/benoit/benoit/application.rs b/source/benoit/benoit/app.rs
index b05ede2..f7ebb47 100644
--- a/source/benoit/benoit/application.rs
+++ b/source/benoit/benoit/app.rs
@@ -23,7 +23,7 @@
use crate::benoit::fractal::Fractal;
use crate::benoit::iteration::IteratorFunction;
-use crate::benoit::render_data::RenderData;
+use crate::benoit::task::render_data::RenderData;
use crate::benoit::video::Video;
extern crate rug;
@@ -33,7 +33,8 @@ use std::sync::Arc;
pub mod animate;
pub mod colour;
-pub mod draw;
+pub mod colour_row;
+pub mod drop;
pub mod dump;
pub mod get_iterator_function;
pub mod get_row_renderer;
@@ -48,13 +49,7 @@ pub mod run;
pub type RowRenderer = fn(Arc<RenderData>, u32, IteratorFunction);
-pub struct PreviousPosition {
- centre_real: Float,
- centre_imag: Float,
- zoom: Float,
-}
-
-pub struct Application {
+pub struct App {
thread_count: u32,
fractal: Fractal,
@@ -69,6 +64,8 @@ pub struct Application {
zoom: Float,
max_iter_count: u32,
+ colour_range: f32,
+
dump_path: String,
video: Option<Video>,
diff --git a/source/benoit/benoit/app/animate.rs b/source/benoit/benoit/app/animate.rs
new file mode 100644
index 0000000..f732e61
--- /dev/null
+++ b/source/benoit/benoit/app/animate.rs
@@ -0,0 +1,120 @@
+/*
+ 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::app::App;
+
+extern crate rug;
+extern crate sdl2;
+
+use rug::Float;
+use rug::ops::PowAssign;
+use std::time::Instant;
+
+impl App {
+ pub fn animate(&self) -> i32 {
+ let canvas_size = self.canvas_width as usize * self.canvas_width as usize;
+
+ let mut iter_count_buffer: Vec::<u32> = vec![0x0; canvas_size];
+ let mut square_dist_buffer: Vec::<f32> = vec![0.0; canvas_size];
+
+ let mut image: Vec::<u8> = vec![0x0; canvas_size * 0x3];
+
+ if self.frame_count == 0x1 {
+ // If only a single frame is to be rendered, we
+ // aren't going to animate it.
+
+ eprint!("rendering at {}{:+}i ({}x)...", self.centre_real.to_f32(), self.centre_imag.to_f32(), self.zoom.to_f32());
+
+ let time_start = Instant::now();
+
+ self.render(&mut iter_count_buffer[..], &mut square_dist_buffer[..], &self.centre_real, &self.centre_imag, &self.zoom, self.max_iter_count);
+ let render_time = time_start.elapsed();
+
+ self.colour(&mut image[..], self.max_iter_count, &mut iter_count_buffer[..], &mut square_dist_buffer[..]);
+ let colour_time = time_start.elapsed() - render_time;
+
+ self.dump(format!("{}/render.webp", self.dump_path), &image, self.canvas_width);
+
+ eprintln!(" rend. {:.3}ms, col. {:.3}ms", render_time.as_micros() as f32 / 1000.0, colour_time.as_micros() as f32 / 1000.0);
+
+ return 0x0;
+ }
+
+ // zoom_start:
+ let mut zoom = Float::with_val(PRECISION, 1.0 / 4.0);
+
+ let zoom_stop = Float::with_val(PRECISION, &self.zoom);
+
+ let zoom_factor = {
+ // To get the zoom factor, we first want the 'a'
+ // value of the growth function from (0) to
+ // (frame_count) on the x-dimension and from
+ // (zoom_start) to (zoom_stop) on the y-dimension:
+ //
+ // a = nroot(x1-x0,y1/y0),
+ //
+ // but this may be simplified for use with Rug
+ // because
+ //
+ // nroot(a,b) = b^(1/a),
+ //
+ // making the final equation
+ //
+ // (y1/y0)^(1/(x1-x0)) = (zoom_stop/zoom_start)^(1/(frame_count-1)).
+ //
+ // N.b. that we subtract one from frame_count as we
+ // want the final render to have exactly the
+ // specified zoom.
+
+ let exponent = Float::with_val(PRECISION, 1.0 / (self.frame_count as f32 - 1.0));
+
+ let mut factor = Float::with_val(PRECISION, &zoom_stop / &zoom);
+ factor.pow_assign(exponent);
+
+ factor
+ };
+
+ eprintln!("animating {} frames at {}{:+}i to {:.3} (fac. {:.3})", self.frame_count, self.centre_real.to_f64(), self.centre_imag.to_f64(), zoom_stop.to_f64(), zoom_factor.to_f64());
+
+ for frame in 0x0..self.frame_count {
+ eprint!("{frame:010} ({:.3}x)...", zoom.to_f32());
+
+ let time_start = Instant::now();
+
+ self.render(&mut iter_count_buffer[..], &mut square_dist_buffer[..], &self.centre_real, &self.centre_imag, &zoom, self.max_iter_count);
+ let render_time = time_start.elapsed();
+
+ self.colour(&mut image[..], self.max_iter_count, &mut iter_count_buffer[..], &mut square_dist_buffer[..]);
+ let colour_time = time_start.elapsed() - render_time;
+
+ self.dump(format!("{}/frame{frame:010}.webp", self.dump_path), &image, self.canvas_width);
+
+ eprintln!(" rend. {:.3}ms, col. {:.3}ms", render_time.as_micros() as f32 / 1000.0, colour_time.as_micros() as f32 / 1000.0);
+
+ zoom *= &zoom_factor;
+ }
+
+ return 0x0;
+ }
+}
diff --git a/source/benoit/benoit/app/colour.rs b/source/benoit/benoit/app/colour.rs
new file mode 100644
index 0000000..3325b55
--- /dev/null
+++ b/source/benoit/benoit/app/colour.rs
@@ -0,0 +1,40 @@
+/*
+ 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::task::colour_data::ColourData;
+
+extern crate rayon;
+
+use rayon::prelude::*;
+use std::sync::Arc;
+
+impl App {
+ pub fn colour(&self, buffer: &mut [u8], max_iter_count: u32, iter_count_buffer: &[u32], square_dist_buffer: &[f32]) {
+ let data = Arc::new(ColourData::new(buffer, self.canvas_width, max_iter_count, self.colour_range, iter_count_buffer, square_dist_buffer));
+
+ (0x0..self.canvas_width).into_par_iter().for_each(|row| {
+ App::colour_row(data.clone(), row as u32);
+ });
+ }
+}
diff --git a/source/benoit/benoit/application/colour.rs b/source/benoit/benoit/app/colour_row.rs
index a4587c6..81896cc 100644
--- a/source/benoit/benoit/application/colour.rs
+++ b/source/benoit/benoit/app/colour_row.rs
@@ -21,7 +21,42 @@
If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::benoit::application::Application;
+use crate::benoit::app::App;
+use crate::benoit::task::colour_data::ColourData;
+
+use std::hint::unreachable_unchecked;
+use std::sync::Arc;
+
+impl App {
+ pub fn colour_row(data: Arc<ColourData>, y: u32) {
+ let (iter_count_buffer, square_dist_buffer, image) = unsafe { data.slice(y) };
+
+ for x in 0x0..data.canvas_width {
+ let x = x as usize;
+
+ let iter_count = iter_count_buffer[ x];
+ let distance = square_dist_buffer[x].sqrt();
+
+ let factor = (iter_count as f32 + 1.0 - distance.log2().log2()) / data.colour_range % 1.0;
+
+ let (red, green, blue) = if iter_count != data.max_iter_count {
+ hsv_to_rgb(factor, 7.0 / 8.0, 7.0 / 8.0)
+ } else {
+ (0.0, 0.0, 0.0)
+ };
+
+ let red = (red * 255.0).round() as u8;
+ let green = (green * 255.0).round() as u8;
+ let blue = (blue * 255.0).round() as u8;
+
+ unsafe {
+ *image.get_unchecked_mut(x * 0x3) = red;
+ *image.get_unchecked_mut(x * 0x3 + 0x1) = green;
+ *image.get_unchecked_mut(x * 0x3 + 0x2) = blue;
+ }
+ }
+ }
+}
fn hsv_to_rgb(hue: f32, saturation: f32, value: f32) -> (f32, f32, f32) {
return if saturation <= 0.0 {
@@ -39,42 +74,13 @@ fn hsv_to_rgb(hue: f32, saturation: f32, value: f32) -> (f32, f32, f32) {
let t = v * (1.0 - s * (1.0 - f));
match h.trunc() as u8 {
- 0x0 => (v, t, p),
- 0x1 => (q, v, p),
- 0x2 => (p, v, t),
- 0x3 => (p, q, v),
- 0x4 => (t, p, v),
- 0x5 => (v, p, q),
- value => unreachable!(),
+ 0x0 => (v, t, p),
+ 0x1 => (q, v, p),
+ 0x2 => (p, v, t),
+ 0x3 => (p, q, v),
+ 0x4 => (t, p, v),
+ 0x5 => (v, p, q),
+ _ => unsafe { unreachable_unchecked() },
}
};
}
-
-impl Application {
- pub fn colour(&self, buffer: &mut [u8], iter_count_buffer: &[u32], square_dist_buffer: &[f32]) {
- let canvas_size = self.canvas_width * self.canvas_width;
-
- for pixel in 0x0..canvas_size {
- let iter_count = iter_count_buffer[pixel as usize];
-
- let distance = square_dist_buffer[pixel as usize].sqrt();
-
- let factor_range = 16.0_f32.min(self.max_iter_count as f32);
- let factor = (iter_count as f32 + 1.0 - distance.log2().log2()) / factor_range % 1.0;
-
- let (red, green, blue) = if iter_count != self.max_iter_count {
- hsv_to_rgb(factor, 7.0 / 8.0, 7.0 / 8.0)
- } else {
- (0.0, 0.0, 0.0)
- };
-
- let red = (red * 255.0).round() as u8;
- let green = (green * 255.0).round() as u8;
- let blue = (blue * 255.0).round() as u8;
-
- buffer[pixel as usize * 0x3] = red;
- buffer[pixel as usize * 0x3 + 0x1] = green;
- buffer[pixel as usize * 0x3 + 0x2] = blue;
- }
- }
-}
diff --git a/source/benoit/benoit/render_data/send.rs b/source/benoit/benoit/app/drop.rs
index b351cdd..dfa6de1 100644
--- a/source/benoit/benoit/render_data/send.rs
+++ b/source/benoit/benoit/app/drop.rs
@@ -21,6 +21,11 @@
If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::benoit::render_data::RenderData;
+use crate::benoit::app::App;
-unsafe impl Send for RenderData {}
+impl Drop for App {
+ fn drop(&mut self) {
+ eprintln!();
+ eprintln!("Goodbye!");
+ }
+}
diff --git a/source/benoit/benoit/application/dump.rs b/source/benoit/benoit/app/dump.rs
index 4a19a52..6001e31 100644
--- a/source/benoit/benoit/application/dump.rs
+++ b/source/benoit/benoit/app/dump.rs
@@ -21,14 +21,14 @@
If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::benoit::application::Application;
+use crate::benoit::app::App;
extern crate webp;
use std::fs::write;
use webp::Encoder;
-impl Application {
+impl App {
pub fn dump(&self, path: String, image: &[u8], canvas_width: u32) {
let encoder = Encoder::from_rgb(&image[..], canvas_width, canvas_width);
diff --git a/source/benoit/benoit/application/get_iterator_function.rs b/source/benoit/benoit/app/get_iterator_function.rs
index 1ca2cb7..1454785 100644
--- a/source/benoit/benoit/application/get_iterator_function.rs
+++ b/source/benoit/benoit/app/get_iterator_function.rs
@@ -22,10 +22,10 @@
*/
use crate::benoit::fractal::Fractal;
-use crate::benoit::application::Application;
+use crate::benoit::app::App;
use crate::benoit::iteration::*;
-impl Application {
+impl App {
pub fn get_iterator_function(fractal: Fractal) -> IteratorFunction {
return match fractal {
Fractal::BurningShip => iterate_burning_ship,
diff --git a/source/benoit/benoit/application/get_row_renderer.rs b/source/benoit/benoit/app/get_row_renderer.rs
index d8c349a..050d14f 100644
--- a/source/benoit/benoit/application/get_row_renderer.rs
+++ b/source/benoit/benoit/app/get_row_renderer.rs
@@ -21,14 +21,14 @@
If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::benoit::application::Application;
-use crate::benoit::application::RowRenderer;
+use crate::benoit::app::App;
+use crate::benoit::app::RowRenderer;
-impl Application {
+impl App {
pub fn get_row_renderer(julia: bool) -> RowRenderer {
return match julia {
- false => Application::render_row_normal,
- true => Application::render_row_julia,
+ false => App::render_row_normal,
+ true => App::render_row_julia,
};
}
}
diff --git a/source/benoit/benoit/application/handle_keys.rs b/source/benoit/benoit/app/handle_keys.rs
index 1991c36..2b2cff5 100644
--- a/source/benoit/benoit/application/handle_keys.rs
+++ b/source/benoit/benoit/app/handle_keys.rs
@@ -22,7 +22,7 @@
*/
use crate::benoit::PRECISION;
-use crate::benoit::application::{Application, RowRenderer};
+use crate::benoit::app::{App, RowRenderer};
use crate::benoit::fractal::Fractal;
use crate::benoit::iteration::IteratorFunction;
@@ -32,34 +32,7 @@ extern crate sdl2;
use rug::Float;
use sdl2::keyboard::Scancode;
-fn cycle_fractal(fractal: Fractal) -> (Fractal, IteratorFunction) {
- let fractal = match fractal {
- Fractal::BurningShip => Fractal::Mandelbrot,
- Fractal::Mandelbrot => Fractal::Tricorn,
- Fractal::Tricorn => Fractal::BurningShip,
- };
-
- let iterator_function = Application::get_iterator_function(fractal);
-
- eprintln!("rendering the {}", fractal.get_name());
-
- return (fractal, iterator_function);
-}
-
-fn toggle_julia(julia: bool) -> (bool, RowRenderer) {
- let julia = !julia;
-
- let row_renderer = Application::get_row_renderer(julia);
-
- match julia {
- false => eprintln!("disabled the julia set"),
- true => eprintln!("enabled the julia set"),
- };
-
- return (julia, row_renderer);
-}
-
-impl Application {
+impl App {
pub fn handle_keys(&mut self, scan_code: Scancode) -> bool {
match scan_code {
Scancode::LAlt => (self.fractal, self.iterator_function) = cycle_fractal(self.fractal),
@@ -103,6 +76,41 @@ impl Application {
_ => self.max_iter_count,
};
+ const COLOUR_RANGE_FACTOR: f32 = 1.0 + 1.0 / 16.0;
+
+ self.colour_range = match scan_code {
+ Scancode::Up => self.colour_range * COLOUR_RANGE_FACTOR,
+ Scancode::Down => self.colour_range / COLOUR_RANGE_FACTOR,
+ _ => self.colour_range,
+ };
+
return false;
}
}
+
+fn cycle_fractal(fractal: Fractal) -> (Fractal, IteratorFunction) {
+ let fractal = match fractal {
+ Fractal::BurningShip => Fractal::Mandelbrot,
+ Fractal::Mandelbrot => Fractal::Tricorn,
+ Fractal::Tricorn => Fractal::BurningShip,
+ };
+
+ let iterator_function = App::get_iterator_function(fractal);
+
+ eprintln!("rendering the {}", fractal.get_name());
+
+ return (fractal, iterator_function);
+}
+
+fn toggle_julia(julia: bool) -> (bool, RowRenderer) {
+ let julia = !julia;
+
+ let row_renderer = App::get_row_renderer(julia);
+
+ match julia {
+ false => eprintln!("disabled the julia set"),
+ true => eprintln!("enabled the julia set"),
+ };
+
+ return (julia, row_renderer);
+}
diff --git a/source/benoit/benoit/application/initialise.rs b/source/benoit/benoit/app/initialise.rs
index f019f02..15d98ac 100644
--- a/source/benoit/benoit/application/initialise.rs
+++ b/source/benoit/benoit/app/initialise.rs
@@ -21,7 +21,7 @@
If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::benoit::application::Application;
+use crate::benoit::app::App;
use crate::benoit::configuration::Configuration;
use crate::benoit::video::Video;
@@ -31,8 +31,8 @@ use rayon::ThreadPoolBuilder;
use std::env::args;
use std::thread::available_parallelism;
-impl Application {
- pub fn initialise() -> Application {
+impl App {
+ pub fn initialise() -> App {
let mut arguments = args();
let configuration = match arguments.nth(0x1) {
@@ -58,7 +58,9 @@ impl Application {
ThreadPoolBuilder::new().num_threads(configuration.thread_count as usize).build_global().unwrap();
- return Application {
+ eprintln!("rendering the {}", configuration.fractal.get_name());
+
+ return App {
thread_count: thread_count,
fractal: configuration.fractal,
@@ -73,6 +75,8 @@ impl Application {
zoom: configuration.zoom,
max_iter_count: configuration.max_iter_count,
+ colour_range: configuration.colour_range,
+
dump_path: configuration.dump_path,
video: video,
@@ -81,8 +85,8 @@ impl Application {
do_render: true,
do_dump: false,
- row_renderer: Application::get_row_renderer( configuration.julia),
- iterator_function: Application::get_iterator_function(configuration.fractal),
+ row_renderer: App::get_row_renderer( configuration.julia),
+ iterator_function: App::get_iterator_function(configuration.fractal),
};
}
}
diff --git a/source/benoit/benoit/app/loop.rs b/source/benoit/benoit/app/loop.rs
new file mode 100644
index 0000000..b40b509
--- /dev/null
+++ b/source/benoit/benoit/app/loop.rs
@@ -0,0 +1,126 @@
+/*
+ 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::FeedbackInfo;
+use crate::benoit::app::App;
+
+extern crate rug;
+
+use rug::Assign;
+use std::time::Instant;
+
+impl App {
+ pub fn r#loop(&mut self) -> i32 {
+ assert_eq!(self.video.is_some(), true);
+
+ eprintln!();
+ eprintln!("Controls:");
+ eprintln!("- W Translate up");
+ eprintln!("- A Translate left");
+ eprintln!("- S Translate down");
+ eprintln!("- D Translate right");
+ eprintln!();
+ eprintln!("- Q Zoom out");
+ eprintln!("- E Zoom in");
+ eprintln!();
+ eprintln!("- R Decrease max. iteration count");
+ eprintln!("- F Increase max. iteration count");
+ eprintln!();
+ eprintln!("- Tab Toggle Julia");
+ eprintln!("- Alt Cycle between fractals");
+ eprintln!();
+ eprintln!("- Up Increase colour range");
+ eprintln!("- Down Decrease colour range");
+ eprintln!();
+ eprintln!("- Z Print centre value (c)");
+ eprintln!("- X Dump frame");
+ eprintln!("- C Render frame");
+ eprintln!();
+
+ let mut event_pump = unsafe { self.video.as_mut().unwrap_unchecked().sdl.event_pump().expect("unable to get event pump") };
+
+ let canvas_size = self.canvas_width as usize * self.canvas_width as usize;
+
+ let mut iter_count_buffer: Vec::<u32> = vec![0x0; canvas_size];
+ let mut square_dist_buffer: Vec::<f32> = vec![0.0; canvas_size];
+
+ let mut image: Vec::<u8> = vec![0x0; canvas_size * 0x3];
+
+ let mut prev_centre_real = self.centre_real.clone();
+ let mut prev_centre_imag = self.centre_imag.clone();
+ let mut prev_zoom = self.zoom.clone();
+ let mut prev_max_iter_count = self.max_iter_count;
+
+ loop {
+ let frame_start = Instant::now();
+
+ if self.poll_events(&mut event_pump) { break }
+
+ if self.do_render {
+ eprint!("rendering...");
+
+ let time_start = Instant::now();
+
+ self.render(&mut iter_count_buffer[..], &mut square_dist_buffer[..], &self.centre_real, &self.centre_imag, &self.zoom, self.max_iter_count);
+ let render_time = time_start.elapsed();
+
+ eprintln!(" rend. {:.3}ms", render_time.as_micros() as f32 / 1000.0);
+
+ prev_centre_real.assign(&self.centre_real);
+ prev_centre_imag.assign(&self.centre_imag);
+ prev_zoom.assign(&self.zoom);
+ prev_max_iter_count = self.max_iter_count;
+
+ self.do_render = false;
+ }
+
+ self.colour(&mut image[..], prev_max_iter_count, &mut iter_count_buffer[..], &mut square_dist_buffer[..]);
+
+ {
+ let feedback_info = FeedbackInfo {
+ prev_centre_real: &prev_centre_real,
+ prev_centre_imag: &prev_centre_imag,
+ prev_zoom: &prev_zoom,
+ next_centre_real: &self.centre_real,
+ next_centre_imag: &self.centre_imag,
+ next_zoom: &self.zoom,
+ };
+
+ unsafe { self.video.as_mut().unwrap_unchecked().draw(&image[..], self.canvas_width, self.scale, Some(&feedback_info)) };
+ }
+
+ if self.do_dump {
+ let path = format!("{}/image.webp", self.dump_path);
+
+ eprintln!("dumping image at \"{path}\"");
+ self.dump(path, &image, self.canvas_width);
+
+ self.do_dump = false;
+ }
+
+ unsafe { self.video.as_ref().unwrap_unchecked().sync(&frame_start) };
+ }
+
+ return 0x0;
+ }
+} \ No newline at end of file
diff --git a/source/benoit/benoit/application/poll_events.rs b/source/benoit/benoit/app/poll_events.rs
index ed26b05..2df0c96 100644
--- a/source/benoit/benoit/application/poll_events.rs
+++ b/source/benoit/benoit/app/poll_events.rs
@@ -21,14 +21,14 @@
If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::benoit::application::Application;
+use crate::benoit::app::App;
extern crate sdl2;
use sdl2::EventPump;
use sdl2::event::Event;
-impl Application {
+impl App {
pub fn poll_events(&mut self, event_pump: &mut EventPump) -> bool {
for event in event_pump.poll_iter() {
let quit = match event {
diff --git a/source/benoit/benoit/application/render.rs b/source/benoit/benoit/app/render.rs
index eae4438..aa5ff9b 100644
--- a/source/benoit/benoit/application/render.rs
+++ b/source/benoit/benoit/app/render.rs
@@ -21,8 +21,8 @@
If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::benoit::application::Application;
-use crate::benoit::render_data::RenderData;
+use crate::benoit::app::App;
+use crate::benoit::task::render_data::RenderData;
extern crate rayon;
extern crate rug;
@@ -30,25 +30,16 @@ extern crate rug;
use rayon::prelude::*;
use rug::Float;
use std::sync::Arc;
-use std::time::Instant;
-impl Application {
+impl App {
pub fn render(&self, iter_count_buffer: &mut [u32], square_dist_buffer: &mut [f32], centre_real: &Float, centre_imag: &Float, zoom: &Float, max_iter_count: u32) {
- eprint!("rendering...");
-
- let time_start = Instant::now();
-
let row_renderer = self.row_renderer;
let iterator = self.iterator_function;
let data = Arc::new(RenderData::new(iter_count_buffer, square_dist_buffer, self.canvas_width, centre_real.clone(), centre_imag.clone(), zoom.clone(), max_iter_count));
(0x0..self.canvas_width).into_par_iter().for_each(|row| {
- row_renderer(data.clone(), row, iterator);
+ row_renderer(data.clone(), row as u32, iterator);
});
-
- let duration = time_start.elapsed();
-
- eprintln!(" done ({}ms)", duration.as_millis());
}
}
diff --git a/source/benoit/benoit/application/render_row_julia.rs b/source/benoit/benoit/app/render_row_julia.rs
index 3f4bb0c..5c3cae8 100644
--- a/source/benoit/benoit/application/render_row_julia.rs
+++ b/source/benoit/benoit/app/render_row_julia.rs
@@ -22,17 +22,18 @@
*/
use crate::benoit::PRECISION;
-use crate::benoit::application::Application;
+use crate::benoit::app::App;
use crate::benoit::iteration::IteratorFunction;
-use crate::benoit::render_data::RenderData;
+use crate::benoit::task::render_data::RenderData;
extern crate rug;
use rug::{Assign, Float};
use rug::float::Special;
+use rug::ops::NegAssign;
use std::sync::Arc;
-impl Application {
+impl App {
pub fn render_row_julia(data: Arc<RenderData>, y: u32, iterator: IteratorFunction) {
let (iter_count_buffer, square_dist_buffer) = unsafe { data.slice(y) };
@@ -53,9 +54,9 @@ impl Application {
// 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);
+ let mut za = Float::with_val(PRECISION, &canvas_width / 2.0);
+ za.neg_assign();
+ za += &x_float;
za *= 4.0;
za /= &canvas_width;
@@ -63,9 +64,9 @@ impl Application {
};
let mut zb = {
- let tmp0 = Float::with_val(PRECISION, &canvas_width / 2.0);
-
- let mut zb = Float::with_val(PRECISION, &y_float - &tmp0);
+ let mut zb = Float::with_val(PRECISION, &canvas_width / 2.0);
+ zb.neg_assign();
+ zb += &y_float;
zb *= 4.0;
zb /= &canvas_width;
diff --git a/source/benoit/benoit/application/render_row_normal.rs b/source/benoit/benoit/app/render_row_normal.rs
index 157c767..381b8bc 100644
--- a/source/benoit/benoit/application/render_row_normal.rs
+++ b/source/benoit/benoit/app/render_row_normal.rs
@@ -22,17 +22,18 @@
*/
use crate::benoit::PRECISION;
-use crate::benoit::application::Application;
+use crate::benoit::app::App;
use crate::benoit::iteration::IteratorFunction;
-use crate::benoit::render_data::RenderData;
+use crate::benoit::task::render_data::RenderData;
extern crate rug;
use rug::{Assign, Float};
use rug::float::Special;
+use rug::ops::NegAssign;
use std::sync::Arc;
-impl Application {
+impl App {
pub fn render_row_normal(data: Arc<RenderData>, y: u32, iterator: IteratorFunction) {
let (iter_count_buffer, square_dist_buffer) = unsafe { data.slice(y) };
@@ -43,9 +44,9 @@ impl Application {
let y_float = Float::with_val(PRECISION, y);
let ca = {
- let tmp0 = Float::with_val(PRECISION, &canvas_width / 2.0);
-
- let mut ca = Float::with_val(PRECISION, &x_float - &tmp0);
+ let mut ca = Float::with_val(PRECISION, &canvas_width / 2.0);
+ ca.neg_assign();
+ ca += &x_float;
ca *= 4.0;
ca /= &canvas_width;
ca /= &data.zoom;
@@ -55,9 +56,9 @@ impl Application {
};
let cb = {
- let tmp0 = Float::with_val(PRECISION, &canvas_width / 2.0);
-
- let mut cb = Float::with_val(PRECISION, &y_float - &tmp0);
+ let mut cb = Float::with_val(PRECISION, &canvas_width / 2.0);
+ cb.neg_assign();
+ cb += &y_float;
cb *= 4.0;
cb /= &canvas_width;
cb /= &data.zoom;
@@ -72,7 +73,7 @@ impl Application {
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 = 0x0;
+ let mut iter_count: u32 = 0x1;
let mut square_dist;
while {
square_dist = Float::with_val(PRECISION, &za * &za + &zb * &zb).to_f32();
diff --git a/source/benoit/benoit/application/run.rs b/source/benoit/benoit/app/run.rs
index b9aa50b..3524cad 100644
--- a/source/benoit/benoit/application/run.rs
+++ b/source/benoit/benoit/app/run.rs
@@ -22,19 +22,17 @@
*/
use crate::benoit::VERSION;
-use crate::benoit::application::Application;
+use crate::benoit::app::App;
extern crate sdl2;
-impl Application {
+impl App {
pub fn run(&mut self) -> i32 {
println!();
- println!("Benoit {VERSION:X}");
+ println!("Benoit {:X}.{:X}.{:X}", VERSION.major, VERSION.minor, VERSION.patch);
println!("Copyright 2021, 2023 Gabriel Bjørnager Jensen.");
println!();
- eprintln!("rendering the {}", self.fractal.get_name());
-
return match self.interactive {
true => self.r#loop(),
false => self.animate(),
diff --git a/source/benoit/benoit/application/animate.rs b/source/benoit/benoit/application/animate.rs
deleted file mode 100644
index 117f430..0000000
--- a/source/benoit/benoit/application/animate.rs
+++ /dev/null
@@ -1,90 +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::application::Application;
-
-extern crate rug;
-extern crate sdl2;
-
-use rug::Float;
-use rug::ops::PowAssign;
-use std::ops::MulAssign;
-
-impl Application {
- pub fn animate(&self) -> i32 {
- // zoom_start:
- let mut zoom = Float::with_val(PRECISION, 1.0 / 4.0);
-
- let zoom_stop = Float::with_val(PRECISION, &self.zoom);
-
- let zoom_factor = {
- // To get the zoom factor, we first want the 'a'
- // value of the growth function from (0) and to
- // (frame_count) on the x-dimension and from (1) to
- // (zoom) on the y-dimension:
- //
- // a = nroot(x1-x0,y1/y0)
- //
- // but this may be simplified for use with Rug
- // because
- //
- // nroot(a,b) = b^(1/a)
- //
- // making the final equation
- //
- // (x1-x0)^(1/(y1*y0)) = (zoom_stop/zoom_start)^(1/frame_count)
-
- let x_difference = Float::with_val(PRECISION, self.frame_count);
-
- let exponent = Float::with_val(PRECISION, 1.0 / &x_difference);
-
- let mut factor = Float::with_val(PRECISION, &zoom_stop);
- factor /= &zoom;
- factor.pow_assign(exponent);
-
- factor
- };
-
- eprintln!("animating {} frames at {}{:+}i to {:.3} (fac.: {:.3})", self.frame_count, self.centre_real.to_f64(), self.centre_imag.to_f64(), zoom_stop.to_f64(), zoom_factor.to_f64());
-
- let canvas_size = self.canvas_width as usize * self.canvas_width as usize;
-
- let mut iter_count_buffer: Vec::<u32> = vec![0x0; canvas_size];
- let mut square_dist_buffer: Vec::<f32> = vec![0.0; canvas_size];
-
- let mut image: Vec::<u8> = vec![0x0; canvas_size * 0x3];
-
- for frame in 0x0..self.frame_count {
- eprint!("{frame:010}: ");
- self.render(&mut iter_count_buffer[..], &mut square_dist_buffer[..], &self.centre_real, &self.centre_imag, &zoom, self.max_iter_count);
- self.colour(&mut image[..], &mut iter_count_buffer[..], &mut square_dist_buffer[..]);
-
- self.dump(format!("{}/frame{frame:010}.webp", self.dump_path), &image, self.canvas_width);
-
- zoom.mul_assign(&zoom_factor);
- }
-
- return 0x0;
- }
-}
diff --git a/source/benoit/benoit/application/loop.rs b/source/benoit/benoit/application/loop.rs
deleted file mode 100644
index 9c5fc55..0000000
--- a/source/benoit/benoit/application/loop.rs
+++ /dev/null
@@ -1,96 +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::application::{Application, PreviousPosition};
-
-extern crate sdl2;
-
-impl Application {
- pub fn r#loop(&mut self) -> i32 {
- eprintln!();
- eprintln!("Controls:");
- eprintln!("- W Translate up");
- eprintln!("- A Translate left");
- eprintln!("- S Translate down");
- eprintln!("- D Translate right");
- eprintln!();
- eprintln!("- Q Zoom out");
- eprintln!("- E Zoom in");
- eprintln!();
- eprintln!("- R Decrease max. iteration count");
- eprintln!("- F Increase max. iteration count");
- eprintln!();
- eprintln!("- Tab Toggle Julia");
- eprintln!("- Alt Cycle between fractals");
- eprintln!();
- eprintln!("- Z Print centre value (c)");
- eprintln!("- X Dump frame");
- eprintln!("- C Render frame");
- eprintln!();
-
- let mut event_pump = self.video.as_mut().unwrap().sdl.event_pump().expect("unable to get event pump");
-
- let canvas_size = self.canvas_width as usize * self.canvas_width as usize;
-
- let mut iter_count_buffer: Vec::<u32> = vec![0x0; canvas_size];
- let mut square_dist_buffer: Vec::<f32> = vec![0.0; canvas_size];
-
- let mut image: Vec::<u8> = vec![0x0; canvas_size * 0x3];
-
- let mut previous_position = PreviousPosition {
- centre_real: self.centre_real.clone(),
- centre_imag: self.centre_imag.clone(),
- zoom: self.zoom.clone(),
- };
-
- loop {
- if self.poll_events(&mut event_pump) { break }
-
- if self.do_render {
- self.render(&mut iter_count_buffer[..], &mut square_dist_buffer[..], &self.centre_real, &self.centre_imag, &self.zoom, self.max_iter_count);
- self.colour(&mut image[..], &iter_count_buffer[..], &square_dist_buffer[..]);
-
- previous_position = PreviousPosition {
- centre_real: self.centre_real.clone(),
- centre_imag: self.centre_imag.clone(),
- zoom: self.zoom.clone(),
- };
-
- self.do_render = false;
- }
-
- self.draw(&image[..], &previous_position);
-
- if self.do_dump {
- let path = format!("{}/image.webp", self.dump_path);
-
- eprintln!("dumping image at \"{path}\"");
- self.dump(path, &image, self.canvas_width);
-
- self.do_dump = false;
- }
- }
-
- return 0x0;
- }
-} \ No newline at end of file
diff --git a/source/benoit/benoit/configuration.rs b/source/benoit/benoit/configuration.rs
index ca36400..f472f62 100644
--- a/source/benoit/benoit/configuration.rs
+++ b/source/benoit/benoit/configuration.rs
@@ -45,6 +45,8 @@ pub struct Configuration {
pub zoom: Float,
pub max_iter_count: u32,
+ pub colour_range: f32,
+
pub dump_path: String,
pub interactive: bool,
diff --git a/source/benoit/benoit/configuration/default.rs b/source/benoit/benoit/configuration/default.rs
index 1d59786..46373cd 100644
--- a/source/benoit/benoit/configuration/default.rs
+++ b/source/benoit/benoit/configuration/default.rs
@@ -46,6 +46,8 @@ impl Configuration {
zoom: Float::with_val(PRECISION, 1.0),
max_iter_count: 0x100,
+ colour_range: 16.0,
+
dump_path: "./render/".to_string(),
interactive: true,
diff --git a/source/benoit/benoit/configuration/load.rs b/source/benoit/benoit/configuration/load.rs
index b06cd71..711c890 100644
--- a/source/benoit/benoit/configuration/load.rs
+++ b/source/benoit/benoit/configuration/load.rs
@@ -43,14 +43,20 @@ impl Configuration {
let configuration_text = match read(path) {
Ok(content) => String::from_utf8_lossy(&content).to_string(),
- Err(..) => {
- eprintln!("unable to read configuration file");
- return configuration;
- },
+ Err(..) => panic!("unable to read configuration file"),
};
let configuration_table = Table::from_str(configuration_text.as_str()).expect("unable to parse configuration");
+ let get_boolean = |buffer: &mut bool, table: &Table, name: &str| {
+ if !table.contains_key(name) { return }
+
+ match &configuration_table[name] {
+ Value::Boolean(value) => *buffer = *value,
+ _ => panic!("mismatched type of {name}"),
+ };
+ };
+
let get_integer = |buffer: &mut u32, table: &Table, name: &str| {
if !table.contains_key(name) { return }
@@ -96,6 +102,8 @@ impl Configuration {
configuration.fractal
};
+ get_boolean(&mut configuration.julia, &configuration_table, "julia");
+
get_integer(&mut configuration.canvas_width, &configuration_table, "canvas_width");
get_integer(&mut configuration.scale, &configuration_table, "scale");
get_integer(&mut configuration.frame_count, &configuration_table, "frame_count");
@@ -105,6 +113,18 @@ impl Configuration {
get_float( &mut configuration.zoom, &configuration_table, "zoom");
get_integer(&mut configuration.max_iter_count, &configuration_table, "maximum_iteration_count");
+ // We allow thread counts of zero as those signal
+ // automatic thread count detection.
+ if configuration.canvas_width == 0x0 {
+ panic!("only non-zero values for canvas_width are allowed");
+ } else if configuration.scale == 0x0 {
+ panic!("only non-zero values for scale are allowed");
+ } else if configuration.frame_count == 0x0 {
+ panic!("only non-zero values for frame_count are allowed");
+ } else if configuration.max_iter_count == 0x0 {
+ panic!("only non-zero values for maximum_iteration_count are allowed");
+ }
+
return configuration;
}
}
diff --git a/source/benoit/benoit/iteration/iterate_burning_ship.rs b/source/benoit/benoit/iteration/iterate_burning_ship.rs
index 89d2ec1..038367f 100644
--- a/source/benoit/benoit/iteration/iterate_burning_ship.rs
+++ b/source/benoit/benoit/iteration/iterate_burning_ship.rs
@@ -30,7 +30,7 @@ pub fn iterate_burning_ship(za: &mut Float, zb: &mut Float, ca: &Float, cb: &Flo
// iteration - the real and imaginary parts of (z)
// are made absolute:
//
- // z(n+1) = (abs(Re(z(n)))+i*abs(Im(z(n))))^2+c
+ // z(n+1) = (abs(Re(z(n)))+i*abs(Im(z(n))))^2+c.
za.abs_mut();
zb.abs_mut();
diff --git a/source/benoit/benoit/iteration/iterate_mandelbrot.rs b/source/benoit/benoit/iteration/iterate_mandelbrot.rs
index 6be612c..9037326 100644
--- a/source/benoit/benoit/iteration/iterate_mandelbrot.rs
+++ b/source/benoit/benoit/iteration/iterate_mandelbrot.rs
@@ -34,14 +34,14 @@ pub fn iterate_mandelbrot(za: &mut Float, zb: &mut Float, ca: &Float, cb: &Float
//
// stays bounded: I.e. the absolute value of (z) stays bounded:
//
- // abs(z) = sqrt(Re(z)^2+Im(z)^2) <= 2^2 = 4
+ // abs(z) = sqrt(Re(z)^2+Im(z)^2) <= 2^2 = 4.
let za_temporary = za.clone();
// We can calculate the square of a complex number
// as:
//
- // (a+bi)^2 = (a+bi)(a+bi) = a^2+abi+abi-b^2 = a^2-b^2+2abi
+ // (a+bi)^2 = (a+bi)(a+bi) = a^2+abi+abi-b^2 = a^2-b^2+2abi.
za.square_mut();
*za -= &*zb * &*zb;
diff --git a/source/benoit/benoit/iteration/iterate_tricorn.rs b/source/benoit/benoit/iteration/iterate_tricorn.rs
index 2edea53..3d1bfb9 100644
--- a/source/benoit/benoit/iteration/iterate_tricorn.rs
+++ b/source/benoit/benoit/iteration/iterate_tricorn.rs
@@ -30,7 +30,7 @@ pub fn iterate_tricorn(za: &mut Float, zb: &mut Float, ca: &Float, cb: &Float) {
// Mandelbrot Set in that the conjugate of (z) is
// used instead of just (z):
//
- // z(n+1) = (Re(z(n))-Im(z(n)))^2+c
+ // z(n+1) = (Re(z(n))-Im(z(n)))^2+c.
let za_temporary = za.clone();
@@ -42,7 +42,7 @@ pub fn iterate_tricorn(za: &mut Float, zb: &mut Float, ca: &Float, cb: &Float) {
// We can negate the value by multiplying with
// (-1). A multiplication can be saved, as
//
- // a*2*(-1) = a*(-2)
+ // a*2*(-1) = a*(-2).
//
// Thus, we may combine these two multiplications.
*zb *= -2.0;
diff --git a/source/benoit/benoit/render_data/sync.rs b/source/benoit/benoit/task.rs
index 454ebb1..ee53b52 100644
--- a/source/benoit/benoit/render_data/sync.rs
+++ b/source/benoit/benoit/task.rs
@@ -21,6 +21,5 @@
If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::benoit::render_data::RenderData;
-
-unsafe impl Sync for RenderData {}
+pub mod colour_data;
+pub mod render_data;
diff --git a/source/benoit/benoit/task/colour_data.rs b/source/benoit/benoit/task/colour_data.rs
new file mode 100644
index 0000000..77d561d
--- /dev/null
+++ b/source/benoit/benoit/task/colour_data.rs
@@ -0,0 +1,40 @@
+/*
+ Copyright 2021, 2023 Gabriel Bjørnager Jensen.
+
+ This file is part of Benoit.
+
+ Benoit is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Benoit is distributed in the hope that it will
+ be useful, but WITHOUT ANY WARRANTY; without
+ even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Benoit.
+ If not, see <https://www.gnu.org/licenses/>.
+*/
+
+pub mod new;
+pub mod slice;
+
+pub struct ColourData {
+ pub canvas_width: u32,
+
+ pub max_iter_count: u32,
+ pub colour_range: f32,
+
+ iter_count_buffer: *const u32,
+ square_dist_buffer: *const f32,
+
+ image: *mut u8,
+}
+
+unsafe impl Send for ColourData {}
+unsafe impl Sync for ColourData {}
diff --git a/source/benoit/benoit/task/colour_data/new.rs b/source/benoit/benoit/task/colour_data/new.rs
new file mode 100644
index 0000000..2707018
--- /dev/null
+++ b/source/benoit/benoit/task/colour_data/new.rs
@@ -0,0 +1,40 @@
+/*
+ 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::task::colour_data::ColourData;
+
+impl ColourData {
+ pub fn new(image: &mut [u8], canvas_width: u32, max_iter_count: u32, colour_range: f32, iter_count_buffer: &[u32], square_dist_buffer: &[f32]) -> ColourData {
+ return ColourData {
+ canvas_width: canvas_width,
+
+ max_iter_count: max_iter_count,
+ colour_range: colour_range,
+
+ iter_count_buffer: iter_count_buffer.as_ptr(),
+ square_dist_buffer: square_dist_buffer.as_ptr(),
+
+ image: image.as_mut_ptr(),
+ };
+ }
+}
diff --git a/source/benoit/benoit/task/colour_data/slice.rs b/source/benoit/benoit/task/colour_data/slice.rs
new file mode 100644
index 0000000..975eda2
--- /dev/null
+++ b/source/benoit/benoit/task/colour_data/slice.rs
@@ -0,0 +1,41 @@
+/*
+ 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::task::colour_data::ColourData;
+
+use std::slice::{from_raw_parts, from_raw_parts_mut};
+
+impl ColourData {
+ pub unsafe fn slice(&self, row: u32) -> (&[u32], &[f32], &mut [u8]) {
+ let offset = row as isize * self.canvas_width as isize;
+
+ let iter_count = from_raw_parts(self.iter_count_buffer.offset(offset), self.canvas_width as usize);
+ let dist = from_raw_parts(self.square_dist_buffer.offset(offset), self.canvas_width as usize);
+
+ let offset = offset * 0x3;
+
+ let image = from_raw_parts_mut(self.image.offset(offset), self.canvas_width as usize * 0x3);
+
+ return (iter_count, dist, image);
+ }
+}
diff --git a/source/benoit/benoit/render_data.rs b/source/benoit/benoit/task/render_data.rs
index 5546e16..e73b514 100644
--- a/source/benoit/benoit/render_data.rs
+++ b/source/benoit/benoit/task/render_data.rs
@@ -26,9 +26,7 @@ extern crate rug;
use rug::Float;
pub mod new;
-pub mod send;
pub mod slice;
-pub mod sync;
pub struct RenderData {
pub canvas_width: u32,
@@ -42,3 +40,6 @@ pub struct RenderData {
iter_count_buffer: *mut u32,
square_dist_buffer: *mut f32,
}
+
+unsafe impl Send for RenderData {}
+unsafe impl Sync for RenderData {}
diff --git a/source/benoit/benoit/render_data/new.rs b/source/benoit/benoit/task/render_data/new.rs
index 4e3f28d..d9509b5 100644
--- a/source/benoit/benoit/render_data/new.rs
+++ b/source/benoit/benoit/task/render_data/new.rs
@@ -21,7 +21,7 @@
If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::benoit::render_data::RenderData;
+use crate::benoit::task::render_data::RenderData;
extern crate rug;
@@ -29,9 +29,6 @@ use rug::Float;
impl RenderData {
pub fn new(iter_count_buffer: &mut [u32], square_dist_buffer: &mut [f32], canvas_width: u32, centre_real: Float, centre_imag: Float, zoom: Float, max_iter_count: u32) -> RenderData {
- let iter_count_buffer_pointer = iter_count_buffer.as_mut_ptr();
- let square_dist_buffer_pointer = square_dist_buffer.as_mut_ptr();
-
return RenderData {
canvas_width: canvas_width,
@@ -41,8 +38,8 @@ impl RenderData {
max_iter_count: max_iter_count,
- iter_count_buffer: iter_count_buffer_pointer,
- square_dist_buffer: square_dist_buffer_pointer,
+ iter_count_buffer: iter_count_buffer.as_mut_ptr(),
+ square_dist_buffer: square_dist_buffer.as_mut_ptr(),
};
}
}
diff --git a/source/benoit/benoit/render_data/slice.rs b/source/benoit/benoit/task/render_data/slice.rs
index ab12d4f..d2660ee 100644
--- a/source/benoit/benoit/render_data/slice.rs
+++ b/source/benoit/benoit/task/render_data/slice.rs
@@ -21,16 +21,17 @@
If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::benoit::render_data::RenderData;
+use crate::benoit::task::render_data::RenderData;
use std::slice::from_raw_parts_mut;
impl RenderData {
pub unsafe fn slice(&self, row: u32) -> (&mut [u32], &mut [f32]) {
let offset = row as isize * self.canvas_width as isize;
+
let iter_count = from_raw_parts_mut(self.iter_count_buffer.offset(offset), self.canvas_width as usize);
- let distance = from_raw_parts_mut(self.square_dist_buffer.offset(offset), self.canvas_width as usize);
+ let dist = from_raw_parts_mut(self.square_dist_buffer.offset(offset), self.canvas_width as usize);
- return (iter_count, distance);
+ return (iter_count, dist);
}
}
diff --git a/source/benoit/benoit/video.rs b/source/benoit/benoit/video.rs
index 2147b27..af060fe 100644
--- a/source/benoit/benoit/video.rs
+++ b/source/benoit/benoit/video.rs
@@ -23,12 +23,15 @@
extern crate sdl2;
-use sdl2::Sdl;
+use sdl2::{Sdl, VideoSubsystem};
use sdl2::render::WindowCanvas;
+pub mod draw;
pub mod initialise;
+pub mod sync;
pub struct Video {
- pub sdl: Sdl,
- pub canvas: WindowCanvas,
+ pub sdl: Sdl,
+ pub sdl_video: VideoSubsystem,
+ pub canvas: WindowCanvas,
}
diff --git a/source/benoit/benoit/application/draw.rs b/source/benoit/benoit/video/draw.rs
index 31ba470..bd5a837 100644
--- a/source/benoit/benoit/application/draw.rs
+++ b/source/benoit/benoit/video/draw.rs
@@ -21,8 +21,8 @@
If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::benoit::PRECISION;
-use crate::benoit::application::{Application, PreviousPosition};
+use crate::benoit::{FeedbackInfo, PRECISION};
+use crate::benoit::video::Video;
extern crate rug;
extern crate sdl2;
@@ -31,13 +31,13 @@ use rug::Float;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
-impl Application {
- pub fn draw(&mut self, image: &[u8], previous_position: &PreviousPosition) {
- let canvas_size = self.canvas_width * self.canvas_width;
+impl Video {
+ pub fn draw(&mut self, image: &[u8], canvas_width: u32, scale: u32, feedback_info: Option<&FeedbackInfo>) {
+ let canvas_size = canvas_width * canvas_width;
for pixel in 0x0..canvas_size {
- let y = pixel as u32 / self.canvas_width;
- let x = pixel as u32 - y * self.canvas_width;
+ let y = pixel as u32 / canvas_width;
+ let x = pixel as u32 - y * canvas_width;
let colour = {
let red = image[pixel as usize * 0x3];
@@ -48,27 +48,29 @@ impl Application {
};
let rectangle = Rect::new(
- (x * self.scale) as i32,
- (y * self.scale) as i32,
- self.scale,
- self.scale
+ (x * scale) as i32,
+ (y * scale) as i32,
+ scale,
+ scale
);
- self.video.as_mut().unwrap().canvas.set_draw_color(colour);
- self.video.as_mut().unwrap().canvas.fill_rects(&[rectangle]).unwrap();
+ self.canvas.set_draw_color(colour);
+ self.canvas.fill_rects(&[rectangle]).unwrap();
}
- if !self.julia {
+ if feedback_info.is_some() {
+ let feedback_info = unsafe { feedback_info.unwrap_unchecked() };
+
let canvas_width = {
- let mut canvas_width = Float::with_val(PRECISION, self.canvas_width);
- canvas_width *= self.scale;
+ let mut canvas_width = Float::with_val(PRECISION, canvas_width);
+ canvas_width *= scale;
canvas_width
};
let viewport = {
let ((offset_x, offset_y), width) = {
- let zoom_ratio = Float::with_val(PRECISION, &self.zoom / &previous_position.zoom);
+ let zoom_ratio = Float::with_val(PRECISION, feedback_info.next_zoom / feedback_info.prev_zoom);
let mut width = Float::with_val(PRECISION, 1.0 / &zoom_ratio);
@@ -76,17 +78,17 @@ impl Application {
// inverted vertical axis compared to those of
// SDL's coordinate system.
- let mut offset_x = self.centre_real.clone();
- let mut offset_y = Float::with_val(PRECISION, -&self.centre_imag);
+ let mut offset_x = feedback_info.next_centre_real.clone();
+ let mut offset_y = Float::with_val(PRECISION, -feedback_info.next_centre_imag);
- offset_x -= &previous_position.centre_real;
- offset_y += &previous_position.centre_imag;
+ offset_x -= feedback_info.prev_centre_real;
+ offset_y += feedback_info.prev_centre_imag;
offset_x /= 4.0;
offset_y /= 4.0;
- offset_x *= &previous_position.zoom;
- offset_y *= &previous_position.zoom;
+ offset_x *= feedback_info.prev_zoom;
+ offset_y *= feedback_info.prev_zoom;
let mut zoom_offset = Float::with_val(PRECISION, 1.0 - &width);
zoom_offset /= 2.0;
@@ -109,13 +111,13 @@ impl Application {
)
};
- self.video.as_mut().unwrap().canvas.set_draw_color(Color::RGBA(0x0, 0x0, 0x0, 0x3F));
- self.video.as_mut().unwrap().canvas.fill_rects(&[viewport]).unwrap();
+ self.canvas.set_draw_color(Color::RGBA(0x0, 0x0, 0x0, 0x3F));
+ self.canvas.fill_rects(&[viewport]).unwrap();
- self.video.as_mut().unwrap().canvas.set_draw_color(Color::RGB(0xFF, 0xFF, 0xFF));
- self.video.as_mut().unwrap().canvas.draw_rects(&[viewport]).unwrap();
+ self.canvas.set_draw_color(Color::RGB(0xFF, 0xFF, 0xFF));
+ self.canvas.draw_rects(&[viewport]).unwrap();
}
- self.video.as_mut().unwrap().canvas.present();
+ self.canvas.present();
}
}
diff --git a/source/benoit/benoit/video/initialise.rs b/source/benoit/benoit/video/initialise.rs
index 40bc68d..f97ae8b 100644
--- a/source/benoit/benoit/video/initialise.rs
+++ b/source/benoit/benoit/video/initialise.rs
@@ -33,15 +33,16 @@ impl Video {
let sdl = sdl2::init().expect("unable to initialise sdl2");
let sdl_video = sdl.video().expect("unable to initialise video");
- let window = sdl_video.window(format!("Benoit {VERSION:X}").as_str(), canvas_width * scale, canvas_width * scale).position_centered().build().expect("unable to open window");
+ let window = sdl_video.window(format!("Benoit {:X}.{:X}.{:X}", VERSION.major, VERSION.minor, VERSION.patch).as_str(), canvas_width * scale, canvas_width * scale).position_centered().build().expect("unable to open window");
let mut canvas = window.into_canvas().build().expect("unable to create canvas");
canvas.set_blend_mode(BlendMode::Blend);
return Video {
- sdl: sdl,
- canvas: canvas,
+ sdl: sdl,
+ sdl_video: sdl_video,
+ canvas: canvas,
};
}
}
diff --git a/source/benoit/benoit/video/sync.rs b/source/benoit/benoit/video/sync.rs
new file mode 100644
index 0000000..c8c016a
--- /dev/null
+++ b/source/benoit/benoit/video/sync.rs
@@ -0,0 +1,46 @@
+/*
+ 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::video::Video;
+
+use std::thread::sleep;
+use std::time::{Duration, Instant};
+
+impl Video {
+ pub fn sync(&self, frame_start: &Instant) {
+ let frame_duration = {
+ let index = self.canvas.window().display_index().expect("unable to get display index");
+
+ let mode = self.sdl_video.current_display_mode(index).expect("unable to get display mode");
+
+ Duration::from_secs(0x1) / mode.refresh_rate as u32
+ };
+
+ let remaining = match frame_duration.checked_sub(frame_start.elapsed()) {
+ Some(value) => value,
+ None => Duration::from_secs(0x0),
+ };
+
+ sleep(remaining);
+ }
+} \ No newline at end of file
diff --git a/source/benoit/main.rs b/source/benoit/main.rs
index ec24cbb..3716309 100644
--- a/source/benoit/main.rs
+++ b/source/benoit/main.rs
@@ -23,15 +23,15 @@
mod benoit;
-use benoit::application::Application;
+use benoit::app::App;
use std::mem::drop;
use std::process::exit;
fn main() {
- let mut application = Application::initialise();
- let code = application.run();
+ let mut app = App::initialise();
+ let code = app.run();
- drop(application);
+ drop(app);
exit(code);
}