diff --git a/Tests/Res128/swap128_res128.png b/Tests/Res128/swap128_res128.png new file mode 100644 index 0000000..1527eab Binary files /dev/null and b/Tests/Res128/swap128_res128.png differ diff --git a/Tests/Res128/swap2_res128.png b/Tests/Res128/swap2_res128.png new file mode 100644 index 0000000..70c593e Binary files /dev/null and b/Tests/Res128/swap2_res128.png differ diff --git a/Tests/Res128/swap4_res128.png b/Tests/Res128/swap4_res128.png new file mode 100644 index 0000000..0be1012 Binary files /dev/null and b/Tests/Res128/swap4_res128.png differ diff --git a/Tests/Res128/swap8_res128.png b/Tests/Res128/swap8_res128.png new file mode 100644 index 0000000..1848770 Binary files /dev/null and b/Tests/Res128/swap8_res128.png differ diff --git a/Tests/Res256/swap128_res256.png b/Tests/Res256/swap128_res256.png new file mode 100644 index 0000000..30f52d2 Binary files /dev/null and b/Tests/Res256/swap128_res256.png differ diff --git a/Tests/Res256/swap2_res256.png b/Tests/Res256/swap2_res256.png new file mode 100644 index 0000000..95e2001 Binary files /dev/null and b/Tests/Res256/swap2_res256.png differ diff --git a/Tests/Res256/swap4_res256.png b/Tests/Res256/swap4_res256.png new file mode 100644 index 0000000..3d14488 Binary files /dev/null and b/Tests/Res256/swap4_res256.png differ diff --git a/Tests/Res256/swap8_res256.png b/Tests/Res256/swap8_res256.png new file mode 100644 index 0000000..7173c6a Binary files /dev/null and b/Tests/Res256/swap8_res256.png differ diff --git a/src/app/calculate/mod.rs b/src/app/calculate/mod.rs index 717d98d..a9ca8a3 100644 --- a/src/app/calculate/mod.rs +++ b/src/app/calculate/mod.rs @@ -90,7 +90,10 @@ pub enum ProgressMsg { data: Vec, }, UpdateAssignments(Vec), - Done(Preset), // result directory + Done { + preset: Preset, + elapsed_seconds: f32, + }, Error(String), Cancelled, } @@ -101,7 +104,7 @@ impl ProgressMsg { ProgressMsg::Progress(_) => "progress", ProgressMsg::UpdatePreview { .. } => "update_preview", ProgressMsg::UpdateAssignments(_) => "update_assignments", - ProgressMsg::Done(_) => "done", + ProgressMsg::Done { .. } => "done", ProgressMsg::Error(_) => "error", ProgressMsg::Cancelled => "cancelled", } @@ -274,18 +277,21 @@ pub fn process_optimal( //let dir_name = util::save_result(target, "todo".to_string(), source, assignments, img)?; - tx.send(ProgressMsg::Done(Preset { - inner: UnprocessedPreset { - name: unprocessed.name, - width: settings.sidelen, - height: settings.sidelen, - source_img: source_pixels - .into_iter() - .flat_map(|(r, g, b)| [r, g, b]) - .collect(), + tx.send(ProgressMsg::Done { + preset: Preset { + inner: UnprocessedPreset { + name: unprocessed.name, + width: settings.sidelen, + height: settings.sidelen, + source_img: source_pixels + .into_iter() + .flat_map(|(r, g, b)| [r, g, b]) + .collect(), + }, + assignments: assignments.clone(), }, - assignments: assignments.clone(), - })); + elapsed_seconds: 0.0, + }); // println!( // "finished in {:.2?} seconds", @@ -347,7 +353,9 @@ impl Pixel { } } -const SWAPS_PER_GENERATION_PER_PIXEL: usize = 128; +const SWAPS_PER_GENERATION_PER_PIXEL: usize = 8; + +use std::time::Instant; pub fn process_genetic( unprocessed: UnprocessedPreset, @@ -355,6 +363,7 @@ pub fn process_genetic( tx: &mut S, #[cfg(not(target_arch = "wasm32"))] cancel: Arc, ) -> Result<(), Box> { + let now = Instant::now(); let source_img = image::ImageBuffer::from_vec( unprocessed.width, unprocessed.height, @@ -384,14 +393,17 @@ pub fn process_genetic( let mut rng = frand::Rand::with_seed(12345); let swaps_per_generation = SWAPS_PER_GENERATION_PER_PIXEL * pixels.len(); + let mut assignments = vec![0; pixels.len()]; + let positions: Vec<(u16, u16)> = (0..pixels.len()) + .map(|i| ((i as u32 % settings.sidelen) as u16, (i as u32 / settings.sidelen) as u16)) + .collect(); let mut max_dist = settings.sidelen; loop { let mut swaps_made = 0; for _ in 0..swaps_per_generation { let apos = rng.gen_range(0..pixels.len() as u32) as usize; - let ax = apos as u16 % settings.sidelen as u16; - let ay = apos as u16 / settings.sidelen as u16; + let (ax, ay) = positions[apos]; let bx = (ax as i16 + rng.gen_range(-(max_dist as i16)..(max_dist as i16 + 1))) .clamp(0, settings.sidelen as i16 - 1) as u16; let by = (ay as i16 + rng.gen_range(-(max_dist as i16)..(max_dist as i16 + 1))) @@ -431,29 +443,35 @@ pub fn process_genetic( if cancel.load(std::sync::atomic::Ordering::Relaxed) { println!("cancelled"); tx.send(ProgressMsg::Cancelled); + let elapsed_time = now.elapsed(); + println!("Running morph() took {:.3} seconds.", elapsed_time.as_secs_f32()); return Ok(()); } } - let assignments = pixels - .iter() - .map(|p| p.src_y as usize * settings.sidelen as usize + p.src_x as usize) - .collect::>(); + for (i, p) in pixels.iter().enumerate() { + assignments[i] = p.src_y as usize * settings.sidelen as usize + p.src_x as usize; + } //debug_print(format!("max_dist = {max_dist}, swaps made = {swaps_made}")); if max_dist < 4 && swaps_made < 10 { //let dir_name = util::save_result(target, base_name, source, assignments, img)?; - tx.send(ProgressMsg::Done(Preset { - inner: UnprocessedPreset { - name: unprocessed.name, - width: settings.sidelen, - height: settings.sidelen, - source_img: source_pixels - .iter() - .flat_map(|(r, g, b)| [*r, *g, *b]) - .collect(), + let elapsed_time = now.elapsed(); + tx.send(ProgressMsg::Done { + preset: Preset { + inner: UnprocessedPreset { + name: unprocessed.name, + width: settings.sidelen, + height: settings.sidelen, + source_img: source_pixels + .iter() + .flat_map(|(r, g, b)| [*r, *g, *b]) + .collect(), + }, + assignments: assignments.clone(), }, - assignments: assignments.clone(), - })); + elapsed_seconds: elapsed_time.as_secs_f32(), + }); + //println!("Running morph() took {:.3} seconds.", elapsed_time.as_secs_f32()); return Ok(()); } let data = make_new_img(&source_pixels, &assignments, settings.sidelen); @@ -503,4 +521,4 @@ pub fn process( Algorithm::Optimal => process_optimal(unprocessed, settings, tx), Algorithm::Genetic => process_genetic(unprocessed, settings, tx), } -} +} \ No newline at end of file diff --git a/src/app/gui.rs b/src/app/gui.rs index 6fc027d..ae5e973 100644 --- a/src/app/gui.rs +++ b/src/app/gui.rs @@ -57,6 +57,7 @@ pub(crate) struct GuiState { error_message: Option, has_obamified_once: bool, + last_processing_time: Option, } impl GuiState { @@ -84,6 +85,7 @@ impl GuiState { current_preset, error_message: None, has_obamified_once, + last_processing_time: None, } } @@ -306,7 +308,7 @@ impl App for ObamifyApp { self.sim.set_assignments(assignments, self.size.0) } ProgressMsg::Progress(_) => todo!(), - ProgressMsg::Done(_) => todo!(), + ProgressMsg::Done { .. } => todo!(), ProgressMsg::Error(_) => todo!(), } } @@ -386,7 +388,7 @@ impl App for ObamifyApp { let name = self.sim.name(); if name.chars().count() > 13 { let truncated: String = name.chars().take(10).collect(); - format!("{truncated}…") + format!("{truncated}...") } else { name.clone() } @@ -546,6 +548,12 @@ impl App for ObamifyApp { .ok(); } } + + // Display last processing time if available + if let Some(elapsed) = self.gui.last_processing_time { + ui.separator(); + ui.label(format!("⏱ Obamification processing time: {:.3}s", elapsed)); + } } } }, @@ -824,7 +832,7 @@ impl App for ObamifyApp { ui.set_min_width(ui.available_width().min(400.0)); while let Some(msg) = self.get_latest_msg() { match msg { - ProgressMsg::Done(new_preset) => { + ProgressMsg::Done { preset: new_preset, elapsed_seconds } => { self.preview_image = None; self.resize_textures( device, @@ -841,6 +849,7 @@ impl App for ObamifyApp { ); self.gui.animate = true; self.gui.has_obamified_once = true; + self.gui.last_processing_time = Some(elapsed_seconds); self.gui.hide_progress_modal(); ui.close(); break; @@ -1402,4 +1411,4 @@ pub fn blend_rgb_images(a: &SourceImg, b: &SourceImg, alpha: f32) -> SourceImg { } out -} +} \ No newline at end of file