fix(viewport): apply per-viewport layer freeze to fills, images and meshes

A content viewport that froze layers still drew those layers' hatches,
2-D solids, images, OLE frames and 3-D solids — only its wires honoured
`Viewport.frozen_layers`. A viewport meant to be empty (all content
layers frozen) leaked the whole model instead.

viewport_data_for fed content viewports the full model hatch/wipeout/
image/mesh sets with no per-viewport frozen filter. Thread the viewport's
frozen-layer set through the builders (synced_hatch_models,
exploded_insert_hatch_models, wipeout_models, image_models, mesh_models,
instanced_block_meshes) via Scene::layer_frozen_in — the same
layer-name→handle→membership test the wire path uses — and expose
*_for_viewport accessors that cache the filtered set per order-independent
frozen-set signature (viewports sharing a frozen set share the build; an
empty set returns the shared unfiltered arc, so model tiles and
non-freezing viewports are byte-identical).

Each viewport renders in its own pipeline slot with the hatch upload
gated on geometry_epoch, so a per-viewport filtered set uploads once per
epoch rather than every frame.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-20 19:01:30 +03:00
1 parent fd33810057
commit b884e33f38
4 files changed
+222 -28

No files matched your search

+25 -3
View File
@@ -568,7 +568,10 @@ impl Scene {
self.bump_geometry();
}
pub(super) fn synced_hatch_models(&self) -> Vec<HatchModel> {
pub(super) fn synced_hatch_models(
&self,
frozen: Option<&rustc_hash::FxHashSet<Handle>>,
) -> Vec<HatchModel> {
let layout_block = self.current_layout_block_handle();
let layer_hidden = |layer: &str| {
@@ -606,6 +609,11 @@ impl Scene {
if c.invisible || layer_hidden(&c.layer) {
return false;
}
// Per-viewport layer freeze: a content viewport that freezes
// this layer hides its fills too, not just its wires.
if self.layer_frozen_in(&c.layer, frozen) {
return false;
}
// Reject block-defn-only hatches (entities owned by a
// BLOCK record that's neither model nor a paper layout
// block) — they're tessellated separately via Insert
@@ -686,7 +694,7 @@ impl Scene {
// layout block and materialize its fills at world position. Shared with
// the export path so a plot draws them identically. (tint_selected =
// true applies the screen selection highlight.)
models.extend(self.exploded_insert_hatch_models(layout_block, hatch_bg, true));
models.extend(self.exploded_insert_hatch_models(layout_block, hatch_bg, true, frozen));
// Wide LwPolyline / Polyline2D bands are no longer hatch fills at
// model level: a flat band is drawn by expanding its centre-line wire
@@ -717,6 +725,7 @@ impl Scene {
layout_block: Handle,
hatch_bg: [f32; 4],
tint_selected: bool,
frozen: Option<&rustc_hash::FxHashSet<Handle>>,
) -> Vec<HatchModel> {
let layer_hidden = |layer: &str| {
self.document
@@ -748,6 +757,11 @@ impl Scene {
if ins.common.invisible || layer_hidden(&ins.common.layer) {
continue;
}
// Per-viewport freeze: an INSERT on a layer frozen in this content
// viewport hides the whole instance, its internal fills included.
if self.layer_frozen_in(&ins.common.layer, frozen) {
continue;
}
if !self.belongs_to_visible_block(
ins.common.handle,
ins.common.owner_handle,
@@ -880,7 +894,10 @@ impl Scene {
/// Wipeout fill models — rendered in a separate pass AFTER wires so that
/// wipeouts correctly mask everything below them in the draw order.
pub(crate) fn wipeout_models(&self) -> Vec<HatchModel> {
pub(crate) fn wipeout_models(
&self,
frozen: Option<&rustc_hash::FxHashSet<Handle>>,
) -> Vec<HatchModel> {
let is_paper = self.current_layout != "Model";
let bg_color: [f32; 4] = if is_paper {
self.paper_bg_color
@@ -910,6 +927,11 @@ impl Scene {
{
continue;
}
// Per-viewport freeze: a wipeout on a layer frozen in this content
// viewport is hidden along with the rest of that layer.
if self.layer_frozen_in(&entity.common().layer, frozen) {
continue;
}
// Per-entity world_offset selection so paper-layout content
// viewports still see model-block wipeouts at the right local
// coordinates (same rationale as hatches).