diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | CHANGELOG.md | 14 | ||||
-rw-r--r-- | Cargo.toml | 3 | ||||
-rw-r--r-- | source/benoit/benoit.rs | 1 | ||||
-rw-r--r-- | source/benoit/benoit/application.rs | 26 | ||||
-rw-r--r-- | source/benoit/benoit/application/animate.rs | 85 | ||||
-rw-r--r-- | source/benoit/benoit/application/colour.rs | 2 | ||||
-rw-r--r-- | source/benoit/benoit/application/draw.rs | 13 | ||||
-rw-r--r-- | source/benoit/benoit/application/dump.rs | 12 | ||||
-rw-r--r-- | source/benoit/benoit/application/handle_keys.rs | 51 | ||||
-rw-r--r-- | source/benoit/benoit/application/initialise.rs | 43 | ||||
-rw-r--r-- | source/benoit/benoit/application/loop.rs | 76 | ||||
-rw-r--r-- | source/benoit/benoit/application/render.rs | 37 | ||||
-rw-r--r-- | source/benoit/benoit/application/render_row.rs | 68 | ||||
-rw-r--r-- | source/benoit/benoit/application/run.rs | 17 | ||||
-rw-r--r-- | source/benoit/benoit/configuration.rs | 7 | ||||
-rw-r--r-- | source/benoit/benoit/configuration/default.rs | 11 | ||||
-rw-r--r-- | source/benoit/benoit/configuration/load.rs | 10 | ||||
-rw-r--r-- | source/benoit/benoit/video.rs | 34 | ||||
-rw-r--r-- | source/benoit/benoit/video/initialise.rs | 42 | ||||
-rw-r--r-- | source/benoit/main.rs | 9 |
21 files changed, 448 insertions, 114 deletions
@@ -1,6 +1,7 @@ *.png *.webp /old +/render /target Benoit.toml Cargo.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index 689d22c..41835d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +# 1↊ + +* Use arbitrary-precision calculations +* Depend on Rug +* Optimise renderer +* Animate if configured +* Update commenting +* Remove scale option from configuration +* Auto-deduce thread count +* Update controls (only render on command) +* Update messages +* Refactor application structure +* Print controls + # 19 * Update controls @@ -1,6 +1,6 @@ [package] name = "benoit" -version = "0.21.0" +version = "0.22.0" authors = ["Gabriel Bjørnager Jensen"] edition = "2021" description = "Mandelbrot renderer." @@ -15,6 +15,7 @@ path = "source/benoit/main.rs" lto = true [dependencies] +rug = "1.20.1" sdl2 = "0.35.2" toml = "0.7.6" webp = "0.2.5" diff --git a/source/benoit/benoit.rs b/source/benoit/benoit.rs index d7deab8..f3d5299 100644 --- a/source/benoit/benoit.rs +++ b/source/benoit/benoit.rs @@ -23,3 +23,4 @@ pub mod application; pub mod configuration; +pub mod video; diff --git a/source/benoit/benoit/application.rs b/source/benoit/benoit/application.rs index 51d0602..ad5964a 100644 --- a/source/benoit/benoit/application.rs +++ b/source/benoit/benoit/application.rs @@ -21,16 +21,19 @@ If not, see <https://www.gnu.org/licenses/>. */ -extern crate sdl2; +use crate::benoit::video::Video; -use sdl2::{Sdl, VideoSubsystem}; -use sdl2::render::WindowCanvas; +extern crate rug; +use rug::Float; + +pub mod animate; pub mod colour; pub mod draw; pub mod dump; pub mod handle_keys; pub mod initialise; +pub mod r#loop; pub mod poll_events; pub mod render_row; pub mod render; @@ -42,17 +45,20 @@ pub struct Application { canvas_width: u32, canvas_height: u32, scale: u32, + frame_count: u32, - position_x: f64, - position_y: f64, - zoom: f64, + center_real: Float, + center_imaginary: Float, + zoom: Float, maximum_iteration_count: u32, dump_path: String, - sdl: Sdl, - sdl_video: VideoSubsystem, - canvas: WindowCanvas, + video: Option<Video>, + + interactive: bool, + do_draw: bool, + do_dump: bool, - do_draw: bool, + precision: u32, } diff --git a/source/benoit/benoit/application/animate.rs b/source/benoit/benoit/application/animate.rs new file mode 100644 index 0000000..6ff628e --- /dev/null +++ b/source/benoit/benoit/application/animate.rs @@ -0,0 +1,85 @@ +/* + 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; + +extern crate rug; +extern crate sdl2; + +use rug::Float; +use rug::ops::PowAssign; +use std::ops::MulAssign; + +impl Application { + pub fn animate(&self) -> i32 { + let stop_zoom = Float::with_val(self.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)^(1/frame_count) + + let x_difference = Float::with_val(self.precision, self.frame_count); + + let exponent = Float::with_val(self.precision, 1.0 / &x_difference); + + let mut factor = Float::with_val(self.precision, &stop_zoom); + factor.pow_assign(exponent); + + factor + }; + + let mut zoom = Float::with_val(self.precision, 1.0); + + eprintln!("animating {} frames at {}{:+} to {:.3} (fac.: {:.3})", self.frame_count, self.center_real.to_f64(), self.center_imaginary.to_f64(), stop_zoom.to_f64(), zoom_factor.to_f64()); + + let canvas_size = self.canvas_height as usize * self.canvas_width as usize; + + let mut data: Vec::<u32> = vec![0x0; canvas_size]; + let mut image: Vec::<u8> = vec![0x0; canvas_size * 0x3]; + + for frame in 0x0..self.frame_count { + eprint!("{frame:010}: "); + self.render(&mut data[..], self.precision, &self.center_real, &self.center_imaginary, &zoom, self.maximum_iteration_count); + self.colour(&mut image[..], &data[..]); + + self.dump(format!("{}/frame{frame:010}.webp", self.dump_path), &image, self.canvas_width, self.canvas_height); + + zoom.mul_assign(&zoom_factor); + } + + return 0x0; + } +} diff --git a/source/benoit/benoit/application/colour.rs b/source/benoit/benoit/application/colour.rs index f0b1f19..db7e467 100644 --- a/source/benoit/benoit/application/colour.rs +++ b/source/benoit/benoit/application/colour.rs @@ -24,7 +24,7 @@ use crate::benoit::application::Application; impl Application { - pub fn colour(&mut self, buffer: &mut [u8], data: &[u32]) { + pub fn colour(&self, buffer: &mut [u8], data: &[u32]) { let canvas_size = self.canvas_height * self.canvas_width; for pixel in 0x0..canvas_size { diff --git a/source/benoit/benoit/application/draw.rs b/source/benoit/benoit/application/draw.rs index 6cf9196..c41d9c9 100644 --- a/source/benoit/benoit/application/draw.rs +++ b/source/benoit/benoit/application/draw.rs @@ -29,13 +29,10 @@ use sdl2::pixels::Color; use sdl2::rect::Rect; impl Application { - pub fn draw(&mut self) { + pub fn draw(&mut self, data: &mut [u32], image: &mut [u8]) { let canvas_size = self.canvas_height * self.canvas_width; - let mut data: Vec::<u32> = vec![0x0; canvas_size as usize]; - self.render(&mut data[..], self.position_x, self.position_y, self.zoom, self.maximum_iteration_count); - - let mut image: Vec::<u8> = vec![0x0; canvas_size as usize * 0x3]; + self.render(&mut data[..], self.precision, &self.center_real, &self.center_imaginary, &self.zoom, self.maximum_iteration_count); self.colour(&mut image[..], &data[..]); for pixel in 0x0..canvas_size { @@ -45,7 +42,7 @@ impl Application { let value = image[pixel as usize * 0x3]; let colour = Color::RGB(value, value, value); - self.canvas.set_draw_color(colour); + self.video.as_mut().unwrap().canvas.set_draw_color(colour); let rectangle = Rect::new( (x * self.scale) as i32, @@ -53,9 +50,9 @@ impl Application { self.scale, self.scale ); - self.canvas.fill_rects(&[rectangle]).unwrap(); + self.video.as_mut().unwrap().canvas.fill_rects(&[rectangle]).unwrap(); } - self.canvas.present(); + self.video.as_mut().unwrap().canvas.present(); } } diff --git a/source/benoit/benoit/application/dump.rs b/source/benoit/benoit/application/dump.rs index ca658b3..a7b2915 100644 --- a/source/benoit/benoit/application/dump.rs +++ b/source/benoit/benoit/application/dump.rs @@ -29,16 +29,8 @@ use std::fs::write; use webp::Encoder; impl Application { - pub fn dump(&mut self, path: String) { - let canvas_size = self.canvas_height * self.canvas_width; - - let mut data: Vec::<u32> = vec![0x0; canvas_size as usize]; - self.render(&mut data[..], self.position_x, self.position_y, self.zoom, self.maximum_iteration_count); - - let mut image: Vec::<u8> = vec![0x0; canvas_size as usize * 0x3]; - self.colour(&mut image[..], &data[..]); - - let encoder = Encoder::from_rgb(&image[..], self.canvas_width, self.canvas_height); + pub fn dump(&self, path: String, image: &[u8], canvas_width: u32, canvas_height: u32) { + let encoder = Encoder::from_rgb(&image[..], canvas_width, canvas_height); let data = encoder.encode_lossless(); diff --git a/source/benoit/benoit/application/handle_keys.rs b/source/benoit/benoit/application/handle_keys.rs index 547971f..265bc18 100644 --- a/source/benoit/benoit/application/handle_keys.rs +++ b/source/benoit/benoit/application/handle_keys.rs @@ -23,36 +23,47 @@ use crate::benoit::application::Application; +extern crate rug; extern crate sdl2; +use rug::Float; use sdl2::keyboard::Scancode; +use std::ops::{AddAssign, DivAssign, MulAssign, SubAssign}; impl Application { pub fn handle_keys(&mut self, scan_code: Scancode) -> bool { match scan_code { Scancode::Escape => return true, - Scancode::X => self.dump(self.dump_path.clone()), + Scancode::C => self.do_draw = true, + Scancode::X => self.do_dump = true, + Scancode::Z => eprintln!("{}{:+}i -- {}x @ {} iter.", self.center_real, self.center_imaginary, self.zoom, self.maximum_iteration_count), _ => {}, } - self.zoom = match scan_code { - Scancode::E => self.zoom * 4.0, - Scancode::Q => self.zoom / 4.0, - _ => self.zoom, + match scan_code { + Scancode::E => self.zoom.mul_assign(4.0), + Scancode::Q => self.zoom.div_assign(4.0), + _ => {}, }; - let translate_ammount: f64 = 1.0 / 4.0 / self.zoom; + let translate_ammount = { + let mut ammount = Float::with_val(self.precision, 1.0); + ammount.div_assign(4.0); + ammount.div_assign(&self.zoom); - self.position_x += match scan_code { - Scancode::A => -translate_ammount, - Scancode::D => translate_ammount, - _ => 0.0, + ammount }; - self.position_y += match scan_code { - Scancode::S => translate_ammount, - Scancode::W => -translate_ammount, - _ => 0.0, + match scan_code { + Scancode::A => self.center_real.sub_assign(&translate_ammount), + Scancode::D => self.center_real.add_assign(&translate_ammount), + _ => {}, + }; + + match scan_code { + Scancode::S => self.center_imaginary.add_assign(&translate_ammount), + Scancode::W => self.center_imaginary.sub_assign(&translate_ammount), + _ => {}, }; self.maximum_iteration_count = match scan_code { @@ -61,18 +72,6 @@ impl Application { _ => self.maximum_iteration_count, }; - self.do_draw = match scan_code { - Scancode::A => true, - Scancode::D => true, - Scancode::E => true, - Scancode::F => true, - Scancode::Q => true, - Scancode::R => true, - Scancode::S => true, - Scancode::W => true, - _ => false, - }; - return false; } } diff --git a/source/benoit/benoit/application/initialise.rs b/source/benoit/benoit/application/initialise.rs index 4e9386f..6091da2 100644 --- a/source/benoit/benoit/application/initialise.rs +++ b/source/benoit/benoit/application/initialise.rs @@ -23,8 +23,13 @@ use crate::benoit::application::Application; use crate::benoit::configuration::Configuration; +use crate::benoit::video::Video; +extern crate rug; + +use rug::Float; use std::env::args; +use std::thread::available_parallelism; impl Application { pub fn initialise() -> Application { @@ -35,32 +40,46 @@ impl Application { None => Configuration::default(), }; - let sdl = sdl2::init().expect("unable to initialise sdl2"); - let sdl_video = sdl.video().expect("unable to initialise video"); + let precision: u32 = 0x100; - let window = sdl_video.window("Benoit", configuration.canvas_width * configuration.scale, configuration.canvas_height * configuration.scale).position_centered().build().expect("unable to open window"); + let thread_count: u32 = if configuration.thread_count == 0x0 { + match available_parallelism() { + Ok(ammount) => ammount.get() as u32, + _ => 0x2, + } + } else { + configuration.thread_count + }; - let canvas = window.into_canvas().build().expect("unable to create canvas"); + eprintln!("using {thread_count} threads"); + + let video = match configuration.interactive { + true => Some(Video::initialise(configuration.canvas_width, configuration.canvas_height, configuration.scale)), + false => None, + }; return Application { - thread_count: configuration.thread_count, + thread_count: thread_count, canvas_width: configuration.canvas_width, canvas_height: configuration.canvas_height, scale: configuration.scale, + frame_count: configuration.frame_count, - position_x: configuration.position_x, - position_y: configuration.position_y, - zoom: configuration.zoom, + center_real: Float::with_val(precision, configuration.center_real), + center_imaginary: Float::with_val(precision, configuration.center_imaginary), + zoom: Float::with_val(precision, configuration.zoom), maximum_iteration_count: configuration.maximum_iteration_count, dump_path: configuration.dump_path, - sdl: sdl, - sdl_video: sdl_video, - canvas: canvas, + video: video, + + interactive: configuration.interactive, + do_draw: true, + do_dump: false, - do_draw: true, + precision: precision, }; } } diff --git a/source/benoit/benoit/application/loop.rs b/source/benoit/benoit/application/loop.rs new file mode 100644 index 0000000..dd35c63 --- /dev/null +++ b/source/benoit/benoit/application/loop.rs @@ -0,0 +1,76 @@ +/* + Copyright 2021, 2023 Gabriel Bjørnager Jensen. + + This file is part of Benoit. + + Benoit is free software: you can redistribute it + and/or modify it under the terms of the GNU + Affero General Public License as published by + the Free Software Foundation, either version 3 + of the License, or (at your option) any later + version. + + Benoit is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without + even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU + Affero General Public License along with Benoit. + If not, see <https://www.gnu.org/licenses/>. +*/ + +use crate::benoit::application::Application; + +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!("- Z Print center value (c)"); + eprintln!("- X Dump render"); + eprintln!("- C Render frame"); + eprintln!(); + + let mut event_pump = self.video.as_mut().unwrap().sdl.event_pump().expect("unable to get event pump"); + + let canvas_size = self.canvas_height as usize * self.canvas_width as usize; + + let mut data: Vec::<u32> = vec![0x0; canvas_size]; + let mut image: Vec::<u8> = vec![0x0; canvas_size * 0x3]; + + loop { + if self.poll_events(&mut event_pump) { break } + + if self.do_draw { + self.draw(data.as_mut_slice(), image.as_mut_slice()); + + self.do_draw = false; + } + + 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.canvas_height); + + self.do_dump = false; + } + } + + return 0x0; + } +} diff --git a/source/benoit/benoit/application/render.rs b/source/benoit/benoit/application/render.rs index df14024..e353732 100644 --- a/source/benoit/benoit/application/render.rs +++ b/source/benoit/benoit/application/render.rs @@ -23,20 +23,25 @@ use crate::benoit::application::Application; +extern crate rug; + +use rug::Float; use std::slice; use std::thread::{JoinHandle, spawn}; use std::time::Instant; use std::ptr::addr_of_mut; impl Application { - pub fn render(&mut self, buffer: &mut [u32], position_x: f64, position_y: f64, zoom: f64, maximum_iteration_count: u32) { - eprintln!("rendering: {}{:+}i ({}x) @ ({})", position_x, position_y, zoom, maximum_iteration_count); + pub fn render(&self, buffer: &mut [u32], precision: u32, center_real: &Float, center_imaginary: &Float, zoom: &Float, maximum_iteration_count: u32) { + eprint!("rendering..."); let mut threads = Vec::<JoinHandle<()>>::with_capacity(self.thread_count as usize); let time_start = Instant::now(); 'render_loop: { + // We render the set using one thread per row. + let get_slice = |buffer: &mut [u32], y: u32, canvas_width: u32| -> &mut [u32] { let slice_start = y as usize * canvas_width as usize; let slice = unsafe { slice::from_raw_parts_mut(addr_of_mut!(buffer[slice_start]), canvas_width as usize) }; @@ -46,34 +51,46 @@ impl Application { let canvas_width = self.canvas_width; let canvas_height = self.canvas_height; - let position_x = position_x; - let position_y = position_y; - let zoom = zoom; - let maximum_iteration_count = maximum_iteration_count; - let mut y: u32 = 0x0; + // Firstly, we fill up the thread vector by + // spawning threads. + let mut y: u32 = 0x0; for _thread in 0x0..self.thread_count { + // We should stop if there are no remaining rows. if y == self.canvas_height { break 'render_loop; } let buffer_slice = get_slice(buffer, y, self.canvas_width); - threads.push(spawn(move || { Application::render_row(buffer_slice, y, canvas_width, canvas_height, position_x, position_y, zoom, maximum_iteration_count) })); + let center_real = center_real.clone(); + let center_imaginary = center_imaginary.clone(); + let zoom = zoom.clone(); + + threads.push(spawn(move || { Application::render_row(buffer_slice, precision, y, canvas_width, canvas_height, center_real, center_imaginary, zoom, maximum_iteration_count) })); y += 0x1; } + // Secondly, we continuously join the first thread + // to spawn another one. This is as to make the + // threads more "active" by making the take on more + // rows when they complete. + for y in 0x0..self.canvas_height { threads.remove(0x0).join().unwrap(); let buffer_slice = get_slice(buffer, y, self.canvas_width); - threads.push(spawn(move || { Application::render_row(buffer_slice, y, canvas_width, canvas_height, position_x, position_y, zoom, maximum_iteration_count) })); + let center_real = center_real.clone(); + let center_imaginary = center_imaginary.clone(); + let zoom = zoom.clone(); + + threads.push(spawn(move || { Application::render_row(buffer_slice, precision, y, canvas_width, canvas_height, center_real, center_imaginary, zoom, maximum_iteration_count) })); } } let duration = time_start.elapsed(); - eprintln!("done ({}ms)", duration.as_millis()); + eprintln!(" done ({}ms)", duration.as_millis()); } } diff --git a/source/benoit/benoit/application/render_row.rs b/source/benoit/benoit/application/render_row.rs index 80e3646..64f9f4c 100644 --- a/source/benoit/benoit/application/render_row.rs +++ b/source/benoit/benoit/application/render_row.rs @@ -23,22 +23,60 @@ use crate::benoit::application::Application; +extern crate rug; + +use rug::Float; +use std::ops::{AddAssign, DivAssign, MulAssign}; + impl Application { - pub fn render_row(data: &mut [u32], y: u32, canvas_width: u32, canvas_height: u32, position_x: f64, position_y: f64, zoom: f64, maximum_iteration_count: u32) { + pub fn render_row(data: &mut [u32], precision: u32, y: u32, canvas_width: u32, canvas_height: u32, center_real: Float, center_imaginary: Float, zoom: Float, maximum_iteration_count: u32) { + let two = Float::with_val(precision, 2.0); + for x in 0x0..canvas_width { - let canvas_width = canvas_width as f64; - let canvas_height = canvas_height as f64; + let canvas_width = Float::with_val(precision, canvas_width); + let canvas_height = Float::with_val(precision, canvas_height); + + //let ca = Float::with_val(precision, (&x - &canvas_width / 2.0) / &canvas_width * 4.0 / &zoom + ¢er_real); + //let cb = Float::with_val(precision, (&y - &canvas_height / 2.0) / &canvas_height * 4.0 / &zoom + ¢er_imaginary); + + let x_float = Float::with_val(precision, x); + let y_float = Float::with_val(precision, y); + + // Re(c) = (x-canvas_width/2)/canvas_width*4/zoom+Re(z) + + let ca = { + let tmp0 = Float::with_val(precision, &canvas_width / 2.0); - let ca = (x as f64 - canvas_width / 2.0) / canvas_width * 4.0 / zoom + position_x; - let cb = (y as f64 - canvas_height / 2.0) / canvas_height * 4.0 / zoom + position_y; + let mut ca = Float::with_val(precision, &x_float - &tmp0); + ca.div_assign(&canvas_width); + ca.mul_assign(4.0); + ca.div_assign(&zoom); + ca.add_assign(¢er_real); - let mut za: f64 = 0.0; - let mut zb: f64 = 0.0; + ca + }; + + // Im(c) = (x-canvas_height/2)/canvas_height*4/zoom+Im(z) + + let cb = { + let tmp0 = Float::with_val(precision, &canvas_height / 2.0); + + let mut cb = Float::with_val(precision, &y_float - &tmp0); + cb.div_assign(&canvas_height); + cb.mul_assign(4.0); + cb.div_assign(&zoom); + cb.add_assign(¢er_imaginary); + + cb + }; + + let mut za = Float::with_val(precision, &ca); + let mut zb = Float::with_val(precision, &cb); let mut iteration_count: u32 = 0x0; while iteration_count < maximum_iteration_count { - let square_distance = za * za + zb * zb; - if square_distance > 2.0 * 2.0 { break } + let square_distance = Float::with_val(precision, &za * &za + &zb * &zb); + if square_distance > 4.0 { break } { // z = z^2 + c @@ -47,15 +85,19 @@ impl Application { // a = a^2 - b^2 // b = 2abi - let za_temporary = za; - za = za * za - zb * zb + ca; - zb = za_temporary * zb * 2.0 + cb; + let za_temporary = Float::with_val(precision, &za); + + za = Float::with_val(precision, &za * &za - &zb * &zb); + za = Float::with_val(precision, &za + &ca); + + zb = Float::with_val(precision, &za_temporary * &zb); + zb = Float::with_val(precision, &zb * &two + &cb); } iteration_count += 0x1; } - data[x as usize] = iteration_count; + unsafe { *data.get_unchecked_mut(x as usize) = iteration_count } } } } diff --git a/source/benoit/benoit/application/run.rs b/source/benoit/benoit/application/run.rs index 393918a..d764084 100644 --- a/source/benoit/benoit/application/run.rs +++ b/source/benoit/benoit/application/run.rs @@ -26,17 +26,10 @@ use crate::benoit::application::Application; extern crate sdl2; impl Application { - pub fn run(&mut self) { - let mut event_pump = self.sdl.event_pump().expect("unable to get event pump"); - - loop { - if self.poll_events(&mut event_pump) { break } - - if self.do_draw { - self.draw(); - - self.do_draw = false; - } - } + pub fn run(&mut self) -> i32 { + return match self.interactive { + true => self.r#loop(), + false => self.animate(), + }; } } diff --git a/source/benoit/benoit/configuration.rs b/source/benoit/benoit/configuration.rs index 6783f21..29a2b67 100644 --- a/source/benoit/benoit/configuration.rs +++ b/source/benoit/benoit/configuration.rs @@ -30,11 +30,14 @@ pub struct Configuration { pub canvas_width: u32, pub canvas_height: u32, pub scale: u32, + pub frame_count: u32, - pub position_x: f64, - pub position_y: f64, + pub center_real: f64, + pub center_imaginary: f64, pub zoom: f64, pub maximum_iteration_count: u32, pub dump_path: String, + + pub interactive: bool, } diff --git a/source/benoit/benoit/configuration/default.rs b/source/benoit/benoit/configuration/default.rs index ddc6578..227e588 100644 --- a/source/benoit/benoit/configuration/default.rs +++ b/source/benoit/benoit/configuration/default.rs @@ -26,18 +26,21 @@ use crate::benoit::configuration::Configuration; impl Configuration { pub fn default() -> Configuration { return Configuration { - thread_count: 0x2, + thread_count: 0x0, canvas_width: 0x100, canvas_height: 0x100, scale: 0x1, + frame_count: 0x10, - position_x: 0.0, - position_y: 0.0, + center_real: 0.0, + center_imaginary: 0.0, zoom: 1.0, maximum_iteration_count: 0x100, - dump_path: "./image.webp".to_string(), + dump_path: "./render/".to_string(), + + interactive: true, }; } } diff --git a/source/benoit/benoit/configuration/load.rs b/source/benoit/benoit/configuration/load.rs index 1c0cfe8..cf74548 100644 --- a/source/benoit/benoit/configuration/load.rs +++ b/source/benoit/benoit/configuration/load.rs @@ -35,6 +35,8 @@ impl Configuration { let mut configuration = Configuration::default(); + configuration.interactive = false; + let configuration_text = match read(path) { Ok(content) => String::from_utf8_lossy(&content).to_string(), Err(..) => { @@ -68,11 +70,11 @@ impl Configuration { get_integer(&mut configuration.canvas_width, &configuration_table, "canvas_width"); get_integer(&mut configuration.canvas_height, &configuration_table, "canvas_height"); get_integer(&mut configuration.scale, &configuration_table, "scale"); + get_integer(&mut configuration.frame_count, &configuration_table, "frame_count"); - get_float(&mut configuration.position_x, &configuration_table, "real"); - get_float(&mut configuration.position_y, &configuration_table, "imaginary"); - get_float(&mut configuration.zoom, &configuration_table, "zoom"); - + get_float( &mut configuration.center_real, &configuration_table, "real"); + get_float( &mut configuration.center_imaginary, &configuration_table, "imaginary"); + get_float( &mut configuration.zoom, &configuration_table, "zoom"); get_integer(&mut configuration.maximum_iteration_count, &configuration_table, "maximum_iteration_count"); return configuration; diff --git a/source/benoit/benoit/video.rs b/source/benoit/benoit/video.rs new file mode 100644 index 0000000..2147b27 --- /dev/null +++ b/source/benoit/benoit/video.rs @@ -0,0 +1,34 @@ +/* + Copyright 2021, 2023 Gabriel Bjørnager Jensen. + + This file is part of Benoit. + + Benoit is free software: you can redistribute it + and/or modify it under the terms of the GNU + Affero General Public License as published by + the Free Software Foundation, either version 3 + of the License, or (at your option) any later + version. + + Benoit is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without + even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU + Affero General Public License along with Benoit. + If not, see <https://www.gnu.org/licenses/>. +*/ + +extern crate sdl2; + +use sdl2::Sdl; +use sdl2::render::WindowCanvas; + +pub mod initialise; + +pub struct Video { + pub sdl: Sdl, + pub canvas: WindowCanvas, +} diff --git a/source/benoit/benoit/video/initialise.rs b/source/benoit/benoit/video/initialise.rs new file mode 100644 index 0000000..595140d --- /dev/null +++ b/source/benoit/benoit/video/initialise.rs @@ -0,0 +1,42 @@ +/* + 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; + +extern crate sdl2; + +impl Video { + pub fn initialise(canvas_width: u32, canvas_height: u32, scale: u32) -> 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("Benoit", canvas_width * scale, canvas_height * scale).position_centered().build().expect("unable to open window"); + + let canvas = window.into_canvas().build().expect("unable to create canvas"); + + return Video { + sdl: sdl, + canvas: canvas, + }; + } +} diff --git a/source/benoit/main.rs b/source/benoit/main.rs index bffc05d..a302b9f 100644 --- a/source/benoit/main.rs +++ b/source/benoit/main.rs @@ -25,7 +25,14 @@ mod benoit; use benoit::application::Application; +use std::mem::drop; +use std::process::exit; + fn main() { let mut application = Application::initialise(); - application.run(); + let code = application.run(); + + drop(application); + + exit(code); } |