diff --git a/Cargo.lock b/Cargo.lock index abee3a7..1659de9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -931,6 +931,12 @@ dependencies = [ "error-code", ] +[[package]] +name = "clone-macro" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11b52aa11e0a83701c2f8a2b683c254889d8a957e7f58a5a06c5f98ebb4fc3c1" + [[package]] name = "cocoa" version = "0.25.0" @@ -3487,6 +3493,7 @@ dependencies = [ "imageproc", "nalgebra", "ordered-float", + "rayon", "stl_io", ] @@ -3869,6 +3876,7 @@ version = "0.1.0" dependencies = [ "anyhow", "bytemuck", + "clone-macro", "common", "eframe", "egui", diff --git a/TODO.md b/TODO.md index ffb2a83..b7a0eef 100644 --- a/TODO.md +++ b/TODO.md @@ -6,10 +6,14 @@ - [ ] Allow slicing multiple modals at once - [ ] Fix translation in slicer (its currently moved by pixels not mm) - [ ] Allow rotating modals -- [ ] Optimize slicer (BVH?) +- [x] Optimize slicer (BVH?) + - [x] ehh just throw rayon on it - [ ] Allow saving / loading projects - [ ] Allow deleting objects - [ ] Use instancing both for object mesh storage and rendering - [ ] Less internal dependence on GOO format - [ ] Anti-aliasing - [ ] Cache transformed points +- [ ] Rename `ui` module to `mslicer` +- [ ] Proper slice preview scaling +- [ ] Preview image generation diff --git a/slicer/Cargo.toml b/slicer/Cargo.toml index 8fd2fad..e1b7169 100644 --- a/slicer/Cargo.toml +++ b/slicer/Cargo.toml @@ -14,3 +14,4 @@ stl_io = "0.7.0" common = { path = "../common" } goo_format = { path = "../goo_format" } +rayon = "1.10.0" diff --git a/slicer/src/config.rs b/slicer/src/config.rs new file mode 100644 index 0000000..74b5f42 --- /dev/null +++ b/slicer/src/config.rs @@ -0,0 +1,33 @@ +use nalgebra::{Vector2, Vector3}; + +#[derive(Clone, Debug)] +pub struct SliceConfig { + pub platform_resolution: Vector2, + pub platform_size: Vector3, + pub slice_height: f32, + + pub exposure_config: ExposureConfig, + pub first_exposure_config: ExposureConfig, + pub first_layers: u32, +} + +#[derive(Clone, Debug)] +pub struct ExposureConfig { + pub exposure_time: f32, + pub lift_distance: f32, + pub lift_speed: f32, + pub retract_distance: f32, + pub retract_speed: f32, +} + +impl Default for ExposureConfig { + fn default() -> Self { + Self { + exposure_time: 3.0, + lift_distance: 5.0, + lift_speed: 65.0, + retract_distance: 5.0, + retract_speed: 150.0, + } + } +} diff --git a/slicer/src/lib.rs b/slicer/src/lib.rs index ae74387..75e1846 100644 --- a/slicer/src/lib.rs +++ b/slicer/src/lib.rs @@ -1,5 +1,6 @@ use nalgebra::Vector3; +pub mod config; pub mod mesh; pub mod slicer; diff --git a/slicer/src/main.rs b/slicer/src/main.rs index b9681cb..7f9ad3c 100644 --- a/slicer/src/main.rs +++ b/slicer/src/main.rs @@ -1,5 +1,7 @@ use std::{ fs::{self, File}, + io::{stdout, Write}, + thread, time::Instant, }; @@ -8,8 +10,9 @@ use common::serde::DynamicSerializer; use nalgebra::{Vector2, Vector3}; use slicer::{ + config::{ExposureConfig, SliceConfig}, mesh::load_mesh, - slicer::{slice_goo, ExposureConfig, SliceConfig}, + slicer::Slicer, Pos, }; @@ -60,16 +63,25 @@ fn main() -> Result<()> { let now = Instant::now(); - let goo = slice_goo(&slice_config, &mesh, |layer, layers| { + let slicer = Slicer::new(slice_config.clone(), mesh); + let progress = slicer.progress(); + + let goo = thread::spawn(move || slicer.slice()); + + let mut completed = 0; + while completed < progress.total() { + completed = progress.wait(); print!( - "\rLayer: {}/{layers} ({:.1}%)", - layer + 1, - (layer as f32 + 1.0) / layers as f32 * 100.0 + "\rLayer: {}/{}, {:.1}%", + completed, + progress.total(), + completed as f32 / progress.total() as f32 * 100.0 ); - }); + stdout().flush()?; + } let mut serializer = DynamicSerializer::new(); - goo.serialize(&mut serializer); + goo.join().unwrap().serialize(&mut serializer); fs::write(OUTPUT_PATH, serializer.into_inner())?; println!("\nDone. Elapsed: {:.1}s", now.elapsed().as_secs_f32()); diff --git a/slicer/src/mesh.rs b/slicer/src/mesh.rs index de452d0..24ea554 100644 --- a/slicer/src/mesh.rs +++ b/slicer/src/mesh.rs @@ -50,35 +50,33 @@ impl Mesh { let v1 = self.transform(&self.vertices[face[1] as usize]); let v2 = self.transform(&self.vertices[face[2] as usize]); - let mut dot0 = v0.z - height; - let mut dot1 = v1.z - height; - let mut dot2 = v2.z - height; + let a = v0.z - height; + let b = v1.z - height; + let c = v2.z - height; - if dot0 == 0.0 || dot1 == 0.0 || dot2 == 0.0 { - dot0 -= 0.0001; - dot1 -= 0.0001; - dot2 -= 0.0001; - } + let a_pos = a > 0.0; + let b_pos = b > 0.0; + let c_pos = c > 0.0; let mut result = [Pos::zeros(); 2]; let mut index = 0; - if dot0 * dot1 < 0.0 { - let t = dot0 / (dot0 - dot1); + if a_pos ^ b_pos { + let t = a / (a - b); let intersection = v0 + t * (v1 - v0); result[index] = intersection; index += 1; } - if dot1 * dot2 < 0.0 { - let t = dot1 / (dot1 - dot2); + if b_pos ^ c_pos { + let t = b / (b - c); let intersection = v1 + t * (v2 - v1); result[index] = intersection; index += 1; } - if dot2 * dot0 < 0.0 { - let t = dot2 / (dot2 - dot0); + if c_pos ^ a_pos { + let t = c / (c - a); let intersection = v2 + t * (v0 - v2); result[index] = intersection; } diff --git a/slicer/src/slicer.rs b/slicer/src/slicer.rs index fa54fbb..d64385f 100644 --- a/slicer/src/slicer.rs +++ b/slicer/src/slicer.rs @@ -1,166 +1,212 @@ -use nalgebra::{Vector2, Vector3}; -use ordered_float::OrderedFloat; +use std::{ + ops::Deref, + sync::{ + atomic::{AtomicU32, Ordering}, + Arc, Condvar, Mutex, + }, +}; -use crate::mesh::Mesh; +use ordered_float::OrderedFloat; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; + +use crate::{config::SliceConfig, mesh::Mesh}; use goo_format::{File as GooFile, HeaderInfo, LayerContent, LayerEncoder}; -#[derive(Clone, Debug)] -pub struct SliceConfig { - pub platform_resolution: Vector2, - pub platform_size: Vector3, - pub slice_height: f32, - - pub exposure_config: ExposureConfig, - pub first_exposure_config: ExposureConfig, - pub first_layers: u32, +pub struct Slicer { + slice_config: SliceConfig, + model: Mesh, + progress: Progress, } -#[derive(Clone, Debug)] -pub struct ExposureConfig { - pub exposure_time: f32, - pub lift_distance: f32, - pub lift_speed: f32, - pub retract_distance: f32, - pub retract_speed: f32, +#[derive(Clone)] +pub struct Progress { + inner: Arc, } -pub fn slice_goo(slice_config: &SliceConfig, model: &Mesh, progress: impl Fn(u32, u32)) -> GooFile { - let (_, max) = model.minmax_point(); - let max = model.transform(&max); - let layers = (max.z / slice_config.slice_height).ceil() as u32; +pub struct ProgressInner { + completed: AtomicU32, + total: u32, - let layers = (0..layers) - .inspect(|&layer| { - progress(layer, layers); - }) - .map(|layer| { - let height = layer as f32 * slice_config.slice_height; - let intersections = model.intersect_plane(height); + notify: Condvar, + last_completed: Mutex, +} - let segments = intersections - .chunks(2) - .map(|x| (x[0], x[1])) - .collect::>(); +impl Slicer { + pub fn new(slice_config: SliceConfig, model: Mesh) -> Self { + let max = model.transform(&model.minmax_point().1); + let layers = (max.z / slice_config.slice_height).ceil() as u32; - let mut out = Vec::new(); - for y in 0..slice_config.platform_resolution.y { - let mut intersections = segments - .iter() - .filter_map(|(a, b)| { - let y = y as f32; - if a.y <= y && b.y >= y { - let t = (y - a.y) / (b.y - a.y); - let x = a.x + t * (b.x - a.x); - Some(x) - } else if b.y <= y && a.y >= y { - let t = (y - b.y) / (a.y - b.y); - let x = b.x + t * (a.x - b.x); - Some(x) - } else { - None - } - }) + Self { + slice_config, + model, + progress: Progress { + inner: Arc::new(ProgressInner { + completed: AtomicU32::new(0), + total: layers, + + notify: Condvar::new(), + last_completed: Mutex::new(0), + }), + }, + } + } + + pub fn progress(&self) -> Progress { + self.progress.clone() + } + + pub fn slice(&self) -> GooFile { + let (slice_config, model) = (&self.slice_config, &self.model); + let layers = (0..self.progress.total) + .into_par_iter() + .inspect(|_| { + self.progress.completed.fetch_add(1, Ordering::Relaxed); + self.progress.notify.notify_all(); + }) + .map(|layer| { + let height = layer as f32 * slice_config.slice_height; + let intersections = model.intersect_plane(height); + + let segments = intersections + .chunks(2) + .map(|x| (x[0], x[1])) .collect::>(); - intersections.sort_by_key(|&x| OrderedFloat(x)); - intersections.dedup(); + let mut out = Vec::new(); + for y in 0..slice_config.platform_resolution.y { + let mut intersections = segments + .iter() + .filter_map(|(a, b)| { + let y = y as f32; + if a.y <= y && b.y >= y { + let t = (y - a.y) / (b.y - a.y); + let x = a.x + t * (b.x - a.x); + Some(x) + } else if b.y <= y && a.y >= y { + let t = (y - b.y) / (a.y - b.y); + let x = b.x + t * (a.x - b.x); + Some(x) + } else { + None + } + }) + .collect::>(); - for span in intersections.chunks_exact(2) { - let y_offset = (slice_config.platform_resolution.x * y) as u64; - out.push((y_offset + span[0] as u64, y_offset + span[1] as u64)); - } - } - - let mut encoder = LayerEncoder::new(); - - let mut last = 0; - for (start, end) in out { - if start > last { - encoder.add_run(start - last, 0); + intersections.sort_by_key(|&x| OrderedFloat(x)); + for span in intersections.chunks_exact(2) { + let y_offset = (slice_config.platform_resolution.x * y) as u64; + out.push((y_offset + span[0] as u64, y_offset + span[1] as u64)); + } } - if start > end { - eprintln!("Invalid run {}-{}", start, end); - } else { + let mut encoder = LayerEncoder::new(); + + let mut last = 0; + for (start, end) in out { + if start > last { + encoder.add_run(start - last, 0); + } + + assert!(end >= start); encoder.add_run(end - start, 255); last = end; } - } - let image_size = slice_config.platform_resolution.x as u64 - * slice_config.platform_resolution.y as u64; - encoder.add_run(image_size - last, 0); + let image_size = slice_config.platform_resolution.x as u64 + * slice_config.platform_resolution.y as u64; + encoder.add_run(image_size - last, 0); - let (data, checksum) = encoder.finish(); - let layer_exposure = if layer < slice_config.first_layers { - &slice_config.first_exposure_config - } else { - &slice_config.exposure_config - }; + let (data, checksum) = encoder.finish(); + let layer_exposure = if layer < slice_config.first_layers { + &slice_config.first_exposure_config + } else { + &slice_config.exposure_config + }; - LayerContent { - data, - checksum, - layer_position_z: slice_config.slice_height * (layer + 1) as f32, + LayerContent { + data, + checksum, + layer_position_z: slice_config.slice_height * (layer + 1) as f32, + + layer_exposure_time: layer_exposure.exposure_time, + lift_distance: layer_exposure.lift_distance, + lift_speed: layer_exposure.lift_speed, + retract_distance: layer_exposure.retract_distance, + retract_speed: layer_exposure.retract_speed, + pause_position_z: slice_config.platform_size.z, + ..Default::default() + } + }) + .collect::>(); + + let layer_time = slice_config.exposure_config.exposure_time + + slice_config.exposure_config.lift_distance / slice_config.exposure_config.lift_speed; + let bottom_layer_time = slice_config.first_exposure_config.exposure_time + + slice_config.first_exposure_config.lift_distance + / slice_config.first_exposure_config.lift_speed; + let total_time = (layers.len() as u32 - slice_config.first_layers) as f32 * layer_time + + slice_config.first_layers as f32 * bottom_layer_time; + + GooFile::new( + HeaderInfo { + x_resolution: slice_config.platform_resolution.x as u16, + y_resolution: slice_config.platform_resolution.y as u16, + x_size: slice_config.platform_size.x, + y_size: slice_config.platform_size.y, + + layer_count: layers.len() as u32, + printing_time: total_time as u32, + layer_thickness: slice_config.slice_height, + bottom_layers: slice_config.first_layers, + transition_layers: slice_config.first_layers as u16 + 1, + + exposure_time: slice_config.exposure_config.exposure_time, + lift_distance: slice_config.exposure_config.lift_distance, + lift_speed: slice_config.exposure_config.lift_speed, + retract_distance: slice_config.exposure_config.retract_distance, + retract_speed: slice_config.exposure_config.retract_speed, + + bottom_exposure_time: slice_config.first_exposure_config.exposure_time, + bottom_lift_distance: slice_config.first_exposure_config.lift_distance, + bottom_lift_speed: slice_config.first_exposure_config.lift_speed, + bottom_retract_distance: slice_config.first_exposure_config.retract_distance, + bottom_retract_speed: slice_config.first_exposure_config.retract_speed, - layer_exposure_time: layer_exposure.exposure_time, - lift_distance: layer_exposure.lift_distance, - lift_speed: layer_exposure.lift_speed, - retract_distance: layer_exposure.retract_distance, - retract_speed: layer_exposure.retract_speed, - pause_position_z: slice_config.platform_size.z, ..Default::default() - } - }) - .collect::>(); - - let layer_time = slice_config.exposure_config.exposure_time - + slice_config.exposure_config.lift_distance / slice_config.exposure_config.lift_speed; - let bottom_layer_time = slice_config.first_exposure_config.exposure_time - + slice_config.first_exposure_config.lift_distance - / slice_config.first_exposure_config.lift_speed; - let total_time = (layers.len() as u32 - slice_config.first_layers) as f32 * layer_time - + slice_config.first_layers as f32 * bottom_layer_time; - - GooFile::new( - HeaderInfo { - x_resolution: slice_config.platform_resolution.x as u16, - y_resolution: slice_config.platform_resolution.y as u16, - x_size: slice_config.platform_size.x, - y_size: slice_config.platform_size.y, - - layer_count: layers.len() as u32, - printing_time: total_time as u32, - layer_thickness: slice_config.slice_height, - bottom_layers: slice_config.first_layers, - transition_layers: slice_config.first_layers as u16 + 1, - - exposure_time: slice_config.exposure_config.exposure_time, - lift_distance: slice_config.exposure_config.lift_distance, - lift_speed: slice_config.exposure_config.lift_speed, - retract_distance: slice_config.exposure_config.retract_distance, - retract_speed: slice_config.exposure_config.retract_speed, - - bottom_exposure_time: slice_config.first_exposure_config.exposure_time, - bottom_lift_distance: slice_config.first_exposure_config.lift_distance, - bottom_lift_speed: slice_config.first_exposure_config.lift_speed, - bottom_retract_distance: slice_config.first_exposure_config.retract_distance, - bottom_retract_speed: slice_config.first_exposure_config.retract_speed, - - ..Default::default() - }, - layers, - ) -} - -impl Default for ExposureConfig { - fn default() -> Self { - Self { - exposure_time: 3.0, - lift_distance: 5.0, - lift_speed: 65.0, - retract_distance: 5.0, - retract_speed: 150.0, - } + }, + layers, + ) + } +} + +impl Deref for Progress { + type Target = ProgressInner; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl Progress { + pub fn wait(&self) -> u32 { + let mut last_completed = self + .notify + .wait(self.last_completed.lock().unwrap()) + .unwrap(); + + let current = self.completed.load(Ordering::Relaxed); + if *last_completed < current { + *last_completed = current; + } + + current + } + + pub fn completed(&self) -> u32 { + self.completed.load(Ordering::Relaxed) + } + + pub fn total(&self) -> u32 { + self.total } } diff --git a/ui/Cargo.toml b/ui/Cargo.toml index baef4ab..ad66d9d 100644 --- a/ui/Cargo.toml +++ b/ui/Cargo.toml @@ -18,3 +18,4 @@ wgpu = "0.19.4" common = { path = "../common" } goo_format = { path = "../goo_format" } slicer = { path = "../slicer" } +clone-macro = "0.1.0" diff --git a/ui/src/app.rs b/ui/src/app.rs index 505ffdb..591964f 100644 --- a/ui/src/app.rs +++ b/ui/src/app.rs @@ -1,11 +1,15 @@ use std::{ - sync::{atomic::AtomicU32, Arc, Mutex, RwLock}, + sync::{Arc, Mutex, RwLock}, time::Instant, }; use egui::{CentralPanel, Frame, Sense}; use egui_wgpu::Callback; use nalgebra::{Vector2, Vector3}; +use slicer::{ + config::{ExposureConfig, SliceConfig}, + slicer::Progress as SliceProgress, +}; use crate::{ render::{ @@ -15,27 +19,20 @@ use crate::{ windows::{self, Windows}, }; use goo_format::File as GooFile; -use slicer::slicer::{ExposureConfig, SliceConfig}; pub struct App { pub camera: Camera, pub slice_config: SliceConfig, pub meshes: Arc>>, - pub slice_progress: Option>, + pub slice_progress: Option, + pub slice_result: Arc>>, pub render_style: RenderStyle, pub fps: FpsTracker, pub windows: Windows, } -pub struct SliceProgress { - pub current: AtomicU32, - pub total: AtomicU32, - - pub result: Mutex>, -} - pub struct SliceResult { pub goo: GooFile, @@ -120,6 +117,7 @@ impl Default for App { }, fps: FpsTracker::new(), slice_progress: None, + slice_result: Arc::new(Mutex::new(None)), meshes: Arc::new(RwLock::new(Vec::new())), windows: Windows::default(), render_style: RenderStyle::Normals, diff --git a/ui/src/windows/slice_config.rs b/ui/src/windows/slice_config.rs index 5e87a5f..0003d68 100644 --- a/ui/src/windows/slice_config.rs +++ b/ui/src/windows/slice_config.rs @@ -1,6 +1,6 @@ use eframe::Frame; use egui::{Context, DragValue, Grid, Ui, Window}; -use slicer::slicer::ExposureConfig; +use slicer::config::ExposureConfig; use crate::{ app::App, diff --git a/ui/src/windows/slice_preview.rs b/ui/src/windows/slice_preview.rs index 380fc4e..d12d37e 100644 --- a/ui/src/windows/slice_preview.rs +++ b/ui/src/windows/slice_preview.rs @@ -9,93 +9,86 @@ use crate::{ }; pub fn ui(app: &mut App, ctx: &Context, _frame: &mut Frame) { - if let Some(slice_progress) = &app.slice_progress { - if let Some(result) = slice_progress.result.lock().unwrap().as_mut() { - Window::new("Slice Preview") - .resizable([true, true]) - .show(ctx, move |ui| { - ui.horizontal(|ui| { - ui.add( - Slider::new( - &mut result.slice_preview_layer, - 1..=result.goo.layers.len(), - ) + if let Some(result) = app.slice_result.lock().unwrap().as_mut() { + Window::new("Slice Preview") + .resizable([true, true]) + .show(ctx, move |ui| { + ui.horizontal(|ui| { + ui.add( + Slider::new(&mut result.slice_preview_layer, 1..=result.goo.layers.len()) .vertical() .show_value(false), + ); + + let new_preview = if result.last_preview_layer != result.slice_preview_layer { + result.last_preview_layer = result.slice_preview_layer; + let (width, height) = ( + result.goo.header.x_resolution as u32, + result.goo.header.y_resolution as u32, ); - let new_preview = if result.last_preview_layer != result.slice_preview_layer - { - result.last_preview_layer = result.slice_preview_layer; - let (width, height) = ( - result.goo.header.x_resolution as u32, - result.goo.header.y_resolution as u32, - ); + let layer_data = &result.goo.layers[result.slice_preview_layer - 1].data; + let decoder = LayerDecoder::new(layer_data); - let layer_data = - &result.goo.layers[result.slice_preview_layer - 1].data; - let decoder = LayerDecoder::new(layer_data); - - let mut image = vec![0; (width * height) as usize]; - let mut pixel = 0; - for run in decoder { - for _ in 0..run.length { - image[pixel] = run.value; - pixel += 1; - } + let mut image = vec![0; (width * height) as usize]; + let mut pixel = 0; + for run in decoder { + for _ in 0..run.length { + image[pixel] = run.value; + pixel += 1; } + } - Some(image) - } else { - None - }; + Some(image) + } else { + None + }; - egui::Frame::canvas(ui.style()).show(ui, |ui| { - let available_size = ui.available_size(); - let (rect, _response) = ui.allocate_exact_size( - Vec2::new( - available_size.x, - available_size.x / result.goo.header.x_resolution as f32 - * result.goo.header.y_resolution as f32, - ), - Sense::drag(), - ); - let callback = Callback::new_paint_callback( - rect, - SlicePreviewRenderCallback { - dimensions: Vector2::new( - result.goo.header.x_resolution as u32, - result.goo.header.y_resolution as u32, - ), - offset: result.preview_offset, - scale: result.preview_scale, - new_preview, - }, - ); - ui.painter().add(callback); - }); - }); - - ui.horizontal(|ui| { - ui.add( - DragValue::new(&mut result.slice_preview_layer) - .clamp_range(1..=result.goo.layers.len()) - .suffix(format!("/{}", result.goo.layers.len())), + egui::Frame::canvas(ui.style()).show(ui, |ui| { + let available_size = ui.available_size(); + let (rect, _response) = ui.allocate_exact_size( + Vec2::new( + available_size.x, + available_size.x / result.goo.header.x_resolution as f32 + * result.goo.header.y_resolution as f32, + ), + Sense::drag(), ); - result.slice_preview_layer += - ui.button(RichText::new("+").monospace()).clicked() as usize; - result.slice_preview_layer -= - ui.button(RichText::new("-").monospace()).clicked() as usize; - - ui.separator(); - ui.label("Offset"); - vec2_dragger(ui, result.preview_offset.as_mut(), |x| x); - - ui.separator(); - ui.label("Scale"); - ui.add(DragValue::new(&mut result.preview_scale)); + let callback = Callback::new_paint_callback( + rect, + SlicePreviewRenderCallback { + dimensions: Vector2::new( + result.goo.header.x_resolution as u32, + result.goo.header.y_resolution as u32, + ), + offset: result.preview_offset, + scale: result.preview_scale, + new_preview, + }, + ); + ui.painter().add(callback); }); }); - } + + ui.horizontal(|ui| { + ui.add( + DragValue::new(&mut result.slice_preview_layer) + .clamp_range(1..=result.goo.layers.len()) + .suffix(format!("/{}", result.goo.layers.len())), + ); + result.slice_preview_layer += + ui.button(RichText::new("+").monospace()).clicked() as usize; + result.slice_preview_layer -= + ui.button(RichText::new("-").monospace()).clicked() as usize; + + ui.separator(); + ui.label("Offset"); + vec2_dragger(ui, result.preview_offset.as_mut(), |x| x); + + ui.separator(); + ui.label("Scale"); + ui.add(DragValue::new(&mut result.preview_scale)); + }); + }); } } diff --git a/ui/src/windows/slice_progress.rs b/ui/src/windows/slice_progress.rs index fd4adb7..e25dde2 100644 --- a/ui/src/windows/slice_progress.rs +++ b/ui/src/windows/slice_progress.rs @@ -1,4 +1,4 @@ -use std::{fs::File, io::Write, sync::atomic::Ordering}; +use std::{fs::File, io::Write}; use common::serde::DynamicSerializer; use eframe::Frame; @@ -12,8 +12,7 @@ pub fn ui(app: &mut App, ctx: &Context, _frame: &mut Frame) { let mut save_complete = false; if let Some(progress) = app.slice_progress.as_ref() { - let current = progress.current.load(Ordering::Relaxed) + 1; - let total = progress.total.load(Ordering::Relaxed); + let (current, total) = (progress.completed(), progress.total()); let mut window = Window::new("Slice Progress"); @@ -33,7 +32,7 @@ pub fn ui(app: &mut App, ctx: &Context, _frame: &mut Frame) { } else { ui.label("Slicing complete!"); if ui.button("Save").clicked() { - let result = progress.result.lock().unwrap().take().unwrap(); + let result = app.slice_result.lock().unwrap().take().unwrap(); if let Some(path) = FileDialog::new().save_file() { let mut file = File::create(path).unwrap(); let mut serializer = DynamicSerializer::new(); diff --git a/ui/src/windows/top_bar.rs b/ui/src/windows/top_bar.rs index 36fa8ab..09d0334 100644 --- a/ui/src/windows/top_bar.rs +++ b/ui/src/windows/top_bar.rs @@ -1,19 +1,14 @@ -use std::{ - sync::{ - atomic::{AtomicU32, Ordering}, - Arc, Mutex, - }, - thread, -}; +use std::thread; +use clone_macro::clone; use eframe::Frame; use egui::{Context, TopBottomPanel, Ui}; use nalgebra::Vector2; use rfd::FileDialog; -use slicer::{slicer::slice_goo, Pos}; +use slicer::{slicer::Slicer, Pos}; use crate::{ - app::{App, SliceProgress, SliceResult}, + app::{App, SliceResult}, render::rendered_mesh::RenderedMesh, }; @@ -83,26 +78,26 @@ pub fn ui(app: &mut App, ctx: &Context, _frame: &mut Frame) { mesh.position.z - app.slice_config.slice_height, ); - let progress = Arc::new(SliceProgress { - current: AtomicU32::new(0), - total: AtomicU32::new(0), - result: Mutex::new(None), - }); - app.slice_progress = Some(progress.clone()); + // let progress = Arc::new(SliceProgress { + // current: AtomicU32::new(0), + // total: AtomicU32::new(0), + // result: Mutex::new(None), + // }); + // app.slice_progress = Some(progress.clone()); - thread::spawn(move || { - let goo = slice_goo(&slice_config, &mesh, |current, total| { - progress.current.store(current, Ordering::Relaxed); - progress.total.store(total, Ordering::Relaxed); - }); - progress.result.lock().unwrap().replace(SliceResult { + let slicer = Slicer::new(slice_config, mesh); + app.slice_progress = Some(slicer.progress()); + + thread::spawn(clone!([{ app.slice_result } as slice_result], move || { + let goo = slicer.slice(); + slice_result.lock().unwrap().replace(SliceResult { goo, slice_preview_layer: 0, last_preview_layer: 0, preview_offset: Vector2::new(0.0, 0.0), preview_scale, }); - }); + })); } }); });