forked from 1b-agent/opencadstudio-upstream
View backgrounds: reference blend, image adjust, layouts, cleanup, style name
- Gradients: the middle colour sits (horizon - 0.5) viewport widths from the centre and blends over height viewport heights each side; two colours blend over a viewport height each side. - Image backgrounds: offset in device pixels (right, down), negative scale mirrors, fitted with aspect ratio covers the viewport; the dialog keeps an image's offset and scale. - Layouts: a model-space view restored on a sheet asks for the viewport, enters it and gives it the view's camera, background and visual style; inside a viewport the view goes there; a paper-space view's background is kept on the sheet viewport but not drawn; floating viewports draw their background. - Background objects no view or viewport uses any more are erased; a view without a background restored where the viewport already is leaves the viewport's background. - The viewport's named visual style (Realistic, ...) shows by name and the render-mode picker records its style on the viewport record. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
1cf13971dc
commit
9ef8f4bedf
12 files changed
+349
-70
No files matched your search
+134
-9
@@ -214,11 +214,28 @@ impl Scene {
|
||||
|
||||
/// Restore camera to a named view from the document view table.
|
||||
pub fn restore_named_view(&mut self, view: &codec::tables::View) {
|
||||
use glam::Vec3;
|
||||
// The model viewport takes a copy of the view's background, or none.
|
||||
let before = {
|
||||
let cam = self.camera.borrow();
|
||||
(cam.rotation, cam.target, cam.distance)
|
||||
};
|
||||
self.restore_named_view_camera(view);
|
||||
let unchanged = {
|
||||
let cam = self.camera.borrow();
|
||||
cam.rotation.abs_diff_eq(before.0, 1e-6)
|
||||
&& cam.target.abs_diff_eq(before.1, 1e-6 * before.1.length().max(1.0))
|
||||
&& (cam.distance - before.2).abs() <= 1e-6 * before.2.abs().max(1.0)
|
||||
};
|
||||
// The model viewport takes a copy of the view's background; a view
|
||||
// without one clears it, unless the view is what the viewport already
|
||||
// shows (the reference leaves the viewport as it is then).
|
||||
if self.current_layout != "Model" && self.active_viewport.is_none() && view.paper_space {
|
||||
self.set_sheet_background(view);
|
||||
}
|
||||
if self.current_layout == "Model" {
|
||||
let background = copy_background(&mut self.document, view.background_handle);
|
||||
self.set_active_background(background);
|
||||
if view.background_handle.is_valid() || !unchanged {
|
||||
let background = copy_background(&mut self.document, view.background_handle);
|
||||
self.set_active_background(background);
|
||||
}
|
||||
if view.visual_style_handle.is_valid() {
|
||||
if let Some(handle) = self.active_tile_vport_handle() {
|
||||
if let Some(value) = self.document.vports.iter_mut().find(|v| v.handle == handle) {
|
||||
@@ -227,7 +244,50 @@ impl Scene {
|
||||
}
|
||||
}
|
||||
}
|
||||
let cam = &mut *self.camera.borrow_mut();
|
||||
}
|
||||
|
||||
fn restore_named_view_camera(&mut self, view: &codec::tables::View) {
|
||||
named_view_camera(view, &mut self.camera.borrow_mut());
|
||||
self.camera_generation += 1;
|
||||
}
|
||||
|
||||
/// Restores a model-space view into a paper-space viewport: its camera,
|
||||
/// a copy of the view's background (or none) and the view's visual style.
|
||||
pub fn restore_named_view_in_viewport(&mut self, view: &codec::tables::View, viewport: Handle) {
|
||||
let mut camera = self.navigation_camera();
|
||||
named_view_camera(view, &mut camera);
|
||||
self.apply_navigation_camera(camera);
|
||||
let background = copy_background(&mut self.document, view.background_handle);
|
||||
let mut old = Handle::NULL;
|
||||
if let Some(EntityType::Viewport(value)) = self.document.get_entity_mut(viewport) {
|
||||
old = std::mem::replace(&mut value.background_handle, background);
|
||||
if view.visual_style_handle.is_valid() {
|
||||
value.visual_style_handle = view.visual_style_handle;
|
||||
}
|
||||
}
|
||||
erase_background(&mut self.document, old);
|
||||
self.notify_viewport_changed(viewport);
|
||||
self.camera_generation += 1;
|
||||
}
|
||||
|
||||
/// The paper-space viewport of the current layout takes a copy of a
|
||||
/// paper-space view's background (kept with the layout; the sheet itself
|
||||
/// is not drawn over).
|
||||
fn set_sheet_background(&mut self, view: &codec::tables::View) {
|
||||
let sheet = self.current_layout_sheet_viewport_handle();
|
||||
let background = copy_background(&mut self.document, view.background_handle);
|
||||
let old = match self.document.get_entity_mut(sheet) {
|
||||
Some(EntityType::Viewport(value)) => std::mem::replace(&mut value.background_handle, background),
|
||||
_ => background,
|
||||
};
|
||||
erase_background(&mut self.document, old);
|
||||
}
|
||||
}
|
||||
|
||||
/// Points a camera along a named view: direction, target and height.
|
||||
fn named_view_camera(view: &codec::tables::View, cam: &mut view::camera::Camera) {
|
||||
use glam::Vec3;
|
||||
{
|
||||
// The stored direction points from the target toward the eye.
|
||||
let eye_dir = Vec3::new(
|
||||
view.direction.x as f32,
|
||||
@@ -254,22 +314,55 @@ impl Scene {
|
||||
} else {
|
||||
cam.distance
|
||||
};
|
||||
self.camera_generation += 1;
|
||||
}
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
/// The background the active model-space viewport shows (null for the
|
||||
/// drawing area colour).
|
||||
pub fn active_background(&self) -> Handle {
|
||||
if self.current_layout != "Model" {
|
||||
// Inside a viewport, that viewport's; the sheet's is not saved
|
||||
// with a paper-space view.
|
||||
return match self.active_viewport.and_then(|handle| self.document.get_entity(handle)) {
|
||||
Some(EntityType::Viewport(value)) => value.background_handle,
|
||||
_ => Handle::NULL,
|
||||
};
|
||||
}
|
||||
self.active_tile_vport_handle()
|
||||
.and_then(|handle| self.document.vports.iter().find(|value| value.handle == handle))
|
||||
.map_or(Handle::NULL, |value| value.background_handle)
|
||||
}
|
||||
|
||||
/// The visual style of the active Model tile's viewport record.
|
||||
pub fn active_visual_style(&self) -> Handle {
|
||||
self.active_tile_vport_handle()
|
||||
.and_then(|handle| self.document.vports.iter().find(|value| value.handle == handle))
|
||||
.map_or(Handle::NULL, |value| value.visual_style_handle)
|
||||
}
|
||||
|
||||
/// Records the visual style named `name` on the active Model tile's
|
||||
/// viewport record, when the drawing has it.
|
||||
pub fn set_active_visual_style_named(&mut self, name: &str) {
|
||||
let style = self.document.objects.iter().find_map(|(handle, object)| match object {
|
||||
codec::objects::ObjectType::VisualStyle(style) if style.description == name => Some(*handle),
|
||||
_ => None,
|
||||
});
|
||||
let (Some(style), Some(handle)) = (style, self.active_tile_vport_handle()) else { return };
|
||||
if let Some(value) = self.document.vports.iter_mut().find(|value| value.handle == handle) {
|
||||
value.visual_style_handle = style;
|
||||
}
|
||||
}
|
||||
|
||||
fn set_active_background(&mut self, background: Handle) {
|
||||
let Some(handle) = self.active_tile_vport_handle() else { return };
|
||||
if let Some(value) = self.document.vports.iter_mut().find(|value| value.handle == handle) {
|
||||
value.background_handle = background;
|
||||
self.camera_generation += 1;
|
||||
let Some(value) = self.document.vports.iter_mut().find(|value| value.handle == handle) else {
|
||||
return;
|
||||
};
|
||||
let old = std::mem::replace(&mut value.background_handle, background);
|
||||
self.camera_generation += 1;
|
||||
if old != background {
|
||||
erase_background(&mut self.document, old);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1713,6 +1806,38 @@ pub fn add_background(
|
||||
handle
|
||||
}
|
||||
|
||||
/// Erases a background object once no view or viewport refers to it (the
|
||||
/// reference erases a view's background when it is replaced, cleared or the
|
||||
/// view deleted, and a viewport's when the viewport takes another).
|
||||
pub fn erase_background(document: &mut codec::CadDocument, handle: Handle) {
|
||||
use codec::objects::{ClassObjectData as D, ObjectType};
|
||||
if !handle.is_valid()
|
||||
|| document.views.iter().any(|view| view.background_handle == handle)
|
||||
|| document.vports.iter().any(|vport| vport.background_handle == handle)
|
||||
|| document.entities().any(|entity| {
|
||||
matches!(entity, codec::EntityType::Viewport(viewport) if viewport.background_handle == handle)
|
||||
})
|
||||
{
|
||||
return;
|
||||
}
|
||||
let owner = match document.objects.get(&handle) {
|
||||
Some(ObjectType::ClassObject(object))
|
||||
if matches!(
|
||||
object.data,
|
||||
D::SolidBackground(_) | D::GradientBackground(_) | D::ImageBackground(_)
|
||||
| D::GroundPlaneBackground(_) | D::SkyLightBackground(_) | D::IblBackground(_)
|
||||
) =>
|
||||
{
|
||||
object.owner
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
document.objects.remove(&handle);
|
||||
if let Some(ObjectType::Dictionary(entries)) = document.objects.get_mut(&owner) {
|
||||
entries.entries.retain(|(_, entry)| *entry != handle);
|
||||
}
|
||||
}
|
||||
|
||||
/// A copy of a background object (the reference gives each view and
|
||||
/// viewport its own); null for none.
|
||||
pub fn copy_background(document: &mut codec::CadDocument, handle: Handle) -> Handle {
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ pub enum BlockScalePolicy {
|
||||
// blocks and/or free functions). Pure text-move from the original mod.rs.
|
||||
mod boundary;
|
||||
mod camera_ops;
|
||||
pub use camera_ops::{add_background, copy_background};
|
||||
pub use camera_ops::{add_background, copy_background, erase_background};
|
||||
pub(crate) mod centerline;
|
||||
pub(crate) mod centermark;
|
||||
pub(crate) mod dimension_assoc;
|
||||
|
||||
+14
-10
@@ -434,8 +434,10 @@ impl shader::Primitive for Primitive {
|
||||
// The scene works in logical pixels; an image background keeps
|
||||
// its size in device pixels.
|
||||
let mut uniforms = vp.uniforms;
|
||||
uniforms.background_image_transform[2] /= scale.max(1e-3);
|
||||
uniforms.background_image_transform[3] /= scale.max(1e-3);
|
||||
// The image's size and offset are in device pixels.
|
||||
for value in &mut uniforms.background_image_transform {
|
||||
*value /= scale.max(1e-3);
|
||||
}
|
||||
inner.upload_uniforms(device, queue, &uniforms);
|
||||
|
||||
// ── Scene-render cache ────────────────────────────────────────
|
||||
@@ -2557,20 +2559,18 @@ impl Scene {
|
||||
if viewport.paper_sheet {
|
||||
let handle = self.current_layout_sheet_viewport_handle();
|
||||
if let Some(EntityType::Viewport(value)) = self.document.get_entity(handle) {
|
||||
return build(
|
||||
value.visual_style_handle,
|
||||
value.brightness,
|
||||
value.contrast,
|
||||
value.background_handle,
|
||||
);
|
||||
// The sheet keeps its page and desk: a paper-space view's
|
||||
// background is kept with the layout but not drawn.
|
||||
return build(value.visual_style_handle, value.brightness, value.contrast, Handle::NULL);
|
||||
}
|
||||
} else if viewport.handle.is_valid() {
|
||||
if let Some(EntityType::Viewport(value)) = self.document.get_entity(viewport.handle) {
|
||||
let flat = value.render_mode == codec::entities::ViewportRenderMode::Wireframe2D;
|
||||
return build(
|
||||
value.visual_style_handle,
|
||||
value.brightness,
|
||||
value.contrast,
|
||||
value.background_handle,
|
||||
if flat { Handle::NULL } else { value.background_handle },
|
||||
);
|
||||
}
|
||||
} else if self.current_layout == "Model" {
|
||||
@@ -4907,7 +4907,11 @@ impl Scene {
|
||||
// (hatched) frame once it settles. Only applied to the on-screen
|
||||
// Model / paper content — the paper *sheet* keeps its fills.
|
||||
skip_hatch: self.hatch_lod_enabled() && navigating,
|
||||
skip_background: !inst.paper_sheet && self.current_layout != "Model",
|
||||
// A floating viewport shows the page behind it unless it has a
|
||||
// background of its own.
|
||||
skip_background: !inst.paper_sheet
|
||||
&& self.current_layout != "Model"
|
||||
&& display.background.params[0] < 0.5,
|
||||
geometry_epoch: self.geometry_epoch,
|
||||
camera_generation: self.camera_generation,
|
||||
wire_content_id,
|
||||
|
||||
Reference in new issue
Block a user