forked from 1b-agent/opencadstudio-upstream
fix(save): preserve 3D view and thumbnails
Persist camera, render state, and solid fallback geometry across saves. Generate previews from a clean live viewport and refresh recent-file thumbnails immediately.
This commit is contained in:
1 parent
c4515cbbc1
commit
e94cbedaa2
15 files changed
+658
-629
No files matched your search
+13
-13
@@ -315,7 +315,9 @@ impl Scene {
|
||||
self.camera_generation = saved_generation;
|
||||
|
||||
if let Some((min, max)) = refreshed {
|
||||
self.camera.borrow_mut().fit_depth_to_bounds(min, max);
|
||||
self.camera
|
||||
.borrow_mut()
|
||||
.fit_depth_to_bounds_f64(min, max);
|
||||
self.projection_bounds_epoch.set(self.geometry_epoch);
|
||||
}
|
||||
}
|
||||
@@ -672,11 +674,7 @@ impl Scene {
|
||||
// The saved-view convention uses a 24 mm vertical aperture. This is
|
||||
// the inverse of the projection path's documented
|
||||
// `distance = view_height * lens / 24` relation.
|
||||
let fov_y = if perspective {
|
||||
2.0 * (12.0 / lens_length).atan()
|
||||
} else {
|
||||
45.0_f32.to_radians()
|
||||
};
|
||||
let fov_y = 2.0 * (12.0 / lens_length).atan();
|
||||
let distance = ((view_height as f32 / 2.0) / (fov_y * 0.5).tan()).max(0.001);
|
||||
Some(Camera {
|
||||
target,
|
||||
@@ -729,9 +727,9 @@ impl Scene {
|
||||
let view_dir = cam.rotation * glam::Vec3::Z;
|
||||
let view_height = cam.ortho_size() * 2.0;
|
||||
let target_wcs = acadrust::types::Vector3 {
|
||||
x: (cam.target.x as f64) + [0.0_f64; 3][0],
|
||||
y: (cam.target.y as f64) + [0.0_f64; 3][1],
|
||||
z: (cam.target.z as f64) + [0.0_f64; 3][2],
|
||||
x: cam.target.x,
|
||||
y: cam.target.y,
|
||||
z: cam.target.z,
|
||||
};
|
||||
entry.lower_left = lower_left;
|
||||
entry.upper_right = upper_right;
|
||||
@@ -1186,9 +1184,11 @@ impl Scene {
|
||||
if !ok {
|
||||
return;
|
||||
}
|
||||
let min = glam::Vec3::new(lo.x as f32, lo.y as f32, lo.z as f32);
|
||||
let max = glam::Vec3::new(hi.x as f32, hi.y as f32, hi.z as f32);
|
||||
self.camera.borrow_mut().fit_depth_to_bounds(min, max);
|
||||
let min = glam::DVec3::new(lo.x, lo.y, lo.z);
|
||||
let max = glam::DVec3::new(hi.x, hi.y, hi.z);
|
||||
self.camera
|
||||
.borrow_mut()
|
||||
.fit_depth_to_bounds_f64(min, max);
|
||||
}
|
||||
|
||||
fn fit_paper_space_extents(&mut self) {
|
||||
@@ -1557,7 +1557,7 @@ impl Scene {
|
||||
if index == active {
|
||||
tile.camera = live_camera.clone();
|
||||
} else {
|
||||
tile.camera.fit_to_bounds(min, max, aspect);
|
||||
tile.camera.fit_to_bounds_f64(min, max, aspect);
|
||||
}
|
||||
}
|
||||
if let Some(aspect) = aspects.get(active) {
|
||||
|
||||
@@ -42,6 +42,8 @@ pub(crate) fn body_transform(
|
||||
values.extend_from_slice(&components[..len]);
|
||||
} else if let Some(value) = token.as_float() {
|
||||
values.push(value);
|
||||
} else if let Some(value) = token.as_integer() {
|
||||
values.push(value as f64);
|
||||
} else if let Some(text) = token.as_string() {
|
||||
for word in text.split_ascii_whitespace() {
|
||||
let Ok(value) = word.parse::<f64>() else {
|
||||
|
||||
+3
-2
@@ -924,6 +924,7 @@ impl Scene {
|
||||
annotation_scale_handle: Option<Handle>,
|
||||
all_visible: bool,
|
||||
viewport: Option<Handle>,
|
||||
tint_selected: bool,
|
||||
) -> Vec<HatchModel> {
|
||||
let layer_hidden = |layer: &str| {
|
||||
self.document
|
||||
@@ -1098,7 +1099,7 @@ impl Scene {
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.selected.contains(&handle) {
|
||||
if tint_selected && self.selected.contains(&handle) {
|
||||
m.color = [0.15, 0.55, 1.00, m.color[3]];
|
||||
}
|
||||
let d = depth_map.get(&handle.value()).map_or(0.0, |d| d[0]);
|
||||
@@ -1115,7 +1116,7 @@ impl Scene {
|
||||
models.extend(self.instanced_hatch_models(
|
||||
target_block,
|
||||
hatch_bg,
|
||||
true,
|
||||
tint_selected,
|
||||
frozen,
|
||||
annotation_scale_handle,
|
||||
all_visible,
|
||||
|
||||
+11
-3
@@ -5674,14 +5674,19 @@ impl Scene {
|
||||
arc
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(super) fn hatch_models_arc(&self) -> Arc<Vec<HatchModel>> {
|
||||
self.hatch_models_arc_for_view(true)
|
||||
}
|
||||
|
||||
fn hatch_models_arc_for_view(&self, tint_selected: bool) -> Arc<Vec<HatchModel>> {
|
||||
// Hatch models bake the selection tint (issue #71), so they depend on
|
||||
// the *selected set* — but NOT on hover. Keying on `selection_generation`
|
||||
// (which also bumps on every hover) made each hover-over a new entity
|
||||
// rebuild every hatch model: an O(N-hatch) stutter on hatch-heavy
|
||||
// drawings. Key on a signature of `selected` instead, so hover (which
|
||||
// never changes `selected`) keeps the cache warm.
|
||||
let sel_sig = self.selected_hatch_sig();
|
||||
let sel_sig = if tint_selected { self.selected_hatch_sig() } else { 0 };
|
||||
let target_block = self.content_render_block_handle();
|
||||
let key = (target_block, self.current_layout.clone());
|
||||
{
|
||||
@@ -5728,6 +5733,7 @@ impl Scene {
|
||||
scale,
|
||||
self.annotation_all_visible(),
|
||||
None,
|
||||
tint_selected,
|
||||
));
|
||||
self.hatch_cache.borrow_mut().insert(
|
||||
key,
|
||||
@@ -6324,9 +6330,10 @@ impl Scene {
|
||||
&self,
|
||||
viewport: Handle,
|
||||
frozen: &HashSet<Handle>,
|
||||
tint_selected: bool,
|
||||
) -> Arc<Vec<HatchModel>> {
|
||||
if viewport.is_null() && frozen.is_empty() {
|
||||
return self.hatch_models_arc();
|
||||
return self.hatch_models_arc_for_view(tint_selected);
|
||||
}
|
||||
let target_block = self.content_render_block_handle();
|
||||
let scale = self.viewport_scale_handle(viewport);
|
||||
@@ -6336,7 +6343,7 @@ impl Scene {
|
||||
^ self.viewport_style_key(Some(viewport)).rotate_left(23);
|
||||
let sig = Self::frozen_layers_sig(frozen) ^ context_sig;
|
||||
let key = (target_block, self.current_layout.clone(), sig);
|
||||
let sel = self.selected_hatch_sig();
|
||||
let sel = if tint_selected { self.selected_hatch_sig() } else { 0 };
|
||||
if let Some((e, s, arc)) = self.frozen_hatch_cache.borrow().get(&key) {
|
||||
if *e == self.geometry_epoch && *s == sel {
|
||||
return Arc::clone(arc);
|
||||
@@ -6348,6 +6355,7 @@ impl Scene {
|
||||
scale,
|
||||
all_visible,
|
||||
Some(viewport),
|
||||
tint_selected,
|
||||
));
|
||||
self.frozen_hatch_cache
|
||||
.borrow_mut()
|
||||
|
||||
+19
-4
@@ -204,7 +204,18 @@ impl Scene {
|
||||
Arc<Vec<HatchModel>>,
|
||||
Arc<Vec<ImageModel>>,
|
||||
) {
|
||||
let selected = self.selected_hatch_sig();
|
||||
self.paper_sheet_render_models_for_view(true)
|
||||
}
|
||||
|
||||
pub(super) fn paper_sheet_render_models_for_view(
|
||||
&self,
|
||||
tint_selected: bool,
|
||||
) -> (
|
||||
Arc<Vec<HatchModel>>,
|
||||
Arc<Vec<HatchModel>>,
|
||||
Arc<Vec<ImageModel>>,
|
||||
) {
|
||||
let selected = if tint_selected { self.selected_hatch_sig() } else { 0 };
|
||||
let reuse = {
|
||||
let cache = self.paper_sheet_render_cache.borrow();
|
||||
if let Some(cache) = cache.get(&self.current_layout) {
|
||||
@@ -259,7 +270,11 @@ impl Scene {
|
||||
if let Some(sheet) = self.paper_sheet_fill() {
|
||||
hatches.push(sheet);
|
||||
}
|
||||
hatches.extend(self.paper_canvas_hatches().iter().cloned());
|
||||
hatches.extend(
|
||||
self.paper_canvas_hatches(tint_selected)
|
||||
.iter()
|
||||
.cloned(),
|
||||
);
|
||||
let hatches = Arc::new(hatches);
|
||||
let wipeouts = self.paper_canvas_wipeouts();
|
||||
let images = self.paper_sheet_images();
|
||||
@@ -381,7 +396,7 @@ impl Scene {
|
||||
/// entity handle) rather than the already-flattened arc — the
|
||||
/// flattened arc carries pattern names, not handles, so filtering
|
||||
/// there is unreliable.
|
||||
pub fn paper_canvas_hatches(&self) -> Arc<Vec<HatchModel>> {
|
||||
fn paper_canvas_hatches(&self, tint_selected: bool) -> Arc<Vec<HatchModel>> {
|
||||
let layout_block = self.current_layout_block_handle();
|
||||
let layer_hidden = |layer: &str| {
|
||||
self.document
|
||||
@@ -455,7 +470,7 @@ impl Scene {
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.selected.contains(&handle) {
|
||||
if tint_selected && self.selected.contains(&handle) {
|
||||
m.color = [0.15, 0.55, 1.00, m.color[3]];
|
||||
}
|
||||
models.push(m);
|
||||
|
||||
+27
-24
@@ -61,7 +61,7 @@ pub struct Camera {
|
||||
/// that span, clipping the drawing (#473). Re-projecting the box each frame
|
||||
/// keeps near/far exactly as deep as the current view needs. `None` falls
|
||||
/// back to `depth_half_range`.
|
||||
pub model_bounds: Option<(Vec3, Vec3)>,
|
||||
pub model_bounds: Option<(DVec3, DVec3)>,
|
||||
}
|
||||
|
||||
impl Default for Camera {
|
||||
@@ -435,25 +435,24 @@ impl Camera {
|
||||
|
||||
if let Some((min, max)) = self.model_bounds {
|
||||
let corners = [
|
||||
Vec3::new(min.x, min.y, min.z),
|
||||
Vec3::new(max.x, min.y, min.z),
|
||||
Vec3::new(min.x, max.y, min.z),
|
||||
Vec3::new(max.x, max.y, min.z),
|
||||
Vec3::new(min.x, min.y, max.z),
|
||||
Vec3::new(max.x, min.y, max.z),
|
||||
Vec3::new(min.x, max.y, max.z),
|
||||
Vec3::new(max.x, max.y, max.z),
|
||||
DVec3::new(min.x, min.y, min.z),
|
||||
DVec3::new(max.x, min.y, min.z),
|
||||
DVec3::new(min.x, max.y, min.z),
|
||||
DVec3::new(max.x, max.y, min.z),
|
||||
DVec3::new(min.x, min.y, max.z),
|
||||
DVec3::new(max.x, min.y, max.z),
|
||||
DVec3::new(min.x, max.y, max.z),
|
||||
DVec3::new(max.x, max.y, max.z),
|
||||
];
|
||||
let mut new_min = Vec3::splat(f32::INFINITY);
|
||||
let mut new_max = Vec3::splat(f32::NEG_INFINITY);
|
||||
let mut new_min = DVec3::splat(f64::INFINITY);
|
||||
let mut new_max = DVec3::splat(f64::NEG_INFINITY);
|
||||
for corner in corners {
|
||||
let transformed = transform.apply(acadrust::types::Vector3::new(
|
||||
corner.x as f64,
|
||||
corner.y as f64,
|
||||
corner.z as f64,
|
||||
corner.x,
|
||||
corner.y,
|
||||
corner.z,
|
||||
));
|
||||
let transformed =
|
||||
Vec3::new(transformed.x as f32, transformed.y as f32, transformed.z as f32);
|
||||
let transformed = DVec3::new(transformed.x, transformed.y, transformed.z);
|
||||
new_min = new_min.min(transformed);
|
||||
new_max = new_max.max(transformed);
|
||||
}
|
||||
@@ -578,16 +577,16 @@ impl Camera {
|
||||
/// current target: `x`/`y` span the screen plane, `z` runs along the eye
|
||||
/// direction. The offset is taken in f64 before the cast, so a corner at
|
||||
/// UTM scale doesn't lose the difference to cancellation.
|
||||
fn bounds_in_view(&self, min: Vec3, max: Vec3) -> [Vec3; 8] {
|
||||
fn bounds_in_view(&self, min: DVec3, max: DVec3) -> [Vec3; 8] {
|
||||
let inv = self.rotation.inverse();
|
||||
let mut out = [Vec3::ZERO; 8];
|
||||
for (i, slot) in out.iter_mut().enumerate() {
|
||||
let corner = Vec3::new(
|
||||
let corner = DVec3::new(
|
||||
if i & 1 == 0 { min.x } else { max.x },
|
||||
if i & 2 == 0 { min.y } else { max.y },
|
||||
if i & 4 == 0 { min.z } else { max.z },
|
||||
);
|
||||
*slot = inv * (corner.as_dvec3() - self.target).as_vec3();
|
||||
*slot = inv * (corner - self.target).as_vec3();
|
||||
}
|
||||
out
|
||||
}
|
||||
@@ -595,7 +594,7 @@ impl Camera {
|
||||
/// Half-extent of `min..max` along the current eye direction (with the
|
||||
/// same 5% margin `ortho_depth_range` needs), measured from the target.
|
||||
/// This is exactly what `distance ± r` has to contain to avoid clipping.
|
||||
fn depth_extent_in_view(&self, min: Vec3, max: Vec3) -> f32 {
|
||||
fn depth_extent_in_view(&self, min: DVec3, max: DVec3) -> f32 {
|
||||
let depth_r = self
|
||||
.bounds_in_view(min, max)
|
||||
.iter()
|
||||
@@ -613,7 +612,11 @@ impl Camera {
|
||||
/// 800 km below its plane zoomed out to 800 km and became a dot. The two
|
||||
/// agree on a flat drawing, which is why it went unnoticed.
|
||||
pub fn fit_to_bounds(&mut self, min: Vec3, max: Vec3, aspect: f32) {
|
||||
self.target = ((min + max) * 0.5).as_dvec3();
|
||||
self.fit_to_bounds_f64(min.as_dvec3(), max.as_dvec3(), aspect);
|
||||
}
|
||||
|
||||
pub fn fit_to_bounds_f64(&mut self, min: DVec3, max: DVec3, aspect: f32) {
|
||||
self.target = (min + max) * 0.5;
|
||||
let corners = self.bounds_in_view(min, max);
|
||||
// Half-height the view needs so the box fits BOTH axes at the given
|
||||
// viewport aspect. The old circumscribed-radius rule fitted the box's
|
||||
@@ -628,7 +631,7 @@ impl Camera {
|
||||
// that to get the distance which just contains `half_h`, plus a small
|
||||
// border margin.
|
||||
self.distance = (half_h / (self.fov_y * 0.5).tan() * 1.1).max(1e-3);
|
||||
self.fit_depth_to_bounds(min, max);
|
||||
self.fit_depth_to_bounds_f64(min, max);
|
||||
}
|
||||
|
||||
/// Size only the near/far span to `min..max`, leaving the pose alone.
|
||||
@@ -636,7 +639,7 @@ impl Camera {
|
||||
/// Split out of [`fit_to_bounds`] for the camera restored from a file's
|
||||
/// saved view: that pose must not move, but its depth range still has to
|
||||
/// cover the model or geometry outside it is silently clipped away.
|
||||
pub fn fit_depth_to_bounds(&mut self, min: Vec3, max: Vec3) {
|
||||
pub fn fit_depth_to_bounds_f64(&mut self, min: DVec3, max: DVec3) {
|
||||
// Cache the box so `ortho_depth_range` re-derives the near/far depth for
|
||||
// the live eye direction every frame — orbiting off the fitted pose then
|
||||
// never clips the drawing (#473). Keeping it tied to the model (not to
|
||||
@@ -648,7 +651,7 @@ impl Camera {
|
||||
self.depth_half_range = self.depth_extent_in_view(min, max);
|
||||
}
|
||||
|
||||
pub(crate) fn fitted_model_bounds(&self) -> Option<(Vec3, Vec3)> {
|
||||
pub(crate) fn fitted_model_bounds(&self) -> Option<(DVec3, DVec3)> {
|
||||
self.model_bounds
|
||||
}
|
||||
|
||||
|
||||
+40
-11
@@ -3174,6 +3174,7 @@ impl Scene {
|
||||
model_render_mode: acadrust::entities::ViewportRenderMode,
|
||||
_hover_region: Option<usize>,
|
||||
show_viewcube: bool,
|
||||
show_interaction: bool,
|
||||
viewcube_text_color: [f32; 4],
|
||||
) -> Primitive {
|
||||
let nav_build_started = iced::time::Instant::now();
|
||||
@@ -3181,7 +3182,7 @@ impl Scene {
|
||||
// Hover comes from the scene cell driven by the app-level
|
||||
// `CursorMoved` handler — the cube overlay sits above the shader
|
||||
// and would otherwise mask the move event from `Program::update`.
|
||||
let hover_region = self.viewcube_hover.get();
|
||||
let hover_region = show_interaction.then(|| self.viewcube_hover.get()).flatten();
|
||||
self.selection.borrow_mut().vp_size = (bounds.width, bounds.height);
|
||||
if bounds.height > 0.0 {
|
||||
self.set_render_aspect(bounds.width / bounds.height);
|
||||
@@ -3197,7 +3198,14 @@ impl Scene {
|
||||
.iter()
|
||||
.filter_map(|inst| {
|
||||
let force = self.refresh_consume(self.instance_id_for(inst));
|
||||
self.viewport_data_for(inst, canvas, hover_region, show_viewcube, force)
|
||||
self.viewport_data_for(
|
||||
inst,
|
||||
canvas,
|
||||
hover_region,
|
||||
show_viewcube,
|
||||
show_interaction,
|
||||
force,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
// Empty viewports → blit nothing; the container background (model bg
|
||||
@@ -3226,9 +3234,10 @@ impl Scene {
|
||||
tile_idx: usize,
|
||||
model_render_mode: acadrust::entities::ViewportRenderMode,
|
||||
show_viewcube: bool,
|
||||
show_interaction: bool,
|
||||
viewcube_text_color: [f32; 4],
|
||||
) -> Primitive {
|
||||
let hover_region = self.viewcube_hover.get();
|
||||
let hover_region = show_interaction.then(|| self.viewcube_hover.get()).flatten();
|
||||
let canvas = (bounds.width.max(1.0), bounds.height.max(1.0));
|
||||
let bg_color = [0.0, 0.0, 0.0, 0.0];
|
||||
let tiles = self.model_tiles.borrow();
|
||||
@@ -3279,7 +3288,14 @@ impl Scene {
|
||||
};
|
||||
let force = self.refresh_consume(self.instance_id_for(&inst));
|
||||
let viewports = self
|
||||
.viewport_data_for(&inst, canvas, hover_region, show_viewcube, force)
|
||||
.viewport_data_for(
|
||||
&inst,
|
||||
canvas,
|
||||
hover_region,
|
||||
show_viewcube,
|
||||
show_interaction,
|
||||
force,
|
||||
)
|
||||
.into_iter()
|
||||
.collect();
|
||||
let perf_nav = perf_nav.map(|mut sample| {
|
||||
@@ -3304,6 +3320,7 @@ impl Scene {
|
||||
canvas: (f32, f32),
|
||||
hover_region: Option<usize>,
|
||||
show_viewcube: bool,
|
||||
show_interaction: bool,
|
||||
force_rasterize: bool,
|
||||
) -> Option<ViewportData> {
|
||||
let display = self.viewport_display_settings(inst);
|
||||
@@ -3443,7 +3460,7 @@ impl Scene {
|
||||
// paper layout, model-space overlays go to all content viewports while
|
||||
// paper-space overlays stay on the sheet. This also keeps model-space
|
||||
// coordinates out of the full-canvas sheet pass (#540).
|
||||
let show_live_overlay = if self.current_layout == "Model" {
|
||||
let show_live_overlay = show_interaction && if self.current_layout == "Model" {
|
||||
true
|
||||
} else if self.active_viewport.is_some() {
|
||||
!inst.paper_sheet
|
||||
@@ -3592,11 +3609,12 @@ impl Scene {
|
||||
// paper area. Content viewport model builders are block-filtered too;
|
||||
// the scissor only clips their already-correct Model Space set.
|
||||
let (hatches, wipeout_hatches, paper_images) = if inst.paper_sheet {
|
||||
let (hatches, wipeouts, images) = self.paper_sheet_render_models();
|
||||
let (hatches, wipeouts, images) =
|
||||
self.paper_sheet_render_models_for_view(show_interaction);
|
||||
(hatches, wipeouts, Some(images))
|
||||
} else {
|
||||
(
|
||||
self.hatch_models_for_viewport(inst.handle, &vp_frozen),
|
||||
self.hatch_models_for_viewport(inst.handle, &vp_frozen, show_interaction),
|
||||
self.wipeout_models_for_viewport(inst.handle, &vp_frozen),
|
||||
None,
|
||||
)
|
||||
@@ -3750,10 +3768,21 @@ impl Scene {
|
||||
camera_generation: self.camera_generation,
|
||||
wire_content_id,
|
||||
wire_patch,
|
||||
selected_handles: Arc::new(self.selected.iter().copied().collect()),
|
||||
hover_handles: Arc::new(self.hover_highlight_handles()),
|
||||
selection_generation: self.selection_generation,
|
||||
selected_sig: self.selected_set_sig(),
|
||||
selected_handles: Arc::new(if show_interaction {
|
||||
self.selected.iter().copied().collect()
|
||||
} else {
|
||||
rustc_hash::FxHashSet::default()
|
||||
}),
|
||||
hover_handles: Arc::new(if show_interaction {
|
||||
self.hover_highlight_handles()
|
||||
} else {
|
||||
rustc_hash::FxHashSet::default()
|
||||
}),
|
||||
selection_generation: self
|
||||
.selection_generation
|
||||
.wrapping_mul(2)
|
||||
.wrapping_add(u64::from(!show_interaction)),
|
||||
selected_sig: if show_interaction { self.selected_set_sig() } else { 0 },
|
||||
screen_rect,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ use iced::{mouse, Event, Rectangle};
|
||||
pub struct ViewportPane<'a> {
|
||||
pub scene: &'a Scene,
|
||||
pub show_viewcube: bool,
|
||||
pub show_interaction: bool,
|
||||
/// Render mode applied to the active Model tile or active paper viewport.
|
||||
/// The app may supply a temporary gallery-hover mode; inactive viewports
|
||||
/// keep the values stored on their own tile/entity.
|
||||
@@ -33,12 +34,14 @@ impl<'a> ViewportPane<'a> {
|
||||
pub fn model(
|
||||
scene: &'a Scene,
|
||||
show_viewcube: bool,
|
||||
show_interaction: bool,
|
||||
render_mode: acadrust::entities::ViewportRenderMode,
|
||||
viewcube_text_color: [f32; 4],
|
||||
) -> Self {
|
||||
Self {
|
||||
scene,
|
||||
show_viewcube,
|
||||
show_interaction,
|
||||
render_mode,
|
||||
pane: None,
|
||||
viewcube_text_color,
|
||||
@@ -50,6 +53,7 @@ impl<'a> ViewportPane<'a> {
|
||||
pub fn for_pane(
|
||||
scene: &'a Scene,
|
||||
show_viewcube: bool,
|
||||
show_interaction: bool,
|
||||
render_mode: acadrust::entities::ViewportRenderMode,
|
||||
tile_idx: usize,
|
||||
viewcube_text_color: [f32; 4],
|
||||
@@ -57,6 +61,7 @@ impl<'a> ViewportPane<'a> {
|
||||
Self {
|
||||
scene,
|
||||
show_viewcube,
|
||||
show_interaction,
|
||||
render_mode,
|
||||
pane: Some(tile_idx),
|
||||
viewcube_text_color,
|
||||
@@ -82,6 +87,7 @@ impl<'a, Msg: std::fmt::Debug + Clone> shader::Program<Msg> for ViewportPane<'a>
|
||||
idx,
|
||||
self.render_mode,
|
||||
self.show_viewcube,
|
||||
self.show_interaction,
|
||||
self.viewcube_text_color,
|
||||
),
|
||||
None => self.scene.build_viewports(
|
||||
@@ -89,6 +95,7 @@ impl<'a, Msg: std::fmt::Debug + Clone> shader::Program<Msg> for ViewportPane<'a>
|
||||
self.render_mode,
|
||||
state.hover_region,
|
||||
self.show_viewcube,
|
||||
self.show_interaction,
|
||||
self.viewcube_text_color,
|
||||
),
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user