some optimisations

This commit is contained in:
Schrottkatze 2024-05-22 11:14:37 +02:00
parent 7234064f12
commit 5450144797
Signed by: schrottkatze
SSH key fingerprint: SHA256:hXb3t1vINBFCiDCmhRABHX5ocdbLiKyCdKI4HK2Rbbc
3 changed files with 95 additions and 66 deletions

View file

@ -7,20 +7,29 @@ pub fn mat_editor<const R: usize, const C: usize>(
id: &str, id: &str,
skip_last: bool, skip_last: bool,
) -> egui::Response { ) -> egui::Response {
egui::Grid::new(id) let mut any_change = false;
let mut r = egui::Grid::new(id)
.show(ui, |ui| { .show(ui, |ui| {
mat.row_iter_mut().enumerate().for_each(|(i, mut row)| { mat.row_iter_mut().enumerate().for_each(|(i, mut row)| {
if !skip_last || i + 1 < R { if !skip_last || i + 1 < R {
row.iter_mut().for_each(|item| { row.iter_mut().for_each(|item| {
ui.add( any_change |= ui
.add(
egui::DragValue::new(item) egui::DragValue::new(item)
.speed(0.01) .speed(0.01)
.clamp_range(-10.0..=10.0), .clamp_range(-10.0..=10.0),
); )
.changed();
}); });
ui.end_row(); ui.end_row();
} }
}) })
}) })
.response .response;
if any_change {
r.mark_changed()
}
r
} }

View file

@ -5,7 +5,7 @@ use std::{
use eframe::egui::{self, TextureOptions}; use eframe::egui::{self, TextureOptions};
use image::{DynamicImage, Pixel, Rgb, Rgb32FImage}; use image::{DynamicImage, Pixel, Rgb, Rgb32FImage};
use nalgebra::{SMatrix, Vector3, Vector4}; use nalgebra::{ComplexField, Const, Matrix, OMatrix, SMatrix, Vector3, Vector4};
use rayon::prelude::*; use rayon::prelude::*;
use image::EncodableLayout; use image::EncodableLayout;
@ -16,6 +16,7 @@ struct ProcessorInstruction {
ret: oneshot::Sender<(egui::TextureHandle, (f32, f32))>, ret: oneshot::Sender<(egui::TextureHandle, (f32, f32))>,
ctx: egui::Context, ctx: egui::Context,
handle: Option<egui::TextureHandle>, handle: Option<egui::TextureHandle>,
realloc: bool,
} }
pub struct Processor { pub struct Processor {
@ -26,6 +27,7 @@ impl Processor {
pub fn init() -> Self { pub fn init() -> Self {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
thread::spawn(|| { thread::spawn(|| {
let mut working_img = DynamicImage::new_rgb32f(1, 1);
for ProcessorInstruction { for ProcessorInstruction {
img, img,
color_matrix, color_matrix,
@ -33,51 +35,81 @@ impl Processor {
ret, ret,
ctx, ctx,
handle, handle,
realloc,
} in rx } in rx
{ {
let (width, height) = img.dimensions(); let (width, height) = img.dimensions();
// let mut r = (*img).clone(); if realloc {
let mut r = Rgb32FImage::new(width, height); working_img = DynamicImage::new_rgb32f(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); 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::<f32, Const<3>, 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(0).unwrap()) *= width as f32;
*(cols_mut.get_mut(1).unwrap()) *= height 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); let working_img = working_img.as_mut_rgb32f().unwrap();
*px = if r.x.is_sign_positive() && r.y.is_sign_positive() { match (do_pos_trans, do_color_trans) {
*img.get_pixel_checked(r.x as u32, r.y as u32) (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.])) .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(),
)
}); });
} }
(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 color_image = egui::ColorImage::from_rgb(
let image = DynamicImage::from(r).to_rgb8(); [working_img.width() as usize, working_img.height() as usize],
working_img.to_rgb8().as_bytes(),
egui::ColorImage::from_rgb( );
[image.width() as usize, image.height() as usize],
image.as_bytes(),
)
};
let handle = if let Some(mut handle) = handle { let handle = if let Some(mut handle) = handle {
handle.set(color_image, TextureOptions::default()); handle.set(color_image, TextureOptions::default());
handle handle
@ -99,6 +131,7 @@ impl Processor {
pos_matrix: SMatrix<f32, 3, 3>, pos_matrix: SMatrix<f32, 3, 3>,
ctx: egui::Context, ctx: egui::Context,
handle: Option<egui::TextureHandle>, handle: Option<egui::TextureHandle>,
realloc: bool,
) -> oneshot::Receiver<(egui::TextureHandle, (f32, f32))> { ) -> oneshot::Receiver<(egui::TextureHandle, (f32, f32))> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
@ -109,6 +142,7 @@ impl Processor {
ret: tx, ret: tx,
ctx, ctx,
handle, handle,
realloc,
}); });
dbg!(r).unwrap(); dbg!(r).unwrap();

View file

@ -64,36 +64,33 @@ impl eframe::App for App {
self.pos_matrix, self.pos_matrix,
ctx.clone(), ctx.clone(),
self.cur_res.clone(), self.cur_res.clone(),
true,
)); ));
} }
} }
} }
ui.add_space(8.); ui.add_space(8.);
let old_color_mat = self.color_matrix;
let old_pos_mat = self.pos_matrix;
ui.label("Color Matrix Editor"); ui.label("Color Matrix Editor");
let color_mat_edited = 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.add_space(8.);
ui.label("Position Matrix Editor"); ui.label("Position Matrix Editor");
let pos_mat_edited = let pos_mat_edited =
components::mat_editor(ui, &mut self.pos_matrix, "pos_matrix", true).dragged(); components::mat_editor(ui, &mut self.pos_matrix, "pos_matrix", true).changed();
mats_changed |= old_color_mat == self.color_matrix || old_pos_mat == self.pos_matrix;
if mats_changed if dbg!(self.cur_img.is_some())
&& self.cur_img.is_some() && dbg!((color_mat_edited || pos_mat_edited))
&& self.cur_res.is_some() && dbg!(self.cur_res.is_some())
&& !color_mat_edited && dbg!(self.cur_rx.is_none())
&& !pos_mat_edited
&& self.cur_rx.is_none()
{ {
self.cur_rx = Some(self.proc.exec( self.cur_rx = Some(self.proc.exec(
self.cur_img.clone().unwrap(), self.cur_img.clone().unwrap(),
self.color_matrix, dbg!(self.color_matrix),
self.pos_matrix, self.pos_matrix,
ctx.clone(), ctx.clone(),
self.cur_res.clone(), self.cur_res.clone(),
false,
)); ));
} }
}); });
@ -119,17 +116,6 @@ impl eframe::App for App {
let img = egui::Image::from_texture(sized_img); let img = egui::Image::from_texture(sized_img);
ui.add(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);
// });
// }
}); });
} }
} }