use std::{ sync::{mpsc, Arc}, thread, }; use eframe::egui::{self, TextureOptions}; use image::{DynamicImage, Pixel, Rgb, Rgb32FImage}; use nalgebra::{SMatrix, Vector4}; use rayon::prelude::*; use image::EncodableLayout; struct ProcessorInstruction { img: Arc<Rgb32FImage>, color_matrix: SMatrix<f32, 3, 4>, pos_matrix: SMatrix<f32, 2, 3>, ret: oneshot::Sender<(egui::TextureHandle, (f32, f32))>, ctx: egui::Context, handle: Option<egui::TextureHandle>, } pub struct Processor { channel: mpsc::Sender<ProcessorInstruction>, } impl Processor { pub fn init() -> Self { let (tx, rx) = mpsc::channel(); thread::spawn(|| { for ProcessorInstruction { img, color_matrix, pos_matrix, ret, ctx, handle, } in rx { let (width, height) = img.dimensions(); let mut 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 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 handle = if let Some(mut handle) = handle { handle.set(color_image, TextureOptions::default()); handle } else { ctx.load_texture("res_tex", color_image, TextureOptions::default()) }; ret.send((handle, (width as f32, height as f32))).unwrap(); // (color_matrix.is_identity(f32::EPSILON), pos_matrix.is_identity(f32::EPSILON)) } }); Self { channel: tx } } pub fn exec( &self, img: Arc<Rgb32FImage>, color_matrix: SMatrix<f32, 3, 4>, pos_matrix: SMatrix<f32, 2, 3>, ctx: egui::Context, handle: Option<egui::TextureHandle>, ) -> oneshot::Receiver<(egui::TextureHandle, (f32, f32))> { let (tx, rx) = oneshot::channel(); let r = self.channel.send(ProcessorInstruction { img, color_matrix, pos_matrix, ret: tx, ctx, handle, }); dbg!(r).unwrap(); rx } }