fix(model): sync solid render interaction
This commit is contained in:
parent
ed21681d48
commit
dc6dc2256d
5 changed files with 127 additions and 64 deletions
|
|
@ -135,6 +135,24 @@ impl OpenCADStudio {
|
||||||
let mut changed_handles: rustc_hash::FxHashSet<_> = handles.iter().copied().collect();
|
let mut changed_handles: rustc_hash::FxHashSet<_> = handles.iter().copied().collect();
|
||||||
for (handle, original) in originals {
|
for (handle, original) in originals {
|
||||||
changed_handles.insert(handle);
|
changed_handles.insert(handle);
|
||||||
|
let current = self.tabs[i]
|
||||||
|
.scene
|
||||||
|
.document
|
||||||
|
.get_entity(handle)
|
||||||
|
.and_then(crate::entities::solid3d::point_of_reference)
|
||||||
|
.map(|point| [point.x, point.y, point.z]);
|
||||||
|
let target = crate::entities::solid3d::point_of_reference(&original)
|
||||||
|
.map(|point| [point.x, point.y, point.z]);
|
||||||
|
if let (Some(current), Some(target)) = (current, target) {
|
||||||
|
self.tabs[i].scene.translate_solid_geometry(
|
||||||
|
handle,
|
||||||
|
[
|
||||||
|
target[0] - current[0],
|
||||||
|
target[1] - current[1],
|
||||||
|
target[2] - current[2],
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
if let Some(entity) = self.tabs[i].scene.document.get_entity_mut(handle) {
|
if let Some(entity) = self.tabs[i].scene.document.get_entity_mut(handle) {
|
||||||
*entity = original;
|
*entity = original;
|
||||||
}
|
}
|
||||||
|
|
@ -2615,10 +2633,16 @@ impl OpenCADStudio {
|
||||||
let color = [0.6f32, 0.6, 0.8, 1.0]; // default colour; command embedded it
|
let color = [0.6f32, 0.6, 0.8, 1.0]; // default colour; command embedded it
|
||||||
let _ = color; // color is captured inside mesh_fn
|
let _ = color; // color is captured inside mesh_fn
|
||||||
if let Some(mesh) = mesh_fn(name) {
|
if let Some(mesh) = mesh_fn(name) {
|
||||||
self.tabs[i]
|
let set = crate::scene::MeshLodSet::from_single(mesh);
|
||||||
.scene
|
if let Some(acadrust::EntityType::Solid3D(entity)) =
|
||||||
.meshes
|
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||||
.insert(handle, crate::scene::MeshLodSet::from_single(mesh));
|
{
|
||||||
|
let center = set.metrics.centroid;
|
||||||
|
entity.point_of_reference = acadrust::types::Vector3::new(
|
||||||
|
center[0], center[1], center[2],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.tabs[i].scene.meshes.insert(handle, set);
|
||||||
}
|
}
|
||||||
self.tabs[i].dirty = true;
|
self.tabs[i].dirty = true;
|
||||||
self.command_line.push_output(crate::t!("Solid created.").as_ref());
|
self.command_line.push_output(crate::t!("Solid created.").as_ref());
|
||||||
|
|
@ -2750,7 +2774,14 @@ impl OpenCADStudio {
|
||||||
|
|
||||||
if let Some(mut set) = result {
|
if let Some(mut set) = result {
|
||||||
let pending = self.begin_undo(i, "SWEEP", 1, true);
|
let pending = self.begin_undo(i, "SWEEP", 1, true);
|
||||||
let new_handle = self.tabs[i].scene.add_entity(empty_solid3d());
|
let mut entity = empty_solid3d();
|
||||||
|
if let acadrust::EntityType::Solid3D(solid) = &mut entity {
|
||||||
|
let center = set.metrics.centroid;
|
||||||
|
solid.point_of_reference = acadrust::types::Vector3::new(
|
||||||
|
center[0], center[1], center[2],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let new_handle = self.tabs[i].scene.add_entity(entity);
|
||||||
for mesh in &mut set.lods {
|
for mesh in &mut set.lods {
|
||||||
mesh.name = format!("{}", new_handle.value());
|
mesh.name = format!("{}", new_handle.value());
|
||||||
}
|
}
|
||||||
|
|
@ -2780,7 +2811,14 @@ impl OpenCADStudio {
|
||||||
.collect();
|
.collect();
|
||||||
if let Some(mut set) = sweep_model::lofted(&profiles, color) {
|
if let Some(mut set) = sweep_model::lofted(&profiles, color) {
|
||||||
let pending = self.begin_undo(i, "LOFT", 1, true);
|
let pending = self.begin_undo(i, "LOFT", 1, true);
|
||||||
let new_handle = self.tabs[i].scene.add_entity(empty_solid3d());
|
let mut entity = empty_solid3d();
|
||||||
|
if let acadrust::EntityType::Solid3D(solid) = &mut entity {
|
||||||
|
let center = set.metrics.centroid;
|
||||||
|
solid.point_of_reference = acadrust::types::Vector3::new(
|
||||||
|
center[0], center[1], center[2],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let new_handle = self.tabs[i].scene.add_entity(entity);
|
||||||
for mesh in &mut set.lods {
|
for mesh in &mut set.lods {
|
||||||
mesh.name = format!("{}", new_handle.value());
|
mesh.name = format!("{}", new_handle.value());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1046,8 +1046,7 @@ impl OpenCADStudio {
|
||||||
.filter(|handle| seen_handles.insert(*handle))
|
.filter(|handle| seen_handles.insert(*handle))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// First move of this drag: hide every edited entity from the base
|
// Wire entities use the overlay; solid meshes stay visible and move live.
|
||||||
// tessellation so subsequent moves refresh only the overlay.
|
|
||||||
if self.grip_preview_handles != edited_handles {
|
if self.grip_preview_handles != edited_handles {
|
||||||
if self.grip_dirty_before.is_none() {
|
if self.grip_dirty_before.is_none() {
|
||||||
self.grip_dirty_before = Some(self.tabs[i].dirty);
|
self.grip_dirty_before = Some(self.tabs[i].dirty);
|
||||||
|
|
@ -1072,7 +1071,9 @@ impl OpenCADStudio {
|
||||||
.collect();
|
.collect();
|
||||||
}
|
}
|
||||||
for &handle in &edited_handles {
|
for &handle in &edited_handles {
|
||||||
self.tabs[i].scene.preview_hidden.insert(handle);
|
if !self.tabs[i].scene.meshes.contains_key(&handle) {
|
||||||
|
self.tabs[i].scene.preview_hidden.insert(handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let changes: Vec<_> = edited_handles
|
let changes: Vec<_> = edited_handles
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -1377,6 +1378,13 @@ impl OpenCADStudio {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let mesh_changes: Vec<_> = edited_handles
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.filter(|handle| self.tabs[i].scene.meshes.contains_key(handle))
|
||||||
|
.map(|handle| (handle, crate::scene::ChangeKind::Modified))
|
||||||
|
.collect();
|
||||||
|
self.tabs[i].scene.bump_entities(&mesh_changes);
|
||||||
self.tabs[i].scene.set_preview_hatches(&edited_handles);
|
self.tabs[i].scene.set_preview_hatches(&edited_handles);
|
||||||
self.tabs[i].dirty = true;
|
self.tabs[i].dirty = true;
|
||||||
if let Some(active) = self.tabs[i].active_grip.as_mut() {
|
if let Some(active) = self.tabs[i].active_grip.as_mut() {
|
||||||
|
|
|
||||||
|
|
@ -2680,11 +2680,22 @@ impl Scene {
|
||||||
/// the mesh pipeline uses, so the mesh is stored as-is (Model-tab geometry
|
/// the mesh pipeline uses, so the mesh is stored as-is (Model-tab geometry
|
||||||
/// is authored at world_offset 0).
|
/// is authored at world_offset 0).
|
||||||
pub fn register_solid_model(&mut self, handle: Handle, solid: cadkernel::brep::Body) {
|
pub fn register_solid_model(&mut self, handle: Handle, solid: cadkernel::brep::Body) {
|
||||||
|
if let Some(center) = crate::scene::model::solid_model::centre(&solid) {
|
||||||
|
if let Some(EntityType::Solid3D(entity)) = self.document.get_entity_mut(handle) {
|
||||||
|
entity.point_of_reference = acadrust::types::Vector3::new(
|
||||||
|
center[0], center[1], center[2],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
let entity = self.document.get_entity(handle);
|
let entity = self.document.get_entity(handle);
|
||||||
let color = entity
|
let color = entity
|
||||||
.map(|e| self.render_style(e).0)
|
.map(|e| self.render_style(e).0)
|
||||||
.unwrap_or([0.8, 0.8, 0.85, 1.0]);
|
.unwrap_or([0.8, 0.8, 0.85, 1.0]);
|
||||||
if let Some(mut set) = crate::scene::model::solid_model::mesh_from_solid(&solid, color) {
|
if let Some(mut set) = crate::scene::model::solid_model::mesh_from_solid(&solid, color) {
|
||||||
|
let name = handle.value().to_string();
|
||||||
|
for mesh in &mut set.lods {
|
||||||
|
mesh.name = name.clone();
|
||||||
|
}
|
||||||
if let Some(entity) = entity {
|
if let Some(entity) = entity {
|
||||||
crate::scene::model::material_model::resolve_material_with_base(
|
crate::scene::model::material_model::resolve_material_with_base(
|
||||||
&self.document,
|
&self.document,
|
||||||
|
|
|
||||||
|
|
@ -625,6 +625,59 @@ impl Scene {
|
||||||
|
|
||||||
// ── Grip editing ──────────────────────────────────────────────────────
|
// ── Grip editing ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
pub(crate) fn translate_solid_geometry(&mut self, handle: Handle, delta: [f64; 3]) {
|
||||||
|
if delta.iter().all(|value| value.abs() <= f64::EPSILON) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let placement = cadkernel::brep::Placement::at(delta);
|
||||||
|
if let Some(body) = self.solid_models.get(&handle).cloned() {
|
||||||
|
if let Some(moved) = cadkernel::brep::transform(&body, &placement) {
|
||||||
|
self.solid_models.insert(handle, moved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let Some(set) = self.meshes.get_mut(&handle) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let translate_split = |high: &mut [f32; 3], low: &mut [f32; 3]| {
|
||||||
|
let absolute = [
|
||||||
|
high[0] as f64 + low[0] as f64 + delta[0],
|
||||||
|
high[1] as f64 + low[1] as f64 + delta[1],
|
||||||
|
high[2] as f64 + low[2] as f64 + delta[2],
|
||||||
|
];
|
||||||
|
*high = [absolute[0] as f32, absolute[1] as f32, absolute[2] as f32];
|
||||||
|
*low = [
|
||||||
|
(absolute[0] - high[0] as f64) as f32,
|
||||||
|
(absolute[1] - high[1] as f64) as f32,
|
||||||
|
(absolute[2] - high[2] as f64) as f32,
|
||||||
|
];
|
||||||
|
};
|
||||||
|
for lod in &mut set.lods {
|
||||||
|
if lod.verts_low.len() != lod.verts.len() {
|
||||||
|
lod.verts_low = vec![[0.0; 3]; lod.verts.len()];
|
||||||
|
}
|
||||||
|
for (high, low) in lod.verts.iter_mut().zip(lod.verts_low.iter_mut()) {
|
||||||
|
translate_split(high, low);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if set.edge_verts_low.len() != set.edge_verts.len() {
|
||||||
|
set.edge_verts_low = vec![[0.0; 3]; set.edge_verts.len()];
|
||||||
|
}
|
||||||
|
for (high, low) in set.edge_verts.iter_mut().zip(set.edge_verts_low.iter_mut()) {
|
||||||
|
translate_split(high, low);
|
||||||
|
}
|
||||||
|
for generator in &mut set.curved_gens {
|
||||||
|
if let Some(source) =
|
||||||
|
cadkernel::brep::mesh::transform_silhouette(&generator.source, &placement)
|
||||||
|
{
|
||||||
|
generator.source = source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set.metrics.centroid[0] += delta[0];
|
||||||
|
set.metrics.centroid[1] += delta[1];
|
||||||
|
set.metrics.centroid[2] += delta[2];
|
||||||
|
set.recompute_aabb();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn apply_grip(&mut self, handle: Handle, grip_id: usize, apply: GripApply) {
|
pub fn apply_grip(&mut self, handle: Handle, grip_id: usize, apply: GripApply) {
|
||||||
// Objects on a locked layer can't be grip-edited.
|
// Objects on a locked layer can't be grip-edited.
|
||||||
if self.is_layer_locked(handle) {
|
if self.is_layer_locked(handle) {
|
||||||
|
|
@ -660,57 +713,7 @@ impl Scene {
|
||||||
.map(|p| [p.x, p.y, p.z]);
|
.map(|p| [p.x, p.y, p.z]);
|
||||||
if let Some(new) = new_por {
|
if let Some(new) = new_por {
|
||||||
let delta = [new[0] - old[0], new[1] - old[1], new[2] - old[2]];
|
let delta = [new[0] - old[0], new[1] - old[1], new[2] - old[2]];
|
||||||
if let Some(set) = self.meshes.get_mut(&handle) {
|
self.translate_solid_geometry(handle, delta);
|
||||||
let translate_split =
|
|
||||||
|high: &mut [f32; 3], low: &mut [f32; 3]| {
|
|
||||||
let absolute = [
|
|
||||||
high[0] as f64 + low[0] as f64 + delta[0],
|
|
||||||
high[1] as f64 + low[1] as f64 + delta[1],
|
|
||||||
high[2] as f64 + low[2] as f64 + delta[2],
|
|
||||||
];
|
|
||||||
*high = [
|
|
||||||
absolute[0] as f32,
|
|
||||||
absolute[1] as f32,
|
|
||||||
absolute[2] as f32,
|
|
||||||
];
|
|
||||||
*low = [
|
|
||||||
(absolute[0] - high[0] as f64) as f32,
|
|
||||||
(absolute[1] - high[1] as f64) as f32,
|
|
||||||
(absolute[2] - high[2] as f64) as f32,
|
|
||||||
];
|
|
||||||
};
|
|
||||||
for lod in &mut set.lods {
|
|
||||||
if lod.verts_low.len() != lod.verts.len() {
|
|
||||||
lod.verts_low = vec![[0.0; 3]; lod.verts.len()];
|
|
||||||
}
|
|
||||||
for (high, low) in lod.verts.iter_mut().zip(lod.verts_low.iter_mut()) {
|
|
||||||
translate_split(high, low);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if set.edge_verts_low.len() != set.edge_verts.len() {
|
|
||||||
set.edge_verts_low = vec![[0.0; 3]; set.edge_verts.len()];
|
|
||||||
}
|
|
||||||
for (high, low) in set
|
|
||||||
.edge_verts
|
|
||||||
.iter_mut()
|
|
||||||
.zip(set.edge_verts_low.iter_mut())
|
|
||||||
{
|
|
||||||
translate_split(high, low);
|
|
||||||
}
|
|
||||||
for generator in &mut set.curved_gens {
|
|
||||||
let placement = cadkernel::brep::Placement::at(delta);
|
|
||||||
if let Some(source) = cadkernel::brep::mesh::transform_silhouette(
|
|
||||||
&generator.source,
|
|
||||||
&placement,
|
|
||||||
) {
|
|
||||||
generator.source = source;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set.metrics.centroid[0] += delta[0];
|
|
||||||
set.metrics.centroid[1] += delta[1];
|
|
||||||
set.metrics.centroid[2] += delta[2];
|
|
||||||
set.recompute_aabb();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -731,9 +734,6 @@ impl Scene {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
// NOTE: no `bump_geometry()` here. The grip-drag caller hides the
|
// The grip-drag caller refreshes changed resident meshes per move.
|
||||||
// edited entity and previews it as an overlay during the drag (so a
|
|
||||||
// move doesn't re-tessellate the whole model), then bumps once on
|
|
||||||
// commit. Any other caller must bump geometry itself.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1248,6 +1248,12 @@ fn render_signature(vp: &ViewportData, clip_w: u32, clip_h: u32) -> u64 {
|
||||||
.map(|image| std::sync::Arc::as_ptr(&image.pixels) as usize)
|
.map(|image| std::sync::Arc::as_ptr(&image.pixels) as usize)
|
||||||
.unwrap_or(0)
|
.unwrap_or(0)
|
||||||
.hash(&mut h);
|
.hash(&mut h);
|
||||||
|
if vp.meshes.is_empty() {
|
||||||
|
0usize
|
||||||
|
} else {
|
||||||
|
std::sync::Arc::as_ptr(&vp.meshes) as usize
|
||||||
|
}
|
||||||
|
.hash(&mut h);
|
||||||
vp.geometry_epoch.hash(&mut h);
|
vp.geometry_epoch.hash(&mut h);
|
||||||
vp.selection_generation.hash(&mut h);
|
vp.selection_generation.hash(&mut h);
|
||||||
vp.selected_sig.hash(&mut h);
|
vp.selected_sig.hash(&mut h);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue