From 36d5c4db797a1962d5db75ce4003b2ad542cbfec Mon Sep 17 00:00:00 2001 From: huanld Date: Fri, 18 Sep 2026 01:21:30 +0700 Subject: [PATCH] fix(render): compose PLOTSTYLE wire-fill depth like the wire pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a display plot style maps an ACI to a fill pattern, wire fill triangles are re-emitted as PLOTSTYLE hatches. Those took depth_override raw — a per-block child label for block wires and 0.0 for top-level ones — while everything else in the hatch/wipeout pass sorts at the composed depths[insert] + label * half. The fill could land outside its host's band and get buried under its own block's masks (same shape as the block-text bug). Both the display and PDF paths now travel through wire_draw_depth / the PlotWire's composed depth, and the display cache key rides the depth generation so a DRAWORDER edit re-ranks the fills without needing a wire rebuild. --- src/io/pdf_export.rs | 8 +++++++- src/scene/mod.rs | 3 ++- src/scene/view/render.rs | 14 +++++++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/io/pdf_export.rs b/src/io/pdf_export.rs index 7d6702bf1..774ec9afa 100644 --- a/src/io/pdf_export.rs +++ b/src/io/pdf_export.rs @@ -605,6 +605,7 @@ fn append_pdf_page( emit_wire_fills( &mut ops, std::slice::from_ref(&wire.wire), + wire.draw_depth, ox, oy, plot_style, @@ -1036,6 +1037,7 @@ fn plotted_color( fn emit_wire_fills( ops: &mut Vec, wires: &[WireModel], + wire_depth: f32, ox: f64, oy: f64, plot_style: Option<&PlotStyleTable>, @@ -1090,7 +1092,11 @@ fn emit_wire_fills( line_weight_px: wire.line_weight_px, angle_offset: 0.0, scale: 1.0 / scale.max(1.0e-6), - draw_depth: wire.depth_override.unwrap_or(0.0), + // The host wire's composed draw depth (PlotWire carries + // wire_draw_depth). depth_override alone is a per-block + // child label and would sort the fill outside its block's + // band; keep the pattern fill co-sorted with its wire. + draw_depth: wire_depth, }; emit_hatch( ops, diff --git a/src/scene/mod.rs b/src/scene/mod.rs index d8b91f5f2..c68c7d03a 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -2204,7 +2204,8 @@ pub struct Scene { RefCell>>>, styled_wire_cache: RefCell>)>>, styled_hatch_cache: RefCell>>>, - styled_wire_fill_cache: RefCell>>>, + styled_wire_fill_cache: + RefCell>>>, /// Per-viewport projected wire cache for paper-space content viewports. /// Stores projected + clipped wires in paper-space coordinates. /// Maps vp_handle → (geometry_epoch, Vec). diff --git a/src/scene/view/render.rs b/src/scene/view/render.rs index 5cbeb605e..a1f79be28 100644 --- a/src/scene/view/render.rs +++ b/src/scene/view/render.rs @@ -3102,14 +3102,19 @@ impl Scene { let Some(style) = self.display_plot_style() else { return None; }; + // Depth generation rides in the key: the fills below compose their + // depth from the live depth map, which can move independently of the + // wire set (a DRAWORDER edit re-ranks without retessellating). let key = ( source_gen, style.name.to_ascii_lowercase(), pattern_scale.to_bits(), + self.draw_depth_generation(), ); if let Some(hatches) = self.styled_wire_fill_cache.borrow().get(&key) { return Some(Arc::clone(hatches)); } + let depths = self.draw_depth_map(); let mut hatches = Vec::new(); for wire in wires.iter().filter(|wire| wire.fill_is_2d_solid && wire.aci > 0) { let Some(pattern) = style @@ -3161,7 +3166,14 @@ impl Scene { line_weight_px, angle_offset: 0.0, scale: pattern_scale, - draw_depth: wire.depth_override.unwrap_or(0.0), + // Compose against the scene graph exactly like the wire + // pipeline does. The raw depth_override is a per-block + // child label (or None for top-level wires) — either way + // it would place the fill outside its host's depth band + // and let sibling wipes/masks bury it. + draw_depth: crate::scene::pipeline::wire_gpu::wire_draw_depth( + wire, &depths, + ), }); } }