diff --git a/src/components.rs b/src/components.rs index 28f23af..28ab0e1 100644 --- a/src/components.rs +++ b/src/components.rs @@ -7,20 +7,29 @@ pub fn mat_editor( id: &str, skip_last: bool, ) -> egui::Response { - egui::Grid::new(id) + let mut any_change = false; + let mut r = egui::Grid::new(id) .show(ui, |ui| { mat.row_iter_mut().enumerate().for_each(|(i, mut row)| { if !skip_last || i + 1 < R { row.iter_mut().for_each(|item| { - ui.add( - egui::DragValue::new(item) - .speed(0.01) - .clamp_range(-10.0..=10.0), - ); + any_change |= ui + .add( + egui::DragValue::new(item) + .speed(0.01) + .clamp_range(-10.0..=10.0), + ) + .changed(); }); ui.end_row(); } }) }) - .response + .response; + + if any_change { + r.mark_changed() + } + + r } diff --git a/src/img_processor.rs b/src/img_processor.rs index 0dfb20a..ba77751 100644 --- a/src/img_processor.rs +++ b/src/img_processor.rs @@ -5,7 +5,7 @@ use std::{ use eframe::egui::{self, TextureOptions}; use image::{DynamicImage, Pixel, Rgb, Rgb32FImage}; -use nalgebra::{SMatrix, Vector3, Vector4}; +use nalgebra::{ComplexField, Const, Matrix, OMatrix, SMatrix, Vector3, Vector4}; use rayon::prelude::*; use image::EncodableLayout; @@ -16,6 +16,7 @@ struct ProcessorInstruction { ret: oneshot::Sender<(egui::TextureHandle, (f32, f32))>, ctx: egui::Context, handle: Option, + realloc: bool, } pub struct Processor { @@ -26,6 +27,7 @@ impl Processor { pub fn init() -> Self { let (tx, rx) = mpsc::channel(); thread::spawn(|| { + let mut working_img = DynamicImage::new_rgb32f(1, 1); for ProcessorInstruction { img, color_matrix, @@ -33,51 +35,81 @@ impl Processor { ret, ctx, handle, + realloc, } in rx { let (width, height) = img.dimensions(); - // let mut r = (*img).clone(); - let mut r = Rgb32FImage::new(width, height); - if !pos_matrix.is_identity(f32::EPSILON) && pos_matrix.is_invertible() { - let mut inv_mat = pos_matrix.try_inverse().unwrap(); - let mut cols_mut = inv_mat.column_part_mut(2, 2); + if realloc { + working_img = DynamicImage::new_rgb32f(width, height); + } + + let do_pos_trans = + !pos_matrix.is_identity(f32::EPSILON) && pos_matrix.is_invertible(); + let do_color_trans = !color_matrix.is_identity(f32::EPSILON); + + let mut inv_pos_mat = OMatrix::, Const<3>>::identity(); + if do_pos_trans { + inv_pos_mat = pos_matrix.try_inverse().unwrap(); + let mut cols_mut = inv_pos_mat.column_part_mut(2, 2); *(cols_mut.get_mut(0).unwrap()) *= width as f32; *(cols_mut.get_mut(1).unwrap()) *= height as f32; - - r.par_enumerate_pixels_mut().for_each(|(x, y, px)| { - let r = inv_mat * Vector3::new(x as f32, y as f32, 1.0); - *px = if r.x.is_sign_positive() && r.y.is_sign_positive() { - *img.get_pixel_checked(r.x as u32, r.y as u32) - .unwrap_or(&Rgb([0., 0., 0.])) - } else { - Rgb([0., 0., 0.]) - }; - }); - } else { - r = (*img).clone() } - if !color_matrix.is_identity(f32::EPSILON) { - r.par_pixels_mut().for_each(|px| { - *px = Rgb::from( - TryInto::<[f32; 3]>::try_into( - (color_matrix * Vector4::new(px.0[0], px.0[1], px.0[2], 1.)) - .as_slice(), - ) - .unwrap(), - ) - }); + { + let working_img = working_img.as_mut_rgb32f().unwrap(); + match (do_pos_trans, do_color_trans) { + (true, true) => { + working_img + .par_enumerate_pixels_mut() + .for_each(|(x, y, px)| { + let org_pos = + inv_pos_mat * Vector3::new(x as f32, y as f32, 1.0); + + let Rgb([r, g, b]) = *img + .get_pixel_checked( + org_pos.x.abs() as u32 % width, + org_pos.y.abs() as u32 % height, + ) + .unwrap_or(&Rgb([0., 0., 0.])); + *px = Rgb::from(Into::<[f32; 3]>::into( + color_matrix * Vector4::new(r, g, b, 1.0), + )); + }) + } + (true, false) => { + working_img + .par_enumerate_pixels_mut() + .for_each(|(x, y, px)| { + let r = inv_pos_mat * Vector3::new(x as f32, y as f32, 1.0); + *px = *img + .get_pixel_checked( + r.x.abs() as u32 % width, + r.y.abs() as u32 % height, + ) + .unwrap_or(&Rgb([0., 0., 0.])) + }); + } + (false, true) => { + working_img + .par_enumerate_pixels_mut() + .for_each(|(x, y, px)| { + let Rgb([r, g, b]) = *img.get_pixel(x, y); + *px = Rgb::from(Into::<[f32; 3]>::into( + color_matrix * Vector4::new(r, g, b, 1.0), + )); + }); + } + (false, false) => { + *working_img = (*img).clone(); + } + } } - let color_image = { - let image = DynamicImage::from(r).to_rgb8(); - - egui::ColorImage::from_rgb( - [image.width() as usize, image.height() as usize], - image.as_bytes(), - ) - }; + let color_image = egui::ColorImage::from_rgb( + [working_img.width() as usize, working_img.height() as usize], + working_img.to_rgb8().as_bytes(), + ); let handle = if let Some(mut handle) = handle { handle.set(color_image, TextureOptions::default()); handle @@ -99,6 +131,7 @@ impl Processor { pos_matrix: SMatrix, ctx: egui::Context, handle: Option, + realloc: bool, ) -> oneshot::Receiver<(egui::TextureHandle, (f32, f32))> { let (tx, rx) = oneshot::channel(); @@ -109,6 +142,7 @@ impl Processor { ret: tx, ctx, handle, + realloc, }); dbg!(r).unwrap(); diff --git a/src/lib.rs b/src/lib.rs index f119682..50c333a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,36 +64,33 @@ impl eframe::App for App { self.pos_matrix, ctx.clone(), self.cur_res.clone(), + true, )); } } } ui.add_space(8.); - let old_color_mat = self.color_matrix; - let old_pos_mat = self.pos_matrix; ui.label("Color Matrix Editor"); let color_mat_edited = - components::mat_editor(ui, &mut self.color_matrix, "color_matrix", false).dragged(); + components::mat_editor(ui, &mut self.color_matrix, "color_matrix", false).changed(); ui.add_space(8.); ui.label("Position Matrix Editor"); let pos_mat_edited = - components::mat_editor(ui, &mut self.pos_matrix, "pos_matrix", true).dragged(); - mats_changed |= old_color_mat == self.color_matrix || old_pos_mat == self.pos_matrix; + components::mat_editor(ui, &mut self.pos_matrix, "pos_matrix", true).changed(); - if mats_changed - && self.cur_img.is_some() - && self.cur_res.is_some() - && !color_mat_edited - && !pos_mat_edited - && self.cur_rx.is_none() + if dbg!(self.cur_img.is_some()) + && dbg!((color_mat_edited || pos_mat_edited)) + && dbg!(self.cur_res.is_some()) + && dbg!(self.cur_rx.is_none()) { self.cur_rx = Some(self.proc.exec( self.cur_img.clone().unwrap(), - self.color_matrix, + dbg!(self.color_matrix), self.pos_matrix, ctx.clone(), self.cur_res.clone(), + false, )); } }); @@ -119,17 +116,6 @@ impl eframe::App for App { let img = egui::Image::from_texture(sized_img); ui.add(img); } - // if let Some(dimensions) = self.cur_img_size { - // egui::Frame::canvas(ui.style()).show(ui, |ui| { - // let (rect, response) = ui.allocate_exact_size(dimensions, egui::Sense::drag()); - - // let callback = egui_wgpu::Callback::new_paint_callback( - // rect, - // CustomTriangleCallback { angle: 0.5 }, - // ); - // ui.painter().add(callback); - // }); - // } }); } }