use crate::{
MainWindow, SolidPreviewModel,
bridge::render_thread::{PlanesOwner, RenderContext},
gui::{
editor,
solid_preview::{
diagram_wiring::{DiagramFacetTier, DiagramHoverText, DiagramPick},
preview_state::{PickBuffer, PreviewFrame, PreviewSink, SolidLastSolved},
},
},
};
use indicatrix::geometry::plane::GpuFacetPlane;
use slint::{ComponentHandle, Weak};
use std::sync::{Arc, Mutex};
pub(super) struct SlintSolidSink {
pub(super) ui: Weak<MainWindow>,
pub(super) pick: Arc<Mutex<Option<PickBuffer>>>,
pub(super) last_solved: SolidLastSolved,
pub(super) diagram_pick: DiagramPick,
pub(super) diagram_hover_text: DiagramHoverText,
pub(super) diagram_facet_tier: DiagramFacetTier,
pub(super) diagram_tooth_pick: DiagramPick,
pub(super) hover_text: Arc<Mutex<Vec<String>>>,
pub(super) facet_tier: Arc<Mutex<Vec<Option<usize>>>>,
pub(super) render_ctx: Arc<Mutex<RenderContext>>,
pub(super) solid_active_planes: Arc<Mutex<Option<Arc<Vec<GpuFacetPlane>>>>>,
pub(super) trace_active_planes: Arc<Mutex<Option<Arc<Vec<GpuFacetPlane>>>>>,
pub(super) mesh_bounding_radius: Arc<Mutex<f64>>,
}
pub(super) fn planes_generations_match(
trace: &Mutex<Option<Arc<Vec<GpuFacetPlane>>>>,
solid: &Mutex<Option<Arc<Vec<GpuFacetPlane>>>>,
) -> bool {
let trace = trace
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.clone();
let solid = solid
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.clone();
match (trace, solid) {
(Some(trace), Some(solid)) => Arc::ptr_eq(&trace, &solid),
_ => true,
}
}
fn sync_planes_and_check_trace_match(
planes: &[(glam::Vec3, f32)],
render_ctx: &Mutex<RenderContext>,
solid_active_planes: &Mutex<Option<Arc<Vec<GpuFacetPlane>>>>,
trace_active_planes: &Mutex<Option<Arc<Vec<GpuFacetPlane>>>>,
generation: u64,
) -> bool {
if !planes.is_empty() {
let converted: Vec<GpuFacetPlane> = planes
.iter()
.map(|&(normal, offset)| GpuFacetPlane::new(normal, -offset))
.collect();
let mut ctx = render_ctx
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
if generation != 0 && ctx.active_planes.as_ref() != &converted {
let design_gear = ctx.design_gear;
if ctx.claim_active_planes(
Arc::new(converted),
design_gear,
PlanesOwner::Editor { generation },
) {
ctx.dirty = true;
}
}
*solid_active_planes
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) =
Some(Arc::clone(&ctx.active_planes));
}
planes_generations_match(trace_active_planes, solid_active_planes)
}
fn store_if_some<T>(state: &Mutex<Option<T>>, value: Option<T>) {
if let Some(value) = value {
*state
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) = Some(value);
}
}
impl PreviewSink for SlintSolidSink {
fn apply(&self, frame: PreviewFrame) {
let PreviewFrame {
image,
has_solid,
status,
solved,
stale,
pick,
edges_image,
diagram_image,
has_diagram,
diagram_pick,
diagram_tooth_pick,
diagram_hover_text,
diagram_facet_tier,
planes,
hover_text,
facet_tier,
generation,
mesh_bounding_radius,
} = frame;
let pick_state = Arc::clone(&self.pick);
let last_solved_state = Arc::clone(&self.last_solved);
let diagram_pick_state = Arc::clone(&self.diagram_pick);
let diagram_tooth_pick_state = Arc::clone(&self.diagram_tooth_pick);
let diagram_hover_text_state = Arc::clone(&self.diagram_hover_text);
let diagram_facet_tier_state = Arc::clone(&self.diagram_facet_tier);
let hover_text_state = Arc::clone(&self.hover_text);
let facet_tier_state = Arc::clone(&self.facet_tier);
let render_ctx_state = Arc::clone(&self.render_ctx);
let solid_active_planes_state = Arc::clone(&self.solid_active_planes);
let trace_active_planes_state = Arc::clone(&self.trace_active_planes);
let mesh_bounding_radius_state = Arc::clone(&self.mesh_bounding_radius);
let _ = self.ui.upgrade_in_event_loop(move |ui| {
*pick_state
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) = Some(pick);
*mesh_bounding_radius_state
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) = mesh_bounding_radius;
if let Some(masts) = solved.as_ref() {
editor::apply_matching_preview_frame(&ui, &render_ctx_state, generation, masts);
}
*last_solved_state
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) = solved;
store_if_some(&diagram_pick_state, diagram_pick);
store_if_some(&diagram_tooth_pick_state, diagram_tooth_pick);
store_if_some(&diagram_hover_text_state, diagram_hover_text);
store_if_some(&diagram_facet_tier_state, diagram_facet_tier);
*hover_text_state
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) = hover_text;
*facet_tier_state
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) = facet_tier;
let trace_matches = sync_planes_and_check_trace_match(
&planes,
&render_ctx_state,
&solid_active_planes_state,
&trace_active_planes_state,
generation,
);
ui.global::<SolidPreviewModel>()
.set_trace_matches_solid(trace_matches);
ui.global::<SolidPreviewModel>()
.set_image(slint::Image::from_rgba8(image));
ui.global::<SolidPreviewModel>().set_has_solid(has_solid);
ui.global::<SolidPreviewModel>().set_status(status.into());
ui.global::<SolidPreviewModel>().set_stale(stale);
if let Some(edges_image) = edges_image {
ui.global::<SolidPreviewModel>()
.set_edges_image(slint::Image::from_rgba8(edges_image));
ui.global::<SolidPreviewModel>().set_has_solid_edges(true);
} else {
ui.global::<SolidPreviewModel>().set_has_solid_edges(false);
}
if let Some(diagram_image) = diagram_image {
ui.global::<SolidPreviewModel>()
.set_diagram_image(slint::Image::from_rgba8(diagram_image));
}
ui.global::<SolidPreviewModel>()
.set_has_diagram(has_diagram);
});
}
}