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:
parent
fd33810057
commit
b884e33f38
4 changed files with 222 additions and 28 deletions
|
|
@ -568,7 +568,10 @@ impl Scene {
|
||||||
self.bump_geometry();
|
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 layout_block = self.current_layout_block_handle();
|
||||||
|
|
||||||
let layer_hidden = |layer: &str| {
|
let layer_hidden = |layer: &str| {
|
||||||
|
|
@ -606,6 +609,11 @@ impl Scene {
|
||||||
if c.invisible || layer_hidden(&c.layer) {
|
if c.invisible || layer_hidden(&c.layer) {
|
||||||
return false;
|
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
|
// Reject block-defn-only hatches (entities owned by a
|
||||||
// BLOCK record that's neither model nor a paper layout
|
// BLOCK record that's neither model nor a paper layout
|
||||||
// block) — they're tessellated separately via Insert
|
// block) — they're tessellated separately via Insert
|
||||||
|
|
@ -686,7 +694,7 @@ impl Scene {
|
||||||
// layout block and materialize its fills at world position. Shared with
|
// layout block and materialize its fills at world position. Shared with
|
||||||
// the export path so a plot draws them identically. (tint_selected =
|
// the export path so a plot draws them identically. (tint_selected =
|
||||||
// true applies the screen selection highlight.)
|
// 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
|
// Wide LwPolyline / Polyline2D bands are no longer hatch fills at
|
||||||
// model level: a flat band is drawn by expanding its centre-line wire
|
// model level: a flat band is drawn by expanding its centre-line wire
|
||||||
|
|
@ -717,6 +725,7 @@ impl Scene {
|
||||||
layout_block: Handle,
|
layout_block: Handle,
|
||||||
hatch_bg: [f32; 4],
|
hatch_bg: [f32; 4],
|
||||||
tint_selected: bool,
|
tint_selected: bool,
|
||||||
|
frozen: Option<&rustc_hash::FxHashSet<Handle>>,
|
||||||
) -> Vec<HatchModel> {
|
) -> Vec<HatchModel> {
|
||||||
let layer_hidden = |layer: &str| {
|
let layer_hidden = |layer: &str| {
|
||||||
self.document
|
self.document
|
||||||
|
|
@ -748,6 +757,11 @@ impl Scene {
|
||||||
if ins.common.invisible || layer_hidden(&ins.common.layer) {
|
if ins.common.invisible || layer_hidden(&ins.common.layer) {
|
||||||
continue;
|
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(
|
if !self.belongs_to_visible_block(
|
||||||
ins.common.handle,
|
ins.common.handle,
|
||||||
ins.common.owner_handle,
|
ins.common.owner_handle,
|
||||||
|
|
@ -880,7 +894,10 @@ impl Scene {
|
||||||
|
|
||||||
/// Wipeout fill models — rendered in a separate pass AFTER wires so that
|
/// Wipeout fill models — rendered in a separate pass AFTER wires so that
|
||||||
/// wipeouts correctly mask everything below them in the draw order.
|
/// 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 is_paper = self.current_layout != "Model";
|
||||||
let bg_color: [f32; 4] = if is_paper {
|
let bg_color: [f32; 4] = if is_paper {
|
||||||
self.paper_bg_color
|
self.paper_bg_color
|
||||||
|
|
@ -910,6 +927,11 @@ impl Scene {
|
||||||
{
|
{
|
||||||
continue;
|
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
|
// Per-entity world_offset selection so paper-layout content
|
||||||
// viewports still see model-block wipeouts at the right local
|
// viewports still see model-block wipeouts at the right local
|
||||||
// coordinates (same rationale as hatches).
|
// coordinates (same rationale as hatches).
|
||||||
|
|
|
||||||
194
src/scene/mod.rs
194
src/scene/mod.rs
|
|
@ -890,6 +890,17 @@ pub struct Scene {
|
||||||
image_cache: RefCell<Option<(u64, Arc<Vec<ImageModel>>)>>,
|
image_cache: RefCell<Option<(u64, Arc<Vec<ImageModel>>)>>,
|
||||||
/// Cached mesh models, keyed by geometry_epoch.
|
/// Cached mesh models, keyed by geometry_epoch.
|
||||||
mesh_cache: RefCell<Option<(u64, Arc<Vec<MeshLodSet>>)>>,
|
mesh_cache: RefCell<Option<(u64, Arc<Vec<MeshLodSet>>)>>,
|
||||||
|
/// Per-viewport (VP-frozen-layer) filtered fill / image / mesh sets, keyed by
|
||||||
|
/// the order-independent signature of the viewport's frozen-layer set. A
|
||||||
|
/// content viewport that freezes layers must hide their hatches, 2-D solids,
|
||||||
|
/// images/OLE and 3-D solids too — not just wires — so these hold the
|
||||||
|
/// filtered variants. Viewports sharing a frozen set share one entry (like
|
||||||
|
/// the resident wire set). Empty for a viewport with no frozen layers (it
|
||||||
|
/// reuses the unfiltered `*_arc` sets directly).
|
||||||
|
frozen_hatch_cache: RefCell<HashMap<u64, (u64, u64, Arc<Vec<HatchModel>>)>>,
|
||||||
|
frozen_wipeout_cache: RefCell<HashMap<u64, (u64, Arc<Vec<HatchModel>>)>>,
|
||||||
|
frozen_image_cache: RefCell<HashMap<u64, (u64, Arc<Vec<ImageModel>>)>>,
|
||||||
|
frozen_mesh_cache: RefCell<HashMap<u64, (u64, Arc<Vec<MeshLodSet>>)>>,
|
||||||
/// Cached block-INSERT hatches for hit-testing, keyed by geometry_epoch.
|
/// Cached block-INSERT hatches for hit-testing, keyed by geometry_epoch.
|
||||||
/// Building this explodes every model-space INSERT, so without the cache a
|
/// Building this explodes every model-space INSERT, so without the cache a
|
||||||
/// heavy block-instanced drawing re-explodes thousands of inserts on every
|
/// heavy block-instanced drawing re-explodes thousands of inserts on every
|
||||||
|
|
@ -1125,6 +1136,10 @@ impl Scene {
|
||||||
wipeout_cache: RefCell::new(None),
|
wipeout_cache: RefCell::new(None),
|
||||||
image_cache: RefCell::new(None),
|
image_cache: RefCell::new(None),
|
||||||
mesh_cache: RefCell::new(None),
|
mesh_cache: RefCell::new(None),
|
||||||
|
frozen_hatch_cache: RefCell::new(HashMap::default()),
|
||||||
|
frozen_wipeout_cache: RefCell::new(HashMap::default()),
|
||||||
|
frozen_image_cache: RefCell::new(HashMap::default()),
|
||||||
|
frozen_mesh_cache: RefCell::new(HashMap::default()),
|
||||||
insert_hatch_cache: RefCell::new(None),
|
insert_hatch_cache: RefCell::new(None),
|
||||||
paper_sheet_cache: RefCell::new(None),
|
paper_sheet_cache: RefCell::new(None),
|
||||||
paper_projected_cache: RefCell::new(HashMap::default()),
|
paper_projected_cache: RefCell::new(HashMap::default()),
|
||||||
|
|
@ -3419,7 +3434,7 @@ impl Scene {
|
||||||
return arc;
|
return arc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let arc = Arc::new(self.synced_hatch_models());
|
let arc = Arc::new(self.synced_hatch_models(None));
|
||||||
*self.hatch_cache.borrow_mut() = Some((self.geometry_epoch, sel_sig, Arc::clone(&arc)));
|
*self.hatch_cache.borrow_mut() = Some((self.geometry_epoch, sel_sig, Arc::clone(&arc)));
|
||||||
arc
|
arc
|
||||||
}
|
}
|
||||||
|
|
@ -3462,7 +3477,7 @@ impl Scene {
|
||||||
return arc;
|
return arc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let arc = Arc::new(self.wipeout_models());
|
let arc = Arc::new(self.wipeout_models(None));
|
||||||
*self.wipeout_cache.borrow_mut() = Some((self.geometry_epoch, Arc::clone(&arc)));
|
*self.wipeout_cache.borrow_mut() = Some((self.geometry_epoch, Arc::clone(&arc)));
|
||||||
arc
|
arc
|
||||||
}
|
}
|
||||||
|
|
@ -3491,21 +3506,33 @@ impl Scene {
|
||||||
return arc;
|
return arc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let depth_map = self.draw_depth_map();
|
let arc = Arc::new(self.image_models(None));
|
||||||
let arc = Arc::new(
|
|
||||||
self.images
|
|
||||||
.iter()
|
|
||||||
.map(|(handle, model)| {
|
|
||||||
let mut m = model.clone();
|
|
||||||
m.draw_depth = depth_map.get(&handle.value()).copied().unwrap_or(0.0);
|
|
||||||
m
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
*self.image_cache.borrow_mut() = Some((self.geometry_epoch, Arc::clone(&arc)));
|
*self.image_cache.borrow_mut() = Some((self.geometry_epoch, Arc::clone(&arc)));
|
||||||
arc
|
arc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Model image / OLE-frame models, optionally dropping those whose layer is
|
||||||
|
/// frozen in a content viewport (`frozen`). `None` reproduces the full set.
|
||||||
|
fn image_models(&self, frozen: Option<&HashSet<Handle>>) -> Vec<ImageModel> {
|
||||||
|
let depth_map = self.draw_depth_map();
|
||||||
|
self.images
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(handle, model)| {
|
||||||
|
if frozen.is_some() {
|
||||||
|
let layer = self.document.get_entity(*handle).map(|e| e.common().layer.clone());
|
||||||
|
if let Some(layer) = layer {
|
||||||
|
if self.layer_frozen_in(&layer, frozen) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut m = model.clone();
|
||||||
|
m.draw_depth = depth_map.get(&handle.value()).copied().unwrap_or(0.0);
|
||||||
|
Some(m)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// Images owned by the active paper layout block only. The full-canvas
|
/// Images owned by the active paper layout block only. The full-canvas
|
||||||
/// sheet viewport uses this so model-block images don't bleed onto the
|
/// sheet viewport uses this so model-block images don't bleed onto the
|
||||||
/// paper sheet (mirrors `paper_canvas_hatches`).
|
/// paper sheet (mirrors `paper_canvas_hatches`).
|
||||||
|
|
@ -3561,12 +3588,29 @@ impl Scene {
|
||||||
return arc;
|
return arc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let arc = Arc::new(self.mesh_models(None));
|
||||||
|
*self.mesh_cache.borrow_mut() = Some((self.geometry_epoch, Arc::clone(&arc)));
|
||||||
|
arc
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Solid-mesh set (top-level + block-instanced), optionally dropping those
|
||||||
|
/// whose layer is frozen in a content viewport (`frozen`). `None` reproduces
|
||||||
|
/// the full set.
|
||||||
|
fn mesh_models(&self, frozen: Option<&HashSet<Handle>>) -> Vec<MeshLodSet> {
|
||||||
// Top-level solids: drop those whose layer is off/frozen or that are
|
// Top-level solids: drop those whose layer is off/frozen or that are
|
||||||
// flagged invisible / isolated-hidden, mirroring the 2D wire path.
|
// flagged invisible / isolated-hidden, mirroring the 2D wire path, plus
|
||||||
|
// any whose layer is frozen in the requesting viewport.
|
||||||
let mut all: Vec<MeshLodSet> = self
|
let mut all: Vec<MeshLodSet> = self
|
||||||
.meshes
|
.meshes
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(&h, _)| self.mesh_entity_visible(h))
|
.filter(|(&h, _)| {
|
||||||
|
self.mesh_entity_visible(h)
|
||||||
|
&& self
|
||||||
|
.document
|
||||||
|
.get_entity(h)
|
||||||
|
.map(|e| !self.layer_frozen_in(&e.common().layer, frozen))
|
||||||
|
.unwrap_or(true)
|
||||||
|
})
|
||||||
.map(|(_, set)| set.clone())
|
.map(|(_, set)| set.clone())
|
||||||
.collect();
|
.collect();
|
||||||
// Block-definition solids are instanced per INSERT of the ACTIVE space's
|
// Block-definition solids are instanced per INSERT of the ACTIVE space's
|
||||||
|
|
@ -3576,10 +3620,9 @@ impl Scene {
|
||||||
all.extend(self.instanced_block_meshes(
|
all.extend(self.instanced_block_meshes(
|
||||||
self.block_edit_block
|
self.block_edit_block
|
||||||
.unwrap_or_else(|| self.model_space_block_handle()),
|
.unwrap_or_else(|| self.model_space_block_handle()),
|
||||||
|
frozen,
|
||||||
));
|
));
|
||||||
let arc = Arc::new(all);
|
all
|
||||||
*self.mesh_cache.borrow_mut() = Some((self.geometry_epoch, Arc::clone(&arc)));
|
|
||||||
arc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// True when `layer` is turned off or frozen — entities on it never render.
|
/// True when `layer` is turned off or frozen — entities on it never render.
|
||||||
|
|
@ -3591,6 +3634,108 @@ impl Scene {
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// True when `layer`'s handle is in a content viewport's per-viewport
|
||||||
|
/// frozen-layer set (VP freeze). Mirrors the wire path's test in
|
||||||
|
/// [`Scene::resident_entity_visible`] so fills / images / meshes hide on the
|
||||||
|
/// same layers wires do. `None` / empty set → never frozen.
|
||||||
|
fn layer_frozen_in(&self, layer: &str, frozen: Option<&HashSet<Handle>>) -> bool {
|
||||||
|
match frozen {
|
||||||
|
Some(fz) if !fz.is_empty() => self
|
||||||
|
.document
|
||||||
|
.layers
|
||||||
|
.get(layer)
|
||||||
|
.map(|l| fz.contains(&l.handle))
|
||||||
|
.unwrap_or(false),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Order-independent signature of a per-viewport frozen-layer set, so
|
||||||
|
/// viewports that freeze the same layers share one cached filtered fill /
|
||||||
|
/// image / mesh set. Matches the fold the resident wire cache uses.
|
||||||
|
fn frozen_layers_sig(frozen: &HashSet<Handle>) -> u64 {
|
||||||
|
let mut sig: u64 = frozen.len() as u64;
|
||||||
|
for h in frozen.iter() {
|
||||||
|
sig ^= h.value().wrapping_mul(0x9E37_79B9_7F4A_7C15);
|
||||||
|
}
|
||||||
|
sig
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hatch / 2-D-solid fills for a content viewport, with its frozen layers
|
||||||
|
/// removed. Cached per frozen-set signature (viewports sharing a frozen set
|
||||||
|
/// share the build). No frozen layers → the shared unfiltered set.
|
||||||
|
pub(super) fn hatch_models_for_viewport(&self, frozen: &HashSet<Handle>) -> Arc<Vec<HatchModel>> {
|
||||||
|
if frozen.is_empty() {
|
||||||
|
return self.hatch_models_arc();
|
||||||
|
}
|
||||||
|
let sig = Self::frozen_layers_sig(frozen);
|
||||||
|
let sel = self.selected_set_sig();
|
||||||
|
if let Some((e, s, arc)) = self.frozen_hatch_cache.borrow().get(&sig) {
|
||||||
|
if *e == self.geometry_epoch && *s == sel {
|
||||||
|
return Arc::clone(arc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let arc = Arc::new(self.synced_hatch_models(Some(frozen)));
|
||||||
|
self.frozen_hatch_cache
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(sig, (self.geometry_epoch, sel, Arc::clone(&arc)));
|
||||||
|
arc
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wipeout fills for a content viewport, with its frozen layers removed.
|
||||||
|
pub(super) fn wipeout_models_for_viewport(&self, frozen: &HashSet<Handle>) -> Arc<Vec<HatchModel>> {
|
||||||
|
if frozen.is_empty() {
|
||||||
|
return self.wipeout_models_arc();
|
||||||
|
}
|
||||||
|
let sig = Self::frozen_layers_sig(frozen);
|
||||||
|
if let Some((e, arc)) = self.frozen_wipeout_cache.borrow().get(&sig) {
|
||||||
|
if *e == self.geometry_epoch {
|
||||||
|
return Arc::clone(arc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let arc = Arc::new(self.wipeout_models(Some(frozen)));
|
||||||
|
self.frozen_wipeout_cache
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(sig, (self.geometry_epoch, Arc::clone(&arc)));
|
||||||
|
arc
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Image / OLE models for a content viewport, with its frozen layers removed.
|
||||||
|
pub(super) fn images_for_viewport(&self, frozen: &HashSet<Handle>) -> Arc<Vec<ImageModel>> {
|
||||||
|
if frozen.is_empty() {
|
||||||
|
return self.images_arc();
|
||||||
|
}
|
||||||
|
let sig = Self::frozen_layers_sig(frozen);
|
||||||
|
if let Some((e, arc)) = self.frozen_image_cache.borrow().get(&sig) {
|
||||||
|
if *e == self.geometry_epoch {
|
||||||
|
return Arc::clone(arc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let arc = Arc::new(self.image_models(Some(frozen)));
|
||||||
|
self.frozen_image_cache
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(sig, (self.geometry_epoch, Arc::clone(&arc)));
|
||||||
|
arc
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Solid meshes for a content viewport, with its frozen layers removed.
|
||||||
|
pub(super) fn meshes_for_viewport(&self, frozen: &HashSet<Handle>) -> Arc<Vec<MeshLodSet>> {
|
||||||
|
if frozen.is_empty() {
|
||||||
|
return self.meshes_arc();
|
||||||
|
}
|
||||||
|
let sig = Self::frozen_layers_sig(frozen);
|
||||||
|
if let Some((e, arc)) = self.frozen_mesh_cache.borrow().get(&sig) {
|
||||||
|
if *e == self.geometry_epoch {
|
||||||
|
return Arc::clone(arc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let arc = Arc::new(self.mesh_models(Some(frozen)));
|
||||||
|
self.frozen_mesh_cache
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(sig, (self.geometry_epoch, Arc::clone(&arc)));
|
||||||
|
arc
|
||||||
|
}
|
||||||
|
|
||||||
/// True when `handle`'s entity sits on a locked layer. Locked objects stay
|
/// True when `handle`'s entity sits on a locked layer. Locked objects stay
|
||||||
/// visible and snappable but cannot be selected or modified — callers in
|
/// visible and snappable but cannot be selected or modified — callers in
|
||||||
/// the pick / modify paths consult this to skip them.
|
/// the pick / modify paths consult this to skip them.
|
||||||
|
|
@ -3628,7 +3773,11 @@ impl Scene {
|
||||||
/// One transformed mesh per block-definition solid instance reached from an
|
/// One transformed mesh per block-definition solid instance reached from an
|
||||||
/// INSERT owned by `layout_block`. Nested INSERTs accumulate their
|
/// INSERT owned by `layout_block`. Nested INSERTs accumulate their
|
||||||
/// transform. Empty when no block solids exist. (#123)
|
/// transform. Empty when no block solids exist. (#123)
|
||||||
fn instanced_block_meshes(&self, layout_block: Handle) -> Vec<MeshLodSet> {
|
fn instanced_block_meshes(
|
||||||
|
&self,
|
||||||
|
layout_block: Handle,
|
||||||
|
frozen: Option<&HashSet<Handle>>,
|
||||||
|
) -> Vec<MeshLodSet> {
|
||||||
if self.block_meshes.is_empty() {
|
if self.block_meshes.is_empty() {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
|
|
@ -3639,8 +3788,11 @@ impl Scene {
|
||||||
}
|
}
|
||||||
if let EntityType::Insert(ins) = e {
|
if let EntityType::Insert(ins) = e {
|
||||||
// INSERT on an off/frozen (or invisible) layer hides the whole
|
// INSERT on an off/frozen (or invisible) layer hides the whole
|
||||||
// instance, block-internal solids included.
|
// instance, block-internal solids included — including a layer
|
||||||
if !self.mesh_entity_visible(ins.common.handle) {
|
// frozen only in the requesting content viewport.
|
||||||
|
if !self.mesh_entity_visible(ins.common.handle)
|
||||||
|
|| self.layer_frozen_in(&ins.common.layer, frozen)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Colour inheritance sources for block-internal solids (#221).
|
// Colour inheritance sources for block-internal solids (#221).
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,7 @@ impl Scene {
|
||||||
} else {
|
} else {
|
||||||
self.bg_color
|
self.bg_color
|
||||||
};
|
};
|
||||||
let exploded = self.exploded_insert_hatch_models(layout_block, hatch_bg, false);
|
let exploded = self.exploded_insert_hatch_models(layout_block, hatch_bg, false, None);
|
||||||
models.extend(exploded);
|
models.extend(exploded);
|
||||||
Arc::new(models)
|
Arc::new(models)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1289,6 +1289,23 @@ impl Scene {
|
||||||
// bleed past the viewport borders whenever model coords overlap the
|
// bleed past the viewport borders whenever model coords overlap the
|
||||||
// paper area. Content viewports keep the full set (the model camera +
|
// paper area. Content viewports keep the full set (the model camera +
|
||||||
// per-viewport scissor place / clip them correctly).
|
// per-viewport scissor place / clip them correctly).
|
||||||
|
// Per-viewport frozen-layer set for a paper content viewport. Content
|
||||||
|
// viewports must hide FILLS / IMAGES / SOLIDS on their frozen layers too,
|
||||||
|
// not just wires (which `model_wires_for_viewport_arc` already filters).
|
||||||
|
// Empty for the sheet, model tiles and the implicit-model view — none of
|
||||||
|
// which carry a per-viewport freeze — so those reuse the shared sets.
|
||||||
|
let vp_frozen: rustc_hash::FxHashSet<Handle> = if !inst.paper_sheet
|
||||||
|
&& inst.tile_idx.is_none()
|
||||||
|
&& inst.handle != acadrust::Handle::NULL
|
||||||
|
{
|
||||||
|
match self.document.get_entity(inst.handle) {
|
||||||
|
Some(EntityType::Viewport(vp)) => vp.frozen_layers.iter().cloned().collect(),
|
||||||
|
_ => rustc_hash::FxHashSet::default(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rustc_hash::FxHashSet::default()
|
||||||
|
};
|
||||||
|
|
||||||
let (hatches, wipeout_hatches) = if inst.paper_sheet {
|
let (hatches, wipeout_hatches) = if inst.paper_sheet {
|
||||||
let mut v: Vec<HatchModel> = Vec::new();
|
let mut v: Vec<HatchModel> = Vec::new();
|
||||||
if let Some(sheet) = self.paper_sheet_fill() {
|
if let Some(sheet) = self.paper_sheet_fill() {
|
||||||
|
|
@ -1297,12 +1314,15 @@ impl Scene {
|
||||||
v.extend(self.paper_canvas_hatches().iter().cloned());
|
v.extend(self.paper_canvas_hatches().iter().cloned());
|
||||||
(Arc::new(v), self.paper_canvas_wipeouts())
|
(Arc::new(v), self.paper_canvas_wipeouts())
|
||||||
} else {
|
} else {
|
||||||
(self.hatch_models_arc(), self.wipeout_models_arc())
|
(
|
||||||
|
self.hatch_models_for_viewport(&vp_frozen),
|
||||||
|
self.wipeout_models_for_viewport(&vp_frozen),
|
||||||
|
)
|
||||||
};
|
};
|
||||||
let images = if inst.paper_sheet {
|
let images = if inst.paper_sheet {
|
||||||
self.paper_sheet_images()
|
self.paper_sheet_images()
|
||||||
} else {
|
} else {
|
||||||
self.images_arc()
|
self.images_for_viewport(&vp_frozen)
|
||||||
};
|
};
|
||||||
// The paper sheet shows the layout's own 2-D content (fills, borders,
|
// The paper sheet shows the layout's own 2-D content (fills, borders,
|
||||||
// annotation) — never the model's 3-D solids. Those are drawn inside
|
// annotation) — never the model's 3-D solids. Those are drawn inside
|
||||||
|
|
@ -1314,7 +1334,7 @@ impl Scene {
|
||||||
let meshes = if inst.paper_sheet {
|
let meshes = if inst.paper_sheet {
|
||||||
Arc::new(Vec::new())
|
Arc::new(Vec::new())
|
||||||
} else {
|
} else {
|
||||||
self.meshes_arc()
|
self.meshes_for_viewport(&vp_frozen)
|
||||||
};
|
};
|
||||||
|
|
||||||
// SDF text quads (behind OCS_TEXT_SDF). The glyph quads ride on each
|
// SDF text quads (behind OCS_TEXT_SDF). The glyph quads ride on each
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue