diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | CHANGELOG.md | 8 | ||||
-rw-r--r-- | Cargo.toml | 3 | ||||
-rw-r--r-- | source/benoit/benoit.rs | 1 | ||||
-rw-r--r-- | source/benoit/benoit/application.rs | 11 | ||||
-rw-r--r-- | source/benoit/benoit/application/draw.rs | 2 | ||||
-rw-r--r-- | source/benoit/benoit/application/dump.rs | 8 | ||||
-rw-r--r-- | source/benoit/benoit/application/handle_key.rs | 78 | ||||
-rw-r--r-- | source/benoit/benoit/application/initialise.rs | 31 | ||||
-rw-r--r-- | source/benoit/benoit/application/poll_events.rs | 59 | ||||
-rw-r--r-- | source/benoit/benoit/application/render.rs | 12 | ||||
-rw-r--r-- | source/benoit/benoit/configuration.rs | 39 | ||||
-rw-r--r-- | source/benoit/benoit/configuration/load.rs | 89 |
13 files changed, 258 insertions, 84 deletions
@@ -2,4 +2,5 @@ *.webp /old /target +Benoit.toml Cargo.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index 829e080..5a7560b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# 17 + +* Modulise code +* Check I/O errors +* Support configuration +* Depend on toml +* Update gitignore + # 16 * Clean up code @@ -1,6 +1,6 @@ [package] name = "benoit" -version = "0.18.0" +version = "0.19.0" authors = ["Gabriel Bjørnager Jensen"] edition = "2021" description = "Mandelbrot renderer." @@ -16,4 +16,5 @@ lto = true [dependencies] 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 5b4b9e2..d7deab8 100644 --- a/source/benoit/benoit.rs +++ b/source/benoit/benoit.rs @@ -22,3 +22,4 @@ */ pub mod application; +pub mod configuration; diff --git a/source/benoit/benoit/application.rs b/source/benoit/benoit/application.rs index 335d754..f6cb60f 100644 --- a/source/benoit/benoit/application.rs +++ b/source/benoit/benoit/application.rs @@ -29,6 +29,7 @@ use sdl2::render::WindowCanvas; pub mod colour; pub mod draw; pub mod dump; +pub mod handle_key; pub mod initialise; pub mod poll_events; pub mod render_row; @@ -36,10 +37,6 @@ pub mod render; pub mod run; pub struct Application { - sdl: Sdl, - sdl_video: VideoSubsystem, - canvas: WindowCanvas, - thread_count: u32, canvas_width: u32, @@ -51,5 +48,11 @@ pub struct Application { zoom: f64, maximum_iteration_count: u32, + dump_path: String, + + sdl: Sdl, + sdl_video: VideoSubsystem, + canvas: WindowCanvas, + do_draw: bool, } diff --git a/source/benoit/benoit/application/draw.rs b/source/benoit/benoit/application/draw.rs index 29e0faf..6cf9196 100644 --- a/source/benoit/benoit/application/draw.rs +++ b/source/benoit/benoit/application/draw.rs @@ -33,7 +33,7 @@ impl Application { 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.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[..]); diff --git a/source/benoit/benoit/application/dump.rs b/source/benoit/benoit/application/dump.rs index 25ec520..ca658b3 100644 --- a/source/benoit/benoit/application/dump.rs +++ b/source/benoit/benoit/application/dump.rs @@ -29,11 +29,11 @@ use std::fs::write; use webp::Encoder; impl Application { - pub fn dump_image(&mut self) { + 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.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[..]); @@ -42,8 +42,6 @@ impl Application { let data = encoder.encode_lossless(); - let file_path = "./image.webp"; - - write(file_path, &*data); + write(path, &*data).expect("unable to write image"); } } diff --git a/source/benoit/benoit/application/handle_key.rs b/source/benoit/benoit/application/handle_key.rs new file mode 100644 index 0000000..e28cef5 --- /dev/null +++ b/source/benoit/benoit/application/handle_key.rs @@ -0,0 +1,78 @@ +/* + 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; + +use sdl2::keyboard::Scancode; + +impl Application { + pub fn handle_key(&mut self, scan_code: Scancode) -> bool { + match scan_code { + Scancode::Escape => return true, + Scancode::X => self.dump(self.dump_path.clone()), + _ => {}, + } + + self.zoom = match scan_code { + Scancode::E => self.zoom * 2.0, + Scancode::Q => self.zoom / 2.0, + _ => self.zoom, + }; + + let translate_ammount: f64 = 1.0 / 16.0 / self.zoom; + + self.position_x += match scan_code { + Scancode::A => -translate_ammount, + Scancode::D => translate_ammount, + _ => 0.0, + }; + + self.position_y += match scan_code { + Scancode::S => translate_ammount, + Scancode::W => -translate_ammount, + _ => 0.0, + }; + + self.maximum_iteration_count = match scan_code { + Scancode::F => self.maximum_iteration_count * 0x2, + Scancode::R => self.maximum_iteration_count / 0x2, + _ => 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 28245b2..3de87e7 100644 --- a/source/benoit/benoit/application/initialise.rs +++ b/source/benoit/benoit/application/initialise.rs @@ -22,35 +22,36 @@ */ use crate::benoit::application::Application; +use crate::benoit::configuration::Configuration; impl Application { pub fn initialise() -> Application { - let canvas_width: u32 = 0x400; - let canvas_height: u32 = 0x400; - let scale: u32 = 0x1; + let configuration = Configuration::load("./Benoit.toml"); 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 window = sdl_video.window("Benoit", configuration.canvas_width * configuration.scale, configuration.canvas_height * configuration.scale).position_centered().build().expect("unable to open window"); let canvas = window.into_canvas().build().expect("unable to create canvas"); return Application { - sdl: sdl, - sdl_video: sdl_video, - canvas: canvas, + thread_count: configuration.thread_count, + + canvas_width: configuration.canvas_width, + canvas_height: configuration.canvas_height, + scale: configuration.scale, - thread_count: 0x10, + position_x: configuration.position_x, + position_y: configuration.position_y, + zoom: configuration.zoom, + maximum_iteration_count: configuration.maximum_iteration_count, - canvas_width: canvas_width, - canvas_height: canvas_height, - scale: scale, + dump_path: configuration.dump_path, - position_x: 0.0, - position_y: 0.0, - zoom: 1.0, - maximum_iteration_count: 0x100, + sdl: sdl, + sdl_video: sdl_video, + canvas: canvas, do_draw: true, }; diff --git a/source/benoit/benoit/application/poll_events.rs b/source/benoit/benoit/application/poll_events.rs index 42e9c55..e89f003 100644 --- a/source/benoit/benoit/application/poll_events.rs +++ b/source/benoit/benoit/application/poll_events.rs @@ -27,69 +27,24 @@ extern crate sdl2; use sdl2::EventPump; use sdl2::event::Event; -use sdl2::keyboard::Scancode; impl Application { pub fn poll_events(&mut self, event_pump: &mut EventPump) -> bool { for event in event_pump.poll_iter() { - match event { + let quit = match event { Event::KeyDown { timestamp: _, window_id: _, keycode: _, - scancode, + scancode: scan_code, keymod: _, repeat: _, - } => { - let scancode = scancode.unwrap(); + } => self.handle_key(scan_code.unwrap()), + Event::Quit { .. } => true, + _ => false, + }; - match scancode { - Scancode::Escape => return true, - Scancode::X => self.dump_image(), - _ => {}, - } - - self.zoom = match scancode { - Scancode::E => self.zoom * 2.0, - Scancode::Q => self.zoom / 2.0, - _ => self.zoom, - }; - - let translate_ammount: f64 = 1.0 / 16.0 / self.zoom; - - self.position_x += match scancode { - Scancode::A => -translate_ammount, - Scancode::D => translate_ammount, - _ => 0.0, - }; - - self.position_y += match scancode { - Scancode::S => translate_ammount, - Scancode::W => -translate_ammount, - _ => 0.0, - }; - - self.maximum_iteration_count = match scancode { - Scancode::F => self.maximum_iteration_count * 0x2, - Scancode::R => self.maximum_iteration_count / 0x2, - _ => self.maximum_iteration_count, - }; - - self.do_draw = match scancode { - 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, - }; - }, - Event::Quit { .. } => return true, - _ => {}, - } + if quit { return true } } return false; diff --git a/source/benoit/benoit/application/render.rs b/source/benoit/benoit/application/render.rs index becf95b..df14024 100644 --- a/source/benoit/benoit/application/render.rs +++ b/source/benoit/benoit/application/render.rs @@ -29,8 +29,8 @@ use std::time::Instant; use std::ptr::addr_of_mut; impl Application { - pub fn render(&mut self, buffer: &mut [u32]) { - eprintln!("rendering: {}{:+}i ({}x) @ ({})", self.position_x, self.position_y, self.zoom, self.maximum_iteration_count); + 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); let mut threads = Vec::<JoinHandle<()>>::with_capacity(self.thread_count as usize); @@ -46,10 +46,10 @@ impl Application { let canvas_width = self.canvas_width; let canvas_height = self.canvas_height; - let position_x = self.position_x; - let position_y = self.position_y; - let zoom = self.zoom; - let maximum_iteration_count = self.maximum_iteration_count; + 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; diff --git a/source/benoit/benoit/configuration.rs b/source/benoit/benoit/configuration.rs new file mode 100644 index 0000000..f7c19e0 --- /dev/null +++ b/source/benoit/benoit/configuration.rs @@ -0,0 +1,39 @@ +/* + 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 load; + +pub struct Configuration { + pub thread_count: u32, + + pub canvas_width: u32, + pub canvas_height: u32, + pub scale: u32, + + pub position_x: f64, + pub position_y: f64, + pub zoom: f64, + pub maximum_iteration_count: u32, + + pub dump_path: String, +} diff --git a/source/benoit/benoit/configuration/load.rs b/source/benoit/benoit/configuration/load.rs new file mode 100644 index 0000000..51db6b1 --- /dev/null +++ b/source/benoit/benoit/configuration/load.rs @@ -0,0 +1,89 @@ +/* + Copyright 2021, 2023 Gabriel Bjørnager Jensen. + + This file is part of Benoit. + + Benoit is free software: you can redistribute it + and/or modify it under the terms of the GNU + Affero General Public License as published by + the Free Software Foundation, either version 3 + of the License, or (at your option) any later + version. + + Benoit is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without + even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU + Affero General Public License along with Benoit. + If not, see <https://www.gnu.org/licenses/>. +*/ + +use crate::benoit::configuration::Configuration; + +extern crate toml; + +use std::fs::read; +use std::str::FromStr; +use toml::{Table, Value}; + +impl Configuration { + pub fn load(path: &str) -> Configuration { + let mut configuration = Configuration { + thread_count: 0x2, + + canvas_width: 0x100, + canvas_height: 0x100, + scale: 0x1, + + position_x: 0.0, + position_y: 0.0, + zoom: 1.0, + maximum_iteration_count: 0x100, + + dump_path: "./image.webp".to_string(), + }; + + let configuration_text = match read(path) { + Ok(content) => String::from_utf8_lossy(&content).to_string(), + Err(..) => { + eprintln!("unable to read configuration file"); + return configuration; + }, + }; + + let configuration_table = Table::from_str(configuration_text.as_str()).expect("unable to parse configuration"); + + let get_integer = |buffer: &mut u32, table: &Table, name: &str| { + if !table.contains_key(name) { return } + + match configuration_table[name] { + Value::Integer(value) => *buffer = value as u32, + _ => panic!("mismatched type for {name}"), + }; + }; + + let get_float = |buffer: &mut f64, table: &Table, name: &str| { + if !table.contains_key(name) { return } + + match configuration_table[name] { + Value::Float(value) => *buffer = value, + _ => panic!("mismatched type for {name}"), + }; + }; + + 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_float(&mut configuration.position_x, &configuration_table, "position_x"); + get_float(&mut configuration.position_y, &configuration_table, "position_y"); + get_float(&mut configuration.zoom, &configuration_table, "zoom"); + + get_integer(&mut configuration.maximum_iteration_count, &configuration_table, "maximum_iteration_count"); + + return configuration; + } +} |