diff --git a/.cargo-husky/hooks/commit-msg b/.cargo-husky/hooks/commit-msg old mode 100755 new mode 100644 diff --git a/.cargo-husky/hooks/pre-commit b/.cargo-husky/hooks/pre-commit old mode 100644 new mode 100755 diff --git a/Cargo.toml b/Cargo.toml index 5e08f37..22ba39a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,10 +16,7 @@ anyhow = "1.0.75" chrono = { version = "0.4.31", default-features = false, features = ["clock"] } # image loading and saving -image = { version = "0.24.7", default-features = false, features = [ - "png", - "jpeg", -] } +image = { version = "0.24.7", default-features = false, features = ["png", "jpeg"] } # logging log = "0.4.20" diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 22a07e2..a4a1a3e 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -11,9 +11,10 @@ use egui::{ }; use egui::{CentralPanel, Color32, ColorImage, ImageData, Sense, TextureHandle, TextureOptions}; use egui_file::FileDialog; +use image::{ImageBuffer, RgbImage}; use std::path::PathBuf; use std::sync::atomic::{AtomicU16, Ordering}; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; pub struct App { current_tab: usize, @@ -23,10 +24,12 @@ pub struct App { rendering_thread: Option>, opened_file: Option, open_file_dialog: Option, + save_img_dialog: Option, render_size: [usize; 2], rendering_progress: Arc, preview_zoom: f32, preview_position: Vec2, + image_buffer: Arc>, } impl App { @@ -53,6 +56,12 @@ impl App { TextureOptions::default(), ); + // Create a dummy ImageBuffer for illustration purposes + let image_buffer = Arc::new(Mutex::new(ImageBuffer::new( + render_size[0] as u32, + render_size[1] as u32, + ))); + Ok(Self { current_tab: 0, scene, @@ -63,8 +72,10 @@ impl App { rendering_thread: None, opened_file: None, open_file_dialog: None, + save_img_dialog: None, render_size, rendering_progress: Arc::new(AtomicU16::new(0)), + image_buffer, }) } } @@ -96,20 +107,33 @@ impl eframe::App for App { } ui.with_layout(Layout::right_to_left(Align::Center), |ui| { - if ui - .add_enabled(self.current_tab == 0, Button::new("Render")) - .on_hover_text("Start rendering") - .clicked() - { - self.render(ctx.clone()); - self.current_tab = 1; - } - if self.rendering_progress.load(Ordering::Relaxed) == u16::MAX + if self.current_tab == 0 { + if ui + .add(Button::new("Render")) + .on_hover_text("Start rendering") + .clicked() + { + self.render(ctx.clone()); + self.current_tab = 1; + } + } else if self.rendering_progress.load(Ordering::Relaxed) == u16::MAX && ui.button("Export").clicked() { log::info!("Exporting image"); - //Export the shown image to a file + let mut dialog = FileDialog::save_file(None).default_filename("Rendered-Image.png"); + dialog.open(); + self.save_img_dialog = Some(dialog); } + + if let Some(dialog) = &mut self.save_img_dialog { + if dialog.show(ctx).selected() { + if let Some(file) = dialog.path() { + log::info!("Saving image to {:?}", file); + self.image_buffer.lock().unwrap().save(file).unwrap(); + } + } + } + ui.add( ProgressBar::new( self.rendering_progress.load(Ordering::Relaxed) as f32 diff --git a/src/ui/render.rs b/src/ui/render.rs index ff5ec9b..d601276 100644 --- a/src/ui/render.rs +++ b/src/ui/render.rs @@ -4,6 +4,7 @@ use std::sync::{ }; use egui::{Color32, ColorImage, ImageData, TextureOptions}; + use log::{debug, info}; use rayon::iter::{IntoParallelIterator, ParallelBridge, ParallelIterator}; @@ -25,6 +26,7 @@ impl super::App { let render_size = self.render_size; let block_size = [render_size[0] / 10, render_size[1] / 10]; let rendering_progress = self.rendering_progress.clone(); + let image_buffer = self.image_buffer.clone(); rendering_progress.store(0, Ordering::Relaxed); @@ -82,11 +84,24 @@ impl super::App { [x_block * block_size[0], y_block * block_size[1]], ImageData::Color(Arc::new(ColorImage { size: block_size, - pixels, + pixels: pixels.clone(), })), TextureOptions::default(), ); - + let mut bufferlock = image_buffer.lock().unwrap(); + for x in 0..block_size[0] { + for y in 0..block_size[1] { + bufferlock.put_pixel( + (x_block * block_size[0] + x) as u32, + (y_block * block_size[1] + y) as u32, + image::Rgb([ + pixels[x + y * block_size[0]].r(), + pixels[x + y * block_size[0]].g(), + pixels[x + y * block_size[0]].b(), + ]), + ); + } + } ctx.request_repaint(); });